import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { useAuth } from "@/hooks/use-auth"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { useEffect, useMemo } from "react"; import { forwardRef, useImperativeHandle } from "react"; import { formatLocalDate } from "@/utils/dateUtils"; import { InsertPatient, insertPatientSchema, Patient, PatientStatus, patientStatusOptions, UpdatePatient, updatePatientSchema, } from "@repo/db/types"; import { z } from "zod"; import { DateInputField } from "@/components/ui/dateInputField"; interface PatientFormProps { patient?: Patient; extractedInfo?: { firstName: string; lastName: string; dateOfBirth: string; insuranceId: string; }; onSubmit: (data: InsertPatient | UpdatePatient) => void; } export type PatientFormRef = { submit: () => void; }; export const PatientForm = forwardRef( ({ patient, extractedInfo, onSubmit }, ref) => { const { user } = useAuth(); const isEditing = !!patient; const schema = useMemo( () => isEditing ? updatePatientSchema : insertPatientSchema.extend({ userId: z.number().optional() }), [isEditing], ); const computedDefaultValues = useMemo(() => { if (isEditing && patient) { const { id, userId, createdAt, ...sanitizedPatient } = patient; return { ...sanitizedPatient, dateOfBirth: patient.dateOfBirth ? formatLocalDate(new Date(patient.dateOfBirth)) : null, }; } return { firstName: extractedInfo?.firstName || "", lastName: extractedInfo?.lastName || "", dateOfBirth: extractedInfo?.dateOfBirth || null, gender: "", phone: "", email: "", address: "", city: "", zipCode: "", insuranceProvider: "", insuranceId: extractedInfo?.insuranceId || "", groupNumber: "", policyHolder: "", allergies: "", medicalConditions: "", preferredLanguage: "English", status: "UNKNOWN", userId: user?.id, }; }, [isEditing, patient, extractedInfo, user?.id]); const form = useForm({ resolver: zodResolver(schema), defaultValues: computedDefaultValues, }); useImperativeHandle(ref, () => ({ submit() { ( document.getElementById("patient-form") as HTMLFormElement | null )?.requestSubmit(); }, })); // Debug form errors useEffect(() => { const errors = form.formState.errors; if (Object.keys(errors).length > 0) { console.log("❌ Form validation errors:", errors); } }, [form.formState.errors]); useEffect(() => { if (patient) { const { id, userId, createdAt, ...sanitizedPatient } = patient; const resetValues: Partial = { ...sanitizedPatient, dateOfBirth: patient.dateOfBirth ? formatLocalDate(new Date(patient.dateOfBirth)) : null, }; form.reset(resetValues); } else { form.reset(computedDefaultValues); } }, [patient, computedDefaultValues, form]); const handleSubmit2 = (data: InsertPatient | UpdatePatient) => { onSubmit(data); }; return (
{ handleSubmit2(data); })} className="space-y-6" > {/* Personal Information */}

Personal Information

( First Name * )} /> ( Last Name * )} /> ( Gender )} /> ( Preferred Language )} />
{/* Contact Information */}

Contact Information

{ const display = (field.value as string)?.startsWith("1") ? (field.value as string).slice(1) : (field.value as string) || ""; return ( Phone Number *
+1 { const digits = e.target.value.replace(/\D/g, "").slice(0, 10); field.onChange(digits ? "1" + digits : ""); }} onBlur={field.onBlur} name={field.name} ref={field.ref} />
); }} /> ( Email )} /> ( Address )} /> ( City )} /> ( ZIP Code )} />
{/* Insurance Information */}

Insurance Information

{ const options = Object.values( patientStatusOptions, ) as PatientStatus[]; // ['ACTIVE','INACTIVE','UNKNOWN'] const toLabel = (v: PatientStatus) => { if (v === "PLAN_NOT_ACCEPTED") return "Plan Not Accepted"; return v[0] + v.slice(1).toLowerCase(); }; return ( Status ); }} /> ( Insurance Provider )} /> ( Insurance ID )} /> ( Group Number )} /> ( Policy Holder (if not self) )} />
{/* Hidden submit button for form validation */}
); }, );