@trackunit/filters-filter-bar 1.7.88 → 1.7.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs.js +420 -71
- package/index.esm.js +415 -74
- package/package.json +14 -14
- package/src/lib/hooks/types.d.ts +4 -0
- package/src/lib/hooks/useSearchParamAsFilter.d.ts +1 -3
- package/src/lib/hooks/utils/useFilterBarActions.d.ts +1 -1
- package/src/lib/hooks/utils/useFilterBarPersistence.d.ts +46 -2
- package/src/lib/hooks/utils/useFilterUrlSync.d.ts +10 -0
- package/src/lib/hooks/utils/useIsDefaultValue.d.ts +10 -0
- package/src/lib/hooks/utils/useSearchUtils.d.ts +8 -0
- package/src/lib/types/FilterTypes.d.ts +21 -3
- package/src/lib/types/FilterZodTypes.d.ts +44 -0
package/index.esm.js
CHANGED
|
@@ -2,8 +2,8 @@ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
|
2
2
|
import { registerTranslations, useNamespaceTranslation } from '@trackunit/i18n-library-translation';
|
|
3
3
|
import { useMemo, useRef, useState, useEffect, useCallback, Fragment as Fragment$1 } from 'react';
|
|
4
4
|
import { Filter, FilterBody, RadioFilterItem, CheckBoxFilterItem, FilterHeader as FilterHeader$1, FilterFooter } from '@trackunit/react-filter-components';
|
|
5
|
-
import { Button, Icon, List, Text, Card, CardBody, useViewportBreakpoints, Popover, PopoverTrigger, Tooltip,
|
|
6
|
-
import { useAnalytics, useTextSearch, useCurrentUser } from '@trackunit/react-core-hooks';
|
|
5
|
+
import { Button, Icon, List, Text, Card, CardBody, useViewportBreakpoints, Popover, PopoverTrigger, Tooltip, IconButton, PopoverContent, MenuList } from '@trackunit/react-components';
|
|
6
|
+
import { useAnalytics, useTextSearch, useCurrentUser, useCustomEncoding } from '@trackunit/react-core-hooks';
|
|
7
7
|
import { capitalize } from 'string-ts';
|
|
8
8
|
import { createEvent } from '@trackunit/react-core-contexts-api';
|
|
9
9
|
import { Search, NumberField, RadioGroup } from '@trackunit/react-form-components';
|
|
@@ -13,9 +13,9 @@ import { twMerge } from 'tailwind-merge';
|
|
|
13
13
|
import { customFieldFilterKey } from '@trackunit/iris-app-api';
|
|
14
14
|
import { cvaMerge } from '@trackunit/css-class-variance-utilities';
|
|
15
15
|
import { dequal } from 'dequal';
|
|
16
|
-
import isEqual from 'lodash/isEqual';
|
|
17
16
|
import { geoJsonPolygonSchema, geoJsonMultiPolygonSchema } from '@trackunit/geo-json-utils';
|
|
18
17
|
import { z } from 'zod';
|
|
18
|
+
import { useLocation, useSearch, useNavigate } from '@tanstack/react-router';
|
|
19
19
|
|
|
20
20
|
var defaultTranslations = {
|
|
21
21
|
"access.management.filter.operator.role.keyAdmin": "Key Admin",
|
|
@@ -1059,7 +1059,7 @@ const FiltersMenu = ({ filterBarDefinition, filterBarConfig, hiddenFilters = [],
|
|
|
1059
1059
|
setSearchText("");
|
|
1060
1060
|
}
|
|
1061
1061
|
}, placement: "bottom-start", children: modalState => {
|
|
1062
|
-
return (jsxs(Fragment, { children: [jsx(PopoverTrigger, { children: jsx("div", { "data-testid": "starred-filters-menu-trigger", id: "starred-filters-menu-trigger", children: jsx(Tooltip, { disabled: !compact || modalState.isOpen, label: jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig, filters: appliedFilters }), children: jsx(Button, { prefix: jsx(Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Filter", size: "small" }), size: "small", suffix: compact && showAppliedFiltersCount && filterBarConfig.appliedFilterKeys().length > 0
|
|
1062
|
+
return (jsxs(Fragment, { children: [jsx(PopoverTrigger, { children: jsx("div", { "data-testid": "starred-filters-menu-trigger", id: "starred-filters-menu-trigger", children: jsx(Tooltip, { disabled: !compact || modalState.isOpen, label: jsx(MultipleFilterTooltipLabel, { filterBarConfig: filterBarConfig, filters: appliedFilters }), children: !isSm ? (jsx(IconButton, { "aria-label": title ?? t("filtersBar.filtersHeading"), icon: jsx(Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Filter", size: "small" }), size: "small", variant: "secondary", ...buttonProps })) : (jsx(Button, { prefix: jsx(Icon, { ariaHidden: true, color: filterBarConfig.appliedFilterKeys().length > 0 ? "primary" : undefined, name: "Filter", size: "small" }), size: "small", suffix: compact && showAppliedFiltersCount && filterBarConfig.appliedFilterKeys().length > 0 ? (jsxs("div", { children: [jsxs("span", { "aria-hidden": true, children: ["(", filterBarConfig.appliedFilterKeys().length, ")"] }), jsxs("span", { className: "sr-only", children: [filterBarConfig.appliedFilterKeys().length, " filters applied"] })] })) : undefined, variant: "secondary", ...buttonProps, children: title !== "" ? (title ?? t("filtersBar.filtersHeading")) : null })) }) }) }), jsx(PopoverContent, { cellPadding: 100, children: jsx(FiltersMenuContent, { appliedCustomFields: appliedCustomFields, filterBarConfig: filterBarConfig, filterBarDefinitionCount: filterBarDefinitionCount, filtersToShowGrouped: filtersToShowGrouped, hasCustomFields: hasCustomFields, removeCustomFieldsGroup: removeCustomFieldsGroup, searchResultsGrouped: searchResultsGrouped, searchText: searchText, setSearchText: setSearchText, setShowCustomFilters: setShowCustomFilters, showCustomFilters: showCustomFilters }) })] }));
|
|
1063
1063
|
} }), showDirectlyFilters.length > 0 ? (jsx(FiltersRenderer, { filterBarConfig: filterBarConfig, filters: showDirectlyFilters })) : null, !compact ? jsx(AppliedFiltersRenderer, { appliedFilters: appliedFilters, filterBarConfig: filterBarConfig }) : null] }));
|
|
1064
1064
|
};
|
|
1065
1065
|
|
|
@@ -1435,6 +1435,23 @@ const createInitialState = ({ name, mainFilters, setValue, }) => {
|
|
|
1435
1435
|
* Dont move these to FilterTypes.ts since rollup will mess up the type.d.ts file by moving jsdocs in random places.
|
|
1436
1436
|
*/
|
|
1437
1437
|
const areaFilterGeoJsonGeometrySchema = z.union([geoJsonPolygonSchema, geoJsonMultiPolygonSchema]);
|
|
1438
|
+
const stringSchema = z.string();
|
|
1439
|
+
const stringArraySchema = z.array(z.string());
|
|
1440
|
+
const numberSchema = z.number();
|
|
1441
|
+
const booleanSchema = z.boolean();
|
|
1442
|
+
const valueNameSchema = z.object({
|
|
1443
|
+
value: stringSchema,
|
|
1444
|
+
name: stringSchema,
|
|
1445
|
+
});
|
|
1446
|
+
const minMaxFilterSchema = z.object({
|
|
1447
|
+
min: numberSchema.optional(),
|
|
1448
|
+
max: numberSchema.optional(),
|
|
1449
|
+
});
|
|
1450
|
+
const dateRangeSchema = z.object({
|
|
1451
|
+
from: stringSchema.optional(),
|
|
1452
|
+
to: stringSchema.optional(),
|
|
1453
|
+
});
|
|
1454
|
+
const valueNameArraySchema = z.array(valueNameSchema);
|
|
1438
1455
|
|
|
1439
1456
|
const hasValue = (value) => {
|
|
1440
1457
|
if (value === undefined || value === null) {
|
|
@@ -1540,9 +1557,49 @@ const validateFilter = ({ values, filterDefinitions, }) => {
|
|
|
1540
1557
|
inBadState = true;
|
|
1541
1558
|
}
|
|
1542
1559
|
});
|
|
1543
|
-
stateKeys
|
|
1544
|
-
|
|
1545
|
-
|
|
1560
|
+
// check that all keys in stateKeys are in filterDefinitions
|
|
1561
|
+
stateKeys.forEach(stateKey => {
|
|
1562
|
+
if (!filterDefinitions.find(filterDefinition => filterDefinition.filterKey === stateKey)) {
|
|
1563
|
+
inBadState = true;
|
|
1564
|
+
}
|
|
1565
|
+
});
|
|
1566
|
+
return !inBadState;
|
|
1567
|
+
};
|
|
1568
|
+
|
|
1569
|
+
/**
|
|
1570
|
+
* Generic hook for setting the value of a filter bar.
|
|
1571
|
+
*
|
|
1572
|
+
* @template TFilterBarDefinition - The type of the filter bar definition.
|
|
1573
|
+
* @returns {object} An object containing the setValue function.
|
|
1574
|
+
*/
|
|
1575
|
+
const useIsDefaultValue = () => {
|
|
1576
|
+
const isDefaultValue = useCallback((key, filterValue, filterBarDefinition, initialState) => {
|
|
1577
|
+
const filterDefinition = filterBarDefinition[key];
|
|
1578
|
+
if ((initialState && dequal(filterValue, initialState[key])) ||
|
|
1579
|
+
dequal(filterValue, filterDefinition?.defaultValue)) {
|
|
1580
|
+
return true;
|
|
1581
|
+
}
|
|
1582
|
+
if (!filterValue) {
|
|
1583
|
+
return true;
|
|
1584
|
+
}
|
|
1585
|
+
if (Array.isArray(filterValue)) {
|
|
1586
|
+
return filterValue.length === 0;
|
|
1587
|
+
}
|
|
1588
|
+
if (isMinMaxFilterValue(filterValue)) {
|
|
1589
|
+
return filterValue.min === undefined && filterValue.max === undefined;
|
|
1590
|
+
}
|
|
1591
|
+
if (isValueName(filterValue)) {
|
|
1592
|
+
return filterValue.value === "";
|
|
1593
|
+
}
|
|
1594
|
+
if (isDateRangeValue(filterValue)) {
|
|
1595
|
+
return filterValue.from === undefined && filterValue.to === undefined;
|
|
1596
|
+
}
|
|
1597
|
+
if (typeof filterValue === "object") {
|
|
1598
|
+
return objectKeys(filterValue).length === 0;
|
|
1599
|
+
}
|
|
1600
|
+
return false;
|
|
1601
|
+
}, []);
|
|
1602
|
+
return useMemo(() => ({ isDefaultValue }), [isDefaultValue]);
|
|
1546
1603
|
};
|
|
1547
1604
|
|
|
1548
1605
|
/**
|
|
@@ -1552,6 +1609,7 @@ const validateFilter = ({ values, filterDefinitions, }) => {
|
|
|
1552
1609
|
* @returns {object} An object containing filter bar configuration and actions.
|
|
1553
1610
|
*/
|
|
1554
1611
|
const useFilterBarActions = ({ name, filterBarConfig, filterBarDefinition, setFilterBarConfig, setValue, initialState, }) => {
|
|
1612
|
+
const { isDefaultValue } = useIsDefaultValue();
|
|
1555
1613
|
const filterMapGetter = useMemo(() => {
|
|
1556
1614
|
return {
|
|
1557
1615
|
getFilterBarName: () => {
|
|
@@ -1564,28 +1622,7 @@ const useFilterBarActions = ({ name, filterBarConfig, filterBarDefinition, setFi
|
|
|
1564
1622
|
const filter = filterBarConfig.values[key];
|
|
1565
1623
|
return filter?.includes(value) || false;
|
|
1566
1624
|
},
|
|
1567
|
-
isDefaultValue(key,
|
|
1568
|
-
const filterDefinition = filterBarDefinition[key];
|
|
1569
|
-
if (dequal(filterValue, initialState?.[key]) || dequal(filterValue, filterDefinition?.defaultValue)) {
|
|
1570
|
-
return true;
|
|
1571
|
-
}
|
|
1572
|
-
if (!filterValue) {
|
|
1573
|
-
return true;
|
|
1574
|
-
}
|
|
1575
|
-
if (Array.isArray(filterValue)) {
|
|
1576
|
-
return filterValue.length === 0;
|
|
1577
|
-
}
|
|
1578
|
-
if (isMinMaxFilterValue(filterValue)) {
|
|
1579
|
-
return filterValue.min === undefined && filterValue.max === undefined;
|
|
1580
|
-
}
|
|
1581
|
-
if (isValueName(filterValue)) {
|
|
1582
|
-
return filterValue.value === "";
|
|
1583
|
-
}
|
|
1584
|
-
if (typeof filterValue === "object") {
|
|
1585
|
-
return objectKeys(filterValue).length === 0;
|
|
1586
|
-
}
|
|
1587
|
-
return false;
|
|
1588
|
-
},
|
|
1625
|
+
isDefaultValue: (key, value) => isDefaultValue(key, value, filterBarDefinition, initialState),
|
|
1589
1626
|
getValuesByKey(key) {
|
|
1590
1627
|
return filterBarConfig.values[key];
|
|
1591
1628
|
},
|
|
@@ -1612,7 +1649,7 @@ const useFilterBarActions = ({ name, filterBarConfig, filterBarDefinition, setFi
|
|
|
1612
1649
|
return filter?.value === value || false;
|
|
1613
1650
|
},
|
|
1614
1651
|
};
|
|
1615
|
-
}, [filterBarDefinition, filterBarConfig.name, filterBarConfig.values, initialState]);
|
|
1652
|
+
}, [filterBarDefinition, filterBarConfig.name, filterBarConfig.values, initialState, isDefaultValue]);
|
|
1616
1653
|
const filterMapActions = useMemo(() => {
|
|
1617
1654
|
// Reset an individual filter to its initial state
|
|
1618
1655
|
const resetIndividualFilterToInitialState = (key) => {
|
|
@@ -1829,6 +1866,127 @@ const useFilterBarActions = ({ name, filterBarConfig, filterBarDefinition, setFi
|
|
|
1829
1866
|
return useMemo(() => ({ filterMapGetter, filterMapActions }), [filterMapGetter, filterMapActions]);
|
|
1830
1867
|
};
|
|
1831
1868
|
|
|
1869
|
+
/**
|
|
1870
|
+
* Hook to sync filter values with URL
|
|
1871
|
+
*
|
|
1872
|
+
* @returns {object} Object containing loadFromUrl and saveToUrl functions
|
|
1873
|
+
*/
|
|
1874
|
+
const useFilterUrlSync = () => {
|
|
1875
|
+
const getZodSchema = useCallback((filterType) => {
|
|
1876
|
+
if (filterType === "string") {
|
|
1877
|
+
return stringSchema;
|
|
1878
|
+
}
|
|
1879
|
+
else if (filterType === "stringArray") {
|
|
1880
|
+
return stringArraySchema;
|
|
1881
|
+
}
|
|
1882
|
+
else if (filterType === "dateRange") {
|
|
1883
|
+
return dateRangeSchema;
|
|
1884
|
+
}
|
|
1885
|
+
else if (filterType === "area") {
|
|
1886
|
+
return areaFilterGeoJsonGeometrySchema;
|
|
1887
|
+
}
|
|
1888
|
+
else if (filterType === "valueNameArray") {
|
|
1889
|
+
return valueNameArraySchema;
|
|
1890
|
+
}
|
|
1891
|
+
else if (filterType === "valueName") {
|
|
1892
|
+
return valueNameSchema;
|
|
1893
|
+
}
|
|
1894
|
+
else if (filterType === "minMax") {
|
|
1895
|
+
return minMaxFilterSchema;
|
|
1896
|
+
}
|
|
1897
|
+
else if (filterType === "boolean") {
|
|
1898
|
+
return booleanSchema;
|
|
1899
|
+
}
|
|
1900
|
+
return numberSchema;
|
|
1901
|
+
}, []);
|
|
1902
|
+
const getJsonParsedVal = useCallback((filterValue, zodSchema) => {
|
|
1903
|
+
if (!zodSchema) {
|
|
1904
|
+
return filterValue;
|
|
1905
|
+
}
|
|
1906
|
+
if (zodSchema._def.typeName === "ZodString") {
|
|
1907
|
+
return filterValue ? filterValue + "" : filterValue;
|
|
1908
|
+
}
|
|
1909
|
+
if (typeof filterValue === "string") {
|
|
1910
|
+
try {
|
|
1911
|
+
return JSON.parse(filterValue);
|
|
1912
|
+
}
|
|
1913
|
+
catch (e) {
|
|
1914
|
+
return filterValue;
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
return filterValue;
|
|
1918
|
+
}, []);
|
|
1919
|
+
const getFilterValuesFromUrl = useCallback((definitions, search) => {
|
|
1920
|
+
const loadedValues = {};
|
|
1921
|
+
definitions.forEach(filter => {
|
|
1922
|
+
const filterValue = search[filter.filterKey];
|
|
1923
|
+
if (filterValue) {
|
|
1924
|
+
const zodSchema = filter.zodSchema || getZodSchema(filter.type);
|
|
1925
|
+
const jsonParsed = getJsonParsedVal(filterValue, zodSchema);
|
|
1926
|
+
const zodParsed = zodSchema.safeParse(jsonParsed);
|
|
1927
|
+
if (zodParsed.success) {
|
|
1928
|
+
loadedValues[filter.filterKey] = zodParsed.data;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
});
|
|
1932
|
+
return loadedValues;
|
|
1933
|
+
}, [getJsonParsedVal, getZodSchema]);
|
|
1934
|
+
const getFilterValuesToUrl = useCallback((values, definitions, setEmptyAndDefaultValues, isDefaultValue) => {
|
|
1935
|
+
const urlObject = {};
|
|
1936
|
+
definitions.forEach(filter => {
|
|
1937
|
+
const value = values?.[filter.filterKey];
|
|
1938
|
+
if (value) {
|
|
1939
|
+
if (setEmptyAndDefaultValues) {
|
|
1940
|
+
urlObject[filter.filterKey] = value;
|
|
1941
|
+
}
|
|
1942
|
+
else if (!isDefaultValue(filter.filterKey, value)) {
|
|
1943
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
1944
|
+
delete urlObject[filter.filterKey];
|
|
1945
|
+
}
|
|
1946
|
+
else {
|
|
1947
|
+
urlObject[filter.filterKey] = value;
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
else {
|
|
1951
|
+
delete urlObject[filter.filterKey];
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
});
|
|
1955
|
+
return urlObject;
|
|
1956
|
+
}, []);
|
|
1957
|
+
return useMemo(() => ({
|
|
1958
|
+
getFilterValuesFromUrl,
|
|
1959
|
+
getFilterValuesToUrl,
|
|
1960
|
+
}), [getFilterValuesFromUrl, getFilterValuesToUrl]);
|
|
1961
|
+
};
|
|
1962
|
+
|
|
1963
|
+
/**
|
|
1964
|
+
* This hook provides functionality to:
|
|
1965
|
+
* - Get the length of the search parameters excluding a specific key
|
|
1966
|
+
*/
|
|
1967
|
+
const useSearchUtils = () => {
|
|
1968
|
+
const location = useLocation();
|
|
1969
|
+
const getSearchParamsLengthExcluding = useCallback((excludeKey, searchParams) => {
|
|
1970
|
+
return objectKeys(searchParams)
|
|
1971
|
+
.filter(key => key !== excludeKey)
|
|
1972
|
+
.reduce((totalLength, key) => {
|
|
1973
|
+
const keyLength = encodeURIComponent(String(key)).length;
|
|
1974
|
+
const value = searchParams[key] !== null ? encodeURIComponent(searchParams[key]?.toString() ?? "") : "";
|
|
1975
|
+
const valueLength = value.length;
|
|
1976
|
+
// Add 1 for '=' and 1 for '&' (except for the first param)
|
|
1977
|
+
return totalLength + keyLength + valueLength + (totalLength > 0 ? 2 : 1);
|
|
1978
|
+
}, 0);
|
|
1979
|
+
}, []);
|
|
1980
|
+
const getUrlLengthWithSearchParam = useCallback((key, value, prev) => {
|
|
1981
|
+
const searchParamsLength = getSearchParamsLengthExcluding(key, prev);
|
|
1982
|
+
const urlLength = location.href.length - (location.searchStr.length || 0) + (location.hash.length || 0) + searchParamsLength;
|
|
1983
|
+
// 1 === '&' and 1 === '='
|
|
1984
|
+
return urlLength + 1 + key.length + 1 + value.length;
|
|
1985
|
+
}, [getSearchParamsLengthExcluding, location]);
|
|
1986
|
+
return useMemo(() => ({ getSearchParamsLengthExcluding, getUrlLengthWithSearchParam }), [getSearchParamsLengthExcluding, getUrlLengthWithSearchParam]);
|
|
1987
|
+
};
|
|
1988
|
+
|
|
1989
|
+
const MAX_URL_LENGTH = 5000;
|
|
1832
1990
|
/**
|
|
1833
1991
|
* Get the persistence key for the filter bar.
|
|
1834
1992
|
*
|
|
@@ -1840,20 +1998,131 @@ const getPersistenceKey = (name, clientSideUserId) => `filter-${name}-${clientSi
|
|
|
1840
1998
|
/**
|
|
1841
1999
|
* Custom hook for managing the persistence of filter bar configurations.
|
|
1842
2000
|
*
|
|
2001
|
+
* This hook provides a complete state management solution for filter bars with automatic
|
|
2002
|
+
* URL synchronization and localStorage persistence. It maintains the following state:
|
|
2003
|
+
*
|
|
2004
|
+
* ## State Management Flow:
|
|
2005
|
+
*
|
|
2006
|
+
* 1. **Initial Load**:
|
|
2007
|
+
* - Loads from localStorage (if no custom loadData or saveData function is provided)
|
|
2008
|
+
* - Updates with state from URL search parameters
|
|
2009
|
+
* - Ensures URL is updated with the final state after load
|
|
2010
|
+
*
|
|
2011
|
+
* 2. **Save Operations**:
|
|
2012
|
+
* - Updates localStorage with new filter values
|
|
2013
|
+
* - Updates URL search parameters to reflect current state
|
|
2014
|
+
* - Maintains synchronization between localStorage and URL
|
|
2015
|
+
*
|
|
2016
|
+
* 3. **URL Change Detection**:
|
|
2017
|
+
* - Listens for changes in URL search parameters
|
|
2018
|
+
* - Compares URL state with last known state to detect external changes
|
|
2019
|
+
* - Triggers refreshData callback when external URL changes are detected
|
|
2020
|
+
* - Only updates URL when no custom loadData or saveData function provided
|
|
2021
|
+
*
|
|
2022
|
+
* ## Behavior Modes:
|
|
2023
|
+
*
|
|
2024
|
+
* **Default Mode** (no custom functions):
|
|
2025
|
+
* - Uses localStorage for persistence
|
|
2026
|
+
* - Automatically syncs with URL search parameters
|
|
2027
|
+
* - Handles URL updates and change detection
|
|
2028
|
+
*
|
|
2029
|
+
* **Custom Mode** (with loadData/saveData functions):
|
|
2030
|
+
* - Does NOT sync with URL or use localStorage
|
|
2031
|
+
* - Relies entirely on provided functions for persistence
|
|
2032
|
+
* - Does not provide URL change detection via refreshData callback
|
|
2033
|
+
*
|
|
2034
|
+
* The hook prevents infinite loops by:
|
|
2035
|
+
* - Tracking what state was last sent to the URL
|
|
2036
|
+
* - Only updating URL when state actually changes
|
|
2037
|
+
* - Distinguishing between internal state changes and external URL changes
|
|
2038
|
+
*
|
|
1843
2039
|
* @template TFilterBarDefinition - The type of the filter bar definition.
|
|
1844
2040
|
* @param {FilterBarPersistenceProps<TFilterBarDefinition>} props - The props for the filter bar persistence.
|
|
1845
2041
|
* @returns { object } An object containing the loadData and saveData functions.
|
|
1846
2042
|
*/
|
|
1847
|
-
const useFilterBarPersistence = ({ name, setValue, loadData: inputLoadData, saveData: inputSaveData, }) => {
|
|
2043
|
+
const useFilterBarPersistence = ({ name, setValue, refreshData, isDefaultValue, loadData: inputLoadData, saveData: inputSaveData, }) => {
|
|
1848
2044
|
const { clientSideUserId } = useCurrentUser();
|
|
2045
|
+
const search = useSearch({ strict: false });
|
|
2046
|
+
const location = useLocation();
|
|
2047
|
+
const navigate = useNavigate();
|
|
2048
|
+
const { encode, decode } = useCustomEncoding();
|
|
2049
|
+
const { getUrlLengthWithSearchParam } = useSearchUtils();
|
|
2050
|
+
const updateSearch = useCallback(async (searchParams) => {
|
|
2051
|
+
if (!inputLoadData && !inputSaveData) {
|
|
2052
|
+
// should check if the state has actually changed from what we last sent to the URL
|
|
2053
|
+
if (!searchParams[name] ||
|
|
2054
|
+
(typeof searchParams[name] === "string" &&
|
|
2055
|
+
!dequal(decode(searchParams[name]), typeof search[name] === "string" ? decode(search[name]) : search[name]))) {
|
|
2056
|
+
return requestAnimationFrame(async () => {
|
|
2057
|
+
const replace = !search[name];
|
|
2058
|
+
await navigate({
|
|
2059
|
+
to: ".",
|
|
2060
|
+
search: (prev) => {
|
|
2061
|
+
if (getUrlLengthWithSearchParam(name, searchParams[name] || "", prev) <= MAX_URL_LENGTH) {
|
|
2062
|
+
return { ...prev, ...searchParams };
|
|
2063
|
+
}
|
|
2064
|
+
else {
|
|
2065
|
+
// eslint-disable-next-line no-console
|
|
2066
|
+
console.log(`URL too long, skipping sync of filters to the browsers URL, to avoid crashing the browser, limit is ${MAX_URL_LENGTH}, was: ${getUrlLengthWithSearchParam(name, searchParams[name] || "", prev)}`);
|
|
2067
|
+
const newSearchParams = { ...prev, [name]: undefined };
|
|
2068
|
+
return newSearchParams;
|
|
2069
|
+
}
|
|
2070
|
+
},
|
|
2071
|
+
hash: location.hash,
|
|
2072
|
+
replace,
|
|
2073
|
+
});
|
|
2074
|
+
});
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
return Promise.resolve();
|
|
2078
|
+
}, [navigate, name, search, inputLoadData, inputSaveData, decode, getUrlLengthWithSearchParam, location.hash]);
|
|
1849
2079
|
const getFromLocalStorage = useCallback((persistenceKey) => {
|
|
1850
2080
|
return localStorage.getItem(getPersistenceKey(persistenceKey, clientSideUserId));
|
|
1851
2081
|
}, [clientSideUserId]);
|
|
1852
2082
|
const lastName = useRef(name);
|
|
1853
2083
|
const [initialStoredFilters] = useState(() => (!inputLoadData && getFromLocalStorage(name)) || "{}");
|
|
1854
|
-
const
|
|
2084
|
+
const { getFilterValuesFromUrl, getFilterValuesToUrl } = useFilterUrlSync();
|
|
2085
|
+
const lastSavedStateRef = useRef(undefined);
|
|
2086
|
+
const lastSearchUpdateRef = useRef(undefined);
|
|
2087
|
+
const refreshDataRef = useRef(refreshData);
|
|
2088
|
+
useEffect(() => {
|
|
2089
|
+
refreshDataRef.current = refreshData;
|
|
2090
|
+
}, [refreshData]);
|
|
2091
|
+
// Add this useEffect to detect external URL changes
|
|
2092
|
+
useEffect(() => {
|
|
2093
|
+
if (!inputLoadData && !inputSaveData) {
|
|
2094
|
+
requestAnimationFrame(() => {
|
|
2095
|
+
const currentSearchValue = search[name];
|
|
2096
|
+
let currentSearchValueParsed;
|
|
2097
|
+
let lastSearchUpdateRefParsed;
|
|
2098
|
+
try {
|
|
2099
|
+
currentSearchValueParsed = currentSearchValue ? decode(currentSearchValue) : undefined;
|
|
2100
|
+
}
|
|
2101
|
+
catch (error) {
|
|
2102
|
+
// Invalid compressed data, treat as undefined
|
|
2103
|
+
currentSearchValueParsed = undefined;
|
|
2104
|
+
}
|
|
2105
|
+
try {
|
|
2106
|
+
lastSearchUpdateRefParsed = lastSearchUpdateRef.current ? decode(lastSearchUpdateRef.current) : undefined;
|
|
2107
|
+
}
|
|
2108
|
+
catch (error) {
|
|
2109
|
+
// Invalid compressed data, treat as undefined
|
|
2110
|
+
lastSearchUpdateRefParsed = undefined;
|
|
2111
|
+
}
|
|
2112
|
+
// H4sIADGRuGgAA3WTy07eQAxGXwVlXUtje27uruqWd0C2x1NaAa2AdoN49xq6-LOgUpQo0onny7H9ctzHsy591q8_73_dxXM8xNPT8fnl-KN3v-P4fHy5vj4-HQ96__5yd3e8fjqeQh_9Nt9v48fVfayr9f3b1YrHBH3f3GDBaj4Zui-HuvsADeO8KeFGrmYrj8hCbzTZrF0coRMRVEYHGcKAsW1Iw8qiF3ox06zbASth1t4GVsqCUvIxqO9R-EJ7w2aDJnjHCbV6JtmlgOSHQzB4DLvQtiwiRGB3aUk3h0lLgdyjFiyD8USPhd55BYzakkbaSbeA2jfmFaV7v9BMErKLguWpUNdQEKwTsqqXNETL_eRkbqojy1K0pCtVkK4LJM2VPtk6lQtdcIpSs2RGno9aQG0LSJrmvgrKHCeDFWWQN0iNNZMYgczFQNtH0VbqKifaq7uVBFdvBIgRIBoClcLXQFlC7VR7E7l2PdHKnH36kN5rJFY96Z0m3mhTKv-hG8cscytgU0vLnAOlTNAWdd_TR11y8m3dsxsGyJp_2XOg5hyZOxaP2Qu6nX137DbnW5L0_S-3p9CPk2hC09sG15SXgrKrHgQlpYe6ZKl9oScNb74IOmMmmbkSYmmHdYWZ7z3baWKpiWq0nA6u2fkEYFoOS-_OtibuIqfdaa0oDytgnB2saSC3YTSI0UKIc9nofWJf_wIRCrRd6AMAAA
|
|
2113
|
+
// Check if this is an external URL change (not from our own updates)
|
|
2114
|
+
// Only trigger refreshData if there's a meaningful change in the URL value
|
|
2115
|
+
if (search[name] !== undefined && !dequal(currentSearchValueParsed, lastSearchUpdateRefParsed)) {
|
|
2116
|
+
// This is an external URL change with actual data, trigger refreshData
|
|
2117
|
+
if (refreshDataRef.current) {
|
|
2118
|
+
refreshDataRef.current();
|
|
2119
|
+
}
|
|
2120
|
+
}
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2123
|
+
}, [search, name, inputLoadData, inputSaveData, decode]);
|
|
1855
2124
|
const saveData = useCallback((filterBarConfig, filterBarDefinitions) => {
|
|
1856
|
-
const newValues = Object.assign({},
|
|
2125
|
+
const newValues = Object.assign({}, lastSavedStateRef.current || {});
|
|
1857
2126
|
if (filterBarConfig.values) {
|
|
1858
2127
|
Object.entries(filterBarConfig.values).forEach(([key, value]) => {
|
|
1859
2128
|
const typedKey = key;
|
|
@@ -1866,41 +2135,83 @@ const useFilterBarPersistence = ({ name, setValue, loadData: inputLoadData, save
|
|
|
1866
2135
|
const toPersist = {
|
|
1867
2136
|
values: newValues,
|
|
1868
2137
|
};
|
|
1869
|
-
if (!dequal(newValues,
|
|
1870
|
-
|
|
2138
|
+
if (!dequal(newValues, lastSavedStateRef.current)) {
|
|
2139
|
+
lastSavedStateRef.current = newValues;
|
|
1871
2140
|
if (inputSaveData) {
|
|
1872
2141
|
inputSaveData(newValues);
|
|
1873
2142
|
}
|
|
1874
2143
|
else {
|
|
1875
2144
|
localStorage.setItem(getPersistenceKey(name, clientSideUserId), JSON.stringify(toPersist));
|
|
2145
|
+
const urlObject = getFilterValuesToUrl(newValues, objectValues(filterBarDefinitions), false, isDefaultValue);
|
|
2146
|
+
const result = {};
|
|
2147
|
+
if (filterBarConfig.name) {
|
|
2148
|
+
result[filterBarConfig.name] = encode(urlObject);
|
|
2149
|
+
// Update the ref BEFORE updating the URL to prevent false external change detection
|
|
2150
|
+
lastSearchUpdateRef.current = result[filterBarConfig.name];
|
|
2151
|
+
}
|
|
2152
|
+
updateSearch(result);
|
|
1876
2153
|
}
|
|
1877
2154
|
}
|
|
1878
|
-
}, [name, clientSideUserId, inputSaveData,
|
|
1879
|
-
const
|
|
1880
|
-
|
|
1881
|
-
|
|
2155
|
+
}, [name, clientSideUserId, inputSaveData, getFilterValuesToUrl, updateSearch, encode, isDefaultValue]);
|
|
2156
|
+
const loadFromLocalStorage = useCallback(() => {
|
|
2157
|
+
let storedFilters = null;
|
|
2158
|
+
if (lastName.current !== name) {
|
|
2159
|
+
storedFilters = localStorage.getItem(getPersistenceKey(name, clientSideUserId)) || "{}";
|
|
2160
|
+
lastName.current = name;
|
|
1882
2161
|
}
|
|
1883
2162
|
else {
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
2163
|
+
storedFilters = initialStoredFilters;
|
|
2164
|
+
}
|
|
2165
|
+
if (storedFilters && storedFilters !== "undefined") {
|
|
2166
|
+
try {
|
|
2167
|
+
const loadedFilterBarConfigValues = JSON.parse(storedFilters);
|
|
2168
|
+
return loadedFilterBarConfigValues?.values || {};
|
|
1888
2169
|
}
|
|
1889
|
-
|
|
1890
|
-
|
|
2170
|
+
catch (error) {
|
|
2171
|
+
return {};
|
|
1891
2172
|
}
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
2173
|
+
}
|
|
2174
|
+
return {};
|
|
2175
|
+
}, [clientSideUserId, name, initialStoredFilters, lastName]);
|
|
2176
|
+
const loadFromSearchURL = useCallback(() => {
|
|
2177
|
+
let searchParams = search || {};
|
|
2178
|
+
const searchParamValue = searchParams[name];
|
|
2179
|
+
if (searchParamValue) {
|
|
2180
|
+
try {
|
|
2181
|
+
searchParams = decode(searchParamValue);
|
|
2182
|
+
}
|
|
2183
|
+
catch (error) {
|
|
2184
|
+
searchParams = {};
|
|
2185
|
+
}
|
|
2186
|
+
return searchParams;
|
|
2187
|
+
}
|
|
2188
|
+
return null;
|
|
2189
|
+
}, [search, name, decode]);
|
|
2190
|
+
const loadValues = useCallback((filterDefinitions) => {
|
|
2191
|
+
if (inputLoadData) {
|
|
2192
|
+
return inputLoadData();
|
|
2193
|
+
}
|
|
2194
|
+
else {
|
|
2195
|
+
const values = loadFromLocalStorage() || {};
|
|
2196
|
+
const searchParams = loadFromSearchURL();
|
|
2197
|
+
if (searchParams && objectKeys(searchParams).length > 0) {
|
|
2198
|
+
const valuesFromUrl = getFilterValuesFromUrl(filterDefinitions, searchParams);
|
|
2199
|
+
if (objectKeys(valuesFromUrl).length > 0) {
|
|
2200
|
+
// if there are values from the URL, update ALL filters values based on the searchParams or their defaults
|
|
2201
|
+
filterDefinitions.forEach(filter => {
|
|
2202
|
+
const key = filter.filterKey;
|
|
2203
|
+
if (key in valuesFromUrl) {
|
|
2204
|
+
values[key] = valuesFromUrl[key];
|
|
2205
|
+
}
|
|
2206
|
+
else {
|
|
2207
|
+
values[key] = filter.defaultValue;
|
|
2208
|
+
}
|
|
2209
|
+
});
|
|
1899
2210
|
}
|
|
1900
2211
|
}
|
|
1901
|
-
return
|
|
2212
|
+
return values;
|
|
1902
2213
|
}
|
|
1903
|
-
}, [inputLoadData,
|
|
2214
|
+
}, [inputLoadData, loadFromLocalStorage, getFilterValuesFromUrl, loadFromSearchURL]);
|
|
1904
2215
|
const loadData = useCallback((updatedFilterDefinitionsValues) => {
|
|
1905
2216
|
const initialStateValues = createInitialState({
|
|
1906
2217
|
name,
|
|
@@ -1908,16 +2219,22 @@ const useFilterBarPersistence = ({ name, setValue, loadData: inputLoadData, save
|
|
|
1908
2219
|
setValue,
|
|
1909
2220
|
});
|
|
1910
2221
|
const loadedFilterBarConfigValues = {
|
|
1911
|
-
values: loadValues(),
|
|
2222
|
+
values: loadValues(updatedFilterDefinitionsValues),
|
|
1912
2223
|
};
|
|
1913
2224
|
let initialFilterBarConfig;
|
|
1914
2225
|
if (loadedFilterBarConfigValues.values) {
|
|
1915
|
-
// make sure the last saved state is the same as the loaded values no manipulation of values!
|
|
1916
|
-
setLastSavedState(Object.assign({}, loadedFilterBarConfigValues.values));
|
|
1917
2226
|
if (validateFilter({
|
|
1918
2227
|
values: loadedFilterBarConfigValues.values,
|
|
1919
2228
|
filterDefinitions: updatedFilterDefinitionsValues,
|
|
1920
2229
|
})) {
|
|
2230
|
+
objectKeys(initialStateValues.values).forEach(key => {
|
|
2231
|
+
if (loadedFilterBarConfigValues.values) {
|
|
2232
|
+
loadedFilterBarConfigValues.values[key] =
|
|
2233
|
+
loadedFilterBarConfigValues.values[key] !== undefined
|
|
2234
|
+
? loadedFilterBarConfigValues.values[key]
|
|
2235
|
+
: initialStateValues.values[key];
|
|
2236
|
+
}
|
|
2237
|
+
});
|
|
1921
2238
|
initialFilterBarConfig = {
|
|
1922
2239
|
values: loadedFilterBarConfigValues.values,
|
|
1923
2240
|
name: name,
|
|
@@ -1939,9 +2256,17 @@ const useFilterBarPersistence = ({ name, setValue, loadData: inputLoadData, save
|
|
|
1939
2256
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1940
2257
|
initialFilterBarConfig.setters[`set${capitalize(key)}`] = (callback) => setValue(key, callback);
|
|
1941
2258
|
});
|
|
2259
|
+
const urlObject = getFilterValuesToUrl(initialFilterBarConfig.values, updatedFilterDefinitionsValues, false, isDefaultValue);
|
|
2260
|
+
const result = {};
|
|
2261
|
+
if (initialFilterBarConfig.name) {
|
|
2262
|
+
result[initialFilterBarConfig.name] = encode(JSON.stringify(urlObject));
|
|
2263
|
+
// Update the ref BEFORE updating the URL to prevent false external change detection
|
|
2264
|
+
lastSearchUpdateRef.current = result[initialFilterBarConfig.name];
|
|
2265
|
+
}
|
|
2266
|
+
updateSearch(result);
|
|
1942
2267
|
return initialFilterBarConfig;
|
|
1943
|
-
}, [name, setValue, loadValues]);
|
|
1944
|
-
return useMemo(() => ({ loadData, saveData }), [loadData, saveData]);
|
|
2268
|
+
}, [name, setValue, loadValues, getFilterValuesToUrl, updateSearch, encode, isDefaultValue]);
|
|
2269
|
+
return useMemo(() => ({ loadData, saveData, getFilterValuesToUrl }), [loadData, saveData, getFilterValuesToUrl]);
|
|
1945
2270
|
};
|
|
1946
2271
|
|
|
1947
2272
|
/**
|
|
@@ -1974,21 +2299,18 @@ const useGenericSetValue = () => {
|
|
|
1974
2299
|
const useFilterBar = ({ name, onValuesChange, filterBarDefinition, loadData: inputLoadData, saveData: inputSaveData, }) => {
|
|
1975
2300
|
const lastName = useRef(name);
|
|
1976
2301
|
const { setValue } = useGenericSetValue();
|
|
2302
|
+
const { isDefaultValue } = useIsDefaultValue();
|
|
1977
2303
|
const { loadData, saveData } = useFilterBarPersistence({
|
|
1978
2304
|
name,
|
|
2305
|
+
isDefaultValue: (key, value) => isDefaultValue(key, value, filterBarDefinition),
|
|
1979
2306
|
setValue: (key, callback) => setValue(setFilterBarConfig, key, callback),
|
|
2307
|
+
refreshData: () => setFilterBarConfig(loadData(objectValues(filterBarDefinition))),
|
|
1980
2308
|
loadData: inputLoadData,
|
|
1981
2309
|
saveData: inputSaveData,
|
|
1982
2310
|
});
|
|
1983
2311
|
const [filterBarConfig, setFilterBarConfig] = useState(() => {
|
|
1984
2312
|
return loadData(objectValues(filterBarDefinition));
|
|
1985
2313
|
});
|
|
1986
|
-
useEffect(() => {
|
|
1987
|
-
if (lastName.current !== name) {
|
|
1988
|
-
setFilterBarConfig(loadData(objectValues(filterBarDefinition)));
|
|
1989
|
-
lastName.current = name;
|
|
1990
|
-
}
|
|
1991
|
-
}, [filterBarDefinition, loadData, name]);
|
|
1992
2314
|
const { filterMapActions, filterMapGetter } = useFilterBarActions({
|
|
1993
2315
|
name,
|
|
1994
2316
|
filterBarConfig,
|
|
@@ -1997,10 +2319,20 @@ const useFilterBar = ({ name, onValuesChange, filterBarDefinition, loadData: inp
|
|
|
1997
2319
|
setFilterBarConfig,
|
|
1998
2320
|
setValue: (key, callback) => setValue(setFilterBarConfig, key, callback),
|
|
1999
2321
|
});
|
|
2322
|
+
const onValuesChangeRef = useRef(onValuesChange);
|
|
2323
|
+
useEffect(() => {
|
|
2324
|
+
onValuesChangeRef.current = onValuesChange;
|
|
2325
|
+
}, [onValuesChange]);
|
|
2000
2326
|
useEffect(() => {
|
|
2001
2327
|
saveData(filterBarConfig, filterBarDefinition);
|
|
2002
|
-
|
|
2003
|
-
}, [filterBarConfig, filterBarDefinition,
|
|
2328
|
+
onValuesChangeRef.current?.(filterBarConfig.values);
|
|
2329
|
+
}, [filterBarConfig, filterBarDefinition, saveData]);
|
|
2330
|
+
useEffect(() => {
|
|
2331
|
+
if (lastName.current !== name) {
|
|
2332
|
+
setFilterBarConfig(loadData(objectValues(filterBarDefinition)));
|
|
2333
|
+
lastName.current = name;
|
|
2334
|
+
}
|
|
2335
|
+
}, [filterBarDefinition, loadData, name]);
|
|
2004
2336
|
return useMemo(() => {
|
|
2005
2337
|
return {
|
|
2006
2338
|
filterBarConfig: { ...filterBarConfig, ...filterMapActions, ...filterMapGetter },
|
|
@@ -2020,13 +2352,20 @@ const useFilterBar = ({ name, onValuesChange, filterBarDefinition, loadData: inp
|
|
|
2020
2352
|
const useFilterBarAsync = ({ name, onValuesChange, filterBarDefinition, loadData: inputLoadData, saveData: inputSaveData, }) => {
|
|
2021
2353
|
const [isDataLoaded, setIsDataLoaded] = useState(false);
|
|
2022
2354
|
const [asyncLoadedFilterBarDefinitions, setAsyncLoadedFilterBarDefinitions] = useState();
|
|
2355
|
+
const { isDefaultValue } = useIsDefaultValue();
|
|
2023
2356
|
const internalFilterBarDefinitions = useMemo(() => asyncLoadedFilterBarDefinitions ?? filterBarDefinition, [filterBarDefinition, asyncLoadedFilterBarDefinitions]);
|
|
2024
2357
|
const { setValue } = useGenericSetValue();
|
|
2025
2358
|
const { loadData, saveData } = useFilterBarPersistence({
|
|
2026
2359
|
name,
|
|
2360
|
+
isDefaultValue: (key, value) => isDefaultValue(key, value, filterBarDefinition, filterBarConfig.initialState),
|
|
2027
2361
|
setValue: (key, callback) => setValue(setFilterBarConfig, key, callback),
|
|
2028
2362
|
loadData: inputLoadData,
|
|
2029
2363
|
saveData: inputSaveData,
|
|
2364
|
+
refreshData: () => {
|
|
2365
|
+
if (asyncLoadedFilterBarDefinitions) {
|
|
2366
|
+
setFilterBarConfig(loadData(objectValues(asyncLoadedFilterBarDefinitions)));
|
|
2367
|
+
}
|
|
2368
|
+
},
|
|
2030
2369
|
});
|
|
2031
2370
|
const [filterBarConfig, setFilterBarConfig] = useState(() => {
|
|
2032
2371
|
const initialConfig = {
|
|
@@ -2037,13 +2376,16 @@ const useFilterBarAsync = ({ name, onValuesChange, filterBarDefinition, loadData
|
|
|
2037
2376
|
};
|
|
2038
2377
|
return initialConfig;
|
|
2039
2378
|
});
|
|
2379
|
+
const setValueMemoized = useCallback((key, callback) => {
|
|
2380
|
+
setValue(setFilterBarConfig, key, callback);
|
|
2381
|
+
}, [setFilterBarConfig, setValue]);
|
|
2040
2382
|
const { filterMapActions, filterMapGetter } = useFilterBarActions({
|
|
2041
2383
|
name,
|
|
2042
2384
|
filterBarConfig,
|
|
2043
2385
|
filterBarDefinition: internalFilterBarDefinitions,
|
|
2044
2386
|
initialState: filterBarConfig.initialState,
|
|
2045
2387
|
setFilterBarConfig,
|
|
2046
|
-
setValue:
|
|
2388
|
+
setValue: setValueMemoized,
|
|
2047
2389
|
});
|
|
2048
2390
|
const dataLoaded = useCallback((loadedFilterDefinitionsValues) => {
|
|
2049
2391
|
setIsDataLoaded(false);
|
|
@@ -2082,19 +2424,18 @@ const useFilterBarAsync = ({ name, onValuesChange, filterBarDefinition, loadData
|
|
|
2082
2424
|
* The parameter is validated using the provided Zod schema.
|
|
2083
2425
|
*
|
|
2084
2426
|
* @template T - A Zod schema used for validation.
|
|
2085
|
-
* @param {string} searchParamName - The name of the search parameter in the URL.
|
|
2086
2427
|
* @param {string} filterName - The name of the filter.
|
|
2087
2428
|
* @param {object} search - The current search state, provided by `useSearch` from @tanstack/react-router.
|
|
2088
2429
|
* @param {T} zodSchema - The Zod schema for validating the filter data.
|
|
2089
2430
|
* @param {ErrorHandlingContextValue} errorHandler - Error handling context for capturing and reporting exceptions.
|
|
2090
2431
|
* @returns {any} The parsed filter data if validation succeeds, otherwise `null`.
|
|
2091
2432
|
*/
|
|
2092
|
-
const useSearchParamAsFilter = ({
|
|
2433
|
+
const useSearchParamAsFilter = ({ filterName, search, zodSchema, errorHandler, }) => {
|
|
2093
2434
|
return useMemo(() => {
|
|
2094
|
-
if (!objectKeys(search).includes(
|
|
2435
|
+
if (!objectKeys(search).includes(filterName)) {
|
|
2095
2436
|
return null;
|
|
2096
2437
|
}
|
|
2097
|
-
const foundParam = search[
|
|
2438
|
+
const foundParam = search[filterName];
|
|
2098
2439
|
try {
|
|
2099
2440
|
const getJsonParsedVal = () => {
|
|
2100
2441
|
if (zodSchema._def.typeName === "ZodString") {
|
|
@@ -2125,7 +2466,7 @@ const useSearchParamAsFilter = ({ searchParamName, filterName, search, zodSchema
|
|
|
2125
2466
|
zodParseError: null,
|
|
2126
2467
|
});
|
|
2127
2468
|
}
|
|
2128
|
-
}, [search,
|
|
2469
|
+
}, [search, zodSchema, errorHandler, filterName]);
|
|
2129
2470
|
};
|
|
2130
2471
|
const captureUrlParseException = (errorHandler, { filterName, param, jsonParsed: parsed }) => errorHandler.captureException(new Error(JSON.stringify({
|
|
2131
2472
|
info: `Received invalid values for ${filterName} from URL query params. Can't set ${filterName} filter with this. Please fix the URL query params (or schema).`,
|
|
@@ -2154,4 +2495,4 @@ const mergeFilters = (filterBarDefinition, extraFilters) => {
|
|
|
2154
2495
|
*/
|
|
2155
2496
|
setupLibraryTranslations();
|
|
2156
2497
|
|
|
2157
|
-
export { AppliedFiltersRenderer, DefaultCheckboxFilter, DefaultDateRangeFilter, DefaultMinMaxFilter, DefaultRadioFilter, DynamicFilterList, FilterBar, FilterButtonTooltipLabel, FilterComponent, FilterEvents, FilterHeader, FilterResults, FilterTableComponent, FiltersMenu, FiltersMenuContent, FiltersRenderer, GroupedFiltersList, HierarchicalCheckboxFilter, MultipleFilterTooltipLabel, ResetFiltersButton, TooltipLabel, areaFilterGeoJsonGeometrySchema, isAreaFilterValue, isArrayFilterValue, isBooleanValue, isDateRangeValue, isMinMaxFilterValue, isStringArrayFilterValue, isValueName, isValueNameArray, mergeFilters, mockFilterBar, toggleFilterValue, useFilterBar, useFilterBarAsync, useFiltersMenu, useSearchParamAsFilter, validateFilter };
|
|
2498
|
+
export { AppliedFiltersRenderer, DefaultCheckboxFilter, DefaultDateRangeFilter, DefaultMinMaxFilter, DefaultRadioFilter, DynamicFilterList, FilterBar, FilterButtonTooltipLabel, FilterComponent, FilterEvents, FilterHeader, FilterResults, FilterTableComponent, FiltersMenu, FiltersMenuContent, FiltersRenderer, GroupedFiltersList, HierarchicalCheckboxFilter, MultipleFilterTooltipLabel, ResetFiltersButton, TooltipLabel, areaFilterGeoJsonGeometrySchema, booleanSchema, dateRangeSchema, isAreaFilterValue, isArrayFilterValue, isBooleanValue, isDateRangeValue, isMinMaxFilterValue, isStringArrayFilterValue, isValueName, isValueNameArray, mergeFilters, minMaxFilterSchema, mockFilterBar, numberSchema, stringArraySchema, stringSchema, toggleFilterValue, useFilterBar, useFilterBarAsync, useFiltersMenu, useSearchParamAsFilter, validateFilter, valueNameArraySchema, valueNameSchema };
|