feat: auto-trigger eligibility selenium from schedule right-click menu

- Remove "Claim Status" from appointment context menu
- Rename "Eligibility Status" → "Check Eligibility"
- Check Eligibility now navigates to insurance-status page and auto-starts
  the correct selenium flow based on the patient's stored insurance provider:
  MassHealth 21+ → MH Eligibility & History
  MassHealth <21  → CMSP Eligibility & History & Remaining
  Delta Dental MA → DDMA selenium
  Delta Dental Ins → Delta Ins selenium (OTP modal if needed)
  United Healthcare SCO → United SCO selenium
  DentaQuest/Tufts → Tufts SCO selenium
  Commonwealth Care Alliance → CCA selenium
  Unknown → scroll to Other provider checks section
- Add autoTrigger/onAutoTriggered props to all five button components

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gitead
2026-05-17 00:12:09 -04:00
parent 4127861d06
commit edec03e893
7 changed files with 154 additions and 93 deletions

View File

@@ -164,7 +164,9 @@ export default function InsuranceStatusPage() {
const [cmspAccumulatorPdfId, setCmspAccumulatorPdfId] = useState<number | null>(null);
const [cmspAccumulatorFilename, setCmspAccumulatorFilename] = useState<string | null>(null);
const pendingAutoCheck = useRef<"mh" | "cmsp" | null>(null);
const pendingAutoCheck = useRef<"mh" | "mh-history" | "cmsp" | "ddma" | "delta-ins" | "united-sco" | "tufts-sco" | "cca" | null>(null);
const [triggerTarget, setTriggerTarget] = useState<string | null>(null);
const pendingScrollTo = useRef<string | null>(null);
// Prefill from chatbot
useEffect(() => {
@@ -603,15 +605,18 @@ export default function InsuranceStatusPage() {
}
};
// Auto-trigger from chatbot after prefill
// Auto-trigger after prefill (from chatbot or schedule page "Check Eligibility")
useEffect(() => {
if (!pendingAutoCheck.current || !memberId || !dateOfBirth) return;
const check = pendingAutoCheck.current;
pendingAutoCheck.current = null;
if (check === "mh") {
if (check === "mh" || check === "mh-history") {
handleMHEligibilityHistoryButton();
} else {
} else if (check === "cmsp") {
handleCMSPButton();
} else {
// Button-component-handled providers: pass target to their autoTrigger prop
setTriggerTarget(check);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [memberId, dateOfBirth]);
@@ -635,66 +640,7 @@ export default function InsuranceStatusPage() {
}
};
// handling case-1, when redirect happens from appointment page:
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const appointmentId = params.get("appointmentId");
const action = params.get("action"); // 'eligibility' | 'claim'
if (!appointmentId) return;
const id = Number(appointmentId);
if (Number.isNaN(id) || id <= 0) return;
if (!action || (action !== "eligibility" && action !== "claim")) return;
let cancelled = false;
(async () => {
try {
const res = await apiRequest("GET", `/api/appointments/${id}/patient`);
if (!res.ok) {
let body: any = null;
try {
body = await res.json();
} catch {}
if (!cancelled) {
toast({
title: "Failed to load patient",
description:
body?.message ??
body?.error ??
`Could not fetch patient for appointment ${id}.`,
variant: "destructive",
});
}
return;
}
const data = await res.json();
const patient = data?.patient ?? data;
if (!cancelled && patient) {
// set selectedPatient as before
setSelectedPatient(patient as Patient);
clearUrlParams(["appointmentId", "action"]);
}
} catch (err: any) {
if (!cancelled) {
console.error("Error fetching patient for appointment:", err);
toast({
title: "Error",
description:
err?.message ?? "An error occurred while fetching patient.",
variant: "destructive",
});
}
}
})();
return () => {
cancelled = true;
};
}, [location]);
// handling case-1, when redirect happens from appointment page:
// Redirect from schedule page "Check Eligibility": prefill patient + optionally auto-trigger or scroll
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const appointmentId = params.get("appointmentId");
@@ -703,6 +649,16 @@ export default function InsuranceStatusPage() {
const id = Number(appointmentId);
if (Number.isNaN(id) || id <= 0) return;
const autoCheck = params.get("autoCheck") as typeof pendingAutoCheck.current;
const scrollTo = params.get("scrollTo");
const knownAutoChecks = ["mh", "mh-history", "cmsp", "ddma", "delta-ins", "united-sco", "tufts-sco", "cca"] as const;
if (autoCheck && (knownAutoChecks as readonly string[]).includes(autoCheck)) {
pendingAutoCheck.current = autoCheck;
} else if (scrollTo) {
pendingScrollTo.current = scrollTo;
}
let cancelled = false;
(async () => {
@@ -714,11 +670,8 @@ export default function InsuranceStatusPage() {
const patient = data?.patient ?? data;
if (!cancelled && patient) {
// ✅ ONLY prefill patient
setSelectedPatient(patient as Patient);
// ✅ clean URL (no auto selenium)
clearUrlParams(["appointmentId", "action"]);
clearUrlParams(["appointmentId", "action", "autoCheck", "scrollTo"]);
}
} catch (err) {
console.error("Failed to fetch patient from appointment", err);
@@ -730,6 +683,23 @@ export default function InsuranceStatusPage() {
};
}, [location]);
// Scroll to highlighted button after patient is loaded from schedule page (other insurance)
useEffect(() => {
if (!selectedPatient || !pendingScrollTo.current) return;
const target = pendingScrollTo.current;
pendingScrollTo.current = null;
setTimeout(() => {
const el = document.getElementById(`eligibility-${target}`);
if (!el) return;
el.scrollIntoView({ behavior: "smooth", block: "center" });
el.classList.add("ring-2", "ring-blue-500", "ring-offset-2", "transition-all");
setTimeout(() => {
el.classList.remove("ring-2", "ring-blue-500", "ring-offset-2", "transition-all");
}, 2500);
}, 300);
}, [selectedPatient]);
return (
<div>
<SeleniumTaskBanner
@@ -852,6 +822,7 @@ export default function InsuranceStatusPage() {
<div className="flex flex-col-2 gap-4 mt-4">
<Button
id="eligibility-mh-history"
className="w-full"
disabled={isCheckingEligibilityHistory}
onClick={() => handleMHEligibilityHistoryButton()}
@@ -870,6 +841,7 @@ export default function InsuranceStatusPage() {
</Button>
<Button
id="eligibility-cmsp"
className="w-full"
disabled={isCheckingCMSP}
onClick={() => handleCMSPButton()}
@@ -889,7 +861,7 @@ export default function InsuranceStatusPage() {
</div>
{/* TEMP PROVIDER BUTTONS */}
<div className="space-y-4 mt-6">
<div id="eligibility-other-providers" className="space-y-4 mt-6">
<h3 className="text-sm font-medium text-muted-foreground">
Other provider checks
</h3>
@@ -902,6 +874,8 @@ export default function InsuranceStatusPage() {
firstName={firstName}
lastName={lastName}
isFormIncomplete={isFormIncomplete}
autoTrigger={triggerTarget === "ddma"}
onAutoTriggered={() => setTriggerTarget(null)}
onPdfReady={(pdfId, fallbackFilename) => {
setPreviewPdfId(pdfId);
setPreviewFallbackFilename(
@@ -917,6 +891,8 @@ export default function InsuranceStatusPage() {
firstName={firstName}
lastName={lastName}
isFormIncomplete={isFormIncomplete}
autoTrigger={triggerTarget === "delta-ins"}
onAutoTriggered={() => setTriggerTarget(null)}
onPdfReady={(pdfId, fallbackFilename) => {
setPreviewPdfId(pdfId);
setPreviewFallbackFilename(
@@ -944,10 +920,12 @@ export default function InsuranceStatusPage() {
firstName={firstName}
lastName={lastName}
isFormIncomplete={isFormIncomplete}
autoTrigger={triggerTarget === "tufts-sco"}
onAutoTriggered={() => setTriggerTarget(null)}
onPdfReady={(pdfId, fallbackFilename) => {
setPreviewPdfId(pdfId);
setPreviewFallbackFilename(
fallbackFilename ?? `eligibility_unitedsco_${memberId}.pdf`,
fallbackFilename ?? `eligibility_tuftssco_${memberId}.pdf`,
);
setPreviewOpen(true);
}}
@@ -959,6 +937,8 @@ export default function InsuranceStatusPage() {
firstName={firstName}
lastName={lastName}
isFormIncomplete={isFormIncomplete}
autoTrigger={triggerTarget === "united-sco"}
onAutoTriggered={() => setTriggerTarget(null)}
onPdfReady={(pdfId, fallbackFilename) => {
setPreviewPdfId(pdfId);
setPreviewFallbackFilename(
@@ -974,6 +954,8 @@ export default function InsuranceStatusPage() {
firstName={firstName}
lastName={lastName}
isFormIncomplete={isFormIncomplete}
autoTrigger={triggerTarget === "cca"}
onAutoTriggered={() => setTriggerTarget(null)}
onPdfReady={(pdfId, fallbackFilename) => {
setPreviewPdfId(pdfId);
setPreviewFallbackFilename(