Merge branch 'release/v0.3.1'

This commit is contained in:
Amirhossein Mahmoodi
2024-07-13 16:00:06 +03:30
46 changed files with 1619 additions and 568 deletions

View File

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

View File

@@ -28,6 +28,8 @@
"next": "^14.2.3",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.52.1",
"react-leaflet": "^4.2.1",
"react-toastify": "^10.0.5",
"sass": "^1.75.0",
"stylis": "^4.3.1",
@@ -41,4 +43,4 @@
"eslint-config-prettier": "^9.1.0",
"prettier": "^3.3.2"
}
}
}

View File

@@ -1,9 +1,10 @@
@import "fontiran";
@import "leaflet/dist/leaflet.css";
@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;
border: 1px dashed #095b8c;
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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

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

View File

@@ -0,0 +1,13 @@
import HeaderWithLogo from "@/components/layouts/dashboard/headerWithLogo";
import HeaderWithSidebar from "@/components/layouts/dashboard/headerWithSidebar";
import { Stack } from "@mui/material";
const Layout = ({ children }) => {
return (
<Stack sx={{ width: '100%', height: '100%' }}>
<HeaderWithLogo />
<HeaderWithSidebar>{children}</HeaderWithSidebar>
</Stack>
);
};
export default Layout;

View File

@@ -1,11 +1,5 @@
"use client";
const Page = () => {
return (
<>
</>
);
return <></>;
};
export default Page;

View File

@@ -1,17 +0,0 @@
import { Box, Stack } from "@mui/material";
import HeaderWithLogo from "@/components/layouts/dashboard/headerWithLogo";
import HeaderWithSidebar from "@/components/layouts/dashboard/headerWithSidebar";
import "react-toastify/dist/ReactToastify.css";
const Template = ({ children }) => {
return (
<Stack>
<HeaderWithLogo />
<Box>
<HeaderWithSidebar>{children}</HeaderWithSidebar>
</Box>
</Stack>
);
};
export default Template;

View File

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

View File

@@ -1,7 +1,8 @@
import { redirect } from "next/navigation";
const prefix = process.env.NODE_ENV === "production" ? "/v3" : "";
function Page() {
redirect("/dashboard", "replace");
redirect(prefix + "/dashboard", "replace");
return null;
}

View File

@@ -1,5 +1,5 @@
import cacheProviderRtl from "@/core/utils/cacheRtl";
import { CssBaseline, ThemeProvider } from "@mui/material";
import { CssBaseline, GlobalStyles, ThemeProvider } from "@mui/material";
import theme from "@/core/utils/theme";
import { AppRouterCacheProvider } from "@mui/material-nextjs/v14-appRouter";
import "^/global.scss";
@@ -9,6 +9,25 @@ const Template = ({ children }) => {
return (
<AppRouterCacheProvider CacheProvider={cacheProviderRtl} options={{ enableCssLayer: true }}>
<ThemeProvider theme={theme}>
<GlobalStyles
styles={{
"*": {
scrollbarWidth: "thin",
scrollbarColor: `#155175 transparent`,
},
"*&::-webkit-scrollbar": {
width: "5px",
},
"*&::-webkit-scrollbar-track": {
boxShadow: "inset 0 0 5px #fff",
borderRadius: "5px",
},
"*&::-webkit-scrollbar-thumb": {
background: "#155175",
borderRadius: "5px",
},
}}
/>
<CssBaseline />
{children}
<ToastContainer rtl containerId="filtering" closeButton={false} />

View File

@@ -0,0 +1,23 @@
import MapLoading from "@/core/components/MapLayer/Loading";
import MarkerLocation from "@/core/components/MapLayer/MarkerLocation";
import { Paper, Stack } from "@mui/material";
import { useFormikContext } from "formik";
import dynamic from "next/dynamic";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading />,
ssr: false,
});
const LocationOnMap = ({ setValue }) => {
return (
<Stack sx={{ height: "100%", position: "relative" }}>
<Paper sx={{ flexGrow: 1, border: 1, borderRadius: 1, borderColor: 'divider' }} elevation={0}>
<MapLayer style={{ borderRadius: '4px' }}>
<MarkerLocation setValue={setValue} />
</MapLayer>
</Paper>
</Stack>
)
}
export default LocationOnMap

View File

@@ -0,0 +1,570 @@
import LtrTextField from "@/core/components/LtrTextField";
import StyledForm from "@/core/components/StyledForm";
import { SET_INQUIRE_PRIVACY_FENCING } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest";
import { Autocomplete, Box, Button, Chip, 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";
import { Controller, useForm } from "react-hook-form";
import LocationOnMap from "./LocationOnMap";
const CreateForm = ({ handleClose, mutate }) => {
const { control, watch, register, handleSubmit, setValue } = useForm({
defaultValues: {
dabirkhaneh_number: '',
nameh_date: moment(),
nameh_date_fa: '',
marjae_pasokh: '',
motaghazi_is_legal_id: null,
motaghazi_is_legal: '',
motaghazi_type_id: '',
motaghazi_type: null,
motaghazi_firstname: '',
motaghazi_lastname: '',
national_id: '',
shenase_melli: '',
tel_number: '',
mobile_number: '',
address: '',
edare_kol_id: null,
edare_kol: '',
edare_shahri_id: null,
edare_shahri: '',
rah_type_id: null,
rah_type: '',
name_mehvar_id: '',
name_mehvar_fa: null,
mizan_harim: null,
arze_navar: null,
samt_id: null,
samt: '',
kilometr: '',
lat: '',
lon: '',
zone: null,
karbari_type_id: null,
karbari_type: '',
tarh_title: '',
masahat_zirbana: '',
ehdasat_type_id: [],
ehdasat_type: '',
divarkeshi_distance: '',
mostahadesat_distance: '',
mahale_ejra_id: null,
mahale_ejra: '',
traffic_id: null,
traffic: '',
vaziat_eghtesadi_id: null,
vaziat_eghtesadi: '',
has_access_id: null,
has_access: '',
shomare_estelam_harim: '',
max_month: '',
max_day: '',
shomare_tahaodname: '',
shomare_daftarkhaneh: '',
description: '',
ronevesht: '',
}
});
const request = useRequest()
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_id)
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(SET_INQUIRE_PRIVACY_FENCING, 'post', { data: formData })
handleClose()
mutate()
} catch (error) {
}
};
return (
<LocalizationProvider
dateAdapter={AdapterDateFnsJalali}
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
>
<DialogContent>
<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" />
</Grid>
<Grid item xs={1}>
<Controller
name="nameh_date"
control={control}
render={({ field: { onChange, value } }) => (
<DatePicker
value={value.toDate()}
onChange={(newValue) => onChange(moment(newValue))}
label="تاریخ نامه درخواست *"
slotProps={{
textField: { fullWidth: true, size: "small", autoComplete: 'off' },
}}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<TextField autoComplete="off" {...register('marjae_pasokh')} label="مرجع درخواست کننده پاسخ به استعلام" size="small" fullWidth />
</Grid>
<Grid item xs={1}>
<Controller
name="motaghazi_is_legal_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["حقوقی", "حقیقی"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="متقاضی *" />}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Fade in={watch('motaghazi_is_legal_id') === 'حقوقی'} mountOnEnter={true} unmountOnExit={true}>
<Box>
<Controller
name="motaghazi_type"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["دولتی", "خصوصی"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="نوع متقاضی *" />}
/>
)}
/>
</Box>
</Fade>
</Grid>
<Grid item xs={1}></Grid>
<Grid item xs={1}>
<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>
</Grid>
<Grid item xs={1}>
<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" />
</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>
</Grid>
<Grid item xs={1}>
<TextField autoComplete="off" {...register('address')} label="آدرس *" size="small" fullWidth />
</Grid>
<Grid item xs={1}>
<Controller
name="edare_kol_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["تهران"]}
renderInput={(params) => (
<TextField autoComplete="off"
fullWidth
{...params}
label="اداره كل راهداری و حمل و نقل جاده ای *"
/>
)}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Controller
name="edare_shahri_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["تهران"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="اداره شهرستان *" />}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Controller
name="rah_type_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["آزاد راه", "بزرگراه", 'راه فرعی درجه 3']}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="نوع راه *" />}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Controller
name="name_mehvar_fa"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["سایر"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="نام محور *" />}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Fade in={watch('name_mehvar_fa') === "سایر"} mountOnEnter={true} unmountOnExit={true}>
<TextField autoComplete="off" label="سایر محورها" size="small" fullWidth />
</Fade>
</Grid>
<Grid item xs={1}>
<Controller
name="samt_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["چپ", "راست"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="سمت *" />}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Controller
name="mizan_harim"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["12.5", "17.5"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="میزان حریم *" />}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Fade in={watch('rah_type_id') !== 'راه فرعی درجه 3'} mountOnEnter={true} unmountOnExit={true}>
<Box>
<Controller
name="arze_navar"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["15", "30"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="عرض نوار تاسیساتی زیربنایی *" />}
/>
)}
/>
</Box>
</Fade>
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('kilometr')} label="كيلومتر *" size="small" fullWidth type="tel" />
</Grid>
<Grid item xs={1} sm={2} sx={{ height: 300 }}>
<LocationOnMap setValue={setValue} />
</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} />
<Controller
name="zone"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["38", "39"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="Zone *" />}
/>
)}
/>
</Stack>
</Grid>
<Grid item xs={1}>
<Controller
name="karbari_type_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["اتاقک نگهبانی", "دولتی"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="نوع کاربری *" />}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<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>,
}} />
</Grid>
<Grid item xs={1}>
<Controller
name="ehdasat_type_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
multiple
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
renderTags={(value, getTagProps) =>
value.map((option, index) => {
const { key, ...tagProps } = getTagProps({ index });
return (
<Chip label={option} key={key} size="small" {...tagProps} />
);
})
}
options={["تعمیرات", "احداث بنا"]}
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>,
}} />
</Grid>
<Grid item xs={1}>
<LtrTextField autoComplete="off" {...register('mostahadesat_distance')} label="فاصله مستحدثات از آکس محور" size="small" fullWidth type="tel" InputProps={{
endAdornment: <InputAdornment position="end">متر</InputAdornment>,
}} />
</Grid>
<Grid item xs={1}>
<Controller
name="mahale_ejra_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["داخل حریم"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="محل اجرا" />}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Controller
name="traffic_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["سبک (ضریب ۱)"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="میزان ترافیک *" />}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Controller
name="vaziat_eghtesadi_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["تست"]}
renderInput={(params) => <TextField autoComplete="off" fullWidth {...params} label="وضعیت اقتصادی" />}
/>
)}
/>
</Grid>
<Grid item xs={1}>
<Controller
name="has_access_id"
control={control}
render={({ field: { onChange, value } }) => (
<Autocomplete
size="small"
disablePortal
value={value}
onChange={(event, newValue) => {
onChange(newValue)
}}
options={["بله", "خیر"]}
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" />
</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>
</Grid>
<Grid item xs={1}>
<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" />
</Grid>
<Grid item xs={1}></Grid>
<Grid item xs={1}>
<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 />
</Grid>
<Grid item xs={1}></Grid>
</Grid>
</StyledForm>
</DialogContent>
<DialogActions sx={{ p: 2 }}>
<Button variant="contained" size="large" type="submit" form={'InquiryPrivacyFencingCreateForm'}>ثبت</Button>
</DialogActions>
</LocalizationProvider >
);
};
export default CreateForm;

