import { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { format, parse } from "date-fns"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; import { X, Calendar as CalendarIcon } from "lucide-react"; import { useToast } from "@/hooks/use-toast"; import { Calendar } from "@/components/ui/calendar"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { PatientUncheckedCreateInputObjectSchema, AppointmentUncheckedCreateInputObjectSchema, } from "@repo/db/usedSchemas"; import { z } from "zod"; import { useQuery } from "@tanstack/react-query"; import { apiRequest } from "@/lib/queryClient"; import { MultipleFileUploadZone } from "../file-upload/multiple-file-upload-zone"; import { useAuth } from "@/hooks/use-auth"; const PatientSchema = ( PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject ).omit({ appointments: true, }); type Patient = z.infer; const updatePatientSchema = ( PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject ) .omit({ id: true, createdAt: true, userId: true, }) .partial(); type UpdatePatient = z.infer; //creating types out of schema auto generated. type Appointment = z.infer; const insertAppointmentSchema = ( AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject ).omit({ id: true, createdAt: true, }); type InsertAppointment = z.infer; const updateAppointmentSchema = ( AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject ) .omit({ id: true, createdAt: true, userId: true, }) .partial(); type UpdateAppointment = z.infer; interface ServiceLine { procedureCode: string; procedureDate: string; // YYYY-MM-DD oralCavityArea?: string; toothNumber?: string; toothSurface?: string; billedAmount: number; } interface ClaimFormData { patientId: number; appointmentId: number; userId: number; staffId: number; patientName: string; memberId: string; dateOfBirth: string; remarks: string; serviceDate: string; // YYYY-MM-DD insuranceProvider: string; status: string; // default "pending" massdhp_username?:string, massdhp_password?:string, serviceLines: ServiceLine[]; } interface ClaimFormProps { patientId: number; extractedData?: Partial; onSubmit: (data: ClaimFormData) => void; onHandleAppointmentSubmit: ( appointmentData: InsertAppointment | UpdateAppointment ) => void; onHandleUpdatePatient: (patient: UpdatePatient & { id: number }) => void; onHandleForSelenium: (data: ClaimFormData) => void; onClose: () => void; } interface Staff { id: string; name: string; role: "doctor" | "hygienist"; color: string; } export function ClaimForm({ patientId, extractedData, onHandleAppointmentSubmit, onHandleUpdatePatient, onHandleForSelenium, onSubmit, onClose, }: ClaimFormProps) { const { toast } = useToast(); const { user } = useAuth(); // Patient state - initialize from extractedData or null (new patient) const [patient, setPatient] = useState( extractedData ? ({ ...extractedData } as Patient) : null ); // Query patient const { data: fetchedPatient, isLoading, error, } = useQuery({ queryKey: ["/api/patients/", patientId], queryFn: async () => { const res = await apiRequest("GET", `/api/patients/${patientId}`); if (!res.ok) throw new Error("Failed to fetch patient"); return res.json(); }, enabled: !!patientId, }); // Sync fetched patient when available useEffect(() => { if (fetchedPatient) { setPatient(fetchedPatient); } }, [fetchedPatient]); //Fetching staff memebers const [staff, setStaff] = useState(null); const { data: staffMembersRaw = [] as Staff[], isLoading: isLoadingStaff } = useQuery({ queryKey: ["/api/staffs/"], queryFn: async () => { const res = await apiRequest("GET", "/api/staffs/"); return res.json(); }, }); useEffect(() => { if (staffMembersRaw.length > 0 && !staff) { const firstStaff = staffMembersRaw[0]; if (firstStaff) setStaff(firstStaff); } }, [staffMembersRaw, staff]); // Service date state const [serviceDateValue, setServiceDateValue] = useState(new Date()); const [serviceDate, setServiceDate] = useState( new Date().toLocaleDateString("en-CA") // "YYYY-MM-DD" ); useEffect(() => { if (extractedData?.serviceDate) { const parsed = new Date(extractedData.serviceDate); const isoFormatted = parsed.toLocaleDateString("en-CA"); setServiceDateValue(parsed); setServiceDate(isoFormatted); } }, [extractedData]); // Update service date when calendar date changes const onServiceDateChange = (date: Date | undefined) => { if (date) { const formattedDate = date.toLocaleDateString("en-CA"); // "YYYY-MM-DD" setServiceDateValue(date); setServiceDate(formattedDate); setForm((prev) => ({ ...prev, serviceDate: formattedDate })); } }; // Determine patient date of birth format const formatDOB = (dob: string | undefined) => { if (!dob) return ""; if (/^\d{2}\/\d{2}\/\d{4}$/.test(dob)) return dob; // already MM/DD/YYYY if (/^\d{4}-\d{2}-\d{2}/.test(dob)) { const datePart = dob?.split("T")[0]; // safe optional chaining if (!datePart) return ""; const [year, month, day] = datePart.split("-"); return `${month}/${day}/${year}`; } return dob; }; // MAIN FORM INITIAL STATE const [form, setForm] = useState({ patientId: patientId || 0, appointmentId: 0, //need to update userId: Number(user?.id), staffId: Number(staff?.id), patientName: `${patient?.firstName} ${patient?.lastName}`.trim(), memberId: patient?.insuranceId, dateOfBirth: formatDOB(patient?.dateOfBirth), remarks: "", serviceDate: serviceDate, insuranceProvider: "", status: "pending", massdhp_username: "", massdhp_password: "", serviceLines: [ { procedureCode: "", procedureDate: serviceDate, oralCavityArea: "", toothNumber: "", toothSurface: "", billedAmount: 0, }, ], uploadedFiles: [], }); // Sync patient data to form when patient updates useEffect(() => { if (patient) { const fullName = `${patient.firstName || ""} ${patient.lastName || ""}`.trim(); setForm((prev) => ({ ...prev, patientName: fullName, dateOfBirth: formatDOB(patient.dateOfBirth), memberId: patient.insuranceId || "", patientId: patient.id, })); } }, [patient]); useEffect(() => { setForm((prevForm) => { const updatedLines = prevForm.serviceLines.map((line) => ({ ...line, procedureDate: serviceDate, // set all to current serviceDate string })); return { ...prevForm, serviceLines: updatedLines, serviceDate, // keep form.serviceDate in sync as well }; }); }, [serviceDate]); // Handle patient field changes (to make inputs controlled and editable) const updatePatientField = (field: keyof Patient, value: any) => { setPatient((prev) => (prev ? { ...prev, [field]: value } : null)); }; const updateServiceLine = ( index: number, field: keyof ServiceLine, value: any ) => { const updatedLines = [...form.serviceLines]; if (updatedLines[index]) { if (field === "billedAmount") { updatedLines[index][field] = parseFloat(value) || 0; } else { updatedLines[index][field] = value; } } setForm({ ...form, serviceLines: updatedLines }); }; const updateProcedureDate = (index: number, date: Date | undefined) => { if (!date) return; const formattedDate = date.toLocaleDateString("en-CA"); const updatedLines = [...form.serviceLines]; if (updatedLines[index]) { updatedLines[index].procedureDate = formattedDate; } setForm({ ...form, serviceLines: updatedLines }); }; // FILE UPLOAD ZONE const [isUploading, setIsUploading] = useState(false); const handleFileUpload = (files: File[]) => { setIsUploading(true); const validFiles = files.filter((file) => file.type === "application/pdf"); if (validFiles.length > 5) { toast({ title: "Too Many Files", description: "You can only upload up to 5 PDFs.", variant: "destructive", }); setIsUploading(false); return; } setForm((prev) => ({ ...prev, uploadedFiles: validFiles, })); toast({ title: "Files Selected", description: `${validFiles.length} PDF file(s) ready for processing.`, }); setIsUploading(false); }; // Delta MA Button Handler const handleDeltaMASubmit = async () => { function convertToISODate(mmddyyyy: string): string { const [month, day, year] = mmddyyyy.split("/"); return `${year}-${month?.padStart(2, "0")}-${day?.padStart(2, "0")}`; } const appointmentData = { patientId: patientId, date: serviceDate, staffId: staff?.id, }; // 1. Create or update appointment const appointmentId = await onHandleAppointmentSubmit(appointmentData); // 2. Update patient if (patient && typeof patient.id === "number") { const { id, createdAt, userId, ...sanitizedFields } = patient; const updatedPatientFields = { id, ...sanitizedFields, insuranceProvider: "Delta MA", }; onHandleUpdatePatient(updatedPatientFields); } else { toast({ title: "Error", description: "Cannot update patient: Missing or invalid patient data", variant: "destructive", }); } // 3. Create Claim(if not) const { uploadedFiles, massdhp_username, massdhp_password, ...formToCreateClaim } = form; onSubmit({ ...formToCreateClaim, staffId: Number(staff?.id), patientId: patientId, insuranceProvider: "Delta MA", appointmentId: appointmentId!, }); // 4. sending form data to selenium service onHandleForSelenium({ ...form, staffId: Number(staff?.id), patientId: patientId, insuranceProvider: "Delta MA", appointmentId: appointmentId!, massdhp_username: "kqkgaox@yahoo.com", massdhp_password: "Lex123456", //fetch this from db, by call }); // 4. Close form onClose(); }; return (
Insurance Claim Form
{/* Patient Information */}
setForm({ ...form, memberId: e.target.value }) } />
{ updatePatientField("dateOfBirth", e.target.value); setForm((prev) => ({ ...prev, dateOfBirth: e.target.value, })); }} disabled={isLoading} />
{ updatePatientField("firstName", e.target.value); setForm((prev) => ({ ...prev, patientName: `${e.target.value} ${patient?.lastName || ""}`.trim(), })); }} disabled={isLoading} />
{ updatePatientField("lastName", e.target.value); setForm((prev) => ({ ...prev, patientName: `${patient?.firstName || ""} ${e.target.value}`.trim(), })); }} disabled={isLoading} />
{/* Clinical Notes Entry */}
setForm({ ...form, remarks: e.target.value })} />
{/* Service Lines */}

Service Lines

{/* Service Date */}
{/* Treating doctor */}
Procedure Code Procedure Date Oral Cavity Area Tooth Number Tooth Surface Billed Amount
{/* Dynamic Rows */} {form.serviceLines.map((line, i) => (
updateServiceLine(i, "procedureCode", e.target.value) } /> {/* Date Picker */} updateProcedureDate(i, date)} /> updateServiceLine(i, "oralCavityArea", e.target.value) } /> updateServiceLine(i, "toothNumber", e.target.value) } /> updateServiceLine(i, "toothSurface", e.target.value) } /> updateServiceLine(i, "billedAmount", e.target.value) } />
))}
{/* File Upload Section */}

Only PDF files allowed. You can upload up to 5 files. File types with 4+ character extensions like .DOCX, .PPTX, or .XLSX are not allowed.

{form.uploadedFiles.length > 0 && (
    {form.uploadedFiles.map((file, index) => (
  • {file.name}
  • ))}
)}
{/* Insurance Carriers */}

Insurance Carriers

); }