Feature/abniye fani

This commit is contained in:
2025-02-19 11:52:27 +00:00
committed by AmirHossein Mahmoodi
parent ed4724a7de
commit f5ff082258
33 changed files with 2085 additions and 126 deletions

View File

@@ -37,7 +37,7 @@ const createCustomIcon = (size, iconUrl, labelText, color) => {
};
const MAX_ZOOM_FOR_MARKER = 13;
const MapInteraction = ({ setValue, startLat, startLng }) => {
const MapInteraction = ({ setValue, startLat, startLng, title }) => {
const [isMarkerLocked, setIsMarkerLocked] = useState(!!(startLat && startLng));
const [enableSend, setEnableSend] = useState(false);
const [startIconColor, setStartIconColor] = useState(startLat ? "#1CAC66" : "#003d4f");
@@ -109,7 +109,7 @@ const MapInteraction = ({ setValue, startLat, startLng }) => {
>
<Zoom in={!enableSend}>
<Alert sx={{ mt: 1, py: 0.5, px: 2, borderRadius: 2, border: 1 }} icon={false} color={"warning"}>
برای ثبت محل فعالیت، لطفاً نقشه را بیشتر زوم کنید.
{title}
</Alert>
</Zoom>
</Stack>
@@ -131,7 +131,12 @@ const MapInteraction = ({ setValue, startLat, startLng }) => {
);
};
const MapInfoOneMarker = ({ setValue, errors, StartPoint = null }) => {
const MapInfoOneMarker = ({
setValue,
errors,
StartPoint = null,
title = "برای ثبت محل فعالیت، لطفاً نقشه را بیشتر زوم کنید.",
}) => {
return (
<Box>
<Box sx={{ width: "100%", height: "400px", marginBottom: "16px" }}>
@@ -140,6 +145,7 @@ const MapInfoOneMarker = ({ setValue, errors, StartPoint = null }) => {
setValue={setValue}
startLat={StartPoint ? StartPoint.lat : null}
startLng={StartPoint ? StartPoint.lng : null}
title={title}
/>
</MapLayer>
</Box>

View File

@@ -8,67 +8,69 @@ import moment from "jalali-moment";
function MuiDatePicker({ value, setFieldValue, name, minDate, maxDate, helperText, placeholder, error, label }) {
return (
<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={label}
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,
InputLabelProps: {
shrink: true,
<>
<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={label}
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,
InputLabelProps: {
shrink: true,
},
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>
),
},
},
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>
),
},
},
}}
/>
{helperText ? (
<FormHelperText id="component-helper-text" sx={{ color: error ? "#d32f2f" : "unset" }}>
{helperText}
</FormHelperText>
) : null}
</LocalizationProvider>
</Box>
}}
/>
</LocalizationProvider>
</Box>
{helperText && (
<FormHelperText id="component-helper-text" sx={{ color: error ? "#d32f2f" : "unset", ml: 2 }}>
{helperText}
</FormHelperText>
)}
</>
);
}

View File

@@ -13,66 +13,68 @@ function MuiTimePicker({ value, setFieldValue, name, minTime, maxTime, helperTex
const parsedMaxTime = 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={label}
ampm={false}
timeSteps={{ hours: 1, minutes: 5 }}
views={["hours", "minutes"]}
name={name}
onChange={(newValue) => {
setFieldValue(name, newValue);
}}
minTime={parsedMinTime}
maxTime={parsedMaxTime}
slotProps={{
textField: {
placeholder: placeholder,
size: "small",
error: error,
InputLabelProps: {
shrink: true,
<>
<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={label}
ampm={false}
timeSteps={{ hours: 1, minutes: 5 }}
views={["hours", "minutes"]}
name={name}
onChange={(newValue) => {
setFieldValue(name, newValue);
}}
minTime={parsedMinTime}
maxTime={parsedMaxTime}
slotProps={{
textField: {
placeholder: placeholder,
size: "small",
error: error,
InputLabelProps: {
shrink: true,
},
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>
),
},
},
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>
),
},
},
}}
/>
{helperText ? (
<FormHelperText id="component-helper-text" sx={{ color: error ? "#d32f2f" : "unset" }}>
{helperText}
</FormHelperText>
) : null}
</LocalizationProvider>
</Box>
}}
/>
</LocalizationProvider>
</Box>
{helperText && (
<FormHelperText id="component-helper-text" sx={{ color: error ? "#d32f2f" : "unset", ml: 2 }}>
{helperText}
</FormHelperText>
)}
</>
);
}

