mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
fix: broken filters (#294)
This commit is contained in:
@@ -90,7 +90,14 @@ const ListingsGrid = () => {
|
|||||||
loadData();
|
loadData();
|
||||||
}, [page, sortField, sortDir, freeTextFilter, providerFilter, activityFilter, jobNameFilter, watchListFilter]);
|
}, [page, sortField, sortDir, freeTextFilter, providerFilter, activityFilter, jobNameFilter, watchListFilter]);
|
||||||
|
|
||||||
const handleFilterChange = useMemo(() => debounce((value) => setFreeTextFilter(value || null), 500), []);
|
const handleFilterChange = useMemo(
|
||||||
|
() =>
|
||||||
|
debounce((value) => {
|
||||||
|
setFreeTextFilter(value || null);
|
||||||
|
setPage(1);
|
||||||
|
}, 500),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
@@ -152,6 +159,7 @@ const ListingsGrid = () => {
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const v = e.target.value;
|
const v = e.target.value;
|
||||||
setActivityFilter(v === 'all' ? null : v === 'true');
|
setActivityFilter(v === 'all' ? null : v === 'true');
|
||||||
|
setPage(1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Radio value="all">All</Radio>
|
<Radio value="all">All</Radio>
|
||||||
@@ -166,6 +174,7 @@ const ListingsGrid = () => {
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const v = e.target.value;
|
const v = e.target.value;
|
||||||
setWatchListFilter(v === 'all' ? null : v === 'true');
|
setWatchListFilter(v === 'all' ? null : v === 'true');
|
||||||
|
setPage(1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Radio value="all">All</Radio>
|
<Radio value="all">All</Radio>
|
||||||
@@ -176,7 +185,10 @@ const ListingsGrid = () => {
|
|||||||
<Select
|
<Select
|
||||||
placeholder="Provider"
|
placeholder="Provider"
|
||||||
showClear
|
showClear
|
||||||
onChange={(val) => setProviderFilter(val)}
|
onChange={(val) => {
|
||||||
|
setProviderFilter(val);
|
||||||
|
setPage(1);
|
||||||
|
}}
|
||||||
value={providerFilter}
|
value={providerFilter}
|
||||||
style={{ width: 130 }}
|
style={{ width: 130 }}
|
||||||
>
|
>
|
||||||
@@ -190,7 +202,10 @@ const ListingsGrid = () => {
|
|||||||
<Select
|
<Select
|
||||||
placeholder="Job"
|
placeholder="Job"
|
||||||
showClear
|
showClear
|
||||||
onChange={(val) => setJobNameFilter(val)}
|
onChange={(val) => {
|
||||||
|
setJobNameFilter(val);
|
||||||
|
setPage(1);
|
||||||
|
}}
|
||||||
value={jobNameFilter}
|
value={jobNameFilter}
|
||||||
style={{ width: 130 }}
|
style={{ width: 130 }}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ export const parseNullableBoolean = {
|
|||||||
* @param {*} defaultValue - value when param is absent
|
* @param {*} defaultValue - value when param is absent
|
||||||
* @param {{ parse: (s: string) => *, stringify: (v: *) => string|null }} [options]
|
* @param {{ parse: (s: string) => *, stringify: (v: *) => string|null }} [options]
|
||||||
*/
|
*/
|
||||||
|
// WeakMap to store pending batched updates per setSearchParams function.
|
||||||
|
// This lets multiple useSearchParamState hooks on the same component batch
|
||||||
|
// their changes into a single setSearchParams call, preventing them from
|
||||||
|
// overwriting each other.
|
||||||
|
const pendingUpdates = new WeakMap();
|
||||||
|
|
||||||
export function useSearchParamState([searchParams, setSearchParams], key, defaultValue, options = {}) {
|
export function useSearchParamState([searchParams, setSearchParams], key, defaultValue, options = {}) {
|
||||||
const { parse = (v) => v, stringify = (v) => String(v) } = options;
|
const { parse = (v) => v, stringify = (v) => String(v) } = options;
|
||||||
|
|
||||||
@@ -48,21 +54,42 @@ export function useSearchParamState([searchParams, setSearchParams], key, defaul
|
|||||||
|
|
||||||
const setValue = useCallback(
|
const setValue = useCallback(
|
||||||
(newValue) => {
|
(newValue) => {
|
||||||
|
// Collect the change
|
||||||
|
if (!pendingUpdates.has(setSearchParams)) {
|
||||||
|
pendingUpdates.set(setSearchParams, new Map());
|
||||||
|
|
||||||
|
// Schedule a single flush at the end of the current microtask
|
||||||
|
queueMicrotask(() => {
|
||||||
|
const updates = pendingUpdates.get(setSearchParams);
|
||||||
|
pendingUpdates.delete(setSearchParams);
|
||||||
|
if (!updates || updates.size === 0) return;
|
||||||
|
|
||||||
setSearchParams(
|
setSearchParams(
|
||||||
(prev) => {
|
(prev) => {
|
||||||
const next = new URLSearchParams(prev);
|
const next = new URLSearchParams(prev);
|
||||||
const serialized = stringify(newValue);
|
for (const [k, entry] of updates) {
|
||||||
if (newValue === defaultValue || newValue === null || newValue === undefined || serialized === null) {
|
if (entry.remove) {
|
||||||
next.delete(key);
|
next.delete(k);
|
||||||
} else {
|
} else {
|
||||||
next.set(key, serialized);
|
next.set(k, entry.serialized);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return next;
|
return next;
|
||||||
},
|
},
|
||||||
{ replace: true },
|
{ replace: true },
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const batch = pendingUpdates.get(setSearchParams);
|
||||||
|
const serialized = stringify(newValue);
|
||||||
|
if (newValue === defaultValue || newValue === null || newValue === undefined || serialized === null) {
|
||||||
|
batch.set(key, { remove: true });
|
||||||
|
} else {
|
||||||
|
batch.set(key, { remove: false, serialized });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[key, defaultValue, stringify],
|
[key, defaultValue, stringify, setSearchParams],
|
||||||
);
|
);
|
||||||
|
|
||||||
return [value, setValue];
|
return [value, setValue];
|
||||||
|
|||||||
@@ -207,14 +207,17 @@ export const useFredyState = create(
|
|||||||
filter,
|
filter,
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
const qryString = queryString.stringify({
|
const qryString = queryString.stringify(
|
||||||
|
{
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
freeTextFilter,
|
freeTextFilter,
|
||||||
sortfield,
|
sortfield,
|
||||||
sortdir,
|
sortdir,
|
||||||
...filter,
|
...filter,
|
||||||
});
|
},
|
||||||
|
{ skipNull: true, skipEmptyString: true },
|
||||||
|
);
|
||||||
const response = await xhrGet(`/api/listings/table?${qryString}`);
|
const response = await xhrGet(`/api/listings/table?${qryString}`);
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
listingsData: { ...state.listingsData, ...response.json },
|
listingsData: { ...state.listingsData, ...response.json },
|
||||||
|
|||||||
Reference in New Issue
Block a user