feat: AI chat file uploads, RCT/PA tooth mapping, check+claim flow, service date column
- Chatbot: add paperclip button to attach X-ray/PDF files to claim submissions; files flow through chatbotFileStore into claim-form uploadedFiles for Selenium - CDT lookup: auto-select D3310/D3320/D3330 by tooth number for RCT; strip #NN from procedure names before alias lookup so "1 pa, #3" → D0220 tooth 3; add "1 pa" alias for D0220; expand multi-PA notation via AI prompt rule - AI classifier: add navigate_eligibility intent ("check mh" → /insurance-status); fix duplicate intent entry; add RCT and multi-PA prompt rules - Check+claim flow: pass serviceDate through check_and_claim_ready actionData; tryClaimFromChatbot skips PDF preview and navigates straight to claims with memberId fallback lookup; wired into all provider onPdfReady callbacks - Claims table: add Service Date column between Patient Name and Submission Date Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -522,6 +522,8 @@ export default function InsuranceStatusPage() {
|
||||
variant: "default",
|
||||
});
|
||||
|
||||
const claimed = await tryClaimFromChatbot(selectedPatient?.id);
|
||||
if (claimed) return;
|
||||
setSelectedPatient(null);
|
||||
await queryClient.invalidateQueries({ queryKey: QK_PATIENTS_BASE });
|
||||
|
||||
@@ -649,6 +651,41 @@ export default function InsuranceStatusPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// After any eligibility check succeeds, check if chatbot wanted auto-claim.
|
||||
// PDF is already saved to Documents by the Selenium worker before this is called.
|
||||
// Returns true if a chatbot claim was pending (caller should skip opening the preview).
|
||||
const tryClaimFromChatbot = async (resolvedPatientId?: number | null): Promise<boolean> => {
|
||||
try {
|
||||
const raw = sessionStorage.getItem("chatbot_claim_codes");
|
||||
if (!raw) return false;
|
||||
const { codes, siteKey, patientId, memberId: storedMemberId, serviceDate } = JSON.parse(raw);
|
||||
sessionStorage.removeItem("chatbot_claim_codes");
|
||||
|
||||
let pid: number | null = resolvedPatientId ?? patientId ?? null;
|
||||
|
||||
// Fallback: look up patient by memberId if patientId wasn't stored
|
||||
if (!pid && storedMemberId) {
|
||||
try {
|
||||
const res = await apiRequest("GET", `/api/patients/by-insurance-id?insuranceId=${encodeURIComponent(storedMemberId)}`);
|
||||
if (res.ok) {
|
||||
const p = await res.json();
|
||||
pid = p?.id ?? null;
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (!codes?.length || !pid) return false;
|
||||
|
||||
sessionStorage.setItem(
|
||||
"chatbot_claim_prefill",
|
||||
JSON.stringify({ codes, siteKey, serviceDate: serviceDate ?? null, autoSubmit: true })
|
||||
);
|
||||
setLocation(`/claims?newPatient=${pid}`);
|
||||
return true;
|
||||
} catch {}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Redirect from schedule page "Check Eligibility": prefill patient + optionally auto-trigger or scroll
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
@@ -886,12 +923,13 @@ export default function InsuranceStatusPage() {
|
||||
isFormIncomplete={isFormIncomplete}
|
||||
autoTrigger={triggerTarget === "ddma"}
|
||||
onAutoTriggered={() => setTriggerTarget(null)}
|
||||
onPdfReady={(pdfId, fallbackFilename) => {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(
|
||||
fallbackFilename ?? `eligibility_ddma_${memberId}.pdf`,
|
||||
);
|
||||
setPreviewOpen(true);
|
||||
onPdfReady={async (pdfId, fallbackFilename) => {
|
||||
const claimed = await tryClaimFromChatbot(selectedPatient?.id);
|
||||
if (!claimed) {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(fallbackFilename ?? `eligibility_ddma_${memberId}.pdf`);
|
||||
setPreviewOpen(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -905,12 +943,13 @@ export default function InsuranceStatusPage() {
|
||||
isFormIncomplete={isFormIncomplete}
|
||||
autoTrigger={triggerTarget === "delta-ins"}
|
||||
onAutoTriggered={() => setTriggerTarget(null)}
|
||||
onPdfReady={(pdfId, fallbackFilename) => {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(
|
||||
fallbackFilename ?? `eligibility_deltains_${memberId}.pdf`,
|
||||
);
|
||||
setPreviewOpen(true);
|
||||
onPdfReady={async (pdfId, fallbackFilename) => {
|
||||
const claimed = await tryClaimFromChatbot(selectedPatient?.id);
|
||||
if (!claimed) {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(fallbackFilename ?? `eligibility_deltains_${memberId}.pdf`);
|
||||
setPreviewOpen(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -944,12 +983,13 @@ export default function InsuranceStatusPage() {
|
||||
isFormIncomplete={isFormIncomplete}
|
||||
autoTrigger={triggerTarget === "tufts-sco"}
|
||||
onAutoTriggered={() => setTriggerTarget(null)}
|
||||
onPdfReady={(pdfId, fallbackFilename) => {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(
|
||||
fallbackFilename ?? `eligibility_tuftssco_${memberId}.pdf`,
|
||||
);
|
||||
setPreviewOpen(true);
|
||||
onPdfReady={async (pdfId, fallbackFilename) => {
|
||||
const claimed = await tryClaimFromChatbot(selectedPatient?.id);
|
||||
if (!claimed) {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(fallbackFilename ?? `eligibility_tuftssco_${memberId}.pdf`);
|
||||
setPreviewOpen(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -963,12 +1003,13 @@ export default function InsuranceStatusPage() {
|
||||
isFormIncomplete={isFormIncomplete}
|
||||
autoTrigger={triggerTarget === "united-sco"}
|
||||
onAutoTriggered={() => setTriggerTarget(null)}
|
||||
onPdfReady={(pdfId, fallbackFilename) => {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(
|
||||
fallbackFilename ?? `eligibility_unitedsco_${memberId}.pdf`,
|
||||
);
|
||||
setPreviewOpen(true);
|
||||
onPdfReady={async (pdfId, fallbackFilename) => {
|
||||
const claimed = await tryClaimFromChatbot(selectedPatient?.id);
|
||||
if (!claimed) {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(fallbackFilename ?? `eligibility_unitedsco_${memberId}.pdf`);
|
||||
setPreviewOpen(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -982,12 +1023,13 @@ export default function InsuranceStatusPage() {
|
||||
isFormIncomplete={isFormIncomplete}
|
||||
autoTrigger={triggerTarget === "cca"}
|
||||
onAutoTriggered={() => setTriggerTarget(null)}
|
||||
onPdfReady={(pdfId, fallbackFilename) => {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(
|
||||
fallbackFilename ?? `eligibility_cca_${memberId}.pdf`,
|
||||
);
|
||||
setPreviewOpen(true);
|
||||
onPdfReady={async (pdfId, fallbackFilename) => {
|
||||
const claimed = await tryClaimFromChatbot(selectedPatient?.id);
|
||||
if (!claimed) {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(fallbackFilename ?? `eligibility_cca_${memberId}.pdf`);
|
||||
setPreviewOpen(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user