Merge branch 'release/v0.7.0'

This commit is contained in:
Amirhossein Mahmoodi
2024-10-26 09:09:19 +03:30
146 changed files with 5988 additions and 554 deletions

View File

@@ -1,3 +1,3 @@
NEXT_PUBLIC_VERSION="0.6.1"
NEXT_PUBLIC_VERSION="0.7.0"
NEXT_PUBLIC_API_URL="https://rms.witel.ir"
NEXT_PUBLIC_MAPTILE_ENDPOINT="https://rmsmap.rmto.ir/141map"

View File

@@ -14,7 +14,9 @@
"@emotion/cache": "^11.11.0",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@hookform/resolvers": "^3.9.0",
"@mui/icons-material": "^5.15.6",
"@mui/lab": "^5.0.0-alpha.173",
"@mui/material": "^5.15.6",
"@mui/material-nextjs": "^5.15.6",
"@mui/x-date-pickers": "^6.19.5",
@@ -32,6 +34,7 @@
"react-dom": "^18",
"react-hook-form": "^7.52.1",
"react-leaflet": "^4.2.1",
"react-leaflet-draw": "^0.20.4",
"react-toastify": "^10.0.5",
"sass": "^1.75.0",
"sharp": "^0.33.4",

View File

@@ -0,0 +1,7 @@
import AssistantZaminGovComponent from "@/components/dashboard/inquiryPrivacy/assistant/zaminGov";
const Page = () => {
return <AssistantZaminGovComponent />;
};
export default Page;

View File

@@ -0,0 +1,7 @@
import CityAdminZaminGovComponent from "@/components/dashboard/inquiryPrivacy/cityAdmin/zaminGov";
const Page = () => {
return <CityAdminZaminGovComponent />;
};
export default Page;

View File

@@ -0,0 +1,7 @@
import GeneralManagerZaminGovComponent from "@/components/dashboard/inquiryPrivacy/generalManager/zaminGov";
const Page = () => {
return <GeneralManagerZaminGovComponent />;
};
export default Page;

View File

@@ -0,0 +1,7 @@
import ProvinceAdminZaminGovComponent from "@/components/dashboard/inquiryPrivacy/provinceAdmin/zaminGov";
const Page = () => {
return <ProvinceAdminZaminGovComponent />;
};
export default Page;

View File

