first commit

This commit is contained in:
2026-05-31 14:22:39 +03:30
commit 98af7d639b
54 changed files with 11545 additions and 0 deletions

214
ui/forms/SkillsForm.tsx Normal file
View File

@@ -0,0 +1,214 @@
import React from "react";
import { Box, MenuItem, Paper, TextField, Typography, Divider, Switch, FormControlLabel } from "@mui/material";
// --- Types ---
type ProficiencyLevel = "" | "NONE" | "VERY_WEAK" | "WEAK" | "AVERAGE" | "GOOD" | "VERY_GOOD" | "EXCELLENT";
export interface ComputerSkillFormData {
pcUsage: ProficiencyLevel;
word: ProficiencyLevel;
excel: ProficiencyLevel;
powerPoint: ProficiencyLevel;
rahkaran: ProficiencyLevel;
kasra: ProficiencyLevel;
didgah: ProficiencyLevel;
his: ProficiencyLevel;
otherSoftware?: string;
}
export interface LanguageSkillsFormData {
englishLevel: ProficiencyLevel;
englishDescription: string;
hasEnglishCertificate: boolean; // جدید
englishCertificateType: string; // جدید
arabicLevel: ProficiencyLevel;
arabicDescription: string;
otherLanguagesDescription: string;
dialectsDescription: string;
otherSkills: string;
}
export interface SkillsFormState {
computerSkill: ComputerSkillFormData;
languageSkill: LanguageSkillsFormData;
}
interface Props {
value: SkillsFormState;
onChange: (next: SkillsFormState) => void;
}
// --- Constants ---
const proficiencyOptions: { value: ProficiencyLevel; label: string }[] = [
{ value: "", label: "انتخاب ..." },
{ value: "NONE", label: "ندارد" },
{ value: "VERY_WEAK", label: "خیلی ضعیف" },
{ value: "WEAK", label: "ضعیف" },
{ value: "AVERAGE", label: "متوسط" },
{ value: "GOOD", label: "خوب" },
{ value: "VERY_GOOD", label: "خیلی خوب" },
{ value: "EXCELLENT", label: "عالی" },
];
const certTypes = ["IELTS", "TOFEL", "TOLIMO", "MCHE"];
export default function SkillsForm({ value, onChange }: Props) {
const handleComputerChange = (key: keyof ComputerSkillFormData, val: string) => {
onChange({
...value,
computerSkill: { ...value.computerSkill, [key]: val },
});
};
const handleLanguageChange = (key: keyof LanguageSkillsFormData, val: any) => {
const nextLang = { ...value.languageSkill, [key]: val };
// پاکسازی فیلد نوع مدرک در صورتی که سوییچ خاموش شود
if (key === "hasEnglishCertificate" && val === false) {
nextLang.englishCertificateType = "";
}
onChange({
...value,
languageSkill: nextLang,
});
};
return (
<Box sx={{ display: "grid", gap: 3 }}>
{/* 1. Computer Skills Section */}
<Paper elevation={0} sx={{ p: { xs: 2, md: 3 }, borderRadius: "24px", border: "1px solid #e2e8f0" }}>
<Typography variant="h6" sx={{ mb: 2, fontWeight: "bold" }}>مهارتهای کامپیوتری</Typography>
<Box sx={{ display: "grid", gridTemplateColumns: { xs: "1fr", md: "repeat(4, 1fr)" }, gap: 2 }}>
{(['pcUsage', 'word', 'excel', 'powerPoint', 'rahkaran', 'kasra', 'didgah', 'his'] as const).map((field) => (
<TextField
key={field}
select
label={field.toUpperCase()}
value={value?.computerSkill[field]}
onChange={(e) => handleComputerChange(field, e.target.value)}
fullWidth
>
{proficiencyOptions.map((o) => (
<MenuItem key={o.value} value={o.value}>{o.label}</MenuItem>
))}
</TextField>
))}
<TextField
label="سایر نرم‌افزارها"
value={value?.computerSkill.otherSoftware || ""}
onChange={(e) => handleComputerChange('otherSoftware', e.target.value)}
fullWidth
multiline
minRows={2}
sx={{ gridColumn: { xs: "1", md: "1 / -1" } }}
/>
</Box>
</Paper>
{/* 2. Language Skills Section */}
<Paper elevation={0} sx={{ p: { xs: 2, md: 3 }, borderRadius: "24px", border: "1px solid #e2e8f0" }}>
<Typography variant="h6" sx={{ mb: 2, fontWeight: "bold" }}>آشنایی با زبانهای خارجه</Typography>
<Box sx={{ display: "grid", gridTemplateColumns: { xs: "1fr", md: "1fr 1fr" }, gap: 2 }}>
{/* English */}
<TextField
select
label="زبان انگلیسی*"
value={value?.languageSkill.englishLevel}
onChange={(e) => handleLanguageChange("englishLevel", e.target.value)}
fullWidth
>
{proficiencyOptions.map((o) => <MenuItem key={o.value} value={o.value}>{o.label}</MenuItem>)}
</TextField>
<FormControlLabel
control={
<Switch
checked={value?.languageSkill.hasEnglishCertificate}
onChange={(e) => handleLanguageChange("hasEnglishCertificate", e.target.checked)}
/>
}
label="مدرک معتبر زبان انگلیسی دارد"
/>
{value?.languageSkill.hasEnglishCertificate && (
<TextField
select
label="نوع مدرک"
value={value?.languageSkill.englishCertificateType}
onChange={(e) => handleLanguageChange("englishCertificateType", e.target.value)}
fullWidth
sx={{ gridColumn: { xs: "1", md: "1 / -1" } }}
>
{certTypes.map((t) => <MenuItem key={t} value={t}>{t}</MenuItem>)}
</TextField>
)}
<TextField
label="توضیحات زبان انگلیسی"
value={value?.languageSkill.englishDescription}
onChange={(e) => handleLanguageChange("englishDescription", e.target.value)}
fullWidth
multiline
sx={{ gridColumn: { xs: "1", md: "1 / -1" } }}
/>
<Divider sx={{ gridColumn: { xs: "1", md: "1 / -1" }, my: 1 }} />
{/* Arabic */}
<TextField
select
label="زبان عربی*"
value={value?.languageSkill.arabicLevel}
onChange={(e) => handleLanguageChange("arabicLevel", e.target.value)}
fullWidth
>
{proficiencyOptions.map((o) => <MenuItem key={o.value} value={o.value}>{o.label}</MenuItem>)}
</TextField>
<Box />
<TextField
label="توضیحات زبان عربی"
value={value?.languageSkill.arabicDescription}
onChange={(e) => handleLanguageChange("arabicDescription", e.target.value)}
fullWidth
multiline
sx={{ gridColumn: { xs: "1", md: "1 / -1" } }}
/>
<Divider sx={{ gridColumn: { xs: "1", md: "1 / -1" }, my: 1 }} />
{/* Other Skills */}
<TextField
label="سایر زبان ها (توضیحات در مورد میزان تسلط)"
value={value?.languageSkill.otherLanguagesDescription}
onChange={(e) => handleLanguageChange("otherLanguagesDescription", e.target.value)}
fullWidth
multiline
sx={{ gridColumn: { xs: "1", md: "1 / -1" } }}
/>
<TextField
label="آشنایی با گویش ها و لهجه های کشور (توضیحات در مورد میزان تسلط)"
value={value?.languageSkill.dialectsDescription}
onChange={(e) => handleLanguageChange("dialectsDescription", e.target.value)}
fullWidth
multiline
sx={{ gridColumn: { xs: "1", md: "1 / -1" } }}
/>
<TextField
label="سایر مهارت ها (اعم از ورزشی، هنری، فرهنگی، اجتماعی و ...)"
value={value?.languageSkill.otherSkills}
onChange={(e) => handleLanguageChange("otherSkills", e.target.value)}
fullWidth
multiline
minRows={3}
sx={{ gridColumn: { xs: "1", md: "1 / -1" } }}
/>
</Box>
</Paper>
</Box>
);
}