Files
hounam-submit-form-frontend/ui/forms/referral/InnerReferralForm.tsx
2026-06-02 17:08:52 +03:30

321 lines
8.8 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import React from "react";
import {
Box,
Paper,
TextField,
Typography,
IconButton,
Button,
MenuItem,
Divider,
} from "@mui/material";
import AddIcon from "@mui/icons-material/Add";
import { DeleteOutlineOutlined } from "@mui/icons-material";
import { FieldArray, Form, getIn, type FormikProps } from "formik";
import type {
ReferralFormProps,
ReferralFormValues,
ReferralItem,
} from "./types";
import {
REFERRAL_EMPTY_ITEM,
REFERRAL_MIN_ITEMS,
} from "./constant";
type Props = FormikProps<ReferralFormValues> & ReferralFormProps;
function ReferralItemForm({
index,
item,
errors,
touched,
handleChange,
setFieldValue,
onRemove,
disableRemove,
}: {
index: number;
item: ReferralItem;
errors: any;
touched: any;
handleChange: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
setFieldValue: (field: string, value: any, shouldValidate?: boolean) => void;
onRemove: () => void;
disableRemove: boolean;
}) {
const itemErrors = getIn(errors, `referrals.${index}`) || {};
const itemTouched = getIn(touched, `referrals.${index}`) || {};
return (
<Paper
elevation={0}
sx={{
p: { xs: 2, md: 2.5 },
borderRadius: "20px",
border: "1px solid #e5e7eb",
backgroundColor: "#fff",
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
mb: 1.5,
gap: 2,
}}
>
<Typography sx={{ fontWeight: 700 }}>معرف {index + 1}</Typography>
<IconButton
onClick={onRemove}
disabled={disableRemove}
color="error"
size="small"
aria-label="حذف معرف"
>
<DeleteOutlineOutlined />
</IconButton>
</Box>
<Box
sx={{
display: "grid",
gridTemplateColumns: { xs: "1fr", md: "1fr 1fr" },
gap: 2,
}}
>
<TextField
label="نام"
name={`referrals.${index}.firstName`}
value={item.firstName}
onChange={handleChange}
fullWidth
error={!!itemTouched.firstName && !!itemErrors.firstName}
helperText={itemTouched.firstName ? itemErrors.firstName : ""}
/>
<TextField
label="نام خانوادگی"
name={`referrals.${index}.lastName`}
value={item.lastName}
onChange={handleChange}
fullWidth
error={!!itemTouched.lastName && !!itemErrors.lastName}
helperText={itemTouched.lastName ? itemErrors.lastName : ""}
/>
<TextField
label="نسبت / رابطه"
name={`referrals.${index}.relationship`}
value={item.relationship}
onChange={handleChange}
fullWidth
placeholder="مثلاً: دوست، همکار، فامیل..."
error={!!itemTouched.relationship && !!itemErrors.relationship}
helperText={itemTouched.relationship ? itemErrors.relationship : ""}
/>
<TextField
label="مدت زمان آشنایی"
name={`referrals.${index}.acquaintanceDuration`}
value={item.acquaintanceDuration}
onChange={handleChange}
fullWidth
placeholder="مثلاً: ۵ سال"
error={
!!itemTouched.acquaintanceDuration &&
!!itemErrors.acquaintanceDuration
}
helperText={
itemTouched.acquaintanceDuration
? itemErrors.acquaintanceDuration
: ""
}
/>
<TextField
select
label="نوع آشنایی"
name={`referrals.${index}.acquaintanceType`}
value={item.acquaintanceType}
onChange={handleChange}
fullWidth
error={
!!itemTouched.acquaintanceType &&
!!itemErrors.acquaintanceType
}
helperText={
itemTouched.acquaintanceType ? itemErrors.acquaintanceType : ""
}
>
<MenuItem value="Direct">مستقیم</MenuItem>
<MenuItem value="Indirect">غیرمستقیم</MenuItem>
</TextField>
<TextField
label="تلفن تماس"
name={`referrals.${index}.phoneNumber`}
value={item.phoneNumber}
onChange={(e) => {
const onlyDigits = e.target.value.replace(/[^\d]/g, "").slice(0, 11);
setFieldValue(`referrals.${index}.phoneNumber`, onlyDigits);
}}
fullWidth
placeholder="مثلاً: 0912xxxxxxx"
error={!!itemTouched.phoneNumber && !!itemErrors.phoneNumber}
helperText={itemTouched.phoneNumber ? itemErrors.phoneNumber : ""}
/>
<TextField
label="شغل معرف"
name={`referrals.${index}.jobTitle`}
value={item.jobTitle}
onChange={handleChange}
fullWidth
error={!!itemTouched.jobTitle && !!itemErrors.jobTitle}
helperText={itemTouched.jobTitle ? itemErrors.jobTitle : ""}
/>
<TextField
label="نام محل کار معرف"
name={`referrals.${index}.workplaceName`}
value={item.workplaceName}
onChange={handleChange}
fullWidth
error={!!itemTouched.workplaceName && !!itemErrors.workplaceName}
helperText={itemTouched.workplaceName ? itemErrors.workplaceName : ""}
/>
</Box>
</Paper>
);
}
export default function InnerReferralForm(props: Props) {
const {
values,
errors,
touched,
handleChange,
setFieldValue,
isSubmitting,
} = props;
const handleBack = () => {
props.update({
referrals: values.referrals,
});
props.setStep(props.step - 1);
};
return (
<Form>
<FieldArray name="referrals">
{({ push, remove }) => (
<Paper
elevation={0}
sx={{
p: { xs: 2, md: 3 },
borderRadius: "24px",
border: "1px solid #e2e8f0",
backgroundColor: "#fff",
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: 2,
flexWrap: "wrap",
}}
>
<Typography variant="h6" sx={{ fontWeight: 700 }}>
معرفها
</Typography>
<Button
type="button"
onClick={() =>
push({
...REFERRAL_EMPTY_ITEM,
id: Date.now(),
})
}
variant="contained"
startIcon={<AddIcon />}
sx={{ borderRadius: "12px", fontWeight: 700 }}
>
افزودن معرف جدید
</Button>
</Box>
<Divider sx={{ my: 2 }} />
<Box sx={{ display: "grid", gap: 2 }}>
{values.referrals.map((item, idx) => (
<ReferralItemForm
key={item.id || idx}
index={idx}
item={item}
errors={errors}
touched={touched}
handleChange={handleChange}
setFieldValue={setFieldValue}
onRemove={() => remove(idx)}
disableRemove={values.referrals.length <= REFERRAL_MIN_ITEMS}
/>
))}
</Box>
{typeof errors.referrals === "string" && (
<Typography color="error" sx={{ mt: 2 }}>
{errors.referrals}
</Typography>
)}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
mt: 4,
}}
>
<Button
type="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>
)}
</FieldArray>
</Form>
);
}