@@ -4,7 +4,7 @@ import { Stack } from "@mui/material";
const Layout = ({ children }) => {
return (
<Stack sx={{ width: '100%', height: '100%' }}>
<Stack sx={{ width: "100%", height: "100%" }}>
<HeaderWithLogo />
<HeaderWithSidebar>{children}</HeaderWithSidebar>
</Stack>

View File

@@ -0,0 +1,7 @@
import TestPage from "@/components/dashboard/test";
const Page = () => {
return <TestPage/>;
};
export default Page;

View File

@@ -1,9 +1,7 @@
import WithAuthMiddleware from "@/core/middlewares/withAuth";
const Layout = ({ children }) => {
return (
<WithAuthMiddleware>{children}</WithAuthMiddleware>
);
return <WithAuthMiddleware>{children}</WithAuthMiddleware>;
};
export default Layout;

View File

@@ -0,0 +1,18 @@
const data = [
{
id: 1,
name: "تهران",
},
{
id: 2,
name: "ری",
},
{
id: 3,
name: "اندیشه",
},
];
export async function GET() {
return Response.json({ data });
}

View File

@@ -0,0 +1,41 @@
const data = [
{
id: 1,
aplication_number: 1,
application_date: "1",
province: "tehran",
city: "tehran",
},
{
id: 2,
aplication_number: 2,
application_date: "1",
province: "tehran",
city: "tehran",
},
{
id: 3,
aplication_number: 3,
application_date: "1",
province: "tehran",
city: "tehran",
},
{
id: 4,
aplication_number: 4,
application_date: "1",
province: "tehran",
city: "tehran",
},
{
id: 5,
aplication_number: 5,
application_date: "1",
province: "tehran",
city: "tehran",
},
];
export async function GET() {
return Response.json({ data });
}

View File

@@ -0,0 +1,9 @@
export async function GET() {
return Response.json({
message:
"به موجب این نامه، به استحضار جنابعالی می رساند، این‌ جانب ……… از تاریخ ……… افتخار همکاری\n" +
"با مجموعه ……… را دارم. اما متاسفانه، به علت ………، تقاضای استعفای خود را از تاریخ ………\n" +
"اعلام میدارم. ضمن تشکر پیشاپیش از همکاری شما خواهشمند است، دستور اقدامات لازم در این\n" +
"زمینه را صادر فرمایید.",
});
}

View File

@@ -0,0 +1,18 @@
const data = [
{
id: 1,
name: "تهران",
},
{
id: 2,
name: "مشهد",
},
{
id: 3,
name: "اصفهان",
},
];
export async function GET() {
return Response.json({ data });
}

View File

@@ -0,0 +1,3 @@
export async function POST() {
return Response.json({ message: "Done" });
}

View File

@@ -0,0 +1,18 @@
const data = [
{
id: 1,
name: "تست نوع 1",
},
{
id: 2,
name: "تست نوع 2",
},
{
id: 3,
name: "تست نوع 3",
},
];
export async function GET() {
return Response.json({data});
}

View File

@@ -0,0 +1,71 @@
const data = [
{
id: 1,
test_type_name: 1,
project_name: "نوع پروژه",
employer: "کارفرما",
consultant: "مشاور",
contractor: "پیمانکار",
applicant: "متقاضی",
work_number: "شماره کار",
request_number: "شماره درخواست",
request_date: "تاریخ درخواست",
report_date: "تاریخ گزارش"
},
{
id: 2,
test_type_name: 5,
project_name: "نوع پروژه",
employer: "کارفرما",
consultant: "مشاور",
contractor: "پیمانکار",
applicant: "متقاضی",
work_number: "شماره کار",
request_number: "شماره درخواست",
request_date: "تاریخ درخواست",
report_date: "تاریخ گزارش"
},
{
id: 3,
test_type_name: 2,
project_name: "نوع پروژه",
employer: "کارفرما",
consultant: "مشاور",
contractor: "پیمانکار",
applicant: "متقاضی",
work_number: "شماره کار",
request_number: "شماره درخواست",
request_date: "تاریخ درخواست",
report_date: "تاریخ گزارش"
},
{
id: 4,
test_type_name: 4,
project_name: "نوع پروژه",
employer: "کارفرما",
consultant: "مشاور",
contractor: "پیمانکار",
applicant: "متقاضی",
work_number: "شماره کار",
request_number: "شماره درخواست",
request_date: "تاریخ درخواست",
report_date: "تاریخ گزارش"
},
{
id: 5,
test_type_name: 3,
project_name: "نوع پروژه",
employer: "کارفرما",
consultant: "مشاور",
contractor: "پیمانکار",
applicant: "متقاضی",
work_number: "شماره کار",
request_number: "شماره درخواست",
request_date: "تاریخ درخواست",
report_date: "تاریخ گزارش"
},
];
export async function GET() {
return Response.json({data});
}

View File

@@ -8,7 +8,7 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="fa" dir={"rtl"}>
<body style={{ height: "100vh", width: '100vw' }}>
<body style={{ height: "100vh", width: "100vw" }}>
<AuthProvider>
<TableSettingProvider>{children}</TableSettingProvider>
</AuthProvider>

View File

@@ -8,7 +8,7 @@ import Link from "next/link";
import { useEffect, useState } from "react";
const Page = ({ searchParams }) => {
const { getUser } = useAuth()
const { getUser } = useAuth();
const { username } = searchParams;
const [login, setLogin] = useState(0);
const request = useRequest();
@@ -17,7 +17,7 @@ const Page = ({ searchParams }) => {
const login = async () => {
try {
await request(`${GET_LOGIN_ROUTE}?username=${username}`);
await getUser()
await getUser();
setLogin(1);
} catch (error) {
setLogin(2);
@@ -31,7 +31,7 @@ const Page = ({ searchParams }) => {
setLogin(0);
try {
await request(`${GET_LOGIN_ROUTE}?username=${username}`);
await getUser()
await getUser();
setLogin(1);
} catch (error) {
setLogin(2);
@@ -44,8 +44,8 @@ const Page = ({ searchParams }) => {
{login === 0
? "درحال دریافت مجوز برای ارتباط با سرور..."
: login === 1
? "ارتباط با سرور برقرار شد."
: "ارتباط با سرور برقرار نشد. مشکلی وجود دارد."}
? "ارتباط با سرور برقرار شد."
: "ارتباط با سرور برقرار نشد. مشکلی وجود دارد."}
</Typography>
<Zoom in={login === 1}>
<Button component={Link} href="/">

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -3,8 +3,7 @@
@import "react-toastify/dist/ReactToastify.css";
.filter-toast {
box-shadow:
rgba(50, 50, 93, 0.25) 0px 13px 27px -5px,
rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
background-color: #d0dfe8;
}
box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px,
rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;
background-color: #d0dfe8;
}

View File

@@ -0,0 +1,27 @@
.leaflet-draw-tooltip {
background-color: #4f4f4f;
font-family: IRANSans;
color: #fff;
font-size: 10px;
padding: 2px 8px;
margin-right: 15px;
border-radius: 4px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
}
.leaflet-draw-tooltip:before {
content: "";
position: absolute;
bottom: 100%;
left: 103%;
transform: rotate(90deg);
margin-left: -6px;
border-width: 6px;
border-style: solid;
border-color: transparent transparent #333 transparent;
}
.leaflet-draw-tooltip-subtext {
font-size: 12px;
color: #ffeb3b;
}

View File

@@ -0,0 +1,29 @@
import { FormControl, FormHelperText, InputLabel, OutlinedInput, Stack } from "@mui/material";
const DescriptionForm = ({ errors, register }) => {
return (
<Stack>
<FormControl error={!!errors.description} size="small" fullWidth variant="outlined">
<InputLabel sx={{ pt: 1 }} htmlFor="description">
توضیحات
</InputLabel>
<OutlinedInput
id="description"
label={"توضیحات"}
multiline
rows={6}
{...register("description")}
autoComplete="off"
size="small"
fullWidth
sx={{ mt: 1 }}
type="text"
/>
<FormHelperText id="description">
{errors.description ? errors.description.message : null}
</FormHelperText>
</FormControl>
</Stack>
);
};
export default DescriptionForm;

View File

@@ -0,0 +1,15 @@
import { Button } from "@mui/material";
const ManagerOrAssistantSubmit = ({ isSubmitting }) => {
return (
<>
<Button fullWidth variant="outlined" color="secondary" disabled={isSubmitting} type={"submit"}>
{isSubmitting ? "در حال ارسال..." : "مخالفت"}
</Button>
<Button fullWidth variant="contained" color="primary" type={"submit"} disabled={isSubmitting}>
{isSubmitting ? "در حال ارسال..." : "موافقت"}
</Button>
</>
);
};
export default ManagerOrAssistantSubmit;

View File

@@ -0,0 +1,25 @@
import { Card, CardContent, CardHeader, CircularProgress, Divider, Stack, Typography } from "@mui/material";
const PrevCartableOpinion = ({ message, loadingMessage, errorMessage }) => {
return (
<Stack>
<Card variant="outlined">
<CardHeader sx={{ pb: 0 }} title="نظر معاون راهداری استان :" />
<CardContent>
{errorMessage ? (
<Typography color={"red"}>خطا در دریافت اطلاعات !!!</Typography>
) : loadingMessage ? (
<Typography sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<CircularProgress size={20} />
درحال دریافت اطلاعات
</Typography>
) : (
<Typography>{message}</Typography>
)}
</CardContent>
</Card>
<Divider sx={{ mt: 2 }} />
</Stack>
);
};
export default PrevCartableOpinion;

View File

@@ -0,0 +1,33 @@
import { Card, CardContent, FormControl, FormLabel, Stack, Typography } from "@mui/material";
const QuestionSafetyForm = () => {
return (
<Stack sx={{ py: 2 }}>
<Card
sx={{ display: "flex", justifyContent: "center", alignItems: "center", borderColor: "primary.main" }}
variant="outlined"
>
<CardContent>
<FormControl>
<FormLabel>
<Typography color={"primary"} variant={"h5"} fontWeight={"bolder"}>
آیا ایمنی راه این طرح مورد تایید است ؟
</Typography>
</FormLabel>
<Stack
sx={{ pt: 2, display: "flex", justifyContent: "center", alignItems: "center" }}
spacing={1}
direction={"row"}
>
<Typography variant={"subtitle1"}>دفتر حریم راه : </Typography>
<Typography variant={"h5"} fontWeight={"bolder"}>
بله
</Typography>
</Stack>
</FormControl>
</CardContent>
</Card>
</Stack>
);
};
export default QuestionSafetyForm;

View File

@@ -0,0 +1,82 @@
import { DialogActions, DialogContent, Stack } from "@mui/material";
import StyledForm from "@/core/components/StyledForm";
import useRequest from "@/lib/hooks/useRequest";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { object, string } from "yup";
import { SUBMIT_ROAD_SAFETY_FORM } from "@/core/utils/routes";
import usePrevStateOpinion from "@/lib/hooks/usePrevStateopinion";
import QuestionSafetyForm from "./QuestionSafetyForm";
import PrevCartableOpinion from "./PrevCartableOpinion";
import DescriptionForm from "./DescriptionForm";
import ManagerOrAssistantSubmit from "./ManagerOrAssistantSubmit";
import ApplicantRequestDetail from "@/core/components/ApplicantRequestDetail";
const fakeData = {
id: 1,
shomareh_darkhast: "2124",
ostan: "ostan",
shahr: "shahr",
shahrestan: "shahrestan",
bakhsh: "bakhsh",
roosta: "roosta",
tarikh_darkhast: "tarikh_darkhast",
sazman: "sazman",
masahat_zamin: "masahat_zamin",
masahat_tarh: "masahat_tarh",
gorooh_tarh: "gorooh_tarh",
onvane_tarh: "onvane_tarh",
address: "کرج - فلان جا - جنب پاساژ - نزدیک اونجا - اونور خیابون - زیر رو گذر - روی زیر گذر",
file_mosavab: "file",
polygon: [
[51.515, -0.09],
[51.52, -0.1],
[51.52, -0.12],
],
};
const validationSchema = object({
description: string().required("وارد کردن توضیحات الزامیست!"),
});
const RoadSafetyFormContext = ({ rowId, mutate, setOpenRoadSafetyForm }) => {
const defaultValues = {
description: "",
};
const requestServer = useRequest({ notification: { success: true, show: true } });
const { message, loadingMessage, errorMessage } = usePrevStateOpinion();
const {
register,
handleSubmit,
formState: { isSubmitting, errors },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
const onSubmit = async (data) => {
const formData = new FormData();
formData.append("description", data.description);
requestServer(`${SUBMIT_ROAD_SAFETY_FORM}/${rowId}`, "post", {
data: formData,
})
.then(() => {
setOpenRoadSafetyForm(false);
mutate();
})
.catch(() => {});
};
return (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<DialogContent>
<ApplicantRequestDetail data={fakeData} />
<Stack spacing={2}>
<QuestionSafetyForm />
<PrevCartableOpinion
message={message}
loadingMessage={loadingMessage}
errorMessage={errorMessage}
/>
<DescriptionForm register={register} errors={errors} />
<DialogActions>
<ManagerOrAssistantSubmit isSubmitting={isSubmitting} />
</DialogActions>
</Stack>
</DialogContent>
</StyledForm>
);
};
export default RoadSafetyFormContext;

View File

@@ -0,0 +1,52 @@
import { Dialog, IconButton, Stack, Tooltip } from "@mui/material";
import EngineeringIcon from "@mui/icons-material/Engineering";
import DialogTransition from "@/core/components/DialogTransition";
import { useState } from "react";
import { Close } from "@mui/icons-material";
import RoadSafetyFormContext from "./RoadSafetyFormContext";
const RoadSafetyForm = ({ rowId, mutate }) => {
const [openRoadSafetyForm, setOpenRoadSafetyForm] = useState(false);
return (
<Stack>
<Tooltip title="فرم ایمنی راه" arrow placement="right">
<IconButton
color="primary"
sx={{ textTransform: "unset", alignSelf: "center" }}
onClick={() => {
setOpenRoadSafetyForm(true);
}}
>
<EngineeringIcon />
</IconButton>
</Tooltip>
<Dialog
PaperProps={{
sx: {
transition: "all .3s",
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
},
}}
open={openRoadSafetyForm}
maxWidth={"lg"}
TransitionComponent={DialogTransition}
>
<IconButton
aria-label="close"
onClick={() => setOpenRoadSafetyForm(false)}
sx={{
position: "absolute",
right: 8,
top: 8,
zIndex: 10,
color: (theme) => theme.palette.grey[500],
}}
>
<Close />
</IconButton>
<RoadSafetyFormContext rowId={rowId} mutate={mutate} setOpenRoadSafetyForm={setOpenRoadSafetyForm} />
</Dialog>
</Stack>
);
};
export default RoadSafetyForm;

View File

@@ -0,0 +1,75 @@
"use client";
import { Dialog, DialogContent } from "@mui/material";
import { object, string } from "yup";
import useRequest from "@/lib/hooks/useRequest";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import StyledForm from "@/core/components/StyledForm";
import ApplicantRequestDetail from "@/core/components/ApplicantRequestDetail";
const fakeData = {
id: 1,
shomareh_darkhast: "2124",
ostan: "ostan",
shahr: "shahr",
shahrestan: "shahrestan",
bakhsh: "bakhsh",
roosta: "roosta",
tarikh_darkhast: "tarikh_darkhast",
sazman: "sazman",
masahat_zamin: "masahat_zamin",
masahat_tarh: "masahat_tarh",
gorooh_tarh: "gorooh_tarh",
onvane_tarh: "onvane_tarh",
address: "کرج - فلان جا - جنب پاساژ - نزدیک اونجا - اونور خیابون - زیر رو گذر - روی زیر گذر",
file_mosavab: "file",
polygon: [
[51.515, -0.09],
[51.52, -0.1],
[51.52, -0.12],
],
};
const validationSchema = object({
description: string().required("وارد کردن توضیحات الزامیست!"),
});
const DetailDialog = ({ taskModal, setTaskModal, rowId, mutate }) => {
const requestServer = useRequest({ auth: true });
const defaultValues = {
description: "",
};
const handleClose = () => {
setTaskModal(false);
};
const {
register,
handleSubmit,
formState: { isSubmitting, errors, touchedFields },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
const onSubmit = async (data) => {
const formData = new FormData();
formData.append("description", data.description);
requestServer(`api-for-send-to-harim/${rowId}`, "post", {
data: formData,
})
.then(() => {
handleClose();
mutate();
})
.catch(() => {});
};
return (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<Dialog open={taskModal} onClose={handleClose} maxWidth="lg" fullWidth>
<DialogContent dividers>
<ApplicantRequestDetail data={fakeData} />
</DialogContent>
</Dialog>
</StyledForm>
);
};
export default DetailDialog;

View File

@@ -0,0 +1,26 @@
"use client";
import { IconButton, Tooltip } from "@mui/material";
import AssignmentIcon from "@mui/icons-material/Assignment";
import DetailDialog from "./DetailDialog";
import { useState } from "react";
const TaskDetail = ({ rowId, mutate }) => {
const [taskModal, setTaskModal] = useState(false);
const openDetailDialog = () => {
setTaskModal(true);
};
return (
<>
<Tooltip title="جزئیات طرح متقاضی" arrow placement="right">
<IconButton color="primary" onClick={openDetailDialog}>
<AssignmentIcon />
</IconButton>
</Tooltip>
<DetailDialog taskModal={taskModal} setTaskModal={setTaskModal} rowId={rowId} mutate={mutate} />
</>
);
};
export default TaskDetail;

View File

@@ -0,0 +1,13 @@
import TaskDetail from "./TaskDetail";
import { Box } from "@mui/material";
import RoadSafetyForm from "./RoadSafetyForm";
const RowActions = ({ row, mutate }) => {
return (
<Box sx={{ display: "flex", gap: 1 }}>
<TaskDetail mutate={mutate} rowId={row.getValue("id")} />
<RoadSafetyForm mutate={mutate} rowId={row.getValue("id")} />
</Box>
);
};
export default RowActions;

View File

@@ -0,0 +1,145 @@
"use client";
import { useMemo } from "react";
import { Box } from "@mui/material";
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import RowActions from "./RowActions";
const TaskList = () => {
const columns = useMemo(
() => [
{
accessorKey: "id",
header: "کد یکتا",
id: "id",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
},
{
accessorKey: "aplication_number",
header: "شماره درخواست",
id: "aplication_number",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
},
{
accessorKey: "application_date",
header: "تاریخ درخواست",
id: "application_date",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "province",
header: "استان",
id: "province",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "township",
header: "شهرستان",
id: "township",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "city",
header: "شهر",
id: "city",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "county",
header: "بخش",
id: "county",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "village",
header: "روستا",
id: "village",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "land_area",
header: "مساحت زمین",
id: "land_area",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_area",
header: "مساحت طرح",
id: "design_area",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "organization",
header: "سازمان",
id: "organization",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_group",
header: "گروه طرح",
id: "design_group",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_title",
header: "عنوان طرح",
id: "design_title",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "state",
header: "وضعیت درخواست",
id: "state",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
],
[]
);
return (
<>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
table_title={"لیست استعلام ها"}
need_filter={false}
columns={columns}
table_url={"/v3/api/fake-data"}
page_name={"assistantZaminGov"}
table_name={"assistantZaminGovList"}
enableRowActions
positionActionsColumn={"last"}
RowActions={RowActions}
/>
</Box>
</>
);
};
export default TaskList;

View File

@@ -0,0 +1,15 @@
"use client";
import PageTitle from "@/core/components/PageTitle";
import { Stack } from "@mui/material";
import TaskList from "./TaskList";
const AssistantZaminGovComponent = () => {
return (
<Stack spacing={1}>
<PageTitle title={"استعلام حرائم پنجره واحد"} />
<TaskList />
</Stack>
);
};
export default AssistantZaminGovComponent;

View File

@@ -0,0 +1,138 @@
import {
Autocomplete,
Button,
CircularProgress,
DialogActions,
DialogContent,
FormControl,
FormHelperText,
InputLabel,
OutlinedInput,
Stack,
TextField,
Typography,
} from "@mui/material";
import { Controller, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { object, string } from "yup";
import StyledForm from "@/core/components/StyledForm";
import useCities from "@/lib/hooks/useCities";
import useRequest from "@/lib/hooks/useRequest";
import { REFER_ADMIN_CITY } from "@/core/utils/routes";
const validationSchema = object({
description: string().required("وارد کردن توضیحات الزامیست!"),
city: string().required("وارد کردن شهرستان الزامیست!"),
});
const ReferFormContext = ({ setOpenReferDialog, rowId, mutate }) => {
const defaultValues = {
description: "",
city: "",
};
const { cities, loadingCities, errorCities } = useCities();
const requestServer = useRequest({ notification: { show: true, success: true } });
const {
control,
register,
handleSubmit,
formState: { isSubmitting, errors, touchedFields },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
const onSubmit = async (data) => {
const formData = new FormData();
formData.append("description", data.description);
formData.append("cityId", data.city);
requestServer(`${REFER_ADMIN_CITY}/${rowId}`, "post", {
data: formData,
})
.then(() => {
setOpenReferDialog(false);
mutate();
})
.catch(() => {});
};
return (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<DialogContent>
<Stack spacing={2}>
<Stack>
<FormControl error={!!errors.description} size="small" fullWidth variant="outlined">
<InputLabel sx={{ pt: 1 }} htmlFor="description">
توضیحات
</InputLabel>
<OutlinedInput
id="description"
label={"توضیحات"}
multiline
rows={8}
autoComplete="off"
{...register("description")}
size="small"
fullWidth
sx={{ mt: 1 }}
type="text"
/>
<FormHelperText id="description">
{errors.description ? errors.description.message : null}
</FormHelperText>
</FormControl>
</Stack>
<Stack>
<Controller
name="city"
control={control}
render={({ field: { onChange, value }, fieldState: { error } }) => (
<FormControl error={!!error} size="small" fullWidth variant="outlined">
<InputLabel htmlFor="city" />
{errorCities ? (
<Typography color={"red"}>خطایی در دریافت شهرستان ها رخ داده است!</Typography>
) : loadingCities ? (
<Typography sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<CircularProgress size={20} />
درحال دریافت لیست شهرستان ها
</Typography>
) : (
<Autocomplete
id="city"
size="small"
value={cities.find((city) => city.id === value) || null}
disablePortal
options={cities}
getOptionLabel={(city) => city.name}
isOptionEqualToValue={(option, value) => option.id === value.id}
onChange={(event, newValue) => {
onChange(newValue ? newValue.id : "");
}}
renderInput={(params) => (
<TextField
{...params}
autoComplete="off"
error={!!errors.city}
fullWidth
label="شهرستان"
/>
)}
/>
)}
<FormHelperText id="city">
{errors.city ? errors.city.message : null}
</FormHelperText>
</FormControl>
)}
/>
</Stack>
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={() => setOpenReferDialog(false)} variant="outlined" color="secondary" autoFocus>
{"انصراف"}
</Button>
<Button variant="contained" color="primary" type={"submit"} disabled={isSubmitting}>
{isSubmitting ? "در حال اسال" : "ارجاع"}
</Button>
</DialogActions>
</StyledForm>
);
};
export default ReferFormContext;

View File

@@ -0,0 +1,41 @@
import { Dialog, DialogTitle, IconButton, Stack, Tooltip } from "@mui/material";
import ReplyIcon from "@mui/icons-material/Reply";
import DialogTransition from "@/core/components/DialogTransition";
import ReferFormContext from "./ReferFormContext";
import { useState } from "react";
const ReferForm = ({ rowId, mutate }) => {
const [openReferDialog, setOpenReferDialog] = useState(false);
return (
<Stack>
<Tooltip title="ارجاع به شهرستان دیگر" arrow placement="right">
<IconButton
color="primary"
sx={{ textTransform: "unset", alignSelf: "center" }}
onClick={() => {
setOpenReferDialog(true);
}}
>
<ReplyIcon />
</IconButton>
</Tooltip>
<Dialog
PaperProps={{
sx: {
transition: "all .3s",
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
},
}}
open={openReferDialog}
fullWidth
TransitionComponent={DialogTransition}
>
<DialogTitle sx={{ m: 0, p: 2, borderBottom: 1, borderColor: "divider" }} id="create-dialog">
ارجاع به شهرستان دیگر
</DialogTitle>
<ReferFormContext rowId={rowId} mutate={mutate} setOpenReferDialog={setOpenReferDialog} />
</Dialog>
</Stack>
);
};
export default ReferForm;

View File

@@ -0,0 +1,109 @@
"use client";
import {
Button,
Dialog,
DialogActions,
DialogContent,
FormControl,
FormHelperText,
InputLabel,
OutlinedInput,
} from "@mui/material";
import { object, string } from "yup";
import useRequest from "@/lib/hooks/useRequest";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import StyledForm from "@/core/components/StyledForm";
import ApplicantRequestDetail from "@/core/components/ApplicantRequestDetail";
const fakeData = {
id: 1,
shomareh_darkhast: "2124",
ostan: "ostan",
shahr: "shahr",
shahrestan: "shahrestan",
bakhsh: "bakhsh",
roosta: "roosta",
tarikh_darkhast: "tarikh_darkhast",
sazman: "sazman",
masahat_zamin: "masahat_zamin",
masahat_tarh: "masahat_tarh",
gorooh_tarh: "gorooh_tarh",
onvane_tarh: "onvane_tarh",
address: "کرج - فلان جا - جنب پاساژ - نزدیک اونجا - اونور خیابون - زیر رو گذر - روی زیر گذر",
file_mosavab: "file",
polygon: [
[51.515, -0.09],
[51.52, -0.1],
[51.52, -0.12],
],
};
const validationSchema = object({
description: string().required("وارد کردن توضیحات الزامیست!"),
});
const DetailDialog = ({ taskModal, setTaskModal, rowId, mutate }) => {
const requestServer = useRequest({ auth: true });
const defaultValues = {
description: "",
};
const handleClose = () => {
setTaskModal(false);
};
const {
register,
handleSubmit,
formState: { isSubmitting, errors, touchedFields },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
const onSubmit = async (data) => {
const formData = new FormData();
formData.append("description", data.description);
requestServer(`api-for-send-to-harim/${rowId}`, "post", {
data: formData,
})
.then(() => {
handleClose();
mutate();
})
.catch(() => {});
};
return (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<Dialog open={taskModal} onClose={handleClose} maxWidth="lg" fullWidth>
<DialogContent dividers>
<ApplicantRequestDetail data={fakeData} />
<FormControl error={!!errors.description} size="small" fullWidth variant="outlined">
<InputLabel sx={{ pt: 1 }} htmlFor="description">
توضیحات
</InputLabel>
<OutlinedInput
id="description"
label={"توضیحات"}
multiline
rows={8}
autoComplete="off"
{...register("description")}
size="small"
fullWidth
sx={{ mt: 1 }}
type="text"
/>
<FormHelperText id="description">
{errors.description ? errors.description.message : null}
</FormHelperText>
</FormControl>
</DialogContent>
<DialogActions sx={{ justifyContent: "center", py: 2 }}>
<Button size="large" variant="contained">
ارسال به دفتر حریم
</Button>
</DialogActions>
</Dialog>
</StyledForm>
);
};
export default DetailDialog;

View File

@@ -0,0 +1,26 @@
"use client";
import { IconButton, Tooltip } from "@mui/material";
import AssignmentIcon from "@mui/icons-material/Assignment";
import DetailDialog from "./DetailDialog";
import { useState } from "react";
const TaskDetail = ({ rowId, mutate }) => {
const [taskModal, setTaskModal] = useState(false);
const openDetailDialog = () => {
setTaskModal(true);
};
return (
<>
<Tooltip title="جزئیات طرح متقاضی" arrow placement="right">
<IconButton color="primary" onClick={openDetailDialog}>
<AssignmentIcon />
</IconButton>
</Tooltip>
<DetailDialog taskModal={taskModal} setTaskModal={setTaskModal} rowId={rowId} mutate={mutate} />
</>
);
};
export default TaskDetail;

View File

@@ -0,0 +1,15 @@
"use client";
import ReferForm from "./Refer";
import TaskDetail from "./TaskDetail";
import { Box } from "@mui/material";
const RowActions = ({ row, mutate }) => {
return (
<Box sx={{ display: "flex", gap: 1 }}>
<ReferForm mutate={mutate} rowId={row.getValue("id")} />
<TaskDetail mutate={mutate} rowId={row.getValue("id")} />
</Box>
);
};
export default RowActions;

View File

@@ -0,0 +1,145 @@
"use client";
import { useMemo } from "react";
import { Box } from "@mui/material";
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import RowActions from "./RowActions";
const TaskList = () => {
const columns = useMemo(
() => [
{
accessorKey: "id",
header: "کد یکتا",
id: "id",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
},
{
accessorKey: "aplication_number",
header: "شماره درخواست",
id: "aplication_number",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
},
{
accessorKey: "application_date",
header: "تاریخ درخواست",
id: "application_date",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "province",
header: "استان",
id: "province",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "township",
header: "شهرستان",
id: "township",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "city",
header: "شهر",
id: "city",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "county",
header: "بخش",
id: "county",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "village",
header: "روستا",
id: "village",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "land_area",
header: "مساحت زمین",
id: "land_area",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_area",
header: "مساحت طرح",
id: "design_area",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "organization",
header: "سازمان",
id: "organization",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_group",
header: "گروه طرح",
id: "design_group",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_title",
header: "عنوان طرح",
id: "design_title",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "state",
header: "وضعیت درخواست",
id: "state",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
],
[]
);
return (
<>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
table_title={"لیست استعلام ها"}
need_filter={false}
columns={columns}
table_url={"/v3/api/fake-data"}
page_name={"cityAdminZaminGov"}
table_name={"cityAdminZaminGovList"}
enableRowActions
positionActionsColumn={"last"}
RowActions={RowActions}
/>
</Box>
</>
);
};
export default TaskList;

View File

@@ -0,0 +1,14 @@
"use client";
import PageTitle from "@/core/components/PageTitle";
import { Stack } from "@mui/material";
import TaskList from "./TaskList";
const CityAdminZaminGovComponent = () => {
return (
<Stack spacing={1}>
<PageTitle title={"استعلام حرائم پنجره واحد"} />
<TaskList />
</Stack>
);
};
export default CityAdminZaminGovComponent;

View File

@@ -0,0 +1,29 @@
import { FormControl, FormHelperText, InputLabel, OutlinedInput, Stack } from "@mui/material";
const DescriptionForm = ({ errors, register }) => {
return (
<Stack>
<FormControl error={!!errors.description} size="small" fullWidth variant="outlined">
<InputLabel sx={{ pt: 1 }} htmlFor="description">
توضیحات
</InputLabel>
<OutlinedInput
id="description"
label={"توضیحات"}
multiline
rows={6}
{...register("description")}
autoComplete="off"
size="small"
fullWidth
sx={{ mt: 1 }}
type="text"
/>
<FormHelperText id="description">
{errors.description ? errors.description.message : null}
</FormHelperText>
</FormControl>
</Stack>
);
};
export default DescriptionForm;

View File

@@ -0,0 +1,15 @@
import { Button } from "@mui/material";
const ManagerOrAssistantSubmit = ({ isSubmitting }) => {
return (
<>
<Button fullWidth variant="outlined" color="secondary" disabled={isSubmitting} type={"submit"}>
{isSubmitting ? "در حال ارسال..." : "مخالفت"}
</Button>
<Button fullWidth variant="contained" color="primary" type={"submit"} disabled={isSubmitting}>
{isSubmitting ? "در حال ارسال..." : "موافقت"}
</Button>
</>
);
};
export default ManagerOrAssistantSubmit;

View File

@@ -0,0 +1,26 @@
import { Card, CardContent, CardHeader, CircularProgress, Divider, Stack, Typography } from "@mui/material";
import usePrevStateOpinion from "@/lib/hooks/usePrevStateopinion";
const PrevCartableOpinion = ({ message, loadingMessage, errorMessage }) => {
return (
<Stack>
<Card variant="outlined">
<CardHeader sx={{ pb: 0 }} title="نظر معاون راهداری استان :" />
<CardContent>
{errorMessage ? (
<Typography color={"red"}>خطا در دریافت اطلاعات !!!</Typography>
) : loadingMessage ? (
<Typography sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<CircularProgress size={20} />
درحال دریافت اطلاعات
</Typography>
) : (
<Typography>{message}</Typography>
)}
</CardContent>
</Card>
<Divider sx={{ mt: 2 }} />
</Stack>
);
};
export default PrevCartableOpinion;

View File

@@ -0,0 +1,33 @@
import { Card, CardContent, FormControl, FormLabel, Stack, Typography } from "@mui/material";
const QuestionSafetyForm = () => {
return (
<Stack sx={{ py: 2 }}>
<Card
sx={{ display: "flex", justifyContent: "center", alignItems: "center", borderColor: "primary.main" }}
variant="outlined"
>
<CardContent>
<FormControl>
<FormLabel>
<Typography color={"primary"} variant={"h5"} fontWeight={"bolder"}>
آیا ایمنی راه این طرح مورد تایید است ؟
</Typography>
</FormLabel>
<Stack
sx={{ pt: 2, display: "flex", justifyContent: "center", alignItems: "center" }}
spacing={1}
direction={"row"}
>
<Typography variant={"subtitle1"}>دفتر حریم راه : </Typography>
<Typography variant={"h5"} fontWeight={"bolder"}>
بله
</Typography>
</Stack>
</FormControl>
</CardContent>
</Card>
</Stack>
);
};
export default QuestionSafetyForm;

View File

@@ -0,0 +1,82 @@
import { DialogActions, DialogContent, Stack } from "@mui/material";
import StyledForm from "@/core/components/StyledForm";
import useRequest from "@/lib/hooks/useRequest";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { object, string } from "yup";
import { SUBMIT_ROAD_SAFETY_FORM } from "@/core/utils/routes";
import QuestionSafetyForm from "./QuestionSafetyForm";
import PrevCartableOpinion from "./PrevCartableOpinion";
import DescriptionForm from "./DescriptionForm";
import ManagerOrAssistantSubmit from "./ManagerOrAssistantSubmit";
import usePrevStateOpinion from "@/lib/hooks/usePrevStateopinion";
import ApplicantRequestDetail from "@/core/components/ApplicantRequestDetail";
const fakeData = {
id: 1,
shomareh_darkhast: "2124",
ostan: "ostan",
shahr: "shahr",
shahrestan: "shahrestan",
bakhsh: "bakhsh",
roosta: "roosta",
tarikh_darkhast: "tarikh_darkhast",
sazman: "sazman",
masahat_zamin: "masahat_zamin",
masahat_tarh: "masahat_tarh",
gorooh_tarh: "gorooh_tarh",
onvane_tarh: "onvane_tarh",
address: "کرج - فلان جا - جنب پاساژ - نزدیک اونجا - اونور خیابون - زیر رو گذر - روی زیر گذر",
file_mosavab: "file",
polygon: [
[51.515, -0.09],
[51.52, -0.1],
[51.52, -0.12],
],
};
const validationSchema = object({
description: string().required("وارد کردن توضیحات الزامیست!"),
});
const RoadSafetyFormContext = ({ rowId, mutate, setOpenRoadSafetyForm }) => {
const defaultValues = {
description: "",
};
const requestServer = useRequest({ notification: { success: true, show: true } });
const { message, loadingMessage, errorMessage } = usePrevStateOpinion();
const {
register,
handleSubmit,
formState: { isSubmitting, errors },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
const onSubmit = async (data) => {
const formData = new FormData();
formData.append("description", data.description);
requestServer(`${SUBMIT_ROAD_SAFETY_FORM}/${rowId}`, "post", {
data: formData,
})
.then(() => {
setOpenRoadSafetyForm(false);
mutate();
})
.catch(() => {});
};
return (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<DialogContent>
<ApplicantRequestDetail data={fakeData} />
<Stack spacing={2}>
<QuestionSafetyForm />
<PrevCartableOpinion
message={message}
loadingMessage={loadingMessage}
errorMessage={errorMessage}
/>
<DescriptionForm register={register} errors={errors} />
<DialogActions>
<ManagerOrAssistantSubmit isSubmitting={isSubmitting} />
</DialogActions>
</Stack>
</DialogContent>
</StyledForm>
);
};
export default RoadSafetyFormContext;

View File

@@ -0,0 +1,52 @@
import { Dialog, IconButton, Stack, Tooltip } from "@mui/material";
import EngineeringIcon from "@mui/icons-material/Engineering";
import DialogTransition from "@/core/components/DialogTransition";
import { useState } from "react";
import { Close } from "@mui/icons-material";
import RoadSafetyFormContext from "./RoadSafetyFormContext";
const RoadSafetyForm = ({ rowId, mutate }) => {
const [openRoadSafetyForm, setOpenRoadSafetyForm] = useState(false);
return (
<Stack>
<Tooltip title="فرم ایمنی راه" arrow placement="right">
<IconButton
color="primary"
sx={{ textTransform: "unset", alignSelf: "center" }}
onClick={() => {
setOpenRoadSafetyForm(true);
}}
>
<EngineeringIcon />
</IconButton>
</Tooltip>
<Dialog
PaperProps={{
sx: {
transition: "all .3s",
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
},
}}
open={openRoadSafetyForm}
maxWidth={"lg"}
TransitionComponent={DialogTransition}
>
<IconButton
aria-label="close"
onClick={() => setOpenRoadSafetyForm(false)}
sx={{
position: "absolute",
right: 8,
top: 8,
zIndex: 10,
color: (theme) => theme.palette.grey[500],
}}
>
<Close />
</IconButton>
<RoadSafetyFormContext rowId={rowId} mutate={mutate} setOpenRoadSafetyForm={setOpenRoadSafetyForm} />
</Dialog>
</Stack>
);
};
export default RoadSafetyForm;

View File

@@ -0,0 +1,75 @@
"use client";
import { Dialog, DialogContent } from "@mui/material";
import { object, string } from "yup";
import useRequest from "@/lib/hooks/useRequest";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import StyledForm from "@/core/components/StyledForm";
import ApplicantRequestDetail from "@/core/components/ApplicantRequestDetail";
const fakeData = {
id: 1,
shomareh_darkhast: "2124",
ostan: "ostan",
shahr: "shahr",
shahrestan: "shahrestan",
bakhsh: "bakhsh",
roosta: "roosta",
tarikh_darkhast: "tarikh_darkhast",
sazman: "sazman",
masahat_zamin: "masahat_zamin",
masahat_tarh: "masahat_tarh",
gorooh_tarh: "gorooh_tarh",
onvane_tarh: "onvane_tarh",
address: "کرج - فلان جا - جنب پاساژ - نزدیک اونجا - اونور خیابون - زیر رو گذر - روی زیر گذر",
file_mosavab: "file",
polygon: [
[51.515, -0.09],
[51.52, -0.1],
[51.52, -0.12],
],
};
const validationSchema = object({
description: string().required("وارد کردن توضیحات الزامیست!"),
});
const DetailDialog = ({ taskModal, setTaskModal, rowId, mutate }) => {
const requestServer = useRequest({ auth: true });
const defaultValues = {
description: "",
};
const handleClose = () => {
setTaskModal(false);
};
const {
register,
handleSubmit,
formState: { isSubmitting, errors, touchedFields },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
const onSubmit = async (data) => {
const formData = new FormData();
formData.append("description", data.description);
requestServer(`api-for-send-to-harim/${rowId}`, "post", {
data: formData,
})
.then(() => {
handleClose();
mutate();
})
.catch(() => {});
};
return (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<Dialog open={taskModal} onClose={handleClose} maxWidth="lg" fullWidth>
<DialogContent dividers>
<ApplicantRequestDetail data={fakeData} />
</DialogContent>
</Dialog>
</StyledForm>
);
};
export default DetailDialog;

View File

@@ -0,0 +1,26 @@
"use client";
import { IconButton, Tooltip } from "@mui/material";
import AssignmentIcon from "@mui/icons-material/Assignment";
import DetailDialog from "./DetailDialog";
import { useState } from "react";
const TaskDetail = ({ rowId, mutate }) => {
const [taskModal, setTaskModal] = useState(false);
const openDetailDialog = () => {
setTaskModal(true);
};
return (
<>
<Tooltip title="جزئیات طرح متقاضی" arrow placement="right">
<IconButton color="primary" onClick={openDetailDialog}>
<AssignmentIcon />
</IconButton>
</Tooltip>
<DetailDialog taskModal={taskModal} setTaskModal={setTaskModal} rowId={rowId} mutate={mutate} />
</>
);
};
export default TaskDetail;

View File

@@ -0,0 +1,13 @@
import TaskDetail from "./TaskDetail";
import { Box } from "@mui/material";
import RoadSafetyForm from "./RoadSafetyForm";
const RowActions = ({ row, mutate }) => {
return (
<Box sx={{ display: "flex", gap: 1 }}>
<TaskDetail mutate={mutate} rowId={row.getValue("id")} />
<RoadSafetyForm mutate={mutate} rowId={row.getValue("id")} />
</Box>
);
};
export default RowActions;

View File

@@ -0,0 +1,145 @@
"use client";
import { useMemo } from "react";
import { Box } from "@mui/material";
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import RowActions from "./RowActions";
const TaskList = () => {
const columns = useMemo(
() => [
{
accessorKey: "id",
header: "کد یکتا",
id: "id",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
},
{
accessorKey: "aplication_number",
header: "شماره درخواست",
id: "aplication_number",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
},
{
accessorKey: "application_date",
header: "تاریخ درخواست",
id: "application_date",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "province",
header: "استان",
id: "province",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "township",
header: "شهرستان",
id: "township",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "city",
header: "شهر",
id: "city",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "county",
header: "بخش",
id: "county",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "village",
header: "روستا",
id: "village",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "land_area",
header: "مساحت زمین",
id: "land_area",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_area",
header: "مساحت طرح",
id: "design_area",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "organization",
header: "سازمان",
id: "organization",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_group",
header: "گروه طرح",
id: "design_group",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_title",
header: "عنوان طرح",
id: "design_title",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "state",
header: "وضعیت درخواست",
id: "state",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
],
[]
);
return (
<>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
table_title={"لیست استعلام ها"}
need_filter={false}
columns={columns}
table_url={"/v3/api/fake-data"}
page_name={"generalManagerZaminGov"}
table_name={"generalManagerZaminGovList"}
enableRowActions
positionActionsColumn={"last"}
RowActions={RowActions}
/>
</Box>
</>
);
};
export default TaskList;

View File

@@ -0,0 +1,15 @@
"use client";
import PageTitle from "@/core/components/PageTitle";
import { Stack } from "@mui/material";
import TaskList from "./TaskList";
const GeneralManagerZaminGovComponent = () => {
return (
<Stack spacing={1}>
<PageTitle title={"استعلام حرائم پنجره واحد"} />
<TaskList />
</Stack>
);
};
export default GeneralManagerZaminGovComponent;

View File

@@ -0,0 +1,96 @@
import {Box, Button, ButtonGroup} from "@mui/material";
import AutoModeIcon from "@mui/icons-material/AutoMode";
import DeleteIcon from "@mui/icons-material/Delete";
import EditLocationAltIcon from "@mui/icons-material/EditLocationAlt";
import SaveIcon from "@mui/icons-material/Save";
import CancelIcon from "@mui/icons-material/Cancel";
const MapActionButtons = ({
disableToCreate,
disableToEditAndDelete,
disableToSaveAndCancel,
onDraw,
onEdit,
onRemove,
onSave,
onCancel,
}) => (
<>
<Box sx={{
background: "#ffffff",
position: "absolute",
zIndex: "1999",
bottom: 0,
left: 0,
p: 2,
pl: 0.5,
pb: 0.5,
borderTopRightRadius: 8,
}}>
<ButtonGroup variant="contained" orientation="vertical" aria-label="map action group button">
<Button
sx={{justifyContent: "space-between"}}
startIcon={<AutoModeIcon/>}
color="primary"
disabled={disableToCreate}
onClick={onDraw}
>
اصلاح
</Button>
<Button
sx={{justifyContent: "space-between"}}
startIcon={<EditLocationAltIcon/>}
color="warning"
disabled={disableToEditAndDelete}
onClick={onEdit}
>
ویرایش
</Button>
<Button
sx={{justifyContent: "space-between"}}
startIcon={<DeleteIcon/>}
color="error"
disabled={disableToEditAndDelete}
onClick={onRemove}
>
حذف
</Button>
</ButtonGroup>
</Box>
<Box sx={{
position: "absolute",
zIndex: "1999",
right: 10,
top: 10,
background: "#fff",
borderRadius: 1,
padding: 0.5,
}}>
<Button
sx={{justifyContent: "space-between", mr: 1}}
startIcon={<SaveIcon/>}
variant="outlined"
size="small"
color="success"
disabled={disableToSaveAndCancel}
onClick={onSave}
>
ذخیره
</Button>
<Button
sx={{justifyContent: "space-between"}}
startIcon={<CancelIcon/>}
variant="outlined"
size="small"
color="error"
disabled={disableToSaveAndCancel}
onClick={onCancel}
>
لغو تغییرات
</Button>
</Box>
</>
);
export default MapActionButtons;

View File

@@ -0,0 +1,91 @@
"use client";
import {
Box,
Button,
Chip,
Dialog,
DialogActions,
DialogContent,
Divider,
FormControl,
FormControlLabel,
FormLabel,
Radio,
RadioGroup,
Typography,
} from "@mui/material";
import dynamic from "next/dynamic";
import MapLoading from "@/core/components/MapLayer/Loading";
import "leaflet-draw/dist/leaflet.draw.css";
import GppMaybeIcon from "@mui/icons-material/GppMaybe";
import PolygonForDesign from "./PolygonForDesign";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading/>,
ssr: false,
});
const MapModifyDialog = ({mapModifyModal, setMapModifyModal}) => {
const handleClose = () => {
setMapModifyModal(false);
};
return (
<Dialog open={mapModifyModal} onClose={handleClose} maxWidth="lg" fullWidth>
<DialogContent sx={{p: 2}} dividers>
<Divider sx={{my: 3}}>
<Chip color="primary" sx={{mx: 1, fontSize: "13px", fontWeight: 500}}
label="بررسی پلیگان طرح متقاضی"/>
</Divider>
<Box sx={{
width: "100%",
height: "400px",
borderRadius: 3,
borderBottomLeftRadius: 0,
overflow: "hidden",
}}>
<MapLayer>
<PolygonForDesign/>
</MapLayer>
</Box>
<Box sx={{display: "flex", my: 2, alignItems: "center"}}>
<GppMaybeIcon color="warning"/>
<Typography variant="button" sx={{color: "warning.main", ml: 1}}>
نکته: اصلاح ننمودن طرح به منزله تایید طرح میباشد.
</Typography>
</Box>
<Box sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
border: "1px solid #e1e1e1",
p: 2,
borderRadius: 1,
}}>
<FormControl sx={{flexDirection: "row", alignItems: "center", gap: 2}}>
<FormLabel id="way-status" sx={{fontWeight: 500, fontSize: "16px", color: "warning.main"}}>آیا
طرح نیاز به ایجاد راه
دسترسی
دارد؟</FormLabel>
<RadioGroup
row
aria-labelledby="way-status"
defaultValue={0}
name="radio-buttons-group"
>
<FormControlLabel value={1} control={<Radio color="warning"/>} label="بله"/>
<FormControlLabel value={0} control={<Radio color="warning"/>} label="خیر"/>
</RadioGroup>
</FormControl>
</Box>
</DialogContent>
<DialogActions sx={{justifyContent: "center", py: 2}}>
<Button size="large" variant="outlined">بستن</Button>
<Button size="large" variant="contained">ثبت</Button>
</DialogActions>
</Dialog>
);
};
export default MapModifyDialog;

View File

@@ -0,0 +1,118 @@
"use client";
import "leaflet-draw/dist/leaflet.draw.css";
import "@/assets/scss/map-styles.scss"
import {FeatureGroup, useMap} from "react-leaflet";
import {EditControl} from "react-leaflet-draw";
import {useEffect, useRef, useState} from "react";
import MapActionButtons from "./MapActionButtons";
const PolygonForDesign = () => {
const map = useMap();
const editableFG = useRef(null);
const [polygonLayer, setPolygonLayer] = useState(null);
const [disableToCreate, setDisableToCreate] = useState(false);
const [disableToEditAndDelete, setDisableToEditAndDelete] = useState(true);
const [disableToSaveAndCancel, setDisableToSaveAndCancel] = useState(true);
const [editToolbar, setEditToolbar] = useState(null);
useEffect(() => {
const {L} = window;
L.drawLocal.draw.handlers.polygon.tooltip = {
start: "برای شروع کشیدن پلیگان، کلیک کنید.",
cont: "گوشه های دیگر پلیگان را نیز انتخاب کنید.",
end: "برای اتمام رسم پلیگان، نقطه آخر را به اول متصل نمایید.",
};
L.drawLocal.edit.handlers.edit.tooltip = {
text: "برای ذخیر یا لغو تغییرات، از دکمه های بالا سمت چپ استفاده نمایید.",
subtext: "نقاط مشخص شده را گرفته و برای ویرایش جابجا نمایید.",
};
}, []);
const handleDrawPolygon = () => {
const {L} = window;
const drawControl = new L.Draw.Polygon(map);
drawControl.enable();
setDisableToCreate(true);
};
const handleEditPolygon = () => {
const {L} = window;
if (editableFG.current && polygonLayer) {
const editControlInstance = new L.EditToolbar.Edit(map, {
featureGroup: editableFG.current,
});
editControlInstance.enable();
setEditToolbar(editControlInstance);
setDisableToEditAndDelete(true);
setDisableToSaveAndCancel(false);
}
};
const handleRemovePolygon = () => {
if (polygonLayer && editableFG.current) {
editableFG.current.removeLayer(polygonLayer);
setPolygonLayer(null);
setDisableToEditAndDelete(true);
setDisableToCreate(false);
}
};
const handleSavePolygon = () => {
if (editToolbar) {
editToolbar.save();
editToolbar.disable();
setDisableToEditAndDelete(false);
setDisableToSaveAndCancel(true);
}
};
const handleCancelEdit = () => {
if (editToolbar) {
editToolbar.revertLayers();
editToolbar.disable();
setDisableToEditAndDelete(false);
setDisableToSaveAndCancel(true);
}
};
const handlePolygonCreate = (e) => {
const layer = e.layer;
setPolygonLayer(layer);
editableFG.current.addLayer(layer);
setDisableToEditAndDelete(false);
};
return (
<>
<FeatureGroup ref={editableFG}>
<EditControl
position="bottomright"
onCreated={handlePolygonCreate}
draw={{
polygon: false,
circlemarker: false,
marker: false,
circle: false,
rectangle: false,
polyline: false,
}}
edit={{edit: false, remove: false}}
/>
</FeatureGroup>
<MapActionButtons
disableToCreate={disableToCreate}
disableToEditAndDelete={disableToEditAndDelete}
disableToSaveAndCancel={disableToSaveAndCancel}
onDraw={handleDrawPolygon}
onEdit={handleEditPolygon}
onRemove={handleRemovePolygon}
onSave={handleSavePolygon}
onCancel={handleCancelEdit}
/>
</>
);
};
export default PolygonForDesign;

View File

@@ -0,0 +1,25 @@
import {IconButton, Tooltip} from "@mui/material";
import MapIcon from "@mui/icons-material/Map";
import {useState} from "react";
import MapModifyDialog from "./MapModifyDialog";
const MapModify = ({rowId, mutate}) => {
const [mapModifyModal, setMapModifyModal] = useState(false);
const openMapModifyDialog = () => {
setMapModifyModal(true);
};
return (
<>
<Tooltip title="بررسی پلیگان طرح" arrow placement="right">
<IconButton color="primary" onClick={openMapModifyDialog}>
<MapIcon/>
</IconButton>
</Tooltip>
<MapModifyDialog mapModifyModal={mapModifyModal} setMapModifyModal={setMapModifyModal} rowId={rowId}
mutate={mutate}/>
</>
);
};
export default MapModify;

View File

@@ -0,0 +1,139 @@
import {
Autocomplete,
Button,
CircularProgress,
DialogActions,
DialogContent,
FormControl,
FormHelperText,
InputLabel,
OutlinedInput,
Stack,
TextField,
Typography,
} from "@mui/material";
import { Controller, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { object, string } from "yup";
import StyledForm from "@/core/components/StyledForm";
import useProvinces from "@/lib/hooks/useProvince";
import useRequest from "@/lib/hooks/useRequest";
import { REFER_ADMIN_PROVINCE } from "@/core/utils/routes";
const validationSchema = object({
description: string().required("وارد کردن توضیحات الزامیست!"),
province: string().required("وارد کردن استان الزامیست!"),
});
const ReferFormContext = ({ setOpenReferDialog, rowId, mutate }) => {
const defaultValues = {
description: "",
province: "",
};
const { provinces, loadingProvinces, errorProvinces } = useProvinces();
const requestServer = useRequest({ notification: { show: true, success: true } });
const {
control,
register,
handleSubmit,
formState: { isSubmitting, errors, touchedFields },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
const onSubmit = async (data) => {
const formData = new FormData();
formData.append("description", data.description);
formData.append("provinceId", data.province);
requestServer(`${REFER_ADMIN_PROVINCE}/${rowId}`, "post", {
data: formData,
})
.then(() => {
setOpenReferDialog(false);
mutate();
})
.catch(() => {});
};
return (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<DialogContent>
<Stack spacing={2}>
<Stack>
<FormControl error={!!errors.description} size="small" fullWidth variant="outlined">
<InputLabel sx={{ pt: 1 }} htmlFor="description">
توضیحات
</InputLabel>
<OutlinedInput
id="description"
label={"توضیحات"}
multiline
rows={8}
autoComplete="off"
{...register("description")}
size="small"
fullWidth
sx={{ mt: 1 }}
type="text"
/>
<FormHelperText id="description">
{errors.description ? errors.description.message : null}
</FormHelperText>
</FormControl>
</Stack>
<Stack>
<Controller
name="province"
control={control}
render={({ field: { onChange, value }, fieldState: { error } }) => (
<FormControl error={!!error} size="small" fullWidth variant="outlined">
<InputLabel htmlFor="province" />
{errorProvinces ? (
<Typography color={"red"}>خطایی در دریافت استان ها رخ داده است!</Typography>
) : loadingProvinces ? (
<Typography sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<CircularProgress size={20} />
درحال دریافت لیست استان ها
</Typography>
) : (
<Autocomplete
id="province"
size="small"
value={provinces.find((province) => province.id === value) || null}
disablePortal
options={provinces}
getOptionLabel={(province) => province.name}
isOptionEqualToValue={(option, value) => option.id === value.id}
onChange={(event, newValue) => {
onChange(newValue ? newValue.id : "");
}}
renderInput={(params) => (
<TextField
{...params}
autoComplete="off"
error={!!errors.province}
fullWidth
label="استان"
/>
)}
/>
)}
<FormHelperText id="province">
{errors.province ? errors.province.message : null}
</FormHelperText>
</FormControl>
)}
/>
</Stack>
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={() => setOpenReferDialog(false)} variant="outlined" color="secondary" autoFocus>
{"انصراف"}
</Button>
<Button variant="contained" color="primary" type={"submit"} disabled={isSubmitting}>
{isSubmitting ? "در حال اسال" : "ارجاع"}
</Button>
</DialogActions>
</StyledForm>
);
};
export default ReferFormContext;

View File

@@ -0,0 +1,41 @@
import { Dialog, DialogTitle, IconButton, Stack, Tooltip } from "@mui/material";
import ReplyIcon from "@mui/icons-material/Reply";
import DialogTransition from "@/core/components/DialogTransition";
import { useState } from "react";
import ReferFormContext from "./ReferFormContext";
const ReferForm = ({ rowId, mutate }) => {
const [openReferDialog, setOpenReferDialog] = useState(false);
return (
<Stack>
<Tooltip title="ارجاع به استان دیگر" arrow placement="right">
<IconButton
color="primary"
sx={{ textTransform: "unset", alignSelf: "center" }}
onClick={() => {
setOpenReferDialog(true);
}}
>
<ReplyIcon />
</IconButton>
</Tooltip>
<Dialog
PaperProps={{
sx: {
transition: "all .3s",
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
},
}}
open={openReferDialog}
fullWidth
TransitionComponent={DialogTransition}
>
<DialogTitle sx={{ m: 0, p: 2, borderBottom: 1, borderColor: "divider" }} id="create-dialog">
ارجاع به استان دیگر
</DialogTitle>
<ReferFormContext rowId={rowId} mutate={mutate} setOpenReferDialog={setOpenReferDialog} />
</Dialog>
</Stack>
);
};
export default ReferForm;

View File

@@ -0,0 +1,29 @@
import { FormControl, FormHelperText, InputLabel, OutlinedInput, Stack } from "@mui/material";
const DescriptionForm = ({ errors, register }) => {
return (
<Stack>
<FormControl error={!!errors.description} size="small" fullWidth variant="outlined">
<InputLabel sx={{ pt: 1 }} htmlFor="description">
توضیحات
</InputLabel>
<OutlinedInput
id="description"
label={"توضیحات"}
multiline
rows={6}
{...register("description")}
autoComplete="off"
size="small"
fullWidth
sx={{ mt: 1 }}
type="text"
/>
<FormHelperText id="description">
{errors.description ? errors.description.message : null}
</FormHelperText>
</FormControl>
</Stack>
);
};
export default DescriptionForm;

View File

@@ -0,0 +1,27 @@
import { Card, CardContent, CardHeader, CircularProgress, Divider, Stack, Typography } from "@mui/material";
import usePrevStateOpinion from "@/lib/hooks/usePrevStateopinion";
const PrevCartableOpinion = () => {
const { message, loadingMessage, errorMessage } = usePrevStateOpinion();
return (
<Stack>
<Card variant="outlined">
<CardHeader sx={{ pb: 0 }} title="نظر معاون راهداری استان :" />
<CardContent>
{errorMessage ? (
<Typography color={"red"}>خطا در دریافت اطلاعات !!!</Typography>
) : loadingMessage ? (
<Typography sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<CircularProgress size={20} />
درحال دریافت اطلاعات
</Typography>
) : (
<Typography>{message}</Typography>
)}
</CardContent>
</Card>
<Divider sx={{ mt: 2 }} />
</Stack>
);
};
export default PrevCartableOpinion;

View File

@@ -0,0 +1,57 @@
import {
Card,
CardContent,
FormControl,
FormControlLabel,
FormLabel,
RadioGroup,
Stack,
Typography,
} from "@mui/material";
import Radio from "@mui/material/Radio";
const QuestionSafetyForm = ({ register, errors }) => {
return (
<Stack sx={{ py: 2 }}>
<Card
variant="outlined"
sx={{ display: "flex", justifyContent: "center", alignItems: "center", borderColor: "primary.main" }}
>
<CardContent>
<FormControl error={!!errors.RadioGroup}>
<FormLabel>
<Typography color={"primary"} variant={"h5"} fontWeight={"bolder"}>
آیا ایمنی راه این طرح مورد تایید است ؟
</Typography>
</FormLabel>
<Stack
sx={{ pt: 2, display: "flex", justifyContent: "center", alignItems: "center" }}
direction={"row"}
>
<RadioGroup row>
<FormControlLabel
value="1"
control={<Radio />}
label="بله"
{...register("RadioGroup")}
/>
<FormControlLabel
value="0"
control={<Radio />}
label="خیر"
{...register("RadioGroup")}
/>
</RadioGroup>
</Stack>
{errors.RadioGroup && (
<Typography textAlign={"center"} variant="body2" color="error">
{errors.RadioGroup.message}
</Typography>
)}
</FormControl>
</CardContent>
</Card>
</Stack>
);
};
export default QuestionSafetyForm;

View File

@@ -0,0 +1,80 @@
import { DialogActions, DialogContent, Stack } from "@mui/material";
import StyledForm from "@/core/components/StyledForm";
import useRequest from "@/lib/hooks/useRequest";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { object, string } from "yup";
import QuestionSafetyForm from "./QuestionSafetyForm";
import PrevCartableOpinion from "./PrevCartableOpinion";
import DescriptionForm from "./DescriptionForm";
import SubmitButtonsAdmin from "./SubmitButtonsAdmin";
import { SUBMIT_ROAD_SAFETY_FORM } from "@/core/utils/routes";
import ApplicantRequestDetail from "@/core/components/ApplicantRequestDetail";
const fakeData = {
id: 1,
shomareh_darkhast: "2124",
ostan: "ostan",
shahr: "shahr",
shahrestan: "shahrestan",
bakhsh: "bakhsh",
roosta: "roosta",
tarikh_darkhast: "tarikh_darkhast",
sazman: "sazman",
masahat_zamin: "masahat_zamin",
masahat_tarh: "masahat_tarh",
gorooh_tarh: "gorooh_tarh",
onvane_tarh: "onvane_tarh",
address: "کرج - فلان جا - جنب پاساژ - نزدیک اونجا - اونور خیابون - زیر رو گذر - روی زیر گذر",
file_mosavab: "file",
polygon: [
[51.515, -0.09],
[51.52, -0.1],
[51.52, -0.12],
],
};
const validationSchema = object({
description: string().required("وارد کردن توضیحات الزامیست!"),
RadioGroup: string().required("تاییدیه ایمنی راه ضروریست!"),
});
const RoadSafetyFormContext = ({ rowId, mutate, setOpenRoadSafetyForm }) => {
const defaultValues = {
description: "",
RadioGroup: "",
};
const requestServer = useRequest({ notification: { success: true, show: true } });
const {
register,
handleSubmit,
formState: { isSubmitting, errors },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
const onSubmit = async (data) => {
const formData = new FormData();
formData.append("description", data.description);
formData.append("provinceId", data.RadioGroup);
requestServer(`${SUBMIT_ROAD_SAFETY_FORM}/${rowId}`, "post", {
data: formData,
})
.then(() => {
setOpenRoadSafetyForm(false);
mutate();
})
.catch(() => {});
};
return (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<DialogContent>
<ApplicantRequestDetail data={fakeData} />
<Stack spacing={2}>
<QuestionSafetyForm register={register} errors={errors} />
<PrevCartableOpinion />
<DescriptionForm register={register} errors={errors} />
<DialogActions>
<SubmitButtonsAdmin isSubmitting={isSubmitting} setOpenRoadSafetyForm={setOpenRoadSafetyForm} />
</DialogActions>
</Stack>
</DialogContent>
</StyledForm>
);
};
export default RoadSafetyFormContext;

View File

@@ -0,0 +1,21 @@
import { Button } from "@mui/material";
const SubmitButtonsAdmin = ({ setOpenRoadSafetyForm, isSubmitting }) => {
return (
<>
<Button
onClick={() => setOpenRoadSafetyForm(false)}
fullWidth
variant="outlined"
color="secondary"
autoFocus
>
{"انصراف"}
</Button>
<Button fullWidth variant="contained" color="primary" type={"submit"} disabled={isSubmitting}>
{isSubmitting ? "در حال ارسال..." : "ارسال"}
</Button>
</>
);
};
export default SubmitButtonsAdmin;

View File

@@ -0,0 +1,52 @@
import { Dialog, IconButton, Stack, Tooltip } from "@mui/material";
import EngineeringIcon from "@mui/icons-material/Engineering";
import DialogTransition from "@/core/components/DialogTransition";
import { useState } from "react";
import RoadSafetyFormContext from "./RoadSaftyFormContext";
import { Close } from "@mui/icons-material";
const RoadSafetyForm = ({ rowId, mutate }) => {
const [openRoadSafetyForm, setOpenRoadSafetyForm] = useState(false);
return (
<Stack>
<Tooltip title="فرم ایمنی راه" arrow placement="right">
<IconButton
color="primary"
sx={{ textTransform: "unset", alignSelf: "center" }}
onClick={() => {
setOpenRoadSafetyForm(true);
}}
>
<EngineeringIcon />
</IconButton>
</Tooltip>
<Dialog
PaperProps={{
sx: {
transition: "all .3s",
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
},
}}
open={openRoadSafetyForm}
maxWidth={"lg"}
TransitionComponent={DialogTransition}
>
<IconButton
aria-label="close"
onClick={() => setOpenRoadSafetyForm(false)}
sx={{
position: "absolute",
right: 8,
top: 8,
zIndex: 10,
color: (theme) => theme.palette.grey[500],
}}
>
<Close />
</IconButton>
<RoadSafetyFormContext rowId={rowId} mutate={mutate} setOpenRoadSafetyForm={setOpenRoadSafetyForm} />
</Dialog>
</Stack>
);
};
export default RoadSafetyForm;

View File

@@ -0,0 +1,75 @@
"use client";
import { Dialog, DialogContent } from "@mui/material";
import { object, string } from "yup";
import useRequest from "@/lib/hooks/useRequest";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import StyledForm from "@/core/components/StyledForm";
import ApplicantRequestDetail from "@/core/components/ApplicantRequestDetail";
const fakeData = {
id: 1,
shomareh_darkhast: "2124",
ostan: "ostan",
shahr: "shahr",
shahrestan: "shahrestan",
bakhsh: "bakhsh",
roosta: "roosta",
tarikh_darkhast: "tarikh_darkhast",
sazman: "sazman",
masahat_zamin: "masahat_zamin",
masahat_tarh: "masahat_tarh",
gorooh_tarh: "gorooh_tarh",
onvane_tarh: "onvane_tarh",
address: "کرج - فلان جا - جنب پاساژ - نزدیک اونجا - اونور خیابون - زیر رو گذر - روی زیر گذر",
file_mosavab: "file",
polygon: [
[51.515, -0.09],
[51.52, -0.1],
[51.52, -0.12],
],
};
const validationSchema = object({
description: string().required("وارد کردن توضیحات الزامیست!"),
});
const DetailDialog = ({ taskModal, setTaskModal, rowId, mutate }) => {
const requestServer = useRequest({ auth: true });
const defaultValues = {
description: "",
};
const handleClose = () => {
setTaskModal(false);
};
const {
register,
handleSubmit,
formState: { isSubmitting, errors, touchedFields },
} = useForm({ defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur" });
const onSubmit = async (data) => {
const formData = new FormData();
formData.append("description", data.description);
requestServer(`api-for-send-to-harim/${rowId}`, "post", {
data: formData,
})
.then(() => {
handleClose();
mutate();
})
.catch(() => {});
};
return (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<Dialog open={taskModal} onClose={handleClose} maxWidth="lg" fullWidth>
<DialogContent dividers>
<ApplicantRequestDetail data={fakeData} />
</DialogContent>
</Dialog>
</StyledForm>
);
};
export default DetailDialog;

View File

@@ -0,0 +1,26 @@
"use client";
import { IconButton, Tooltip } from "@mui/material";
import AssignmentIcon from "@mui/icons-material/Assignment";
import DetailDialog from "./DetailDialog";
import { useState } from "react";
const TaskDetail = ({ rowId, mutate }) => {
const [taskModal, setTaskModal] = useState(false);
const openDetailDialog = () => {
setTaskModal(true);
};
return (
<>
<Tooltip title="جزئیات طرح متقاضی" arrow placement="right">
<IconButton color="primary" onClick={openDetailDialog}>
<AssignmentIcon />
</IconButton>
</Tooltip>
<DetailDialog taskModal={taskModal} setTaskModal={setTaskModal} rowId={rowId} mutate={mutate} />
</>
);
};
export default TaskDetail;

View File

@@ -0,0 +1,17 @@
import ReferForm from "./Refer";
import TaskDetail from "./TaskDetail";
import {Box} from "@mui/material";
import RoadSafetyForm from "./RoadSafetyForm";
import MapModify from "./MapModify";
const RowActions = ({row, mutate}) => {
return (
<Box sx={{display: "flex", gap: 1}}>
<MapModify mutate={mutate} rowId={row.getValue("id")}/>
<ReferForm mutate={mutate} rowId={row.getValue("id")}/>
<TaskDetail mutate={mutate} rowId={row.getValue("id")}/>
<RoadSafetyForm rowId={row.getValue("id")} mutate={mutate}/>
</Box>
);
};
export default RowActions;

View File

@@ -0,0 +1,145 @@
"use client";
import { useMemo } from "react";
import { Box } from "@mui/material";
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import RowActions from "./RowActions";
const TaskList = () => {
const columns = useMemo(
() => [
{
accessorKey: "id",
header: "کد یکتا",
id: "id",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
},
{
accessorKey: "aplication_number",
header: "شماره درخواست",
id: "aplication_number",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
},
{
accessorKey: "application_date",
header: "تاریخ درخواست",
id: "application_date",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "province",
header: "استان",
id: "province",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "township",
header: "شهرستان",
id: "township",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "city",
header: "شهر",
id: "city",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "county",
header: "بخش",
id: "county",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "village",
header: "روستا",
id: "village",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "land_area",
header: "مساحت زمین",
id: "land_area",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_area",
header: "مساحت طرح",
id: "design_area",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "organization",
header: "سازمان",
id: "organization",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_group",
header: "گروه طرح",
id: "design_group",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "design_title",
header: "عنوان طرح",
id: "design_title",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "state",
header: "وضعیت درخواست",
id: "state",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
],
[]
);
return (
<>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTableWithAuth
table_title={"لیست استعلام ها"}
need_filter={false}
columns={columns}
table_url={"/v3/api/fake-data"}
page_name={"provinceAdminZaminGov"}
table_name={"provinceAdminZaminGovList"}
enableRowActions
positionActionsColumn={"last"}
RowActions={RowActions}
/>
</Box>
</>
);
};
export default TaskList;

View File

@@ -0,0 +1,15 @@
"use client";
import PageTitle from "@/core/components/PageTitle";
import { Stack } from "@mui/material";
import TaskList from "./TaskList";
const ProvinceAdminZaminGovComponent = () => {
return (
<Stack spacing={1}>
<PageTitle title={"استعلام حرائم پنجره واحد"} />
<TaskList />
</Stack>
);
};
export default ProvinceAdminZaminGovComponent;

View File

@@ -27,12 +27,7 @@ const InquiryPrivacyFencingCreate = ({ mutate }) => {
<AddCircle sx={{ fontSize: "25px" }} />
</IconButton>
) : (
<Button
variant="contained"
color="primary"
startIcon={<AddCircle />}
onClick={handleOpen}
>
<Button variant="contained" color="primary" startIcon={<AddCircle />} onClick={handleOpen}>
ایجاد پاسخ به استعلام
</Button>
)}

View File

@@ -1,7 +1,21 @@
import LtrTextField from "@/core/components/LtrTextField";
import StyledForm from "@/core/components/StyledForm";
import useRequest from "@/lib/hooks/useRequest";
import { Autocomplete, Box, Button, Chip, Container, DialogActions, DialogContent, Fade, Grid, InputAdornment, Stack, TextField, Typography } from "@mui/material";
import {
Autocomplete,
Box,
Button,
Chip,
Container,
DialogActions,
DialogContent,
Fade,
Grid,
InputAdornment,
Stack,
TextField,
Typography,
} from "@mui/material";
import { DatePicker, LocalizationProvider, faIR } from "@mui/x-date-pickers";
import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali";
import moment from "jalali-moment";
@@ -9,130 +23,135 @@ import { Controller, useForm } from "react-hook-form";
import LocationOnMap from "./LocationOnMap";
const initValues = {
dabirkhaneh_number: '',
dabirkhaneh_number: "",
nameh_date: moment(),
nameh_date_fa: '',
marjae_pasokh: '',
nameh_date_fa: "",
marjae_pasokh: "",
motaghazi_is_legal_id: null,
motaghazi_is_legal: '',
motaghazi_type_id: '',
motaghazi_is_legal: "",
motaghazi_type_id: "",
motaghazi_type: null,
motaghazi_firstname: '',
motaghazi_lastname: '',
national_id: '',
shenase_melli: '',
tel_number: '',
mobile_number: '',
address: '',
motaghazi_firstname: "",
motaghazi_lastname: "",
national_id: "",
shenase_melli: "",
tel_number: "",
mobile_number: "",
address: "",
edare_kol_id: null,
edare_kol: '',
edare_kol: "",
edare_shahri_id: null,
edare_shahri: '',
edare_shahri: "",
rah_type_id: null,
rah_type: '',
name_mehvar_id: '',
rah_type: "",
name_mehvar_id: "",
name_mehvar_fa: null,
mizan_harim: null,
arze_navar: null,
samt_id: null,
samt: '',
kilometr: '',
lat: '',
lon: '',
samt: "",
kilometr: "",
lat: "",
lon: "",
zone: null,
karbari_type_id: null,
karbari_type: '',
tarh_title: '',
masahat_zirbana: '',
karbari_type: "",
tarh_title: "",
masahat_zirbana: "",
ehdasat_type_id: [],
ehdasat_type: '',
divarkeshi_distance: '',
mostahadesat_distance: '',
ehdasat_type: "",
divarkeshi_distance: "",
mostahadesat_distance: "",
mahale_ejra_id: null,
mahale_ejra: '',
mahale_ejra: "",
traffic_id: null,
traffic: '',
traffic: "",
vaziat_eghtesadi_id: null,
vaziat_eghtesadi: '',
vaziat_eghtesadi: "",
has_access_id: null,
has_access: '',
shomare_estelam_harim: '',
max_month: '',
max_day: '',
shomare_tahaodname: '',
shomare_daftarkhaneh: '',
description: '',
ronevesht: '',
}
has_access: "",
shomare_estelam_harim: "",
max_month: "",
max_day: "",
shomare_tahaodname: "",
shomare_daftarkhaneh: "",
description: "",
ronevesht: "",
};
const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
const request = useRequest()
const { control, watch, register, handleSubmit, setValue, formState: { isSubmitting } } = useForm({ defaultValues: defaultValues || initValues });
const request = useRequest();
const {
control,
watch,
register,
handleSubmit,
setValue,
formState: { isSubmitting },
} = useForm({ defaultValues: defaultValues || initValues });
const onSubmit = async (data) => {
const formData = new FormData()
formData.append('dabirkhaneh_number', data.dabirkhaneh_number)
formData.append('nameh_date', data.nameh_date.format('YYYY-MM-DD'))
formData.append('nameh_date_fa', data.nameh_date)
formData.append('marjae_pasokh', data.marjae_pasokh)
formData.append('motaghazi_is_legal_id', data.motaghazi_is_legal_id)
formData.append('motaghazi_is_legal', data.motaghazi_is_legal_id)
formData.append('motaghazi_type_id', 1)
formData.append('motaghazi_type', data.motaghazi_type)
formData.append('motaghazi_firstname', data.motaghazi_firstname)
formData.append('motaghazi_lastname', data.motaghazi_lastname)
formData.append('national_id', data.national_id)
formData.append('shenase_melli', data.national_id)
formData.append('tel_number', data.tel_number)
formData.append('mobile_number', data.mobile_number)
formData.append('address', data.address)
formData.append('edare_kol_id', data.edare_kol_id)
formData.append('edare_kol', data.edare_kol_id)
formData.append('edare_shahri_id', data.edare_shahri_id)
formData.append('edare_shahri', data.edare_shahri_id)
formData.append('rah_type_id', data.rah_type_id)
formData.append('rah_type', data.rah_type_id)
formData.append('name_mehvar_id', 1)
formData.append('name_mehvar_fa', data.name_mehvar_fa)
formData.append('mizan_harim', data.mizan_harim)
formData.append('arze_navar', data.arze_navar)
formData.append('samt_id', data.samt_id)
formData.append('samt', data.samt_id)
formData.append('kilometr', data.kilometr)
formData.append('lat', data.lat)
formData.append('lon', data.lon)
formData.append('zone', data.zone)
formData.append('karbari_type_id', data.karbari_type_id)
formData.append('karbari_type', data.karbari_type_id)
formData.append('tarh_title', data.tarh_title)
formData.append('masahat_zirbana', data.masahat_zirbana)
formData.append('ehdasat_type_id', data.ehdasat_type_id.join("|"))
formData.append('ehdasat_type', data.ehdasat_type_id.join("|"))
formData.append('divarkeshi_distance', data.divarkeshi_distance)
formData.append('mostahadesat_distance', data.mostahadesat_distance)
formData.append('mahale_ejra_id', data.mahale_ejra_id)
formData.append('mahale_ejra', data.mahale_ejra)
formData.append('traffic_id', data.traffic_id)
formData.append('traffic', data.traffic_id)
formData.append('vaziat_eghtesadi_id', data.vaziat_eghtesadi_id)
formData.append('vaziat_eghtesadi', data.vaziat_eghtesadi)
formData.append('has_access_id', data.has_access_id)
formData.append('has_access', data.has_access_id)
formData.append('shomare_estelam_harim', data.shomare_estelam_harim)
formData.append('max_month', data.max_month)
formData.append('max_day', data.max_day)
formData.append('shomare_tahaodname', data.shomare_tahaodname)
formData.append('shomare_daftarkhaneh', data.shomare_daftarkhaneh)
formData.append('description', data.description)
formData.append('ronevesht', data.ronevesht)
const formData = new FormData();
formData.append("dabirkhaneh_number", data.dabirkhaneh_number);
formData.append("nameh_date", data.nameh_date.format("YYYY-MM-DD"));
formData.append("nameh_date_fa", data.nameh_date);
formData.append("marjae_pasokh", data.marjae_pasokh);
formData.append("motaghazi_is_legal_id", data.motaghazi_is_legal_id);
formData.append("motaghazi_is_legal", data.motaghazi_is_legal_id);
formData.append("motaghazi_type_id", 1);
formData.append("motaghazi_type", data.motaghazi_type);
formData.append("motaghazi_firstname", data.motaghazi_firstname);
formData.append("motaghazi_lastname", data.motaghazi_lastname);
formData.append("national_id", data.national_id);
formData.append("shenase_melli", data.national_id);
formData.append("tel_number", data.tel_number);
formData.append("mobile_number", data.mobile_number);
formData.append("address", data.address);
formData.append("edare_kol_id", data.edare_kol_id);
formData.append("edare_kol", data.edare_kol_id);
formData.append("edare_shahri_id", data.edare_shahri_id);
formData.append("edare_shahri", data.edare_shahri_id);
formData.append("rah_type_id", data.rah_type_id);
formData.append("rah_type", data.rah_type_id);
formData.append("name_mehvar_id", 1);
formData.append("name_mehvar_fa", data.name_mehvar_fa);
formData.append("mizan_harim", data.mizan_harim);
formData.append("arze_navar", data.arze_navar);
formData.append("samt_id", data.samt_id);
formData.append("samt", data.samt_id);
formData.append("kilometr", data.kilometr);
formData.append("lat", data.lat);
formData.append("lon", data.lon);
formData.append("zone", data.zone);
formData.append("karbari_type_id", data.karbari_type_id);
formData.append("karbari_type", data.karbari_type_id);
formData.append("tarh_title", data.tarh_title);
formData.append("masahat_zirbana", data.masahat_zirbana);
formData.append("ehdasat_type_id", data.ehdasat_type_id.join("|"));
formData.append("ehdasat_type", data.ehdasat_type_id.join("|"));
formData.append("divarkeshi_distance", data.divarkeshi_distance);
formData.append("mostahadesat_distance", data.mostahadesat_distance);
formData.append("mahale_ejra_id", data.mahale_ejra_id);
formData.append("mahale_ejra", data.mahale_ejra);
formData.append("traffic_id", data.traffic_id);
formData.append("traffic", data.traffic_id);
formData.append("vaziat_eghtesadi_id", data.vaziat_eghtesadi_id);
formData.append("vaziat_eghtesadi", data.vaziat_eghtesadi);
formData.append("has_access_id", data.has_access_id);
formData.append("has_access", data.has_access_id);
formData.append("shomare_estelam_harim", data.shomare_estelam_harim);
formData.append("max_month", data.max_month);
formData.append("max_day", data.max_day);
formData.append("shomare_tahaodname", data.shomare_tahaodname);
formData.append("shomare_daftarkhaneh", data.shomare_daftarkhaneh);
formData.append("description", data.description);
formData.append("ronevesht", data.ronevesht);
try {
await request(url, 'post', { data: formData })
handleClose()
mutate()
} catch (error) {
}
await request(url, "post", { data: formData });
handleClose();
mutate();
} catch (error) {}
};
return (
@@ -141,11 +160,18 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
>
<DialogContent>
<Container maxWidth='lg'>
<StyledForm onSubmit={handleSubmit(onSubmit)} id={'InquiryPrivacyFencingCreateForm'}>
<Container maxWidth="lg">
<StyledForm onSubmit={handleSubmit(onSubmit)} id={"InquiryPrivacyFencingCreateForm"}>
<Grid container columns={{ xs: 1, sm: 2, md: 3 }} spacing={4}>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('dabirkhaneh_number')} label="شماره دبیرخانه درخواست *" size="small" fullWidth type="tel" />
<LtrTextField
autoComplete="off"
{...register("dabirkhaneh_number")}
label="شماره دبیرخانه درخواست *"
size="small"
fullWidth
type="tel"
/>
</Grid>
<Grid item xs={1}>
<Controller
@@ -157,14 +183,20 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
onChange={(newValue) => onChange(moment(newValue))}
label="تاریخ نامه درخواست *"
slotProps={{
textField: { fullWidth: true, size: "small", autoComplete: 'off' },
textField: { fullWidth: true, size: "small", autoComplete: "off" },
}}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<TextField autoComplete="off" {...register('marjae_pasokh')} label="مرجع درخواست کننده پاسخ به استعلام" size="small" fullWidth />
<TextField
autoComplete="off"
{...register("marjae_pasokh")}
label="مرجع درخواست کننده پاسخ به استعلام"
size="small"
fullWidth
/>
</Grid>
<Grid item xs={1}>
<Controller
@@ -176,16 +208,22 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["حقوقی", "حقیقی"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="متقاضی *" />}
renderInput={(params) => (
<TextField autoComplete="off" fullWidth {...params} label="متقاضی *" />
)}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Fade in={watch('motaghazi_is_legal_id') === 'حقوقی'} mountOnEnter={true} unmountOnExit={true}>
<Fade
in={watch("motaghazi_is_legal_id") === "حقوقی"}
mountOnEnter={true}
unmountOnExit={true}
>
<Box>
<Controller
name="motaghazi_type"
@@ -196,10 +234,17 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["دولتی", "خصوصی"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="نوع متقاضی *" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="نوع متقاضی *"
/>
)}
/>
)}
/>
@@ -208,26 +253,76 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
</Grid>
<Grid item xs={1}></Grid>
<Grid item xs={1}>
<TextField autoComplete="off" {...register('motaghazi_firstname')} label="نام متقاضی *" size="small" fullWidth />
<TextField
autoComplete="off"
{...register("motaghazi_firstname")}
label="نام متقاضی *"
size="small"
fullWidth
/>
</Grid>
<Grid item xs={1}>
<Fade in={watch('motaghazi_is_legal_id') === 'حقیقی'} mountOnEnter={true} unmountOnExit={true}>
<TextField autoComplete="off" {...register('motaghazi_lastname')} label="نام خانوادگی متقاضی *" size="small" fullWidth />
<Fade
in={watch("motaghazi_is_legal_id") === "حقیقی"}
mountOnEnter={true}
unmountOnExit={true}
>
<TextField
autoComplete="off"
{...register("motaghazi_lastname")}
label="نام خانوادگی متقاضی *"
size="small"
fullWidth
/>
</Fade>
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('national_id')} label="کد ملی/شناسه ملی *" size="small" fullWidth type="tel" />
<LtrTextField
autoComplete="off"
{...register("national_id")}
label="کد ملی/شناسه ملی *"
size="small"
fullWidth
type="tel"
/>
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('tel_number')} label="تلفن" size="small" fullWidth type="tel" />
<LtrTextField
autoComplete="off"
{...register("tel_number")}
label="تلفن"
size="small"
fullWidth
type="tel"
/>
</Grid>
<Grid item xs={1}>
<Fade in={watch('motaghazi_type') !== 'دولتی' || watch('formik.values.motaghazi_is_legal_id') === 'حقیقی'} mountOnEnter={true} unmountOnExit={true}>
<LtrTextField autoComplete="off" {...register('mobile_number')} label="تلفن همراه *" size="small" fullWidth type="tel" />
<Fade
in={
watch("motaghazi_type") !== "دولتی" ||
watch("formik.values.motaghazi_is_legal_id") === "حقیقی"
}
mountOnEnter={true}
unmountOnExit={true}
>
<LtrTextField
autoComplete="off"
{...register("mobile_number")}
label="تلفن همراه *"
size="small"
fullWidth
type="tel"
/>
</Fade>
</Grid>
<Grid item xs={1}>
<TextField autoComplete="off" {...register('address')} label="آدرس *" size="small" fullWidth />
<TextField
autoComplete="off"
{...register("address")}
label="آدرس *"
size="small"
fullWidth
/>
</Grid>
<Grid item xs={1}>
<Controller
@@ -239,11 +334,12 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["تهران"]}
renderInput={(params) => (
<TextField autoComplete="off"
<TextField
autoComplete="off"
fullWidth
{...params}
label="اداره كل راهداری و حمل و نقل جاده ای *"
@@ -263,10 +359,17 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["تهران"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="اداره شهرستان *" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="اداره شهرستان *"
/>
)}
/>
)}
/>
@@ -281,10 +384,12 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["آزاد راه", "بزرگراه", 'راه فرعی درجه 3']}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="نوع راه *" />}
options={["آزاد راه", "بزرگراه", "راه فرعی درجه 3"]}
renderInput={(params) => (
<TextField autoComplete="off" fullWidth {...params} label="نوع راه *" />
)}
/>
)}
/>
@@ -299,16 +404,23 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["سایر"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="نام محور *" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="نام محور *"
/>
)}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Fade in={watch('name_mehvar_fa') === "سایر"} mountOnEnter={true} unmountOnExit={true}>
<Fade in={watch("name_mehvar_fa") === "سایر"} mountOnEnter={true} unmountOnExit={true}>
<TextField autoComplete="off" label="سایر محورها" size="small" fullWidth />
</Fade>
</Grid>
@@ -322,10 +434,12 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["چپ", "راست"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="سمت *" />}
renderInput={(params) => (
<TextField autoComplete="off" fullWidth {...params} label="سمت *" />
)}
/>
)}
/>
@@ -340,16 +454,27 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["12.5", "17.5"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="میزان حریم *" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="میزان حریم *"
/>
)}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Fade in={watch('rah_type_id') !== 'راه فرعی درجه 3'} mountOnEnter={true} unmountOnExit={true}>
<Fade
in={watch("rah_type_id") !== "راه فرعی درجه 3"}
mountOnEnter={true}
unmountOnExit={true}
>
<Box>
<Controller
name="arze_navar"
@@ -360,10 +485,17 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["15", "30"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="عرض نوار تاسیساتی زیربنایی *" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="عرض نوار تاسیساتی زیربنایی *"
/>
)}
/>
)}
/>
@@ -371,15 +503,40 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
</Fade>
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('kilometr')} label="كيلومتر *" size="small" fullWidth type="tel" />
<LtrTextField
autoComplete="off"
{...register("kilometr")}
label="كيلومتر *"
size="small"
fullWidth
type="tel"
/>
</Grid>
<Grid item xs={1} sm={2} sx={{ height: 300 }}>
<LocationOnMap setValue={setValue} defaultLatLon={defaultValues ? [defaultValues.lat, defaultValues.lon] : null} defaultValues />
<LocationOnMap
setValue={setValue}
defaultLatLon={defaultValues ? [defaultValues.lat, defaultValues.lon] : null}
defaultValues
/>
</Grid>
<Grid item xs={1}>
<Stack spacing={3}>
<LtrTextField autoComplete="off" {...register('lat')} label="عرض جغرافیایی" size="small" fullWidth disabled={true} />
<LtrTextField autoComplete="off" {...register('lon')} label="طول جغرافیایی" size="small" fullWidth disabled={true} />
<LtrTextField
autoComplete="off"
{...register("lat")}
label="عرض جغرافیایی"
size="small"
fullWidth
disabled={true}
/>
<LtrTextField
autoComplete="off"
{...register("lon")}
label="طول جغرافیایی"
size="small"
fullWidth
disabled={true}
/>
<Controller
name="zone"
control={control}
@@ -389,10 +546,17 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["38", "39"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="Zone *" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="Zone *"
/>
)}
/>
)}
/>
@@ -408,22 +572,42 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["اتاقک نگهبانی", "دولتی"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="نوع کاربری *" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="نوع کاربری *"
/>
)}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<TextField autoComplete="off" {...register('tarh_title')} label="عنوان طرح *" size="small" fullWidth />
<TextField
autoComplete="off"
{...register("tarh_title")}
label="عنوان طرح *"
size="small"
fullWidth
/>
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('masahat_zirbana')} label="مساحت زیربنا" size="small" fullWidth type="tel" InputProps={{
endAdornment: <InputAdornment position="end">
مترمربع</InputAdornment>,
}} />
<LtrTextField
autoComplete="off"
{...register("masahat_zirbana")}
label="مساحت زیربنا"
size="small"
fullWidth
type="tel"
InputProps={{
endAdornment: <InputAdornment position="end">مترمربع</InputAdornment>,
}}
/>
</Grid>
<Grid item xs={1}>
<Controller
@@ -436,31 +620,60 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
renderTags={(value, getTagProps) =>
value.map((option, index) => {
const { key, ...tagProps } = getTagProps({ index });
return (
<Chip label={option} key={key} size="small" sx={{ '&.MuiAutocomplete-tag': { my: 0 } }} {...tagProps} />
<Chip
label={option}
key={key}
size="small"
sx={{ "&.MuiAutocomplete-tag": { my: 0 } }}
{...tagProps}
/>
);
})
}
options={["تعمیرات", "احداث بنا"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="نوع احداثات *" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="نوع احداثات *"
/>
)}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('divarkeshi_distance')} label="فاصله دیوارکشی از آکس محور" size="small" fullWidth type="tel" InputProps={{
endAdornment: <InputAdornment position="end">متر</InputAdornment>,
}} />
<LtrTextField
autoComplete="off"
{...register("divarkeshi_distance")}
label="فاصله دیوارکشی از آکس محور"
size="small"
fullWidth
type="tel"
InputProps={{
endAdornment: <InputAdornment position="end">متر</InputAdornment>,
}}
/>
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('mostahadesat_distance')} label="فاصله مستحدثات از آکس محور" size="small" fullWidth type="tel" InputProps={{
endAdornment: <InputAdornment position="end">متر</InputAdornment>,
}} />
<LtrTextField
autoComplete="off"
{...register("mostahadesat_distance")}
label="فاصله مستحدثات از آکس محور"
size="small"
fullWidth
type="tel"
InputProps={{
endAdornment: <InputAdornment position="end">متر</InputAdornment>,
}}
/>
</Grid>
<Grid item xs={1}>
<Controller
@@ -472,10 +685,12 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["داخل حریم"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="محل اجرا" />}
renderInput={(params) => (
<TextField autoComplete="off" fullWidth {...params} label="محل اجرا" />
)}
/>
)}
/>
@@ -490,10 +705,17 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["سبک (ضریب ۱)"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="میزان ترافیک *" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="میزان ترافیک *"
/>
)}
/>
)}
/>
@@ -508,10 +730,17 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["تست"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="وضعیت اقتصادی" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="وضعیت اقتصادی"
/>
)}
/>
)}
/>
@@ -526,46 +755,115 @@ const CreateOrUpdateForm = ({ handleClose, mutate, defaultValues, url }) => {
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
onChange(newValue);
}}
options={["بله", "خیر"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="آیا راه دسترسی از قبل وجود دارد؟ *" />}
renderInput={(params) => (
<TextField
autoComplete="off"
fullWidth
{...params}
label="آیا راه دسترسی از قبل وجود دارد؟ *"
/>
)}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('shomare_estelam_harim')} label="شماره استعلام دفتر ایمنی و حریم" size="small" fullWidth type="tel" />
<LtrTextField
autoComplete="off"
{...register("shomare_estelam_harim")}
label="شماره استعلام دفتر ایمنی و حریم"
size="small"
fullWidth
type="tel"
/>
</Grid>
<Grid item xs={1}>
<Stack direction={'row'} spacing={1} alignItems={'center'}>
<Typography sx={{ flex: 2 }} variant="body2">حداکثر مدت زمان شروع عملیات: *</Typography>
<LtrTextField autoComplete="off" {...register('max_month')} sx={{ width: 60 }} label="ماه" size="small" type="tel" />
<LtrTextField autoComplete="off" {...register('max_day')} sx={{ width: 60 }} label="روز" size="small" type="tel" />
<Stack direction={"row"} spacing={1} alignItems={"center"}>
<Typography sx={{ flex: 2 }} variant="body2">
حداکثر مدت زمان شروع عملیات: *
</Typography>
<LtrTextField
autoComplete="off"
{...register("max_month")}
sx={{ width: 60 }}
label="ماه"
size="small"
type="tel"
/>
<LtrTextField
autoComplete="off"
{...register("max_day")}
sx={{ width: 60 }}
label="روز"
size="small"
type="tel"
/>
</Stack>
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('shomare_tahaodname')} label="شماره تعهدنامه" size="small" fullWidth type="tel" />
<LtrTextField
autoComplete="off"
{...register("shomare_tahaodname")}
label="شماره تعهدنامه"
size="small"
fullWidth
type="tel"
/>
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('shomare_daftarkhaneh')} label="شماره دفترخانه" size="small" fullWidth type="tel" />
<LtrTextField
autoComplete="off"
{...register("shomare_daftarkhaneh")}
label="شماره دفترخانه"
size="small"
fullWidth
type="tel"
/>
</Grid>
<Grid item xs={1}></Grid>
<Grid item xs={1}>
<TextField autoComplete="off" {...register('description')} multiline rows={2} label="توضیحات" size="small" fullWidth />
<TextField
autoComplete="off"
{...register("description")}
multiline
rows={2}
label="توضیحات"
size="small"
fullWidth
/>
</Grid>
<Grid item xs={1}>
<TextField autoComplete="off" {...register('ronevesht')} multiline rows={2} label="رونوشت" size="small" fullWidth />
<TextField
autoComplete="off"
{...register("ronevesht")}
multiline
rows={2}
label="رونوشت"
size="small"
fullWidth
/>
</Grid>
<Grid item xs={1}></Grid>
</Grid>
</StyledForm>
</Container>
</DialogContent>
<DialogActions sx={{ p: 2, borderTop: 1, borderColor: 'divider' }}>
<Button variant="contained" size="large" sx={{ width: 150 }} type="submit" form={'InquiryPrivacyFencingCreateForm'} disabled={isSubmitting}>ثبت</Button>
<DialogActions sx={{ p: 2, borderTop: 1, borderColor: "divider" }}>
<Button
variant="contained"
size="large"
sx={{ width: 150 }}
type="submit"
form={"InquiryPrivacyFencingCreateForm"}
disabled={isSubmitting}
>
ثبت
</Button>
</DialogActions>
</LocalizationProvider >
</LocalizationProvider>
);
};
export default CreateOrUpdateForm;