View File

@@ -0,0 +1,32 @@
"use client";
import DialogTransition from "@/core/components/DialogTransition";
import { Close } from "@mui/icons-material";
import { Dialog, DialogTitle, IconButton } from "@mui/material";
import CreateForm from "./Form";
const InquiryPrivacyFencingCreate = ({ open, handleClose, mutate }) => {
return (
<>
<Dialog open={open} fullScreen TransitionComponent={DialogTransition}>
<DialogTitle sx={{ m: 0, p: 2 }} id="create-dialog">
ایجاد پاسخ به استعلام
</DialogTitle>
<IconButton
aria-label="close"
onClick={handleClose}
sx={{
position: "absolute",
right: 8,
top: 8,
color: (theme) => theme.palette.grey[500],
}}
>
<Close />
</IconButton>
<CreateForm handleClose={handleClose} mutate={mutate} />
</Dialog>
</>
);
};
export default InquiryPrivacyFencingCreate;

View File

@@ -0,0 +1,26 @@
import { Button } from "@mui/material";
import AddCircleIcon from "@mui/icons-material/AddCircle";
import { useState } from "react";
import InquiryPrivacyFencingCreate from "@/components/dashboard/inquiryPrivacyFencing/Create";
const Toolbar = ({ mutate }) => {
const [open, setOpen] = useState(false);
const handleOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<>
<Button variant="contained" color="primary2" startIcon={<AddCircleIcon />} onClick={handleOpen}>
ایجاد پاسخ به استعلام
</Button>
<InquiryPrivacyFencingCreate open={open} handleClose={handleClose} mutate={mutate} />
</>
);
};
export default Toolbar;

View File

