311 lines
12 KiB
JavaScript
311 lines
12 KiB
JavaScript
"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, 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: () => <MapLoading />,
|
||
ssr: false,
|
||
});
|
||
|
||
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;
|
||
|
||
const containerStyles = {
|
||
width: "100%",
|
||
height: "100%",
|
||
p: 1,
|
||
border: "1px dashed",
|
||
borderColor: "divider",
|
||
borderRadius: 1,
|
||
};
|
||
|
||
const controlBarStyles = {
|
||
p: 1,
|
||
background: "#fff",
|
||
};
|
||
|
||
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 (
|
||
<CustomSelectByDependency
|
||
{...props}
|
||
value={loadingProvinces ? "loading" : props.filterParameters.value}
|
||
selectOption={getSelectOptions}
|
||
/>
|
||
);
|
||
},
|
||
},
|
||
{
|
||
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 (
|
||
<CustomSelectByDependency
|
||
{...props}
|
||
value={
|
||
props.dependencyFieldValue?.value === ""
|
||
? "empty"
|
||
: loadingEdaratList
|
||
? "loading"
|
||
: props.filterParameters.value
|
||
}
|
||
selectOption={getSelectOptions}
|
||
/>
|
||
);
|
||
},
|
||
},
|
||
{
|
||
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 (
|
||
<CustomSelectByDependency
|
||
{...props}
|
||
value={loadingItemsList ? "loading" : props.filterParameters.value}
|
||
selectOption={getSelectOptions}
|
||
/>
|
||
);
|
||
},
|
||
},
|
||
{
|
||
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.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 filters = DataTableFilterDataStructure(filterData, isArrayEmpty);
|
||
params.set("filters", JSON.stringify(filters || []));
|
||
return params.toString();
|
||
}, [filterData]);
|
||
|
||
useEffect(() => {
|
||
const fetchData = async () => {
|
||
try {
|
||
setLoading(true);
|
||
const query = buildQueryParams();
|
||
const response = await requestServer(`${GET_ROAD_SAFETY_REPORT_MAP}?${query}`);
|
||
const fetchedData = response?.data?.data || [];
|
||
|
||
if (fetchedData.length > MAX_POINTS) {
|
||
setCluster(true);
|
||
}
|
||
setData(fetchedData);
|
||
} catch (error) {
|
||
console.log(error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
fetchData();
|
||
}, [filterData, buildQueryParams]);
|
||
|
||
return (
|
||
<Box sx={containerStyles}>
|
||
<MapLayer style={{ borderRadius: "4px" }}>
|
||
<Stack
|
||
direction="row-reverse"
|
||
sx={{ position: "absolute", top: 0, right: 0, width: "100%", zIndex: 1000 }}
|
||
>
|
||
<Stack direction="row" spacing={1} sx={{ ...controlBarStyles, borderBottomLeftRadius: "4px" }}>
|
||
<ClusterSwitch
|
||
isCluster={isCluster}
|
||
setCluster={setCluster}
|
||
disabled={data.length > MAX_POINTS}
|
||
max={MAX_POINTS}
|
||
/>
|
||
<Filter filterData={filterData} setFilterData={setFilterData} />
|
||
</Stack>
|
||
</Stack>
|
||
|
||
<Stack
|
||
direction="row-reverse"
|
||
sx={{ position: "absolute", bottom: 0, right: 0, width: "100%", zIndex: 1000 }}
|
||
>
|
||
<Stack direction="row" spacing={1} sx={{ ...controlBarStyles, pb: 0, borderTopLeftRadius: "4px" }}>
|
||
<Legend />
|
||
</Stack>
|
||
</Stack>
|
||
|
||
{isLoading && (
|
||
<Box sx={{ position: "relative", width: "100%", height: "100%", opacity: 0.7, zIndex: 999 }}>
|
||
<LoadingHardPage width={80} height={80} loading={isLoading} sx={{ position: "absolute" }} />
|
||
</Box>
|
||
)}
|
||
|
||
<PointsOnMap data={data} isCluster={isCluster} />
|
||
</MapLayer>
|
||
</Box>
|
||
);
|
||
};
|
||
export default RoadSafetyReportMap;
|