change some files

This commit is contained in:
2026-06-02 17:08:52 +03:30
parent b8dc1d0e1b
commit cfb48c5bb0
76 changed files with 5204 additions and 2555 deletions

View File

@@ -0,0 +1,207 @@
"use client";
import React from "react";
import {
Box,
MenuItem,
Paper,
TextField,
Typography,
Switch,
FormControlLabel,
Button,
} from "@mui/material";
import { DatePicker } from "@mui/x-date-pickers";
import { Form, type FormikProps } from "formik";
import { format, parseISO, isValid } from "date-fns-jalali";
import type { JobInfoFormProps, JobInfoFormValues } from "./types";
import { retirementOptions } from "./constant";
type Props = FormikProps<JobInfoFormValues> & JobInfoFormProps;
export default function InnerJobInfoForm(props: Props) {
const {
values,
errors,
touched,
handleChange,
setFieldValue,
isSubmitting,
} = props;
const handleBack = () => {
props.update({ jobInfo: values });
props.setStep(props.step - 1);
};
const handleDateChange = (date: Date | null) => {
if (date && isValid(date)) {
const formattedDate = format(date, "yyyy-MM-dd");
setFieldValue("readyToWorkDate", formattedDate);
} else {
setFieldValue("readyToWorkDate", "");
}
};
// Helper برای تبدیل رشته تاریخ به شیء Date جهت نمایش در DatePicker
const getDateValue = () => {
if (!values.readyToWorkDate) return null;
const parsed = parseISO(values.readyToWorkDate);
return isValid(parsed) ? parsed : null;
};
return (
<Form>
<Paper
elevation={0}
sx={{
p: { xs: 2, md: 3 },
borderRadius: "24px",
border: "1px solid #e2e8f0",
backgroundColor: "#fff",
}}
>
<Typography variant="h6" sx={{ mb: 3, fontWeight: "bold" }}>
اطلاعات شغلی و بیمه
</Typography>
<Box
sx={{
display: "grid",
gridTemplateColumns: { xs: "1fr", md: "1fr 1fr" },
gap: 3,
}}
>
{/* تاریخ آمادگی */}
<DatePicker
label="تاریخ آمادگی برای شروع کار*"
value={getDateValue()}
onChange={handleDateChange}
slotProps={{
textField: {
fullWidth: true,
error: !!errors.readyToWorkDate && !!touched.readyToWorkDate,
helperText: touched.readyToWorkDate ? errors.readyToWorkDate : "",
},
}}
/>
{/* وضعیت بازنشستگی */}
<TextField
select
label="وضعیت بازنشستگی*"
name="retirementStatus"
value={values.retirementStatus}
onChange={handleChange}
fullWidth
error={!!errors.retirementStatus && !!touched.retirementStatus}
helperText={touched.retirementStatus ? errors.retirementStatus : ""}
>
{retirementOptions.map((opt) => (
<MenuItem key={opt.value} value={opt.value}>
{opt.label}
</MenuItem>
))}
</TextField>
{/* سوییچ‌ها */}
{[
{ name: "isCurrentEmployee", label: "از پرسنل حال حاضر هستم" },
{ name: "hasPastCooperation", label: "سابقه همکاری در گذشته دارم" },
{ name: "isCurrentlyEmployed", label: "در حال حاضر مشغول به کار هستم" },
{ name: "dualJobInterest", label: "تمایل به شغل دوم دارم" },
{ name: "isMilitary", label: "نظامی هستم" },
].map((sw) => (
<FormControlLabel
key={sw.name}
control={
<Switch
checked={(values as any)[sw.name]}
onChange={(e) => setFieldValue(sw.name, e.target.checked)}
/>
}
label={sw.label}
/>
))}
<FormControlLabel
control={
<Switch
checked={values.hasInsurance}
onChange={(e) => {
const checked = e.target.checked;
setFieldValue("hasInsurance", checked);
if (!checked) {
setFieldValue("insuranceType", "");
setFieldValue("totalInsuranceYears", "0");
}
}}
/>
}
label="دارای سابقه بیمه هستم"
/>
{/* فیلدهای شرطی بیمه */}
{values.hasInsurance && (
<>
<TextField
label="نوع بیمه*"
name="insuranceType"
value={values.insuranceType}
onChange={handleChange}
fullWidth
error={!!errors.insuranceType && !!touched.insuranceType}
helperText={touched.insuranceType ? errors.insuranceType : ""}
/>
<TextField
type="number"
label="جمع سال‌های سابقه بیمه*"
name="totalInsuranceYears"
value={values.totalInsuranceYears}
onChange={handleChange}
fullWidth
error={!!errors.totalInsuranceYears && !!touched.totalInsuranceYears}
helperText={
touched.totalInsuranceYears ? errors.totalInsuranceYears : ""
}
/>
</>
)}
</Box>
{/* Buttons */}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
mt: 4,
}}
>
<Button
disabled={props.step === 1 || isSubmitting}
onClick={handleBack}
sx={{ borderRadius: "12px", color: "#64748b", fontWeight: 700 }}
>
بازگشت
</Button>
<Button
variant="contained"
type="submit"
disabled={isSubmitting}
sx={{
borderRadius: "12px",
px: 4,
py: 1.5,
bgcolor: props.step === 12 ? "green" : "#2563eb",
fontWeight: 700,
}}
>
{props.step === 12 ? "اتمام و ثبت نهایی" : "گام بعدی"}
</Button>
</Box>
</Paper>
</Form>
);
}