View File

@@ -12,21 +12,26 @@ const MarkerLocation = ({ setValue, defaultLatLon }) => {
const location = useRef();
const map = useMapEvents({
move: (e) => {
const latlon = e.target.getCenter()
const latlon = e.target.getCenter();
location.current?.setLatLng(latlon);
setValue('lat', latlon.lat)
setValue('lon', latlon.lng)
setValue("lat", latlon.lat);
setValue("lon", latlon.lng);
},
zoom: (e) => {
const latlon = e.target.getCenter()
const latlon = e.target.getCenter();
location.current?.setLatLng(latlon);
setValue('lat', latlon.lat)
setValue('lon', latlon.lng)
setValue("lat", latlon.lat);
setValue("lon", latlon.lng);
},
});
return (
<Marker ref={location} icon={locationMarker} position={defaultLatLon ? L.LatLng(defaultLatLon.lat, defaultLatLon.lon) : map.getCenter()} key="location" />
)
}
export default MarkerLocation
<Marker
ref={location}
icon={locationMarker}
position={defaultLatLon ? L.LatLng(defaultLatLon.lat, defaultLatLon.lon) : map.getCenter()}
key="location"
/>
);
};
export default MarkerLocation;

View File

@@ -11,12 +11,12 @@ const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
const LocationOnMap = ({ setValue, defaultLatLon }) => {
return (
<Stack sx={{ height: "100%", position: "relative" }}>
<Paper sx={{ flexGrow: 1, border: 1, borderRadius: 1, borderColor: 'divider' }} elevation={0}>
<MapLayer style={{ borderRadius: '4px' }}>
<Paper sx={{ flexGrow: 1, border: 1, borderRadius: 1, borderColor: "divider" }} elevation={0}>
<MapLayer style={{ borderRadius: "4px" }}>
<MarkerLocation setValue={setValue} defaultLatLon={defaultLatLon} />
</MapLayer>
</Paper>
</Stack>
)
}
export default LocationOnMap
);
};
export default LocationOnMap;