View File

@@ -0,0 +1,197 @@
import { Box, Button, Drawer, FormHelperText, Stack, TextField } from "@mui/material";
import AccessibleIcon from "@mui/icons-material/Accessible";
import { Controller, useFormState, useWatch } from "react-hook-form";
import { useEffect, useState } from "react";
const plate_words = [
{ id: 1, value: "الف", name: "الف" },
{ id: 2, value: "ب", name: "ب" },
{ id: 3, value: "پ", name: "پ" },
{ id: 4, value: "ت", name: "ت" },
{ id: 5, value: "ث", name: "ث" },
{ id: 6, value: "ج", name: "ج" },
{ id: 7, value: "د", name: "د" },
{ id: 8, value: "ز", name: "ز" },
{ id: 9, value: "س", name: "س" },
{ id: 10, value: "ش", name: "ش" },
{ id: 11, value: "ص", name: "ص" },
{ id: 12, value: "ط", name: "ط" },
{ id: 13, value: "ع", name: "ع" },
{ id: 14, value: "ف", name: "ف" },
{ id: 15, value: "ق", name: "ق" },
{ id: 16, value: "ک", name: "گ" },
{ id: 17, value: "ل", name: "ل" },
{ id: 18, value: "م", name: "م" },
{ id: 19, value: "ن", name: "ن" },
{ id: 20, value: "و", name: "و" },
{ id: 21, value: "ه", name: "ه" },
{ id: 22, value: "ی", name: "ی" },
{ id: 23, value: "*", name: <AccessibleIcon /> },
];
const PlateNumber = ({ control }) => {
const platePart2 = useWatch({ control, name: "plate_part2" });
const [plateDrawer, setPlateDrawer] = useState(false);
const { errors } = useFormState({ control });
const plateErrors = ["plate_part1", "plate_part2", "plate_part3", "plate_part4"].some((part) => errors[part]);
return (
<>
<Stack
direction={"row"}
sx={{
border: 1,
borderColor: plateErrors ? "error.main" : "divider",
overflow: "hidden",
borderRadius: 1,
}}
>
<Controller
name="plate_part4"
control={control}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
type="tel"
inputProps={{
inputMode: "number",
min: 0,
pattern: "[0-9]*",
sx: { textAlign: "center" },
}}
onChange={(event) => {
const inputValue = event.target.value;
if (isNaN(Number(inputValue))) {
return;
}
inputValue.length <= 2 ? field.onChange(inputValue) : null;
}}
size="small"
placeholder="xx"
sx={{ flexGrow: 2, "& fieldset": { border: "none" } }}
/>
)}
/>
<Controller
name="plate_part3"
control={control}
defaultValue=""
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
type="tel"
inputProps={{
inputMode: "number",
min: 0,
pattern: "[0-9]*",
sx: { textAlign: "center" },
}}
onChange={(event) => {
const inputValue = event.target.value;
if (isNaN(Number(inputValue))) {
return;
}
inputValue.length <= 3 ? field.onChange(inputValue) : null;
}}
size="small"
placeholder="xxx"
sx={{
flexGrow: 3,
borderLeft: 1,
borderRadius: 0,
borderColor: "divider",
"& fieldset": { border: "none" },
}}
/>
)}
/>
<Box sx={{ flexGrow: 1 }}>
<Button
onClick={() => setPlateDrawer(true)}
sx={{ height: "100%", borderRadius: 0, borderColor: "divider" }}
size={"small"}
>
{plate_words.find((p) => p.value === platePart2)?.name || "الف"}
</Button>
</Box>
<Drawer
sx={{ zIndex: 9999 }}
anchor={"bottom"}
open={plateDrawer}
onClose={() => setPlateDrawer(false)}
>
<Box
sx={{
display: "flex",
flexWrap: "wrap",
mx: "auto",
my: 2,
gap: 2,
width: "60%",
justifyContent: "center",
}}
>
{plate_words.map((item) => (
<Controller
key={item.id}
name="plate_part2"
control={control}
defaultValue=""
render={({ field, fieldState: { error } }) => (
<Button
onClick={() => {
setPlateDrawer(false);
field.onChange(item.value);
}}
sx={{ width: "fit-content" }}
variant="contained"
>
{item.name}
</Button>
)}
/>
))}
</Box>
</Drawer>
<Controller
name="plate_part1"
control={control}
defaultValue=""
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
type="tel"
size="small"
placeholder="xx"
sx={{ flexGrow: 2, "& fieldset": { border: "none" } }}
inputProps={{
inputMode: "number",
min: 0,
pattern: "[0-9]*",
sx: { textAlign: "center" },
}}
onChange={(event) => {
const inputValue = event.target.value;
if (isNaN(Number(inputValue))) {
return;
}
inputValue.length <= 2 ? field.onChange(inputValue) : null;
}}
/>
)}
/>
<Stack sx={{ width: 24, borderLeft: 1, borderColor: "divider" }}>
<Box sx={{ flexGrow: 1, bgcolor: "#1ebc1e" }}></Box>
<Box sx={{ flexGrow: 1, bgcolor: "white" }}></Box>
<Box sx={{ flexGrow: 1, bgcolor: "#f52121" }}></Box>
</Stack>
</Stack>
{plateErrors && (
<FormHelperText sx={{ ml: 2 }} error>
پلاک نامعتبر است!!!
</FormHelperText>
)}
</>
);
};
export default PlateNumber;