@@ -0,0 +1,352 @@
"use client";
import { useMemo } from "react";
import Toolbar from "@/components/dashboard/inquiryPrivacyFencing/Toolbar";
import DataTable from "@/core/components/DataTable";
import { Box } from "@mui/material";
import { GET_INQUIRY_PRIVACY_FENCING_ROUTE } from "@/core/utils/routes";
const InquiryPrivacyFencingPage = () => {
const columns = useMemo(
() => [
{
accessorKey: "dabirkhaneh_number",
header: "شماره دبیرخانه درخواست",
id: "dabirkhaneh_number",
enableColumnFilter: false,
datatype: "text",
filterFn: "notEquals",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "marjae_pasokh",
header: "مرجع درخواست کننده پاسخ به استعلام",
id: "marjae_pasokh",
enableColumnFilter: false,
datatype: "text",
filterFn: "equals",
columnFilterModeOptions: ["equals", "notEquals", "contains", "lessThan", "greaterThan", "fuzzy"],
},
{
accessorKey: "motaghazi_is_legal",
header: "متقاضی",
id: "motaghazi_is_legal",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "nameh_date",
header: "تاریخ نامه درخواست",
id: "nameh_date",
enableColumnFilter: false,
datatype: "date",
filterFn: "equals",
},
{
accessorKey: "motaghazi_type",
header: "نوع متقاضی",
id: "motaghazi_type",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "motaghazi_firstname",
header: "نام متقاضی",
id: "motaghazi_firstname",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "motaghazi_lastname",
header: "نام خانوادگی متقاضی",
id: "motaghazi_lastname",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "national_id",
header: "کد ملی/شناسه ملی",
id: "national_id",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "tel_number",
header: "تلفن",
id: "tel_number",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "mobile_number",
header: "تلفن همراه",
id: "mobile_number",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "address",
header: "آدرس",
id: "address",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "edare_kol",
header: "اداره كل راهداری",
id: "edare_kol",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "edare_shahri",
header: "اداره شهرستان",
id: "edare_shahri",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "rah_type",
header: "نوع راه",
id: "rah_type",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "name_mehvar_fa",
header: "نام محور",
id: "name_mehvar_fa",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "mizan_harim",
header: "میزان حریم",
id: "mizan_harim",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "arze_navar",
header: "عرض نوار تاسیساتی زیربنایی",
id: "arze_navar",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "samt",
header: "سمت",
id: "samt",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "kilometr",
header: "كيلومتر",
id: "kilometr",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "zone",
header: "zone",
id: "zone",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "karbari_type",
header: "نوع کاربری",
id: "karbari_type",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "tarh_title",
header: "عنوان طرح",
id: "tarh_title",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "masahat_zirbana",
header: "مساحت زیربنا",
id: "masahat_zirbana",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "ehdasat_type",
header: "نوع احداثات",
id: "ehdasat_type",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "divarkeshi_distance",
header: "فاصله دیوارکشی از آکس محور",
id: "divarkeshi_distance",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "mahale_ejra",
header: "محل اجرا",
id: "mahale_ejra",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "traffic",
header: "میزان ترافیک",
id: "traffic",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "vaziat_eghtesadi",
header: "وضعیت اقتصادی",
id: "vaziat_eghtesadi",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "has_access",
header: "آیا راه دسترسی از قبل وجود دارد؟",
id: "has_access",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "shomare_estelam_harim",
header: "شماره استعلام دفتر ایمنی و حریم",
id: "shomare_estelam_harim",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "max_month",
header: "ماه",
id: "max_month",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "max_day",
header: "روز",
id: "max_day",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "shomare_tahaodname",
header: "شماره تعهدنامه",
id: "shomare_tahaodname",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "shomare_daftarkhaneh",
header: "شماره دفترخانه",
id: "shomare_daftarkhaneh",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "description",
header: "توضیحات",
id: "description",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "ronevesht",
header: "رونوشت",
id: "ronevesht",
enableColumnFilter: false,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
],
[]
);
return (
<DataTable
need_filter={false}
columns={columns}
table_url={GET_INQUIRY_PRIVACY_FENCING_ROUTE}
user_id={0}
page_name={"inquiryPrivacyFencing"}
table_name={"inquiryPrivacyFencingList"}
TableToolbar={Toolbar}
/>
);
};
export default InquiryPrivacyFencingPage;

View File

@@ -1,10 +0,0 @@
import { Button } from "@mui/material";
const Toolbar = ({ columns }) => {
return (
<>
<Button>add something</Button>
</>
);
};
export default Toolbar;

View File

@@ -1,129 +0,0 @@
"use client";
import DataTable from "@/core/components/DataTable";
import { useMemo } from "react";
function HomeComponent() {
const columns = useMemo(
() => [
{
accessorKey: "fullname",
header: "نام کامل",
id: "fullname",
columns: [
{
accessorKey: "name.firstName",
header: "نام",
id: "firstName",
enableColumnFilter: true,
datatype: "text",
filterFn: "contains",
enableClickToCopy: true,
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "name.lastName",
header: "نام خانوادگی",
id: "lastName",
enableColumnFilter: true,
datatype: "text",
filterFn: "equals",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
],
},
{
accessorKey: "address",
header: "آدرس",
id: "address",
enableColumnFilter: true,
datatype: "text",
filterFn: "notEquals",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "city",
header: "شهر",
id: "city",
enableColumnFilter: true,
datatype: "text",
filterFn: "equals",
columnFilterModeOptions: ["equals", "notEquals", "contains", "lessThan", "greaterThan", "fuzzy"],
},
{
accessorKey: "state",
header: "وضعیت",
id: "state",
enableColumnFilter: true,
datatype: "text",
filterFn: "contains",
columnFilterModeOptions: ["equals", "notEquals", "contains"],
},
{
accessorKey: "price",
header: "محدوده",
id: "price",
enableColumnFilter: true,
datatype: "numeric",
filterFn: "equals",
columnFilterModeOptions: ["equals", "notEquals"],
},
{
accessorKey: "created_at",
header: "تاریخ ساخت",
id: "created_at",
enableColumnFilter: true,
datatype: "date",
filterFn: "between",
},
{
accessorKey: "updated_at",
header: "تاریخ بروزرسانی",
id: "updated_at",
enableColumnFilter: true,
datatype: "date",
filterFn: "equals",
},
{
accessorKey: "company",
header: "نام شرکت",
id: "company",
enableColumnFilter: true,
datatype: "numeric",
filterFn: "equals",
columnSelectOption: [
{ value: 1, label: "وایتل" },
{ value: 2, label: "اسنپ" },
{ value: 3, label: "تپسی" },
],
},
{
accessorKey: "area",
header: "منطقه",
id: "area",
enableColumnFilter: true,
datatype: "array",
filterFn: "equals",
columnSelectOption: [
{ value: 1, label: "وایتل" },
{ value: 2, label: "اسنپ" },
{ value: 3, label: "تپسی" },
],
},
],
[]
);
return (
<>
<DataTable
columns={columns}
table_url={"api"}
user_id={0}
page_name={"testPage"}
table_name={"testTable"}
/>
</>
);
}
export default HomeComponent;

View File

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

View File

@@ -2,15 +2,16 @@
import SidebarMenu from "@/core/components/SidebarMenu";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import MenuIcon from "@mui/icons-material/Menu";
import { Box, Drawer, IconButton, Paper, styled, Toolbar } from "@mui/material";
import { Box, Drawer, IconButton, Paper, Stack, styled, Toolbar } from "@mui/material";
import MuiAppBar from "@mui/material/AppBar";
import { useState } from "react";
import HeaderMenu from "./HeaderMenu";
const drawerWidth = 300;
const Main = styled(Paper, { shouldForwardProp: (prop) => prop !== "open" })(({ theme, open }) => ({
const Main = styled(Stack, { shouldForwardProp: (prop) => prop !== "open" })(({ theme, open }) => ({
flexGrow: 1,
height: '100%',
transition: theme.transitions.create("margin", {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
@@ -47,6 +48,7 @@ const DrawerHeader = styled("div")(({ theme }) => ({
alignItems: "center",
padding: theme.spacing(0, 1),
...theme.mixins.toolbar,
minHeight: '48px !important',
justifyContent: "flex-end",
}));
@@ -60,7 +62,7 @@ const HeaderWithSidebar = ({ children }) => {
setOpen(false);
};
return (
<Box sx={{ display: "flex" }}>
<Box sx={{ display: "flex", height: 'calc(100% - 163px)', width: '100%', mt: '163px' }}>
<AppBar sx={{ position: "fixed", top: "unset" }} elevation={0} open={open}>
<Toolbar variant="dense">
<IconButton
@@ -79,6 +81,7 @@ const HeaderWithSidebar = ({ children }) => {
</AppBar>
<Drawer
sx={{
height: '100%',
width: drawerWidth,
flexShrink: 0,
"& .MuiDrawer-paper": {
@@ -100,11 +103,13 @@ const HeaderWithSidebar = ({ children }) => {
</DrawerHeader>
<SidebarMenu />
</Drawer>
<Main elevation={0} open={open}>
<Main open={open} sx={{ height: '100%', width: '100%', overflow: 'hidden' }}>
<DrawerHeader />
{children}
<Box sx={{ height: '100%', width: '100%', overflowY: 'auto', p: 2, overflowX: 'hidden', }}>
{children}
</Box>
</Main>
</Box>
);
};
export default HeaderWithSidebar;
export default HeaderWithSidebar;

View File

@@ -3,138 +3,68 @@ import { useMaterialReactTable } from "material-react-table";
import { FA_DATATABLE_LOCALIZATION } from "./localization/fa/datatable";
import useTableSetting from "@/lib/hooks/useTableSetting";
import { flattenArrayOfObjects } from "@/core/utils/flattenArrayOfObjects";
import Toolbar from "@/components/home/Toolbar";
import useDataTable from "@/lib/hooks/useDataTable";
import { useMemo, useState } from "react";
const data = [
{
name: {
firstName: "امین",
lastName: "قاسمپور",
},
address: "فلان جا",
city: "تهران",
state: "بررسی شده",
price: "20",
updated_at: "2024/05/02",
company: "همراه اول",
area: "منطقه 5",
},
{
name: {
firstName: "امیر حسین",
lastName: "محمودی",
},
address: "فلان جا",
city: "تهران",
state: "تکمیل شده",
price: "27",
updated_at: "2024/05/02",
company: "وایتل",
area: "منطقه 27",
},
{
name: {
firstName: "یاسمن",
lastName: "علی اکبری",
},
address: "فلان جا",
city: "شیراز",
state: "بررسی شده",
price: "32",
updated_at: "2024/05/02",
company: "ایرانسل",
area: "منطقه 23",
},
{
name: {
firstName: "حمیدرضا",
lastName: "رنجبرپور",
},
address: "فلان جا",
city: "اصفهان",
state: "بررسی شده",
price: "45",
updated_at: "2024/05/02",
company: "ایرانول",
area: "منطقه 21",
},
{
name: {
firstName: "محمد",
lastName: "جلالی",
},
address: "فلان جا",
city: "رشت",
state: "درحال بررسی",
price: "8",
updated_at: "2024/05/02",
company: "فیلیمو",
area: "منطقه 8",
},
];
import useRequest from "@/lib/hooks/useRequest";
import useSWR from "swr";
const DataTable_Main = (props) => {
const { filterData } = useDataTable();
const { table_url, user_id, page_name, table_name, columns, initialStateProps } = props;
const request = useRequest();
const isEmptyObject = (obj) => obj && Object.keys(obj).length === 0 && obj.constructor === Object;
const { filterData, sortData, setSortData } = useDataTable();
const { need_filter, table_url, user_id, page_name, table_name, columns, initialStateProps, TableToolbar } = props;
const flatColumns = flattenArrayOfObjects(columns, "columns");
const { settingStore, hideAction, sortAction } = useTableSetting();
const { settingStore, hideAction } = useTableSetting();
const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 });
const filters = Object.keys(filterData)
.map((key) => {
const value = filterData[key].value;
if (
value !== "" &&
!(
Array.isArray(value) &&
(value.length === 0 || (value.length === 2 && value[0] === "" && value[1] === ""))
)
) {
return filterData[key];
}
})
.filter(Boolean);
const storedFilters = settingStore?.[user_id]?.[page_name]?.[table_name]?.filters;
const finalFilters = storedFilters || filters;
const fetchUrl = useMemo(() => {
const params = new URLSearchParams();
params.set("start", `${pagination.pageIndex * pagination.pageSize}`);
params.set("size", pagination.pageSize);
params.set("filters", JSON.stringify(finalFilters ?? []));
params.set("sorting", JSON.stringify(settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] ?? []));
return `${table_url}?${params}`;
}, [table_url, finalFilters, pagination, columns]);
const onColumnVisibilityChange = (event) => {
const settingValue = event();
hideAction(user_id, page_name, table_name, settingValue, flatColumns);
};
const onSortingChange = (event) => {
const settingValue = event(settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] || []);
sortAction(user_id, page_name, table_name, settingValue, flatColumns);
setSortData(event);
};
const fetchUrl = useMemo(() => {
const params = new URLSearchParams();
params.set("start", `${pagination.pageIndex * pagination.pageSize}`);
params.set("size", pagination.pageSize);
params.set("filters", JSON.stringify(isEmptyObject(filterData) ? [] : [filterData]));
params.set("sorting", JSON.stringify(sortData));
return `${table_url}?${params}`;
}, [table_url, filterData, pagination, columns, sortData]);
const fetcher = async (url) => {
try {
const response = await request(url);
return response.data;
} catch (error) {
throw error;
}
};
const { data, isValidating, mutate } = useSWR(fetchUrl, fetcher, {
revalidateIfStale: true,
revalidateOnFocus: false,
revalidateOnReconnect: true,
keepPreviousData: true,
});
const table = useMaterialReactTable({
localization: FA_DATATABLE_LOCALIZATION,
columns,
data: data,
// manualSorting: true,
renderTopToolbarCustomActions: ({ table }) => (
<>
<Toolbar columns={flatColumns} />
</>
),
data: data?.data ?? [],
initialState: {
density: "compact",
columnVisibility: settingStore?.[user_id]?.[page_name]?.[table_name]?.["hides"],
sorting: settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] || [],
sorting: sortData,
...initialStateProps,
},
state: {
showProgressBars: isValidating,
columnVisibility: settingStore?.[user_id]?.[page_name]?.[table_name]?.["hides"],
sorting: settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] || [],
sorting: sortData,
pagination,
},
muiTableHeadProps: {
@@ -162,16 +92,24 @@ const DataTable_Main = (props) => {
},
manualFiltering: true,
manualPagination: true,
onPaginationChange: setPagination,
manualSorting: true,
onPaginationChange: setPagination,
onColumnVisibilityChange: onColumnVisibilityChange,
onSortingChange: onSortingChange,
renderTopToolbarCustomActions: ({ table }) => (
<>
<TableToolbar mutate={mutate} />
</>
),
...props,
});
return (
<DataTable_Paper
table={table}
need_filter={need_filter}
mutate={mutate}
table_url={table_url}
columns={flatColumns}
user_id={user_id}
page_name={page_name}

View File

@@ -3,12 +3,10 @@
import { Box, Button, Drawer, styled } from "@mui/material";
import { Form, Formik } from "formik";
import useTableSetting from "@/lib/hooks/useTableSetting";
import { useEffect, useRef, useState } from "react";
import { useEffect, useState } from "react";
import FilterHeader from "@/core/components/DataTable/filter/FilterHeader";
import * as Yup from "yup";
import FilterBodyField from "@/core/components/DataTable/filter/FilterBodyField";
import { toast } from "react-toastify";
import AskForKeep from "@/core/components/NotificationDesign/AskForKeep";
import useDataTable from "@/lib/hooks/useDataTable";
const ScrollBox = styled(Box)({
@@ -29,46 +27,13 @@ const ScrollBox = styled(Box)({
});
function FilterBody({ columns, drawerState, setDrawerState, user_id, page_name, table_name }) {
const { settingStore, filterAction } = useTableSetting();
const { settingStore } = useTableSetting();
const [initialValues, setInitialValues] = useState({});
const [validationSchema, setValidationSchema] = useState({});
const { filterData, setFilterData } = useDataTable();
const filterDataRef = useRef(filterData);
useEffect(() => {
filterDataRef.current = filterData;
}, [filterData]);
useEffect(() => {
const values = columns.reduce((acc, column) => {
if (!column.enableColumnFilter) return acc;
const filter = settingStore?.[user_id]?.[page_name]?.[table_name]?.["filters"]?.find(
(filter) => filter.id === column.id
);
if (column.datatype === "array") {
acc[column.id] = {
id: column.id,
value: filter?.value || [],
filterFn: filter?.fn || column._filterFn,
datatype: column.datatype,
};
} else if (column._filterFn === "between") {
acc[column.id] = {
id: column.id,
value: filter?.value || ["", ""],
filterFn: filter?.fn || column._filterFn,
datatype: column.datatype,
};
} else {
acc[column.id] = {
id: column.id,
value: filter?.value || "",
filterFn: filter?.fn || column._filterFn,
datatype: column.datatype,
};
}
return acc;
}, {});
setInitialValues(Object.keys(filterData).length !== 0 ? filterData : values);
setInitialValues(filterData);
}, [columns, settingStore, user_id, page_name, table_name, filterData]);
useEffect(() => {
@@ -107,49 +72,16 @@ function FilterBody({ columns, drawerState, setDrawerState, user_id, page_name,
}, [initialValues]);
const handleSubmit = (values, { setSubmitting }) => {
toast.dismiss({ containerId: "filtering" });
setDrawerState(false);
setFilterData(values);
toast(<AskForKeep onSaveFilter={onSaveFilter} />, {
containerId: "filtering",
className: "filter-toast",
position: "bottom-left",
draggable: true,
autoClose: false,
});
setSubmitting(false);
};
const onSaveFilter = () => {
const currentFilterData = filterDataRef.current;
const arrayOfObjects = Object.keys(currentFilterData)
.map((key) => {
const value = currentFilterData[key].value;
if (
value !== "" &&
!(
Array.isArray(value) &&
(value.length === 0 || (value.length === 2 && value[0] === "" && value[1] === ""))
)
) {
return currentFilterData[key];
}
})
.filter(Boolean);
filterAction(user_id, page_name, table_name, arrayOfObjects, columns);
toast.dismiss({ containerId: "filtering" });
};
return (
<Drawer
open={drawerState}
onClose={() => setDrawerState(false)}
sx={{
overflowY: "hidden",
display: "flex",
flexDirection: "column",
height: "100%",
}}
sx={{ overflowY: "hidden", display: "flex", flexDirection: "column", height: "100%" }}
>
<FilterHeader setDrawerState={setDrawerState} />
{Object.keys(initialValues).length > 0 && (
@@ -203,9 +135,9 @@ function FilterBody({ columns, drawerState, setDrawerState, user_id, page_name,
px: 8,
boxShadow:
"rgba(0, 0, 0, 0.23) 0px 6px 6px, rgba(0, 0, 0, 0.19) 10px 0px 20px",
backgroundColor: "#155175",
backgroundColor: "primary2",
":hover": {
backgroundColor: "#155175",
backgroundColor: "primary2",
},
}}
>

View File

@@ -32,12 +32,7 @@ function FilterOptionList({
key={index}
onClick={(event) => handleChangeItem(event, index)}
selected={option === selectedFilter}
sx={{
cursor: "pointer",
width: "100px",
display: "flex",
justifyContent: "center",
}}
sx={{ cursor: "pointer", width: "100px", display: "flex", justifyContent: "center" }}
>
{columnFilterModeOptionFa[option]}
</ListItem>

View File

@@ -7,7 +7,6 @@ import ClearIcon from "@mui/icons-material/Clear";
import moment from "jalali-moment";
function MuiDatePicker({ value, setFieldValue, name, minDate, maxDate, helperText, placeholder, error }) {
return (
<Box sx={{ display: "flex", flexDirection: "column", my: 1 }}>
<LocalizationProvider

View File

@@ -214,9 +214,9 @@ const DataTable_TableHeadCell = ({ columnVirtualizer, header, staticColumnIndex,
minWidth: `${Math.min(columnDef.header?.length ?? 0, 4)}ch`,
overflow: columnDefType === "data" ? "hidden" : undefined,
textOverflow: "ellipsis",
textAlign: "start",
color: "#fff",
fontSize: "14px",
fontWeight: "500",
fontWeight: "400",
whiteSpace: (columnDef.header?.length ?? 0) < 20 ? "nowrap" : "normal",
}}
>

View File

@@ -3,7 +3,12 @@ import DataTableProvider from "@/lib/contexts/DataTable";
const DataTable = (props) => {
return (
<DataTableProvider>
<DataTableProvider
user_id={props.user_id}
page_name={props.page_name}
table_name={props.table_name}
columns={props.columns}
>
<DataTable_Main {...props} />
</DataTableProvider>
);

View File

@@ -1,17 +1,10 @@
"use client";
import { IconButton, Tooltip } from "@mui/material";
import RestartAltIcon from "@mui/icons-material/RestartAlt";
import useTableSetting from "@/lib/hooks/useTableSetting";
import { useState } from "react";
function RefactorTable() {
const { refactorAction } = useTableSetting();
const [userId, setUserId] = useState(0);
const [pageName, setPageName] = useState("testPage");
const [tableName, setTableName] = useState("testTable");
function RefactorTable({ mutate }) {
const refactor = () => {
refactorAction(userId, pageName, tableName);
mutate();
};
return (

View File

@@ -4,7 +4,17 @@ import DataTable_BottomToolbar from "../toolbar/BottomToolbar";
import DataTable_TopToolbar from "../toolbar/TopToolbar";
import DataTable_TableContainer from "./TableContainer";
const DataTable_Paper = ({ table, ...rest }) => {
const DataTable_Paper = ({
table,
table_name,
columns,
user_id,
page_name,
mutate,
need_filter,
table_url,
...rest
}) => {
const {
getState,
options: {
@@ -66,12 +76,14 @@ const DataTable_Paper = ({ table, ...rest }) => {
{enableTopToolbar &&
(parseFromValuesOrFunc(renderTopToolbar, { table }) ?? (
<DataTable_TopToolbar
need_filter={need_filter}
table={table}
columns={paperProps.columns}
table_url={paperProps.table_url}
user_id={paperProps.user_id}
page_name={paperProps.page_name}
table_name={paperProps.table_name}
mutate={mutate}
columns={columns}
table_url={table_url}
user_id={user_id}
page_name={page_name}
table_name={table_name}
/>
))}
<DataTable_TableContainer table={table} />

View File

@@ -6,7 +6,7 @@ import DataTable_ToolbarInternalButtons from "./ToolbarInternalButtons";
import FilterColumn from "@/core/components/DataTable/filter";
import RefactorTable from "@/core/components/DataTable/refactor/RefactorTable";
const DataTable_TopToolbar = ({ table, columns, table_url, user_id, page_name, table_name }) => {
const DataTable_TopToolbar = ({ mutate, need_filter, table, columns, table_url, user_id, page_name, table_name }) => {
const {
getState,
options: {
@@ -69,14 +69,16 @@ const DataTable_TopToolbar = ({ table, columns, table_url, user_id, page_name, t
justifyContent: "flex-end",
}}
>
<RefactorTable />
<FilterColumn
columns={columns}
table_url={table_url}
user_id={user_id}
page_name={page_name}
table_name={table_name}
/>
<RefactorTable mutate={mutate} />
{need_filter && (
<FilterColumn
columns={columns}
table_url={table_url}
user_id={user_id}
page_name={page_name}
table_name={table_name}
/>
)}
<DataTable_ToolbarInternalButtons table={table} />
</Box>
)}

View File

@@ -0,0 +1,8 @@
import { Slide } from "@mui/material";
import React from "react";
const DialogTransition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
export default DialogTransition

View File

@@ -0,0 +1,10 @@
import { TextField, styled } from "@mui/material";
const LtrTextField = styled(TextField)`
.MuiInputBase-input {
/* @noflip */
direction: ltr;
}
`;
export default LtrTextField;

View File

@@ -0,0 +1,17 @@
import { Box, LinearProgress, Stack } from "@mui/material";
function MapLoading() {
return (
<Stack
sx={{ height: "100%" }}
alignItems={"center"}
justifyContent={"center"}
>
<Box sx={{ width: 200 }}>
<LinearProgress />
</Box>
</Stack>
);
}
export default MapLoading;

View File

@@ -0,0 +1,32 @@
import { useRef } from "react";
import { Marker, useMapEvents } from "react-leaflet";
const prefix = process.env.NODE_ENV === "production" ? "/v3" : "";
const locationMarker = L.icon({
iconUrl: prefix + "/images/locationMarker.png",
iconSize: [50, 50],
iconAnchor: [25, 50],
});
const MarkerLocation = ({ setValue }) => {
const location = useRef();
const map = useMapEvents({
move: (e) => {
const latlon = e.target.getCenter()
location.current?.setLatLng(latlon);
setValue('lat', latlon.lat)
setValue('lon', latlon.lng)
},
zoom: (e) => {
const latlon = e.target.getCenter()
location.current?.setLatLng(latlon);
setValue('lat', latlon.lat)
setValue('lon', latlon.lng)
},
});
return (
<Marker ref={location} icon={locationMarker} position={map.getCenter()} key="location" />
)
}
export default MarkerLocation

View File

@@ -0,0 +1,43 @@
"use client";
import { MapContainer, TileLayer, useMap } from "react-leaflet";
export const IRAN_CENTER = L.latLng(32.4279, 53.6880);
const MapOptions = ({ options }) => {
const map = useMap();
if (!options) return;
if (options.mapDrag) {
map.dragging.enable();
map.scrollWheelZoom.enable();
map.touchZoom.enable();
map.doubleClickZoom.enable();
} else {
map.dragging.disable();
map.scrollWheelZoom.disable();
map.touchZoom.disable();
map.doubleClickZoom.disable();
}
};
function MapLayer({ children, style, otherLayers, options }) {
return (
<>
<MapContainer
style={{ width: "100%", height: "100%", ...style }}
center={IRAN_CENTER}
zoom={6}
zoomControl={false}
attributionControl={false}
{...options}
>
<MapOptions options={options} />
<TileLayer url={`${process.env.NEXT_PUBLIC_MAPTILE_ENDPOINT}/{z}/{x}/{y}.png`} />
{children}
</MapContainer>
{otherLayers}
</>
);
}
export default MapLayer;

View File

@@ -4,29 +4,46 @@ import SaveIcon from "@mui/icons-material/Save";
import { Box, Button, Typography } from "@mui/material";
import DownloadIcon from "@mui/icons-material/Download";
import { toast } from "react-toastify";
import useTableSetting from "@/lib/hooks/useTableSetting";
function AskForKeepData({ filterData, sortData, user_id, page_name, table_name, columns }) {
const { filterAction, sortAction } = useTableSetting();
const onSaveFilter = () => {
const filteredItems = Object.keys(filterData)
.map((key) => {
const value = filterData[key].value;
if (
value !== "" &&
!(
Array.isArray(value) &&
(value.length === 0 || (value.length === 2 && value[0] === "" && value[1] === ""))
)
) {
return filterData[key];
}
})
.filter(Boolean);
filterAction(user_id, page_name, table_name, filteredItems, columns);
sortAction(user_id, page_name, table_name, sortData, columns);
toast.dismiss({ containerId: "datatable" });
};
function AskForKeep({ onSaveFilter }) {
const handleDismiss = () => {
toast.dismiss({ containerId: "filtering" });
toast.dismiss({ containerId: "datatable" });
};
return (
<Box sx={{ width: "100%" }}>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
mb: 1,
}}
>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", mb: 1 }}>
<Typography color="#155175" variant="subtitle1" sx={{ fontWeight: "500" }}>
ذخیره سازی اطلاعات
ذخیره سازی تغییرات
</Typography>
<SaveIcon sx={{ color: "#155175" }} />
</Box>
<Box sx={{ display: "flex", flexDirection: "column" }}>
<Typography variant="caption">آیا مایل به ذخیره فیلتر های اعمال شده برای دفعات بعد هستید؟</Typography>
<Typography variant="caption">آیا مایل به ذخیره تغییر های اعمال شده برای دفعات بعد هستید؟</Typography>
</Box>
<Box sx={{ display: "flex", gap: 1, mt: 1 }}>
<Button
@@ -51,11 +68,11 @@ function AskForKeep({ onSaveFilter }) {
boxShadow: "rgba(0, 0, 0, 0.23) 0px 6px 6px, rgba(0, 0, 0, 0.19) 10px 0px 20px",
}}
>
ذخیره فیلتر
ذخیره
</Button>
</Box>
</Box>
);
}
export default AskForKeep;
export default AskForKeepData;

View File

@@ -7,95 +7,80 @@ import { useEffect, useReducer, useState } from "react";
import { filterMenuItems } from "../utils/filterMenuItems";
import { pageMenu } from "../utils/pageMenu";
function selectPage(item, route) {
if (item.type === "page") {
return {
...item,
selected: item.route === route,
showSubitems: item.route === route,
};
} else if (item.Subitems && Array.isArray(item.Subitems)) {
const updatedSubitems = item.Subitems.map((subitem) => selectPage(subitem, route));
return {
...item,
Subitems: updatedSubitems,
showSubitems: updatedSubitems.some((subitem) => subitem.showSubitems || subitem.route === route),
};
}
return item;
}
function reducer(state, action) {
switch (action.type) {
case "UPDATE_MENU":
const _permissions = action.permissions || []
const filteredPageMenu = filterMenuItems(pageMenu, ['all', ..._permissions])
return filteredPageMenu
const _permissions = action.permissions || [];
const filteredPageMenu = filterMenuItems(state, ["all", ..._permissions]);
return filteredPageMenu;
case "COLLAPSE_MENU":
return state.map((item) =>
action.id == item.id
? {
...item,
showSubitems: !item.showSubitems,
}
...item,
showSubitems: !item.showSubitems,
}
: item
);
case "COLLAPSE_SUB_ITEMS":
return state.map((item) => {
return item.hasSubitems
? {
...item,
Subitems: item.Subitems.map((subitem) =>
action.id === subitem.id
? {
...subitem,
showSubitems: !subitem.showSubitems,
}
: subitem
),
}
...item,
Subitems: item.Subitems.map((subitem) =>
action.id === subitem.id
? {
...subitem,
showSubitems: !subitem.showSubitems,
}
: 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,
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;
});
case "SELECTED":
return state.map((item) => {
return item.type === "page"
? {
...item,
selected: action.route === item.route,
showSubitems: item.route === action.route,
}
: item.Subitems && Array.isArray(item.Subitems)
? {
...item,
Subitems: item.Subitems.map((subitem) => {
return subitem.type === "page"
? {
...subitem,
selected: action.route === subitem.route,
showSubitems: subitem.route === action.route,
}
: subitem.Subitems && Array.isArray(subitem.Subitems)
? {
...subitem,
Subitems: subitem.Subitems.map((secondSubItem) => ({
...secondSubItem,
selected: secondSubItem.route === action.route,
})),
showSubitems: subitem.Subitems.some(
(secondSubItem) => secondSubItem.route === action.route
),
}
: subitem;
}),
showSubitems: item.Subitems.some((subitem) => subitem.showSubitems),
}
: item;
});
return state.map((item) => selectPage(item, action.route));
default:
throw new Error();
@@ -103,19 +88,20 @@ function reducer(state, action) {
}
const SidebarMenu = () => {
const { data: userPermissions } = usePermissions()
const { data: userPermissions } = usePermissions();
const [menuItems, dispatch] = useReducer(reducer, pageMenu);
const pathname = usePathname();
const [selectedKey, setSelectedKey] = useState(null);
useEffect(() => {
dispatch({ type: 'UPDATE_MENU', permissions: userPermissions });
}, [userPermissions])
useEffect(() => {
dispatch({ type: "SELECTED", route: pathname });
setSelectedKey(pathname);
}, [pathname]);
}, [userPermissions, pathname]);
useEffect(() => {
if (!userPermissions) return;
dispatch({ type: "UPDATE_MENU", permissions: userPermissions });
}, [userPermissions]);
useEffect(() => {
selectedKey &&
@@ -126,11 +112,13 @@ const SidebarMenu = () => {
}, [selectedKey]);
return (
<List disablePadding dense>
{menuItems.map((menuItem) => {
return <SidebarListItems dispatch={dispatch} key={menuItem.id} menuItem={menuItem} />;
})}
</List>
userPermissions && (
<List disablePadding dense>
{menuItems.map((menuItem) => {
return <SidebarListItems dispatch={dispatch} key={menuItem.id} menuItem={menuItem} />;
})}
</List>
)
);
};
export default SidebarMenu;

View File

@@ -0,0 +1,5 @@
import { styled } from "@mui/material";
const StyledForm = styled('form')``;
export default StyledForm;

View File

@@ -1,7 +1,7 @@
export function filterMenuItems(items, _permissions = []) {
return items.reduce((acc, item) => {
if (item.permissions) {
if (item.permissions.some(permission => _permissions.includes(permission))) {
if (item.permissions.some((permission) => _permissions.includes(permission))) {
acc.push(item);
}
} else if (item.hasSubitems) {
@@ -14,4 +14,4 @@ export function filterMenuItems(items, _permissions = []) {
}
return acc;
}, []);
}
}

View File

@@ -1,5 +1,5 @@
import { Security } from "@mui/icons-material";
const prefix = process.env.NODE_ENV === 'production' ? '/v3' : ''
const prefix = process.env.NODE_ENV === "production" ? "/v3" : "";
export const pageMenu = [
{
@@ -8,7 +8,7 @@ export const pageMenu = [
type: "page",
route: prefix + "/dashboard",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"]
permissions: ["all"],
},
{
id: "userManagement",
@@ -16,7 +16,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/user_management",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['full-user-management', 'limited-user-management']
permissions: ["full-user-management", "limited-user-management"],
},
{
id: "projectsManagment",
@@ -31,7 +31,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/finance",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-contract', 'show-contract-province'],
permissions: ["show-contract", "show-contract-province"],
},
{
id: "projectsManagmentList",
@@ -39,7 +39,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/projects_list",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"]
permissions: ["all"],
},
{
id: "projectsManagmentProposal",
@@ -47,7 +47,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/proposal",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-proposal', 'show-proposal-province']
permissions: ["show-proposal", "show-proposal-province"],
},
{
id: "projectsManagmentLawmaker",
@@ -55,7 +55,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/lawmakers",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-lawmaker', 'show-lawmaker-province']
permissions: ["show-lawmaker", "show-lawmaker-province"],
},
{
id: "projectsManagmentMap",
@@ -63,7 +63,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=rahdari_projects",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"]
permissions: ["all"],
},
],
},
@@ -86,7 +86,10 @@ export const pageMenu = [
label: "کارتابل",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/supervisor/cartable",
permissions: ['show-road-item-supervise-cartable', 'show-road-item-supervise-cartable-province']
permissions: [
"show-road-item-supervise-cartable",
"show-road-item-supervise-cartable-province",
],
},
],
},
@@ -102,14 +105,14 @@ export const pageMenu = [
label: "ثبت فعالیت",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/operator/create",
permissions: ['create-road-item']
permissions: ["create-road-item"],
},
{
id: "roadItemManagmentOparationCartable",
label: "کارتابل",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/operator/cartable",
permissions: ['create-road-item']
permissions: ["create-road-item"],
},
],
},
@@ -119,7 +122,11 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_items",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-road-item-supervise-cartable', 'show-road-item-supervise-cartable-province', 'create-road-item']
permissions: [
"show-road-item-supervise-cartable",
"show-road-item-supervise-cartable-province",
"create-road-item",
],
},
{
id: "roadItemManagmentReport",
@@ -127,7 +134,11 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/report",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-road-item-supervise-cartable', 'show-road-item-supervise-cartable-province', 'create-road-item']
permissions: [
"show-road-item-supervise-cartable",
"show-road-item-supervise-cartable-province",
"create-road-item",
],
},
],
},
@@ -150,7 +161,10 @@ export const pageMenu = [
label: "کارتابل",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/road_patrols/supervisor/cartable",
permissions: ['show-road-patrol-supervise-cartable', 'show-road-patrol-supervise-cartable-province']
permissions: [
"show-road-patrol-supervise-cartable",
"show-road-patrol-supervise-cartable-province",
],
},
],
},
@@ -166,14 +180,14 @@ export const pageMenu = [
label: "ثبت اقدام",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/operator/create",
permissions: ['add-road-patrol']
permissions: ["add-road-patrol"],
},
{
id: "roadPatrolManagmentOparationCartable",
label: "کارتابل",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/operator/cartable",
permissions: ['add-road-patrol']
permissions: ["add-road-patrol"],
},
],
},
@@ -183,7 +197,11 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_patrols",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['add-road-patrol', 'show-road-patrol-supervise-cartable', 'show-road-patrol-supervise-cartable-province']
permissions: [
"add-road-patrol",
"show-road-patrol-supervise-cartable",
"show-road-patrol-supervise-cartable-province",
],
},
{
id: "roadPatrolManagmentReport",
@@ -191,7 +209,41 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/report",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['add-road-patrol', 'show-road-patrol-supervise-cartable', 'show-road-patrol-supervise-cartable-province']
permissions: [
"add-road-patrol",
"show-road-patrol-supervise-cartable",
"show-road-patrol-supervise-cartable-province",
],
},
],
},
{
id: "inquiryPrivacyManagment",
label: "استعلام حریم راه",
type: "menu",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true,
Subitems: [
{
id: "inquiryPrivacyManagmentFencing",
label: "احداث و بهره برداری دیوارکشی و مستحدثات",
type: "page",
route: prefix + "/dashboard/inquiry_privacy/fencing",
permissions: ["all"],
},
{
id: "inquiryPrivacyManagmentRoad",
label: "احداث راه دسترسی اختصاصی",
type: "page",
route: prefix + "/dashboard/inquiry_privacy/road",
permissions: ["all"],
},
{
id: "inquiryPrivacyManagmentInfrastructure",
label: "احداث و بهره برداری تاسیسات زیربنایی",
type: "page",
route: prefix + "/dashboard/inquiry_privacy/infrastructure",
permissions: ["all"],
},
],
},
@@ -214,14 +266,18 @@ export const pageMenu = [
label: "ثبت فعالیت",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/safety_and_privacy/operator/first_step",
permissions: ['add-safety-and-privacy']
permissions: ["add-safety-and-privacy"],
},
{
id: "safetyAndPrivacyManagmentOparationCartable",
label: "کارتابل",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/safety_and_privacy/operator/cartable",
permissions: ['show-safety-and-privacy-operator-cartable', 'show-safety-and-privacy-operator-cartable-province', 'show-safety-and-privacy-operator-cartable-edarate-shahri']
permissions: [
"show-safety-and-privacy-operator-cartable",
"show-safety-and-privacy-operator-cartable-province",
"show-safety-and-privacy-operator-cartable-edarate-shahri",
],
},
],
},
@@ -231,8 +287,12 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=safety_and_privacy",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-safety-and-privacy-operator-cartable', 'show-safety-and-privacy-operator-cartable-province',
'show-safety-and-privacy-operator-cartable-edarate-shahri', 'add-safety-and-privacy']
permissions: [
"show-safety-and-privacy-operator-cartable",
"show-safety-and-privacy-operator-cartable-province",
"show-safety-and-privacy-operator-cartable-edarate-shahri",
"add-safety-and-privacy",
],
},
{
id: "safetyAndPrivacyManagmentReport",
@@ -240,8 +300,12 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/safety_and_privacy/report",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-safety-and-privacy-operator-cartable', 'show-safety-and-privacy-operator-cartable-province',
'show-safety-and-privacy-operator-cartable-edarate-shahri', 'add-safety-and-privacy']
permissions: [
"show-safety-and-privacy-operator-cartable",
"show-safety-and-privacy-operator-cartable-province",
"show-safety-and-privacy-operator-cartable-edarate-shahri",
"add-safety-and-privacy",
],
},
],
},
@@ -264,7 +328,7 @@ export const pageMenu = [
label: "کارتابل",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/supervisor/cartable",
permissions: ['supervise-fast-react', 'supervise-fast-react-province']
permissions: ["supervise-fast-react", "supervise-fast-react-province"],
},
],
},
@@ -274,7 +338,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-fast-react', 'show-fast-react-province', 'show-fast-react-edarate-shahri']
permissions: ["show-fast-react", "show-fast-react-province", "show-fast-react-edarate-shahri"],
},
{
id: "roadObservationsManagmentOparation",
@@ -288,7 +352,7 @@ export const pageMenu = [
label: "کارتابل",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/operator/cartable",
permissions: ['show-fast-react', 'show-fast-react-province', 'show-fast-react-edarate-shahri']
permissions: ["show-fast-react", "show-fast-react-province", "show-fast-react-edarate-shahri"],
},
],
},
@@ -298,7 +362,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_observations",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"]
permissions: ["all"],
},
{
id: "roadObservationsManagmentReport",
@@ -306,7 +370,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/report/index",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"]
permissions: ["all"],
},
],
},
@@ -323,7 +387,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/winter_camp",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-camp', 'show-camp-province']
permissions: ["show-camp", "show-camp-province"],
},
{
id: "winterCampManagmentFirstRing",
@@ -331,7 +395,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=camp",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-camp', 'show-camp-province']
permissions: ["show-camp", "show-camp-province"],
},
{
id: "winterCampManagmentReport",
@@ -339,7 +403,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=campNew",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ['show-camp', 'show-camp-province']
permissions: ["show-camp", "show-camp-province"],
},
],
},
@@ -362,7 +426,7 @@ export const pageMenu = [
label: "کارتابل",
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/receipt",
permissions: ["all"]
permissions: ["all"],
},
],
},
@@ -372,7 +436,7 @@ export const pageMenu = [
type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/receipt/report",
icon: <Security sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"]
permissions: ["all"],
},
],
},