View File

@@ -1,7 +1,6 @@
import InquiryPrivacyFencingCreate from "./Actions/Create";
const Toolbar = ({ mutate }) => {
return (
<>
<InquiryPrivacyFencingCreate mutate={mutate} />

View File

@@ -6,11 +6,10 @@ import { Stack } from "@mui/material";
const InquiryPrivacyFencingPage = () => {
return (
<Stack spacing={2}>
<Stack spacing={1}>
<PageTitle title={"احداث و بهره برداری دیوارکشی و مستحدثات"} />
<InquiryPrivacyFencingList />
</Stack>
);
};
export default InquiryPrivacyFencingPage;

View File

@@ -231,12 +231,12 @@ const InquiryPrivacyFencingList = () => {
enableColumnFilter: false,
},
],
[],
[]
);
return (
<>
<Box sx={{ p: 2, border: 1, borderColor: 'divider', borderRadius: 1 }}>
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
<DataTable
table_title={"لیست استعلام ها"}
need_filter={false}
@@ -252,4 +252,3 @@ const InquiryPrivacyFencingList = () => {
);
};
export default InquiryPrivacyFencingList;

View File

@@ -0,0 +1,162 @@
"use client";
import {Marker, useMapEvents} from "react-leaflet";
import {useEffect, useRef} from "react";
import L from "leaflet";
import TestIcon from "@/assets/images/examine_marker.png";
import TestActiveIcon from "@/assets/images/examine_marker_active.png";
import {
Box,
Button,
FormControl,
InputAdornment,
InputLabel,
OutlinedInput,
Stack,
Tooltip,
useMediaQuery
} from "@mui/material";
import NewReleasesIcon from '@mui/icons-material/NewReleases';
import VerifiedIcon from '@mui/icons-material/Verified';
import EditIcon from '@mui/icons-material/Edit';
import {useTheme} from "@emotion/react";
const ChooseLocation = ({mapBoxData, setMapBoxData}) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
const mapTestMarker = 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) {
if (!mapBoxData) {
mapTestMarker.current.setLatLng(e.target.getCenter());
}
},
movestart() {
if (!mapBoxData) {
mapTestMarker.current.setIcon(createCustomIcon([45, 45], TestIcon.src));
}
},
moveend() {
if (!mapBoxData) {
mapTestMarker.current.setIcon(createCustomIcon(defaultIconSize, TestIcon.src));
}
}
});
useEffect(() => {
if (mapTestMarker.current) {
const newIcon = mapBoxData
? createCustomIcon([45, 45], TestActiveIcon.src)
: createCustomIcon(defaultIconSize, TestIcon.src);
mapTestMarker.current.setIcon(newIcon);
}
if (mapBoxData) {
mapTestMarker.current.setLatLng(mapBoxData);
map.flyTo(mapBoxData, 14);
}
}, [mapBoxData]);
const handleMarkerClick = () => {
if (!mapBoxData) {
setMapBoxData({lat: mapTestMarker.current.getLatLng().lat, lng: mapTestMarker.current.getLatLng().lng});
}
};
const handleEditLocation = () => {
setMapBoxData(null);
}
return (
<>
<Marker
position={map.getCenter()}
ref={mapTestMarker}
eventHandlers={{click: handleMarkerClick}}
icon={createCustomIcon(defaultIconSize, TestIcon.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: "10px",
right: isMobile ? "10px" : "",
}}>
<Stack sx={{gap: 2}}>
<Tooltip title="با کلیک بر روی مارکر، محل آزمایش را انتخاب کنید" arrow>
<FormControl size="small" variant="outlined">
<InputLabel sx={{color: mapBoxData ? "success.main" : ""}} htmlFor="lat">
طول جغرافیایی
</InputLabel>
<OutlinedInput
id="lat"
type="text"
size="small"
readOnly
sx={{
'& .MuiOutlinedInput-notchedOutline': {
borderColor: mapBoxData ? "success.main" : "",
},
color: mapBoxData ? "success.main" : ""
}}
value={mapBoxData ? `${mapBoxData.lat}` : ""}
endAdornment={
<InputAdornment position="end">
{mapBoxData ? <VerifiedIcon color="success"/> :
<NewReleasesIcon color="error"/>}
</InputAdornment>
}
label="طول جغرافیایی"
/>
</FormControl>
</Tooltip>
<Tooltip title="با کلیک بر روی مارکر، محل آزمایش را انتخاب کنید" arrow>
<FormControl size="small" variant="outlined">
<InputLabel sx={{color: mapBoxData ? "success.main" : ""}} htmlFor="lng">
عرض جغرافیایی
</InputLabel>
<OutlinedInput
id="lng"
type="text"
size="small"
readOnly
sx={{
'& .MuiOutlinedInput-notchedOutline': {
borderColor: mapBoxData ? "success.main" : "",
},
color: mapBoxData ? "success.main" : ""
}}
value={mapBoxData ? `${mapBoxData.lng}` : ""}
endAdornment={
<InputAdornment position="end">
{mapBoxData ? <VerifiedIcon color="success"/> :
<NewReleasesIcon color="error"/>}
</InputAdornment>
}
label="عرض جغرافیایی"
/>
</FormControl>
</Tooltip>
<Button variant="contained" color="primary" disabled={!mapBoxData} startIcon={<EditIcon/>}
onClick={handleEditLocation}>ویرایش مختصات</Button>
</Stack>
</Box>
</>
);
};
export default ChooseLocation;