View File

@@ -0,0 +1,49 @@
import { FormControl, FormHelperText, InputLabel, MenuItem, Select } from "@mui/material";
function SelectBox({
name,
value,
onChange,
onBlur,
selectors,
label,
error,
schema,
disabled,
helperText,
isLoading,
errorEcured,
variant = "outlined",
}) {
return (
<FormControl disabled={disabled || false} fullWidth variant={variant} size="small" error={!!error}>
<InputLabel>{label}</InputLabel>
<Select
label={label}
name={name}
size="small"
value={value}
onChange={(e) => {
onChange(e.target.value);
}}
onBlur={onBlur}
>
{isLoading ? (
<MenuItem sx={{ color: "primary.main" }}>درحال دریافت اطلاعات...</MenuItem>
) : errorEcured ? (
<MenuItem sx={{ color: "secondary.main" }}>خطا در دریافت اطلاعات!!!</MenuItem>
) : (
selectors.map((selector) => {
return (
<MenuItem key={selector.id} value={selector[schema.value]}>
{selector[schema.name]}
</MenuItem>
);
})
)}
</Select>
<FormHelperText>{helperText || error?.message}</FormHelperText>
</FormControl>
);
}
export default SelectBox;

View File

@@ -14,7 +14,6 @@ const ShowPlak = ({ plak_number }) => {
};
};
const plakParts = processPlak(plak_number);
return (
<Stack sx={{ border: 1, borderColor: "divider", borderRadius: 1 }} direction={"row"}>
<Stack

View File

@@ -468,7 +468,7 @@ export const pageMenu = [
id: "receiptManagmentOparationCartable",
label: "کارتابل",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/receipt",
route: "/dashboard/technical-building-damage/operator",
permissions: ["all"],
},
],

View File

@@ -85,5 +85,8 @@ export const CREATE_RECEIPT_DAMAGE_ITEMS = api + "/api/v3/damages";
export const UPDATE_RECEIPT_DAMAGE_ITEMS = api + "/api/v3/damages";
export const ATIVITY_RECEIPT_DAMAGE_ITEMS = api + "/api/v3/damages/activate";
// damage receipt
export const GET_TECHNICAL_DAMAGE_OPERATOR_LIST = api + "/api/v3/receipts";
export const GET_DAMAGE_ITEM_LIST = api + "/api/v3/damages/list";
// activity code log
export const ACTIVITY_LOG = api + "/api/v3/profile/add_activity";