"use client"; import { Box, TextField, MenuItem, Button, Drawer, FormControl, Select, Typography, Stack, debounce, } from "@mui/material"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import SearchIcon from "@mui/icons-material/Search"; import RefreshIcon from "@mui/icons-material/Refresh"; import { useDispatch, useSelector } from "react-redux"; import { useState, useEffect, useMemo } from "react"; import { ISearchLabel } from "../DataTable/types"; import { AppDispatch } from "@/app/redux/store"; import { updateFilter, clearFilters, FilterValue, } from "@/app/redux/advanedSearch/advancedSearchSlice"; import { selectFilters } from "@/app/redux/advanedSearch/selectors"; import { normalizeValue, defaultOperatorForField } from "./utils/utils"; // ----------------------------------------------------- // COMPONENT // ----------------------------------------------------- export default function AdvancedSearch({ labels }: { labels: ISearchLabel[] }) { const dispatch = useDispatch(); const filters = useSelector(selectFilters); const [open, setOpen] = useState(false); // Local form state for UI (synced with Redux) const [formValues, setFormValues] = useState>({}); const [operators, setOperators] = useState>({}); // ----------------------------------------------------- // SYNC REDUX FILTERS TO LOCAL STATE ON LOAD // ----------------------------------------------------- useEffect(() => { const values: Record = {}; const ops: Record = {}; labels.forEach(({ field, type }) => { const filter = filters[field]; if (filter) { if (typeof filter === "string") { // Simple string filter values[field] = filter; ops[field] = defaultOperatorForField(field, type); } else { // FilterValue object with operator and value values[field] = filter.value; ops[field] = filter.operator; } } // Handle date ranges const startKey = `${field}_start`; const endKey = `${field}_end`; const startFilter = filters[startKey]; const endFilter = filters[endKey]; if (startFilter && typeof startFilter === "string") { values[startKey] = startFilter; } if (endFilter && typeof endFilter === "string") { values[endKey] = endFilter; } }); setFormValues(values); setOperators(ops); }, [filters, labels]); // ----------------------------------------------------- // DEBOUNCED FILTER UPDATE // ----------------------------------------------------- const debouncedUpdateFilter = useMemo( () => debounce( (field: string, value: string | undefined, operator?: string) => { if (!value || value === "") { dispatch(updateFilter({ field, value: undefined })); return; } const safeValue = normalizeValue(value); if (!safeValue) { dispatch(updateFilter({ field, value: undefined })); return; } // For text/select fields, use FilterValue with operator const filterValue: FilterValue = { operator: operator ?? defaultOperatorForField(field, "text"), value: safeValue, }; dispatch(updateFilter({ field, value: filterValue })); }, 300 ), [dispatch] ); // ----------------------------------------------------- // handlers // ----------------------------------------------------- const updateField = (field: string, value: string) => { setFormValues(prev => ({ ...prev, [field]: value })); const operator = operators[field] ?? defaultOperatorForField(field, "text"); debouncedUpdateFilter(field, value, operator); }; const updateOperator = (field: string, op: string) => { setOperators(prev => ({ ...prev, [field]: op })); // If value exists, update filter immediately with new operator const currentValue = formValues[field]; if (currentValue) { const safeValue = normalizeValue(currentValue); if (safeValue) { dispatch( updateFilter({ field, value: { operator: op, value: safeValue }, }) ); } } }; const updateDateRange = ( field: string, start: string | undefined, end: string | undefined ) => { if (start) { dispatch(updateFilter({ field: `${field}_start`, value: start })); } else { dispatch(updateFilter({ field: `${field}_start`, value: undefined })); } if (end) { dispatch(updateFilter({ field: `${field}_end`, value: end })); } else { dispatch(updateFilter({ field: `${field}_end`, value: undefined })); } }; const resetForm = () => { setFormValues({}); setOperators({}); dispatch(clearFilters()); }; // ----------------------------------------------------- // render // ----------------------------------------------------- return ( setOpen(false)}> Search