feat: Preauth column for AI claims; searchable policy holder + ADA box 18; 2PA fix
- Schedule: last column is the Preauth column; "Claim for Column with AI" is now "Claim/Preauth for Column with AI" — that column's appointments go to PreAuth (MH, CCA, Tufts SCO, United/DentalHub; other insurances are skipped), the rest to Claim. Preauthorized appointments (hasPreauth) aren't resubmitted - PreAuth payloads carry appointmentId; appointment X-rays/attachments are sent with MH/CCA/UnitedDH/Tufts preauths (shared appendAppointmentFiles helper) - Patient form: policy holder is searchable from patients in the DB, plus "Relationship to Policy Holder/Subscriber" (Self, Spouse, Dependent Child, Other). New Patient columns policyHolderPatientId, policyHolderRelationship; browser-side schema updated so the fields aren't stripped on save - ADA form: box 12-14 filled from the linked policy holder's record; box 18 ticks the relationship (Self when the patient is the holder) - AI notes: a bare "2PA" is an image count, not tooth #2 — restored before CDT lookup so it maps to D0220 #8 / D0230 #24 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -638,7 +638,8 @@ export function ClaimForm({
|
||||
insuranceSiteKey,
|
||||
});
|
||||
});
|
||||
setPrefillDone(true);
|
||||
// With an appointment, 2b (procedures + X-ray attachments) marks prefill done
|
||||
if (!appointmentId) setPrefillDone(true);
|
||||
} catch {}
|
||||
}, []);
|
||||
|
||||
@@ -1118,6 +1119,7 @@ export function ClaimForm({
|
||||
patientId: patientId,
|
||||
insuranceProvider: "Mass Health",
|
||||
insuranceSiteKey: "MH",
|
||||
appointmentId: appointmentId ?? 0,
|
||||
});
|
||||
|
||||
// 5. Close form
|
||||
@@ -1607,6 +1609,7 @@ export function ClaimForm({
|
||||
patientId,
|
||||
insuranceProvider: "CCA",
|
||||
insuranceSiteKey: "CCA",
|
||||
appointmentId: appointmentId ?? 0,
|
||||
});
|
||||
|
||||
onClose();
|
||||
@@ -1650,7 +1653,8 @@ export function ClaimForm({
|
||||
patientId,
|
||||
insuranceProvider: "United/DentalHub",
|
||||
insuranceSiteKey: "UNITED_SCO",
|
||||
claimFiles: udPreAuthFilesMeta,
|
||||
appointmentId: appointmentId ?? 0,
|
||||
claimFiles: mergeWithExistingAttachments(udPreAuthFilesMeta),
|
||||
});
|
||||
|
||||
onClose();
|
||||
@@ -1694,7 +1698,8 @@ export function ClaimForm({
|
||||
patientId,
|
||||
insuranceProvider: "Tufts SCO",
|
||||
insuranceSiteKey: "TUFTS_SCO",
|
||||
claimFiles: preAuthFilesMeta,
|
||||
appointmentId: appointmentId ?? 0,
|
||||
claimFiles: mergeWithExistingAttachments(preAuthFilesMeta),
|
||||
});
|
||||
|
||||
onClose();
|
||||
|
||||
@@ -32,6 +32,15 @@ import {
|
||||
} from "@repo/db/types";
|
||||
import { z } from "zod";
|
||||
import { DateInputField } from "@/components/ui/dateInputField";
|
||||
import { PolicyHolderSearch } from "@/components/patients/policy-holder-search";
|
||||
|
||||
// ADA claim form box 18 — relationship to policyholder/subscriber
|
||||
const POLICY_HOLDER_RELATIONSHIPS = [
|
||||
{ value: "SELF", label: "Self" },
|
||||
{ value: "SPOUSE", label: "Spouse" },
|
||||
{ value: "DEPENDENT", label: "Dependent Child" },
|
||||
{ value: "OTHER", label: "Other" },
|
||||
];
|
||||
|
||||
// New England first (most patients), then the remaining states alphabetically
|
||||
const US_STATES = [
|
||||
@@ -53,6 +62,11 @@ interface PatientFormProps {
|
||||
onSubmit: (data: InsertPatient | UpdatePatient) => void;
|
||||
}
|
||||
|
||||
// Patients saved before the relationship field existed: no policy holder means the
|
||||
// patient is the holder, so show Self (matches how the ADA form treats them).
|
||||
const defaultRelationship = (p: Patient): string =>
|
||||
p.policyHolderRelationship || (!(p.policyHolder ?? "").trim() ? "SELF" : "");
|
||||
|
||||
export type PatientFormRef = {
|
||||
submit: () => void;
|
||||
};
|
||||
@@ -100,6 +114,7 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
|
||||
? formatLocalDate(new Date(patient.dateOfBirth))
|
||||
: null,
|
||||
insuranceProvider: normalizeInsuranceProvider(patient.insuranceProvider),
|
||||
policyHolderRelationship: defaultRelationship(patient),
|
||||
};
|
||||
}
|
||||
return {
|
||||
@@ -117,6 +132,8 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
|
||||
insuranceId: extractedInfo?.insuranceId || "",
|
||||
groupNumber: "",
|
||||
policyHolder: "",
|
||||
policyHolderPatientId: null,
|
||||
policyHolderRelationship: "SELF",
|
||||
allergies: "",
|
||||
medicalConditions: "",
|
||||
preferredLanguage: "English",
|
||||
@@ -156,6 +173,7 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
|
||||
? formatLocalDate(new Date(patient.dateOfBirth))
|
||||
: null,
|
||||
insuranceProvider: normalized,
|
||||
policyHolderRelationship: defaultRelationship(patient),
|
||||
};
|
||||
form.reset(resetValues);
|
||||
// Explicit setValue ensures the controlled Select re-renders with the new value
|
||||
@@ -532,6 +550,41 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="policyHolderRelationship"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Relationship to Policy Holder/Subscriber</FormLabel>
|
||||
<Select
|
||||
value={field.value || ""}
|
||||
onValueChange={(v) => {
|
||||
field.onChange(v);
|
||||
// Self: the patient is the policy holder, so drop any other holder
|
||||
if (v === "SELF") {
|
||||
form.setValue("policyHolder", "", { shouldDirty: true });
|
||||
form.setValue("policyHolderPatientId" as any, null, { shouldDirty: true });
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select relationship" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{POLICY_HOLDER_RELATIONSHIPS.map((r) => (
|
||||
<SelectItem key={r.value} value={r.value}>
|
||||
{r.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="policyHolder"
|
||||
@@ -539,7 +592,19 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
|
||||
<FormItem>
|
||||
<FormLabel>Policy Holder (if not self)</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} value={field.value || ""} />
|
||||
<PolicyHolderSearch
|
||||
value={field.value || ""}
|
||||
holderPatientId={(form.watch("policyHolderPatientId" as any) as number | null) ?? null}
|
||||
excludePatientId={patient?.id}
|
||||
onChange={(name, holderPatientId) => {
|
||||
field.onChange(name);
|
||||
form.setValue("policyHolderPatientId" as any, holderPatientId, { shouldDirty: true });
|
||||
// Picking someone else means the patient isn't the holder
|
||||
if (name.trim() && form.getValues("policyHolderRelationship" as any) === "SELF") {
|
||||
form.setValue("policyHolderRelationship" as any, "", { shouldDirty: true });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@@ -1320,6 +1320,14 @@ export function PatientTable({
|
||||
<span className="text-gray-500">Policy Holder:</span>{" "}
|
||||
{currentPatient.policyHolder || "Self"}
|
||||
</p>
|
||||
{currentPatient.policyHolderRelationship && (
|
||||
<p>
|
||||
<span className="text-gray-500">Relationship:</span>{" "}
|
||||
{({ SELF: "Self", SPOUSE: "Spouse", DEPENDENT: "Dependent Child", OTHER: "Other" } as Record<string, string>)[
|
||||
currentPatient.policyHolderRelationship
|
||||
] ?? currentPatient.policyHolderRelationship}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useDebounce } from "use-debounce";
|
||||
import { X } from "lucide-react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { apiRequest } from "@/lib/queryClient";
|
||||
import { formatLocalDate } from "@/utils/dateUtils";
|
||||
import type { Patient } from "@repo/db/types";
|
||||
|
||||
interface PolicyHolderSearchProps {
|
||||
/** Policy holder name as stored on the patient (free text) */
|
||||
value: string;
|
||||
/** Linked patient record of the policy holder, if one was picked */
|
||||
holderPatientId: number | null;
|
||||
/** Patient being edited — hidden from the results */
|
||||
excludePatientId?: number;
|
||||
onChange: (name: string, holderPatientId: number | null) => void;
|
||||
}
|
||||
|
||||
// Type to search patients in the DB and pick the policy holder; free text is still allowed
|
||||
// for holders who aren't patients here (then holderPatientId is null).
|
||||
export function PolicyHolderSearch({ value, holderPatientId, excludePatientId, onChange }: PolicyHolderSearchProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [debounced] = useDebounce(value.trim(), 300);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// The search API matches one name field at a time, so query by the first word
|
||||
// and narrow by the remaining words here ("john smith" → name=john, then must contain "smith").
|
||||
const tokens = debounced.toLowerCase().split(/[\s,]+/).filter(Boolean);
|
||||
const { data: results = [], isFetching } = useQuery<Patient[]>({
|
||||
queryKey: ["policy-holder-search", tokens[0] ?? ""],
|
||||
queryFn: async () => {
|
||||
const res = await apiRequest(
|
||||
"GET",
|
||||
`/api/patients/search?name=${encodeURIComponent(tokens[0]!)}&limit=50&offset=0`,
|
||||
);
|
||||
if (!res.ok) return [];
|
||||
const payload = await res.json();
|
||||
return Array.isArray(payload) ? payload : (payload.patients ?? []);
|
||||
},
|
||||
enabled: open && tokens.length > 0 && holderPatientId == null,
|
||||
});
|
||||
|
||||
const matches = results
|
||||
.filter((p) => p.id !== excludePatientId)
|
||||
.filter((p) => {
|
||||
const full = `${p.firstName} ${p.lastName}`.toLowerCase();
|
||||
return tokens.every((t) => full.includes(t));
|
||||
})
|
||||
.slice(0, 10);
|
||||
|
||||
useEffect(() => {
|
||||
const onDown = (e: MouseEvent) => {
|
||||
if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) setOpen(false);
|
||||
};
|
||||
document.addEventListener("mousedown", onDown);
|
||||
return () => document.removeEventListener("mousedown", onDown);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={wrapperRef} className="relative">
|
||||
<Input
|
||||
value={value}
|
||||
placeholder="Search patient by name…"
|
||||
autoComplete="off"
|
||||
onFocus={() => setOpen(true)}
|
||||
onChange={(e) => {
|
||||
// Editing the text unlinks any previously selected patient
|
||||
onChange(e.target.value, null);
|
||||
setOpen(true);
|
||||
}}
|
||||
className={holderPatientId != null ? "pr-8 border-blue-400 bg-blue-50" : "pr-8"}
|
||||
/>
|
||||
{value && (
|
||||
<button
|
||||
type="button"
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
|
||||
onClick={() => onChange("", null)}
|
||||
title="Clear"
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
{holderPatientId != null && (
|
||||
<p className="mt-1 text-xs text-blue-600">Linked to patient record #{holderPatientId}</p>
|
||||
)}
|
||||
{open && holderPatientId == null && tokens.length > 0 && (
|
||||
<div className="absolute z-50 mt-1 w-full max-h-60 overflow-y-auto rounded-md border bg-white shadow-md">
|
||||
{isFetching && matches.length === 0 ? (
|
||||
<div className="px-3 py-2 text-xs text-gray-500">Searching…</div>
|
||||
) : matches.length === 0 ? (
|
||||
<div className="px-3 py-2 text-xs text-gray-500">No matching patients — the name will be saved as typed.</div>
|
||||
) : (
|
||||
matches.map((p) => (
|
||||
<button
|
||||
key={p.id}
|
||||
type="button"
|
||||
className="block w-full px-3 py-2 text-left text-sm hover:bg-gray-100"
|
||||
onClick={() => {
|
||||
onChange(`${p.firstName} ${p.lastName}`.trim(), Number(p.id));
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<span className="font-medium">{p.firstName} {p.lastName}</span>
|
||||
<span className="ml-2 text-xs text-gray-500">
|
||||
{p.dateOfBirth ? `DOB ${formatLocalDate(new Date(p.dateOfBirth))}` : ""}
|
||||
{p.insuranceId ? ` · ID ${p.insuranceId}` : ""}
|
||||
</span>
|
||||
</button>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -100,6 +100,7 @@ interface ScheduledAppointment {
|
||||
patientInsuranceProvider: string | null;
|
||||
hasProcedures: boolean;
|
||||
hasClaimWithNumber: boolean;
|
||||
hasPreauth: boolean;
|
||||
movedByAi?: boolean;
|
||||
staffId: number;
|
||||
date: string | Date;
|
||||
@@ -111,6 +112,17 @@ interface ScheduledAppointment {
|
||||
procedureCodes?: string[];
|
||||
}
|
||||
|
||||
// Insurances with an online PreAuth flow on the claims page (others can't be preauthorized there).
|
||||
// Maps either site-key spelling (AI "TUFTS_SCO" / local "TuftsSCO") to the key the claim form expects.
|
||||
const PREAUTH_SITE_KEYS: Record<string, string> = {
|
||||
MH: "MH",
|
||||
CCA: "CCA",
|
||||
TUFTSSCO: "TUFTS_SCO",
|
||||
UNITEDSCO: "UNITED_SCO",
|
||||
};
|
||||
const toPreauthSiteKey = (siteKey: string): string | undefined =>
|
||||
PREAUTH_SITE_KEYS[siteKey.replace(/_/g, "").toUpperCase()];
|
||||
|
||||
function deriveInsuranceSiteKey(provider: string | null | undefined): string {
|
||||
const p = (provider || "").toLowerCase().trim();
|
||||
if (!p) return "";
|
||||
@@ -384,6 +396,10 @@ export default function AppointmentsPage() {
|
||||
color: colors[index % colors.length] || "bg-gray-400",
|
||||
}));
|
||||
|
||||
// The last schedule column is the Preauth column: "Claim/Preauth for Column with AI"
|
||||
// sends its appointments to PreAuth instead of Claim.
|
||||
const preauthStaffId = staffMembers.length ? Number(staffMembers[staffMembers.length - 1]!.id) : null;
|
||||
|
||||
// Initialize column labels from localStorage; default A, B, C… for new staff
|
||||
useEffect(() => {
|
||||
if (!staffMembersRaw.length) return;
|
||||
@@ -703,6 +719,7 @@ export default function AppointmentsPage() {
|
||||
patientInsuranceProvider,
|
||||
hasProcedures: !!(apt as any).hasProcedures,
|
||||
hasClaimWithNumber: !!(apt as any).hasClaimWithNumber,
|
||||
hasPreauth: !!(apt as any).hasPreauth,
|
||||
notes: (apt as any).notes ?? null,
|
||||
procedureCodes: (apt as any).procedureCodes ?? [],
|
||||
movedByAi: !!(apt as any).movedByAi,
|
||||
@@ -1654,10 +1671,12 @@ export default function AppointmentsPage() {
|
||||
const handleClaimForColumnWithAi = async () => {
|
||||
if (selectedClaimAiColumns.size === 0) return;
|
||||
const unclaimed = processedAppointments.filter(
|
||||
(apt) => selectedClaimAiColumns.has(apt.staffId) && !apt.hasClaimWithNumber
|
||||
(apt) =>
|
||||
selectedClaimAiColumns.has(apt.staffId) &&
|
||||
(apt.staffId === preauthStaffId ? !apt.hasPreauth : !apt.hasClaimWithNumber)
|
||||
);
|
||||
if (!unclaimed.length) {
|
||||
toast({ title: "No unclaimed appointments", description: "All appointments in the selected columns are already claimed." });
|
||||
toast({ title: "Nothing to submit", description: "All appointments in the selected columns are already claimed / preauthorized." });
|
||||
return;
|
||||
}
|
||||
const autoRun = autoConfirmEnabled || autoClaimEnabled;
|
||||
@@ -1677,6 +1696,17 @@ export default function AppointmentsPage() {
|
||||
const handleAiClaimConfirm = () => {
|
||||
if (!aiClaimCurrentData) return;
|
||||
const { matchedCodes, siteKey, serviceDate, appointmentId } = aiClaimCurrentData;
|
||||
const isPreauth = aiClaimQueue[aiClaimCurrentIndex]?.staffId === preauthStaffId;
|
||||
const preauthSiteKey = toPreauthSiteKey(siteKey);
|
||||
if (isPreauth && !preauthSiteKey) {
|
||||
toast({
|
||||
title: "PreAuth not supported",
|
||||
description: `${aiClaimCurrentData.patientName}: online PreAuth isn't available for ${siteKey || "this insurance"} — skipped.`,
|
||||
variant: "destructive",
|
||||
});
|
||||
handleAiClaimSkip();
|
||||
return;
|
||||
}
|
||||
// Include current patient in queue; claims-page advances it only on successful submit.
|
||||
const fromCurrent = aiClaimQueue.slice(aiClaimCurrentIndex);
|
||||
if (fromCurrent.length > 0) {
|
||||
@@ -1689,14 +1719,24 @@ export default function AppointmentsPage() {
|
||||
} else {
|
||||
sessionStorage.removeItem("ai_claim_queue");
|
||||
}
|
||||
sessionStorage.setItem("chatbot_claim_prefill", JSON.stringify({
|
||||
codes: matchedCodes,
|
||||
siteKey,
|
||||
serviceDate,
|
||||
autoSubmit: true,
|
||||
}));
|
||||
if (isPreauth) {
|
||||
sessionStorage.removeItem("chatbot_claim_prefill");
|
||||
sessionStorage.setItem("chatbot_preauth_prefill", JSON.stringify({
|
||||
codes: matchedCodes,
|
||||
siteKey: preauthSiteKey,
|
||||
serviceDate,
|
||||
}));
|
||||
} else {
|
||||
sessionStorage.removeItem("chatbot_preauth_prefill");
|
||||
sessionStorage.setItem("chatbot_claim_prefill", JSON.stringify({
|
||||
codes: matchedCodes,
|
||||
siteKey,
|
||||
serviceDate,
|
||||
autoSubmit: true,
|
||||
}));
|
||||
}
|
||||
// BCBS is a paper form filled and saved in the background — come straight back here
|
||||
if (/^bcbs/i.test(siteKey)) sessionStorage.setItem("ai_claim_return_to_schedule", "1");
|
||||
if (!isPreauth && /^bcbs/i.test(siteKey)) sessionStorage.setItem("ai_claim_return_to_schedule", "1");
|
||||
else sessionStorage.removeItem("ai_claim_return_to_schedule");
|
||||
setAiClaimModalOpen(false);
|
||||
setLocation(`/claims?appointmentId=${appointmentId}`);
|
||||
@@ -1924,7 +1964,7 @@ export default function AppointmentsPage() {
|
||||
) : (
|
||||
<>
|
||||
<Bot className="h-4 w-4 mr-1" />
|
||||
Claim for Column with AI
|
||||
Claim/Preauth for Column with AI
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
@@ -2375,8 +2415,14 @@ export default function AppointmentsPage() {
|
||||
{columnLabels[String(staff.id)] ?? String.fromCharCode(65 + index)}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-xs text-gray-500">{staff.name}</div>
|
||||
<div className="text-xs text-gray-400">{staff.role}</div>
|
||||
{Number(staff.id) === preauthStaffId ? (
|
||||
<div className="text-xs font-semibold text-blue-600">Preauth</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="text-xs text-gray-500">{staff.name}</div>
|
||||
<div className="text-xs text-gray-400">{staff.role}</div>
|
||||
</>
|
||||
)}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
@@ -2516,7 +2562,7 @@ export default function AppointmentsPage() {
|
||||
<div className="p-4 border-b flex items-center justify-between">
|
||||
<h3 className="font-semibold text-base flex items-center gap-2">
|
||||
<Bot className="h-4 w-4 text-teal-600" />
|
||||
AI Claim Queue
|
||||
AI Claim/Preauth Queue
|
||||
</h3>
|
||||
<span className="text-xs text-gray-500 font-medium">
|
||||
{aiClaimAutoRun && (
|
||||
@@ -2626,7 +2672,7 @@ export default function AppointmentsPage() {
|
||||
onClick={handleAiClaimConfirm}
|
||||
>
|
||||
<FileCheck className="h-3.5 w-3.5" />
|
||||
Confirm & Claim
|
||||
{aiClaimQueue[aiClaimCurrentIndex]?.staffId === preauthStaffId ? "Confirm & PreAuth" : "Confirm & Claim"}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
|
||||
@@ -325,6 +325,15 @@ export default function ClaimsPage() {
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
// Preauth column of "Claim/Preauth for Column with AI": open the PreAuth tab and auto-submit
|
||||
try {
|
||||
const preauthRaw = sessionStorage.getItem("chatbot_preauth_prefill");
|
||||
if (preauthRaw) {
|
||||
setChatbotInitialTab("preauth");
|
||||
const parsed = JSON.parse(preauthRaw);
|
||||
if (parsed?.siteKey) setChatbotAutoSubmitPreauthSiteKey(parsed.siteKey);
|
||||
}
|
||||
} catch {}
|
||||
handleNewClaim(patientId, appointmentId);
|
||||
clearUrlParams(["appointmentId"]);
|
||||
}
|
||||
@@ -761,6 +770,7 @@ export default function ClaimsPage() {
|
||||
|
||||
// United/DentalHub pre-auth selenium handler
|
||||
const handleUnitedDHPreAuthSubmitSelenium = async (data: any) => {
|
||||
advanceAiClaimQueue();
|
||||
try {
|
||||
dispatch(setTaskStatus({ key: "claimSubmit", status: "pending", message: "Submitting United/DentalHub pre-authorization..." }));
|
||||
const response = await apiRequest("POST", "/api/claims/uniteddh-preauth", {
|
||||
@@ -826,6 +836,7 @@ export default function ClaimsPage() {
|
||||
|
||||
// Tufts SCO pre-auth selenium handler
|
||||
const handleTuftsSCOPreAuthSubmitSelenium = async (data: any) => {
|
||||
advanceAiClaimQueue();
|
||||
try {
|
||||
dispatch(setTaskStatus({ key: "claimSubmit", status: "pending", message: "Submitting Tufts SCO pre-authorization..." }));
|
||||
const response = await apiRequest("POST", "/api/claims/tuftssco-preauth", {
|
||||
@@ -1044,6 +1055,7 @@ export default function ClaimsPage() {
|
||||
|
||||
// CCA pre-auth selenium handler
|
||||
const handleCCAPreAuthSubmitSelenium = async (data: any) => {
|
||||
advanceAiClaimQueue();
|
||||
const formData = new FormData();
|
||||
formData.append("data", JSON.stringify(data));
|
||||
if (socketId) formData.append("socketId", socketId);
|
||||
@@ -1203,6 +1215,7 @@ export default function ClaimsPage() {
|
||||
|
||||
// Pre Auth section
|
||||
const handleMHClaimPreAuthSubmitSelenium = async (data: any) => {
|
||||
advanceAiClaimQueue();
|
||||
const formData = new FormData();
|
||||
formData.append("data", JSON.stringify(data));
|
||||
if (socketId) formData.append("socketId", socketId);
|
||||
|
||||
Reference in New Issue
Block a user