feat(FontStore): implement state getters, pagination, buildQueryKey, buildOptions
This commit is contained in:
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
type InfiniteData,
|
||||
QueryClient,
|
||||
} from '@tanstack/query-core';
|
||||
import { QueryClient } from '@tanstack/query-core';
|
||||
import { flushSync } from 'svelte';
|
||||
import {
|
||||
afterEach,
|
||||
|
||||
@@ -47,26 +47,49 @@ export class FontStore {
|
||||
return this.#params;
|
||||
}
|
||||
get fonts(): UnifiedFont[] {
|
||||
return [];
|
||||
return this.#result.data?.pages.flatMap((p: FontPage) => p.fonts) ?? [];
|
||||
}
|
||||
get isLoading(): boolean {
|
||||
return false;
|
||||
return this.#result.isLoading;
|
||||
}
|
||||
get isFetching(): boolean {
|
||||
return false;
|
||||
return this.#result.isFetching;
|
||||
}
|
||||
get isError(): boolean {
|
||||
return false;
|
||||
return this.#result.isError;
|
||||
}
|
||||
|
||||
get error(): Error | null {
|
||||
return null;
|
||||
return this.#result.error ?? null;
|
||||
}
|
||||
// isEmpty is false during loading/fetching so the UI never flashes "no results"
|
||||
// while a fetch is in progress. The !isFetching guard is specifically for the filter-change
|
||||
// transition: fonts clear synchronously → isFetching becomes true → isEmpty stays false.
|
||||
get isEmpty(): boolean {
|
||||
return false;
|
||||
return !this.isLoading && !this.isFetching && this.fonts.length === 0;
|
||||
}
|
||||
|
||||
get pagination() {
|
||||
return { total: 0, limit: 50, offset: 0, hasMore: false, page: 1, totalPages: 0 };
|
||||
const pages = this.#result.data?.pages;
|
||||
const last = pages?.at(-1);
|
||||
if (!last) {
|
||||
return {
|
||||
total: 0,
|
||||
limit: this.#params.limit ?? 50,
|
||||
offset: 0,
|
||||
hasMore: false,
|
||||
page: 1,
|
||||
totalPages: 0,
|
||||
};
|
||||
}
|
||||
return {
|
||||
total: last.total,
|
||||
limit: last.limit,
|
||||
offset: last.offset,
|
||||
hasMore: this.#result.hasNextPage,
|
||||
page: pages!.length,
|
||||
totalPages: Math.ceil(last.total / last.limit),
|
||||
};
|
||||
}
|
||||
|
||||
// -- Lifecycle --
|
||||
@@ -124,17 +147,30 @@ export class FontStore {
|
||||
// -- Private helpers (TypeScript-private so tests can spy via `as any`) --
|
||||
|
||||
private buildQueryKey(params: FontStoreParams): readonly unknown[] {
|
||||
return ['fonts', params];
|
||||
const normalized = Object.entries(params).reduce<Record<string, unknown>>((acc, [k, v]) => {
|
||||
if (v === undefined || v === '' || (Array.isArray(v) && v.length === 0)) return acc;
|
||||
return { ...acc, [k]: v };
|
||||
}, {});
|
||||
return ['fonts', normalized] as const;
|
||||
}
|
||||
|
||||
private buildOptions(params = this.#params) {
|
||||
const hasFilters = !!(
|
||||
params.q
|
||||
|| (Array.isArray(params.providers) && params.providers.length > 0)
|
||||
|| (Array.isArray(params.categories) && params.categories.length > 0)
|
||||
|| (Array.isArray(params.subsets) && params.subsets.length > 0)
|
||||
);
|
||||
return {
|
||||
queryKey: this.buildQueryKey(params),
|
||||
queryFn: ({ pageParam }: QueryFunctionContext<readonly unknown[], PageParam>) =>
|
||||
this.fetchPage({ ...this.#params, ...pageParam }),
|
||||
initialPageParam: { offset: 0 } as PageParam,
|
||||
getNextPageParam: (_lastPage: FontPage): PageParam | undefined => undefined,
|
||||
staleTime: 5 * 60 * 1000,
|
||||
getNextPageParam: (lastPage: FontPage): PageParam | undefined => {
|
||||
const next = lastPage.offset + lastPage.limit;
|
||||
return next < lastPage.total ? { offset: next } : undefined;
|
||||
},
|
||||
staleTime: hasFilters ? 0 : 5 * 60 * 1000,
|
||||
gcTime: 10 * 60 * 1000,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user