{
);
};
export default InquiryPrivacyFencingList;
-
diff --git a/src/components/dashboard/test/Actions/create/CreateDialog/ChooseLocation.jsx b/src/components/dashboard/test/Actions/create/CreateDialog/ChooseLocation.jsx
new file mode 100644
index 0000000..433543e
--- /dev/null
+++ b/src/components/dashboard/test/Actions/create/CreateDialog/ChooseLocation.jsx
@@ -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 (
+ <>
+
+
+
+
+
+
+ طول جغرافیایی
+
+
+ {mapBoxData ? :
+ }
+
+ }
+ label="طول جغرافیایی"
+ />
+
+
+
+
+
+ عرض جغرافیایی
+
+
+ {mapBoxData ? :
+ }
+
+ }
+ label="عرض جغرافیایی"
+ />
+
+
+
+
+
+ >
+ );
+};
+
+export default ChooseLocation;
\ No newline at end of file
diff --git a/src/components/dashboard/test/Actions/create/CreateDialog/CreateTimeLine.jsx b/src/components/dashboard/test/Actions/create/CreateDialog/CreateTimeLine.jsx
new file mode 100644
index 0000000..49a7d90
--- /dev/null
+++ b/src/components/dashboard/test/Actions/create/CreateDialog/CreateTimeLine.jsx
@@ -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 (
+
+
+
+
+
+
+
+
+
+
+
+
+ نقشه
+
+ ثبت مختصات محل
+ آزمایش
+
+
+
+
+
+
+
+
+
+
+
+
+ مشخصات آزمایش
+
+ ثبت مشخصات اولیه
+
+
+
+
+ );
+};
+export default CreateTimeLine;
diff --git a/src/components/dashboard/test/Actions/create/CreateDialog/MapBox.jsx b/src/components/dashboard/test/Actions/create/CreateDialog/MapBox.jsx
new file mode 100644
index 0000000..8b1611c
--- /dev/null
+++ b/src/components/dashboard/test/Actions/create/CreateDialog/MapBox.jsx
@@ -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: () => ,
+ ssr: false,
+});
+
+const MapBox = ({mapBoxData, setMapBoxData}) => {
+ return (
+
+
+
+
+
+
+
+
+
+ );
+};
+export default MapBox;
diff --git a/src/components/dashboard/test/Actions/create/CreateDialog/TestGeneralInfo.jsx b/src/components/dashboard/test/Actions/create/CreateDialog/TestGeneralInfo.jsx
new file mode 100644
index 0000000..d424a1a
--- /dev/null
+++ b/src/components/dashboard/test/Actions/create/CreateDialog/TestGeneralInfo.jsx
@@ -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 (
+
+
+ (
+
+
+ {errorTests ? (
+
+ خطایی در دریافت لیست آزمایش ها رخ داده است!
+
+ ) : loadingTests ? (
+
+
+ درحال دریافت لیست آزمایش ها
+
+ ) : (
+ 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) => (
+
+ )}
+ />
+ )}
+
+ {errors.azmayesh_type_id ? errors.azmayesh_type_id.message : null}
+
+
+ )}
+ />
+
+
+ (
+
+
+ {errorProvinces ? (
+
+ خطایی در دریافت لیست استان ها رخ داده است!
+
+ ) : loadingProvinces ? (
+
+
+ درحال دریافت لیست استان ها
+
+ ) : (
+ 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) => (
+
+ )}
+ />
+ )}
+
+ {errors.province_id ? errors.province_id.message : null}
+
+
+ )}
+ />
+
+
+
+
+ پروژه
+
+
+
+ {errors.project_name ? errors.project_name.message : null}
+
+
+
+
+
+
+ کارفرما
+
+
+
+ {errors.employer ? errors.employer.message : null}
+
+
+
+
+
+
+ مشاور
+
+
+
+ {errors.consultant ? errors.consultant.message : null}
+
+
+
+
+
+
+ پیمانکار
+
+
+
+ {errors.contractor ? errors.contractor.message : null}
+
+
+
+
+
+
+ متقاضی
+
+
+
+ {errors.applicant ? errors.applicant.message : null}
+
+
+
+
+
+
+ شماره کار
+
+
+
+ {errors.work_number ? errors.work_number.message : null}
+
+
+
+
+
+
+ شماره درخواست
+
+
+
+ {errors.request_number ? errors.request_number.message : null}
+
+
+
+
+ (
+
+
+ {
+ onChange(newValue);
+ }}
+ slotProps={{
+ textField: {
+ size: "small",
+ error: !!errors.request_date,
+ placeholder: "تاریخ درخواست",
+ InputProps: {
+ endAdornment: (
+
+ {
+ event.stopPropagation();
+ setValue("request_date", "");
+ }}
+ sx={{
+ color: "#bfbfbf",
+ "&:hover": {
+ backgroundColor: "rgba(189, 189, 189, 0.1)",
+ color: "#363434",
+ },
+ }}
+ >
+
+
+
+ ),
+ },
+ },
+ }}
+ />
+
+
+ {errors.request_date ? errors.request_date.message : null}
+
+
+ )}
+ />
+
+
+ (
+
+
+ {
+ onChange(newValue);
+ }}
+ slotProps={{
+ textField: {
+ size: "small",
+ error: !!errors.report_date,
+ placeholder: "تاریخ گزارش",
+ InputProps: {
+ endAdornment: (
+
+ {
+ event.stopPropagation();
+ setValue("report_date", "");
+ }}
+ sx={{
+ color: "#bfbfbf",
+ "&:hover": {
+ backgroundColor: "rgba(189, 189, 189, 0.1)",
+ color: "#363434",
+ },
+ }}
+ >
+
+
+
+ ),
+ },
+ },
+ }}
+ />
+
+
+ {errors.report_date ? errors.report_date.message : null}
+
+
+ )}
+ />
+
+
+ );
+};
+export default TestGeneralInfo;
\ No newline at end of file
diff --git a/src/components/dashboard/test/Actions/create/CreateDialog/index.jsx b/src/components/dashboard/test/Actions/create/CreateDialog/index.jsx
new file mode 100644
index 0000000..f52c42a
--- /dev/null
+++ b/src/components/dashboard/test/Actions/create/CreateDialog/index.jsx
@@ -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 (
+
+ {value === index && (
+
+ {children}
+
+ )}
+
+ );
+}
+
+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 (
+
+ );
+};
+export default CreateDialog;
diff --git a/src/components/dashboard/test/Actions/create/index.jsx b/src/components/dashboard/test/Actions/create/index.jsx
new file mode 100644
index 0000000..9d59d00
--- /dev/null
+++ b/src/components/dashboard/test/Actions/create/index.jsx
@@ -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 ? (
+
+
+
+ ) : (
+
+ )}
+ {open && }
+ >
+ );
+};
+export default TestCreate;
diff --git a/src/components/dashboard/test/ShowLocation/ShowLocationMarker.jsx b/src/components/dashboard/test/ShowLocation/ShowLocationMarker.jsx
new file mode 100644
index 0000000..6b65250
--- /dev/null
+++ b/src/components/dashboard/test/ShowLocation/ShowLocationMarker.jsx
@@ -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 (
+ <>
+
+
+
+
+
+ طول جغرافیایی
+
+
+
+
+ }
+ label="طول جغرافیایی"
+ />
+
+
+
+ عرض جغرافیایی
+
+
+
+
+ }
+ label="عرض جغرافیایی"
+ />
+
+
+
+ >
+ );
+};
+
+export default ShowLocationMarker;
\ No newline at end of file
diff --git a/src/components/dashboard/test/ShowLocation/index.jsx b/src/components/dashboard/test/ShowLocation/index.jsx
new file mode 100644
index 0000000..557a780
--- /dev/null
+++ b/src/components/dashboard/test/ShowLocation/index.jsx
@@ -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: () => ,
+ ssr: false,
+});
+
+const ShowLocation = ({lat, lng}) => {
+ const [openShowLocationModal, setOpenShowLocationModal] = useState(false);
+
+ const handleOpenShowLocationModal = () => {
+ setOpenShowLocationModal(true);
+ };
+
+ const handleCloseShowLocationModal = () => {
+ setOpenShowLocationModal(false);
+ };
+
+ return (
+
+
+
+
+ );
+};
+export default ShowLocation;
diff --git a/src/components/dashboard/test/TestList.jsx b/src/components/dashboard/test/TestList.jsx
new file mode 100644
index 0000000..2c735f4
--- /dev/null
+++ b/src/components/dashboard/test/TestList.jsx
@@ -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}) => (),
+ },
+ {
+ 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}) => ({moment(renderedCellValue).locale("fa").format("YYYY/MM/DD")}),
+ },
+ {
+ accessorKey: "report_date",
+ header: "تاریخ گزارش",
+ id: "report_date",
+ enableColumnFilter: false,
+ datatype: "date",
+ filterFn: "equals",
+ Cell: ({renderedCellValue}) => ({moment(renderedCellValue).locale("fa").format("YYYY/MM/DD")}),
+ },
+ ],
+ []
+ );
+
+ return (
+ <>
+
+
+
+ >
+ );
+};
+export default TestList;
diff --git a/src/components/dashboard/test/Toolbar.jsx b/src/components/dashboard/test/Toolbar.jsx
new file mode 100644
index 0000000..8aaa0a9
--- /dev/null
+++ b/src/components/dashboard/test/Toolbar.jsx
@@ -0,0 +1,10 @@
+import TestCreate from "./Actions/Create";
+
+const Toolbar = ({mutate}) => {
+ return (
+ <>
+
+ >
+ );
+};
+export default Toolbar;
diff --git a/src/components/dashboard/test/index.jsx b/src/components/dashboard/test/index.jsx
new file mode 100644
index 0000000..d2503a0
--- /dev/null
+++ b/src/components/dashboard/test/index.jsx
@@ -0,0 +1,15 @@
+"use client";
+
+import PageTitle from "@/core/components/PageTitle";
+import {Stack} from "@mui/material";
+import TestList from "./TestList";
+
+const TestPage = () => {
+ return (
+
+
+
+
+ );
+};
+export default TestPage;
diff --git a/src/components/layouts/dashboard/headerWithLogo/HaederBottom/index.jsx b/src/components/layouts/dashboard/headerWithLogo/HaederBottom/index.jsx
index f23833c..1ab9f22 100644
--- a/src/components/layouts/dashboard/headerWithLogo/HaederBottom/index.jsx
+++ b/src/components/layouts/dashboard/headerWithLogo/HaederBottom/index.jsx
@@ -15,9 +15,9 @@ const HeaderBottom = () => {
alignItems={"center"}
direction={"row"}
>
-
+
- theme.palette.primary2.contrastText }}>
+ theme.palette.primary2.contrastText }}>
سامانه جامع راهداری
theme.palette.primary2.contrastText }}>rms.rmto.ir
diff --git a/src/components/layouts/dashboard/headerWithLogo/HaederTop/index.jsx b/src/components/layouts/dashboard/headerWithLogo/HaederTop/index.jsx
index 2c0c3b6..4926625 100644
--- a/src/components/layouts/dashboard/headerWithLogo/HaederTop/index.jsx
+++ b/src/components/layouts/dashboard/headerWithLogo/HaederTop/index.jsx
@@ -5,7 +5,7 @@ import HeaderLogo from "@/assets/images/headerLogo.png";
const HeaderTop = () => {
return (
-
+
);
};
diff --git a/src/components/layouts/dashboard/headerWithLogo/index.jsx b/src/components/layouts/dashboard/headerWithLogo/index.jsx
index 2d0b7bc..9b59fa6 100644
--- a/src/components/layouts/dashboard/headerWithLogo/index.jsx
+++ b/src/components/layouts/dashboard/headerWithLogo/index.jsx
@@ -4,7 +4,7 @@ import HeaderBottom from "./HaederBottom";
const HeaderWithLogo = () => {
return (
-
+
diff --git a/src/components/layouts/dashboard/headerWithSidebar/HeaderMenu/index.jsx b/src/components/layouts/dashboard/headerWithSidebar/HeaderMenu/index.jsx
index c705242..47decdf 100644
--- a/src/components/layouts/dashboard/headerWithSidebar/HeaderMenu/index.jsx
+++ b/src/components/layouts/dashboard/headerWithSidebar/HeaderMenu/index.jsx
@@ -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 (
+ <>
+ : }
+ >
+ {menu.title}
+
+
+ >
+ );
};
+
export default HeaderMenu;
diff --git a/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarBadge.jsx b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarBadge.jsx
new file mode 100644
index 0000000..4ee1a83
--- /dev/null
+++ b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarBadge.jsx
@@ -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 ;
+};
+export default SidebarBadge;
diff --git a/src/core/components/SidebarListItems.jsx b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarListItems.jsx
similarity index 78%
rename from src/core/components/SidebarListItems.jsx
rename to src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarListItems.jsx
index 050d9a6..7b0aabc 100644
--- a/src/core/components/SidebarListItems.jsx
+++ b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarListItems.jsx
@@ -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 (
<>
{
{menuItem.icon}
+ {menuItem.badges && (
+
+ {menuItem.badges.map((badge, i) => (
+
+ ))}
+
+ )}
{menuItem.hasSubitems ? menuItem.showSubitems ? : : null}
diff --git a/src/core/components/SidebarMenu.jsx b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarMenu.jsx
similarity index 54%
rename from src/core/components/SidebarMenu.jsx
rename to src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarMenu.jsx
index 625972a..4142b7f 100644
--- a/src/core/components/SidebarMenu.jsx
+++ b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarMenu.jsx
@@ -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 && (
-
- {menuItems.map((menuItem) => {
- return ;
- })}
-
- )
+ <>
+
+ {userPermissions && (
+
+ {menuItems.map((menuItem) => {
+ return ;
+ })}
+
+ )}
+ >
);
};
export default SidebarMenu;
diff --git a/src/core/components/SidebarSubitems.jsx b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarSubitems.jsx
similarity index 67%
rename from src/core/components/SidebarSubitems.jsx
rename to src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarSubitems.jsx
index 69418ea..3018520 100644
--- a/src/core/components/SidebarSubitems.jsx
+++ b/src/components/layouts/dashboard/headerWithSidebar/Sidebar/SidebarSubitems.jsx
@@ -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 }) => {
{
{subitem.icon}
- {subitem.hasSubitems ? subitem.showSubitems ? : : null}
+ {subitem.badges && (
+
+ {subitem.badges.map((badge, i) => (
+
+ ))}
+
+ )}
+ {subitem.hasSubitems ? (
+ subitem.showSubitems ? (
+
+ ) : (
+
+ )
+ ) : (
+
+ )}
diff --git a/src/components/layouts/dashboard/headerWithSidebar/index.jsx b/src/components/layouts/dashboard/headerWithSidebar/index.jsx
index 68f4bc6..a0ffad2 100644
--- a/src/components/layouts/dashboard/headerWithSidebar/index.jsx
+++ b/src/components/layouts/dashboard/headerWithSidebar/index.jsx
@@ -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 (
-
+
-
+
{
-
+ {headerMenu.map((menu) => (
+
+ ))}
@@ -90,27 +103,33 @@ const HeaderWithSidebar = ({ children }) => {
boxSizing: "border-box",
borderTop: 1,
borderTopColor: "divider",
- position: 'inherit'
+ position: "inherit",
},
}}
variant="persistent"
anchor="left"
open={open}
>
-
+
+
+ تاریخ امروز: {now}
+
+
+ v{process.env.NEXT_PUBLIC_VERSION}
+
-
+
{children}
);
};
-export default HeaderWithSidebar;
\ No newline at end of file
+export default HeaderWithSidebar;
diff --git a/src/core/components/ApplicantRequestDetail/DetailItem.jsx b/src/core/components/ApplicantRequestDetail/DetailItem.jsx
new file mode 100644
index 0000000..099e955
--- /dev/null
+++ b/src/core/components/ApplicantRequestDetail/DetailItem.jsx
@@ -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: },
+ shomareh_darkhast: { title: "شماره درخواست", icon: },
+ ostan: { title: "استان", icon: },
+ shahr: { title: "شهر", icon: },
+ shahrestan: { title: "شهرستان", icon: },
+ bakhsh: { title: "بخش", icon: },
+ roosta: { title: "روستا", icon: },
+ tarikh_darkhast: { title: "تاریخ درخواست", icon: },
+ sazman: { title: "سازمان", icon: },
+ masahat_zamin: { title: "مساحت زمین", icon: },
+ masahat_tarh: { title: "مساحت طرح", icon: },
+ gorooh_tarh: { title: "گروه طرح", icon: },
+ onvane_tarh: { title: "عنوان طرح", icon: },
+};
+
+const DetailItem = ({ item }) => {
+ const currentItem = findItem[item.key];
+ if (!currentItem) return null;
+
+ return (
+
+
+
+
+ {item.value}
+
+
+ );
+};
+export default DetailItem;
diff --git a/src/core/components/ApplicantRequestDetail/DetailMap.jsx b/src/core/components/ApplicantRequestDetail/DetailMap.jsx
new file mode 100644
index 0000000..902ec3a
--- /dev/null
+++ b/src/core/components/ApplicantRequestDetail/DetailMap.jsx
@@ -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: () => ,
+ ssr: false,
+});
+
+const DetailMap = ({ data }) => {
+ return (
+
+
+
+
+
+
+
+ );
+};
+export default DetailMap;
diff --git a/src/core/components/ApplicantRequestDetail/FlyToPolygon.jsx b/src/core/components/ApplicantRequestDetail/FlyToPolygon.jsx
new file mode 100644
index 0000000..4a39edd
--- /dev/null
+++ b/src/core/components/ApplicantRequestDetail/FlyToPolygon.jsx
@@ -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 ;
+};
+
+export default FlyToPolygon;
diff --git a/src/core/components/ApplicantRequestDetail/index.jsx b/src/core/components/ApplicantRequestDetail/index.jsx
new file mode 100644
index 0000000..bfdbf35
--- /dev/null
+++ b/src/core/components/ApplicantRequestDetail/index.jsx
@@ -0,0 +1,57 @@
+"use client";
+
+import { Box, Button, Chip, Divider, Grid, Typography } from "@mui/material";
+import AttachFileIcon from "@mui/icons-material/AttachFile";
+import DownloadingIcon from "@mui/icons-material/Downloading";
+import DetailItem from "./DetailItem";
+import DetailMap from "./DetailMap";
+import ContactMailIcon from "@mui/icons-material/ContactMail";
+
+const ApplicantRequestDetail = ({ data }) => {
+ return (
+ <>
+
+
+
+
+ {Object.entries(data).map(([key, value]) => (
+
+ ))}
+
+
+ }
+ sx={{ fontSize: "12px", fontWeight: 500, pl: "5px" }}
+ label="فایل مصوب"
+ />
+
+ }
+ sx={{ borderRadius: 5 }}
+ >
+ دریافت
+
+
+
+
+
+
+
+ }
+ label="آدرس"
+ />
+
+
+ {data.address}
+
+
+
+
+ >
+ );
+};
+export default ApplicantRequestDetail;
diff --git a/src/core/components/DataTable/Main.js b/src/core/components/DataTable/Main.js
index 1f51695..5d0d98d 100644
--- a/src/core/components/DataTable/Main.js
+++ b/src/core/components/DataTable/Main.js
@@ -21,6 +21,7 @@ const DataTable_Main = (props) => {
initialStateProps,
TableToolbar,
table_title,
+ RowActions,
} = props;
const flatColumns = flattenArrayOfObjects(columns, "columns");
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });
@@ -32,13 +33,11 @@ const DataTable_Main = (props) => {
const fetchUrl = useMemo(() => {
const isValueEmpty = (value) => {
if (Array.isArray(value)) {
- return value.length === 0 || value.every(v => v === "");
+ return value.length === 0 || value.every((v) => v === "");
}
return value === "" || value === null || value === undefined;
};
- const filteredFilterData = Object.values(filterData).filter(
- (filter) => !isValueEmpty(filter.value),
- );
+ const filteredFilterData = Object.values(filterData).filter((filter) => !isValueEmpty(filter.value));
const params = new URLSearchParams();
params.set("start", `${pagination.pageIndex * pagination.pageSize}`);
@@ -108,11 +107,8 @@ const DataTable_Main = (props) => {
manualSorting: true,
onPaginationChange: setPagination,
onSortingChange: onSortingChange,
- renderTopToolbarCustomActions: ({ table }) => (
- <>
-
- >
- ),
+ renderTopToolbarCustomActions: ({ table }) => <>{TableToolbar && }>,
+ renderRowActions: ({ row }) => ,
...props,
});
diff --git a/src/core/components/DataTable/body/TableBodyCell.js b/src/core/components/DataTable/body/TableBodyCell.js
index 902f9c7..292f39e 100644
--- a/src/core/components/DataTable/body/TableBodyCell.js
+++ b/src/core/components/DataTable/body/TableBodyCell.js
@@ -1,11 +1,10 @@
+import { getCommonMRTCellStyles, parseFromValuesOrFunc } from "@/core/utils/utils";
+import { useTheme } from "@emotion/react";
+import { Skeleton, TableCell } from "@mui/material";
import { isCellEditable, openEditingCell } from "material-react-table";
-
-const { parseFromValuesOrFunc, getCommonMRTCellStyles } = require("@/core/utils/utils");
-const { useTheme } = require("@emotion/react");
-const { TableCell, Skeleton } = require("@mui/material");
-const { useState, useEffect, useMemo, memo } = require("react");
-const { default: DataTable_CopyButton } = require("../buttons/CopyButton");
-const { default: DataTable_TableBodyCellValue } = require("./TableBodyCellValue");
+import { memo, useEffect, useMemo, useState } from "react";
+import DataTable_CopyButton from "../buttons/CopyButton";
+import DataTable_TableBodyCellValue from "./TableBodyCellValue";
const DataTable_TableBodyCell = ({ cell, numRows, rowRef, staticColumnIndex, staticRowIndex, table, ...rest }) => {
const theme = useTheme();
@@ -83,10 +82,10 @@ const DataTable_TableBodyCell = ({ cell, numRows, rowRef, staticColumnIndex, sta
const borderStyle = showResizeBorder
? `2px solid ${draggingBorderColor} !important`
: isDraggingColumn || isDraggingRow
- ? `1px dashed ${theme.palette.grey[500]} !important`
- : isHoveredColumn || isHoveredRow || isResizingColumn
- ? `2px dashed ${draggingBorderColor} !important`
- : undefined;
+ ? `1px dashed ${theme.palette.grey[500]} !important`
+ : isHoveredColumn || isHoveredRow || isResizingColumn
+ ? `2px dashed ${draggingBorderColor} !important`
+ : undefined;
if (showResizeBorder) {
return columnResizeDirection === "ltr" ? { borderRight: borderStyle } : { borderLeft: borderStyle };
@@ -94,18 +93,18 @@ const DataTable_TableBodyCell = ({ cell, numRows, rowRef, staticColumnIndex, sta
return borderStyle
? {
- borderBottom:
- isDraggingRow || isHoveredRow || (isLastRow && !isResizingColumn) ? borderStyle : undefined,
- borderLeft:
- isDraggingColumn || isHoveredColumn || ((isDraggingRow || isHoveredRow) && isFirstColumn)
- ? borderStyle
- : undefined,
- borderRight:
- isDraggingColumn || isHoveredColumn || ((isDraggingRow || isHoveredRow) && isLastColumn)
- ? borderStyle
- : undefined,
- borderTop: isDraggingRow || isHoveredRow ? borderStyle : undefined,
- }
+ borderBottom:
+ isDraggingRow || isHoveredRow || (isLastRow && !isResizingColumn) ? borderStyle : undefined,
+ borderLeft:
+ isDraggingColumn || isHoveredColumn || ((isDraggingRow || isHoveredRow) && isFirstColumn)
+ ? borderStyle
+ : undefined,
+ borderRight:
+ isDraggingColumn || isHoveredColumn || ((isDraggingRow || isHoveredRow) && isLastColumn)
+ ? borderStyle
+ : undefined,
+ borderTop: isDraggingRow || isHoveredRow ? borderStyle : undefined,
+ }
: undefined;
}, [columnSizingInfo.isResizingColumn, draggingColumn, draggingRow, hoveredColumn, hoveredRow, staticRowIndex]);
@@ -179,8 +178,8 @@ const DataTable_TableBodyCell = ({ cell, numRows, rowRef, staticColumnIndex, sta
"&:hover": {
outline:
actionCell?.id === cell.id ||
- (editDisplayMode === "cell" && isEditable) ||
- (editDisplayMode === "table" && (isCreating || isEditing))
+ (editDisplayMode === "cell" && isEditable) ||
+ (editDisplayMode === "table" && (isCreating || isEditing))
? `1px solid ${theme.palette.grey[500]}`
: undefined,
textOverflow: "clip",
@@ -189,8 +188,8 @@ const DataTable_TableBodyCell = ({ cell, numRows, rowRef, staticColumnIndex, sta
cursor: isRightClickable
? "context-menu"
: isEditable && editDisplayMode === "cell"
- ? "pointer"
- : "inherit",
+ ? "pointer"
+ : "inherit",
outline: actionCell?.id === cell.id ? `1px solid ${theme.palette.grey[500]}` : undefined,
outlineOffset: "-1px",
overflow: "hidden",
@@ -200,12 +199,12 @@ const DataTable_TableBodyCell = ({ cell, numRows, rowRef, staticColumnIndex, sta
? "0 0.5rem"
: "0.5rem"
: density === "comfortable"
- ? columnDefType === "display"
- ? "0.5rem 0.75rem"
- : "1rem"
- : columnDefType === "display"
- ? "1rem 1.25rem"
- : "1.5rem",
+ ? columnDefType === "display"
+ ? "0.5rem 0.75rem"
+ : "1rem"
+ : columnDefType === "display"
+ ? "1rem 1.25rem"
+ : "1.5rem",
textOverflow: columnDefType !== "display" ? "ellipsis" : undefined,
whiteSpace: row.getIsPinned() || density === "compact" ? "nowrap" : "normal",
@@ -216,18 +215,18 @@ const DataTable_TableBodyCell = ({ cell, numRows, rowRef, staticColumnIndex, sta
theme,
}),
...draggingBorders,
- backgroundColor: baseBackgroundColor
+ backgroundColor: baseBackgroundColor,
})}
>
{tableCellProps.children ?? (
<>
{cell.getIsPlaceholder() ? (
- columnDef.PlaceholderCell?.({ cell, column, row, table }) ?? null
+ (columnDef.PlaceholderCell?.({ cell, column, row, table }) ?? null)
) : showSkeletons !== false && (isLoading || showSkeletons) ? (
) : columnDefType === "display" &&
- (["mrt-row-expand", "mrt-row-numbers", "mrt-row-select"].includes(column.id) ||
- !row.getIsGrouped()) ? (
+ (["mrt-row-expand", "mrt-row-numbers", "mrt-row-select"].includes(column.id) ||
+ !row.getIsGrouped()) ? (
columnDef.Cell?.({
cell,
column,
diff --git a/src/core/components/DataTable/body/TableBodyRow.js b/src/core/components/DataTable/body/TableBodyRow.js
index e35f29a..2d21f32 100644
--- a/src/core/components/DataTable/body/TableBodyRow.js
+++ b/src/core/components/DataTable/body/TableBodyRow.js
@@ -91,16 +91,16 @@ const DataTable_TableBodyRow = ({
const cellHighlightColor = isRowSelected
? selectedRowBackgroundColor
: isRowPinned
- ? pinnedRowBackgroundColor
- : undefined;
+ ? pinnedRowBackgroundColor
+ : undefined;
const cellHighlightColorHover =
tableRowProps?.hover !== false
? isRowSelected
? cellHighlightColor
: theme.palette.mode === "dark"
- ? `${lighten(baseBackgroundColor, 0.2)}`
- : `${darken(baseBackgroundColor, 0.2)}`
+ ? `${lighten(baseBackgroundColor, 0.2)}`
+ : `${darken(baseBackgroundColor, 0.2)}`
: undefined;
return (
@@ -126,9 +126,9 @@ const DataTable_TableBodyRow = ({
sx={(theme) => ({
"&:hover td:after": cellHighlightColorHover
? {
- backgroundColor: alpha(cellHighlightColorHover, 0.3),
- ...commonCellBeforeAfterStyles,
- }
+ backgroundColor: alpha(cellHighlightColorHover, 0.3),
+ ...commonCellBeforeAfterStyles,
+ }
: undefined,
bottom:
!virtualRow && bottomPinnedIndex !== undefined && isRowPinned
@@ -140,24 +140,25 @@ const DataTable_TableBodyRow = ({
position: virtualRow
? "absolute"
: rowPinningDisplayMode?.includes("sticky") && isRowPinned
- ? "sticky"
- : "relative",
+ ? "sticky"
+ : "relative",
td: {
...getCommonPinnedCellStyles({ table, theme }),
},
"td:after": cellHighlightColor
? {
- backgroundColor: cellHighlightColor,
- ...commonCellBeforeAfterStyles,
- }
+ backgroundColor: cellHighlightColor,
+ ...commonCellBeforeAfterStyles,
+ }
: undefined,
top: virtualRow
? 0
: topPinnedIndex !== undefined && isRowPinned
- ? `${topPinnedIndex * rowHeight +
- (enableStickyHeader || isFullScreen ? tableHeadHeight - 1 : 0)
+ ? `${
+ topPinnedIndex * rowHeight +
+ (enableStickyHeader || isFullScreen ? tableHeadHeight - 1 : 0)
}px`
- : undefined,
+ : undefined,
transition: virtualRow ? "none" : "all 150ms ease-in-out",
width: "100%",
zIndex: rowPinningDisplayMode?.includes("sticky") && isRowPinned ? 2 : 0,
@@ -181,11 +182,11 @@ const DataTable_TableBodyRow = ({
};
return cell ? (
memoMode === "cells" &&
- cell.column.columnDef.columnDefType === "data" &&
- !draggingColumn &&
- !draggingRow &&
- editingCell?.id !== cell.id &&
- editingRow?.id !== row.id ? (
+ cell.column.columnDef.columnDefType === "data" &&
+ !draggingColumn &&
+ !draggingRow &&
+ editingCell?.id !== cell.id &&
+ editingRow?.id !== row.id ? (
) : (
diff --git a/src/core/components/DataTable/filter/FilterBodyField.jsx b/src/core/components/DataTable/filter/FilterBodyField.jsx
index 7f0337e..a9bef12 100644
--- a/src/core/components/DataTable/filter/FilterBodyField.jsx
+++ b/src/core/components/DataTable/filter/FilterBodyField.jsx
@@ -18,15 +18,15 @@ const columnFilterModeOptionFa = {
};
function FilterBodyField({
- column,
- filterParameters,
- handleChange,
- handleBlur,
- setFieldValue,
- errors,
- touched,
- resetForm,
- }) {
+ column,
+ filterParameters,
+ handleChange,
+ handleBlur,
+ setFieldValue,
+ errors,
+ touched,
+ resetForm,
+}) {
const [anchorEl, setAnchorEl] = useState(null);
const defaultFilterTranslation = columnFilterModeOptionFa[filterParameters.filterFn] || filterParameters.filterFn;
@@ -48,8 +48,8 @@ function FilterBodyField({
touched={touched}
/>
) : filterParameters.datatype === "numeric" &&
- filterParameters.filterFn === "equals" &&
- Array.isArray(column.columnSelectOption) ? (
+ filterParameters.filterFn === "equals" &&
+ Array.isArray(column.columnSelectOption) ? (
{
diff --git a/src/core/components/DataTable/head/TableHeadCell.js b/src/core/components/DataTable/head/TableHeadCell.js
index 046f833..631a122 100644
--- a/src/core/components/DataTable/head/TableHeadCell.js
+++ b/src/core/components/DataTable/head/TableHeadCell.js
@@ -67,20 +67,20 @@ const DataTable_TableHeadCell = ({ columnVirtualizer, header, staticColumnIndex,
const borderStyle = showResizeBorder
? `2px solid ${draggingBorderColor} !important`
: draggingColumn?.id === column.id
- ? `1px dashed ${theme.palette.grey[500]}`
- : hoveredColumn?.id === column.id
- ? `2px dashed ${draggingBorderColor}`
- : undefined;
+ ? `1px dashed ${theme.palette.grey[500]}`
+ : hoveredColumn?.id === column.id
+ ? `2px dashed ${draggingBorderColor}`
+ : undefined;
if (showResizeBorder) {
return columnResizeDirection === "ltr" ? { borderRight: borderStyle } : { borderLeft: borderStyle };
}
const draggingBorders = borderStyle
? {
- borderLeft: borderStyle,
- borderRight: borderStyle,
- borderTop: borderStyle,
- }
+ borderLeft: borderStyle,
+ borderRight: borderStyle,
+ borderTop: borderStyle,
+ }
: undefined;
return draggingBorders;
@@ -151,19 +151,19 @@ const DataTable_TableHeadCell = ({ columnVirtualizer, header, staticColumnIndex,
density === "compact"
? "0.5rem"
: density === "comfortable"
- ? columnDefType === "display"
- ? "0.75rem"
- : "1rem"
- : columnDefType === "display"
- ? "1rem 1.25rem"
- : "1.5rem",
+ ? columnDefType === "display"
+ ? "0.75rem"
+ : "1rem"
+ : columnDefType === "display"
+ ? "1rem 1.25rem"
+ : "1.5rem",
pb: columnDefType === "display" ? 0 : showColumnFilters || density === "compact" ? "0.4rem" : "0.6rem",
pt:
columnDefType === "group" || density === "compact"
? "0.25rem"
: density === "comfortable"
- ? ".75rem"
- : "1.25rem",
+ ? ".75rem"
+ : "1.25rem",
userSelect: enableMultiSort && column.getCanSort() ? "none" : undefined,
verticalAlign: "middle",
...getCommonMRTCellStyles({
@@ -188,8 +188,8 @@ const DataTable_TableHeadCell = ({ columnVirtualizer, header, staticColumnIndex,
columnDefType === "group" || tableCellProps?.align === "center"
? "center"
: column.getCanResize()
- ? "space-between"
- : "flex-start",
+ ? "space-between"
+ : "flex-start",
position: "relative",
width: "100%",
}}
@@ -218,7 +218,7 @@ const DataTable_TableHeadCell = ({ columnVirtualizer, header, staticColumnIndex,
textAlign: "start",
color: "#fff",
fontWeight: "400",
- whiteSpace: "nowrap"
+ whiteSpace: "nowrap",
}}
>
{HeaderElement}
@@ -226,9 +226,10 @@ const DataTable_TableHeadCell = ({ columnVirtualizer, header, staticColumnIndex,
{column.getCanSort() && columnDefType !== "group" && (
{columns.map((column) => (
-
+
))}
@@ -50,4 +45,4 @@ function HideBody({ columns, drawerState, setDrawerState }) {
);
}
-export default HideBody;
\ No newline at end of file
+export default HideBody;
diff --git a/src/core/components/DataTable/hide/HideBodyField.jsx b/src/core/components/DataTable/hide/HideBodyField.jsx
index fe3dc2d..6b60966 100644
--- a/src/core/components/DataTable/hide/HideBodyField.jsx
+++ b/src/core/components/DataTable/hide/HideBodyField.jsx
@@ -22,7 +22,7 @@ const CustomTreeItem = styled(TreeItem)(({ theme }) => ({
function HideBodyField({ column, hideData, setHideData }) {
const handleCheckboxChange = () => {
- setHideData(prevData => {
+ setHideData((prevData) => {
const updateHideData = (data, id) => {
if (data.hasOwnProperty(id)) {
return { ...data, [id]: !data[id] };
@@ -44,11 +44,7 @@ function HideBodyField({ column, hideData, setHideData }) {
if (typeof hideData[column.id] === "boolean") {
return (
-
+
{column.header}
);
@@ -77,4 +73,4 @@ function HideBodyField({ column, hideData, setHideData }) {
);
}
-export default HideBodyField;
\ No newline at end of file
+export default HideBodyField;
diff --git a/src/core/components/DataTable/hide/HideOrShowAll.jsx b/src/core/components/DataTable/hide/HideOrShowAll.jsx
index ee3a903..c0d2e8d 100644
--- a/src/core/components/DataTable/hide/HideOrShowAll.jsx
+++ b/src/core/components/DataTable/hide/HideOrShowAll.jsx
@@ -67,4 +67,4 @@ function HideOrShowAll({ hideData, setHideData }) {
);
}
-export default HideOrShowAll;
\ No newline at end of file
+export default HideOrShowAll;
diff --git a/src/core/components/DataTable/reset/ResetStorage.jsx b/src/core/components/DataTable/reset/ResetStorage.jsx
index 6d8a534..9f6abd5 100644
--- a/src/core/components/DataTable/reset/ResetStorage.jsx
+++ b/src/core/components/DataTable/reset/ResetStorage.jsx
@@ -19,4 +19,4 @@ function ResetStorage({ user_id, page_name, table_name }) {
);
}
-export default ResetStorage;
\ No newline at end of file
+export default ResetStorage;
diff --git a/src/core/components/DataTable/table/Paper.js b/src/core/components/DataTable/table/Paper.js
index 05a0dbb..f972030 100644
--- a/src/core/components/DataTable/table/Paper.js
+++ b/src/core/components/DataTable/table/Paper.js
@@ -5,17 +5,17 @@ import DataTable_TopToolbar from "../toolbar/TopToolbar";
import DataTable_TableContainer from "./TableContainer";
const DataTable_Paper = ({
- table,
- table_name,
- columns,
- user_id,
- page_name,
- mutate,
- need_filter,
- table_url,
- table_title,
- ...rest
- }) => {
+ table,
+ table_name,
+ columns,
+ user_id,
+ page_name,
+ mutate,
+ need_filter,
+ table_url,
+ table_title,
+ ...rest
+}) => {
const {
getState,
options: {
@@ -50,19 +50,19 @@ const DataTable_Paper = ({
style={{
...(isFullScreen
? {
- bottom: 0,
- height: "100dvh",
- left: 0,
- margin: 0,
- maxHeight: "100dvh",
- maxWidth: "100dvw",
- padding: 0,
- position: "fixed",
- right: 0,
- top: 0,
- width: "100dvw",
- zIndex: 999,
- }
+ bottom: 0,
+ height: "100dvh",
+ left: 0,
+ margin: 0,
+ maxHeight: "100dvh",
+ maxWidth: "100dvw",
+ padding: 0,
+ position: "fixed",
+ right: 0,
+ top: 0,
+ width: "100dvw",
+ zIndex: 999,
+ }
: {}),
...paperProps?.style,
}}
diff --git a/src/core/components/DataTable/table/TableContainer.js b/src/core/components/DataTable/table/TableContainer.js
index bc1d80c..3e1320e 100644
--- a/src/core/components/DataTable/table/TableContainer.js
+++ b/src/core/components/DataTable/table/TableContainer.js
@@ -27,9 +27,10 @@ const DataTable_TableContainer = ({ table, ...rest }) => {
};
useIsomorphicLayoutEffect(() => {
- const topToolbarHeight = typeof document !== "undefined" ? topToolbarRef.current?.offsetHeight ?? 0 : 0;
+ const topToolbarHeight = typeof document !== "undefined" ? (topToolbarRef.current?.offsetHeight ?? 0) : 0;
- const bottomToolbarHeight = typeof document !== "undefined" ? bottomToolbarRef?.current?.offsetHeight ?? 0 : 0;
+ const bottomToolbarHeight =
+ typeof document !== "undefined" ? (bottomToolbarRef?.current?.offsetHeight ?? 0) : 0;
setTotalToolbarHeight(topToolbarHeight + bottomToolbarHeight);
});
diff --git a/src/core/components/DataTable/toolbar/TopToolbar.js b/src/core/components/DataTable/toolbar/TopToolbar.js
index fc21ae7..a4d9db7 100644
--- a/src/core/components/DataTable/toolbar/TopToolbar.js
+++ b/src/core/components/DataTable/toolbar/TopToolbar.js
@@ -8,16 +8,16 @@ import ResetStorage from "@/core/components/DataTable/reset/ResetStorage";
import HideColumn from "@/core/components/DataTable/hide";
const DataTable_TopToolbar = ({
- mutate,
- need_filter,
- table,
- columns,
- table_url,
- user_id,
- page_name,
- table_name,
- table_title,
- }) => {
+ mutate,
+ need_filter,
+ table,
+ columns,
+ table_url,
+ user_id,
+ page_name,
+ table_name,
+ table_title,
+}) => {
const {
getState,
options: {
@@ -70,13 +70,21 @@ const DataTable_TopToolbar = ({
width: "100%",
}}
>
- {renderTopToolbarCustomActions?.({ table })}
- {table_title || ""}
+
+ {renderTopToolbarCustomActions?.({ table })}
+
+
+ {table_title || ""}
+
{enableToolbarInternalActions && (
-
+
+ table_name={table_name}
+ />
{need_filter && (
{
+ const { user } = useAuth();
+ return ;
+};
+export default DataTableWithAuth;
diff --git a/src/core/components/DialogTransition.jsx b/src/core/components/DialogTransition.jsx
index f289140..1232e48 100644
--- a/src/core/components/DialogTransition.jsx
+++ b/src/core/components/DialogTransition.jsx
@@ -5,4 +5,4 @@ const DialogTransition = React.forwardRef(function Transition(props, ref) {
return ;
});
-export default DialogTransition
\ No newline at end of file
+export default DialogTransition;
diff --git a/src/core/components/MapLayer/Loading/index.jsx b/src/core/components/MapLayer/Loading/index.jsx
index 5d42012..806168c 100644
--- a/src/core/components/MapLayer/Loading/index.jsx
+++ b/src/core/components/MapLayer/Loading/index.jsx
@@ -2,11 +2,7 @@ import { Box, LinearProgress, Stack } from "@mui/material";
function MapLoading() {
return (
-
+
@@ -14,4 +10,4 @@ function MapLoading() {
);
}
-export default MapLoading;
\ No newline at end of file
+export default MapLoading;
diff --git a/src/core/components/MapLayer/index.jsx b/src/core/components/MapLayer/index.jsx
index 52209da..1a07c9c 100644
--- a/src/core/components/MapLayer/index.jsx
+++ b/src/core/components/MapLayer/index.jsx
@@ -1,7 +1,7 @@
"use client";
import { MapContainer, TileLayer, useMap } from "react-leaflet";
-export const IRAN_CENTER = L.latLng(32.4279, 53.6880);
+export const IRAN_CENTER = L.latLng(32.4279, 53.688);
const MapOptions = ({ options }) => {
const map = useMap();
@@ -40,4 +40,4 @@ function MapLayer({ children, style, otherLayers, options }) {
);
}
-export default MapLayer;
\ No newline at end of file
+export default MapLayer;
diff --git a/src/core/components/NotificationDesign/AskForKeepData.jsx b/src/core/components/NotificationDesign/AskForKeepData.jsx
index fa9bfa6..9e1cbd9 100644
--- a/src/core/components/NotificationDesign/AskForKeepData.jsx
+++ b/src/core/components/NotificationDesign/AskForKeepData.jsx
@@ -10,9 +10,7 @@ import { flattenObjectOfObjects } from "@/core/utils/flattenObjectOfObjects";
function AskForKeepData({ filterData, sortData, hideData, user_id, page_name, table_name, columns }) {
const { filterAction, sortAction, hideAction } = useTableSetting();
- const filteredHideData = Object.fromEntries(
- Object.entries(hideData).filter(([key, value]) => value === false),
- );
+ const filteredHideData = Object.fromEntries(Object.entries(hideData).filter(([key, value]) => value === false));
const flattenHideData = flattenObjectOfObjects(filteredHideData);
@@ -53,19 +51,10 @@ function AskForKeepData({ filterData, sortData, hideData, user_id, page_name, ta
آیا مایل به ذخیره تغییر های اعمال شده برای دفعات بعد هستید؟
- }
- onClick={onSaveFilter}
- >
+ } onClick={onSaveFilter}>
ذخیره
-
@@ -73,4 +62,4 @@ function AskForKeepData({ filterData, sortData, hideData, user_id, page_name, ta
);
}
-export default AskForKeepData;
\ No newline at end of file
+export default AskForKeepData;
diff --git a/src/core/components/PageTitle.jsx b/src/core/components/PageTitle.jsx
index 605ad47..4c93098 100644
--- a/src/core/components/PageTitle.jsx
+++ b/src/core/components/PageTitle.jsx
@@ -4,9 +4,15 @@ import { Chip, Divider, Typography } from "@mui/material";
const PageTitle = ({ title }) => {
return (
- {title}} />
+
+
+ {title}
+
+ }
+ />
+
);
};
export default PageTitle;
-
diff --git a/src/core/components/Profile/ChangePass/Form.jsx b/src/core/components/Profile/ChangePass/Form.jsx
new file mode 100644
index 0000000..80d1890
--- /dev/null
+++ b/src/core/components/Profile/ChangePass/Form.jsx
@@ -0,0 +1,152 @@
+"use client";
+
+import {
+ Chip,
+ Divider,
+ FormControl,
+ FormHelperText,
+ Grid,
+ IconButton,
+ InputAdornment,
+ InputLabel,
+ OutlinedInput,
+} from "@mui/material";
+import StyledForm from "@/core/components/StyledForm";
+import { useForm } from "react-hook-form";
+import useRequest from "@/lib/hooks/useRequest";
+import { CHANGE_USER_PASSWORD } from "@/core/utils/routes";
+import { object, string } from "yup";
+import { yupResolver } from "@hookform/resolvers/yup";
+import { useEffect, useState } from "react";
+import Visibility from "@mui/icons-material/Visibility";
+import VisibilityOff from "@mui/icons-material/VisibilityOff";
+
+const validationSchema = object({
+ current_password: string().required("اجباری"),
+ new_password: string().required("اجباری"),
+ repeat_new_password: string()
+ .required("اجباری")
+ .test("password-match", "رمز عبور جدید و تکرار آن باید یکسان باشند", function (value) {
+ return this.parent.new_password === value;
+ }),
+});
+
+const Form = ({ handleCloseForm, setLoading }) => {
+ const request = useRequest();
+ const [showNewPassword, setShowNewPassword] = useState();
+ const [showRepeatNewPassword, setShowRepeatNewPassword] = useState();
+
+ const defaultValues = {
+ current_password: "",
+ new_password: "",
+ repeat_new_password: "",
+ };
+
+ const {
+ register,
+ handleSubmit,
+ formState: { isSubmitting, errors },
+ } = useForm({ defaultValues, resolver: yupResolver(validationSchema) });
+
+ useEffect(() => {
+ setLoading(isSubmitting);
+ }, [isSubmitting]);
+
+ const onSubmit = async (data) => {
+ const formData = new FormData();
+ formData.append("current_password", data.current_password);
+ formData.append("new_password", data.new_password);
+ try {
+ await request(CHANGE_USER_PASSWORD, "post", { data: formData, signal: controller.signal });
+ handleCloseForm();
+ } catch (error) {}
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+ رمز عبور فعلی
+
+
+ {errors.current_password ? errors.current_password.message : null}
+
+
+
+
+
+ رمز عبور جدید
+
+ setShowNewPassword(!showNewPassword)}
+ onMouseDown={(event) => event.preventDefault()}
+ edge="end"
+ >
+ {showNewPassword ? : }
+
+
+ }
+ />
+
+ {errors.new_password ? errors.new_password.message : null}
+
+
+
+
+
+ تکرار رمز عبور جدید
+
+ setShowRepeatNewPassword(!showRepeatNewPassword)}
+ onMouseDown={(event) => event.preventDefault()}
+ edge="end"
+ >
+ {showRepeatNewPassword ? : }
+
+
+ }
+ />
+
+ {errors.repeat_new_password ? errors.repeat_new_password.message : null}
+
+
+
+
+
+ >
+ );
+};
+export default Form;
diff --git a/src/core/components/Profile/ChangePass/index.jsx b/src/core/components/Profile/ChangePass/index.jsx
new file mode 100644
index 0000000..4b388da
--- /dev/null
+++ b/src/core/components/Profile/ChangePass/index.jsx
@@ -0,0 +1,47 @@
+"use client";
+
+import { Dialog, DialogActions, DialogContent } from "@mui/material";
+import Form from "./Form";
+import SaveIcon from "@mui/icons-material/Save";
+import { LoadingButton } from "@mui/lab";
+import { useState } from "react";
+
+const ChangePass = ({ open, setOpen }) => {
+ const [loading, setLoading] = useState(false);
+
+ const handleCloseForm = () => {
+ setOpen(false);
+ };
+
+ return (
+
+ );
+};
+export default ChangePass;
diff --git a/src/core/components/Profile/ProfileActions.jsx b/src/core/components/Profile/ProfileActions.jsx
new file mode 100644
index 0000000..1bb99be
--- /dev/null
+++ b/src/core/components/Profile/ProfileActions.jsx
@@ -0,0 +1,54 @@
+"use client";
+
+import { Box, Divider, IconButton, Tooltip } from "@mui/material";
+import PowerSettingsNewIcon from "@mui/icons-material/PowerSettingsNew";
+import ModeEditIcon from "@mui/icons-material/ModeEdit";
+import VpnKeyIcon from "@mui/icons-material/VpnKey";
+import { useState } from "react";
+import Update from "@/core/components/Profile/Update";
+import ChangePass from "@/core/components/Profile/ChangePass";
+import { useAuth } from "@/lib/contexts/auth";
+
+const ProfileActions = () => {
+ const { getUser } = useAuth();
+ const [openUpdate, setOpenUpdate] = useState(false);
+ const [openChangePass, setOpenChangePass] = useState(false);
+
+ const openUpdateProfile = () => {
+ getUser();
+ setOpenUpdate(true);
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ setOpenChangePass(true);
+ }}
+ >
+
+
+
+
+
+
+ >
+ );
+};
+export default ProfileActions;
diff --git a/src/core/components/Profile/ProfileInfo.jsx b/src/core/components/Profile/ProfileInfo.jsx
new file mode 100644
index 0000000..6af5082
--- /dev/null
+++ b/src/core/components/Profile/ProfileInfo.jsx
@@ -0,0 +1,38 @@
+"use client";
+
+import { useAuth } from "@/lib/contexts/auth";
+import { Avatar, Box, Chip, Divider, Stack, Typography } from "@mui/material";
+import moment from "jalali-moment";
+
+const ProfileInfo = () => {
+ const { user } = useAuth();
+
+ return (
+ <>
+
+
+
+
+ {`${user.first_name} ${user.last_name}`}
+
+ .: {user.name} :.
+
+
+
+
+ آخرین ورود
+
+
+
+ {moment(user.last_login).locale("fa").fromNow()}
+
+
+
+
+
+
+
+ >
+ );
+};
+export default ProfileInfo;
diff --git a/src/core/components/Profile/Update/Form.jsx b/src/core/components/Profile/Update/Form.jsx
new file mode 100644
index 0000000..69b1466
--- /dev/null
+++ b/src/core/components/Profile/Update/Form.jsx
@@ -0,0 +1,251 @@
+"use client";
+
+import {
+ Autocomplete,
+ Avatar,
+ Backdrop,
+ Box,
+ Button,
+ Chip,
+ Divider,
+ FormControl,
+ FormHelperText,
+ Grid,
+ InputLabel,
+ OutlinedInput,
+ TextField,
+} from "@mui/material";
+import StyledForm from "@/core/components/StyledForm";
+import useRequest from "@/lib/hooks/useRequest";
+import { Controller, useForm } from "react-hook-form";
+import { useAuth } from "@/lib/contexts/auth";
+import CloudUploadIcon from "@mui/icons-material/CloudUpload";
+import { styled } from "@mui/material/styles";
+import { useEffect, useState } from "react";
+import { yupResolver } from "@hookform/resolvers/yup";
+import { object, string } from "yup";
+import { UPDATE_USER_ROUTE } from "@/core/utils/routes";
+
+const degreeItems = ["دیپلم", "کارشناسی", "کارشناسی ارشد", "دکترا"];
+
+const VisuallyHiddenInput = styled("input")({
+ clip: "rect(0 0 0 0)",
+ clipPath: "inset(50%)",
+ height: 1,
+ overflow: "hidden",
+ position: "absolute",
+ bottom: 0,
+ left: 0,
+ whiteSpace: "nowrap",
+ width: 1,
+});
+
+const validationSchema = object({
+ first_name: string().required("اجباری"),
+ last_name: string().required("اجباری"),
+ degree: string().required("اجباری"),
+ major: string().required("اجباری"),
+ mobile: string().required("اجباری"),
+});
+
+const Form = ({ handleCloseForm, setLoading }) => {
+ const request = useRequest();
+ const { user, getUser } = useAuth();
+ const [uploadBackDrop, setUploadBackDrop] = useState(false);
+ const defaultValues = {
+ first_name: user.first_name,
+ last_name: user.last_name,
+ major: user.major,
+ degree: user.degree,
+ mobile: user.mobile,
+ avatar: null,
+ };
+
+ const {
+ control,
+ watch,
+ register,
+ setValue,
+ handleSubmit,
+ formState: { isSubmitting, errors },
+ } = useForm({ defaultValues, resolver: yupResolver(validationSchema) });
+
+ useEffect(() => {
+ setLoading(isSubmitting);
+ }, [isSubmitting]);
+
+ const onSubmit = async (data) => {
+ const formData = new FormData();
+ formData.append("first_name", data.first_name);
+ formData.append("last_name", data.last_name);
+ formData.append("major", data.major);
+ formData.append("degree", data.degree);
+ formData.append("mobile", data.mobile);
+ if (data.avatar) {
+ formData.append("avatar", data.avatar);
+ }
+
+ try {
+ await request(UPDATE_USER_ROUTE, "post", { data: formData });
+ getUser();
+ handleCloseForm();
+ } catch (error) {}
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+ setUploadBackDrop(true)}
+ onMouseLeave={() => setUploadBackDrop(false)}
+ >
+
+ theme.zIndex.drawer + 1,
+ position: "absolute",
+ width: 120,
+ height: 120,
+ marginLeft: "auto",
+ marginRight: "auto",
+ borderRadius: "50%",
+ }}
+ open={uploadBackDrop}
+ >
+
+
+
+ setValue("avatar", event.target.files[0])}
+ />
+
+
+
+
+
+ نام
+
+
+ {errors.first_name ? errors.first_name.message : null}
+
+
+
+
+
+ نام خانوادگی
+
+
+ {errors.last_name ? errors.last_name.message : null}
+
+
+
+
+
+ رشته تحصیلی
+
+ {errors.major ? errors.major.message : null}
+
+
+
+ (
+
+ {
+ onChange(newValue);
+ }}
+ options={degreeItems}
+ renderInput={(params) => (
+
+ )}
+ />
+ {error ? error.message : null}
+
+ )}
+ />
+
+
+
+ موبایل
+
+ {errors.mobile ? errors.mobile.message : null}
+
+
+
+
+ >
+ );
+};
+export default Form;
diff --git a/src/core/components/Profile/Update/index.jsx b/src/core/components/Profile/Update/index.jsx
new file mode 100644
index 0000000..d72b5a0
--- /dev/null
+++ b/src/core/components/Profile/Update/index.jsx
@@ -0,0 +1,44 @@
+"use client";
+
+import { Button, Dialog, DialogActions, DialogContent, useMediaQuery } from "@mui/material";
+import { useTheme } from "@mui/material/styles";
+import Form from "./Form";
+import SaveIcon from "@mui/icons-material/Save";
+import { LoadingButton } from "@mui/lab";
+import { useState } from "react";
+
+const Update = ({ open, setOpen }) => {
+ const theme = useTheme();
+ const fullScreen = useMediaQuery(theme.breakpoints.down("sm"));
+ const [loading, setLoading] = useState(false);
+
+ const handleCloseForm = () => {
+ setOpen(false);
+ };
+
+ return (
+
+ );
+};
+export default Update;
diff --git a/src/core/components/Profile/index.jsx b/src/core/components/Profile/index.jsx
new file mode 100644
index 0000000..fd5cbf4
--- /dev/null
+++ b/src/core/components/Profile/index.jsx
@@ -0,0 +1,22 @@
+"use client";
+
+import { Stack } from "@mui/material";
+import ProfileInfo from "./ProfileInfo";
+import ProfileActions from "./ProfileActions";
+
+const Profile = () => {
+ return (
+
+
+
+
+ );
+};
+export default Profile;
diff --git a/src/core/components/StyledForm.jsx b/src/core/components/StyledForm.jsx
index 4513129..accf0ab 100644
--- a/src/core/components/StyledForm.jsx
+++ b/src/core/components/StyledForm.jsx
@@ -1,5 +1,5 @@
import { styled } from "@mui/material";
-const StyledForm = styled('form')``;
+const StyledForm = styled("form")``;
export default StyledForm;
diff --git a/src/core/components/Toasts/success.jsx b/src/core/components/Toasts/success.jsx
index 36023c6..fc11759 100644
--- a/src/core/components/Toasts/success.jsx
+++ b/src/core/components/Toasts/success.jsx
@@ -16,7 +16,7 @@ export const successToast = (toastContainer) =>
- {"Your operation was successful"}
+ {"عملیات با موفقیت انجام شد"}