fix/filtration #20

Merged
ilia merged 7 commits from fix/filtration into main 2026-02-05 08:51:46 +00:00
2 changed files with 34 additions and 9 deletions
Showing only changes of commit 1e2daa410c - Show all commits

View File

@@ -9,7 +9,6 @@ import type { UnifiedFont } from '../types';
/** */ /** */
export abstract class BaseFontStore<TParams extends Record<string, any>> { export abstract class BaseFontStore<TParams extends Record<string, any>> {
// params = $state<TParams>({} as TParams);
cleanup: () => void; cleanup: () => void;
#bindings = $state<(() => Partial<TParams>)[]>([]); #bindings = $state<(() => Partial<TParams>)[]>([]);
@@ -18,9 +17,11 @@ export abstract class BaseFontStore<TParams extends Record<string, any>> {
params = $derived.by(() => { params = $derived.by(() => {
let merged = { ...this.#internalParams }; let merged = { ...this.#internalParams };
// Loop through every "Cable" plugged into the store
// Loop through every "Cable" plugged into the store // Loop through every "Cable" plugged into the store
for (const getter of this.#bindings) { for (const getter of this.#bindings) {
merged = { ...merged, ...getter() }; const bindingResult = getter();
merged = { ...merged, ...bindingResult };
} }
return merged as TParams; return merged as TParams;
@@ -54,7 +55,7 @@ export abstract class BaseFontStore<TParams extends Record<string, any>> {
protected abstract getQueryKey(params: TParams): QueryKey; protected abstract getQueryKey(params: TParams): QueryKey;
protected abstract fetchFn(params: TParams): Promise<UnifiedFont[]>; protected abstract fetchFn(params: TParams): Promise<UnifiedFont[]>;
private getOptions(params = this.params): QueryObserverOptions<UnifiedFont[], Error> { protected getOptions(params = this.params): QueryObserverOptions<UnifiedFont[], Error> {
return { return {
queryKey: this.getQueryKey(params), queryKey: this.getQueryKey(params),
queryFn: () => this.fetchFn(params), queryFn: () => this.fetchFn(params),

View File

@@ -12,6 +12,7 @@
* - Provider-specific shortcuts for common operations * - Provider-specific shortcuts for common operations
*/ */
import type { QueryObserverOptions } from '@tanstack/query-core';
import type { ProxyFontsParams } from '../../api'; import type { ProxyFontsParams } from '../../api';
import { fetchProxyFonts } from '../../api'; import { fetchProxyFonts } from '../../api';
import type { UnifiedFont } from '../types'; import type { UnifiedFont } from '../types';
@@ -121,6 +122,19 @@ export class UnifiedFontStore extends BaseFontStore<ProxyFontsParams> {
this.#previousFilterParams = filterParams; this.#previousFilterParams = filterParams;
} }
}); });
// Effect: Sync state from Query result (Handles Cache Hits)
$effect(() => {
const data = this.result.data;
const offset = this.params.offset || 0;
// When we have data and we are at the start (offset 0),
// we must ensure accumulatedFonts matches the fresh (or cached) data.
// This fixes the issue where cache hits skip fetchFn side-effects.
if (offset === 0 && data && data.length > 0) {
this.#accumulatedFonts = data;
}
});
}); });
} }
@@ -145,15 +159,26 @@ export class UnifiedFontStore extends BaseFontStore<ProxyFontsParams> {
protected getQueryKey(params: ProxyFontsParams) { protected getQueryKey(params: ProxyFontsParams) {
// Normalize params to treat empty arrays/strings as undefined // Normalize params to treat empty arrays/strings as undefined
const normalized = Object.entries(params).reduce((acc, [key, value]) => { const normalized = Object.entries(params).reduce((acc, [key, value]) => {
if (value === '' || (Array.isArray(value) && value.length === 0)) { if (value === '' || value === undefined || (Array.isArray(value) && value.length === 0)) {
return acc; return acc;
} }
return { ...acc, [key]: value }; return { ...acc, [key]: value };
}, {}); }, {});
// Return a consistent key
return ['unifiedFonts', normalized] as const; return ['unifiedFonts', normalized] as const;
} }
protected getOptions(params = this.params): QueryObserverOptions<UnifiedFont[], Error> {
const hasFilters = !!(params.q || params.provider || params.category || params.subset);
return {
queryKey: this.getQueryKey(params),
queryFn: () => this.fetchFn(params),
staleTime: hasFilters ? 0 : 5 * 60 * 1000,
gcTime: 10 * 60 * 1000,
};
}
/** /**
* Fetch function that calls the proxy API * Fetch function that calls the proxy API
* Returns the full response including pagination metadata * Returns the full response including pagination metadata
@@ -187,11 +212,10 @@ export class UnifiedFontStore extends BaseFontStore<ProxyFontsParams> {
}; };
// Accumulate fonts for infinite scroll // Accumulate fonts for infinite scroll
if (params.offset === 0) { // Note: For offset === 0, we rely on the $effect above to handle the reset/init
// Reset when starting from beginning (new search/filter) // This prevents race conditions and double-setting.
this.#accumulatedFonts = response.fonts; if (params.offset !== 0) {
} else { // Append new fonts to existing ones only for pagination
// Append new fonts to existing ones
this.#accumulatedFonts = [...this.#accumulatedFonts, ...response.fonts]; this.#accumulatedFonts = [...this.#accumulatedFonts, ...response.fonts];
} }