View File

@@ -1,6 +1,10 @@
const api = process.env.NEXT_PUBLIC_API_URL;
export const GET_CSRF = api + "/csrf";
export const GET_USER_ROUTE = api + "/webapi/user/get-permission";
export const GET_LOGIN_ROUTE = api + "/login_dev";
export const GET_INQUIRY_PRIVACY_FENCING_ROUTE = api + "/api/v3/harim/divarkeshi";
export const GET_PERMISSIONS_ROUTE = api + "/webapi/user/get-permission";
export const GET_PERMISSIONS_ROUTE = api + "/webapi/user/get-permission";
export const SET_INQUIRE_PRIVACY_FENCING = api + "/api/v3/harim/divarkeshi/store";

View File

@@ -1,11 +1,110 @@
import { createContext, useState } from "react";
import { createContext, useEffect, useState } from "react";
import { toast } from "react-toastify";
import useTableSetting from "@/lib/hooks/useTableSetting";
import { flattenArrayOfObjects } from "@/core/utils/flattenArrayOfObjects";
import AskForKeepData from "@/core/components/NotificationDesign/AskForKeepData";
export const DataTableContext = createContext();
const DataTableProvider = ({ children }) => {
const DataTableProvider = ({ children, user_id, page_name, table_name, columns }) => {
const { settingStore } = useTableSetting();
const [isInitStates, setInitStates] = useState(false);
const flatColumns = flattenArrayOfObjects(columns, "columns");
const [initFilter, setInitFilter] = useState({});
const [initSort, setInitSort] = useState([]);
const [filterData, setFilterData] = useState({});
const [sortData, setSortData] = useState([]);
return <DataTableContext.Provider value={{ filterData, setFilterData }}>{children}</DataTableContext.Provider>;
useEffect(() => {
if (!settingStore) return;
const values = flatColumns.reduce((acc, column) => {
if (!column.enableColumnFilter) return acc;
const filter = settingStore?.[user_id]?.[page_name]?.[table_name]?.["filters"]?.find(
(filter) => filter.id === column.id
);
if (column.datatype === "array") {
acc[column.id] = {
id: column.id,
value: filter?.value || [],
filterFn: filter?.filterFn || column._filterFn,
datatype: column.datatype,
};
} else if (column._filterFn === "between") {
acc[column.id] = {
id: column.id,
value: filter?.value || ["", ""],
filterFn: filter?.filterFn || column._filterFn,
datatype: column.datatype,
};
} else {
acc[column.id] = {
id: column.id,
value: filter?.value || "",
filterFn: filter?.filterFn || column._filterFn,
datatype: column.datatype,
};
}
return acc;
}, {});
setFilterData(values);
setSortData(settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] || []);
setInitFilter(values);
setInitSort(settingStore?.[user_id]?.[page_name]?.[table_name]?.["sorts"] || []);
setInitStates(true);
}, [settingStore, isInitStates]);
useEffect(() => {
if (
JSON.stringify(initFilter) !== JSON.stringify(filterData) ||
JSON.stringify(initSort) !== JSON.stringify(sortData)
) {
if (!toast.isActive("keep_data", "filtering")) {
toast(
<AskForKeepData
filterData={filterData}
sortData={sortData}
user_id={user_id}
page_name={page_name}
table_name={table_name}
columns={flatColumns}
/>,
{
containerId: "filtering",
toastId: "keep_data",
className: "filter-toast",
position: "bottom-left",
draggable: true,
autoClose: false,
}
);
} else {
toast.update("keep_data", {
containerId: "filtering",
toastId: "keep_data",
render: (
<AskForKeepData
filterData={filterData}
sortData={sortData}
user_id={user_id}
page_name={page_name}
table_name={table_name}
columns={flatColumns}
/>
),
});
}
} else {
toast.dismiss({ containerId: "datatable" });
}
}, [filterData, sortData]);
if (!isInitStates) return null;
return (
<DataTableContext.Provider value={{ filterData, setFilterData, sortData, setSortData }}>
{children}
</DataTableContext.Provider>
);
};
export default DataTableProvider;