View File

@@ -0,0 +1,59 @@
"use client";
import {Box, Typography} from "@mui/material";
import TextSnippetIcon from '@mui/icons-material/TextSnippet';
import TravelExploreIcon from '@mui/icons-material/TravelExplore';
import {
Timeline,
TimelineConnector,
TimelineContent,
TimelineDot,
TimelineItem,
timelineItemClasses,
TimelineSeparator
} from "@mui/lab";
const CreateTimeLine = ({tabState}) => {
return (
<Box sx={{display: "flex", alignItems: "center"}}>
<Timeline position="right" sx={{
[`& .${timelineItemClasses.root}:before`]: {flex: 0, padding: 0}
}}>
<TimelineItem>
<TimelineSeparator>
<TimelineConnector/>
<TimelineDot sx={{backgroundColor: "#fff"}}>
<TravelExploreIcon color={tabState === 0 ? "primary" : "error"}
sx={{width: "1.5rem", height: "1.5rem"}}/>
</TimelineDot>
<TimelineConnector/>
</TimelineSeparator>
<TimelineContent sx={{py: '12px', px: 2}}>
<Typography variant="h6">
نقشه
</Typography>
<Typography variant="caption" sx={{color: "#606060"}}>ثبت مختصات محل
آزمایش</Typography>
</TimelineContent>
</TimelineItem>
<TimelineItem>
<TimelineSeparator>
<TimelineConnector/>
<TimelineDot sx={{backgroundColor: "#fff"}}>
<TextSnippetIcon color={tabState === 1 ? "primary" : "error"}
sx={{width: "1.5rem", height: "1.5rem"}}/>
</TimelineDot>
<TimelineConnector/>
</TimelineSeparator>
<TimelineContent sx={{py: '12px', px: 2}}>
<Typography variant="h6">
مشخصات آزمایش
</Typography>
<Typography variant="caption" sx={{color: "#606060"}}>ثبت مشخصات اولیه</Typography>
</TimelineContent>
</TimelineItem>
</Timeline>
</Box>
);
};
export default CreateTimeLine;

