change some files
This commit is contained in:
207
ui/forms/jobInfo/InnerJobInfoForm.tsx
Normal file
207
ui/forms/jobInfo/InnerJobInfoForm.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
32
ui/forms/jobInfo/JobInfoForm.tsx
Normal file
32
ui/forms/jobInfo/JobInfoForm.tsx
Normal 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;
|
||||
20
ui/forms/jobInfo/constant/index.ts
Normal file
20
ui/forms/jobInfo/constant/index.ts
Normal 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: "بازخرید" },
|
||||
];
|
||||
31
ui/forms/jobInfo/types/index.ts
Normal file
31
ui/forms/jobInfo/types/index.ts
Normal 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;
|
||||
}
|
||||
26
ui/forms/jobInfo/validation/index.ts
Normal file
26
ui/forms/jobInfo/validation/index.ts
Normal 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(),
|
||||
}),
|
||||
});
|
||||
Reference in New Issue
Block a user