feat: add United Ucard eligibility check with OTP + persistent session
Adds a full login/OTP/search/capture flow for United Ucard (OneHealthcareID -> UHC Dental provider portal), mirroring the United SCO/DDMA pattern: persistent Chrome profile, OTP polling, member eligibility search, and PDF capture saved to the patient's Eligibility folder. Also fixes a validation bug in the browser-safe patient schema where email/address/city/zipCode/gender/phone were optional but not nullable, rejecting patient records with null values on those fields during edits (e.g. "Expected string, received null"). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,7 @@ import { DdmaEligibilityButton } from "@/components/insurance-status/ddma-buton-
|
||||
import { DeltaInsEligibilityButton } from "@/components/insurance-status/deltains-button-modal";
|
||||
import { TuftsSCOEligibilityButton } from "@/components/insurance-status/tufts-sco-button-modal";
|
||||
import { UnitedSCOEligibilityButton } from "@/components/insurance-status/united-sco-button-modal";
|
||||
import { UnitedUcardEligibilityButton } from "@/components/insurance-status/united-ucard-button-modal";
|
||||
import { CCAEligibilityButton } from "@/components/insurance-status/cca-button-modal";
|
||||
import { BcbsMaEligibilityButton } from "@/components/insurance-status/bcbs-ma-button-modal";
|
||||
import { useLicense } from "@/hooks/use-license";
|
||||
@@ -171,7 +172,7 @@ export default function InsuranceStatusPage() {
|
||||
const [cmspAccumulatorPdfId, setCmspAccumulatorPdfId] = useState<number | string | null>(null);
|
||||
const [cmspAccumulatorFilename, setCmspAccumulatorFilename] = useState<string | null>(null);
|
||||
|
||||
const pendingAutoCheck = useRef<"mh" | "mh-history" | "cmsp" | "ddma" | "delta-ins" | "united-sco" | "tufts-sco" | "cca" | null>(null);
|
||||
const pendingAutoCheck = useRef<"mh" | "mh-history" | "cmsp" | "ddma" | "delta-ins" | "united-sco" | "united-ucard" | "tufts-sco" | "cca" | null>(null);
|
||||
const [triggerTarget, setTriggerTarget] = useState<string | null>(null);
|
||||
const pendingScrollTo = useRef<string | null>(null);
|
||||
const [prefillTick, setPrefillTick] = useState(0);
|
||||
@@ -909,7 +910,7 @@ export default function InsuranceStatusPage() {
|
||||
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;
|
||||
const knownAutoChecks = ["mh", "mh-history", "cmsp", "ddma", "delta-ins", "united-sco", "united-ucard", "tufts-sco", "cca"] as const;
|
||||
if (autoCheck && (knownAutoChecks as readonly string[]).includes(autoCheck)) {
|
||||
pendingAutoCheck.current = autoCheck;
|
||||
} else if (scrollTo) {
|
||||
@@ -1196,14 +1197,27 @@ export default function InsuranceStatusPage() {
|
||||
|
||||
{/* Row 3 */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<Button
|
||||
className="w-full"
|
||||
variant="outline"
|
||||
disabled={isFormIncomplete}
|
||||
>
|
||||
<CheckCircle className="h-4 w-4 mr-2" />
|
||||
United AAPR
|
||||
</Button>
|
||||
<div title={!isLicensed ? "License required" : undefined} className={!isLicensed ? "opacity-40 pointer-events-none" : ""}>
|
||||
<UnitedUcardEligibilityButton
|
||||
memberId={memberId}
|
||||
dateOfBirth={dateOfBirth}
|
||||
firstName={firstName}
|
||||
lastName={lastName}
|
||||
isFormIncomplete={isFormIncomplete}
|
||||
autoTrigger={triggerTarget === "united-ucard"}
|
||||
onAutoTriggered={() => setTriggerTarget(null)}
|
||||
onPdfReady={async (pdfId, fallbackFilename) => {
|
||||
const claimed = await tryClaimFromChatbot(selectedPatient?.id);
|
||||
void tryAppointmentFromChatbot();
|
||||
if (!claimed) {
|
||||
setPreviewPdfId(pdfId);
|
||||
setPreviewFallbackFilename(fallbackFilename ?? `eligibility_uniteducard_${memberId}.pdf`);
|
||||
setPreviewOpen(true);
|
||||
}
|
||||
processNextInQueue();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
className="w-full"
|
||||
|
||||
Reference in New Issue
Block a user