View File

@@ -0,0 +1,39 @@
"use client";
import {Box, Stack} from "@mui/material";
import dynamic from "next/dynamic";
import MapLoading from "@/core/components/MapLayer/Loading";
import ChooseLocation from "./ChooseLocation";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading/>,
ssr: false,
});
const MapBox = ({mapBoxData, setMapBoxData}) => {
return (
<Stack spacing={1} sx={{height: "500px"}}>
<Box sx={{
p: 1,
border: "1px dashed",
borderColor: "divider",
borderRadius: 1,
height: "100%"
}}>
<Box
sx={{
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<MapLayer>
<ChooseLocation mapBoxData={mapBoxData} setMapBoxData={setMapBoxData}/>
</MapLayer>
</Box>
</Box>
</Stack>
);
};
export default MapBox;

View File

@@ -0,0 +1,387 @@
"use client";
import {Controller} from "react-hook-form";
import {
Autocomplete,
CircularProgress,
FormControl,
FormHelperText,
Grid,
IconButton,
InputAdornment,
InputLabel,
OutlinedInput,
TextField,
Typography
} from "@mui/material";
import useTest from "@/lib/hooks/useTest";
import useProvinces from "@/lib/hooks/useProvince";
import {LocalizationProvider, MobileDatePicker} from "@mui/x-date-pickers";
import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali";
import {faIR} from "@mui/x-date-pickers/locales";
import ClearIcon from "@mui/icons-material/Clear";
import React from "react";
const TestGeneralInfo = ({control, register, setValue, errors}) => {
const {tests, errorTests, loadingTests} = useTest();
const {provinces, errorProvinces, loadingProvinces} = useProvinces();
return (
<Grid container spacing={2}>
<Grid item xs={12} md={6}
sx={{display: "flex", alignItems: "center", justifyContent: "center"}}>
<Controller
name="azmayesh_type_id"
control={control}
render={({field: {onChange, value}, fieldState: {error}}) => (
<FormControl error={!!errors.azmayesh_type_id} size="small" fullWidth
variant="outlined">
<InputLabel htmlFor="azmayesh_type_id"/>
{errorTests ? (
<Typography color={"red"}
sx={{display: "flex", alignItems: "center", gap: 2}}>
خطایی در دریافت لیست آزمایش ها رخ داده است!
</Typography>
) : loadingTests ? (
<Typography sx={{display: "flex", alignItems: "center", gap: 2}}>
<CircularProgress size={20}/>
درحال دریافت لیست آزمایش ها
</Typography>
) : (
<Autocomplete
id="azmayesh_type_id"
size="small"
value={tests.find((test) => test.id === value) || null}
disablePortal
options={tests}
getOptionLabel={(test) => test.name}
isOptionEqualToValue={(option, value) => option.id === value?.id}
onChange={(event, newValue) => {
onChange(newValue ? newValue.id : "");
setValue("azmayesh_type_name", newValue ? newValue.name : "");
}}
renderInput={(params) => (
<TextField
{...params}
autoComplete="off"
error={!!errors.azmayesh_type_id}
fullWidth
label="نوع آزمایش"
/>
)}
/>
)}
<FormHelperText id="azmayesh_type_id">
{errors.azmayesh_type_id ? errors.azmayesh_type_id.message : null}
</FormHelperText>
</FormControl>
)}
/>
</Grid>
<Grid item xs={12} md={6}
sx={{display: "flex", alignItems: "center", justifyContent: "center"}}>
<Controller
name="province_id"
control={control}
render={({field: {onChange, value}, fieldState: {error}}) => (
<FormControl error={!!errors.province_id} size="small" fullWidth
variant="outlined">
<InputLabel htmlFor="province_id"/>
{errorProvinces ? (
<Typography color={"red"}
sx={{display: "flex", alignItems: "center", gap: 2}}>
خطایی در دریافت لیست استان ها رخ داده است!
</Typography>
) : loadingProvinces ? (
<Typography sx={{display: "flex", alignItems: "center", gap: 2}}>
<CircularProgress size={20}/>
درحال دریافت لیست استان ها
</Typography>
) : (
<Autocomplete
id="province_id"
size="small"
value={provinces.find((province) => province.id === value) || null}
disablePortal
options={provinces}
getOptionLabel={(province) => province.name}
isOptionEqualToValue={(option, value) => option.id === value?.id}
onChange={(event, newValue) => {
onChange(newValue ? newValue.id : "");
setValue("province_name", newValue ? newValue.name : "");
}}
renderInput={(params) => (
<TextField
{...params}
autoComplete="off"
error={!!errors.province_id}
fullWidth
label="استان"
/>
)}
/>
)}
<FormHelperText id="province_id">
{errors.province_id ? errors.province_id.message : null}
</FormHelperText>
</FormControl>
)}
/>
</Grid>
<Grid item xs={12} md={6}>
<FormControl error={!!errors.project_name} size="small" fullWidth
variant="outlined">
<InputLabel htmlFor="project_name">
پروژه
</InputLabel>
<OutlinedInput
id="project_name"
label={"پروژه"}
autoComplete="off"
{...register("project_name")}
size="small"
fullWidth
type="text"
/>
<FormHelperText id="project_name">
{errors.project_name ? errors.project_name.message : null}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} md={6}>
<FormControl error={!!errors.employer} size="small" fullWidth variant="outlined">
<InputLabel htmlFor="employer">
کارفرما
</InputLabel>
<OutlinedInput
id="employer"
label={"کارفرما"}
autoComplete="off"
{...register("employer")}
size="small"
fullWidth
type="text"
/>
<FormHelperText id="employer">
{errors.employer ? errors.employer.message : null}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} md={6}>
<FormControl error={!!errors.consultant} size="small" fullWidth variant="outlined">
<InputLabel htmlFor="consultant">
مشاور
</InputLabel>
<OutlinedInput
id="consultant"
label={"مشاور"}
autoComplete="off"
{...register("consultant")}
size="small"
fullWidth
type="text"
/>
<FormHelperText id="consultant">
{errors.consultant ? errors.consultant.message : null}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} md={6}>
<FormControl error={!!errors.contractor} size="small" fullWidth variant="outlined">
<InputLabel htmlFor="contractor">
پیمانکار
</InputLabel>
<OutlinedInput
id="contractor"
label={"پیمانکار"}
autoComplete="off"
{...register("contractor")}
size="small"
fullWidth
type="text"
/>
<FormHelperText id="contractor">
{errors.contractor ? errors.contractor.message : null}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} md={6}>
<FormControl error={!!errors.applicant} size="small" fullWidth variant="outlined">
<InputLabel htmlFor="applicant">
متقاضی
</InputLabel>
<OutlinedInput
id="applicant"
label={"متقاضی"}
autoComplete="off"
{...register("applicant")}
size="small"
fullWidth
type="text"
/>
<FormHelperText id="applicant">
{errors.applicant ? errors.applicant.message : null}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} md={6}>
<FormControl error={!!errors.work_number} size="small" fullWidth variant="outlined">
<InputLabel htmlFor="work_number">
شماره کار
</InputLabel>
<OutlinedInput
id="work_number"
label={"شماره کار"}
autoComplete="off"
{...register("work_number")}
size="small"
fullWidth
type="text"
/>
<FormHelperText id="work_number">
{errors.work_number ? errors.work_number.message : null}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} md={6}>
<FormControl error={!!errors.request_number} size="small" fullWidth
variant="outlined">
<InputLabel htmlFor="request_number">
شماره درخواست
</InputLabel>
<OutlinedInput
id="request_number"
label={"شماره درخواست"}
autoComplete="off"
{...register("request_number")}
size="small"
fullWidth
type="text"
/>
<FormHelperText id="request_number">
{errors.request_number ? errors.request_number.message : null}
</FormHelperText>
</FormControl>
</Grid>
<Grid item xs={12} md={6}>
<Controller
name="request_date"
control={control}
defaultValue={new Date()}
render={({field: {onChange, value}, fieldState: {error}}) => (
<FormControl
error={!!errors.request_date}
fullWidth
size="small"
variant="outlined"
>
<LocalizationProvider
dateAdapter={AdapterDateFnsJalali}
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
>
<MobileDatePicker
value={value || null}
onChange={(newValue) => {
onChange(newValue);
}}
slotProps={{
textField: {
size: "small",
error: !!errors.request_date,
placeholder: "تاریخ درخواست",
InputProps: {
endAdornment: (
<InputAdornment position="end">
<IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
setValue("request_date", "");
}}
sx={{
color: "#bfbfbf",
"&:hover": {
backgroundColor: "rgba(189, 189, 189, 0.1)",
color: "#363434",
},
}}
>
<ClearIcon/>
</IconButton>
</InputAdornment>
),
},
},
}}
/>
</LocalizationProvider>
<FormHelperText id="request_date">
{errors.request_date ? errors.request_date.message : null}
</FormHelperText>
</FormControl>
)}
/>
</Grid>
<Grid item xs={12} md={6}>
<Controller
name="report_date"
control={control}
defaultValue={new Date()}
render={({field: {onChange, value}, fieldState: {error}}) => (
<FormControl
error={!!errors.report_date}
fullWidth
size="small"
variant="outlined"
>
<LocalizationProvider
dateAdapter={AdapterDateFnsJalali}
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
>
<MobileDatePicker
value={value || null}
onChange={(newValue) => {
onChange(newValue);
}}
slotProps={{
textField: {
size: "small",
error: !!errors.report_date,
placeholder: "تاریخ گزارش",
InputProps: {
endAdornment: (
<InputAdornment position="end">
<IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
setValue("report_date", "");
}}
sx={{
color: "#bfbfbf",
"&:hover": {
backgroundColor: "rgba(189, 189, 189, 0.1)",
color: "#363434",
},
}}
>
<ClearIcon/>
</IconButton>
</InputAdornment>
),
},
},
}}
/>
</LocalizationProvider>
<FormHelperText id="report_date">
{errors.report_date ? errors.report_date.message : null}
</FormHelperText>
</FormControl>
)}
/>
</Grid>
</Grid>
);
};
export default TestGeneralInfo;