View File

@@ -0,0 +1,32 @@
"use client";
import { withFormik, type FormikBag } from "formik";
import type { JobInfoFormProps, JobInfoFormValues } from "./types";
import { INITIAL_JOB_INFO_VALUES } from "./constant";
import { JobInfoValidationSchema } from "./validation";
import InnerJobInfoForm from "./InnerJobInfoForm";
const JobInfoForm = withFormik<JobInfoFormProps, JobInfoFormValues>({
displayName: "JobInfoForm",
enableReinitialize: true,
mapPropsToValues: (props) => {
return props.data?.jobInfo || INITIAL_JOB_INFO_VALUES;
},
validationSchema: JobInfoValidationSchema,
handleSubmit: async (
values,
bag: FormikBag<JobInfoFormProps, JobInfoFormValues>
) => {
const { props, setSubmitting } = bag;
props.update({ jobInfo: values });
props.setStep((prev) => prev + 1);
setSubmitting(false);
},
})(InnerJobInfoForm);
export default JobInfoForm;

View File

@@ -0,0 +1,20 @@
import type { JobInfoFormData } from "../types";
export const INITIAL_JOB_INFO_VALUES: JobInfoFormData = {
readyToWorkDate: "",
isCurrentEmployee: false,
hasPastCooperation: false,
isCurrentlyEmployed: false,
dualJobInterest: false,
retirementStatus: "None",
isMilitary: false,
hasInsurance: false,
insuranceType: "",
totalInsuranceYears: "0",
};
export const retirementOptions = [
{ value: "None", label: "هیچکدام" },
{ value: "Retired", label: "بازنشسته" },
{ value: "Redeemed", label: "بازخرید" },
];

View File

@@ -0,0 +1,31 @@
import type React from "react";
export type RetirementStatus = "None" | "Retired" | "Redeemed" | "";
export interface JobInfoFormData {
readyToWorkDate: string; // YYYY-MM-DD
isCurrentEmployee: boolean;
hasPastCooperation: boolean;
isCurrentlyEmployed: boolean;
dualJobInterest: boolean;
retirementStatus: RetirementStatus;
isMilitary: boolean;
hasInsurance: boolean;
insuranceType: string;
totalInsuranceYears: string;
}
export interface JobInfoFormValues extends JobInfoFormData {}
/** این ساختار را با کل Wizard خود تطابق دهید */
export interface WizardFormData {
jobInfo: JobInfoFormData;
// ... سایر استپ‌ها
}
export interface JobInfoFormProps {
step: number;
setStep: React.Dispatch<React.SetStateAction<number>>;
data: WizardFormData;
update: (patch: Partial<WizardFormData>) => void;
}

View File

@@ -0,0 +1,26 @@
import * as Yup from "yup";
export const JobInfoValidationSchema = Yup.object().shape({
readyToWorkDate: Yup.string().required("تاریخ آمادگی برای شروع کار الزامی است"),
retirementStatus: Yup.string().required("وضعیت بازنشستگی الزامی است"),
isCurrentEmployee: Yup.boolean(),
hasPastCooperation: Yup.boolean(),
isCurrentlyEmployed: Yup.boolean(),
dualJobInterest: Yup.boolean(),
isMilitary: Yup.boolean(),
hasInsurance: Yup.boolean(),
insuranceType: Yup.string().when("hasInsurance", {
is: true,
then: (schema) => schema.required("نوع بیمه الزامی است"),
otherwise: (schema) => schema.optional(),
}),
totalInsuranceYears: Yup.number().when("hasInsurance", {
is: true,
then: (schema) =>
schema
.typeError("باید عدد باشد")
.required("تعداد سال بیمه الزامی است")
.min(0, "نمی‌تواند منفی باشد"),
otherwise: (schema) => schema.optional(),
}),
});