diff --git a/src/core/hooks/useNodeFilters.ts b/src/core/hooks/useNodeFilters.ts index 85039b16..344b924f 100644 --- a/src/core/hooks/useNodeFilters.ts +++ b/src/core/hooks/useNodeFilters.ts @@ -6,7 +6,7 @@ interface BooleanFilter { key: string; label: string; type: "boolean"; - predicate: (node: Node, value: boolean) => boolean; + predicate: (node: Protobuf.Mesh.NodeInfo, value: boolean) => boolean; } interface RangeFilter { @@ -14,14 +14,14 @@ interface RangeFilter { label: string; type: "range"; bounds: [number, number]; - predicate: (node: Node, value: [number, number]) => boolean; + predicate: (node: Protobuf.Mesh.NodeInfo, value: [number, number]) => boolean; } interface SearchFilter { key: string; label: string; type: "search"; - predicate: (node: Node, value: string) => boolean; + predicate: (node: Protobuf.Mesh.NodeInfo, value: string) => boolean; } export type FilterConfig = BooleanFilter | RangeFilter | SearchFilter; @@ -113,7 +113,7 @@ export function useNodeFilters(nodes: Protobuf.Mesh.NodeInfo[]) { acc[cfg.key] = false; break; case "range": - acc[cfg.key] = cfg.bounds!; + acc[cfg.key] = cfg.bounds; break; case "search": acc[cfg.key] = ""; @@ -141,13 +141,36 @@ export function useNodeFilters(nodes: Protobuf.Mesh.NodeInfo[]) { const filteredNodes = useMemo( () => nodes.filter((node) => - filterConfigs.every((cfg) => cfg.predicate(node, filters[cfg.key])) + filterConfigs.every((cfg) => { + const val = filters[cfg.key]; + switch (cfg.type) { + case "boolean": + if (typeof val !== "boolean") return true; + return cfg.predicate(node, val); + + case "range": + if ( + !Array.isArray(val) || + val.length !== 2 || + typeof val[0] !== "number" || + typeof val[1] !== "number" + ) { + return true; + } + return cfg.predicate(node, val); + + case "search": + if (typeof val !== "string") return true; + return cfg.predicate(node, val); + } + }) ), [nodes, filters], ); return { filters, + defaultState, onFilterChange, resetFilters, filteredNodes, diff --git a/src/pages/Map/FilterControl.tsx b/src/pages/Map/FilterControl.tsx index a8313d5d..cace3ebb 100644 --- a/src/pages/Map/FilterControl.tsx +++ b/src/pages/Map/FilterControl.tsx @@ -10,6 +10,7 @@ import type { FilterConfig, FilterValueMap, } from "@core/hooks/useNodeFilters.ts"; +import { cn } from "@core/utils/cn.ts"; interface FilterControlProps { configs: FilterConfig[]; @@ -19,18 +20,25 @@ interface FilterControlProps { value: FilterValueMap[K], ) => void; resetFilters: () => void; + isDirty: boolean; children?: React.ReactNode; } export function FilterControl( - { configs, values, onChange, resetFilters, children }: FilterControlProps, + { configs, values, onChange, resetFilters, isDirty, children }: + FilterControlProps, ) { return (