View File

@@ -0,0 +1,187 @@
"use client";
import {Box, Button, Dialog, DialogActions, DialogContent, Tab, Tabs, useMediaQuery} from "@mui/material";
import {useTheme} from "@emotion/react";
import React, {useState} from "react";
import MapBox from "./MapBox";
import TravelExploreIcon from '@mui/icons-material/TravelExplore';
import TextSnippetIcon from '@mui/icons-material/TextSnippet';
import KeyboardDoubleArrowRightIcon from '@mui/icons-material/KeyboardDoubleArrowRight';
import KeyboardDoubleArrowLeftIcon from '@mui/icons-material/KeyboardDoubleArrowLeft';
import ExitToAppIcon from '@mui/icons-material/ExitToApp';
import BeenhereIcon from '@mui/icons-material/Beenhere';
import CreateTimeLine from "./CreateTimeLine";
import {useForm} from "react-hook-form";
import StyledForm from "@/core/components/StyledForm";
import {object, string} from "yup";
import useRequest from "@/lib/hooks/useRequest";
import {yupResolver} from "@hookform/resolvers/yup";
import moment from "jalali-moment";
import {POST_TEST} from "@/core/utils/routes";
import TestGeneralInfo from "@/components/dashboard/test/Actions/create/CreateDialog/TestGeneralInfo";
function TabPanel(props) {
const {children, value, index} = props;
return (
<div
role="tabpanel"
hidden={value !== index}
>
{value === index && (
<Box>
{children}
</Box>
)}
</div>
);
}
const CreateDialog = ({open, setOpen}) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
const [tabState, setTabState] = useState(0);
const [mapBoxData, setMapBoxData] = useState(null);
const handleClose = () => {
setOpen(false);
};
const handleChangeTab = (event, newValue) => {
setTabState(newValue);
};
const handlePrev = () => {
if (tabState === 0) {
handleClose();
} else {
setTabState(tabState - 1)
}
};
const validationSchema = object({
azmayesh_type_id: string().required("نوع آزمایش را مشخص کنید!"),
province_id: string().required("استان را وارد کنید!"),
project_name: string().required("عنوان پروژه را وارد کنید!"),
employer: string().required("کارفرما را وارد کنید!"),
consultant: string().required("مشاور را وارد کنید!"),
contractor: string().required("پیمانکار را وارد کنید!"),
applicant: string().required("متقاضی را وارد کنید!"),
work_number: string().required("شماره کار را وارد کنید!"),
request_number: string().required("شماره درخواست را وارد کنید!"),
request_date: string().required("تاریخ درخواست را وارد کنید!"),
report_date: string().required("تاریخ گزارش را وارد کنید!"),
});
const requestServer = useRequest({auth: true});
const defaultValues = {
azmayesh_type_id: "",
azmayesh_type_name: "",
province_id: "",
province_name: "",
project_name: "",
employer: "",
consultant: "",
contractor: "",
applicant: "",
work_number: "",
request_number: "",
request_date: "",
report_date: "",
};
const {
control,
register,
handleSubmit,
setValue,
formState: {isSubmitting, errors, touchedFields},
} = useForm({defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur"});
const onSubmit = async (data) => {
console.log("data", data);
const formData = new FormData();
formData.append("lat", mapBoxData.lat);
formData.append("lng", mapBoxData.lng);
formData.append("azmayesh_type_id", data.azmayesh_type_id);
formData.append("azmayesh_type_name", data.azmayesh_type_name);
formData.append("province_id", data.province_id);
formData.append("province_name", data.province_name);
formData.append("project_name", data.project_name);
formData.append("employer", data.employer);
formData.append("consultant", data.consultant);
formData.append("contractor", data.contractor);
formData.append("applicant", data.applicant);
formData.append("work_number", data.work_number);
formData.append("request_number", data.request_number);
formData.append("request_date", moment(data.request_date).format("YYYY-MM-DD"));
formData.append("report_date", moment(data.report_date).format("YYYY-MM-DD"));
for (var pair of formData.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
requestServer(POST_TEST, "post", {
data: formData,
})
.then(() => {
handleClose();
})
.catch(() => {
});
};
return (
<Dialog open={open} fullWidth={true} maxWidth={"lg"}>
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<Tabs allowScrollButtonsMobile value={tabState} onChange={handleChangeTab}
variant={`${isMobile ? "scrollable" : "fullWidth"}`}
sx={{
display: "flex",
justifyContent: "space-around",
width: "100%",
backgroundColor: "#efefef"
}}>
<Tab icon={<TravelExploreIcon/>} label="انتخاب محل آزمایش"></Tab>
<Tab disabled={!mapBoxData} icon={<TextSnippetIcon/>} label="مشخصات آزمایش"></Tab>
</Tabs>
<DialogContent dividers sx={{display: "flex"}}>
<Box sx={{flex: 1}}>
<TabPanel value={tabState} index={0}>
<MapBox mapBoxData={mapBoxData} setMapBoxData={setMapBoxData}/>
</TabPanel>
<TabPanel value={tabState} index={1}>
<TestGeneralInfo control={control} register={register} setValue={setValue} errors={errors}/>
</TabPanel>
</Box>
{!isMobile && (
<Box sx={{display: "flex", alignItems: "center"}}>
<CreateTimeLine tabState={tabState}/>
</Box>
)}
</DialogContent>
<DialogActions sx={{alignItems: "center", justifyContent: "center"}}>
<Button onClick={handlePrev} variant="outlined" color="error" size="large"
startIcon={tabState === 0 ? <ExitToAppIcon/> : <KeyboardDoubleArrowRightIcon/>}>
{tabState === 0 ? "بستن" : "مرحله قبل"}
</Button>
{
tabState === 0 ? <Button onClick={() => setTabState(tabState + 1)} variant="contained"
size="large"
disabled={!mapBoxData}
endIcon={<KeyboardDoubleArrowLeftIcon/>}>
مرحله بعد
</Button> : <Button variant="contained"
size="large"
disabled={isSubmitting}
type={"submit"}
endIcon={<BeenhereIcon/>}>
{isSubmitting ? "در حال ثبت آزمایش" : "ثبت آزمایش"}
</Button>
}
</DialogActions>
</StyledForm>
</Dialog>
);
};
export default CreateDialog;

View File

@@ -0,0 +1,33 @@
"use client";
import {Button, IconButton, useMediaQuery} from "@mui/material";
import {useTheme} from "@emotion/react";
import {useState} from "react";
import {AddCircle} from "@mui/icons-material";
import CreateDialog from "./CreateDialog";
const TestCreate = () => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
const [open, setOpen] = useState(false);
const handleOpen = () => {
setOpen(true);
};
return (
<>
{isMobile ? (
<IconButton aria-label="ایجاد آزمایش جدید" color="primary" onClick={handleOpen}>
<AddCircle sx={{fontSize: "25px"}}/>
</IconButton>
) : (
<Button variant="contained" color="primary" startIcon={<AddCircle/>} onClick={handleOpen}>
ثبت آزمایش
</Button>
)}
{open && <CreateDialog open={open} setOpen={setOpen}/>}
</>
);
};
export default TestCreate;

View File

@@ -0,0 +1,105 @@
"use client";
import {Marker, useMap} from "react-leaflet";
import {useEffect, useRef} from "react";
import L from "leaflet";
import TestActiveIcon 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 = ({lat, lng}) => {
const map = useMap();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
const mapTestMarker = 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]]
});
};
useEffect(() => {
map.flyTo({lat: lat, lng: lng}, 14);
}, []);
return (
<>
<Marker
position={{lat: lat, lng: lng}}
ref={mapTestMarker}
icon={createCustomIcon(defaultIconSize, TestActiveIcon.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: "10px",
right: isMobile ? "10px" : "",
}}>
<Stack sx={{gap: 2}}>
<FormControl size="small" variant="outlined">
<InputLabel sx={{color: "success.main"}} htmlFor="lat">
طول جغرافیایی
</InputLabel>
<OutlinedInput
id="lat"
type="text"
size="small"
readOnly
sx={{
'& .MuiOutlinedInput-notchedOutline': {
borderColor: "success.main",
},
color: "success.main"
}}
value={lat}
endAdornment={
<InputAdornment position="end">
<VerifiedIcon color="success"/>
</InputAdornment>
}
label="طول جغرافیایی"
/>
</FormControl>
<FormControl size="small" variant="outlined">
<InputLabel sx={{color: "success.main"}} htmlFor="lng">
عرض جغرافیایی
</InputLabel>
<OutlinedInput
id="lng"
type="text"
size="small"
readOnly
sx={{
'& .MuiOutlinedInput-notchedOutline': {
borderColor: "success.main",
},
color: "success.main"
}}
value={lng}
endAdornment={
<InputAdornment position="end">
<VerifiedIcon color="success"/>
</InputAdornment>
}
label="عرض جغرافیایی"
/>
</FormControl>
</Stack>
</Box>
</>
);
};
export default ShowLocationMarker;

View File

@@ -0,0 +1,50 @@
"use client";
import ExploreIcon from "@mui/icons-material/Explore";
import {Box, Button, Dialog, DialogActions, DialogContent, IconButton} from "@mui/material";
import {useState} from "react";
import dynamic from "next/dynamic";
import MapLoading from "@/core/components/MapLayer/Loading";
import ShowLocationMarker from "./ShowLocationMarker";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading/>,
ssr: false,
});
const ShowLocation = ({lat, lng}) => {
const [openShowLocationModal, setOpenShowLocationModal] = useState(false);
const handleOpenShowLocationModal = () => {
setOpenShowLocationModal(true);
};
const handleCloseShowLocationModal = () => {
setOpenShowLocationModal(false);
};
return (
<Box sx={{display: "flex", justifyContent: "center"}}>
<IconButton onClick={handleOpenShowLocationModal} size="small" color="primary"><ExploreIcon/></IconButton>
<Dialog
open={openShowLocationModal}
onClose={handleCloseShowLocationModal}
aria-labelledby="responsive-dialog-title"
>
<DialogContent>
<Box sx={{width: "400px", height: "400px"}}>
<MapLayer>
<ShowLocationMarker lat={lat} lng={lng}/>
</MapLayer>
</Box>
</DialogContent>
<DialogActions>
<Button color="error" variant="outlined" onClick={handleCloseShowLocationModal}>
بستن
</Button>
</DialogActions>
</Dialog>
</Box>
);
};
export default ShowLocation;

View File

@@ -0,0 +1,135 @@
"use client";
import {useMemo} from "react";
import {Box, Typography} from "@mui/material";
import DataTableWithAuth from "@/core/components/DataTableWithAuth";
import Toolbar from "./Toolbar";
import {GET_AZMAYESH_LIST} from "@/core/utils/routes";
import moment from "jalali-moment";
import ShowLocation from "./ShowLocation";
const TestList = () => {
const columns = useMemo(
() => [
{
accessorKey: "id",
header: "کد یکتا",
id: "id",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
},
{
accessorKey: "azmayesh_type_name",
header: "نوع آزمایش",
id: "azmayesh_type_name",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
},
{
accessorKey: "project_name",
header: "پروژه",
id: "project_name",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "lat",
header: "نمایش مختصات",
id: "lat",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
Cell: ({row}) => (<ShowLocation lat={row.original.lat} lng={row.original.lng}/>),
},
{
accessorKey: "employer",
header: "کارفرما",
id: "employer",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "consultant",
header: "مشاور",
id: "consultant",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "contractor",
header: "پیمانکار",
id: "contractor",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "applicant",
header: "متقاضی",
id: "applicant",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "work_number",
header: "شماره کار",
id: "work_number",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "request_number",
header: "شماره درخواست",
id: "request_number",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
},
{
accessorKey: "request_date",
header: "تاریخ درخواست",
id: "request_date",
enableColumnFilter: false,
datatype: "date",
filterFn: "equals",
Cell: ({renderedCellValue}) => (<Typography
variant="body2">{moment(renderedCellValue).locale("fa").format("YYYY/MM/DD")}</Typography>),
},
{
accessorKey: "report_date",
header: "تاریخ گزارش",
id: "report_date",
enableColumnFilter: false,
datatype: "date",
filterFn: "equals",
Cell: ({renderedCellValue}) => (<Typography
variant="body2">{moment(renderedCellValue).locale("fa").format("YYYY/MM/DD")}</Typography>),
},
],
[]
);
return (
<>
<Box sx={{p: 1, border: 1, borderColor: "divider", borderRadius: 1}}>
<DataTableWithAuth
table_title={"لیست آزمایش ها"}
need_filter={false}
columns={columns}
table_url={GET_AZMAYESH_LIST}
page_name={"azmayesh"}
table_name={"azmayeshList"}
TableToolbar={Toolbar}
/>
</Box>
</>
);
};
export default TestList;

