2025-08-06 09:41:20 +02:00

218 lines
7.4 KiB
TypeScript

"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 { useSearchParams, useRouter } from "next/navigation";
import { useState, useEffect, useMemo } from "react";
import { ISearchLabel } from "../DataTable/types";
export default function AdvancedSearch({ labels }: { labels: ISearchLabel[] }) {
const searchParams = useSearchParams();
const router = useRouter();
const [open, setOpen] = useState(false);
const [formValues, setFormValues] = useState<Record<string, string>>({});
useEffect(() => {
const initialParams = Object.fromEntries(searchParams.entries());
setFormValues(initialParams);
}, [searchParams]);
const updateURL = useMemo(
() =>
debounce((newValues: Record<string, string>) => {
const updatedParams = new URLSearchParams();
Object.entries(newValues).forEach(([key, value]) => {
if (value) updatedParams.set(key, value);
});
router.push(`?${updatedParams.toString()}`);
}, 500),
[router],
);
const handleFieldChange = (field: string, value: string) => {
const updatedValues = { ...formValues, [field]: value };
console.log(updatedValues);
setFormValues(updatedValues);
updateURL(updatedValues);
};
const resetForm = () => {
setFormValues({});
router.push("?");
};
const toggleDrawer =
(open: boolean) => (event: React.KeyboardEvent | React.MouseEvent) => {
if (
event.type === "keydown" &&
((event as React.KeyboardEvent).key === "Tab" ||
(event as React.KeyboardEvent).key === "Shift")
) {
return;
}
setOpen(open);
};
return (
<Box sx={{ width: "185px" }}>
<Button
sx={{
borderRadius: "8px",
textTransform: "none",
backgroundColor: "#f5f5f5",
color: "#555",
padding: "6px 12px",
boxShadow: "inset 0 0 0 1px #ddd",
fontWeight: 400,
fontSize: "16px",
justifyContent: "flex-start",
"& .MuiButton-startIcon": {
borderRadius: "4px",
display: "flex",
alignItems: "center",
justifyContent: "center",
},
"&:hover": {
backgroundColor: "#e0e0e0",
},
}}
startIcon={<SearchIcon />}
onClick={toggleDrawer(true)}
>
Advanced Search
</Button>
<Drawer anchor="right" open={open} onClose={toggleDrawer(false)}>
<Box sx={{ width: 400 }} role="presentation">
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Box p={2}>
<Box sx={{ display: "flex", gap: "60px" }}>
<Typography variant="h6" gutterBottom>
Search
</Typography>
<Box display="flex" justifyContent="flex-end" gap={2}>
<Button
variant="contained"
startIcon={<SearchIcon />}
onClick={() => console.log("Params:", formValues)}
>
Apply Filter
</Button>
<Button
variant="outlined"
startIcon={<RefreshIcon />}
onClick={resetForm}
/>
</Box>
</Box>
<Stack spacing={2}>
{labels?.map(({ label, field, type, options }) => (
<Box key={field}>
<Typography variant="body2" fontWeight={600} mb={0.5}>
{label}
</Typography>
{type === "text" && (
<TextField
fullWidth
size="small"
value={formValues[field] || ""}
onChange={(e) =>
handleFieldChange(field, e.target.value)
}
/>
)}
{type === "select" && (
<FormControl fullWidth size="small">
<Select
value={formValues[field] || ""}
onChange={(e) =>
handleFieldChange(field, e.target.value)
}
displayEmpty
>
<MenuItem value="">
<em>{label}</em>
</MenuItem>
{options?.map((option) => (
<MenuItem value={option} key={option}>
{option}
</MenuItem>
))}
</Select>
</FormControl>
)}
{type === "date" && (
<Stack spacing={2}>
<DatePicker
label="Start Date"
value={
formValues[`${field}_start`]
? new Date(formValues[`${field}_start`])
: null
}
onChange={(newValue) => {
if (!newValue)
return handleFieldChange(`${field}_start`, "");
const start = new Date(newValue);
start.setHours(0, 0, 0, 0); // force start of day
handleFieldChange(
`${field}_start`,
start.toISOString(),
);
}}
slotProps={{
textField: { fullWidth: true, size: "small" },
}}
/>
<DatePicker
label="End Date"
value={
formValues[`${field}_end`]
? new Date(formValues[`${field}_end`])
: null
}
onChange={(newValue) => {
if (!newValue)
return handleFieldChange(`${field}_end`, "");
const end = new Date(newValue);
end.setHours(23, 59, 59, 999); // force end of day
handleFieldChange(
`${field}_end`,
end.toISOString(),
);
}}
slotProps={{
textField: { fullWidth: true, size: "small" },
}}
/>
</Stack>
)}
</Box>
))}
</Stack>
</Box>
</LocalizationProvider>
</Box>
</Drawer>
</Box>
);
}