import { useState, useEffect, useRef, useCallback, memo } 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 { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; import { X, Calendar as CalendarIcon, HelpCircle, Trash2 } from "lucide-react"; import { useToast } from "@/hooks/use-toast"; import { Calendar } from "@/components/ui/calendar"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { useQuery } from "@tanstack/react-query"; import { apiRequest } from "@/lib/queryClient"; import { MultipleFileUploadZone, MultipleFileUploadZoneHandle, } from "../file-upload/multiple-file-upload-zone"; import { useAuth } from "@/hooks/use-auth"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { formatLocalDate, parseLocalDate } from "@/utils/dateUtils"; import { Claim, ClaimFileMeta, ClaimFormData, ClaimPreAuthData, InputServiceLine, InsertAppointment, MissingTeethStatus, Patient, Staff, UpdateAppointment, UpdatePatient, } from "@repo/db/types"; import { Decimal } from "decimal.js"; import { mapPricesForForm, applyComboToForm, getDescriptionForCode, } from "@/utils/procedureCombosMapping"; import { COMBO_CATEGORIES, PROCEDURE_COMBOS } from "@/utils/procedureCombos"; import { DateInput } from "../ui/dateInput"; import { MissingTeethSimple, type MissingMapStrict } from "./tooth-ui"; import { RemarksField } from "./claims-ui"; interface ClaimFormProps { patientId: number; appointmentId?: number; onSubmit: (data: ClaimFormData) => Promise; onHandleAppointmentSubmit: ( appointmentData: InsertAppointment | UpdateAppointment ) => Promise; onHandleUpdatePatient: (patient: UpdatePatient & { id: number }) => void; onHandleForMHSeleniumClaim: (data: ClaimFormData) => void; onHandleForMHSeleniumClaimPreAuth: (data: ClaimPreAuthData) => void; onClose: () => void; } const PERMANENT_TOOTH_NAMES = Array.from( { length: 32 }, (_, i) => `T_${i + 1}` ); const PRIMARY_TOOTH_NAMES = Array.from("ABCDEFGHIJKLMNOPQRST").map( (ch) => `T_${ch}` ); function isValidToothKey(key: string) { return ( PERMANENT_TOOTH_NAMES.includes(key) || PRIMARY_TOOTH_NAMES.includes(key) ); } export function ClaimForm({ patientId, appointmentId, onHandleAppointmentSubmit, onHandleUpdatePatient, onHandleForMHSeleniumClaim, onHandleForMHSeleniumClaimPreAuth, onSubmit, onClose, }: ClaimFormProps) { const { toast } = useToast(); const { user } = useAuth(); const [patient, setPatient] = useState(null); // Query patient based on given patient id 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 kaiGao = staffMembersRaw.find( (member) => member.name === "Kai Gao" ); const defaultStaff = kaiGao || staffMembersRaw[0]; if (defaultStaff) setStaff(defaultStaff); } }, [staffMembersRaw, staff]); // Service date state const [serviceDateValue, setServiceDateValue] = useState(new Date()); const [serviceDate, setServiceDate] = useState( formatLocalDate(new Date()) ); const [serviceDateOpen, setServiceDateOpen] = useState(false); const [openProcedureDateIndex, setOpenProcedureDateIndex] = useState< number | null >(null); //incase when appointmentId is given - directly from appoinmentpage - claimpage - to here. // then, update the service date as per the appointment date. useEffect(() => { if (!appointmentId) return; if (!Number.isFinite(appointmentId) || appointmentId <= 0) return; let cancelled = false; (async () => { try { const res = await apiRequest( "GET", `/api/appointments/${appointmentId}` ); if (!res.ok) { let body: any = null; try { body = await res.json(); } catch {} if (!cancelled) { toast({ title: "Failed to load appointment", description: body?.message ?? body?.error ?? `Could not fetch appointment ${appointmentId}.`, variant: "destructive", }); } return; } const appointment = await res.json(); // appointment.date is expected to be either "YYYY-MM-DD" or an ISO string. const rawDate = appointment?.date ?? appointment?.day ?? ""; if (!rawDate) return; // Use your parseLocalDate to create a local-midnight Date (avoid TZ shifts) let dateVal: Date; try { dateVal = parseLocalDate(String(rawDate)); } catch (e) { // Fallback - try constructing Date and then normalize const maybe = new Date(rawDate); if (isNaN(maybe.getTime())) { console.error("Could not parse appointment date:", rawDate); return; } dateVal = new Date( maybe.getFullYear(), maybe.getMonth(), maybe.getDate() ); } if (!cancelled) { setServiceDateValue(dateVal); setServiceDate(formatLocalDate(dateVal)); } } catch (err: any) { if (!cancelled) { console.error("Error fetching appointment:", err); toast({ title: "Error", description: err?.message ?? "Failed to fetch Appointment.", variant: "destructive", }); } } })(); return () => { cancelled = true; }; }, [appointmentId]); // Update service date when calendar date changes const onServiceDateChange = (date: Date | undefined) => { if (date) { const formattedDate = formatLocalDate(date); setServiceDateValue(date); setServiceDate(formattedDate); setForm((prev) => ({ ...prev, serviceDate: formattedDate })); } }; // when service date is chenged, it will change the each service lines procedure date in sync as well. 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]); // Determine patient date of birth format - required as date extracted from pdfs has different format. // Replace previous implementation with this type-safe normalizer. // Always returns canonical YYYY-MM-DD or "" if it cannot parse. function normalizeToIsoDateString(dob: string | Date | undefined): string { if (!dob) return ""; // Date object -> canonicalize if (dob instanceof Date) { if (isNaN(dob.getTime())) return ""; return formatLocalDate(dob); } const raw = String(dob).trim(); if (!raw) return ""; // 1) If already date-only ISO (yyyy-mm-dd) if (/^\d{4}-\d{2}-\d{2}$/.test(raw)) { try { parseLocalDate(raw); // validate return raw; } catch { return ""; } } // 2) Try parseLocalDate for ISO-like inputs (will throw if not suitable) try { const parsed = parseLocalDate(raw); return formatLocalDate(parsed); } catch { // continue to other fallbacks } // 3) MM/DD/YYYY or M/D/YYYY -> convert to ISO const m1 = raw.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/); if (m1) { const mm = m1[1] ?? ""; const dd = m1[2] ?? ""; const yyyy = m1[3] ?? ""; if (mm && dd && yyyy) { const iso = `${yyyy}-${mm.padStart(2, "0")}-${dd.padStart(2, "0")}`; try { parseLocalDate(iso); return iso; } catch { return ""; } } } // 4) OCR-ish short form: MMDDYY (exactly 6 digits) -> guess century const m2 = raw.match(/^(\d{6})$/); if (m2) { const s = m2[1]; if (s && s.length === 6) { const mm = s.slice(0, 2); const dd = s.slice(2, 4); const yy = s.slice(4, 6); const year = Number(yy) < 50 ? 2000 + Number(yy) : 1900 + Number(yy); const iso = `${year}-${mm.padStart(2, "0")}-${dd.padStart(2, "0")}`; try { parseLocalDate(iso); return iso; } catch { return ""; } } } // 5) Last resort: naive Date parse -> normalize to local calendar fields try { const maybe = new Date(raw); if (!isNaN(maybe.getTime())) { return formatLocalDate(maybe); } } catch { /* ignore */ } return ""; } // assumes input is either "" or "YYYY-MM-DD" const toMMDDYYYY = (iso: string): string => { if (!iso) return ""; const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso); return m ? `${m[2]}-${m[3]}-${m[1]}` : ""; }; // MAIN FORM INITIAL STATE const [form, setForm] = useState({ patientId: patientId || 0, appointmentId: 0, userId: Number(user?.id), staffId: Number(staff?.id), patientName: `${patient?.firstName} ${patient?.lastName}`.trim(), memberId: patient?.insuranceId ?? "", dateOfBirth: normalizeToIsoDateString(patient?.dateOfBirth), remarks: "", missingTeethStatus: "No_missing", missingTeeth: {} as MissingMapStrict, serviceDate: serviceDate, insuranceProvider: "", insuranceSiteKey: "", status: "PENDING", serviceLines: Array.from({ length: 10 }, () => ({ procedureCode: "", procedureDate: serviceDate, oralCavityArea: "", toothNumber: "", toothSurface: "", totalBilled: new Decimal(0), totalAdjusted: new Decimal(0), totalPaid: new Decimal(0), })), uploadedFiles: [], }); // Sync patient data to form when patient updates useEffect(() => { if (patient) { const fullName = `${patient.firstName || ""} ${patient.lastName || ""}`.trim(); setForm((prev) => ({ ...prev, patientId: Number(patient.id), patientName: fullName, dateOfBirth: normalizeToIsoDateString(patient.dateOfBirth), memberId: patient.insuranceId || "", })); } }, [patient]); // 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 InputServiceLine, value: any ) => { const updatedLines = [...form.serviceLines]; if (updatedLines[index]) { if (field === "totalBilled") { const num = typeof value === "string" ? parseFloat(value) : value; const rounded = Math.round((isNaN(num) ? 0 : num) * 100) / 100; updatedLines[index][field] = new Decimal(rounded); } else { updatedLines[index][field] = value; } } setForm({ ...form, serviceLines: updatedLines }); }; const updateProcedureDate = (index: number, date: Date | undefined) => { if (!date) return; const formattedDate = formatLocalDate(date); const updatedLines = [...form.serviceLines]; if (updatedLines[index]) { updatedLines[index].procedureDate = formattedDate; } setForm({ ...form, serviceLines: updatedLines }); }; // normalize for display while typing: uppercase and allow letters, commas and spaces function normalizeToothSurface(raw?: string): string { if (!raw) return ""; // Uppercase and remove characters that are not A-Z, comma or space return raw.toUpperCase().replace(/[^A-Z,\s]/g, ""); } // Missing teeth section const setMissingTeethStatus = (status: MissingTeethStatus) => { setForm((prev) => { if (prev.missingTeethStatus === status) return prev; // no-op return { ...prev, missingTeethStatus: status, missingTeeth: status === "Yes_missing" ? prev.missingTeeth : {}, }; }); }; const updateMissingTooth = useCallback( (name: string, value: "" | "X" | "O") => { if (!isValidToothKey(name)) return; setForm((prev) => { const current = prev.missingTeeth[name] ?? ""; if (current === value) return prev; const nextMap = { ...prev.missingTeeth }; if (!value) delete nextMap[name]; else nextMap[name] = value; return { ...prev, missingTeeth: nextMap }; }); }, [] ); const clearAllToothSelections = () => setForm((prev) => ({ ...prev, missingTeeth: {} as MissingMapStrict })); // for serviceLine rows, to auto scroll when it got updated by combo buttons and all. const rowRefs = useRef<(HTMLDivElement | null)[]>([]); const scrollToLine = (index: number) => { const el = rowRefs.current[index]; if (el) { el.scrollIntoView({ behavior: "smooth", block: "start" }); } }; // Map Price function const onMapPrice = () => { setForm((prev) => mapPricesForForm({ form: prev, patientDOB: patient?.dateOfBirth ?? "", }) ); }; // FILE UPLOAD ZONE const uploadZoneRef = useRef(null); const [isUploading, setIsUploading] = useState(false); // NO validation here — the upload zone handles validation, toasts, max files, sizes, etc. const handleFilesChange = useCallback((files: File[]) => { setForm((prev) => ({ ...prev, uploadedFiles: files })); }, []); // 1st Button workflow - Mass Health Button Handler const handleMHSubmit = async ( formToUse?: ClaimFormData & { uploadedFiles?: File[] } ) => { // Use the passed form, or fallback to current state const f = formToUse ?? form; // 0. Validate required fields const missingFields: string[] = []; if (!f.memberId?.trim()) missingFields.push("Member ID"); if (!f.dateOfBirth?.trim()) missingFields.push("Date of Birth"); if (!patient?.firstName?.trim()) missingFields.push("First Name"); if (missingFields.length > 0) { toast({ title: "Missing Required Fields", description: `Please fill out the following field(s): ${missingFields.join(", ")}`, variant: "destructive", }); return; } // require at least one procedure code before proceeding const filteredServiceLines = (f.serviceLines || []).filter( (line) => (line.procedureCode ?? "").trim() !== "" ); if (filteredServiceLines.length === 0) { toast({ title: "No procedure codes", description: "Please add at least one procedure code before submitting the claim.", variant: "destructive", }); return; } // 1. Create or update appointment let appointmentIdToUse = appointmentId; if (appointmentIdToUse == null) { const appointmentData = { patientId: patientId, date: serviceDate, staffId: staff?.id, }; const created = await onHandleAppointmentSubmit(appointmentData); if (typeof created === "number" && created > 0) { appointmentIdToUse = created; } else if (created && typeof (created as any).id === "number") { appointmentIdToUse = (created as any).id; } } // 2. Update patient if (patient && typeof patient.id === "number") { const { id, createdAt, userId, ...sanitizedFields } = patient; const updatedPatientFields = { id, ...sanitizedFields, insuranceProvider: "MassHealth", }; onHandleUpdatePatient(updatedPatientFields); } else { toast({ title: "Error", description: "Cannot update patient: Missing or invalid patient data", variant: "destructive", }); } // 3. Create Claim(if not) // Filter out empty service lines (empty procedureCode) const { uploadedFiles, insuranceSiteKey, ...formToCreateClaim } = f; // build claimFiles metadata from uploadedFiles (only filename + mimeType) const claimFilesMeta: ClaimFileMeta[] = (uploadedFiles || []).map((f) => ({ filename: f.name, mimeType: f.type, })); const createdClaim = await onSubmit({ ...formToCreateClaim, serviceLines: filteredServiceLines, staffId: Number(staff?.id), patientId: patientId, insuranceProvider: "MassHealth", appointmentId: appointmentIdToUse!, claimFiles: claimFilesMeta, }); // 4. sending form data to selenium service onHandleForMHSeleniumClaim({ ...f, dateOfBirth: toMMDDYYYY(f.dateOfBirth), serviceLines: filteredServiceLines, staffId: Number(staff?.id), patientId: patientId, insuranceProvider: "Mass Health", appointmentId: appointmentIdToUse!, insuranceSiteKey: "MH", claimId: createdClaim.id, }); // 5. Close form onClose(); }; // 2st Button workflow - Mass Health Pre Auth Button Handler const handleMHPreAuth = async ( formToUse?: ClaimFormData & { uploadedFiles?: File[] } ) => { // Use the passed form, or fallback to current state const f = formToUse ?? form; // 0. Validate required fields const missingFields: string[] = []; if (!f.memberId?.trim()) missingFields.push("Member ID"); if (!f.dateOfBirth?.trim()) missingFields.push("Date of Birth"); if (!patient?.firstName?.trim()) missingFields.push("First Name"); if (missingFields.length > 0) { toast({ title: "Missing Required Fields", description: `Please fill out the following field(s): ${missingFields.join(", ")}`, variant: "destructive", }); return; } // require at least one procedure code before proceeding const filteredServiceLines = (f.serviceLines || []).filter( (line) => (line.procedureCode ?? "").trim() !== "" ); if (filteredServiceLines.length === 0) { toast({ title: "No procedure codes", description: "Please add at least one procedure code before submitting the claim preAuth.", variant: "destructive", }); return; } // 2. Update patient if (patient && typeof patient.id === "number") { const { id, createdAt, userId, ...sanitizedFields } = patient; const updatedPatientFields = { id, ...sanitizedFields, insuranceProvider: "MassHealth", }; onHandleUpdatePatient(updatedPatientFields); } else { toast({ title: "Error", description: "Cannot update patient: Missing or invalid patient data", variant: "destructive", }); } // 4. sending form data to selenium service onHandleForMHSeleniumClaimPreAuth({ ...f, dateOfBirth: toMMDDYYYY(f.dateOfBirth), serviceLines: filteredServiceLines, staffId: Number(staff?.id), patientId: patientId, insuranceProvider: "Mass Health", insuranceSiteKey: "MH", }); // 5. Close form onClose(); }; // 3nd Button workflow - Only Creates Data, patient, appointmetn, claim, payment, not actually submits claim to MH site. const handleAddService = async () => { // 0. Validate required fields const missingFields: string[] = []; if (!form.memberId?.trim()) missingFields.push("Member ID"); if (!form.dateOfBirth?.trim()) missingFields.push("Date of Birth"); if (!patient?.firstName?.trim()) missingFields.push("First Name"); if (missingFields.length > 0) { toast({ title: "Missing Required Fields", description: `Please fill out the following field(s): ${missingFields.join(", ")}`, variant: "destructive", }); return; } // require at least one procedure code before proceeding const filteredServiceLines = (form.serviceLines || []).filter( (line) => (line.procedureCode ?? "").trim() !== "" ); if (filteredServiceLines.length === 0) { toast({ title: "No procedure codes", description: "Please add at least one procedure code before submitting the claim.", variant: "destructive", }); return; } // 1. Create or update appointment let appointmentIdToUse = appointmentId; if (appointmentIdToUse == null) { const appointmentData = { patientId: patientId, date: serviceDate, staffId: staff?.id, }; const created = await onHandleAppointmentSubmit(appointmentData); if (typeof created === "number" && created > 0) { appointmentIdToUse = created; } else if (created && typeof (created as any).id === "number") { appointmentIdToUse = (created as any).id; } } // 2. Update patient if (patient && typeof patient.id === "number") { const { id, createdAt, userId, ...sanitizedFields } = patient; const updatedPatientFields = { id, ...sanitizedFields, insuranceProvider: "MassHealth", }; onHandleUpdatePatient(updatedPatientFields); } else { toast({ title: "Error", description: "Cannot update patient: Missing or invalid patient data", variant: "destructive", }); } // 3. Create Claim(if not) // Filter out empty service lines (empty procedureCode) const { uploadedFiles, insuranceSiteKey, ...formToCreateClaim } = form; // build claimFiles metadata from uploadedFiles (only filename + mimeType) const claimFilesMeta: ClaimFileMeta[] = (uploadedFiles || []).map((f) => ({ filename: f.name, mimeType: f.type, })); const createdClaim = await onSubmit({ ...formToCreateClaim, serviceLines: filteredServiceLines, staffId: Number(staff?.id), patientId: patientId, insuranceProvider: "MassHealth", appointmentId: appointmentIdToUse!, claimFiles: claimFilesMeta, }); // 4. Close form onClose(); }; // for direct combo button. const applyComboAndThenMH = async ( comboId: keyof typeof PROCEDURE_COMBOS ) => { const nextForm = applyComboToForm( form, comboId, patient?.dateOfBirth ?? "", { replaceAll: false, lineDate: form.serviceDate } ); setForm(nextForm); setTimeout(() => scrollToLine(0), 0); await handleMHSubmit(nextForm); }; // overlay click handler (close when clicking backdrop) const onOverlayMouseDown = (e: React.MouseEvent) => { // only close if clicked the backdrop itself (not inner modal) if (e.target === e.currentTarget) { onClose(); } }; return (
Insurance Claim Form
{/* Patient Information */}
{ setForm({ ...form, memberId: e.target.value }); updatePatientField("insuranceId", e.target.value); }} />
{ const formatted = date ? formatLocalDate(date) : ""; setForm((prev) => ({ ...prev, dateOfBirth: formatted })); updatePatientField("dateOfBirth", formatted); }} disableFuture />
{ 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} />
{/* Service Lines */}