View File

@@ -55,23 +55,7 @@ export const TableSettingProvider = ({ children }) => {
localStorage.setItem("_setting-app", JSON.stringify(updatedLocalStorage));
setSettingStore(updatedLocalStorage);
};
const refactorAction = (user_id, page_name, table_name) => {
const prevLocalStorage = JSON.parse(localStorage.getItem("_setting-app")) || {};
const userSettings = prevLocalStorage[user_id] || {};
const pageSettings = userSettings[page_name] || {};
const refactorData = {
...prevLocalStorage,
[user_id]: {
...userSettings,
[page_name]: {
...pageSettings,
[table_name]: {},
},
},
};
localStorage.setItem("_setting-app", JSON.stringify(refactorData));
setSettingStore(refactorData);
};
const SummaryTextMessage = (values, columns) => {
let SummaryText = "";
let HideText = "";
@@ -96,10 +80,7 @@ export const TableSettingProvider = ({ children }) => {
}
if (values.hides) {
const hidesArray = Object.entries(values.hides).map((e) => ({
id: e[0],
value: e[1],
}));
const hidesArray = Object.entries(values.hides).map((e) => ({ id: e[0], value: e[1] }));
if (hidesArray.length > 0) {
const _list = [];
for (const hide of hidesArray) {
@@ -136,15 +117,7 @@ export const TableSettingProvider = ({ children }) => {
};
return (
<TableSettingContext.Provider
value={{
settingStore,
hideAction,
sortAction,
filterAction,
refactorAction,
}}
>
<TableSettingContext.Provider value={{ settingStore, hideAction, sortAction, filterAction }}>
{children}
</TableSettingContext.Provider>
);

View File

@@ -2,8 +2,8 @@ import { useContext } from "react";
import { DataTableContext } from "@/lib/contexts/DataTable";
const useTableSetting = () => {
const { filterData, setFilterData } = useContext(DataTableContext);
return { filterData, setFilterData };
const { filterData, setFilterData, sortData, setSortData } = useContext(DataTableContext);
return { filterData, setFilterData, sortData, setSortData };
};
export default useTableSetting;

View File

@@ -3,16 +3,16 @@ import useSWR from "swr";
import useRequest from "./useRequest";
export const usePermissions = () => {
const request = useRequest()
const request = useRequest();
const fetcher = async (url) => {
try {
const response = await request(url)
return response.data.data
const response = await request(url);
return response.data.data;
} catch (error) {
throw new Error();
}
};
return useSWR(GET_PERMISSIONS_ROUTE, fetcher, { keepPreviousData: true });
}
};

View File

@@ -1,7 +1,18 @@
import { errorResponse } from "@/core/utils/errorResponse";
import { GET_CSRF } from "@/core/utils/routes";
import { successRequest } from "@/core/utils/successRequest";
import axios from "axios";
const getCsrfToken = async () => {
try {
const response = await axios.get(GET_CSRF);
return response.data.data;
} catch (error) {
console.error("Error fetching CSRF token:", error);
throw error;
}
};
const defaultOptions = {
data: {},
requestOptions: {
@@ -15,13 +26,27 @@ const defaultOptions = {
};
const useRequest = (initOptions) => {
const instance = axios.create();
instance.interceptors.request.use(
async function (config) {
if (config.method !== 'get') {
const csrfToken = await getCsrfToken();
config.headers['X-CSRF-TOKEN'] = csrfToken;
}
return config;
},
function (error) {
return Promise.reject(error);
}
);
const _options = Object.assign({}, defaultOptions, initOptions);
return async (url = "", method = "get", options) => {
const mergedOptions = Object.assign({}, _options, options);
try {
const response = await axios({
const response = await instance({
url,
method,
data: method === "get" ? null : mergedOptions.data,

View File

@@ -2,8 +2,8 @@ import { useContext } from "react";
import { TableSettingContext } from "../contexts/tableSetting";
const useTableSetting = () => {
const { settingStore, hideAction, sortAction, filterAction, refactorAction } = useContext(TableSettingContext);
return { settingStore, hideAction, sortAction, filterAction, refactorAction };
const { settingStore, hideAction, sortAction, filterAction } = useContext(TableSettingContext);
return { settingStore, hideAction, sortAction, filterAction };
};
export default useTableSetting;