add base routing

This commit is contained in:
2026-05-20 08:54:41 +03:30
parent 83587962fd
commit 6b70eb8e27
4 changed files with 142 additions and 108 deletions

View File

@@ -1,116 +1,113 @@
import { Delete, Route } from "@mui/icons-material";
import { Box, Button, Stack, Typography } from "@mui/material";
import { useReducer } from "react";
import DrawBound from "./DrawBound";
"use client";
const statusType = [
{
id: 0,
message: "برای آغاز ترسیم مسیر، کلیک کنید!",
buttons: [
{
label: "شروع ترسیم مسیر",
key: "start",
color: "primary",
icon: <Route />,
onclick: (controlDispach) => {
controlDispach({ type: "SET_STATUS", status: 1 });
},
},
],
},
{
id: 1,
message: "مسیر موردنظر را با کلیک روی نقشه مشخص کنید. برای اتمام، روی نقطه‌ی پایانی کلیک کنید!",
buttons: [],
},
{
id: 2,
message: "برای اصلاح مسیر، گوشه‌ها را بکشید. برای ترسیم دوباره، آن را حذف کنید",
buttons: [
{
label: "حذف",
key: "end",
color: "error",
icon: <Delete />,
onclick: (controlDispach) => {
controlDispach({ type: "SET_STATUS", status: 0 });
},
},
],
},
];
import { useEffect, useState } from "react";
import { Marker, Polyline, useMap } from "react-leaflet";
import L from "leaflet";
const createInitialState = (bound) => {
if (bound) {
return { status: 2 };
}
return { status: 0 };
};
// ===== Icons =====
const originIcon = new L.Icon({
iconUrl: "/icons/origin-marker.png",
iconSize: [32, 32],
iconAnchor: [16, 32],
});
const reducer = (state, action) => {
switch (action.type) {
case "SET_STATUS":
return { ...state, status: action.status };
default:
return state;
}
};
const destinationIcon = new L.Icon({
iconUrl: "/icons/destination-marker.png",
iconSize: [32, 32],
iconAnchor: [16, 32],
});
const MapControlPolyline = ({ bound, setBound }) => {
const [control, controlDispach] = useReducer(reducer, bound, createInitialState);
// ===== Track Center =====
function MapCenterTracker({ setCenter }) {
const map = useMap();
useEffect(() => {
const updateCenter = () => {
setCenter(map.getCenter());
};
updateCenter();
map.on("move", updateCenter);
return () => {
map.off("move", updateCenter);
};
}, [map, setCenter]);
return null;
}
// ===== Fixed Center Marker =====
function FixedCenterMarker() {
return (
<div
style={{
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -100%)",
zIndex: 1000,
pointerEvents: "none",
}}
>
<img src="/icons/pin-center.png" width={40} height={40} alt="center" />
</div>
);
}
export default function Example() {
const [center, setCenter] = useState(null);
const [origin, setOrigin] = useState(null);
const [destination, setDestination] = useState(null);
const [step, setStep] = useState("origin");
const handleOk = () => {
if (!center) return;
if (step === "origin") {
setOrigin(center);
setStep("destination");
return;
}
if (step === "destination") {
setDestination(center);
setStep("done");
}
};
return (
<>
<DrawBound bound={bound} setBound={setBound} control={control} controlDispach={controlDispach} />
<Stack
direction={"row"}
justifyContent={"center"}
sx={{ position: "absolute", left: 0, top: 0, zIndex: 2000, width: "100%" }}
>
<Box
sx={{
background: (theme) => theme.palette.info.main,
borderBottomLeftRadius: 8,
borderBottomRightRadius: 8,
py: 0.5,
px: 2,
}}
>
<Typography align="center" component={"div"} variant="caption" color={"#fff"}>
{statusType.find((st) => st.id == control.status).message}
</Typography>
</Box>
</Stack>
<Box
sx={{
position: "absolute",
left: 0,
bottom: 0,
zIndex: 2000,
width: "100%",
py: 1,
background: "linear-gradient(to top, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0))",
<div>
<div
style={{
position: "relative",
height: "400px",
}}
>
<Stack direction={"row"} justifyContent={"center"} spacing={2}>
{statusType
.find((st) => st.id == control.status)
.buttons.map((button) => (
<Button
size="small"
key={button.key}
variant="contained"
onClick={() => button.onclick(controlDispach)}
color={button.color}
startIcon={button.icon}
>
{button.label}
</Button>
))}
</Stack>
</Box>
</>
<MapCenterTracker setCenter={setCenter} />
{/* saved markers */}
{origin && <Marker position={origin} icon={originIcon} />}
{destination && <Marker position={destination} icon={destinationIcon} />}
{/* route line */}
{origin && destination && <Polyline positions={[origin, destination]} />}
{/* fixed center pin */}
{step !== "done" && <FixedCenterMarker />}
</div>
<div style={{ marginTop: 16, position: "absolute", z : 50, top : 5 }}>
<button onClick={handleOk}>
{step === "origin" && "Set Origin"}
{step === "destination" && "Set Destination"}
{step === "done" && "Completed"}
</button>
</div>
</div>
);
};
export default MapControlPolyline;
}

View File

@@ -3,6 +3,7 @@ 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";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading />,
ssr: false,
@@ -22,7 +23,7 @@ const Area = ({ allData, setAllData, handlePrev, setTabState }) => {
<Stack spacing={2}>
<Box sx={{ width: "100%", height: "400px" }}>
<MapLayer style={{ borderRadius: "4px" }}>
<MapControlPolyline bound={bound} setBound={setBound} boundType={"polyline"} />
<Example />
</MapLayer>
</Box>
</Stack>