Service Lines

{/* Service Date */}
{ onServiceDateChange(date); }} onClose={() => setServiceDateOpen(false)} /> {/* Treating doctor */} {/* Map Price Button */}
{/* Section Title */}
Direct Claim Submission Buttons
{/* CHILD RECALL GROUP */}
Child Recall
{[ "childRecallDirect", "childRecallDirect2BW", "childRecallDirect4BW", "childRecallDirect2PA2BW", "childRecallDirect2PA4BW", "childRecallDirectPANO", ].map((comboId) => { const b = PROCEDURE_COMBOS[comboId]; if (!b) return null; const codesWithTooth = b.codes.map((code, idx) => { const tooth = b.toothNumbers?.[idx]; return tooth ? `${code} (tooth ${tooth})` : code; }); const tooltipText = codesWithTooth.join(", "); const labelMap: Record = { childRecallDirect: "Direct", childRecallDirect2BW: "Direct 2BW", childRecallDirect4BW: "Direct 4BW", childRecallDirect2PA2BW: "Direct 2PA 2BW", childRecallDirect2PA4BW: "Direct 2PA 4BW", childRecallDirectPANO: "Direct Pano", }; return (
{tooltipText}
); })}
{/* ADULT RECALL GROUP */}
Adult Recall
{[ "adultRecallDirect", "adultRecallDirect2BW", "adultRecallDirect4BW", "adultRecallDirect2PA2BW", "adultRecallDirect2PA4BW", "adultRecallDirectPano", ].map((comboId) => { const b = PROCEDURE_COMBOS[comboId]; if (!b) return null; const codesWithTooth = b.codes.map((code, idx) => { const tooth = b.toothNumbers?.[idx]; return tooth ? `${code} (tooth ${tooth})` : code; }); const tooltipText = codesWithTooth.join(", "); const labelMap: Record = { adultRecallDirect: "Direct", adultRecallDirect2BW: "Direct 2BW", adultRecallDirect4BW: "Direct 4BW", adultRecallDirect2PA2BW: "Direct 2PA 2BW", adultRecallDirect2PA4BW: "Direct 2PA 4BW", adultRecallDirectPano: "Direct Pano", }; return (
{tooltipText}
); })}
{/* ORTH GROUP */}
Orth
{[ "orthPreExamDirect", "orthRecordDirect", "orthPerioVisitDirect", "orthRetentionDirect", ].map((comboId) => { const b = PROCEDURE_COMBOS[comboId]; if (!b) return null; const tooltipText = b.codes.join(", "); return (
{tooltipText}
); })}
{/* Header */}
Procedure Code
Info Procedure Date Oral Cavity Area Tooth Number Tooth Surface Billed Amount
{/* Dynamic Rows */} {form.serviceLines.map((line, i) => { const raw = line.procedureCode || ""; const code = raw.trim(); const desc = code ? getDescriptionForCode(code) || "No description available" : "Enter a procedure code"; return (
{ rowRefs.current[i] = el; if (!el) rowRefs.current.splice(i, 1); }} className="scroll-mt-28 grid grid-cols-[1.5fr,0.5fr,1fr,1fr,1fr,1fr,1fr] gap-1 mb-2 items-center" >
updateServiceLine( i, "procedureCode", e.target.value.toUpperCase() ) } />
{desc}
{/* Date Picker */} setOpenProcedureDateIndex(open ? i : null) } > updateProcedureDate(i, date)} onClose={() => setOpenProcedureDateIndex(null)} /> updateServiceLine(i, "oralCavityArea", e.target.value) } /> updateServiceLine(i, "toothNumber", e.target.value) } /> { const typed = normalizeToothSurface(e.target.value); updateServiceLine(i, "toothSurface", typed); }} /> { updateServiceLine(i, "totalBilled", e.target.value); }} onBlur={(e) => { const val = parseFloat(e.target.value); const rounded = Math.round(val * 100) / 100; updateServiceLine( i, "totalBilled", isNaN(rounded) ? 0 : rounded ); }} />
); })}
{Object.entries(COMBO_CATEGORIES).map(([section, ids]) => (
{section}
{ids.map((id) => { const b = PROCEDURE_COMBOS[id]; if (!b) { return; } // Build a human readable string for the tooltip const codesWithTooth = b.codes.map((code, idx) => { const tooth = b.toothNumbers?.[idx]; return tooth ? `${code} (tooth ${tooth})` : code; }); const tooltipText = codesWithTooth.join(", "); return (
{tooltipText}
); })}
))}
{/* File Upload Section */}

File Upload

You can upload up to 10 files. Allowed types: PDF, JPG, PNG, WEBP.

{form.uploadedFiles.length > 0 && (
    {form.uploadedFiles.map((file, index) => (
  • {file.name}
  • ))}
)}
{/* Missing Teeth (MassHealth Step 3) */}

Missing Teeth

{/* Status selector – must match Selenium's exact case */}
{form.missingTeethStatus === "Yes_missing" && ( )}
{/* When specifying per-tooth values, show Permanent + Primary grids */} {form.missingTeethStatus === "Yes_missing" && ( setForm((prev) => ({ ...prev, missingTeeth: next })) } /> )}
{/* Clinical Notes Entry */}

Remarks

setForm((prev) => ({ ...prev, remarks: next })) } />
{/* Insurance Carriers */}

Insurance Carriers

); }