import * as React from "react"; import { Box, Button, Paper, TextField, Autocomplete, Typography, } from "@mui/material"; import FilterListIcon from "@mui/icons-material/FilterList"; import { ResourceField, ResourceMode } from "../types/config"; function extractOptions( fieldName: string, field: ResourceField, data: any[] ): string[] { const values = new Set(); if (field.options) return field.options; if (!data) return []; const pull = (item: any): string | null => { if (item == null) return null; if (typeof item === "string") return item; if (typeof item !== "object") return String(item); const df = field.displayField; if (!df) { debugger; return null; } if (Array.isArray(df)) { const parts = df.map((k) => item[k]).filter((v) => v != null); if (parts.length > 0) return parts.join(" "); } else { const v = item[df]; if (v != null) return String(v); } debugger; return null; }; for (const row of data) { const v = row[fieldName]; if (v == null) continue; if (Array.isArray(v)) { for (const el of v) { const label = pull(el); if (label) values.add(label); } } else { const label = pull(v); if (label) values.add(label); } } // console.log('extracted', fieldName, Array.from(values).sort()) return Array.from(values).sort(); } function renderFilterInput( fieldName: string, field: ResourceField, options: string[], value: any, onChange: (key: string, val: any) => void ) { const filterType = field.filterType; if (filterType === "number-range") { const rangeVal = (value as { min?: string; max?: string }) || {}; return ( {field.label} onChange("min", e.target.value || undefined)} sx={{ width: 120 }} /> onChange("max", e.target.value || undefined)} sx={{ width: 120 }} /> ); } if (filterType === "date-range") { const rangeVal = (value as { start?: string; end?: string }) || {}; return ( {field.label} onChange("start", e.target.value || undefined)} InputLabelProps={{ shrink: true }} sx={{ width: 190 }} /> onChange("end", e.target.value || undefined)} InputLabelProps={{ shrink: true }} sx={{ width: 190 }} /> ); } if (filterType === "multiselect") { const selected = Array.isArray(value) ? value : []; return ( onChange("value", val.length > 0 ? val : undefined)} renderInput={(params) => ( )} sx={{ minWidth: 220 }} size="small" /> ); } const selected = Array.isArray(value) ? value : []; return ( onChange("value", val.length > 0 ? val : undefined)} ChipProps={{ size: 'small' }} renderInput={(params) => ( )} sx={{ minWidth: 220 }} size="small" /> ); } export interface FilterBarProps { fields: Record; filterableFields: string[]; mode: ResourceMode; data?: any[]; appliedValues: Record; onApply: (values: Record) => void; onClear: () => void; } export default function FilterBar({ fields, filterableFields, data, appliedValues, onApply, onClear, }: FilterBarProps) { const [open, setOpen] = React.useState(false); const [draft, setDraft] = React.useState>(() => ({ ...appliedValues })); React.useEffect(() => { if (!open) setDraft({ ...appliedValues }); }, [appliedValues, open]); if (!filterableFields || filterableFields.length === 0) return null; const activeCount = Object.keys(appliedValues).filter((k) => { const v = appliedValues[k]; if (v == null || v === "") return false; if (typeof v === "object" && Object.values(v).every((x) => x == null || x === "")) return false; return true; }).length; const handleApply = () => onApply({ ...draft }); const handleClear = () => { setDraft({}); onClear(); }; const updateDraft = (fieldName: string, key: string, val: any) => { setDraft((prev) => { if (key === "value") { return { ...prev, [fieldName]: val }; } const existing = prev[fieldName] || {}; return { ...prev, [fieldName]: { ...existing, [key]: val } }; }); }; return ( setOpen((o) => !o)} > {open ? "Hide Filters" : "Show Filters"} {activeCount > 0 && ( {activeCount} active )} {open && ( {filterableFields.map((fieldName) => { const field = fields[fieldName]; if (!field) return null; const needsOptions = !field.filterType || field.filterType === "autocomplete" || field.filterType === "multiselect"; const options = needsOptions ? extractOptions(fieldName, field, data ?? []) : []; const raw = draft[fieldName]; return ( {renderFilterInput(fieldName, field, options, raw, (key, val) => updateDraft(fieldName, key, val) )} ); })} )} ); }