first commit
This commit is contained in:
241
ui/forms/ReferralForm.tsx
Normal file
241
ui/forms/ReferralForm.tsx
Normal file
@@ -0,0 +1,241 @@
|
||||
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";
|
||||
|
||||
// ---------------- Types ----------------
|
||||
export type AcquaintanceType = "Direct" | "Indirect";
|
||||
|
||||
export interface ReferralFormData {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
relationship: string;
|
||||
acquaintanceDuration: string; // optional in DB, but keep as string
|
||||
acquaintanceType: AcquaintanceType;
|
||||
jobTitle: string;
|
||||
workplaceName: string;
|
||||
phoneNumber: string;
|
||||
}
|
||||
|
||||
interface ReferralItemFormProps {
|
||||
index: number;
|
||||
value: ReferralFormData;
|
||||
onChange: (next: ReferralFormData) => void;
|
||||
onRemove?: () => void;
|
||||
disableRemove?: boolean;
|
||||
}
|
||||
|
||||
// ---------------- Item Form ----------------
|
||||
export function ReferralItemForm({
|
||||
index,
|
||||
value,
|
||||
onChange,
|
||||
onRemove,
|
||||
disableRemove,
|
||||
}: ReferralItemFormProps) {
|
||||
const setField =
|
||||
(key: keyof ReferralFormData) =>
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
onChange({ ...value, [key]: e.target.value });
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper
|
||||
elevation={0}
|
||||
sx={{
|
||||
p: { xs: 2, md: 2.5 },
|
||||
borderRadius: 2,
|
||||
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="نام"
|
||||
value={value.firstName}
|
||||
onChange={setField("firstName")}
|
||||
fullWidth
|
||||
required
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="نام خانوادگی"
|
||||
value={value.lastName}
|
||||
onChange={setField("lastName")}
|
||||
fullWidth
|
||||
required
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="نسبت / رابطه"
|
||||
value={value.relationship}
|
||||
onChange={setField("relationship")}
|
||||
fullWidth
|
||||
required
|
||||
placeholder="مثلاً: دوست، همکار، فامیل..."
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="مدت زمان آشنایی"
|
||||
value={value.acquaintanceDuration}
|
||||
onChange={setField("acquaintanceDuration")}
|
||||
fullWidth
|
||||
placeholder="مثلاً: ۵ سال"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
select
|
||||
label="نوع آشنایی"
|
||||
value={value.acquaintanceType}
|
||||
onChange={setField("acquaintanceType")}
|
||||
fullWidth
|
||||
required
|
||||
>
|
||||
<MenuItem value="Direct">مستقیم</MenuItem>
|
||||
<MenuItem value="Indirect">غیرمستقیم</MenuItem>
|
||||
</TextField>
|
||||
|
||||
<TextField
|
||||
label="تلفن تماس"
|
||||
value={value.phoneNumber}
|
||||
onChange={setField("phoneNumber")}
|
||||
fullWidth
|
||||
required
|
||||
placeholder="مثلاً: 0912xxxxxxx"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="شغل معرف"
|
||||
value={value.jobTitle}
|
||||
onChange={setField("jobTitle")}
|
||||
fullWidth
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="نام محل کار معرف"
|
||||
value={value.workplaceName}
|
||||
onChange={setField("workplaceName")}
|
||||
fullWidth
|
||||
/>
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------- Section (Multi) ----------------
|
||||
interface ReferralSectionProps {
|
||||
value: ReferralFormData[];
|
||||
onChange: (next: ReferralFormData[]) => void;
|
||||
minItems?: number; // پیشفرض 1
|
||||
maxItems?: number; // اختیاری
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const emptyReferral = (): ReferralFormData => ({
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
relationship: "",
|
||||
acquaintanceDuration: "",
|
||||
acquaintanceType: "Direct",
|
||||
jobTitle: "",
|
||||
workplaceName: "",
|
||||
phoneNumber: "",
|
||||
});
|
||||
|
||||
export function ReferralSection({
|
||||
value,
|
||||
onChange,
|
||||
minItems = 1,
|
||||
maxItems,
|
||||
title = "معرفها",
|
||||
}: ReferralSectionProps) {
|
||||
const items = value?.length ? value : Array.from({ length: minItems }, emptyReferral);
|
||||
|
||||
const addItem = () => {
|
||||
if (maxItems && items.length >= maxItems) return;
|
||||
onChange([...(items || []), emptyReferral()]);
|
||||
};
|
||||
|
||||
const updateItem = (idx: number, nextItem: ReferralFormData) => {
|
||||
const next = items.map((it, i) => (i === idx ? nextItem : it));
|
||||
onChange(next);
|
||||
};
|
||||
|
||||
const removeItem = (idx: number) => {
|
||||
if (items.length <= minItems) return;
|
||||
const next = items.filter((_, i) => i !== idx);
|
||||
onChange(next);
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper
|
||||
elevation={0}
|
||||
|
||||
>
|
||||
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 2 }}>
|
||||
|
||||
|
||||
<Button
|
||||
onClick={addItem}
|
||||
variant="contained"
|
||||
startIcon={<AddIcon />}
|
||||
disabled={!!maxItems && items.length >= maxItems}
|
||||
>
|
||||
افزودن معرف جديد
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ my: 2 }} />
|
||||
|
||||
<Box sx={{ display: "grid", gap: 2 }}>
|
||||
{items.map((item, idx) => (
|
||||
<ReferralItemForm
|
||||
key={idx}
|
||||
index={idx}
|
||||
value={item}
|
||||
onChange={(next) => updateItem(idx, next)}
|
||||
onRemove={() => removeItem(idx)}
|
||||
disableRemove={items.length <= minItems}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user