Feature/faaliyat rozane cartable
This commit is contained in:
@@ -1,28 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import {Autocomplete, CircularProgress, TextField} from "@mui/material";
|
||||
import {useEffect, useState} from "react";
|
||||
import { Autocomplete, CircularProgress, TextField } from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import {debounce} from "@mui/material/utils";
|
||||
import { debounce } from "@mui/material/utils";
|
||||
import { GET_CAR_LIST_SEARCH } from "@/core/utils/routes";
|
||||
|
||||
const CarCode = ({carCode, setCarCode}) => {
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const CarCode = ({ carCode, setCarCode, inputValueDefault = "", error }) => {
|
||||
const [inputValue, setInputValue] = useState(inputValueDefault);
|
||||
const [options, setOptions] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const requestServer = useRequest();
|
||||
|
||||
const fetchCarCodes = (inputValue, controller) => {
|
||||
const debouncer = debounce((query) => {
|
||||
if (query.length < 2) {
|
||||
if (!query || query?.length < 3) {
|
||||
setOptions([]);
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
requestServer(`car-code/api?${query}`, "get", {
|
||||
requestOptions: {signal: controller.signal}
|
||||
requestServer(`${GET_CAR_LIST_SEARCH}?machine_code=${query}`, "get", {
|
||||
requestOptions: { signal: controller.signal },
|
||||
})
|
||||
.then((response) => {
|
||||
setOptions(response || []);
|
||||
setOptions(response.data.data || []);
|
||||
})
|
||||
.catch(() => {
|
||||
setOptions([]);
|
||||
@@ -30,9 +28,9 @@ const CarCode = ({carCode, setCarCode}) => {
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}, 500)
|
||||
debouncer(inputValue)
|
||||
}
|
||||
}, 500);
|
||||
debouncer(inputValue);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
@@ -45,34 +43,35 @@ const CarCode = ({carCode, setCarCode}) => {
|
||||
value={carCode}
|
||||
size="small"
|
||||
onChange={(event, newValue) => {
|
||||
setCarCode(newValue);
|
||||
setCarCode(newValue || null); // Set an empty string if no value is selected
|
||||
}}
|
||||
inputValue={inputValue}
|
||||
onInputChange={(event, newInputValue) => {
|
||||
setInputValue(newInputValue);
|
||||
setInputValue(newInputValue || ""); // Prevent inputValue from being null or undefined
|
||||
}}
|
||||
options={options}
|
||||
getOptionLabel={(option) =>
|
||||
typeof option === 'string' ? option : option.name || option.code
|
||||
}
|
||||
getOptionLabel={(option) => (typeof option === "string" ? option : option.machine_code)}
|
||||
isOptionEqualToValue={(option, value) => {
|
||||
if (!value) return false; // Handle null/undefined values
|
||||
if (value === "") return option.machine_code === ""; // Handle empty string case
|
||||
return option.machine_code === (value?.machine_code || value);
|
||||
}}
|
||||
loading={loading}
|
||||
loadingText="درحال جستجوی کد خودرو"
|
||||
noOptionsText={
|
||||
inputValue.length < 2
|
||||
? "حداقل دو رقم از کد خودرو را وارد کنید"
|
||||
: "کد خودرویی یافت نشد"
|
||||
}
|
||||
sx={{width: 300}}
|
||||
noOptionsText={inputValue?.length < 3 ? "حداقل سه رقم از کد خودرو را وارد کنید" : "کد خودرویی یافت نشد"}
|
||||
fullWidth
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="کد خودرو"
|
||||
fullWidth
|
||||
error={!!error} // نمایش خطا
|
||||
helperText={error?.message} // پیام خطا
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
endAdornment: (
|
||||
<>
|
||||
{loading ? <CircularProgress size="25px" color="inherit"/> : null}
|
||||
{loading ? <CircularProgress size="25px" color="inherit" /> : null}
|
||||
{params.InputProps.endAdornment}
|
||||
</>
|
||||
),
|
||||
@@ -82,5 +81,4 @@ const CarCode = ({carCode, setCarCode}) => {
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default CarCode;
|
||||
export default CarCode;
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Box, Button, Drawer, styled } from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Controller, useForm, useWatch } from "react-hook-form";
|
||||
import * as Yup from "yup";
|
||||
import FilterBodyController from "./FilterBodyController";
|
||||
|
||||
const ScrollBox = styled(Box)({
|
||||
flexGrow: 1,
|
||||
@@ -95,27 +96,12 @@ function FilterBody({ columns, drawerState, setDrawerState }) {
|
||||
{columns.map(
|
||||
(column) =>
|
||||
column.enableColumnFilter && (
|
||||
<Controller
|
||||
<FilterBodyController
|
||||
key={column.id}
|
||||
name={`${column.id}`}
|
||||
column={column}
|
||||
control={control}
|
||||
render={({ field: { value, onBlur, onChange } }) => {
|
||||
let dependencyField;
|
||||
if (column.dependencyId) {
|
||||
dependencyField = useWatch({ control, name: column.dependencyId });
|
||||
}
|
||||
return (
|
||||
<FilterBodyField
|
||||
column={column}
|
||||
filterParameters={value}
|
||||
handleChange={onChange}
|
||||
handleBlur={onBlur}
|
||||
dependencyFieldValue={dependencyField}
|
||||
resetForm={() => reset()}
|
||||
errors={errors}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
errors={errors}
|
||||
reset={reset}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Controller, useWatch } from "react-hook-form";
|
||||
import FilterBodyField from "./FilterBodyField";
|
||||
|
||||
const FilterBodyController = ({ column, control, reset, errors }) => {
|
||||
const dependencyField = useWatch({ control, name: column?.dependencyId });
|
||||
|
||||
return (
|
||||
<Controller
|
||||
name={`${column.id}`}
|
||||
control={control}
|
||||
render={({ field: { value, onBlur, onChange } }) => (
|
||||
<FilterBodyField
|
||||
column={column}
|
||||
filterParameters={value}
|
||||
handleChange={onChange}
|
||||
handleBlur={onBlur}
|
||||
dependencyFieldValue={dependencyField || null}
|
||||
resetForm={() => reset()}
|
||||
errors={errors}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export default FilterBodyController;
|
||||
@@ -1,11 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { IconButton, Tooltip } from "@mui/material";
|
||||
import { IconButton, Tooltip, Badge } from "@mui/material";
|
||||
import AutorenewIcon from "@mui/icons-material/Autorenew";
|
||||
import useTableSetting from "@/lib/hooks/useTableSetting";
|
||||
import useDataTable from "@/lib/hooks/useDataTable";
|
||||
|
||||
function ResetStorage({ user_id, page_name, table_name }) {
|
||||
const { resetAction } = useTableSetting();
|
||||
const { isDirty } = useDataTable();
|
||||
const reset = () => {
|
||||
resetAction(user_id, page_name, table_name);
|
||||
};
|
||||
@@ -13,7 +14,20 @@ function ResetStorage({ user_id, page_name, table_name }) {
|
||||
return (
|
||||
<Tooltip title="بازنشانی اطلاعات">
|
||||
<IconButton onClick={reset} aria-label="reset table data">
|
||||
<AutorenewIcon />
|
||||
{isDirty ? (
|
||||
<Badge
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
color="primary"
|
||||
variant="dot"
|
||||
>
|
||||
<AutorenewIcon />
|
||||
</Badge>
|
||||
) : (
|
||||
<AutorenewIcon />
|
||||
)}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
137
src/core/components/MapInfoOneMarker.jsx
Normal file
137
src/core/components/MapInfoOneMarker.jsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Marker, useMapEvents } from "react-leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import L from "leaflet";
|
||||
import { Box, Button, Typography } from "@mui/material";
|
||||
import dynamic from "next/dynamic";
|
||||
import MapLoading from "@/core/components/MapLayer/Loading";
|
||||
import HereIcon from "@/assets/images/examine_marker_active.png";
|
||||
|
||||
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
|
||||
loading: () => <MapLoading />,
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
const createCustomIcon = (size, iconUrl, labelText) => {
|
||||
if (labelText) {
|
||||
return L.divIcon({
|
||||
html: `
|
||||
<div style="position: relative; display: inline-block; text-align: center;">
|
||||
<img
|
||||
src="${iconUrl}"
|
||||
style="width: ${size[0]}px; height: ${size[1]}px;"
|
||||
alt="icon"
|
||||
/>
|
||||
<div style="position: absolute; top: 100%; left: 50%; transform: translate(-50%, 0); color: black; font-size: 12px;">
|
||||
${labelText}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
iconSize: size,
|
||||
iconAnchor: [size[0] / 2, size[1]],
|
||||
popupAnchor: [0, -size[1]],
|
||||
});
|
||||
}
|
||||
|
||||
return L.icon({
|
||||
iconUrl: iconUrl,
|
||||
iconSize: size,
|
||||
iconAnchor: [size[0] / 2, size[1]],
|
||||
popupAnchor: [0, -size[1]],
|
||||
});
|
||||
};
|
||||
|
||||
const MapInteraction = ({ setValue, startLat, startLng }) => {
|
||||
const [isMarkerLocked, setIsMarkerLocked] = useState(!!(startLat && startLng)); // وضعیت قفل مارکر
|
||||
const [markerPosition, setMarkerPosition] = useState(
|
||||
startLat && startLng ? { lat: startLat, lng: startLng } : null
|
||||
);
|
||||
const markerRef = useRef();
|
||||
|
||||
const map = useMapEvents({
|
||||
move(e) {
|
||||
if (!isMarkerLocked && markerRef.current) {
|
||||
markerRef.current.setLatLng(e.target.getCenter());
|
||||
}
|
||||
},
|
||||
zoom(e) {
|
||||
if (!isMarkerLocked && markerRef.current) {
|
||||
markerRef.current.setLatLng(e.target.getCenter());
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (startLat && startLng) {
|
||||
const position = { lat: startLat, lng: startLng };
|
||||
map.setView(position, 15);
|
||||
}
|
||||
}, [startLat, startLng, map]);
|
||||
|
||||
const handleMarkerClick = () => {
|
||||
if (!isMarkerLocked) {
|
||||
const center = map.getCenter();
|
||||
setValue("start_point", { lat: center.lat.toString(), lng: center.lng.toString() });
|
||||
setMarkerPosition({ lat: center.lat, lng: center.lng }); // بهروزرسانی موقعیت مارکر
|
||||
setIsMarkerLocked(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleUnlockMarker = () => {
|
||||
setValue("start_point", null); // حذف مقدار قبلی
|
||||
setIsMarkerLocked(false); // باز کردن قفل مارکر
|
||||
setMarkerPosition(null); // تنظیم مارکر به مرکز نقشه
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Marker
|
||||
position={markerPosition || map.getCenter()} // استفاده از موقعیت
|
||||
ref={markerRef}
|
||||
icon={createCustomIcon([35, 35], HereIcon.src, "اینجا")}
|
||||
eventHandlers={{
|
||||
click: handleMarkerClick,
|
||||
}}
|
||||
/>
|
||||
{isMarkerLocked && (
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: 10,
|
||||
left: 10,
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<Button variant="contained" onClick={handleUnlockMarker}>
|
||||
ویرایش
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const MapInfoOneMarker = ({ setValue, errors, StartPoint = null }) => {
|
||||
return (
|
||||
<Box>
|
||||
<Box sx={{ width: "100%", height: "400px", marginBottom: "16px" }}>
|
||||
<MapLayer style={{ border: "1px solid #0009", borderRadius: "4px" }}>
|
||||
<MapInteraction
|
||||
setValue={setValue}
|
||||
startLat={StartPoint ? StartPoint.lat : null}
|
||||
startLng={StartPoint ? StartPoint.lng : null}
|
||||
/>
|
||||
</MapLayer>
|
||||
</Box>
|
||||
<Box display="flex" gap={2}>
|
||||
{errors.start_point && (
|
||||
<Typography color="error" variant="body2">
|
||||
{errors.start_point.message}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default MapInfoOneMarker;
|
||||
191
src/core/components/MapInfoTwoMarker.jsx
Normal file
191
src/core/components/MapInfoTwoMarker.jsx
Normal file
@@ -0,0 +1,191 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Marker, useMapEvents } from "react-leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import L from "leaflet";
|
||||
import { Box, Button, Typography } from "@mui/material";
|
||||
import dynamic from "next/dynamic";
|
||||
import MapLoading from "@/core/components/MapLayer/Loading";
|
||||
import EndIcon from "@/assets/images/examine_marker_active.png";
|
||||
import StartIcon from "@/assets/images/examine_marker.png";
|
||||
|
||||
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
|
||||
loading: () => <MapLoading />,
|
||||
ssr: false,
|
||||
});
|
||||
const createCustomIcon = (size, iconUrl, labelText) => {
|
||||
if (labelText) {
|
||||
return L.divIcon({
|
||||
html: `
|
||||
<div style="position: relative; display: inline-block; text-align: center;">
|
||||
<img
|
||||
src="${iconUrl}"
|
||||
style="width: ${size[0]}px; height: ${size[1]}px;"
|
||||
alt="icon"
|
||||
/>
|
||||
<div style="position: absolute; top: 100%; left: 50%; transform: translate(-50%, 0); color: black; font-size: 12px;">
|
||||
${labelText}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
iconSize: size,
|
||||
iconAnchor: [size[0] / 2, size[1]],
|
||||
popupAnchor: [0, -size[1]],
|
||||
});
|
||||
}
|
||||
|
||||
return L.icon({
|
||||
iconUrl: iconUrl,
|
||||
iconSize: size,
|
||||
iconAnchor: [size[0] / 2, size[1]],
|
||||
popupAnchor: [0, -size[1]],
|
||||
});
|
||||
};
|
||||
|
||||
const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => {
|
||||
const [isStartLocked, setIsStartLocked] = useState(!!(startLat && startLng)); // وضعیت قفل نقطه آغاز
|
||||
const [isEndLocked, setIsEndLocked] = useState(!!(endLat && endLng)); // وضعیت قفل نقطه پایان
|
||||
const [startPosition, setStartPosition] = useState(startLat && startLng ? { lat: startLat, lng: startLng } : null);
|
||||
const [endPosition, setEndPosition] = useState(endLat && endLng ? { lat: endLat, lng: endLng } : null);
|
||||
const startRef = useRef();
|
||||
const endRef = useRef();
|
||||
|
||||
const map = useMapEvents({
|
||||
move(e) {
|
||||
if (!isStartLocked && startRef.current) {
|
||||
startRef.current.setLatLng(e.target.getCenter());
|
||||
} else if (isStartLocked && !isEndLocked && endRef.current) {
|
||||
endRef.current.setLatLng(e.target.getCenter());
|
||||
}
|
||||
},
|
||||
zoom(e) {
|
||||
if (!isStartLocked && startRef.current) {
|
||||
startRef.current.setLatLng(e.target.getCenter());
|
||||
} else if (isStartLocked && !isEndLocked && endRef.current) {
|
||||
endRef.current.setLatLng(e.target.getCenter());
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (startLat && endLng) {
|
||||
map.fitBounds(
|
||||
[
|
||||
{ lat: startLat, lng: startLng },
|
||||
{ lat: endLat, lng: endLng },
|
||||
],
|
||||
{ paddingTopLeft: [16, 16], paddingBottomRight: [16, 130] }
|
||||
);
|
||||
}
|
||||
}, [startLat, map, endLng]);
|
||||
|
||||
const handleUnlockStart = () => {
|
||||
setIsStartLocked(false);
|
||||
setStartPosition(null);
|
||||
setValue("start_point", null);
|
||||
};
|
||||
|
||||
const handleUnlockEnd = () => {
|
||||
setIsEndLocked(false);
|
||||
setIsStartLocked(false);
|
||||
setEndPosition(null);
|
||||
setStartPosition(null);
|
||||
setValue("end_point", "");
|
||||
setValue("start_point", null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Marker
|
||||
position={startPosition || map.getCenter()}
|
||||
ref={startRef}
|
||||
icon={createCustomIcon([35, 35], StartIcon.src, "نقطه شروع")}
|
||||
eventHandlers={{
|
||||
click: () => {
|
||||
if (!isStartLocked) {
|
||||
const center = map.getCenter();
|
||||
setValue("start_point", { lat: center.lat.toString(), lng: center.lng.toString() });
|
||||
setStartPosition({ lat: center.lat, lng: center.lng });
|
||||
setIsStartLocked(true);
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
{isStartLocked && !isEndLocked && (
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: 10,
|
||||
left: 10,
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<Button variant={"contained"} onClick={handleUnlockStart}>
|
||||
ویرایش نقطه شروع
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
{isStartLocked && (
|
||||
<Marker
|
||||
position={endPosition || map.getCenter()}
|
||||
ref={endRef}
|
||||
icon={createCustomIcon([35, 35], EndIcon.src, "نقطه پایان")}
|
||||
eventHandlers={{
|
||||
click: () => {
|
||||
if (!isEndLocked) {
|
||||
const center = map.getCenter();
|
||||
setValue("end_point", { lat: center.lat.toString(), lng: center.lng.toString() });
|
||||
setEndPosition({ lat: center.lat, lng: center.lng });
|
||||
setIsEndLocked(true);
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{isEndLocked && (
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: 10,
|
||||
left: 10,
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<Button variant={"contained"} onClick={handleUnlockEnd}>
|
||||
ویرایش نقاط
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const MapInfoTwoMarker = ({ setValue, errors, StartPoint = null, EndPoint = null }) => {
|
||||
return (
|
||||
<Box>
|
||||
<Box sx={{ width: "100%", height: "400px", marginBottom: "16px" }}>
|
||||
<MapLayer style={{ border: "1px solid #0009", borderRadius: "4px" }}>
|
||||
<MapInteraction
|
||||
setValue={setValue}
|
||||
startLat={StartPoint ? StartPoint.lat : null}
|
||||
startLng={StartPoint ? StartPoint.lng : null}
|
||||
endLat={EndPoint ? EndPoint.lat : null}
|
||||
endLng={EndPoint ? EndPoint.lng : null}
|
||||
/>
|
||||
</MapLayer>
|
||||
</Box>
|
||||
<Box display="flex" gap={2}>
|
||||
{errors.start_point && (
|
||||
<Typography color="error" variant="body2">
|
||||
{errors.start_point.message}
|
||||
</Typography>
|
||||
)}
|
||||
{errors.end_point && (
|
||||
<Typography color="error" variant="body2">
|
||||
{errors.end_point.message}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
export default MapInfoTwoMarker;
|
||||
@@ -1,53 +1,70 @@
|
||||
import { LocalizationProvider, MobileDateTimePicker } from "@mui/x-date-pickers";
|
||||
import React from "react";
|
||||
import { LocalizationProvider, MobileDatePicker } from "@mui/x-date-pickers";
|
||||
import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali";
|
||||
import moment from "jalali-moment";
|
||||
import { faIR } from "@mui/x-date-pickers/locales";
|
||||
import { Box, IconButton, FormControl, FormHelperText, InputAdornment, Stack } from "@mui/material";
|
||||
import { Box, FormHelperText, IconButton, InputAdornment } from "@mui/material";
|
||||
import ClearIcon from "@mui/icons-material/Clear";
|
||||
import moment from "jalali-moment";
|
||||
|
||||
export default function PickerWithButtonField({ formik, name, value, error, touched, disabled }) {
|
||||
function MuiDatePicker({ value, setFieldValue, name, minDate, maxDate, helperText, placeholder, error }) {
|
||||
return (
|
||||
<FormControl variant="outlined" fullWidth size="small" error={!!error}>
|
||||
<Stack sx={{ width: "100%" }} direction={"row"}>
|
||||
<LocalizationProvider
|
||||
dateAdapter={AdapterDateFnsJalali}
|
||||
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
|
||||
>
|
||||
<MobileDateTimePicker
|
||||
ampm={false}
|
||||
disableFuture
|
||||
value={value ? new Date(value) : null}
|
||||
onChange={(newValue) => {
|
||||
const formattedDate = moment(newValue).locale("en").format("YYYY-MM-DD HH:mm");
|
||||
formik.setFieldValue(name, formattedDate);
|
||||
}}
|
||||
slotProps={{
|
||||
textField: {
|
||||
placeholder:
|
||||
name === "start_date" ? "تاریخ شروع را وارد کنید" : "تاریخ اتمام را وارد کنید",
|
||||
variant: "outlined",
|
||||
disabled,
|
||||
fullWidth: true,
|
||||
error: !!error,
|
||||
helperText: touched && error,
|
||||
size: "small", // Ensure that the TextField is small
|
||||
InputProps: {
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton
|
||||
size="small" // Set size="small" for IconButton
|
||||
onClick={() => formik.setFieldValue(name, null)}
|
||||
>
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
},
|
||||
<Box sx={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>
|
||||
<LocalizationProvider
|
||||
dateAdapter={AdapterDateFnsJalali}
|
||||
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
|
||||
>
|
||||
<MobileDatePicker
|
||||
value={value ? new Date(value) : null}
|
||||
sx={{ width: "100%" }}
|
||||
id={name}
|
||||
name={name}
|
||||
closeOnSelect
|
||||
disableFuture
|
||||
label={helperText}
|
||||
aria-describedby="component-helper-text"
|
||||
onChange={(value) => {
|
||||
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: {
|
||||
error: error,
|
||||
size: "small",
|
||||
placeholder: placeholder,
|
||||
InputProps: {
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
setFieldValue(name, "");
|
||||
}}
|
||||
sx={{
|
||||
color: "#bfbfbf",
|
||||
"&:hover": {
|
||||
backgroundColor: "rgba(189, 189, 189, 0.1)",
|
||||
color: "#363434",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
</Stack>
|
||||
</FormControl>
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text" sx={{ color: error ? "#d32f2f" : "unset" }}>
|
||||
{helperText ? helperText : ""}
|
||||
</FormHelperText>
|
||||
</LocalizationProvider>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default MuiDatePicker;
|
||||
|
||||
75
src/core/components/MuiTimePicker.jsx
Normal file
75
src/core/components/MuiTimePicker.jsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import React from "react";
|
||||
import { LocalizationProvider, MobileTimePicker } 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 { parseISO, format } from "date-fns";
|
||||
|
||||
function MuiTimePicker({ value, setFieldValue, name, minTime, maxTime, helperText, placeholder, error }) {
|
||||
// Ensure value, minTime, maxTime are Date objects
|
||||
const parsedValue = value ? (typeof value === "string" ? parseISO(value) : value) : null;
|
||||
const parsedMinTime = minTime ? (typeof minTime === "string" ? parseISO(minTime) : minTime) : null;
|
||||
const parsedMaxTime = maxTime && (typeof maxTime === "string" ? parseISO(maxTime) : null);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>
|
||||
<LocalizationProvider
|
||||
dateAdapter={AdapterDateFnsJalali}
|
||||
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
|
||||
>
|
||||
<MobileTimePicker
|
||||
value={parsedValue}
|
||||
sx={{ width: "100%" }}
|
||||
id={name}
|
||||
closeOnSelect
|
||||
label={helperText ? helperText : placeholder}
|
||||
ampm={false}
|
||||
timeSteps={{ hours: 1, minutes: 5 }}
|
||||
views={["hours", "minutes"]}
|
||||
name={name}
|
||||
onChange={(newValue) => {
|
||||
const formattedTime = newValue ? format(new Date(newValue), "HH:mm") : "";
|
||||
setFieldValue(name, formattedTime);
|
||||
}}
|
||||
minTime={parsedMinTime}
|
||||
maxTime={parsedMaxTime}
|
||||
slotProps={{
|
||||
textField: {
|
||||
placeholder: placeholder,
|
||||
size: "small",
|
||||
error: error,
|
||||
InputProps: {
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
setFieldValue(name, "");
|
||||
}}
|
||||
sx={{
|
||||
color: "#bfbfbf",
|
||||
"&:hover": {
|
||||
backgroundColor: "rgba(189, 189, 189, 0.1)",
|
||||
color: "#363434",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<ClearIcon />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<FormHelperText id="component-helper-text" sx={{ color: error ? "#d32f2f" : "unset" }}>
|
||||
{helperText ? helperText : ""}
|
||||
</FormHelperText>
|
||||
</LocalizationProvider>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default MuiTimePicker;
|
||||
90
src/core/components/RahdarCode.jsx
Normal file
90
src/core/components/RahdarCode.jsx
Normal file
@@ -0,0 +1,90 @@
|
||||
"use client";
|
||||
import { Autocomplete, CircularProgress, TextField } from "@mui/material";
|
||||
import { useEffect, useState } from "react";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import { debounce } from "@mui/material/utils";
|
||||
import { GET_RAHDARANS_LIST_SEARCH } from "@/core/utils/routes";
|
||||
|
||||
const RahdarCode = ({ rahdarsCode, setRahdarsCode, error }) => {
|
||||
const [inputValue, setInputValue] = useState(""); // مدیریت مقدار تایپشده
|
||||
const [options, setOptions] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const requestServer = useRequest();
|
||||
|
||||
const fetchRahdarCodes = (inputValue, controller) => {
|
||||
const debouncer = debounce((query) => {
|
||||
if ((query || "").length < 3) {
|
||||
setOptions([]);
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
requestServer(`${GET_RAHDARANS_LIST_SEARCH}?code=${query}`, "get", {
|
||||
requestOptions: { signal: controller.signal },
|
||||
})
|
||||
.then((response) => {
|
||||
setOptions(response.data.data || []);
|
||||
})
|
||||
.catch(() => {
|
||||
setOptions([]);
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}, 500);
|
||||
debouncer(inputValue);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
fetchRahdarCodes(inputValue, controller);
|
||||
return () => controller.abort();
|
||||
}, [inputValue]);
|
||||
|
||||
return (
|
||||
<Autocomplete
|
||||
multiple // قابلیت انتخاب چندگانه
|
||||
value={rahdarsCode} // آرایه موارد انتخابشده
|
||||
size="small"
|
||||
onChange={(event, newValue) => {
|
||||
setRahdarsCode(newValue || []); // بهروزرسانی موارد انتخابشده
|
||||
}}
|
||||
inputValue={inputValue} // مقدار تایپشده
|
||||
onInputChange={(event, newInputValue) => {
|
||||
setInputValue(newInputValue || ""); // بهروزرسانی مقدار تایپشده
|
||||
}}
|
||||
options={options} // گزینههای موجود
|
||||
getOptionLabel={(option) => (typeof option === "string" ? option : `${option.code} - ${option.name}`)}
|
||||
isOptionEqualToValue={(option, value) => {
|
||||
if (!value) return false;
|
||||
if (value === "") return option.code === "";
|
||||
return option.code === (value?.code || value);
|
||||
}}
|
||||
loading={loading}
|
||||
loadingText="درحال جستجوی کد راهدار"
|
||||
noOptionsText={
|
||||
(inputValue || "").length < 3 ? "حداقل سه رقم از کد راهدار را وارد کنید" : "کد راهداری یافت نشد"
|
||||
}
|
||||
fullWidth
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="کد راهداران"
|
||||
fullWidth
|
||||
error={!!error}
|
||||
helperText={error?.message}
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
endAdornment: (
|
||||
<>
|
||||
{loading ? <CircularProgress size="25px" color="inherit" /> : null}
|
||||
{params.InputProps.endAdornment}
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default RahdarCode;
|
||||
181
src/core/components/ShowLocationMarker.jsx
Normal file
181
src/core/components/ShowLocationMarker.jsx
Normal file
@@ -0,0 +1,181 @@
|
||||
"use client";
|
||||
|
||||
import { Marker, useMap } from "react-leaflet";
|
||||
import { useEffect } from "react";
|
||||
import L from "leaflet";
|
||||
import AzmayeshActiveIcon from "@/assets/images/examine_marker_active.png";
|
||||
import { Box, FormControl, InputAdornment, InputLabel, OutlinedInput, Stack, useMediaQuery } from "@mui/material";
|
||||
import VerifiedIcon from "@mui/icons-material/Verified";
|
||||
import { useTheme } from "@emotion/react";
|
||||
|
||||
const ShowLocationMarker = ({ start_lat, start_lng, end_lat, end_lng }) => {
|
||||
const map = useMap();
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
|
||||
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]],
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (start_lat && end_lng) {
|
||||
map.fitBounds(
|
||||
[
|
||||
{ lat: start_lat, lng: start_lng },
|
||||
{ lat: end_lat, lng: end_lng },
|
||||
],
|
||||
{ paddingTopLeft: [16, 16], paddingBottomRight: [16, 130] }
|
||||
);
|
||||
} else if (start_lat) {
|
||||
map.setView({ lat: start_lat, lng: start_lng }, 15);
|
||||
}
|
||||
}, [start_lat, start_lng, map, end_lng, end_lat]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{start_lat && start_lng && (
|
||||
<Marker
|
||||
position={{ lat: start_lat, lng: start_lng }}
|
||||
icon={createCustomIcon(defaultIconSize, AzmayeshActiveIcon.src)}
|
||||
/>
|
||||
)}
|
||||
{end_lat && end_lng && (
|
||||
<Marker
|
||||
position={{ lat: end_lat, lng: end_lng }}
|
||||
icon={createCustomIcon(defaultIconSize, AzmayeshActiveIcon.src)}
|
||||
/>
|
||||
)}
|
||||
<Box
|
||||
sx={{
|
||||
zIndex: "400",
|
||||
position: "absolute",
|
||||
background: "#ffffff94",
|
||||
p: 2,
|
||||
borderRadius: "10px",
|
||||
boxShadow: "rgba(0, 0, 0, 0.24) 0px 3px 8px",
|
||||
bottom: "5px",
|
||||
left: "5px",
|
||||
right: "5px",
|
||||
}}
|
||||
>
|
||||
<Stack direction={end_lat && end_lng ? "row" : "column"} spacing={end_lat && end_lng ? 0.5 : 0}>
|
||||
{start_lat && start_lng && (
|
||||
<Stack spacing={1}>
|
||||
<FormControl size="small" variant="outlined">
|
||||
<InputLabel sx={{ color: "success.main" }} htmlFor="start_lat">
|
||||
{end_lat && end_lng ? "طول جغرافیایی شروع" : "طول جغرافیایی"}
|
||||
</InputLabel>
|
||||
<OutlinedInput
|
||||
id="start_lat"
|
||||
type="text"
|
||||
size="small"
|
||||
readOnly
|
||||
fullWidth
|
||||
sx={{
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: "success.main",
|
||||
},
|
||||
color: "success.main",
|
||||
}}
|
||||
value={start_lat}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<VerifiedIcon color="success" />
|
||||
</InputAdornment>
|
||||
}
|
||||
label={end_lat && end_lng ? "طول جغرافیایی شروع" : "طول جغرافیایی"}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl size="small" variant="outlined">
|
||||
<InputLabel sx={{ color: "success.main" }} htmlFor="start_lng">
|
||||
{end_lat && end_lng ? "عرض جغرافیایی شروع" : "عرض جغرافیایی"}
|
||||
</InputLabel>
|
||||
<OutlinedInput
|
||||
id="start_lng"
|
||||
type="text"
|
||||
size="small"
|
||||
readOnly
|
||||
fullWidth
|
||||
sx={{
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: "success.main",
|
||||
},
|
||||
color: "success.main",
|
||||
}}
|
||||
value={start_lng}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<VerifiedIcon color="success" />
|
||||
</InputAdornment>
|
||||
}
|
||||
label={end_lat && end_lng ? "عرض جغرافیایی شروع" : "عرض جغرافیایی"}
|
||||
/>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
)}
|
||||
{end_lat && end_lng && (
|
||||
<Stack spacing={1}>
|
||||
<FormControl size="small" variant="outlined">
|
||||
<InputLabel sx={{ color: "success.main" }} htmlFor="end_lat">
|
||||
طول جغرافیایی پایان
|
||||
</InputLabel>
|
||||
<OutlinedInput
|
||||
id="end_lat"
|
||||
type="text"
|
||||
size="small"
|
||||
readOnly
|
||||
sx={{
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: "success.main",
|
||||
},
|
||||
color: "success.main",
|
||||
}}
|
||||
value={end_lat}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<VerifiedIcon color="success" />
|
||||
</InputAdornment>
|
||||
}
|
||||
label="طول جغرافیایی پایان"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl size="small" variant="outlined">
|
||||
<InputLabel sx={{ color: "success.main" }} htmlFor="end_lng">
|
||||
عرض جغرافیایی پایان
|
||||
</InputLabel>
|
||||
<OutlinedInput
|
||||
id="end_lng"
|
||||
type="text"
|
||||
size="small"
|
||||
readOnly
|
||||
sx={{
|
||||
"& .MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: "success.main",
|
||||
},
|
||||
color: "success.main",
|
||||
}}
|
||||
value={end_lng}
|
||||
endAdornment={
|
||||
<InputAdornment position="end">
|
||||
<VerifiedIcon color="success" />
|
||||
</InputAdornment>
|
||||
}
|
||||
label="عرض جغرافیایی پایان"
|
||||
/>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ShowLocationMarker;
|
||||
@@ -61,6 +61,35 @@ export const errorUnauthorizedToast = (toastContainer) =>
|
||||
draggable: true,
|
||||
}
|
||||
);
|
||||
export const errorAccessDeniedToast = (message, toastContainer) =>
|
||||
toast.error(
|
||||
() => (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "start",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Dangerous color="error" sx={{ mr: 1.6 }} />
|
||||
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||
<Typography variant="caption">{message || "Access Denied"}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
),
|
||||
{
|
||||
icon: false,
|
||||
containerId: toastContainer,
|
||||
autoClose: 3000,
|
||||
hideProgressBar: true,
|
||||
pauseOnHover: true,
|
||||
closeOnClick: false,
|
||||
draggable: true,
|
||||
}
|
||||
);
|
||||
|
||||
export const errorLogicToast = (message, toastContainer) =>
|
||||
toast.error(
|
||||
|
||||
94
src/core/components/UploadSystem.jsx
Normal file
94
src/core/components/UploadSystem.jsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import { Box, Button, Paper, Typography } from "@mui/material";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
|
||||
import { useRef } from "react";
|
||||
|
||||
const UploadSystem = ({ selectedImage, handleUploadChange, imageSize, fileType, showAddIcon }) => {
|
||||
const fileInputRef = useRef(null);
|
||||
|
||||
const handleClick = () => {
|
||||
fileInputRef.current.click();
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ width: "100%", my: 1 }}>
|
||||
{showAddIcon ? (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
border: "1px solid #b3b3b3",
|
||||
borderRadius: "10px",
|
||||
cursor: "pointer",
|
||||
padding: "5px",
|
||||
height: imageSize[1],
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<AddIcon sx={{ fontSize: "2rem", color: "#a19d9d" }} />
|
||||
<Typography
|
||||
variant="subtitle2"
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
fontSize: "0.8rem",
|
||||
color: "#a19d9d",
|
||||
mt: 1,
|
||||
}}
|
||||
textAlign="center"
|
||||
>
|
||||
فرمت قابل قبول : png, jpg
|
||||
<br />
|
||||
حداکثر 3Mb
|
||||
</Typography>
|
||||
</Box>
|
||||
) : (
|
||||
<>
|
||||
{fileType && fileType.startsWith("image/") && (
|
||||
<Box
|
||||
width="100%"
|
||||
height={imageSize[1]}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
cursor: "pointer",
|
||||
objectFit: "contain",
|
||||
border: "1px solid #b3b3b3",
|
||||
borderRadius: "10px",
|
||||
padding: "5px",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundSize: "contain",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center",
|
||||
backgroundImage: `url(${selectedImage})`,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
style={{ display: "none" }}
|
||||
onChange={handleUploadChange}
|
||||
ref={fileInputRef}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
export default UploadSystem;
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
import { toast } from "react-toastify";
|
||||
import {
|
||||
errorAccessDeniedToast,
|
||||
errorClientToast,
|
||||
errorLogicToast,
|
||||
errorServerToast,
|
||||
@@ -22,6 +23,9 @@ const errorClient = (response, notification, toastContainer, logout) => {
|
||||
logout();
|
||||
if (notification) errorUnauthorizedToast(toastContainer);
|
||||
break;
|
||||
case 403:
|
||||
if (notification) errorAccessDeniedToast(response.data.message, toastContainer);
|
||||
break;
|
||||
case 422:
|
||||
if ("type" in response.data) {
|
||||
if (Array.isArray(response.data.message)) {
|
||||
|
||||
@@ -108,7 +108,7 @@ export const pageMenu = [
|
||||
id: "roadItemManagmentSupervisorCartable",
|
||||
label: "کارتابل",
|
||||
type: "page",
|
||||
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/supervisor/cartable",
|
||||
route: "/dashboard/road-items/supervisor",
|
||||
permissions: [
|
||||
"show-road-item-supervise-cartable",
|
||||
"show-road-item-supervise-cartable-province",
|
||||
@@ -135,7 +135,7 @@ export const pageMenu = [
|
||||
id: "roadItemManagmentOparationCartable",
|
||||
label: "کارتابل",
|
||||
type: "page",
|
||||
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/operator/cartable",
|
||||
route: "/dashboard/road-items/operator",
|
||||
permissions: ["create-road-item"],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -27,7 +27,25 @@ export const DELETE_SAMPLE_LIST = api + "/api/v3/azmayesh_samples/delete";
|
||||
export const DELETE_AZMAYESH_TYPE_LIST = api + "/api/v3/azmayesh_types/delete";
|
||||
export const ADD_AZMAYESH_TYPE = api + "/api/v3/azmayesh_types/store";
|
||||
export const UPDATE_AZMAYESH_TYPE = api + "/api/v3/azmayesh_types/update";
|
||||
export const GET_OPERATOR_LIST = "/v3/api/fake-operator-list";
|
||||
export const EXPORT_OPERATOR_LIST = "https://rms.rmto.ir/v2/road_patrols/operator/cartable/report";
|
||||
export const GET_SUPERVISOR_LIST = "/v3/api/fake-supervisor-list";
|
||||
export const EXPORT_SUPERVISOR_LIST = "https://rms.rmto.ir/v2/road_patrols/supervisor/cartable/report";
|
||||
|
||||
//road patrol
|
||||
export const GET_ROAD_PATROL_OPERATOR_LIST = "/v3/api/fake-road-patrol/operator";
|
||||
export const EXPORT_ROAD_PATROL_OPERATOR_LIST = "https://rms.rmto.ir/v2/road_patrols/operator/cartable/report";
|
||||
export const GET_ROAD_PATROL_SUPERVISOR_LIST = "/v3/api/fake-road-patrol/supervisor";
|
||||
export const EXPORT_ROAD_PATROL_SUPERVISOR_LIST = "https://rms.rmto.ir/v2/road_patrols/supervisor/cartable/report";
|
||||
|
||||
// road items
|
||||
export const GET_ROAD_ITEMS_SUPERVISOR_LIST = api + "/api/v3/road_items/supervisor_index";
|
||||
export const EXPORT_ROAD_ITEMS_SUPERVISOR_LIST = api + "/api/v3/road_items/supervisor_report";
|
||||
export const GET_ROAD_ITEMS_OPERATOR_LIST = api + "/api/v3/road_items/operator_index";
|
||||
export const EXPORT_ROAD_ITEMS_OPERATOR_LIST = api + "/api/v3/road_items/operator_report";
|
||||
export const GET_ROAD_ITEMS_ITEM = "https://rms.witel.ir/v2/items";
|
||||
export const GET_ROAD_ITEMS_SUB_ITEM = "https://rms.witel.ir/v2/sub_items";
|
||||
export const CREATE_ROAD_ITEMS = api + "/api/v3/road_items/store";
|
||||
export const UPDATE_ROAD_ITEMS = api + "/api/v3/road_items/update";
|
||||
export const VERIFY_BY_SUPERVISOR = api + "/api/v3/road_items/verify_by_supervisor";
|
||||
export const REJECT_BY_SUPERVISOR = api + "/api/v3/road_items/verify_by_supervisor";
|
||||
export const DELETE_BY_SUPERVISOR = api + "/api/v3/road_items/delete";
|
||||
export const RESTORE_BY_SUPERVISOR = api + "/api/v3/road_items/restore";
|
||||
export const GET_CAR_LIST_SEARCH = api + "/api/v3/cmms_machines/search";
|
||||
export const GET_RAHDARANS_LIST_SEARCH = api + "/api/v3/rahdaran/search";
|
||||
|
||||
Reference in New Issue
Block a user