View File

@@ -0,0 +1,10 @@
import TestCreate from "./Actions/Create";
const Toolbar = ({mutate}) => {
return (
<>
<TestCreate mutate={mutate}/>
</>
);
};
export default Toolbar;

View File

@@ -0,0 +1,15 @@
"use client";
import PageTitle from "@/core/components/PageTitle";
import {Stack} from "@mui/material";
import TestList from "./TestList";
const TestPage = () => {
return (
<Stack spacing={1}>
<PageTitle title={"آزمایشات"}/>
<TestList/>
</Stack>
);
};
export default TestPage;

View File

@@ -15,9 +15,9 @@ const HeaderBottom = () => {
alignItems={"center"}
direction={"row"}
>
<Image alt="" priority src={RmsLogo.src} width={65} height={71} />
<Image alt="" priority src={RmsLogo.src} width={50} height={54} />
<Stack alignItems={"center"} spacing={1}>
<Typography variant="h5" sx={{ color: (theme) => theme.palette.primary2.contrastText }}>
<Typography variant="h6" sx={{ color: (theme) => theme.palette.primary2.contrastText }}>
سامانه جامع راهداری
</Typography>
<Typography sx={{ color: (theme) => theme.palette.primary2.contrastText }}>rms.rmto.ir</Typography>

View File

@@ -5,7 +5,7 @@ import HeaderLogo from "@/assets/images/headerLogo.png";
const HeaderTop = () => {
return (
<Stack sx={{ p: 2 }}>
<Image alt="" priority src={HeaderLogo.src} width={190} height={44} />
<Image alt="" priority src={HeaderLogo.src} width={140} height={32} />
</Stack>
);
};

View File

@@ -4,7 +4,7 @@ import HeaderBottom from "./HaederBottom";
const HeaderWithLogo = () => {
return (
<Stack sx={{ width: '100%', position: 'fixed', zIndex: 1200, background: '#fff' }}>
<Stack sx={{ width: "100%", position: "fixed", zIndex: 1200, background: "#fff" }}>
<HeaderTop />
<HeaderBottom />
</Stack>

View File

@@ -1,4 +1,45 @@
const HeaderMenu = () => {
return <>منو</>;
import { ExpandLess, ExpandMore, Link } from "@mui/icons-material";
import { Button, Divider, ListItemIcon, ListItemText, Menu, MenuItem } from "@mui/material";
import NextLink from "next/link";
import { useState } from "react";
const HeaderMenu = ({ menu }) => {
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<>
<Button
color="inherit"
aria-haspopup="true"
aria-expanded={open ? "true" : undefined}
onClick={handleClick}
endIcon={open ? <ExpandLess /> : <ExpandMore />}
>
{menu.title}
</Button>
<Menu anchorEl={anchorEl} open={open} onClose={handleClose}>
{menu.subMenu.flatMap((subMenu, index) => [
...subMenu.map((sub) => (
<MenuItem component={NextLink} href={sub.href} key={sub.title} onClick={handleClose}>
<ListItemIcon>
<Link fontSize="small" />
</ListItemIcon>
<ListItemText>{sub.title}</ListItemText>
</MenuItem>
)),
index < menu.subMenu.length - 1 && <Divider key={`divider-${index}`} />,
])}
</Menu>
</>
);
};
export default HeaderMenu;

View File

@@ -0,0 +1,19 @@
import { getValueByPath } from "@/core/utils/getValueByPath";
import { useSidebarBadge } from "@/lib/hooks/useSidebarBadge";
import { Chip } from "@mui/material";
import { useEffect, useState } from "react";
const SidebarBadge = ({ badge, chipProps = {} }) => {
const { data } = useSidebarBadge();
const [value, setValue] = useState();
useEffect(() => {
setValue(getValueByPath(data, badge));
}, [data, badge]);
if (!data) return null;
if (!value) return null;
return <Chip label={value.toLocaleString("fa-IR")} size="small" {...chipProps} />;
};
export default SidebarBadge;

View File

@@ -1,14 +1,15 @@
import SidebarSubitems from "@/core/components/SidebarSubitems";
import { ExpandLess, ExpandMore } from "@mui/icons-material";
import { Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from "@mui/material";
import { Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Stack } from "@mui/material";
import Link from "next/link";
import SidebarBadge from "./SidebarBadge";
import SidebarSubitems from "./SidebarSubitems";
const SidebarListItems = ({ menuItem, dispatch }) => {
return (
<>
<ListItem disablePadding divider>
<ListItemButton
sx={{ py: 1, px: 0.5 }}
sx={{ p: 0.5 }}
disableGutters
selected={menuItem.selected}
component={menuItem.type === "page" ? Link : null}
@@ -29,6 +30,13 @@ const SidebarListItems = ({ menuItem, dispatch }) => {
{menuItem.icon}
</ListItemIcon>
<ListItemText primary={menuItem.label} />
{menuItem.badges && (
<Stack direction={"row"} sx={{ px: 0.5 }} spacing={0.5}>
{menuItem.badges.map((badge, i) => (
<SidebarBadge chipProps={{ color: "primary" }} key={i} badge={badge} />
))}
</Stack>
)}
{menuItem.hasSubitems ? menuItem.showSubitems ? <ExpandLess /> : <ExpandMore /> : null}
</ListItemButton>
</ListItem>

View File

@@ -1,11 +1,12 @@
"use client";
import SidebarListItems from "@/core/components/SidebarListItems";
import { usePermissions } from "@/lib/hooks/usePermissions";
import { List } from "@mui/material";
import { usePathname } from "next/navigation";
import { useEffect, useReducer, useState } from "react";
import { filterMenuItems } from "../utils/filterMenuItems";
import { pageMenu } from "../utils/pageMenu";
import Profile from "@/core/components/Profile";
import { filterMenuItems } from "@/core/utils/filterMenuItems";
import { pageMenu } from "@/core/utils/pageMenu";
import SidebarListItems from "./SidebarListItems";
function selectPage(item, route) {
if (item.type === "page") {
@@ -25,60 +26,46 @@ function selectPage(item, route) {
return item;
}
function toggleSubitems(items, actionId) {
return items.map((item) =>
actionId === item.id ? { ...item, showSubitems: !item.showSubitems } : { ...item, showSubitems: false }
);
}
function reducer(state, action) {
switch (action.type) {
case "UPDATE_MENU":
const _permissions = action.permissions || [];
const filteredPageMenu = filterMenuItems(state, ["all", ..._permissions]);
return filteredPageMenu;
return filterMenuItems(state, ["all", ..._permissions]);
case "COLLAPSE_MENU":
return state.map((item) =>
action.id == item.id
? {
...item,
showSubitems: !item.showSubitems,
}
: item
);
return state.map((item) => ({
...item,
showSubitems: item.id === action.id ? !item.showSubitems : false,
}));
case "COLLAPSE_SUB_ITEMS":
return state.map((item) => {
return item.hasSubitems
return state.map((item) =>
item.hasSubitems ? { ...item, Subitems: toggleSubitems(item.Subitems, action.id) } : item
);
case "COLLAPSE_SUB_SECOND_ITEMS":
return state.map((item) =>
item.hasSubitems
? {
...item,
Subitems: item.Subitems.map((subitem) =>
action.id === subitem.id
subitem.hasSubitems
? {
...subitem,
showSubitems: !subitem.showSubitems,
Subitems: toggleSubitems(subitem.Subitems, action.id),
}
: subitem
),
}
: item;
});
case "COLLAPSE_SUB_SECOND_ITEMS":
return state.map((item) => {
return item.hasSubitems
? {
...item,
Subitems: item.Subitems.map((subitem) => {
return subitem.hasSubitems
? {
...subitem,
Subitems: subitem.Subitems.map((secondSubitem) =>
action.id === secondSubitem.id
? {
...secondSubitem,
showSubitems: !secondSubitem.showSubitems,
}
: secondSubitem
),
}
: subitem;
}),
}
: item;
});
: item
);
case "SELECTED":
return state.map((item) => selectPage(item, action.route));
@@ -112,13 +99,16 @@ const SidebarMenu = () => {
}, [selectedKey]);
return (
userPermissions && (
<List sx={{ overflow: "auto" }} disablePadding dense>
{menuItems.map((menuItem) => {
return <SidebarListItems dispatch={dispatch} key={menuItem.id} menuItem={menuItem} />;
})}
</List>
)
<>
<Profile />
{userPermissions && (
<List sx={{ overflow: "auto", flex: 1 }} disablePadding dense>
{menuItems.map((menuItem) => {
return <SidebarListItems dispatch={dispatch} key={menuItem.id} menuItem={menuItem} />;
})}
</List>
)}
</>
);
};
export default SidebarMenu;

View File

@@ -1,6 +1,7 @@
import { ExpandLess, ExpandMore } from "@mui/icons-material";
import { Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from "@mui/material";
import { Box, Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Stack } from "@mui/material";
import Link from "next/link";
import SidebarBadge from "./SidebarBadge";
const SidebarSubitems = ({ subitem, dispatch }) => {
return (
@@ -8,7 +9,7 @@ const SidebarSubitems = ({ subitem, dispatch }) => {
<ListItem disablePadding divider>
<ListItemButton
disableGutters
sx={{ py: 1, px: 0.5, pl: 1 }}
sx={{ p: 0.5, pl: 1 }}
selected={subitem.selected}
component={subitem.type === "page" ? Link : null}
href={subitem.type === "page" ? subitem.route : null}
@@ -27,7 +28,22 @@ const SidebarSubitems = ({ subitem, dispatch }) => {
{subitem.icon}
</ListItemIcon>
<ListItemText primary={subitem.label} />
{subitem.hasSubitems ? subitem.showSubitems ? <ExpandLess /> : <ExpandMore /> : null}
{subitem.badges && (
<Stack direction={"row"} sx={{ px: 0.5 }} spacing={0.5}>
{subitem.badges.map((badge, i) => (
<SidebarBadge key={i} badge={badge} />
))}
</Stack>
)}
{subitem.hasSubitems ? (
subitem.showSubitems ? (
<ExpandLess />
) : (
<ExpandMore />
)
) : (
<Box sx={{ width: 29 }} />
)}
</ListItemButton>
</ListItem>
<Collapse in={subitem.showSubitems} timeout="auto" mountOnEnter={true} unmountOnExit={true}>

View File

@@ -1,13 +1,16 @@
"use client";
import SidebarMenu from "@/core/components/SidebarMenu";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import MenuIcon from "@mui/icons-material/Menu";
import { Box, Drawer, IconButton, Stack, styled, Toolbar } from "@mui/material";
import { Box, Drawer, IconButton, Stack, styled, Toolbar, Typography } from "@mui/material";
import MuiAppBar from "@mui/material/AppBar";
import { useState } from "react";
import HeaderMenu from "./HeaderMenu";
import moment from "jalali-moment";
import { headerMenu } from "@/core/utils/headerMenu";
import SidebarMenu from "./Sidebar/SidebarMenu";
const drawerWidth = 300;
const headersHeight = 136;
const Main = styled(Stack, { shouldForwardProp: (prop) => prop !== "open" })(({ theme, open }) => ({
flexGrow: 1,
@@ -48,12 +51,13 @@ const DrawerHeader = styled("div")(({ theme }) => ({
alignItems: "center",
padding: theme.spacing(0, 1),
...theme.mixins.toolbar,
minHeight: "48px !important",
minHeight: "40px !important",
justifyContent: "flex-end",
}));
const HeaderWithSidebar = ({ children }) => {
const [open, setOpen] = useState(true);
const now = moment().locale("fa").format("YYYY/MM/DD");
const handleDrawerOpen = () => {
setOpen(true);
@@ -62,9 +66,16 @@ const HeaderWithSidebar = ({ children }) => {
setOpen(false);
};
return (
<Box sx={{ display: "flex", height: "calc(100% - 163px)", width: "100%", mt: "163px" }}>
<Box
sx={{
display: "flex",
height: `calc(100% - ${headersHeight}px)`,
width: "100%",
mt: `${headersHeight}px`,
}}
>
<AppBar sx={{ position: "fixed", top: "unset" }} elevation={0} open={open}>
<Toolbar variant="dense">
<Toolbar variant="dense" sx={{ minHeight: 40 }}>
<IconButton
color="inherit"
aria-label="open drawer"
@@ -75,7 +86,9 @@ const HeaderWithSidebar = ({ children }) => {
<MenuIcon />
</IconButton>
<Box sx={{ flexGrow: 1, display: { xs: "none", md: "flex" } }}>
<HeaderMenu />
{headerMenu.map((menu) => (
<HeaderMenu key={menu.title} menu={menu} />
))}
</Box>
</Toolbar>
</AppBar>
@@ -90,27 +103,33 @@ const HeaderWithSidebar = ({ children }) => {
boxSizing: "border-box",
borderTop: 1,
borderTopColor: "divider",
position: 'inherit'
position: "inherit",
},
}}
variant="persistent"
anchor="left"
open={open}
>
<DrawerHeader>
<DrawerHeader sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Typography variant="subtitle2" color="#757575" sx={{ px: 1 }}>
تاریخ امروز: {now}
</Typography>
<IconButton onClick={handleDrawerClose}>
<ChevronRightIcon />
</IconButton>
</DrawerHeader>
<SidebarMenu />
<Typography textAlign={"center"} variant="caption" sx={{ py: 0.2, fontFamily: "sans-serif" }}>
v{process.env.NEXT_PUBLIC_VERSION}
</Typography>
</Drawer>
<Main open={open} sx={{ height: "100%", width: "100%", overflow: "hidden" }}>
<DrawerHeader />
<Box sx={{ height: "100%", width: "100%", overflowY: "auto", p: 2, overflowX: "hidden" }}>
<Box sx={{ height: "100%", width: "100%", overflowY: "auto", p: 1, overflowX: "hidden" }}>
{children}
</Box>
</Main>
</Box>
);
};
export default HeaderWithSidebar;
export default HeaderWithSidebar;

View File

@@ -0,0 +1,52 @@
"use client";
import { Box, Chip, Divider, Grid, Typography } from "@mui/material";
import QrCode2Icon from "@mui/icons-material/QrCode2";
import HomeWorkIcon from "@mui/icons-material/HomeWork";
import DomainIcon from "@mui/icons-material/Domain";
import CottageIcon from "@mui/icons-material/Cottage";
import AccountTreeIcon from "@mui/icons-material/AccountTree";
import HolidayVillageIcon from "@mui/icons-material/HolidayVillage";
import CalendarMonthIcon from "@mui/icons-material/CalendarMonth";
import FaxIcon from "@mui/icons-material/Fax";
import FullscreenIcon from "@mui/icons-material/Fullscreen";
import ArchitectureIcon from "@mui/icons-material/Architecture";
import Diversity2Icon from "@mui/icons-material/Diversity2";
import SubtitlesIcon from "@mui/icons-material/Subtitles";
import FingerprintIcon from "@mui/icons-material/Fingerprint";
const findItem = {
id: { title: "کد یکتا", icon: <FingerprintIcon /> },
shomareh_darkhast: { title: "شماره درخواست", icon: <QrCode2Icon /> },
ostan: { title: "استان", icon: <HomeWorkIcon /> },
shahr: { title: "شهر", icon: <DomainIcon /> },
shahrestan: { title: "شهرستان", icon: <CottageIcon /> },
bakhsh: { title: "بخش", icon: <AccountTreeIcon /> },
roosta: { title: "روستا", icon: <HolidayVillageIcon /> },
tarikh_darkhast: { title: "تاریخ درخواست", icon: <CalendarMonthIcon /> },
sazman: { title: "سازمان", icon: <FaxIcon /> },
masahat_zamin: { title: "مساحت زمین", icon: <FullscreenIcon /> },
masahat_tarh: { title: "مساحت طرح", icon: <ArchitectureIcon /> },
gorooh_tarh: { title: "گروه طرح", icon: <Diversity2Icon /> },
onvane_tarh: { title: "عنوان طرح", icon: <SubtitlesIcon /> },
};
const DetailItem = ({ item }) => {
const currentItem = findItem[item.key];
if (!currentItem) return null;
return (
<Grid item xs={12} md={6}>
<Box sx={{ display: "flex", alignItems: "center" }}>
<Chip
icon={currentItem?.icon}
sx={{ fontSize: "12px", fontWeight: 500, pl: "5px" }}
label={currentItem?.title}
/>
<Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{item.value}</Typography>
</Box>
</Grid>
);
};
export default DetailItem;

View File

@@ -0,0 +1,39 @@
"use client";
import { Box } from "@mui/material";
import dynamic from "next/dynamic";
import MapLoading from "@/core/components/MapLayer/Loading";
import FlyToPolyGon from "./FlyToPolygon";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading />,
ssr: false,
});
const DetailMap = ({ data }) => {
return (
<Box
sx={{
width: "100%",
height: "200px",
border: "1px solid #e1e1e1",
borderRadius: 2,
my: 3,
}}
>
<Box
sx={{
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<MapLayer>
<FlyToPolyGon polygon={data.polygon} />
</MapLayer>
</Box>
</Box>
);
};
export default DetailMap;

View File

@@ -0,0 +1,22 @@
"use client";
import { Polygon, useMap } from "react-leaflet";
import { useEffect } from "react";
const purpleOptions = { color: "purple" };
const FlyToPolygon = ({ polygon }) => {
const map = useMap();
useEffect(() => {
if (map) {
const leafletPolygon = L.polygon(polygon);
const bounds = leafletPolygon.getBounds();
map.flyToBounds(bounds, { padding: [50, 50] });
}
}, [map, polygon]);
return <Polygon pathOptions={purpleOptions} positions={polygon} />;
};
export default FlyToPolygon;

Some files were not shown because too many files have changed in this diff Show More