import { useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { ChevronRightIcon } from '@heroicons/react/24/outline'; import { toast } from 'sonner'; import { api } from '../lib/api'; import type { ApiResponse } from '../lib/api'; import type { PatientRecord } from '../types'; import PersianDateInput from '../components/ui/PersianDateInput'; import SearchableSelect from '../components/ui/SearchableSelect'; import { numericField } from '../lib/forms'; import { iranNationalCodeSchema, iranMobileSchema } from '../lib/utils'; const REFERRAL_OPTIONS = ['اینستاگرام', 'معرفی دوستان و آشنایان', 'جستجوی اینترنتی', 'تابلو مطب', 'سایر']; const schema = z.object({ name: z.string().min(1, 'نام و نام خانوادگی الزامی است'), record_number: z.string().min(1, 'شماره پرونده الزامی است'), gender: z.enum(['male', 'female'], { errorMap: () => ({ message: 'جنسیت را انتخاب کنید' }) }), national_code: iranNationalCodeSchema, mobile: iranMobileSchema, birth_date: z.string().optional(), referral_source: z.string().optional(), description: z.string().optional(), }); type Form = z.infer; const toEpoch = (iso?: string) => (iso ? Math.floor(new Date(iso).getTime() / 1000) : null); const fromEpoch = (ts?: number | null) => (ts ? new Date(ts * 1000).toISOString().slice(0, 10) : ''); /** تشکیل/ویرایش پرونده — patient record create & edit form (Figma "تشکیل پرونده"). */ export default function PatientRecordFormPage() { const { uuid } = useParams<{ uuid: string }>(); const isEdit = !!uuid; const navigate = useNavigate(); const qc = useQueryClient(); const form = useForm
({ resolver: zodResolver(schema), defaultValues: { name: '', record_number: '', gender: undefined as any, national_code: '', mobile: '', birth_date: '', referral_source: '', description: '' }, }); const { data: recordData } = useQuery>({ queryKey: ['patient', uuid], queryFn: () => api.get(`/api/v1/patient/${uuid}`), enabled: isEdit, }); useEffect(() => { const r = recordData?.data; if (!r) return; const p: any = r.profile ?? {}; form.reset({ name: r.user_name ?? '', record_number: r.record_number ?? '', gender: (p.gender as 'male' | 'female') ?? undefined, national_code: r.user_national_code ?? '', mobile: r.user_mobile ?? '', birth_date: fromEpoch(p.date_of_birth), referral_source: p.referral_source ?? '', description: p.description ?? '', }); }, [recordData]); // eslint-disable-line react-hooks/exhaustive-deps const save = useMutation({ mutationFn: async (d: Form) => { const profilePayload = { gender: d.gender, date_of_birth: toEpoch(d.birth_date), referral_source: d.referral_source || null, description: d.description || null, }; if (isEdit) { return api.patch(`/api/v1/patient/${uuid}`, { name: d.name, national_code: d.national_code, mobile: d.mobile, record_number: d.record_number, ...profilePayload, }); } // create: POST creates the record + identity, then PATCH applies the profile demographics const created = await api.post>('/api/v1/patient', { name: d.name, mobile: d.mobile, national_code: d.national_code, record_number: d.record_number, }); const newUuid = (created as any)?.data?.uuid; if (newUuid) await api.patch(`/api/v1/patient/${newUuid}`, profilePayload); return created; }, onSuccess: () => { qc.invalidateQueries({ queryKey: ['patients'] }); toast.success(isEdit ? 'پرونده ویرایش شد' : 'پرونده تشکیل شد'); navigate('/admin/patients'); }, onError: (e: any) => toast.error(e.message), }); const Field = ({ label, required, error, children }: { label: string; required?: boolean; error?: string; children: React.ReactNode }) => (
{children} {error && {error}}
); return (
بازگشت
پرونده › {isEdit ? 'ویرایش پرونده' : 'تشکیل پرونده'}
save.mutate(d))} style={{ background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 'var(--r-lg)', padding: 24 }}>
form.setValue('gender', v as Form['gender'], { shouldValidate: true, shouldDirty: true })} placeholder="انتخاب..." height={38} />
form.setValue('birth_date', v)} enableYearPicker /> ({ value: o, label: o }))} value={form.watch('referral_source') || null} onChange={(v) => form.setValue('referral_source', v ? String(v) : '', { shouldDirty: true })} placeholder="انتخاب کنید..." isClearable height={38} />