"use client"; import { useEffect, useRef, useState } from "react"; import * as yup from "yup"; import { Alert, Spinner } from "../UI"; import { createUserSchema, updateUserSchema } from "@/validations/user.validator"; import type { Branch } from "../../types/branch"; import type { Role } from "../../types/role"; import type { FormErrors, User, UserFormData } from "../../types/user"; // ── fixed styles ───────────────────────────────────────── const S = { input: { width: "100%", height: 40, padding: "0 0.75rem", borderRadius: "var(--radius-md)", border: "1px solid var(--color-border)", background: "var(--color-surface)", fontSize: 13, color: "var(--color-text-primary)", outline: "none", fontFamily: "var(--font-sans)", } as React.CSSProperties, label: { display: "flex", flexDirection: "column" as const, gap: 6, fontSize: 12, fontWeight: 600, color: "var(--color-text-secondary)", } as React.CSSProperties, errorText: { fontSize: 11, color: "var(--color-danger)", fontWeight: 500 } as React.CSSProperties, }; // ── yup validation ──────────────────────────────────────────────────────────── async function validate(data: UserFormData, isNew: boolean): Promise { const schema = isNew ? createUserSchema : updateUserSchema; try { await schema.validate(data, { abortEarly: false }); return {}; } catch (err) { if (err instanceof yup.ValidationError) { return err.inner.reduce((acc, e) => { const field = e.path as keyof FormErrors; if (field && !acc[field]) acc[field] = e.message; return acc; }, {}); } return {}; } } // ── Props ───────────────────────────────────────────────────────────────────── interface UserFormModalProps { editUser: User | null; roles: Role[]; branches: Branch[]; onClose: () => void; onSubmit: (data: UserFormData, isNew: boolean) => Promise; } // ── main component ──────────────────────────────────────────────────────────── export function UserFormModal({ editUser, roles, branches, onClose, onSubmit }: UserFormModalProps) { const isNew = editUser === null; const [form, setForm] = useState({ name: editUser?.name ?? "", email: editUser?.email ?? "", phone: editUser?.phone ?? "", password: "", roleId: editUser?.role?.id ?? "", branchId: editUser?.branch?.id ?? "", }); const [errors, setErrors] = useState({}); const [saving, setSaving] = useState(false); const [apiError, setApiError] = useState(""); const firstInputRef = useRef(null); useEffect(() => { firstInputRef.current?.focus(); }, []); useEffect(() => { const handler = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); }, [onClose]); const set = (field: keyof UserFormData) => (e: React.ChangeEvent) => { setForm(p => ({ ...p, [field]: e.target.value })); // clear field error on change if (errors[field]) setErrors(p => ({ ...p, [field]: undefined })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const errs = await validate( !isNew && !form.password ? { ...form, password: undefined as unknown as string } : form, isNew, ); if (Object.keys(errs).length) { setErrors(errs); return; } setSaving(true); setApiError(""); const payload: Partial = { ...form }; if (!isNew && !payload.password) delete payload.password; const ok = await onSubmit(payload as UserFormData, isNew); setSaving(false); if (ok) onClose(); else setApiError("حدث خطأ غير متوقع. يرجى المحاولة لاحقاً."); }; // dynamic styles for inputs with errors const inputStyle = (field: keyof FormErrors): React.CSSProperties => ({ ...S.input, ...(errors[field] ? { borderColor: "var(--color-danger)", background: "#FEF2F2" } : {}), }); return (
{ if (e.target === e.currentTarget) onClose(); }} style={{ position: "fixed", inset: 0, zIndex: 50, background: "rgba(15,23,42,0.55)", backdropFilter: "blur(4px)", display: "flex", alignItems: "center", justifyContent: "center", padding: "1rem", }} >
e.stopPropagation()} style={{ width: "100%", maxWidth: 520, background: "var(--color-surface)", borderRadius: "var(--radius-2xl)", border: "1px solid var(--color-border)", boxShadow: "0 24px 64px rgba(0,0,0,.18)", overflow: "hidden", }} > {/* header */}

{isNew ? "إضافة مستخدم" : "تعديل مستخدم"}

{/* body */}
{apiError && setApiError("")} />} {/* name */} {/* email + phone */}
{/* password */} {/* role + branch */}
{/* actions */}
); }