diff --git a/src/components/dashboard/roadSafety/operator/OperatorList.jsx b/src/components/dashboard/roadSafety/operator/OperatorList.jsx
index 0e889da..13a530c 100644
--- a/src/components/dashboard/roadSafety/operator/OperatorList.jsx
+++ b/src/components/dashboard/roadSafety/operator/OperatorList.jsx
@@ -121,8 +121,8 @@ const OperatorList = () => {
props.dependencyFieldValue?.value === ""
? "empty"
: loadingEdaratList
- ? "loading"
- : props.filterParameters.value
+ ? "loading"
+ : props.filterParameters.value
}
columnSelectOption={getColumnSelectOptions}
/>
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/ActionDate.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/ActionDate.jsx
deleted file mode 100644
index 431c7ac..0000000
--- a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/ActionDate.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
-import { Box } from "@mui/material";
-
-const ActionDate = ({ value, onChange, error }) => {
- return (
-
- {
- onChange([formattedDate, value[1]]);
- }}
- maxDate={value[1]}
- placeholder={`از تاریخ`}
- />
- {
- onChange([value[0], formattedDate]);
- }}
- minDate={value[0]}
- placeholder={`تا تاریخ`}
- helperText={error ? error.message : null}
- error={Boolean(error)}
- />
-
- );
-};
-export default ActionDate;
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/ActivityDateTimeFilter.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/ActivityDateTimeFilter.jsx
deleted file mode 100644
index 143c0cd..0000000
--- a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/ActivityDateTimeFilter.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
-import { Box } from "@mui/material";
-
-const ActivityDateTimeFilter = ({ value, onChange, error }) => {
- return (
-
- {
- onChange([formattedDate, value[1]]);
- }}
- maxDate={value[1]}
- placeholder={`از تاریخ`}
- />
- {
- onChange([value[0], formattedDate]);
- }}
- minDate={value[0]}
- placeholder={`تا تاریخ`}
- helperText={error ? error.message : null}
- error={Boolean(error)}
- />
-
- );
-};
-export default ActivityDateTimeFilter;
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/AxisTypeFilter.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/AxisTypeFilter.jsx
deleted file mode 100644
index 037a6a2..0000000
--- a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/AxisTypeFilter.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
-
-const AxisTypeFilter = ({ value, onChange }) => {
- const axisOptions = [
- { value: "", label: "همه محور ها" },
- { value: 1, label: "آزادراه" },
- { value: 2, label: "بزرگراه" },
- { value: 3, label: "اصلی" },
- { value: 4, label: "فرعی" },
- { value: 5, label: "روستایی" },
- ];
-
- return (
-
-
- نوع محور
-
- }
- size="small"
- onChange={(e) => onChange(e.target.value)}
- displayEmpty
- >
- {axisOptions.map((option) => (
-
- ))}
-
-
- );
-};
-export default AxisTypeFilter;
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/CreatedAtFilter.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/CreatedAtFilter.jsx
deleted file mode 100644
index 1bcffba..0000000
--- a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/CreatedAtFilter.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
-import { Box } from "@mui/material";
-
-const CreatedAtFilter = ({ value, onChange, error }) => {
- return (
-
- {
- onChange([formattedDate, value[1]]);
- }}
- maxDate={value[1]}
- placeholder={`از تاریخ`}
- />
- {
- onChange([value[0], formattedDate]);
- }}
- minDate={value[0]}
- placeholder={`تا تاریخ`}
- helperText={error ? error.message : null}
- error={Boolean(error)}
- />
-
- );
-};
-export default CreatedAtFilter;
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/EdarehShahriFilter.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/EdarehShahriFilter.jsx
deleted file mode 100644
index eb08e27..0000000
--- a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/EdarehShahriFilter.jsx
+++ /dev/null
@@ -1,65 +0,0 @@
-"use client";
-import useEdaratLists from "@/lib/hooks/useEdaratLists";
-import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
-import { useEffect, useMemo, useState } from "react";
-import { useWatch } from "react-hook-form";
-
-const EdarehShahriFilter = ({ control, value, onChange }) => {
- const dependencyField = useWatch({ control, name: "province_id" });
- return ;
-};
-
-const EdarehShahriController = ({ value, onChange, dependencyField }) => {
- const { edaratList, loadingEdaratList, errorEdaratList } = useEdaratLists(dependencyField);
- const [prevDependency, setPrevDependency] = useState(dependencyField);
-
- const columnSelectOption = useMemo(() => {
- if (dependencyField === "") {
- return [{ value: "empty", label: "ابتدا استان را انتخاب کنید" }];
- }
- if (loadingEdaratList) {
- return [{ value: "loading", label: "در حال بارگذاری..." }];
- }
- if (errorEdaratList) {
- return [{ value: "error", label: "خطا در بارگذاری" }];
- }
- return [
- { value: "", label: "کل ادارات" },
- ...edaratList.map((edare) => ({
- value: edare.id,
- label: edare.name_fa,
- })),
- ];
- }, [edaratList, loadingEdaratList, errorEdaratList]);
-
- useEffect(() => {
- if (prevDependency === dependencyField) return;
- onChange("");
- setPrevDependency(dependencyField);
- }, [dependencyField]);
-
- return (
-
-
- اداره
-
- }
- size="small"
- onChange={(e) => onChange(e.target.value)}
- displayEmpty
- >
- {columnSelectOption.map((option) => (
-
- ))}
-
-
- );
-};
-export default EdarehShahriFilter;
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/InfoFilter.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/InfoFilter.jsx
deleted file mode 100644
index 605c0af..0000000
--- a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/InfoFilter.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import useSafetyAndPrivacyGetItems from "@/lib/hooks/useSafetyAndPrivacyGetItems";
-import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
-import { useMemo } from "react";
-
-const InfoFilter = ({ value, onChange }) => {
- const { itemsList, loadingItemsList, errorItemsList } = useSafetyAndPrivacyGetItems();
- const columnSelectOption = useMemo(() => {
- if (loadingItemsList) {
- return [{ value: "loading", label: "در حال بارگذاری..." }];
- }
- if (errorItemsList) {
- return [{ value: "error", label: "خطا در بارگذاری" }];
- }
- return [
- { value: "", label: "همه موارد" },
- ...itemsList.map((item) => ({
- value: item.id,
- label: item.name,
- })),
- ];
- }, [itemsList, loadingItemsList, errorItemsList]);
-
- return (
-
-
- مورد مشاهده شده
-
- }
- size="small"
- onChange={(e) => onChange(e.target.value)}
- displayEmpty
- >
- {columnSelectOption.map((option) => (
-
- ))}
-
-
- );
-};
-export default InfoFilter;
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/JudiciaryDocumentUploadDateFilter.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/JudiciaryDocumentUploadDateFilter.jsx
deleted file mode 100644
index 24a6b2f..0000000
--- a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/JudiciaryDocumentUploadDateFilter.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
-import { Box } from "@mui/material";
-
-const JudiciaryDocumentUploadDateFilter = ({ value, onChange, error }) => {
- return (
-
- {
- onChange([formattedDate, value[1]]);
- }}
- maxDate={value[1]}
- placeholder={`از تاریخ`}
- />
- {
- onChange([value[0], formattedDate]);
- }}
- minDate={value[0]}
- placeholder={`تا تاریخ`}
- helperText={error ? error.message : null}
- error={Boolean(error)}
- />
-
- );
-};
-export default JudiciaryDocumentUploadDateFilter;
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/ProvinceFilter.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/ProvinceFilter.jsx
deleted file mode 100644
index 4de3f9e..0000000
--- a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/ProvinceFilter.jsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import useProvinces from "@/lib/hooks/useProvince";
-import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
-import { useMemo } from "react";
-
-const ProvinceFilter = ({ value, onChange }) => {
- const { provinces, errorProvinces, loadingProvinces } = useProvinces();
- const columnSelectOption = useMemo(() => {
- if (loadingProvinces) {
- return [{ value: "loading", label: "در حال بارگذاری..." }];
- }
- if (errorProvinces) {
- return [{ value: "error", label: "خطا در بارگذاری" }];
- }
- return [
- { value: "", label: "کل کشور" },
- ...provinces.map((province) => ({
- value: province.id,
- label: province.name_fa,
- })),
- ];
- }, [provinces, errorProvinces, loadingProvinces]);
-
- return (
-
-
- استان
-
- }
- size="small"
- onChange={(e) => onChange(e.target.value)}
- displayEmpty
- >
- {columnSelectOption.map((option) => (
-
- ))}
-
-
- );
-};
-export default ProvinceFilter;
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/StepFilter.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/StepFilter.jsx
deleted file mode 100644
index b6eca29..0000000
--- a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/StepFilter.jsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
-
-const StepFilter = ({ value, onChange }) => {
- const statusOptions = [
- { value: "", label: "همه وضعیت ها" },
- { value: 1, label: "گام اول (شناسایی)" },
- { value: 2, label: "گام دوم (مستندات قضایی)" },
- { value: 3, label: "گام سوم (برخورد)" },
- ];
-
- return (
-
-
- وضعیت
-
- }
- size="small"
- onChange={(e) => onChange(e.target.value)}
- displayEmpty
- >
- {statusOptions.map((option) => (
-
- ))}
-
-
- );
-};
-export default StepFilter;
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/index.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/index.jsx
deleted file mode 100644
index 1a39633..0000000
--- a/src/components/dashboard/roadSafety/reports/map/Filter/Drawer/index.jsx
+++ /dev/null
@@ -1,166 +0,0 @@
-import ScrollBox from "@/core/components/ScrollBox";
-import { yupResolver } from "@hookform/resolvers/yup";
-import CancelIcon from "@mui/icons-material/Cancel";
-import FilterAltIcon from "@mui/icons-material/FilterAlt";
-import { Box, Button, IconButton, Typography } from "@mui/material";
-import { Controller, useForm } from "react-hook-form";
-import * as Yup from "yup";
-import ActivityDateTimeFilter from "./ActivityDateTimeFilter";
-import AxisTypeFilter from "./AxisTypeFilter";
-import EdarehShahriFilter from "./EdarehShahriFilter";
-import InfoFilter from "./InfoFilter";
-import ProvinceFilter from "./ProvinceFilter";
-import StepFilter from "./StepFilter";
-import CreatedAtFilter from "./CreatedAtFilter";
-import JudiciaryDocumentUploadDateFilter from "./JudiciaryDocumentUploadDateFilter";
-import ActionPictureDocumentUploadDateFilter from "./ActionDate";
-import ActionDate from "./ActionDate";
-
-const validationSchema = Yup.object({
- activity_date_time: Yup.array()
- .of(Yup.string().nullable())
- .test({
- test(value, ctx) {
- const [start, end] = value || ["", ""];
- if ((start && !end) || (!start && end)) {
- return ctx.createError({ message: "این بخش را تکمیل نمایید" });
- }
- return true;
- },
- }),
-});
-
-const headerSx = {
- display: "flex",
- alignItems: "center",
- justifyContent: "space-between",
- px: 2,
- py: 1,
- backgroundColor: "#155175",
- boxShadow: "rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px",
- maxWidth: "450px",
-};
-
-const headerTitleSx = { display: "flex", alignItems: "center" };
-const headerIconSx = { color: "#fff", mr: 1 };
-const iconButtonSx = { color: "#fff" };
-
-const formContainerSx = { px: 2, py: 3 };
-const footerSx = { display: "flex", justifyContent: "center", alignItems: "center", pb: 2 };
-
-const submitButtonSx = {
- px: 8,
- boxShadow: "rgba(0, 0, 0, 0.23) 0px 6px 6px, rgba(0, 0, 0, 0.19) 10px 0px 20px",
- backgroundColor: "primary2",
- ":hover": { backgroundColor: "primary2" },
-};
-
-const FilterDrawer = ({ defaultValues, setFilterData, closeDrawer }) => {
- const {
- control,
- handleSubmit,
- formState: { isDirty },
- } = useForm({
- defaultValues,
- resolver: yupResolver(validationSchema),
- mode: "onBlur",
- });
-
- const onSubmit = (data) => {
- setFilterData(data);
- closeDrawer();
- };
-
- return (
- <>
-
-
-
-
- فیلتر
-
-
-
-
-
-
-
-
-
-
- >
- );
-};
-export default FilterDrawer;
diff --git a/src/components/dashboard/roadSafety/reports/map/Filter/index.jsx b/src/components/dashboard/roadSafety/reports/map/Filter/index.jsx
index c12a511..3cbbe5d 100644
--- a/src/components/dashboard/roadSafety/reports/map/Filter/index.jsx
+++ b/src/components/dashboard/roadSafety/reports/map/Filter/index.jsx
@@ -2,7 +2,7 @@
import { Box, Button, Drawer } from "@mui/material";
import FilterListIcon from "@mui/icons-material/FilterList";
import { useCallback, useState } from "react";
-import FilterDrawer from "./Drawer";
+import FilterDrawer from "@/core/components/FilterDrawer";
const drawerSx = {
overflowY: "hidden",
diff --git a/src/components/dashboard/roadSafety/reports/map/PointsOnMap/DialogInfoItem/ContentInfoItem.jsx b/src/components/dashboard/roadSafety/reports/map/PointsOnMap/DialogInfoItem/ContentInfoItem.jsx
index bcfc03d..50957e5 100644
--- a/src/components/dashboard/roadSafety/reports/map/PointsOnMap/DialogInfoItem/ContentInfoItem.jsx
+++ b/src/components/dashboard/roadSafety/reports/map/PointsOnMap/DialogInfoItem/ContentInfoItem.jsx
@@ -63,7 +63,7 @@ const ContentInfoItem = ({ data }) => {
)}
-
+
{
/>
-
-
-
-
-
-
+ {data.step == 3 && (
+
+
+
+
+
+
+ )}
);
diff --git a/src/components/dashboard/roadSafety/reports/map/index.jsx b/src/components/dashboard/roadSafety/reports/map/index.jsx
index 907f90b..37bc5cd 100644
--- a/src/components/dashboard/roadSafety/reports/map/index.jsx
+++ b/src/components/dashboard/roadSafety/reports/map/index.jsx
@@ -1,31 +1,40 @@
"use client";
import LoadingHardPage from "@/core/components/LoadingHardPage";
import MapLoading from "@/core/components/MapLayer/Loading";
+import isArrayEmpty from "@/core/utils/isArrayEmpty";
import { GET_ROAD_SAFETY_REPORT_MAP } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest";
import { Box, Stack } from "@mui/material";
import dynamic from "next/dynamic";
-import { useCallback, useEffect, useState } from "react";
+import { useCallback, useEffect, useMemo, useState } from "react";
import ClusterSwitch from "./ClusterSwitch";
import Filter from "./Filter";
import Legend from "./Legend";
import PointsOnMap from "./PointsOnMap";
+import DataTableFilterDataStructure from "@/core/utils/DataTableFilterDataStructure";
+import useProvinces from "@/lib/hooks/useProvince";
+import CustomSelectByDependency from "@/core/components/FilterDrawer/fieldsType/CustomSelectByDependency";
+import useEdaratLists from "@/lib/hooks/useEdaratLists";
+import useSafetyAndPrivacyGetItems from "@/lib/hooks/useSafetyAndPrivacyGetItems";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => ,
ssr: false,
});
-const defaultValues = {
- province_id: "",
- edarat_id: "",
- info_id: "",
- axis_type_id: "",
- step: "",
- created_at: ["", ""],
- activity_date_time: ["", ""],
- judiciary_document_upload_date: ["", ""],
- action_date: ["", ""],
-};
+const statusOptions = [
+ { value: "", label: "همه وضعیت ها" },
+ { value: 1, label: "گام اول (شناسایی)" },
+ { value: 2, label: "گام دوم (مستندات قضایی)" },
+ { value: 3, label: "گام سوم (برخورد)" },
+];
+const axisOptions = [
+ { value: "", label: "همه محور ها" },
+ { value: 1, label: "آزادراه" },
+ { value: 2, label: "بزرگراه" },
+ { value: 3, label: "اصلی" },
+ { value: 4, label: "فرعی" },
+ { value: 5, label: "روستایی" },
+];
const MAX_POINTS = 1000;
@@ -44,62 +53,205 @@ const controlBarStyles = {
};
const RoadSafetyReportMap = () => {
+ const defaultValues = useMemo(
+ () => [
+ {
+ header: "استان",
+ id: "province_id",
+ filterMode: "equals",
+ datatype: "numeric",
+ value: "",
+ SelectComponent: (props) => {
+ const { provinces, errorProvinces, loadingProvinces } = useProvinces();
+ const getSelectOptions = useMemo(() => {
+ if (loadingProvinces) {
+ return [{ value: "loading", label: "در حال بارگذاری..." }];
+ }
+ if (errorProvinces) {
+ return [{ value: "error", label: "خطا در بارگذاری" }];
+ }
+ return [
+ { value: "", label: "کل کشور" },
+ ...provinces.map((province) => ({
+ value: province.id,
+ label: province.name_fa,
+ })),
+ ];
+ }, [provinces, errorProvinces, loadingProvinces]);
+ return (
+
+ );
+ },
+ },
+ {
+ eader: "اداره",
+ id: "edare_shahri_id",
+ filterMode: "equals",
+ datatype: "numeric",
+ dependencyId: "province_id",
+ value: "",
+ SelectComponent: (props) => {
+ const { edaratList, loadingEdaratList, errorEdaratList } = useEdaratLists(
+ props.dependencyFieldValue.value
+ );
+ const [prevDependency, setPrevDependency] = useState(props.dependencyFieldValue.value);
+
+ const getSelectOptions = useMemo(() => {
+ if (props.dependencyFieldValue.value === "") {
+ return [{ value: "empty", label: "ابتدا استان را انتخاب کنید" }];
+ }
+ if (loadingEdaratList) {
+ return [{ value: "loading", label: "در حال بارگذاری..." }];
+ }
+ if (errorEdaratList) {
+ return [{ value: "error", label: "خطا در بارگذاری" }];
+ }
+ return [
+ { value: "", label: "کل ادارات" },
+ ...edaratList.map((edare) => ({
+ value: edare.id,
+ label: edare.name_fa,
+ })),
+ ];
+ }, [edaratList, loadingEdaratList, errorEdaratList]);
+ useEffect(() => {
+ if (prevDependency === props.dependencyFieldValue?.value) return;
+ props.handleChange({ ...props.filterParameters, value: "" });
+ setPrevDependency(props.dependencyFieldValue?.value);
+ }, [props.dependencyFieldValue?.value]);
+ return (
+
+ );
+ },
+ },
+ {
+ header: "مورد مشاهده شده",
+ id: "info_id",
+ filterMode: "equals",
+ datatype: "numeric",
+ value: "",
+ SelectComponent: (props) => {
+ const { itemsList, loadingItemsList, errorItemsList } = useSafetyAndPrivacyGetItems();
+
+ const getSelectOptions = useMemo(() => {
+ if (loadingItemsList) {
+ return [{ value: "loading", label: "در حال بارگذاری..." }];
+ }
+ if (errorItemsList) {
+ return [{ value: "error", label: "خطا در بارگذاری" }];
+ }
+ return [
+ { value: "", label: "همه موارد" },
+ ...itemsList.map((item) => ({
+ value: item.id,
+ label: item.name,
+ })),
+ ];
+ }, [itemsList, loadingItemsList, errorItemsList]);
+
+ return (
+
+ );
+ },
+ },
+ {
+ header: "نوع محور",
+ id: "axis_type_id",
+ filterMode: "equals",
+ datatype: "numeric",
+ value: "",
+ selectOption: () => {
+ return axisOptions.map((status) => ({
+ value: status.value,
+ label: status.label,
+ }));
+ },
+ },
+ {
+ header: "وضعیت",
+ id: "step",
+ filterMode: "equals",
+ datatype: "numeric",
+ value: "",
+ selectOption: () => {
+ return statusOptions.map((status) => ({
+ value: status.value,
+ label: status.label,
+ }));
+ },
+ },
+ {
+ header: "تاریخ ثبت",
+ id: "created_at",
+ filterMode: "between",
+ datatype: "date",
+ value: ["", ""],
+ },
+ {
+ header: "تاریخ بازدید",
+ id: "activity_date_time",
+ filterMode: "between",
+ datatype: "date",
+ value: ["", ""],
+ },
+ {
+ header: "تاریخ بارگذاری مستندات",
+ id: "judiciary_document_upload_date",
+ filterMode: "between",
+ datatype: "date",
+ value: ["", ""],
+ },
+ {
+ header: "تاریخ اقدام",
+ id: "action_date",
+ filterMode: "between",
+ datatype: "date",
+ value: ["", ""],
+ },
+ ],
+ []
+ );
const requestServer = useRequest();
- const [filterData, setFilterData] = useState(defaultValues);
+ const [filterData, setFilterData] = useState(
+ defaultValues.reduce((acc, item) => {
+ acc[item.id] = item;
+ return acc;
+ }, {})
+ );
const [isCluster, setCluster] = useState(false);
const [data, setData] = useState([]);
const [isLoading, setLoading] = useState(true);
const buildQueryParams = useCallback(() => {
const params = new URLSearchParams();
- const {
- province_id,
- edarat_id,
- info_id,
- axis_type_id,
- step,
- created_at,
- activity_date_time,
- judiciary_document_upload_date,
- action_date,
- } = filterData;
-
- const filterArray = [];
-
- if (province_id) filterArray.push({ id: "province_id", fn: "equals", datatype: "numeric", value: province_id });
- if (edarat_id) filterArray.push({ id: "edarat_id", fn: "equals", datatype: "numeric", value: edarat_id });
- if (info_id) filterArray.push({ id: "info_id", fn: "equals", datatype: "numeric", value: info_id });
- if (axis_type_id)
- filterArray.push({ id: "axis_type_id", fn: "equals", datatype: "numeric", value: axis_type_id });
- if (step) filterArray.push({ id: "step", fn: "equals", datatype: "numeric", value: step });
- if (created_at[0]) filterArray.push({ id: "created_at", fn: "between", datatype: "date", value: created_at });
- if (activity_date_time[0])
- filterArray.push({ id: "activity_date_time", fn: "between", datatype: "date", value: activity_date_time });
- if (judiciary_document_upload_date[0])
- filterArray.push({
- id: "judiciary_document_upload_date",
- fn: "between",
- datatype: "date",
- value: judiciary_document_upload_date,
- });
- if (action_date[0])
- filterArray.push({ id: "action_date", fn: "between", datatype: "date", value: action_date });
-
- console.log(filterArray);
-
- params.set("filters", JSON.stringify(filterArray || []));
+ const filters = DataTableFilterDataStructure(filterData, isArrayEmpty);
+ params.set("filters", JSON.stringify(filters || []));
return params.toString();
}, [filterData]);
useEffect(() => {
- console.log("gasgsa");
-
const fetchData = async () => {
try {
setLoading(true);
const query = buildQueryParams();
- console.log("amir");
-
const response = await requestServer(`${GET_ROAD_SAFETY_REPORT_MAP}?${query}`);
const fetchedData = response?.data?.data || [];
@@ -117,8 +269,6 @@ const RoadSafetyReportMap = () => {
fetchData();
}, [filterData, buildQueryParams]);
- console.log("sfa");
-
return (
diff --git a/src/core/components/FilterDrawer/FilterController.jsx b/src/core/components/FilterDrawer/FilterController.jsx
new file mode 100644
index 0000000..4a6a125
--- /dev/null
+++ b/src/core/components/FilterDrawer/FilterController.jsx
@@ -0,0 +1,25 @@
+import { Controller } from "react-hook-form";
+import FilterField from "./FilterField";
+
+const FilterController = ({ item, control, reset, errors }) => {
+ return (
+ {
+ return (
+ reset()}
+ errors={errors}
+ />
+ );
+ }}
+ />
+ );
+};
+export default FilterController;
diff --git a/src/core/components/FilterDrawer/FilterControllerWithDependency.jsx b/src/core/components/FilterDrawer/FilterControllerWithDependency.jsx
new file mode 100644
index 0000000..361941f
--- /dev/null
+++ b/src/core/components/FilterDrawer/FilterControllerWithDependency.jsx
@@ -0,0 +1,27 @@
+import { Controller, useWatch } from "react-hook-form";
+import FilterField from "./FilterField";
+
+const FilterControllerWithDependency = ({ item, control, reset, errors }) => {
+ const dependencyField = useWatch({ control, name: item.dependencyId });
+
+ return (
+ {
+ return (
+ reset()}
+ errors={errors}
+ />
+ );
+ }}
+ />
+ );
+};
+export default FilterControllerWithDependency;
diff --git a/src/core/components/FilterDrawer/FilterField.jsx b/src/core/components/FilterDrawer/FilterField.jsx
new file mode 100644
index 0000000..ed86df8
--- /dev/null
+++ b/src/core/components/FilterDrawer/FilterField.jsx
@@ -0,0 +1,103 @@
+import { useState } from "react";
+import CustomTextFieldRange from "./fieldsType/CustomTextFieldRange";
+import CustomSelect from "./fieldsType/CustomSelect";
+import CustomDatePicker from "../CustomDatePicker";
+import CustomDatePickerRange from "./fieldsType/CustomDate/CustomDatePickerRange";
+import CustomSelectMultiple from "./fieldsType/CustomSelectMultiple";
+import CustomTextField from "./fieldsType/CustomTextField";
+import FilterOptionList from "./FilterOptionList";
+
+const filterModeOptionFa = {
+ equals: "برابر",
+ notEquals: "نابرابر",
+ contains: "شامل",
+ lessThan: "کوچکتر",
+ greaterThan: "بزرگتر",
+ fuzzy: "فازی",
+ between: "مابین",
+};
+
+function FilterField({
+ item,
+ filterParameters,
+ handleChange,
+ handleBlur,
+ dependencyFieldValue,
+ setFieldValue,
+ resetForm,
+ errors,
+}) {
+ const [anchorEl, setAnchorEl] = useState(null);
+ const defaultFilterTranslation = filterModeOptionFa[filterParameters.filterMode] || filterParameters.filterMode;
+
+ const handleOpenFilterBox = (event) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const renderField = () => {
+ const commonProps = {
+ item,
+ filterParameters,
+ defaultFilterTranslation,
+ handleOpenFilterBox,
+ dependencyFieldValue,
+ setFieldValue,
+ handleChange,
+ handleBlur,
+ errors,
+ };
+
+ switch (filterParameters.datatype) {
+ case "numeric":
+ if (filterParameters.filterMode === "between") {
+ return ;
+ }
+ if (filterParameters.filterMode === "equals") {
+ return item.SelectComponent ? (
+
+ ) : (
+
+ );
+ }
+ break;
+ case "date":
+ if (filterParameters.filterMode === "equals") {
+ return ;
+ }
+ if (filterParameters.filterMode === "between") {
+ return ;
+ }
+ break;
+
+ case "array":
+ if (filterParameters.filterMode === "equals") {
+ return ;
+ }
+ break;
+
+ default:
+ return ;
+ }
+ };
+
+ return (
+ <>
+ {renderField()}
+ {Array.isArray(item.filterModeOptions) && (
+
+ )}
+ >
+ );
+}
+
+export default FilterField;
diff --git a/src/core/components/FilterDrawer/FilterOptionList.jsx b/src/core/components/FilterDrawer/FilterOptionList.jsx
new file mode 100644
index 0000000..1a797f6
--- /dev/null
+++ b/src/core/components/FilterDrawer/FilterOptionList.jsx
@@ -0,0 +1,47 @@
+"use client";
+
+import { ListItem, Menu } from "@mui/material";
+import { useState } from "react";
+
+function FilterOptionList({
+ filterType,
+ filterOption,
+ filterParameters,
+ anchorEl,
+ filterModeOptionFa,
+ setAnchorEl,
+ handleChange,
+}) {
+ const [selectedFilter, setSelectedFilter] = useState(filterType);
+
+ const handleChangeItem = (event, index) => {
+ handleChange({
+ ...filterParameters,
+ value: filterOption[index] === "between" ? ["", ""] : "",
+ filterMode: filterOption[index],
+ });
+ setSelectedFilter(filterOption[index]);
+ setAnchorEl(null);
+ };
+
+ const handleCloseFilterBox = () => {
+ setAnchorEl(null);
+ };
+
+ return (
+
+ );
+}
+
+export default FilterOptionList;
diff --git a/src/core/components/FilterDrawer/fieldsType/CustomDate/CustomDatePicker.jsx b/src/core/components/FilterDrawer/fieldsType/CustomDate/CustomDatePicker.jsx
new file mode 100644
index 0000000..e207cfb
--- /dev/null
+++ b/src/core/components/FilterDrawer/fieldsType/CustomDate/CustomDatePicker.jsx
@@ -0,0 +1,23 @@
+import React from "react";
+import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
+import { Typography } from "@mui/material";
+
+function CustomDatePicker({ column, filterParameters, defaultFilterTranslation, handleChange }) {
+ return (
+ {
+ handleChange({ ...filterParameters, value: formattedDate });
+ }}
+ placeholder={column.header}
+ helperText={
+
+ نوع فیلتر: {defaultFilterTranslation} (تاریخ)
+
+ }
+ />
+ );
+}
+
+export default CustomDatePicker;
diff --git a/src/core/components/FilterDrawer/fieldsType/CustomDate/CustomDatePickerRange.jsx b/src/core/components/FilterDrawer/fieldsType/CustomDate/CustomDatePickerRange.jsx
new file mode 100644
index 0000000..58c597f
--- /dev/null
+++ b/src/core/components/FilterDrawer/fieldsType/CustomDate/CustomDatePickerRange.jsx
@@ -0,0 +1,41 @@
+"use client";
+
+import React from "react";
+import { Box, Typography } from "@mui/material";
+import MuiDatePicker from "@/core/components/DataTable/filter/fieldsType/CustomDate/MuiDatePicker";
+
+function CustomDatePickerRange({ item, filterParameters, defaultFilterTranslation, handleChange, errors }) {
+ return (
+
+ {
+ handleChange({ ...filterParameters, value: [formattedDate, filterParameters.value[1]] });
+ }}
+ maxDate={filterParameters.value[1]}
+ placeholder={`از تاریخ`}
+ helperText={
+
+ نوع فیلتر: {defaultFilterTranslation} (تاریخ)
+
+ }
+ />
+ {
+ handleChange({ ...filterParameters, value: [filterParameters.value[0], formattedDate] });
+ }}
+ minDate={filterParameters.value[0]}
+ placeholder={`تا تاریخ`}
+ helperText={errors?.[`${item.id}`]?.value ? errors?.[`${item.id}`]?.value.message : null}
+ error={Boolean(errors?.[`${item.id}`]?.value)}
+ />
+
+ );
+}
+
+export default CustomDatePickerRange;
diff --git a/src/core/components/FilterDrawer/fieldsType/CustomDate/MuiDatePicker.jsx b/src/core/components/FilterDrawer/fieldsType/CustomDate/MuiDatePicker.jsx
new file mode 100644
index 0000000..d2d9df0
--- /dev/null
+++ b/src/core/components/FilterDrawer/fieldsType/CustomDate/MuiDatePicker.jsx
@@ -0,0 +1,72 @@
+import React from "react";
+import { LocalizationProvider, MobileDatePicker } from "@mui/x-date-pickers";
+import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali";
+import { faIR } from "@mui/x-date-pickers/locales";
+import { Box, FormHelperText, IconButton, InputAdornment } from "@mui/material";
+import ClearIcon from "@mui/icons-material/Clear";
+import moment from "jalali-moment";
+
+function MuiDatePicker({ label, value, setFieldValue, name, minDate, maxDate, helperText, placeholder, error }) {
+ return (
+
+
+ {
+ const date = new Date(value);
+ const formattedDate = moment(date).locale("en").format("YYYY-MM-DD");
+ setFieldValue(name, formattedDate);
+ }}
+ minDate={minDate ? new Date(minDate) : null}
+ maxDate={maxDate ? new Date(maxDate) : null}
+ slotProps={{
+ textField: {
+ size: "small",
+ error: error,
+ placeholder: placeholder,
+ InputProps: {
+ endAdornment: (
+
+ {
+ event.stopPropagation();
+ setFieldValue(name, "");
+ }}
+ sx={{
+ color: "#bfbfbf",
+ "&:hover": {
+ backgroundColor: "rgba(189, 189, 189, 0.1)",
+ color: "#363434",
+ },
+ }}
+ >
+
+
+
+ ),
+ },
+ InputLabelProps: {
+ shrink: true,
+ },
+ },
+ }}
+ />
+ {/*
+ {helperText ? helperText : ""}
+ */}
+
+
+ );
+}
+
+export default MuiDatePicker;
diff --git a/src/core/components/FilterDrawer/fieldsType/CustomSelect.jsx b/src/core/components/FilterDrawer/fieldsType/CustomSelect.jsx
new file mode 100644
index 0000000..61172e6
--- /dev/null
+++ b/src/core/components/FilterDrawer/fieldsType/CustomSelect.jsx
@@ -0,0 +1,30 @@
+"use client";
+
+import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
+function CustomSelect({ item, filterParameters, handleChange }) {
+ return (
+
+
+ {item.header}
+
+ }
+ size="small"
+ onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
+ displayEmpty
+ >
+ {item.selectOption().map((option) => (
+
+ ))}
+
+
+ );
+}
+
+export default CustomSelect;
diff --git a/src/core/components/FilterDrawer/fieldsType/CustomSelectByDependency.jsx b/src/core/components/FilterDrawer/fieldsType/CustomSelectByDependency.jsx
new file mode 100644
index 0000000..69536cd
--- /dev/null
+++ b/src/core/components/FilterDrawer/fieldsType/CustomSelectByDependency.jsx
@@ -0,0 +1,30 @@
+"use client";
+
+import { FormControl, InputLabel, MenuItem, OutlinedInput, Select } from "@mui/material";
+function CustomSelectByDependency({ item, filterParameters, value, handleChange, selectOption }) {
+ return (
+
+
+ {item.header}
+
+ }
+ onChange={(e) => handleChange({ ...filterParameters, value: e.target.value })}
+ displayEmpty
+ >
+ {selectOption.map((option) => (
+
+ ))}
+
+
+ );
+}
+
+export default CustomSelectByDependency;
diff --git a/src/core/components/FilterDrawer/fieldsType/CustomSelectMultiple.jsx b/src/core/components/FilterDrawer/fieldsType/CustomSelectMultiple.jsx
new file mode 100644
index 0000000..c1fd7fa
--- /dev/null
+++ b/src/core/components/FilterDrawer/fieldsType/CustomSelectMultiple.jsx
@@ -0,0 +1,55 @@
+"use client";
+
+import {
+ Box,
+ Chip,
+ FormControl,
+ FormHelperText,
+ InputLabel,
+ MenuItem,
+ OutlinedInput,
+ Select,
+ Typography,
+} from "@mui/material";
+
+function CustomSelectMultiple({ item, filterParameters, handleChange }) {
+ const selectOption = item.selectOption;
+
+ const getLabelForValue = (value) => {
+ const option = selectOption.find((opt) => opt.value === value);
+ return option ? option.label : value;
+ };
+
+ return (
+
+
+ {item.header}
+
+
+
+ );
+}
+
+export default CustomSelectMultiple;
diff --git a/src/core/components/FilterDrawer/fieldsType/CustomTextField.jsx b/src/core/components/FilterDrawer/fieldsType/CustomTextField.jsx
new file mode 100644
index 0000000..86a9c57
--- /dev/null
+++ b/src/core/components/FilterDrawer/fieldsType/CustomTextField.jsx
@@ -0,0 +1,29 @@
+import { InputAdornment, TextField, Typography } from "@mui/material";
+import FilterListIcon from "@mui/icons-material/FilterList";
+
+function CustomTextField({ item, filterParameters, handleOpenFilterBox, handleBlur, handleChange }) {
+ return (
+ handleChange({ ...filterParameters, value: e.target.value })}
+ onBlur={handleBlur}
+ fullWidth
+ variant="outlined"
+ size="small"
+ sx={{ my: 1 }}
+ InputProps={{
+ endAdornment: (
+
+
+
+ ),
+ }}
+ InputLabelProps={{ shrink: true }}
+ />
+ );
+}
+
+export default CustomTextField;
diff --git a/src/core/components/FilterDrawer/fieldsType/CustomTextFieldRange.jsx b/src/core/components/FilterDrawer/fieldsType/CustomTextFieldRange.jsx
new file mode 100644
index 0000000..147ec85
--- /dev/null
+++ b/src/core/components/FilterDrawer/fieldsType/CustomTextFieldRange.jsx
@@ -0,0 +1,62 @@
+import { Box, InputAdornment, TextField, Typography } from "@mui/material";
+import FilterListIcon from "@mui/icons-material/FilterList";
+
+function CustomTextFieldRange({
+ item,
+ defaultFilterTranslation,
+ handleOpenFilterBox,
+ handleChange,
+ filterParameters,
+ handleBlur,
+ errors,
+}) {
+ return (
+
+
+ handleChange({ ...filterParameters, value: [e.target.value, filterParameters.value[1]] })
+ }
+ onBlur={handleBlur}
+ label={از {item.header}}
+ value={filterParameters.value[0]}
+ fullWidth
+ error={touched?.[`${item.id}`]?.value && Boolean(errors?.[`${item.id}`]?.value)}
+ helperText={
+
+ نوع فیلتر: {defaultFilterTranslation}
+
+ }
+ variant="outlined"
+ size="small"
+ sx={{ my: 1, marginRight: 1 }}
+ />
+
+ handleChange({ ...filterParameters, value: [filterParameters.value[0], e.target.value] })
+ }
+ onBlur={handleBlur}
+ error={Boolean(errors?.[`${item.id}`]?.value)}
+ helperText={errors?.[`${item.id}`]?.value ? errors?.[`${item.id}`]?.value.message : null}
+ label={تا {item.header}}
+ value={filterParameters.value[1]}
+ fullWidth
+ variant="outlined"
+ size="small"
+ sx={{ my: 1 }}
+ InputProps={{
+ endAdornment: (
+
+
+
+ ),
+ }}
+ />
+
+ );
+}
+
+export default CustomTextFieldRange;
diff --git a/src/core/components/FilterDrawer/index.jsx b/src/core/components/FilterDrawer/index.jsx
new file mode 100644
index 0000000..3b3699b
--- /dev/null
+++ b/src/core/components/FilterDrawer/index.jsx
@@ -0,0 +1,151 @@
+import { yupResolver } from "@hookform/resolvers/yup";
+import { Cancel, FilterAlt } from "@mui/icons-material";
+import { Box, Button, IconButton, Typography } from "@mui/material";
+import { useForm } from "react-hook-form";
+import * as Yup from "yup";
+import ScrollBox from "../ScrollBox";
+import FilterController from "./FilterController";
+import FilterControllerWithDependency from "./FilterControllerWithDependency";
+
+const headerSx = {
+ display: "flex",
+ alignItems: "center",
+ justifyContent: "space-between",
+ px: 2,
+ py: 1,
+ backgroundColor: "#155175",
+ boxShadow: "rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px",
+ maxWidth: "450px",
+};
+
+const headerTitleSx = { display: "flex", alignItems: "center" };
+const headerIconSx = { color: "#fff", mr: 1 };
+const iconButtonSx = { color: "#fff" };
+
+const formContainerSx = { px: 2, py: 3 };
+const footerSx = { display: "flex", justifyContent: "center", alignItems: "center", pb: 2 };
+
+const submitButtonSx = {
+ px: 8,
+ boxShadow: "rgba(0, 0, 0, 0.23) 0px 6px 6px, rgba(0, 0, 0, 0.19) 10px 0px 20px",
+ backgroundColor: "primary2",
+ ":hover": { backgroundColor: "primary2" },
+};
+
+const validationSchema = Yup.object({
+ activity_date_time: Yup.array()
+ .of(Yup.string().nullable())
+ .test({
+ test(value, ctx) {
+ const [start, end] = value || ["", ""];
+ if ((start && !end) || (!start && end)) {
+ return ctx.createError({ message: "این بخش را تکمیل نمایید" });
+ }
+ return true;
+ },
+ }),
+});
+
+const FilterDrawer = ({ defaultValues, setFilterData, closeDrawer }) => {
+ const {
+ control,
+ errors,
+ reset,
+ handleSubmit,
+ formState: { isDirty },
+ } = useForm({
+ defaultValues,
+ resolver: yupResolver(
+ Yup.object(
+ Object.keys(defaultValues).reduce((acc, key) => {
+ const initialValue = defaultValues[key];
+ if (initialValue.filterMode === "between") {
+ acc[key] = Yup.object().shape({
+ value: Yup.array()
+ .of(Yup.string().nullable())
+ .test({
+ test(value, ctx) {
+ const [start, end] = value || ["", ""];
+ if (
+ initialValue.datatype === "numeric" &&
+ parseInt(end, 10) <= parseInt(start, 10)
+ ) {
+ return ctx.createError({
+ message: `مقدار وارده باید بیشتر از (${start}) باشد`,
+ });
+ } else if ((start && !end) || (!start && end)) {
+ return ctx.createError({
+ message: "این بخش را تکمیل نمایید",
+ });
+ }
+ return true;
+ },
+ }),
+ });
+ }
+ return acc;
+ }, {})
+ )
+ ),
+ mode: "onBlur",
+ });
+
+ const onSubmit = (data) => {
+ setFilterData(data);
+ closeDrawer();
+ };
+
+ return (
+ <>
+
+
+
+
+ فیلتر
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+export default FilterDrawer;