Feature/refahi register
This commit is contained in:
138
src/core/components/EditedDatePicker.jsx
Normal file
138
src/core/components/EditedDatePicker.jsx
Normal file
@@ -0,0 +1,138 @@
|
||||
import { FormControl, FormHelperText } from "@mui/material";
|
||||
import Button from "@mui/material/Button";
|
||||
import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali";
|
||||
import { DatePicker } from "@mui/x-date-pickers/DatePicker";
|
||||
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
|
||||
import { faIR } from "@mui/x-date-pickers/locales";
|
||||
import moment from "jalali-moment";
|
||||
import { useState, useMemo } from "react";
|
||||
|
||||
function DynamicButtonField(props) {
|
||||
const {
|
||||
label,
|
||||
id,
|
||||
disabled,
|
||||
InputProps: { ref } = {},
|
||||
inputProps: { "aria-label": ariaLabel } = {},
|
||||
error,
|
||||
selectedDate,
|
||||
buttonLabel,
|
||||
onClick,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Button
|
||||
sx={{ width: "100%", padding: 0.8 }}
|
||||
variant="outlined"
|
||||
color={error ? "error" : "primary"}
|
||||
id={id}
|
||||
disabled={disabled}
|
||||
ref={ref}
|
||||
aria-label={ariaLabel}
|
||||
onClick={onClick}
|
||||
>
|
||||
{selectedDate ? `${buttonLabel} : ${selectedDate}` : buttonLabel ? buttonLabel : label}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
function DynamicDatePicker({
|
||||
formik,
|
||||
fieldName,
|
||||
label,
|
||||
disabled,
|
||||
minDate,
|
||||
maxDate,
|
||||
errorText,
|
||||
helperText,
|
||||
buttonLabel,
|
||||
onChange,
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const computedMinMaxDates = useMemo(() => {
|
||||
const today = moment();
|
||||
const min = minDate ? moment(minDate, "jYYYY-jMM-jDD").toDate() : null;
|
||||
const max = maxDate ? moment(maxDate, "jYYYY-jMM-jDD").toDate() : null;
|
||||
return { min, max };
|
||||
}, [minDate, maxDate]);
|
||||
|
||||
const selectedDate = useMemo(() => {
|
||||
if (formik.values[fieldName]) {
|
||||
return moment(formik.values[fieldName]).locale("fa").format("YYYY/MM/DD");
|
||||
}
|
||||
return null;
|
||||
}, [formik.values, fieldName]);
|
||||
|
||||
return (
|
||||
<DatePicker
|
||||
slots={{ field: DynamicButtonField }}
|
||||
slotProps={{
|
||||
field: {
|
||||
setOpen,
|
||||
selectedDate,
|
||||
buttonLabel,
|
||||
error: formik.touched[fieldName] && Boolean(formik.errors[fieldName]),
|
||||
helperText: helperText || formik.errors[fieldName],
|
||||
onClick: () => setOpen((prev) => !prev),
|
||||
},
|
||||
}}
|
||||
label={label}
|
||||
disabled={disabled}
|
||||
disableFuture
|
||||
open={open}
|
||||
minDate={computedMinMaxDates.min}
|
||||
maxDate={computedMinMaxDates.max}
|
||||
value={formik.values[fieldName] ? formik.values[fieldName].toDate() : null}
|
||||
onChange={(newValue) => {
|
||||
const formattedValue = moment(newValue);
|
||||
formik.setFieldValue(fieldName, formattedValue);
|
||||
onChange?.(formattedValue);
|
||||
}}
|
||||
onClose={() => setOpen(false)}
|
||||
onOpen={() => setOpen(true)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PickerWithDynamicField({
|
||||
formik,
|
||||
fieldName,
|
||||
label,
|
||||
disabled = false,
|
||||
minDate,
|
||||
maxDate,
|
||||
buttonLabel,
|
||||
errorText,
|
||||
helperText,
|
||||
}) {
|
||||
return (
|
||||
<FormControl variant="outlined" fullWidth size="small">
|
||||
<LocalizationProvider
|
||||
dateAdapter={AdapterDateFnsJalali}
|
||||
localeText={{
|
||||
...faIR.components.MuiLocalizationProvider.defaultProps.localeText,
|
||||
okButtonLabel: "تایید",
|
||||
}}
|
||||
>
|
||||
<DynamicDatePicker
|
||||
onChange={(newValue) => {
|
||||
formik.setFieldValue(fieldName, moment(newValue));
|
||||
}}
|
||||
formik={formik}
|
||||
fieldName={fieldName}
|
||||
label={label}
|
||||
disabled={disabled}
|
||||
minDate={minDate}
|
||||
maxDate={maxDate}
|
||||
buttonLabel={buttonLabel}
|
||||
errorText={errorText}
|
||||
helperText={helperText}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
<FormHelperText error={Boolean(formik.errors[fieldName])}>
|
||||
{formik.touched[fieldName] && formik.errors[fieldName]}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
@@ -24,7 +24,8 @@ function ButtonField(props) {
|
||||
sx={{ width: "100%", padding: 0.8 }}
|
||||
variant="outlined"
|
||||
color={
|
||||
props.slotProps.formik.touched.company_date && Boolean(props.slotProps.formik.errors.company_date)
|
||||
props.slotProps.formik.touched.company_register_date &&
|
||||
Boolean(props.slotProps.formik.errors.company_register_date)
|
||||
? "error"
|
||||
: "primary"
|
||||
}
|
||||
@@ -50,7 +51,7 @@ function ButtonDatePicker(props) {
|
||||
formik: props.formik,
|
||||
field: { setOpen },
|
||||
textField: {
|
||||
helperText: props.formik.errors.company_date ? `${t("company_date")}` : null,
|
||||
helperText: props.formik.errors.company_register_date ? `${t("company_date")}` : null,
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
@@ -74,18 +75,24 @@ const LegalPersonDatePicker = ({ formik, disabled }) => {
|
||||
>
|
||||
<ButtonDatePicker
|
||||
label={
|
||||
formik.values.company_date !== "" &&
|
||||
formik.values.company_date?.locale("fa").format("YYYY/MM/DD")
|
||||
formik.values.company_register_date !== "" &&
|
||||
formik.values.company_register_date?.locale("fa").format("YYYY/MM/DD")
|
||||
}
|
||||
value={
|
||||
formik.values.company_register_date !== ""
|
||||
? formik.values.company_register_date?.toDate()
|
||||
: null
|
||||
}
|
||||
value={formik.values.company_date !== "" ? formik.values.company_date?.toDate() : null}
|
||||
formik={formik}
|
||||
disabled={disabled}
|
||||
onChange={(newValue) => {
|
||||
formik.setFieldValue("company_date", moment(newValue));
|
||||
formik.setFieldValue("company_register_date", moment(newValue));
|
||||
}}
|
||||
/>
|
||||
</LocalizationProvider>
|
||||
<FormHelperText>{formik.touched.company_date && formik.errors.company_date}</FormHelperText>
|
||||
<FormHelperText>
|
||||
{formik.touched.company_register_date && formik.errors.company_register_date}
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,156 +1,95 @@
|
||||
import { Box, Button, FormHelperText, TextField, Typography } from "@mui/material";
|
||||
import { useTranslations } from "next-intl";
|
||||
import Image from "next/image";
|
||||
import { Box, Button, Paper, Typography } from "@mui/material";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
|
||||
import { useRef, useState } from "react";
|
||||
import { useRef } from "react";
|
||||
|
||||
const UploadSystem = ({
|
||||
fieldName,
|
||||
default_image,
|
||||
helperText,
|
||||
error,
|
||||
setFieldValue,
|
||||
imageAlt,
|
||||
label,
|
||||
enableDelete,
|
||||
}) => {
|
||||
const t = useTranslations();
|
||||
const UploadSystem = ({ selectedImage, handleUploadChange, imageSize, fileType, showAddIcon }) => {
|
||||
const fileInputRef = useRef(null);
|
||||
const [selectedImage, setSelectedImage] = useState(default_image || "/images/upload-image.svg");
|
||||
const [fileType, setFileType] = useState(null);
|
||||
const [fileName, setFileName] = useState("");
|
||||
|
||||
// upload files
|
||||
const handleUploadChange = (event) => {
|
||||
const uploadedFile = event.target?.files?.[0];
|
||||
if (uploadedFile) {
|
||||
setSelectedImage(URL.createObjectURL(uploadedFile));
|
||||
setFileType(uploadedFile.type);
|
||||
setFileName(uploadedFile.name);
|
||||
setFieldValue(fieldName, uploadedFile);
|
||||
}
|
||||
};
|
||||
// end upload files
|
||||
|
||||
const uploadBoxStyle = error
|
||||
? {
|
||||
cursor: "pointer",
|
||||
objectFit: "contain",
|
||||
border: "1px dashed #d32f2f",
|
||||
borderRadius: "5px",
|
||||
padding: "5px",
|
||||
}
|
||||
: {
|
||||
cursor: "pointer",
|
||||
objectFit: "contain",
|
||||
border: "1px dashed #e1e1e1",
|
||||
borderRadius: "5px",
|
||||
padding: "5px",
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
fileInputRef.current.click();
|
||||
};
|
||||
const handleDeleteImage = () => {
|
||||
setselectedImage("/images/upload-image.svg");
|
||||
setFieldValue(fieldname, null);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ my: 2 }}>
|
||||
<Typography
|
||||
margin={1}
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
fontSize: "0.9rem",
|
||||
color: "#a19d9d",
|
||||
}}
|
||||
textAlign="center"
|
||||
>
|
||||
{label}
|
||||
</Typography>
|
||||
<Box sx={{ position: "relative" }}></Box>
|
||||
{selectedImage === "/images/upload-image.svg" || selectedImage === default_image ? (
|
||||
<Image
|
||||
src={selectedImage}
|
||||
priority
|
||||
alt={imageAlt}
|
||||
width={200}
|
||||
height={200}
|
||||
onClick={handleClick}
|
||||
style={uploadBoxStyle}
|
||||
/>
|
||||
) : fileType && fileType.startsWith("image/") ? (
|
||||
<Image
|
||||
src={selectedImage}
|
||||
priority
|
||||
alt={imageAlt}
|
||||
width={200}
|
||||
height={200}
|
||||
onClick={handleClick}
|
||||
style={uploadBoxStyle}
|
||||
/>
|
||||
) : (
|
||||
<Box sx={{ width: "100%" }}>
|
||||
{showAddIcon ? (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
border: "1px dashed #e1e1e1",
|
||||
cursor: "pointer",
|
||||
borderRadius: "5px",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "200px",
|
||||
height: "200px",
|
||||
border: 1,
|
||||
borderColor: "divider",
|
||||
borderRadius: 2,
|
||||
cursor: "pointer",
|
||||
padding: "5px",
|
||||
height: imageSize[1],
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<AddIcon sx={{ fontSize: "2rem", color: "#a19d9d" }} />
|
||||
<Typography
|
||||
margin={2}
|
||||
variant="subtitle2"
|
||||
sx={{
|
||||
fontWeight: 600,
|
||||
fontSize: "1rem",
|
||||
fontSize: "0.8rem",
|
||||
color: "#a19d9d",
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
justifyContent: "end",
|
||||
overflow: "hidden",
|
||||
mt: 1,
|
||||
}}
|
||||
textAlign="center"
|
||||
>
|
||||
{fileName}
|
||||
فرمت قابل قبول : png, jpg
|
||||
<br />
|
||||
حداکثر 2Mb
|
||||
</Typography>
|
||||
</Box>
|
||||
) : (
|
||||
<>
|
||||
{fileType && fileType.startsWith("image/") && (
|
||||
<Box
|
||||
width="100%"
|
||||
height={imageSize[1]}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
cursor: "pointer",
|
||||
objectFit: "contain",
|
||||
border: "1px solid #b3b3b3",
|
||||
borderRadius: "10px",
|
||||
padding: "5px",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
backgroundSize: "contain",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center",
|
||||
backgroundImage: `url(${selectedImage})`,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
id="avatar-upload"
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
style={{ display: "none" }}
|
||||
onChange={(e) => handleUploadChange(e)}
|
||||
inputRef={fileInputRef}
|
||||
onChange={handleUploadChange}
|
||||
ref={fileInputRef}
|
||||
/>
|
||||
{enableDelete ? (
|
||||
<Button
|
||||
sx={{
|
||||
width: "100%",
|
||||
borderTopLeftRadius: "unset",
|
||||
borderTopRightRadius: "unset",
|
||||
}}
|
||||
color="error"
|
||||
disabled={selectedImage === "/images/upload-image.svg"}
|
||||
endIcon={<DeleteForeverIcon />}
|
||||
variant="contained"
|
||||
onClick={handleDeleteImage}
|
||||
>
|
||||
{t("delete")}
|
||||
</Button>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<FormHelperText sx={{ color: "#d32f2f" }}>{helperText}</FormHelperText>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default UploadSystem;
|
||||
|
||||
40
src/core/components/notifications/UploadFileNotification.jsx
Normal file
40
src/core/components/notifications/UploadFileNotification.jsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import DangerousIcon from "@mui/icons-material/Dangerous";
|
||||
import { Box, Typography } from "@mui/material";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
const UploadFileNotification = (t) => {
|
||||
toast(
|
||||
({ closeToast }) => (
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "start",
|
||||
justifyContent: "start",
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<DangerousIcon color="error" sx={{ mr: 1.6 }} />
|
||||
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||
<Typography color="error" variant="button">
|
||||
{t("UploadSystem.uploadfile_error")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</>
|
||||
),
|
||||
{
|
||||
containerId: "validation",
|
||||
toastId: "upload",
|
||||
autoClose: 3000,
|
||||
hideProgressBar: true,
|
||||
pauseOnHover: true,
|
||||
closeOnClick: false,
|
||||
draggable: true,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default UploadFileNotification;
|
||||
@@ -27,3 +27,4 @@ export const UPDATE_LOAN = BASE_URL + "/navgan/loan/update/";
|
||||
export const GET_PROJECT_TITLE = BASE_URL + "/navgan_plans";
|
||||
export const GET_ACTIVITY_LIST = BASE_URL + "/activity_types";
|
||||
export const GET_PRIORITY_LIST = BASE_URL + "/activity_priorities";
|
||||
export const SEND_LOAN_REQUEST_REFAHI = BASE_URL + "/refahi/loan/store";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard";
|
||||
import BookmarkAddedIcon from "@mui/icons-material/BookmarkAdded";
|
||||
import DataSaverOnIcon from "@mui/icons-material/DataSaverOn";
|
||||
import VolunteerActivismIcon from "@mui/icons-material/VolunteerActivism";
|
||||
import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
|
||||
|
||||
const sidebarMenu = [
|
||||
[
|
||||
@@ -14,19 +15,30 @@ const sidebarMenu = [
|
||||
permission: "all",
|
||||
},
|
||||
{
|
||||
key: "sidebar.add-request-loan",
|
||||
name: "sidebar.add-request-loan",
|
||||
key: "sidebar.add-request-navgan-loan",
|
||||
name: "sidebar.add-request-navgan-loan",
|
||||
secondary: "secondary.navgan",
|
||||
type: "page",
|
||||
route: "/dashboard/navgan/add-request-loan",
|
||||
icon: <DataSaverOnIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
icon: <DirectionsCarIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
selected: false,
|
||||
permission: "can_request_navgan_loan",
|
||||
},
|
||||
{
|
||||
key: "sidebar.add-request-refahi-loan",
|
||||
name: "sidebar.add-request-refahi-loan",
|
||||
secondary: "secondary.refahi",
|
||||
type: "page",
|
||||
route: "/dashboard/refahi/add-request-loan",
|
||||
icon: <VolunteerActivismIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
selected: false,
|
||||
permission: "can_request_refahi_loan",
|
||||
},
|
||||
{
|
||||
key: "sidebar.followUp-loan",
|
||||
name: "sidebar.followUp-loan",
|
||||
type: "page",
|
||||
route: "/dashboard/navgan/followUp-loan",
|
||||
route: "/dashboard/followUp-loan",
|
||||
icon: <BookmarkAddedIcon sx={{ width: "inherit", height: "inherit" }} />,
|
||||
selected: false,
|
||||
permission: "all",
|
||||
|
||||
Reference in New Issue
Block a user