From 5d9a86f2cf7cb6367903bd8fa3557713377125e5 Mon Sep 17 00:00:00 2001 From: mhmjalali Date: Wed, 20 May 2026 16:30:10 +0330 Subject: [PATCH 1/7] work on source marker --- src/assets/images/destination-icon.svg | 18 ++++++++ src/assets/images/prev-destination-icon.svg | 21 +++++++++ src/assets/images/prev-source-icon.svg | 21 +++++++++ src/assets/images/source-icon.svg | 18 ++++++++ .../Form/Area/MapControlPolyline/index.jsx | 6 +-- .../Create/Form/Area/Routing/index.jsx | 46 +++++++++++++++++++ .../Actions/Create/Form/Area/index.jsx | 5 +- .../operator/Actions/Create/Form/index.jsx | 2 +- 8 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 src/assets/images/destination-icon.svg create mode 100644 src/assets/images/prev-destination-icon.svg create mode 100644 src/assets/images/prev-source-icon.svg create mode 100644 src/assets/images/source-icon.svg create mode 100644 src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx diff --git a/src/assets/images/destination-icon.svg b/src/assets/images/destination-icon.svg new file mode 100644 index 0000000..ad8a633 --- /dev/null +++ b/src/assets/images/destination-icon.svg @@ -0,0 +1,18 @@ + +
+ + + + + + + + + + + + + + + +
diff --git a/src/assets/images/prev-destination-icon.svg b/src/assets/images/prev-destination-icon.svg new file mode 100644 index 0000000..656eca3 --- /dev/null +++ b/src/assets/images/prev-destination-icon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/prev-source-icon.svg b/src/assets/images/prev-source-icon.svg new file mode 100644 index 0000000..621e71a --- /dev/null +++ b/src/assets/images/prev-source-icon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/source-icon.svg b/src/assets/images/source-icon.svg new file mode 100644 index 0000000..295c9da --- /dev/null +++ b/src/assets/images/source-icon.svg @@ -0,0 +1,18 @@ + +
+ + + + + + + + + + + + + + + +
diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/MapControlPolyline/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/MapControlPolyline/index.jsx index 7302f7d..3cf2a09 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/MapControlPolyline/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/MapControlPolyline/index.jsx @@ -6,13 +6,13 @@ import L from "leaflet"; // ===== Icons ===== const originIcon = new L.Icon({ - iconUrl: "/icons/origin-marker.png", + iconUrl: "/icons/origin-icon.svg", iconSize: [32, 32], iconAnchor: [16, 32], }); const destinationIcon = new L.Icon({ - iconUrl: "/icons/destination-marker.png", + iconUrl: "/icons/destination-icon.svg", iconSize: [32, 32], iconAnchor: [16, 32], }); @@ -51,7 +51,7 @@ function FixedCenterMarker() { pointerEvents: "none", }} > - center + center ); } diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx new file mode 100644 index 0000000..f7e6f44 --- /dev/null +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx @@ -0,0 +1,46 @@ +import { Marker, useMapEvents } from "react-leaflet"; +import L from "leaflet"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import PrevSourceIcon from "@/assets/images/prev-source-icon.svg"; +import { useRef } from "react"; + + +const Routing = () => { + const mapPrevSourceMarker = useRef(); + const defaultIconSize = [35, 35]; + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + const map = useMapEvents({ + move(e) { + mapPrevSourceMarker.current.setLatLng(e.target.getCenter()); + }, + movestart() { + mapPrevSourceMarker.current.setIcon(createCustomIcon([45, 45], PrevSourceIcon.src)); + }, + moveend() { + mapPrevSourceMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevSourceIcon.src)); + }, + }); + + const handleMarkerClick = () => { + console.log(mapPrevSourceMarker.current.getLatLng().lat); + }; + + return ( + + ) +} + +export default Routing \ No newline at end of file diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/index.jsx index dac1df2..f221fcc 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/index.jsx @@ -2,8 +2,7 @@ import MapLoading from "@/core/components/MapLayer/Loading"; import { Box, Button, DialogActions, DialogContent, Stack } from "@mui/material"; import dynamic from "next/dynamic"; import { useCallback, useState } from "react"; -import MapControlPolyline from "./MapControlPolyline"; -import Example from "./MapControlPolyline"; +import Routing from "./Routing"; const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { loading: () => , ssr: false, @@ -23,7 +22,7 @@ const Area = ({ allData, setAllData, handlePrev, setTabState }) => { - + diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/index.jsx index 994ce63..dd39d68 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/index.jsx @@ -27,7 +27,7 @@ const reducer = (state, action) => { const CreateForm = ({ defaultValues, submitForm, setOpen, submitting }) => { const [allData, dispatch] = useReducer(reducer, defaultValues); - const [tabState, setTabState] = useState(0); + const [tabState, setTabState] = useState(2); const handleClose = () => { setOpen(false); }; From efb260b66daa78da05768549f21e6a20b60b824f Mon Sep 17 00:00:00 2001 From: mhmjalali Date: Sun, 24 May 2026 15:37:12 +0330 Subject: [PATCH 2/7] complete most of the routing task just request to server --- package.json | 1 + .../Form/Area/MapControlPolyline/index.jsx | 14 +- .../Create/Form/Area/Routing/DataBox.jsx | 46 ++++ .../Create/Form/Area/Routing/index.jsx | 230 +++++++++++++++--- .../CreateWithoutProcess/Form/Area/index.jsx | 2 +- .../reports/taradodReports/Search/index.jsx | 5 +- .../violationsReports/Search/index.jsx | 5 +- src/core/utils/routes.js | 6 +- 8 files changed, 252 insertions(+), 57 deletions(-) create mode 100644 src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/DataBox.jsx diff --git a/package.json b/package.json index 8a2e759..79b3f30 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@hookform/resolvers": "^3.9.0", + "@mapbox/polyline": "^1.2.1", "@mui/icons-material": "^5.16.7", "@mui/lab": "^5.0.0-alpha.173", "@mui/material": "^5.16.7", diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/MapControlPolyline/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/MapControlPolyline/index.jsx index 3cf2a09..0a14736 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/MapControlPolyline/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/MapControlPolyline/index.jsx @@ -87,21 +87,21 @@ export default function Example() { height: "400px", }} > - + - {/* saved markers */} - {origin && } + {/* saved markers */} + {origin && } - {destination && } + {destination && } - {/* route line */} - {origin && destination && } + {/* route line */} + {origin && destination && } {/* fixed center pin */} {step !== "done" && } -
+
+
+ {isDest && ( +
+ + +
+ )} + + ); +}; + +export default DataBox; \ No newline at end of file diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx index f7e6f44..c27cb73 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx @@ -1,46 +1,202 @@ -import { Marker, useMapEvents } from "react-leaflet"; +import { Marker, Polyline, useMapEvents } from "react-leaflet"; import L from "leaflet"; +import polyline from "@mapbox/polyline"; import SourceIcon from "@/assets/images/source-icon.svg"; import PrevSourceIcon from "@/assets/images/prev-source-icon.svg"; -import { useRef } from "react"; - +import PrevDestIcon from "@/assets/images/prev-destination-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; +import { useRef, useState } from "react"; +import DataBox from "./DataBox"; const Routing = () => { - const mapPrevSourceMarker = useRef(); - const defaultIconSize = [35, 35]; - const createCustomIcon = (size, iconUrl) => { - return L.icon({ - iconUrl: iconUrl, - iconSize: size, - iconAnchor: [size[0] / 2, size[1]], - popupAnchor: [0, -size[1]], - }); - }; + const mapPrevSourceMarker = useRef(); + const mapPrevDestMarker = useRef(); + const defaultIconSize = [35, 35]; + const [isSource, setIsSource] = useState(false); + const [sourcePosition, setSourcePosition] = useState(null); + const [isDest, setIsDest] = useState(false); + const [destPosition, setDestPosition] = useState(null); + const [routeCoords, setRouteCoords] = useState([]); + const [alternateCoords, setAlternateCoords] = useState([]); + const [editingTarget, setEditingTarget] = useState(null); + const [selectedRoute, setSelectedRoute] = useState(null); - const map = useMapEvents({ - move(e) { - mapPrevSourceMarker.current.setLatLng(e.target.getCenter()); - }, - movestart() { - mapPrevSourceMarker.current.setIcon(createCustomIcon([45, 45], PrevSourceIcon.src)); - }, - moveend() { - mapPrevSourceMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevSourceIcon.src)); - }, - }); + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; - const handleMarkerClick = () => { - console.log(mapPrevSourceMarker.current.getLatLng().lat); - }; + const defaultIcon = createCustomIcon( + defaultIconSize, + isSource && editingTarget !== "source" ? SourceIcon.src : PrevSourceIcon.src + ); - return ( - - ) -} + const prevDestIcon = createCustomIcon( + defaultIconSize, + isDest && editingTarget !== "dest" ? DestIcon.src : PrevDestIcon.src + ); -export default Routing \ No newline at end of file + const isMovingSource = !isSource || editingTarget === "source"; + const isMovingDest = isSource && (!isDest || editingTarget === "dest"); + + const map = useMapEvents({ + move(e) { + if (isMovingSource) { + mapPrevSourceMarker.current.setLatLng(e.target.getCenter()); + } + if (isMovingDest && mapPrevDestMarker.current) { + mapPrevDestMarker.current.setLatLng(e.target.getCenter()); + } + }, + movestart() { + if (isMovingSource) { + mapPrevSourceMarker.current.setIcon(createCustomIcon([45, 45], PrevSourceIcon.src)); + } + if (isMovingDest && mapPrevDestMarker.current) { + mapPrevDestMarker.current.setIcon(createCustomIcon([45, 45], PrevDestIcon.src)); + } + }, + moveend() { + if (isMovingSource) { + mapPrevSourceMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevSourceIcon.src)); + } + if (isMovingDest && mapPrevDestMarker.current) { + mapPrevDestMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevDestIcon.src)); + } + }, + }); + + const fetchRoute = async (source, dest) => { + const locations = [ + { lat: source.lat, lon: source.lng }, + { lat: dest.lat, lon: dest.lng }, + ]; + try { + const response = await fetch("https://jouya.141.ir/api/router/drive", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ locations }), + }); + const data = await response.json(); + + const shape = data.trip.legs[0].shape; + const decoded = polyline.decode(shape, 6); + setRouteCoords(decoded); + setSelectedRoute({ index: "main", coords: decoded }); + + if (data.alternates && data.alternates.length > 0) { + const decodedAlternates = data.alternates.map((alt) => + polyline.decode(alt.trip.legs[0].shape, 6) + ); + setAlternateCoords(decodedAlternates); + } else { + setAlternateCoords([]); + } + map.flyToBounds(decoded, { padding: [50, 50], duration: 1.5 }); + } catch (error) { + console.error("Routing error:", error); + } + }; + + const handleMarkerClick = async () => { + if (!isSource || editingTarget === "source") { + const clickedPosition = mapPrevSourceMarker.current.getLatLng(); + console.log("Source:", clickedPosition.lat, clickedPosition.lng); + setSourcePosition(clickedPosition); + setIsSource(true); + setEditingTarget(null); + setRouteCoords([]); + setAlternateCoords([]); + setSelectedRoute(null); + + if (editingTarget === "source" && destPosition) { + await fetchRoute(clickedPosition, destPosition); + } + } + }; + + const handleDestMarkerClick = async () => { + if (!isDest || editingTarget === "dest") { + const clickedPosition = mapPrevDestMarker.current.getLatLng(); + setDestPosition(clickedPosition); + setIsDest(true); + setEditingTarget(null); + + await fetchRoute(sourcePosition, clickedPosition); + } + }; + + const handleEditSource = () => { + setEditingTarget("source"); + setRouteCoords([]); + setAlternateCoords([]); + setSelectedRoute(null); + }; + + const handleEditDest = () => { + setEditingTarget("dest"); + setRouteCoords([]); + setAlternateCoords([]); + setSelectedRoute(null); + }; + + const handleSelectRoute = (index, coords) => { + setSelectedRoute({ index, coords }); + map.flyToBounds(coords, { padding: [50, 50], duration: 0.3 }); + console.log("Selected route:", index, coords); + }; + + return ( + <> + + + {isSource && ( + + )} + {alternateCoords.map((coords, index) => ( + handleSelectRoute(index, coords) }} + /> + ))} + {routeCoords.length > 0 && ( + handleSelectRoute("main", routeCoords) }} + /> + )} + + ); +}; + +export default Routing; \ No newline at end of file diff --git a/src/components/dashboard/roadMissions/operator/Actions/CreateWithoutProcess/Form/Area/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/CreateWithoutProcess/Form/Area/index.jsx index 38ec045..a985737 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/CreateWithoutProcess/Form/Area/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/CreateWithoutProcess/Form/Area/index.jsx @@ -24,7 +24,7 @@ const Area = ({ allData, setAllData, handlePrev, setTabState }) => { - + diff --git a/src/components/dashboard/roadMissions/reports/taradodReports/Search/index.jsx b/src/components/dashboard/roadMissions/reports/taradodReports/Search/index.jsx index 2b0d128..f29d302 100644 --- a/src/components/dashboard/roadMissions/reports/taradodReports/Search/index.jsx +++ b/src/components/dashboard/roadMissions/reports/taradodReports/Search/index.jsx @@ -5,10 +5,7 @@ const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesP return ( <> - + ); diff --git a/src/components/dashboard/roadMissions/reports/violationsReports/Search/index.jsx b/src/components/dashboard/roadMissions/reports/violationsReports/Search/index.jsx index 2b0d128..f29d302 100644 --- a/src/components/dashboard/roadMissions/reports/violationsReports/Search/index.jsx +++ b/src/components/dashboard/roadMissions/reports/violationsReports/Search/index.jsx @@ -5,10 +5,7 @@ const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesP return ( <> - + ); diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index c1656f7..a2ea39f 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -47,10 +47,8 @@ export const GET_COUNTRY_ACTIVITY_REPORT = api + "/api/v3/missions/report/countr export const EXPORT_COUNTRY_ROAD_PATROL_REPORTS = api + "/api/v3/road_patrols/report/country_activity_excel"; export const EXPORT_PROVINCE_ROAD_PATROL_REPORTS = api + "/api/v3/road_patrols/report/province_activity_excel"; -export const GET_MISSIONS_REPORT_TARADOD_COUNTRY_ACTIVITY = - api + "/api/v3/missions/report_taradod/country_activity"; -export const GET_MISSIONS_REPORT_TARADOD_PROVINCE_ACTIVITY = - api + "/api/v3/missions/report_taradod/province_activity"; +export const GET_MISSIONS_REPORT_TARADOD_COUNTRY_ACTIVITY = api + "/api/v3/missions/report_taradod/country_activity"; +export const GET_MISSIONS_REPORT_TARADOD_PROVINCE_ACTIVITY = api + "/api/v3/missions/report_taradod/province_activity"; export const EXPORT_MISSIONS_REPORT_TARADOD_COUNTRY_EXCEL_ACTIVITY = api + "/api/v3/missions/report_taradod/country_excel_activity"; export const EXPORT_MISSIONS_REPORT_TARADOD_PROVINCE_EXCEL_ACTIVITY = From 46bb4e4228ad583d3068ede3831669418f0c4f49 Mon Sep 17 00:00:00 2001 From: mhmjalali Date: Sat, 6 Jun 2026 10:18:30 +0330 Subject: [PATCH 3/7] working on map in rms mission --- .../Create/Form/Area/Routing/DataBox.jsx | 33 +++++++++++-------- .../Create/Form/Area/Routing/index.jsx | 8 ++--- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/DataBox.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/DataBox.jsx index def45cb..5269a52 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/DataBox.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/DataBox.jsx @@ -4,7 +4,22 @@ const DataBox = ({ isSource, isDest, sourcePosition, destPosition, editingTarget if (!isSource) return null; return ( - +
-
@@ -29,12 +39,7 @@ const DataBox = ({ isSource, isDest, sourcePosition, destPosition, editingTarget readOnly value={destPosition ? `${destPosition.lat.toFixed(6)}, ${destPosition.lng.toFixed(6)}` : ""} /> -
@@ -43,4 +48,4 @@ const DataBox = ({ isSource, isDest, sourcePosition, destPosition, editingTarget ); }; -export default DataBox; \ No newline at end of file +export default DataBox; diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx index c27cb73..4f1e47a 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx @@ -89,9 +89,7 @@ const Routing = () => { setSelectedRoute({ index: "main", coords: decoded }); if (data.alternates && data.alternates.length > 0) { - const decodedAlternates = data.alternates.map((alt) => - polyline.decode(alt.trip.legs[0].shape, 6) - ); + const decodedAlternates = data.alternates.map((alt) => polyline.decode(alt.trip.legs[0].shape, 6)); setAlternateCoords(decodedAlternates); } else { setAlternateCoords([]); @@ -175,7 +173,7 @@ const Routing = () => { icon={prevDestIcon} /> )} - {alternateCoords.map((coords, index) => ( + {alternateCoords.map((coords, index) => ( { ); }; -export default Routing; \ No newline at end of file +export default Routing; From 6d8e9ddb5b6baa7d96a3583c22e910a20bf4132f Mon Sep 17 00:00:00 2001 From: mhmjalali Date: Wed, 10 Jun 2026 16:05:25 +0330 Subject: [PATCH 4/7] complete routing section and view of route on table actions --- .../Create/Form/Area/Routing/AlarmText.jsx | 28 ++++++++ .../Create/Form/Area/Routing/DataBox.jsx | 8 ++- .../Create/Form/Area/Routing/ShowRoute.jsx | 46 +++++++++++++ .../Create/Form/Area/Routing/index.jsx | 65 ++++++++++++------- .../Actions/Create/Form/Area/index.jsx | 14 ++-- .../Actions/Create/Form/Verify/index.jsx | 18 +++-- .../operator/Actions/Create/Form/index.jsx | 2 +- .../operator/Actions/Create/index.jsx | 11 +--- .../roadMissions/operator/OperatorList.jsx | 18 ++--- .../operator/RowActions/RouteDetail/index.jsx | 57 ++++++++++++++++ 10 files changed, 211 insertions(+), 56 deletions(-) create mode 100644 src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/AlarmText.jsx create mode 100644 src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/ShowRoute.jsx create mode 100644 src/components/dashboard/roadMissions/operator/RowActions/RouteDetail/index.jsx diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/AlarmText.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/AlarmText.jsx new file mode 100644 index 0000000..0a3be1b --- /dev/null +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/AlarmText.jsx @@ -0,0 +1,28 @@ +import { Box, Typography } from "@mui/material"; + +const AlarmText = ({ isSource }) => { + if (isSource) return null; + return ( + + + با کلیک بر روی مارکر موقعیت را انتخاب کنید + + + ); +}; + +export default AlarmText; diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/DataBox.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/DataBox.jsx index 5269a52..c19cb6f 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/DataBox.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/DataBox.jsx @@ -27,9 +27,11 @@ const DataBox = ({ isSource, isDest, sourcePosition, destPosition, editingTarget readOnly value={sourcePosition ? `${sourcePosition.lat.toFixed(6)}, ${sourcePosition.lng.toFixed(6)}` : ""} /> - + {isSource && isDest && ( + + )} {isDest && (
diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/ShowRoute.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/ShowRoute.jsx new file mode 100644 index 0000000..8cc7e90 --- /dev/null +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/ShowRoute.jsx @@ -0,0 +1,46 @@ +import { useEffect, useRef } from "react"; +import { Marker, Polyline, useMap } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; + +const ShowRoute = ({ area }) => { + const map = useMap(); + const defaultIconSize = [35, 35]; + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); + const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); + + if (!area) return null; + const coords = polyline.decode(area, 6); + + if (coords.length === 0) return null; + + const sourcePosition = coords[0]; + const destPosition = coords[coords.length - 1]; + useEffect(() => { + if (coords.length > 0) { + map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); + } + }, [area]); + + return ( + <> + + + + + ); +}; + +export default ShowRoute; diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx index 4f1e47a..06e7c9b 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Area/Routing/index.jsx @@ -5,12 +5,14 @@ import SourceIcon from "@/assets/images/source-icon.svg"; import PrevSourceIcon from "@/assets/images/prev-source-icon.svg"; import PrevDestIcon from "@/assets/images/prev-destination-icon.svg"; import DestIcon from "@/assets/images/destination-icon.svg"; -import { useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import DataBox from "./DataBox"; +import AlarmText from "./AlarmText"; -const Routing = () => { +const Routing = ({ setArea, setLocations, locations, area }) => { const mapPrevSourceMarker = useRef(); const mapPrevDestMarker = useRef(); + const mapRef = useRef(null); const defaultIconSize = [35, 35]; const [isSource, setIsSource] = useState(false); const [sourcePosition, setSourcePosition] = useState(null); @@ -45,33 +47,48 @@ const Routing = () => { const map = useMapEvents({ move(e) { - if (isMovingSource) { - mapPrevSourceMarker.current.setLatLng(e.target.getCenter()); - } - if (isMovingDest && mapPrevDestMarker.current) { - mapPrevDestMarker.current.setLatLng(e.target.getCenter()); - } + if (isMovingSource) mapPrevSourceMarker.current.setLatLng(e.target.getCenter()); + if (isMovingDest && mapPrevDestMarker.current) mapPrevDestMarker.current.setLatLng(e.target.getCenter()); }, movestart() { - if (isMovingSource) { - mapPrevSourceMarker.current.setIcon(createCustomIcon([45, 45], PrevSourceIcon.src)); - } - if (isMovingDest && mapPrevDestMarker.current) { + if (isMovingSource) mapPrevSourceMarker.current.setIcon(createCustomIcon([45, 45], PrevSourceIcon.src)); + if (isMovingDest && mapPrevDestMarker.current) mapPrevDestMarker.current.setIcon(createCustomIcon([45, 45], PrevDestIcon.src)); - } }, moveend() { - if (isMovingSource) { + if (isMovingSource) mapPrevSourceMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevSourceIcon.src)); - } - if (isMovingDest && mapPrevDestMarker.current) { + if (isMovingDest && mapPrevDestMarker.current) mapPrevDestMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevDestIcon.src)); - } }, }); + useEffect(() => { + mapRef.current = map; + }, [map]); + + useEffect(() => { + if (locations.length < 2) return; + const restoredSource = { lat: locations[0].lat, lng: locations[0].lon }; + const restoredDest = { lat: locations[1].lat, lng: locations[1].lon }; + setSourcePosition(restoredSource); + setDestPosition(restoredDest); + setIsSource(true); + setIsDest(true); + if (area) { + const decoded = polyline.decode(area, 6); + setRouteCoords(decoded); + setSelectedRoute({ index: "main", coords: decoded }); + setTimeout(() => { + mapRef.current?.flyToBounds(decoded, { padding: [50, 50], duration: 1.5 }); + }, 100); + } else { + fetchRoute(restoredSource, restoredDest); + } + }, []); + const fetchRoute = async (source, dest) => { - const locations = [ + const locs = [ { lat: source.lat, lon: source.lng }, { lat: dest.lat, lon: dest.lng }, ]; @@ -79,16 +96,17 @@ const Routing = () => { const response = await fetch("https://jouya.141.ir/api/router/drive", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ locations }), + body: JSON.stringify({ locations: locs }), }); const data = await response.json(); - const shape = data.trip.legs[0].shape; + setLocations(locs); + setArea(shape); const decoded = polyline.decode(shape, 6); setRouteCoords(decoded); setSelectedRoute({ index: "main", coords: decoded }); - if (data.alternates && data.alternates.length > 0) { + if (data.alternates?.length > 0) { const decodedAlternates = data.alternates.map((alt) => polyline.decode(alt.trip.legs[0].shape, 6)); setAlternateCoords(decodedAlternates); } else { @@ -103,7 +121,6 @@ const Routing = () => { const handleMarkerClick = async () => { if (!isSource || editingTarget === "source") { const clickedPosition = mapPrevSourceMarker.current.getLatLng(); - console.log("Source:", clickedPosition.lat, clickedPosition.lng); setSourcePosition(clickedPosition); setIsSource(true); setEditingTarget(null); @@ -144,8 +161,9 @@ const Routing = () => { const handleSelectRoute = (index, coords) => { setSelectedRoute({ index, coords }); + const encoded = polyline.encode(coords, 6); + setArea(encoded); map.flyToBounds(coords, { padding: [50, 50], duration: 0.3 }); - console.log("Selected route:", index, coords); }; return ( @@ -159,6 +177,7 @@ const Routing = () => { onEditSource={handleEditSource} onEditDest={handleEditDest} /> + import("@/core/components/MapLayer"), { }); const Area = ({ allData, setAllData, handlePrev, setTabState }) => { - const [bound, setBound] = useState(allData.bound); + const [area, setArea] = useState(allData.area); + const [locations, setLocations] = useState(allData.locations); const handleNext = useCallback(() => { - setAllData({ bound: bound }); + setAllData({ area: area }); + setAllData({ locations: locations }); setTabState((s) => s + 1); - }, [bound]); + }, [area]); return ( <> @@ -22,7 +24,7 @@ const Area = ({ allData, setAllData, handlePrev, setTabState }) => { - + @@ -31,8 +33,8 @@ const Area = ({ allData, setAllData, handlePrev, setTabState }) => { - diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Verify/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Verify/index.jsx index 57515c4..639fdef 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Verify/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Verify/index.jsx @@ -7,7 +7,7 @@ import { Box, Button, Chip, DialogActions, DialogContent, Divider, Stack, Typogr import moment from "jalali-moment"; import dynamic from "next/dynamic"; import { useCallback } from "react"; -import ShowBound from "../../../showBound"; +import ShowRoute from "../Area/Routing/ShowRoute"; const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { loading: () => , ssr: false, @@ -23,11 +23,17 @@ const Verify = ({ allData, handlePrev, submitForm, submitting }) => { - - - - - + + + + + + {console.log("allData.area", allData.area)} + + + + + diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/index.jsx index dd39d68..994ce63 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/index.jsx @@ -27,7 +27,7 @@ const reducer = (state, action) => { const CreateForm = ({ defaultValues, submitForm, setOpen, submitting }) => { const [allData, dispatch] = useReducer(reducer, defaultValues); - const [tabState, setTabState] = useState(2); + const [tabState, setTabState] = useState(0); const handleClose = () => { setOpen(false); }; diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/index.jsx index 3726f9e..2595dca 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/index.jsx @@ -19,8 +19,6 @@ const Create = ({ mutate }) => { const submitForm = async (result) => { setSubmitting(true); - const bound = result.bound.getLatLngs(); - let area = bound.map((latlng) => [latlng.lng, latlng.lat]); await requestServer(REQUEST_MISSION, "post", { data: { @@ -31,10 +29,7 @@ const Create = ({ mutate }) => { road_observed_id: result.road_observed_id, } : {}), - area: { - type: result.bound_type, - coordinates: area, - }, + encoded_route: result.area, ...(result.rahdaran.length != 0 ? { rahdaran: result.rahdaran.map((r) => r.id) } : {}), requested_machines: result.requested_machines, type: result.type, @@ -101,8 +96,8 @@ const Create = ({ mutate }) => { road_observed_id: "", rahdaran: [], requested_machines: [], - bound: null, - bound_type: "polyline", + area: null, + locations: [], type: "", start_date: "", start_time: null, diff --git a/src/components/dashboard/roadMissions/operator/OperatorList.jsx b/src/components/dashboard/roadMissions/operator/OperatorList.jsx index e343866..8c277e3 100644 --- a/src/components/dashboard/roadMissions/operator/OperatorList.jsx +++ b/src/components/dashboard/roadMissions/operator/OperatorList.jsx @@ -1,21 +1,21 @@ "use client"; +import DescriptionDialog from "@/components/dashboard/roadMissions/operator/RowActions/DescriptionDialog"; +import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency"; import DataTableWithAuth from "@/core/components/DataTableWithAuth"; import { missionCategoryTypes } from "@/core/utils/missionCategoryTypes"; import { missionRegions } from "@/core/utils/missionRegions"; import { missionTypes } from "@/core/utils/missionTypes"; import { GET_ROAD_MISSIONS_OPERATOR_LIST } from "@/core/utils/routes"; +import useCities from "@/lib/hooks/useCities"; +import useProvinces from "@/lib/hooks/useProvince"; import { Box, Stack } from "@mui/material"; import moment from "jalali-moment"; import { useMemo } from "react"; -import ShowArea from "./Actions/showArea"; import RowActions from "./RowActions"; import MachinesDialog from "./RowActions/Machines"; -import Toolbar from "./Toolbar"; import RahdaranDialog from "./RowActions/Rahdaran"; -import DescriptionDialog from "@/components/dashboard/roadMissions/operator/RowActions/DescriptionDialog"; -import useProvinces from "@/lib/hooks/useProvince"; -import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency"; -import useCities from "@/lib/hooks/useCities"; +import RouteDetail from "./RowActions/RouteDetail"; +import Toolbar from "./Toolbar"; const OperatorList = () => { const columns = useMemo(() => { @@ -247,7 +247,7 @@ const OperatorList = () => { }, { header: "منطقه عملیاتی", - id: "area", + id: "encoded_route", enableColumnFilter: false, datatype: "numeric", filterMode: "equals", @@ -263,9 +263,9 @@ const OperatorList = () => { }, }, Cell: ({ row }) => - row.original.area ? ( + row.original.encoded_route ? ( - + ) : ( "-" diff --git a/src/components/dashboard/roadMissions/operator/RowActions/RouteDetail/index.jsx b/src/components/dashboard/roadMissions/operator/RowActions/RouteDetail/index.jsx new file mode 100644 index 0000000..e345bf9 --- /dev/null +++ b/src/components/dashboard/roadMissions/operator/RowActions/RouteDetail/index.jsx @@ -0,0 +1,57 @@ +import { Box, Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import MapIcon from "@mui/icons-material/Map"; +import MapLayer from "@/core/components/MapLayer"; +import ShowRoute from "../../Actions/Create/Form/Area/Routing/ShowRoute"; + +const RouteDetail = ({ encoded_route }) => { + const [openRouteDetailDialog, setOpenRouteDetailDialog] = useState(false); + return ( + <> + + setOpenRouteDetailDialog(true)}> + + + + setOpenRouteDetailDialog(false)} + PaperProps={{ + sx: { + boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", + }, + }} + dir="rtl" + maxWidth={"sm"} + > + مسیر انتخابی + + + + + + + + + + + + + ); +}; +export default RouteDetail; From 70ea71cbfaff8369e2e4c46cbe65ce434e28112c Mon Sep 17 00:00:00 2001 From: mhmjalali Date: Wed, 10 Jun 2026 16:11:24 +0330 Subject: [PATCH 5/7] add showroute to transportation component --- .../RowActions/RouteDetail/ShowRoute.jsx | 46 +++++++++++++++ .../RowActions/RouteDetail/index.jsx | 57 +++++++++++++++++++ .../transportation/TransportationList.jsx | 6 +- 3 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 src/components/dashboard/roadMissions/transportation/RowActions/RouteDetail/ShowRoute.jsx create mode 100644 src/components/dashboard/roadMissions/transportation/RowActions/RouteDetail/index.jsx diff --git a/src/components/dashboard/roadMissions/transportation/RowActions/RouteDetail/ShowRoute.jsx b/src/components/dashboard/roadMissions/transportation/RowActions/RouteDetail/ShowRoute.jsx new file mode 100644 index 0000000..8cc7e90 --- /dev/null +++ b/src/components/dashboard/roadMissions/transportation/RowActions/RouteDetail/ShowRoute.jsx @@ -0,0 +1,46 @@ +import { useEffect, useRef } from "react"; +import { Marker, Polyline, useMap } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; + +const ShowRoute = ({ area }) => { + const map = useMap(); + const defaultIconSize = [35, 35]; + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); + const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); + + if (!area) return null; + const coords = polyline.decode(area, 6); + + if (coords.length === 0) return null; + + const sourcePosition = coords[0]; + const destPosition = coords[coords.length - 1]; + useEffect(() => { + if (coords.length > 0) { + map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); + } + }, [area]); + + return ( + <> + + + + + ); +}; + +export default ShowRoute; diff --git a/src/components/dashboard/roadMissions/transportation/RowActions/RouteDetail/index.jsx b/src/components/dashboard/roadMissions/transportation/RowActions/RouteDetail/index.jsx new file mode 100644 index 0000000..4501d35 --- /dev/null +++ b/src/components/dashboard/roadMissions/transportation/RowActions/RouteDetail/index.jsx @@ -0,0 +1,57 @@ +import { Box, Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import MapIcon from "@mui/icons-material/Map"; +import MapLayer from "@/core/components/MapLayer"; +import ShowRoute from "./ShowRoute"; + +const RouteDetail = ({ encoded_route }) => { + const [openRouteDetailDialog, setOpenRouteDetailDialog] = useState(false); + return ( + <> + + setOpenRouteDetailDialog(true)}> + + + + setOpenRouteDetailDialog(false)} + PaperProps={{ + sx: { + boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", + }, + }} + dir="rtl" + maxWidth={"sm"} + > + مسیر انتخابی + + + + + + + + + + + + + ); +}; +export default RouteDetail; diff --git a/src/components/dashboard/roadMissions/transportation/TransportationList.jsx b/src/components/dashboard/roadMissions/transportation/TransportationList.jsx index ab735d2..51872c9 100644 --- a/src/components/dashboard/roadMissions/transportation/TransportationList.jsx +++ b/src/components/dashboard/roadMissions/transportation/TransportationList.jsx @@ -4,13 +4,13 @@ import { GET_ROAD_MISSIONS_TRANSPORTATION_LIST } from "@/core/utils/routes"; import { Box, Stack } from "@mui/material"; import moment from "jalali-moment"; import { useMemo } from "react"; -import ShowArea from "./Actions/showArea"; import RowActions from "./RowActions"; import { missionRegions } from "@/core/utils/missionRegions"; import { missionTypes } from "@/core/utils/missionTypes"; import useProvinces from "@/lib/hooks/useProvince"; import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency"; import useCities from "@/lib/hooks/useCities"; +import RouteDetail from "./RowActions/RouteDetail"; const TransportationList = () => { const columns = useMemo(() => { @@ -230,9 +230,9 @@ const TransportationList = () => { }, }, Cell: ({ row }) => - row.original.area ? ( + row.original.encoded_route ? ( - + ) : ( "-" From e3ca4a20526b10e176b5d1e876e0536b515b8f50 Mon Sep 17 00:00:00 2001 From: mhmjalali Date: Sat, 13 Jun 2026 06:13:17 +0330 Subject: [PATCH 6/7] complete transportation page --- .../RowActions/Allocation/Form/index.jsx | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/components/dashboard/roadMissions/transportation/RowActions/Allocation/Form/index.jsx b/src/components/dashboard/roadMissions/transportation/RowActions/Allocation/Form/index.jsx index c35018d..be001cc 100644 --- a/src/components/dashboard/roadMissions/transportation/RowActions/Allocation/Form/index.jsx +++ b/src/components/dashboard/roadMissions/transportation/RowActions/Allocation/Form/index.jsx @@ -14,16 +14,10 @@ import MachinesDialog from "./MachinesDialog"; import Reject from "./Reject"; import SelectBox from "@/core/components/SelectBox"; import { Controller, useForm } from "react-hook-form"; +import RouteDetail from "../../RouteDetail"; +import ShowRoute from "../../RouteDetail/ShowRoute"; const AllocationForm = ({ row, mutate, setOpenAllocationDialog }) => { - const latLngs = useMemo(() => { - return row.area.coordinates.map(([lng, lat]) => [lat, lng]); - }, [row.area.coordinates]); - - const bound = useMemo( - () => (row.area.type === "polygon" ? L.polygon(latLngs) : L.polyline(latLngs)), - [row.area.type, latLngs] - ); const requestServer = useRequest({ notificationSuccess: true }); const [machine, setMachine] = useState(); const [driver, setDriver] = useState(); @@ -180,10 +174,32 @@ const AllocationForm = ({ row, mutate, setOpenAllocationDialog }) => { )} - - - - + + {row.encoded_route ? ( + + + + ) : ( + + مختصات برای این ماموریت در دسترس نمیباشد + + )} From 855afc05e56a9bb1a145594d43faf7cbef0d8c5d Mon Sep 17 00:00:00 2001 From: mhmjalali Date: Sat, 13 Jun 2026 10:22:49 +0330 Subject: [PATCH 7/7] complete adding route selection and view of it for violation page --- .../Actions/Create/Form/Verify/index.jsx | 1 - .../MapControlPolygon/DrawBound/index.jsx | 129 ----------- .../Form/Area/MapControlPolygon/index.jsx | 116 ---------- .../MapControlPolyline/DrawBound/index.jsx | 129 ----------- .../Form/Area/MapControlPolyline/index.jsx | 116 ---------- .../Form/Area/Routing/AlarmText.jsx | 28 +++ .../Form/Area/Routing/DataBox.jsx | 53 +++++ .../Form/Area/Routing/ShowRoute.jsx | 46 ++++ .../Form/Area/Routing/index.jsx | 219 ++++++++++++++++++ .../Form/Area/SelectBoundType/index.jsx | 25 -- .../CreateWithoutProcess/Form/Area/index.jsx | 29 +-- .../Form/Verify/index.jsx | 12 +- .../CreateWithoutProcess/Form/index.jsx | 20 +- .../Actions/CreateWithoutProcess/index.jsx | 5 +- 14 files changed, 386 insertions(+), 542 deletions(-) delete mode 100644 src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolygon/DrawBound/index.jsx delete mode 100644 src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolygon/index.jsx delete mode 100644 src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolyline/DrawBound/index.jsx delete mode 100644 src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolyline/index.jsx create mode 100644 src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/AlarmText.jsx create mode 100644 src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/DataBox.jsx create mode 100644 src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/ShowRoute.jsx create mode 100644 src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/index.jsx delete mode 100644 src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/SelectBoundType/index.jsx diff --git a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Verify/index.jsx b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Verify/index.jsx index 639fdef..e48883e 100644 --- a/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Verify/index.jsx +++ b/src/components/dashboard/roadMissions/operator/Actions/Create/Form/Verify/index.jsx @@ -28,7 +28,6 @@ const Verify = ({ allData, handlePrev, submitForm, submitting }) => { - {console.log("allData.area", allData.area)} diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolygon/DrawBound/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolygon/DrawBound/index.jsx deleted file mode 100644 index 5a253a9..0000000 --- a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolygon/DrawBound/index.jsx +++ /dev/null @@ -1,129 +0,0 @@ -import React, { useCallback, useEffect, useRef, useState } from "react"; -import L from "leaflet"; -import { FeatureGroup, useMap } from "react-leaflet"; -import "leaflet-draw"; - -const DrawBound = ({ control, controlDispach, bound, setBound }) => { - const map = useMap(); - const featureRef = useRef(null); - const [area, setArea] = useState(); - const drawControlRef = useRef(null); - - const safeFlyToBounds = (layer) => { - if (!layer || !map) return; - try { - const latLngs = layer.getLatLngs(); - map.flyToBounds(latLngs, { - paddingTopLeft: [20, 35], - paddingBottomRight: [20, 55], - }); - } catch (e) { - console.warn("flyToBounds failed:", e); - } - }; - - const safeFitBounds = (layer) => { - if (!layer || !map) return; - try { - const latLngs = layer.getLatLngs(); - map.fitBounds(latLngs, { - paddingTopLeft: [20, 35], - paddingBottomRight: [20, 55], - }); - } catch (e) { - console.warn("fitBounds failed:", e); - } - }; - - const bindEditEvent = (layer) => { - if (!layer) return; - layer.on("edit", function (e) { - const editedLayer = e.target; - setArea(editedLayer); - setBound(editedLayer); - safeFlyToBounds(editedLayer); - }); - }; - - const handlerCreatedBound = useCallback((event) => { - const { layer } = event; - layer.editing.enable(); - featureRef.current.addLayer(layer); // 🟢 اول اضافه به نقشه - setArea(layer); - setBound(layer); - safeFlyToBounds(layer); - bindEditEvent(layer); - controlDispach({ type: "SET_STATUS", status: 2 }); - }, []); - - useEffect(() => { - if ( - control.status === 1 && - drawControlRef.current && - drawControlRef.current._toolbars?.draw?._modes?.polygon?.handler - ) { - drawControlRef.current._toolbars.draw._modes.polygon.handler.enable(); - } - }, [control.status]); - - useEffect(() => { - if (control.status === 0 && area && featureRef.current) { - featureRef.current.removeLayer(area); - setArea(null); - setBound(null); - } - }, [control.status, area]); - - useEffect(() => { - if (control.status === 2 && bound && featureRef.current) { - setArea(bound); - featureRef.current.addLayer(bound); - bound.editing.enable(); - safeFitBounds(bound); - bindEditEvent(bound); - } - }, [control.status, bound]); - - useEffect(() => { - if (!featureRef.current) return; - - L.drawLocal.draw.handlers.polygon.tooltip.start = "برای شروع ترسیم محدوده، روی نقشه کلیک کنید"; - L.drawLocal.draw.handlers.polygon.tooltip.cont = "برای ادامه ترسیم، نقاط بعدی را کلیک کنید"; - L.drawLocal.draw.handlers.polygon.tooltip.end = "برای بستن محدوده، روی نقطه‌ی شروع کلیک کنید"; - - const drawControl = new L.Control.Draw({ - draw: { - polygon: { - shapeOptions: { - color: "#3388ff", - weight: 3, - clickable: true, - }, - }, - polyline: false, - rectangle: false, - circle: false, - marker: false, - circlemarker: false, - }, - edit: { - featureGroup: featureRef.current, - edit: true, - remove: false, - }, - }); - - drawControlRef.current = drawControl; - map.addControl(drawControl); - map.on(L.Draw.Event.CREATED, handlerCreatedBound); - - return () => { - map.off(L.Draw.Event.CREATED, handlerCreatedBound); - map.removeControl(drawControl); - }; - }, [map, handlerCreatedBound]); - - return ; -}; - -export default DrawBound; diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolygon/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolygon/index.jsx deleted file mode 100644 index 718600c..0000000 --- a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolygon/index.jsx +++ /dev/null @@ -1,116 +0,0 @@ -import { Delete, Route } from "@mui/icons-material"; -import { Box, Button, Stack, Typography } from "@mui/material"; -import { useReducer } from "react"; -import DrawBound from "./DrawBound"; - -const statusType = [ - { - id: 0, - message: "برای آغاز ترسیم محدوده، کلیک کنید!", - buttons: [ - { - label: "شروع ترسیم محدوده", - key: "start", - color: "primary", - icon: , - onclick: (controlDispach) => { - controlDispach({ type: "SET_STATUS", status: 1 }); - }, - }, - ], - }, - { - id: 1, - message: "محدوده‌ی موردنظر را با کلیک روی نقشه مشخص کنید. برای اتمام، روی نقطه‌ی ابتدایی کلیک کنید!", - buttons: [], - }, - { - id: 2, - message: "برای اصلاح محدوده، گوشه‌ها را بکشید. برای ترسیم دوباره، آن را حذف کنید", - buttons: [ - { - label: "حذف", - key: "end", - color: "error", - icon: , - onclick: (controlDispach) => { - controlDispach({ type: "SET_STATUS", status: 0 }); - }, - }, - ], - }, -]; - -const createInitialState = (bound) => { - if (bound) { - return { status: 2 }; - } - return { status: 0 }; -}; - -const reducer = (state, action) => { - switch (action.type) { - case "SET_STATUS": - return { ...state, status: action.status }; - default: - return state; - } -}; - -const MapControlPolygon = ({ bound, setBound }) => { - const [control, controlDispach] = useReducer(reducer, bound, createInitialState); - - return ( - <> - - - theme.palette.info.main, - borderBottomLeftRadius: 8, - borderBottomRightRadius: 8, - py: 0.5, - px: 2, - }} - > - - {statusType.find((st) => st.id == control.status).message} - - - - - - {statusType - .find((st) => st.id == control.status) - .buttons.map((button) => ( - - ))} - - - - ); -}; -export default MapControlPolygon; diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolyline/DrawBound/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolyline/DrawBound/index.jsx deleted file mode 100644 index 5456d12..0000000 --- a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolyline/DrawBound/index.jsx +++ /dev/null @@ -1,129 +0,0 @@ -import React, { useCallback, useEffect, useRef, useState } from "react"; -import L from "leaflet"; -import { FeatureGroup, useMap } from "react-leaflet"; -import "leaflet-draw"; - -const DrawBound = ({ control, controlDispach, bound, setBound }) => { - const map = useMap(); - const featureRef = useRef(null); - const [area, setArea] = useState(); - const drawControlRef = useRef(null); - - const safeFlyToBounds = (layer) => { - if (!layer || !map) return; - try { - const latLngs = layer.getLatLngs(); - map.flyToBounds(latLngs, { - paddingTopLeft: [20, 35], - paddingBottomRight: [20, 55], - }); - } catch (e) { - console.warn("flyToBounds failed:", e); - } - }; - - const safeFitBounds = (layer) => { - if (!layer || !map) return; - try { - const latLngs = layer.getLatLngs(); - map.fitBounds(latLngs, { - paddingTopLeft: [20, 35], - paddingBottomRight: [20, 55], - }); - } catch (e) { - console.warn("fitBounds failed:", e); - } - }; - - const bindEditEvent = (layer) => { - if (!layer) return; - layer.on("edit", function (e) { - const editedLayer = e.target; - setArea(editedLayer); - setBound(editedLayer); - safeFlyToBounds(editedLayer); - }); - }; - - const handlerCreatedBound = useCallback((event) => { - const { layer } = event; - layer.editing.enable(); - featureRef.current.addLayer(layer); // 🟢 اول اضافه به نقشه - setArea(layer); - setBound(layer); - safeFlyToBounds(layer); - bindEditEvent(layer); - controlDispach({ type: "SET_STATUS", status: 2 }); - }, []); - - useEffect(() => { - if ( - control.status === 1 && - drawControlRef.current && - drawControlRef.current._toolbars?.draw?._modes?.polyline?.handler - ) { - drawControlRef.current._toolbars.draw._modes.polyline.handler.enable(); - } - }, [control.status]); - - useEffect(() => { - if (control.status === 0 && area && featureRef.current) { - featureRef.current.removeLayer(area); - setArea(null); - setBound(null); - } - }, [control.status, area]); - - useEffect(() => { - if (control.status === 2 && bound && featureRef.current) { - setArea(bound); - featureRef.current.addLayer(bound); - bound.editing.enable(); - safeFitBounds(bound); - bindEditEvent(bound); - } - }, [control.status, bound]); - - useEffect(() => { - if (!featureRef.current) return; - - L.drawLocal.draw.handlers.polyline.tooltip.start = "برای شروع ترسیم مسیر، روی نقشه کلیک کنید"; - L.drawLocal.draw.handlers.polyline.tooltip.cont = "برای ادامه ترسیم، نقاط بعدی را کلیک کنید"; - L.drawLocal.draw.handlers.polyline.tooltip.end = "برای بستن مسیر، روی نقطه پایانی کلیک کنید"; - - const drawControl = new L.Control.Draw({ - draw: { - polyline: { - shapeOptions: { - color: "#3388ff", - weight: 3, - clickable: true, - }, - }, - polygon: false, - rectangle: false, - circle: false, - marker: false, - circlemarker: false, - }, - edit: { - featureGroup: featureRef.current, - edit: true, - remove: false, - }, - }); - - drawControlRef.current = drawControl; - map.addControl(drawControl); - map.on(L.Draw.Event.CREATED, handlerCreatedBound); - - return () => { - map.off(L.Draw.Event.CREATED, handlerCreatedBound); - map.removeControl(drawControl); - }; - }, [map, handlerCreatedBound]); - - return ; -}; - -export default DrawBound; diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolyline/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolyline/index.jsx deleted file mode 100644 index 8d9b5d0..0000000 --- a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/MapControlPolyline/index.jsx +++ /dev/null @@ -1,116 +0,0 @@ -import { Delete, Route } from "@mui/icons-material"; -import { Box, Button, Stack, Typography } from "@mui/material"; -import { useReducer } from "react"; -import DrawBound from "./DrawBound"; - -const statusType = [ - { - id: 0, - message: "برای آغاز ترسیم مسیر، کلیک کنید!", - buttons: [ - { - label: "شروع ترسیم مسیر", - key: "start", - color: "primary", - icon: , - onclick: (controlDispach) => { - controlDispach({ type: "SET_STATUS", status: 1 }); - }, - }, - ], - }, - { - id: 1, - message: "مسیر موردنظر را با کلیک روی نقشه مشخص کنید. برای اتمام، روی نقطه‌ی پایانی کلیک کنید!", - buttons: [], - }, - { - id: 2, - message: "برای اصلاح مسیر، گوشه‌ها را بکشید. برای ترسیم دوباره، آن را حذف کنید", - buttons: [ - { - label: "حذف", - key: "end", - color: "error", - icon: , - onclick: (controlDispach) => { - controlDispach({ type: "SET_STATUS", status: 0 }); - }, - }, - ], - }, -]; - -const createInitialState = (bound) => { - if (bound) { - return { status: 2 }; - } - return { status: 0 }; -}; - -const reducer = (state, action) => { - switch (action.type) { - case "SET_STATUS": - return { ...state, status: action.status }; - default: - return state; - } -}; - -const MapControlPolyline = ({ bound, setBound }) => { - const [control, controlDispach] = useReducer(reducer, bound, createInitialState); - - return ( - <> - - - theme.palette.info.main, - borderBottomLeftRadius: 8, - borderBottomRightRadius: 8, - py: 0.5, - px: 2, - }} - > - - {statusType.find((st) => st.id == control.status).message} - - - - - - {statusType - .find((st) => st.id == control.status) - .buttons.map((button) => ( - - ))} - - - - ); -}; -export default MapControlPolyline; diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/AlarmText.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/AlarmText.jsx new file mode 100644 index 0000000..0a3be1b --- /dev/null +++ b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/AlarmText.jsx @@ -0,0 +1,28 @@ +import { Box, Typography } from "@mui/material"; + +const AlarmText = ({ isSource }) => { + if (isSource) return null; + return ( + + + با کلیک بر روی مارکر موقعیت را انتخاب کنید + + + ); +}; + +export default AlarmText; diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/DataBox.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/DataBox.jsx new file mode 100644 index 0000000..c19cb6f --- /dev/null +++ b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/DataBox.jsx @@ -0,0 +1,53 @@ +import { Box, Button, TextField } from "@mui/material"; + +const DataBox = ({ isSource, isDest, sourcePosition, destPosition, editingTarget, onEditSource, onEditDest }) => { + if (!isSource) return null; + + return ( + +
+ + {isSource && isDest && ( + + )} +
+ {isDest && ( +
+ + +
+ )} +
+ ); +}; + +export default DataBox; diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/ShowRoute.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/ShowRoute.jsx new file mode 100644 index 0000000..8cc7e90 --- /dev/null +++ b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/ShowRoute.jsx @@ -0,0 +1,46 @@ +import { useEffect, useRef } from "react"; +import { Marker, Polyline, useMap } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; + +const ShowRoute = ({ area }) => { + const map = useMap(); + const defaultIconSize = [35, 35]; + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); + const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); + + if (!area) return null; + const coords = polyline.decode(area, 6); + + if (coords.length === 0) return null; + + const sourcePosition = coords[0]; + const destPosition = coords[coords.length - 1]; + useEffect(() => { + if (coords.length > 0) { + map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); + } + }, [area]); + + return ( + <> + + + + + ); +}; + +export default ShowRoute; diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/index.jsx new file mode 100644 index 0000000..06e7c9b --- /dev/null +++ b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/Routing/index.jsx @@ -0,0 +1,219 @@ +import { Marker, Polyline, useMapEvents } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import PrevSourceIcon from "@/assets/images/prev-source-icon.svg"; +import PrevDestIcon from "@/assets/images/prev-destination-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; +import { useEffect, useRef, useState } from "react"; +import DataBox from "./DataBox"; +import AlarmText from "./AlarmText"; + +const Routing = ({ setArea, setLocations, locations, area }) => { + const mapPrevSourceMarker = useRef(); + const mapPrevDestMarker = useRef(); + const mapRef = useRef(null); + const defaultIconSize = [35, 35]; + const [isSource, setIsSource] = useState(false); + const [sourcePosition, setSourcePosition] = useState(null); + const [isDest, setIsDest] = useState(false); + const [destPosition, setDestPosition] = useState(null); + const [routeCoords, setRouteCoords] = useState([]); + const [alternateCoords, setAlternateCoords] = useState([]); + const [editingTarget, setEditingTarget] = useState(null); + const [selectedRoute, setSelectedRoute] = useState(null); + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + const defaultIcon = createCustomIcon( + defaultIconSize, + isSource && editingTarget !== "source" ? SourceIcon.src : PrevSourceIcon.src + ); + + const prevDestIcon = createCustomIcon( + defaultIconSize, + isDest && editingTarget !== "dest" ? DestIcon.src : PrevDestIcon.src + ); + + const isMovingSource = !isSource || editingTarget === "source"; + const isMovingDest = isSource && (!isDest || editingTarget === "dest"); + + const map = useMapEvents({ + move(e) { + if (isMovingSource) mapPrevSourceMarker.current.setLatLng(e.target.getCenter()); + if (isMovingDest && mapPrevDestMarker.current) mapPrevDestMarker.current.setLatLng(e.target.getCenter()); + }, + movestart() { + if (isMovingSource) mapPrevSourceMarker.current.setIcon(createCustomIcon([45, 45], PrevSourceIcon.src)); + if (isMovingDest && mapPrevDestMarker.current) + mapPrevDestMarker.current.setIcon(createCustomIcon([45, 45], PrevDestIcon.src)); + }, + moveend() { + if (isMovingSource) + mapPrevSourceMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevSourceIcon.src)); + if (isMovingDest && mapPrevDestMarker.current) + mapPrevDestMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevDestIcon.src)); + }, + }); + + useEffect(() => { + mapRef.current = map; + }, [map]); + + useEffect(() => { + if (locations.length < 2) return; + const restoredSource = { lat: locations[0].lat, lng: locations[0].lon }; + const restoredDest = { lat: locations[1].lat, lng: locations[1].lon }; + setSourcePosition(restoredSource); + setDestPosition(restoredDest); + setIsSource(true); + setIsDest(true); + if (area) { + const decoded = polyline.decode(area, 6); + setRouteCoords(decoded); + setSelectedRoute({ index: "main", coords: decoded }); + setTimeout(() => { + mapRef.current?.flyToBounds(decoded, { padding: [50, 50], duration: 1.5 }); + }, 100); + } else { + fetchRoute(restoredSource, restoredDest); + } + }, []); + + const fetchRoute = async (source, dest) => { + const locs = [ + { lat: source.lat, lon: source.lng }, + { lat: dest.lat, lon: dest.lng }, + ]; + try { + const response = await fetch("https://jouya.141.ir/api/router/drive", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ locations: locs }), + }); + const data = await response.json(); + const shape = data.trip.legs[0].shape; + setLocations(locs); + setArea(shape); + const decoded = polyline.decode(shape, 6); + setRouteCoords(decoded); + setSelectedRoute({ index: "main", coords: decoded }); + + if (data.alternates?.length > 0) { + const decodedAlternates = data.alternates.map((alt) => polyline.decode(alt.trip.legs[0].shape, 6)); + setAlternateCoords(decodedAlternates); + } else { + setAlternateCoords([]); + } + map.flyToBounds(decoded, { padding: [50, 50], duration: 1.5 }); + } catch (error) { + console.error("Routing error:", error); + } + }; + + const handleMarkerClick = async () => { + if (!isSource || editingTarget === "source") { + const clickedPosition = mapPrevSourceMarker.current.getLatLng(); + setSourcePosition(clickedPosition); + setIsSource(true); + setEditingTarget(null); + setRouteCoords([]); + setAlternateCoords([]); + setSelectedRoute(null); + + if (editingTarget === "source" && destPosition) { + await fetchRoute(clickedPosition, destPosition); + } + } + }; + + const handleDestMarkerClick = async () => { + if (!isDest || editingTarget === "dest") { + const clickedPosition = mapPrevDestMarker.current.getLatLng(); + setDestPosition(clickedPosition); + setIsDest(true); + setEditingTarget(null); + + await fetchRoute(sourcePosition, clickedPosition); + } + }; + + const handleEditSource = () => { + setEditingTarget("source"); + setRouteCoords([]); + setAlternateCoords([]); + setSelectedRoute(null); + }; + + const handleEditDest = () => { + setEditingTarget("dest"); + setRouteCoords([]); + setAlternateCoords([]); + setSelectedRoute(null); + }; + + const handleSelectRoute = (index, coords) => { + setSelectedRoute({ index, coords }); + const encoded = polyline.encode(coords, 6); + setArea(encoded); + map.flyToBounds(coords, { padding: [50, 50], duration: 0.3 }); + }; + + return ( + <> + + + + {isSource && ( + + )} + {alternateCoords.map((coords, index) => ( + handleSelectRoute(index, coords) }} + /> + ))} + {routeCoords.length > 0 && ( + handleSelectRoute("main", routeCoords) }} + /> + )} + + ); +}; + +export default Routing; diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/SelectBoundType/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/SelectBoundType/index.jsx deleted file mode 100644 index ebb3c69..0000000 --- a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/SelectBoundType/index.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import SelectBox from "@/core/components/SelectBox"; - -export const boundTypes = [ - { id: "polygon", name_fa: "محدوده" }, - { id: "polyline", name_fa: "مسیر" }, -]; - -const SelectBoundType = ({ boundType, setBoundType, setBound, setAllData }) => { - return ( - <> - { - setBound(null); - setBoundType(newValue); - setAllData({ bound_type: newValue }); - }} - /> - - ); -}; -export default SelectBoundType; diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/index.jsx index 3d666fd..200c1e0 100644 --- a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/index.jsx +++ b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Area/index.jsx @@ -2,40 +2,29 @@ import MapLoading from "@/core/components/MapLayer/Loading"; import { Box, Button, DialogActions, DialogContent, Stack } from "@mui/material"; import dynamic from "next/dynamic"; import { useCallback, useState } from "react"; -import MapControlPolygon from "./MapControlPolygon"; -import MapControlPolyline from "./MapControlPolyline"; -import SelectBoundType from "./SelectBoundType"; +import Routing from "./Routing"; const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { loading: () => , ssr: false, }); const Area = ({ allData, setAllData, handlePrev, setTabState }) => { - const [bound, setBound] = useState(allData.bound); - const [boundType, setBoundType] = useState(allData.bound_type); + const [area, setArea] = useState(allData.area); + const [locations, setLocations] = useState(allData.locations); const handleNext = useCallback(() => { - setAllData({ bound: bound }); + setAllData({ area: area }); + setAllData({ locations: locations }); setTabState((s) => s + 1); - }, [bound]); + }, [area]); return ( <> - - {boundType == "polygon" ? ( - - ) : ( - - )} + @@ -44,8 +33,8 @@ const Area = ({ allData, setAllData, handlePrev, setTabState }) => { - diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Verify/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Verify/index.jsx index 09f865f..68f99e7 100644 --- a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Verify/index.jsx +++ b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/Verify/index.jsx @@ -5,7 +5,7 @@ import { Box, Button, Chip, DialogActions, DialogContent, Divider, Stack, Typogr import moment from "jalali-moment"; import dynamic from "next/dynamic"; import { useCallback } from "react"; -import ShowBound from "../../../showBound"; +import ShowRoute from "../Area/Routing/ShowRoute"; const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { loading: () => , ssr: false, @@ -22,6 +22,16 @@ const Verify = ({ allData, handlePrev, submitForm, submitting }) => { + + + + + + + + + + diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/index.jsx index 96de65d..0f9c7b2 100644 --- a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/index.jsx +++ b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/Form/index.jsx @@ -1,4 +1,4 @@ -import { AccessTime, Engineering, InsertDriveFile, Person, Verified } from "@mui/icons-material"; +import { AccessTime, Engineering, InsertDriveFile, Person, Verified, Map } from "@mui/icons-material"; import { Box, Tab, Tabs } from "@mui/material"; import { useReducer, useState } from "react"; import GetDateTime from "./GetDateTime"; @@ -6,6 +6,7 @@ import GetItemInfo from "./GetItemInfo"; import MachineAndDriver from "./MachineAndDriver"; import Rahdaran from "./Rahdaran"; import Verify from "./Verify"; +import Area from "./Area"; function TabPanel(props) { const { children, value, index } = props; @@ -61,8 +62,9 @@ const CreateForm = ({ defaultValues, submitForm, setOpen, submitting }) => { } label="مشخصات" /> } label="زمانبندی" /> } label="راننده" /> - } label="همراهان" /> - } label="بررسی نهایی" /> + } label="مختصات" /> + } label="همراهان" /> + } label="بررسی نهایی" /> { /> - { dispatch({ type: "changeData", data }); @@ -105,6 +107,16 @@ const CreateForm = ({ defaultValues, submitForm, setOpen, submitting }) => { /> + { + dispatch({ type: "changeData", data }); + }} + handlePrev={handlePrev} + setTabState={setTabState} + /> + + diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/index.jsx index 0e1f42b..f2d3d09 100644 --- a/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/index.jsx +++ b/src/components/dashboard/roadMissions/violations/Actions/CreateWithoutProcess/index.jsx @@ -28,6 +28,7 @@ const CreateWithoutProcess = ({ row, mutate }) => { start_date: `${result.start_date} ${moment(result.start_time).format("HH:mm")}`, end_date: `${result.end_date} ${moment(result.end_time).format("HH:mm")}`, driver: result.driver.id, + encoded_route: result.area, }, hasSidebarUpdate: true, }) @@ -49,7 +50,7 @@ const CreateWithoutProcess = ({ row, mutate }) => { - + setOpen(false)} @@ -77,6 +78,8 @@ const CreateWithoutProcess = ({ row, mutate }) => { end_point: "", region: "", driver: null, + area: null, + locations: [], }} submitForm={submitForm} submitting={submitting}