diff --git a/.turbo/preferences/tui.json b/.turbo/preferences/tui.json index f46ddd7d..efb36255 100644 --- a/.turbo/preferences/tui.json +++ b/.turbo/preferences/tui.json @@ -1,4 +1,4 @@ { "is_task_list_visible": true, - "active_task": "backend#dev" + "active_task": "frontend#dev" } \ No newline at end of file diff --git a/apps/Backend/src/queue/jobRunner.ts b/apps/Backend/src/queue/jobRunner.ts index 98016a69..f0bb2ebf 100644 --- a/apps/Backend/src/queue/jobRunner.ts +++ b/apps/Backend/src/queue/jobRunner.ts @@ -7,7 +7,6 @@ */ import { InProcessQueue } from "./inProcessQueue"; import { io } from "../socket"; -import { runEligibilityProcessor } from "./processors/eligibilityProcessor"; import { runClaimStatusProcessor } from "./processors/claimStatusProcessor"; import { runClaimSubmitProcessor } from "./processors/claimSubmitProcessor"; import { runOcrProcessor } from "./processors/ocrProcessor"; @@ -23,8 +22,6 @@ import { runUnitedDHClaimProcessor } from "./processors/unitedDHClaimProcessor"; import { runUnitedDHPreAuthProcessor } from "./processors/unitedDHPreAuthProcessor"; import { runTuftsSCOPreAuthProcessor } from "./processors/tuftsSCOPreAuthProcessor"; import { runTuftsSCOClaimProcessor } from "./processors/tuftsSCOClaimProcessor"; -import { runEligibilityHistoryProcessor } from "./processors/eligibilityHistoryProcessor"; -import { runCmspEligibilityHistoryRemainingProcessor } from "./processors/cmspEligibilityHistoryRemainingProcessor"; import { runBcbsMaEligibilityProcessor } from "./processors/bcbsMaEligibilityProcessor"; import type { SeleniumJobData, OcrJobData } from "./queues"; @@ -59,16 +56,6 @@ export function enqueueSeleniumJob(data: SeleniumJobData): string { message: "Selenium browser starting…", }); - if (jobType === "eligibility-check") { - return runEligibilityProcessor({ - enrichedPayload: data.enrichedPayload, - userId: data.userId, - insuranceId: data.insuranceId!, - formFirstName: data.formFirstName, - formLastName: data.formLastName, - formDob: data.formDob, - }); - } if (jobType === "claim-status-check") { return runClaimStatusProcessor({ enrichedPayload: data.enrichedPayload, @@ -231,26 +218,6 @@ export function enqueueSeleniumJob(data: SeleniumJobData): string { job.id ); } - if (jobType === "cmsp-eligibility-history-remaining-check") { - return runCmspEligibilityHistoryRemainingProcessor({ - enrichedPayload: data.enrichedPayload, - userId: data.userId, - insuranceId: data.insuranceId!, - formFirstName: data.formFirstName, - formLastName: data.formLastName, - formDob: data.formDob, - }); - } - if (jobType === "mh-eligibility-history-check") { - return runEligibilityHistoryProcessor({ - enrichedPayload: data.enrichedPayload, - userId: data.userId, - insuranceId: data.insuranceId!, - formFirstName: data.formFirstName, - formLastName: data.formLastName, - formDob: data.formDob, - }); - } if (jobType === "bcbs-ma-eligibility-check") { return runBcbsMaEligibilityProcessor( { diff --git a/apps/Backend/src/queue/processors/cmspEligibilityHistoryRemainingProcessor.ts b/apps/Backend/src/queue/processors/cmspEligibilityHistoryRemainingProcessor.ts deleted file mode 100644 index c1c82336..00000000 --- a/apps/Backend/src/queue/processors/cmspEligibilityHistoryRemainingProcessor.ts +++ /dev/null @@ -1,169 +0,0 @@ -/** - * Processor for "cmsp-eligibility-history-remaining-check" jobs. - * Saves eligibility PDF, service history PDF, and accumulator PDF - * to the patient's ELIGIBILITY_STATUS document group. - */ -import fs from "fs/promises"; -import path from "path"; -import { storage } from "../../storage"; -import { emptyFolderContainingFile } from "../../utils/emptyTempFolder"; -import forwardToPatientDataExtractorService from "../../services/patientDataExtractorService"; -import { - callPythonSync, - splitName, - createOrUpdatePatientByInsuranceId, -} from "./_shared"; - -export interface CmspEligibilityHistoryRemainingProcessorInput { - enrichedPayload: any; - userId: number; - insuranceId: string; - formFirstName?: string; - formLastName?: string; - formDob?: string; -} - -export interface CmspEligibilityHistoryRemainingProcessorResult { - patientUpdateStatus?: string; - pdfUploadStatus?: string; - pdfFileId?: number | null; - pdfFilename?: string | null; - memberDetailsPdfFileId?: number | null; - memberDetailsPdfFilename?: string | null; - historyPdfFileId?: number | null; - historyPdfFilename?: string | null; - accumulatorPdfFileId?: number | null; - accumulatorPdfFilename?: string | null; -} - -export async function runCmspEligibilityHistoryRemainingProcessor( - input: CmspEligibilityHistoryRemainingProcessorInput -): Promise { - const { enrichedPayload, userId, insuranceId, formFirstName, formLastName, formDob } = input; - - const seleniumResult = await callPythonSync("/cmsp-eligibility-history-remaining-check", { - data: enrichedPayload, - }); - - const outputResult: CmspEligibilityHistoryRemainingProcessorResult = {}; - - // Extract patient name - const seleniumFirst = seleniumResult.firstName?.trim() || null; - const seleniumLast = seleniumResult.lastName?.trim() || null; - const seleniumName = seleniumResult.name?.trim() || null; - const seleniumInsurance = seleniumResult.insurance?.trim() || null; - - const extracted: { firstName?: string | null; lastName?: string | null } = {}; - - if (seleniumFirst || seleniumLast) { - extracted.firstName = seleniumFirst; - extracted.lastName = seleniumLast; - } else if (seleniumName) { - const parts = splitName(seleniumName); - extracted.firstName = parts.firstName || null; - extracted.lastName = parts.lastName || null; - } - - if (!extracted.firstName && !extracted.lastName && seleniumResult?.pdf_path?.endsWith(".pdf")) { - try { - const pdfBuffer = await fs.readFile(seleniumResult.pdf_path); - const extraction = await forwardToPatientDataExtractorService({ - buffer: pdfBuffer, - originalname: path.basename(seleniumResult.pdf_path), - mimetype: "application/pdf", - } as any); - if (extraction.name) { - const parts = splitName(extraction.name); - extracted.firstName = parts.firstName || null; - extracted.lastName = parts.lastName || null; - } - } catch (e) { - console.error("[cmspProcessor] PDF name extraction failed:", e); - } - } - - const preferFirst = extracted.firstName || formFirstName || null; - const preferLast = extracted.lastName || formLastName || null; - - let patient; - try { - patient = await createOrUpdatePatientByInsuranceId({ - insuranceId, - firstName: preferFirst, - lastName: preferLast, - dob: formDob, - userId, - }); - } catch (e: any) { - throw new Error(`Failed to create/update patient: ${e.message}`); - } - - if (patient && patient.id !== undefined) { - let newStatus = "UNKNOWN"; - if (seleniumResult.eligibility === "Y") newStatus = "ACTIVE"; - else if (seleniumResult.eligibility === "N") newStatus = "INACTIVE"; - - const updates: any = { status: newStatus }; - if (seleniumInsurance) updates.insuranceProvider = seleniumInsurance; - await storage.updatePatient(patient.id, updates); - outputResult.patientUpdateStatus = `Patient status updated to ${newStatus}`; - - // Helper: save a single PDF to the patient's ELIGIBILITY_STATUS group - const saveToGroup = async (pdfPath: string): Promise => { - try { - const buffer = await fs.readFile(pdfPath); - const groupTitleKey = "ELIGIBILITY_STATUS"; - const groupTitle = "Eligibility Status"; - let group = await storage.findPdfGroupByPatientTitleKey(patient!.id, groupTitleKey); - if (!group) group = await storage.createPdfGroup(patient!.id, groupTitle, groupTitleKey); - if (!group?.id) throw new Error("PDF group creation failed"); - const created = await storage.createPdfFile(group.id, path.basename(pdfPath), buffer); - if (created && typeof created === "object" && "id" in created) { - return Number(created.id); - } - return null; - } catch (e: any) { - console.error("[cmspProcessor] saveToGroup failed:", e.message); - return null; - } - }; - - // Save eligibility PDF - if (seleniumResult.pdf_path?.endsWith(".pdf")) { - outputResult.pdfFileId = await saveToGroup(seleniumResult.pdf_path); - outputResult.pdfFilename = path.basename(seleniumResult.pdf_path); - outputResult.pdfUploadStatus = outputResult.pdfFileId ? "Eligibility PDF saved" : "Eligibility PDF upload failed"; - } else { - outputResult.pdfUploadStatus = "No eligibility PDF returned by Selenium"; - } - - // Save member details PDF - if (seleniumResult.member_details_pdf_path?.endsWith(".pdf")) { - outputResult.memberDetailsPdfFileId = await saveToGroup(seleniumResult.member_details_pdf_path); - outputResult.memberDetailsPdfFilename = path.basename(seleniumResult.member_details_pdf_path); - } - - // Save history PDF - if (seleniumResult.history_pdf_path?.endsWith(".pdf")) { - outputResult.historyPdfFileId = await saveToGroup(seleniumResult.history_pdf_path); - outputResult.historyPdfFilename = path.basename(seleniumResult.history_pdf_path); - } - - // Save accumulator PDF - if (seleniumResult.accumulator_pdf_path?.endsWith(".pdf")) { - outputResult.accumulatorPdfFileId = await saveToGroup(seleniumResult.accumulator_pdf_path); - outputResult.accumulatorPdfFilename = path.basename(seleniumResult.accumulator_pdf_path); - } - } else { - outputResult.patientUpdateStatus = "Patient not found or missing ID; no update performed"; - } - - // Cleanup temp files - try { - if (seleniumResult.pdf_path) await emptyFolderContainingFile(seleniumResult.pdf_path); - } catch (e) { - console.error("[cmspProcessor] cleanup failed:", e); - } - - return outputResult; -} diff --git a/apps/Backend/src/queue/processors/eligibilityHistoryProcessor.ts b/apps/Backend/src/queue/processors/eligibilityHistoryProcessor.ts deleted file mode 100644 index 2e4ede8b..00000000 --- a/apps/Backend/src/queue/processors/eligibilityHistoryProcessor.ts +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Processor for "mh-eligibility-history-check" jobs. - * Runs MH eligibility + service history selenium flow and saves both PDFs - * to the patient's ELIGIBILITY_STATUS document group. - */ -import fs from "fs/promises"; -import path from "path"; -import { storage } from "../../storage"; -import { emptyFolderContainingFile } from "../../utils/emptyTempFolder"; -import forwardToPatientDataExtractorService from "../../services/patientDataExtractorService"; -import { - callPythonSync, - splitName, - createOrUpdatePatientByInsuranceId, -} from "./_shared"; - -export interface EligibilityHistoryProcessorInput { - enrichedPayload: any; - userId: number; - insuranceId: string; - formFirstName?: string; - formLastName?: string; - formDob?: string; -} - -export interface EligibilityHistoryProcessorResult { - patientUpdateStatus?: string; - pdfUploadStatus?: string; - pdfFileId?: number | null; - pdfFilename?: string | null; - memberDetailsPdfFileId?: number | null; - memberDetailsPdfFilename?: string | null; - historyPdfFileId?: number | null; - historyPdfFilename?: string | null; -} - -export async function runEligibilityHistoryProcessor( - input: EligibilityHistoryProcessorInput -): Promise { - const { enrichedPayload, userId, insuranceId, formFirstName, formLastName, formDob } = input; - - const seleniumResult = await callPythonSync("/mh-eligibility-history-check", { - data: enrichedPayload, - }); - - const outputResult: EligibilityHistoryProcessorResult = {}; - - // Extract patient name - const seleniumFirst = seleniumResult.firstName?.trim() || null; - const seleniumLast = seleniumResult.lastName?.trim() || null; - const seleniumName = seleniumResult.name?.trim() || null; - const seleniumInsurance = seleniumResult.insurance?.trim() || null; - - const extracted: { firstName?: string | null; lastName?: string | null } = {}; - - if (seleniumFirst || seleniumLast) { - extracted.firstName = seleniumFirst; - extracted.lastName = seleniumLast; - } else if (seleniumName) { - const parts = splitName(seleniumName); - extracted.firstName = parts.firstName || null; - extracted.lastName = parts.lastName || null; - } - - if (!extracted.firstName && !extracted.lastName && seleniumResult?.pdf_path?.endsWith(".pdf")) { - try { - const pdfBuffer = await fs.readFile(seleniumResult.pdf_path); - const extraction = await forwardToPatientDataExtractorService({ - buffer: pdfBuffer, - originalname: path.basename(seleniumResult.pdf_path), - mimetype: "application/pdf", - } as any); - if (extraction.name) { - const parts = splitName(extraction.name); - extracted.firstName = parts.firstName || null; - extracted.lastName = parts.lastName || null; - } - } catch (e) { - console.error("[eligibilityHistoryProcessor] PDF name extraction failed:", e); - } - } - - const preferFirst = extracted.firstName || formFirstName || null; - const preferLast = extracted.lastName || formLastName || null; - - let patient; - try { - patient = await createOrUpdatePatientByInsuranceId({ - insuranceId, - firstName: preferFirst, - lastName: preferLast, - dob: formDob, - userId, - }); - } catch (e: any) { - throw new Error(`Failed to create/update patient: ${e.message}`); - } - - if (patient && patient.id !== undefined) { - let newStatus = "UNKNOWN"; - if (seleniumResult.eligibility === "Y") newStatus = "ACTIVE"; - else if (seleniumResult.eligibility === "N") newStatus = "INACTIVE"; - - const updates: any = { status: newStatus }; - if (seleniumInsurance) updates.insuranceProvider = seleniumInsurance; - await storage.updatePatient(patient.id, updates); - outputResult.patientUpdateStatus = `Patient status updated to ${newStatus}`; - - // Helper: save a PDF buffer to the patient's ELIGIBILITY_STATUS group - const saveToGroup = async (pdfPath: string): Promise => { - try { - const buffer = await fs.readFile(pdfPath); - const groupTitleKey = "ELIGIBILITY_STATUS"; - const groupTitle = "Eligibility Status"; - let group = await storage.findPdfGroupByPatientTitleKey(patient!.id, groupTitleKey); - if (!group) group = await storage.createPdfGroup(patient!.id, groupTitle, groupTitleKey); - if (!group?.id) throw new Error("PDF group creation failed"); - const created = await storage.createPdfFile(group.id, path.basename(pdfPath), buffer); - if (created && typeof created === "object" && "id" in created) { - return Number(created.id); - } - return null; - } catch (e: any) { - console.error("[eligibilityHistoryProcessor] saveToGroup failed:", e.message); - return null; - } - }; - - // Save eligibility PDF - let eligibilityPdfFileId: number | null = null; - if (seleniumResult.pdf_path?.endsWith(".pdf")) { - eligibilityPdfFileId = await saveToGroup(seleniumResult.pdf_path); - outputResult.pdfUploadStatus = eligibilityPdfFileId - ? "Eligibility PDF saved" - : "Eligibility PDF upload failed"; - outputResult.pdfFilename = path.basename(seleniumResult.pdf_path); - } else { - outputResult.pdfUploadStatus = "No eligibility PDF returned by Selenium"; - } - outputResult.pdfFileId = eligibilityPdfFileId; - - // Save member details PDF - if (seleniumResult.member_details_pdf_path?.endsWith(".pdf")) { - outputResult.memberDetailsPdfFileId = await saveToGroup(seleniumResult.member_details_pdf_path); - outputResult.memberDetailsPdfFilename = path.basename(seleniumResult.member_details_pdf_path); - } - - // Save history PDF - let historyPdfFileId: number | null = null; - if (seleniumResult.history_pdf_path?.endsWith(".pdf")) { - historyPdfFileId = await saveToGroup(seleniumResult.history_pdf_path); - outputResult.historyPdfFilename = path.basename(seleniumResult.history_pdf_path); - } - outputResult.historyPdfFileId = historyPdfFileId; - } else { - outputResult.patientUpdateStatus = "Patient not found or missing ID; no update performed"; - } - - // Cleanup temp files - try { - if (seleniumResult.pdf_path) await emptyFolderContainingFile(seleniumResult.pdf_path); - } catch (e) { - console.error("[eligibilityHistoryProcessor] cleanup failed:", e); - } - - return outputResult; -} diff --git a/apps/Backend/src/queue/queues.ts b/apps/Backend/src/queue/queues.ts index 9e1f64d8..86a66a40 100644 --- a/apps/Backend/src/queue/queues.ts +++ b/apps/Backend/src/queue/queues.ts @@ -3,7 +3,6 @@ import { redisConnection } from "./connection"; /** Job types dispatched to the selenium Python worker. */ export type SeleniumJobType = - | "eligibility-check" | "claim-status-check" | "claim-submit" | "claim-pre-auth" @@ -19,8 +18,6 @@ export type SeleniumJobType = | "uniteddh-preauth-submit" | "tuftssco-preauth-submit" | "tuftssco-eligibility-check" - | "mh-eligibility-history-check" - | "cmsp-eligibility-history-remaining-check" | "bcbs-ma-eligibility-check"; export interface SeleniumJobData { diff --git a/apps/Backend/src/queue/workers/seleniumWorker.ts b/apps/Backend/src/queue/workers/seleniumWorker.ts index 7a9bc84a..4aee33c1 100644 --- a/apps/Backend/src/queue/workers/seleniumWorker.ts +++ b/apps/Backend/src/queue/workers/seleniumWorker.ts @@ -2,7 +2,6 @@ import { Worker, Job } from "bullmq"; import { redisConnection } from "../connection"; import { SeleniumJobData } from "../queues"; import { io } from "../../socket"; -import { runEligibilityProcessor } from "../processors/eligibilityProcessor"; import { runClaimStatusProcessor } from "../processors/claimStatusProcessor"; import { runClaimSubmitProcessor } from "../processors/claimSubmitProcessor"; @@ -27,7 +26,7 @@ function emitJobUpdate( } async function processSeleniumJob(job: Job) { - const { jobType, userId, socketId, enrichedPayload } = job.data; + const { jobType, socketId, enrichedPayload } = job.data; const jobId = job.id ?? job.name; emitJobUpdate(socketId, jobId, jobType, "active", { @@ -37,16 +36,7 @@ async function processSeleniumJob(job: Job) { try { let result: any; - if (jobType === "eligibility-check") { - result = await runEligibilityProcessor({ - enrichedPayload, - userId, - insuranceId: job.data.insuranceId!, - formFirstName: job.data.formFirstName, - formLastName: job.data.formLastName, - formDob: job.data.formDob, - }); - } else if (jobType === "claim-status-check") { + if (jobType === "claim-status-check") { result = await runClaimStatusProcessor({ enrichedPayload, insuranceId: job.data.insuranceId!, diff --git a/apps/Backend/src/routes/insuranceStatus.ts b/apps/Backend/src/routes/insuranceStatus.ts index e3f4646f..5e126174 100755 --- a/apps/Backend/src/routes/insuranceStatus.ts +++ b/apps/Backend/src/routes/insuranceStatus.ts @@ -15,7 +15,7 @@ import { } from "../../../../packages/db/types/patient-types"; import { formatDobForAgent } from "../utils/dateUtils"; import { seleniumQueue } from "../queue/queues"; -import { enqueueSeleniumJob, getSeleniumJobStatus } from "../queue/jobRunner"; +import { getSeleniumJobStatus } from "../queue/jobRunner"; const router = Router(); @@ -113,160 +113,6 @@ async function createOrUpdatePatientByInsuranceId(options: { } } -/** - * /eligibility-check - * - run selenium - * - if pdf created -> call extractor -> get name - * - create or update patient (by memberId) - * - attach PDF to patient (create pdf group/file) - * - return { patient, pdfFileId, extractedName ... } - */ -router.post( - "/eligibility-check", - async (req: Request, res: Response): Promise => { - if (!req.body.data) { - return res - .status(400) - .json({ error: "Missing Insurance Eligibility data for selenium" }); - } - if (!req.user || !req.user.id) { - return res.status(401).json({ error: "Unauthorized: user info missing" }); - } - - const insuranceEligibilityData = - typeof req.body.data === "string" - ? JSON.parse(req.body.data) - : req.body.data; - - const credentials = await storage.getInsuranceCredentialByUserAndSiteKey( - req.user.id, - insuranceEligibilityData.insuranceSiteKey - ); - if (!credentials) { - return res.status(404).json({ - error: - "No insurance credentials found for this provider, Kindly Update this at Settings Page.", - }); - } - - const insuranceId = String(insuranceEligibilityData.memberId ?? "").trim(); - if (!insuranceId) { - return res.status(400).json({ error: "Missing memberId" }); - } - - const enrichedData = { - ...insuranceEligibilityData, - massdhpUsername: credentials.username, - massdhpPassword: credentials.password, - }; - - const job = await seleniumQueue.add("eligibility-check", { - jobType: "eligibility-check", - userId: req.user.id, - socketId: req.body.socketId, - enrichedPayload: enrichedData, - insuranceId, - formFirstName: insuranceEligibilityData.firstName, - formLastName: insuranceEligibilityData.lastName, - formDob: insuranceEligibilityData.dateOfBirth, - }); - - return res.json({ jobId: job.id, status: "queued" }); - } -); - -router.post( - "/eligibility-history-check", - async (req: Request, res: Response): Promise => { - if (!req.body.data) { - return res.status(400).json({ error: "Missing Insurance Eligibility data for selenium" }); - } - if (!req.user || !req.user.id) { - return res.status(401).json({ error: "Unauthorized: user info missing" }); - } - - const data = - typeof req.body.data === "string" ? JSON.parse(req.body.data) : req.body.data; - - const credentials = await storage.getInsuranceCredentialByUserAndSiteKey(req.user.id, "MH"); - if (!credentials) { - return res.status(404).json({ - error: "No MassHealth credentials found. Please update them in Settings.", - }); - } - - const insuranceId = String(data.memberId ?? "").trim(); - if (!insuranceId) { - return res.status(400).json({ error: "Missing memberId" }); - } - - const enrichedData = { - ...data, - massdhpUsername: credentials.username, - massdhpPassword: credentials.password, - }; - - const jobId = enqueueSeleniumJob({ - jobType: "mh-eligibility-history-check", - userId: req.user.id, - socketId: req.body.socketId, - enrichedPayload: enrichedData, - insuranceId, - formFirstName: data.firstName, - formLastName: data.lastName, - formDob: data.dateOfBirth, - }); - - return res.json({ jobId, status: "queued" }); - } -); - -router.post( - "/cmsp-eligibility-history-remaining-check", - async (req: Request, res: Response): Promise => { - if (!req.body.data) { - return res.status(400).json({ error: "Missing data for selenium" }); - } - if (!req.user || !req.user.id) { - return res.status(401).json({ error: "Unauthorized: user info missing" }); - } - - const data = - typeof req.body.data === "string" ? JSON.parse(req.body.data) : req.body.data; - - const credentials = await storage.getInsuranceCredentialByUserAndSiteKey(req.user.id, "MH"); - if (!credentials) { - return res.status(404).json({ - error: "No MassHealth credentials found. Please update them in Settings.", - }); - } - - const insuranceId = String(data.memberId ?? "").trim(); - if (!insuranceId) { - return res.status(400).json({ error: "Missing memberId" }); - } - - const enrichedData = { - ...data, - massdhpUsername: credentials.username, - massdhpPassword: credentials.password, - }; - - const jobId = enqueueSeleniumJob({ - jobType: "cmsp-eligibility-history-remaining-check", - userId: req.user.id, - socketId: req.body.socketId, - enrichedPayload: enrichedData, - insuranceId, - formFirstName: data.firstName, - formLastName: data.lastName, - formDob: data.dateOfBirth, - }); - - return res.json({ jobId, status: "queued" }); - } -); - router.post( "/claim-status-check", async (req: Request, res: Response): Promise => { diff --git a/apps/Frontend/index.html b/apps/Frontend/index.html index 9089baf2..ca855f7a 100755 --- a/apps/Frontend/index.html +++ b/apps/Frontend/index.html @@ -7,7 +7,7 @@ - My Dental Office Management + Wellspring Acupuncture Office Management
diff --git a/apps/Frontend/src/components/insurance-status/ddma-buton-modal.tsx b/apps/Frontend/src/components/insurance-status/ddma-buton-modal.tsx index c6d4fc0f..08eb6c0c 100755 --- a/apps/Frontend/src/components/insurance-status/ddma-buton-modal.tsx +++ b/apps/Frontend/src/components/insurance-status/ddma-buton-modal.tsx @@ -419,7 +419,7 @@ export function DdmaEligibilityButton({ ) : ( <> - Delta MA + Claim MD )} diff --git a/apps/Frontend/src/components/layout/chatbot.tsx b/apps/Frontend/src/components/layout/chatbot.tsx index 281fffe8..8347ec1e 100644 --- a/apps/Frontend/src/components/layout/chatbot.tsx +++ b/apps/Frontend/src/components/layout/chatbot.tsx @@ -2,7 +2,6 @@ import { useState, useRef, useEffect } from "react"; import { Bot, X, - ChevronRight, Stethoscope, Calendar, FileText, @@ -13,7 +12,6 @@ import { Paperclip, } from "lucide-react"; import { Button } from "@/components/ui/button"; -import { Label } from "@/components/ui/label"; import { useLocation } from "wouter"; import { cn } from "@/lib/utils"; import { apiRequest } from "@/lib/queryClient"; @@ -21,8 +19,6 @@ import { setChatbotPendingFiles } from "@/lib/chatbotFileStore"; type Step = | "menu" - | "eligibility-input" - | "eligibility-confirm" | "ai-loading" | "patient-found" | "eligibility-id-ready" @@ -53,12 +49,6 @@ interface PatientResult { dateOfBirth: string | null; } -interface EligibilityData { - memberId: string; - dob: string; - dobISO: string; -} - interface CheckAndClaimData { patient: PatientResult | null; memberId: string; @@ -75,40 +65,6 @@ function makeMsg(role: "bot" | "user", text: string, isLoading = false): Message return { id: ++msgCounter, role, text, isLoading }; } -function getAutoCheck(dobISO: string): "mh" | "cmsp" { - const [y, m, d] = dobISO.split("-").map(Number); - const today = new Date(); - let age = today.getFullYear() - (y ?? 0); - const monthDiff = today.getMonth() + 1 - (m ?? 0); - if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < (d ?? 0))) age--; - return age >= 21 ? "mh" : "cmsp"; -} - -function parseEligibilityInput( - raw: string -): { memberId: string; display: string; iso: string } | null { - const dateMatch = raw.match(/\b(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})\b/); - if (!dateMatch) return null; - const m = dateMatch[1]; - const d = dateMatch[2]; - const y = dateMatch[3]; - if (!m || !d || !y) return null; - const month = parseInt(m, 10); - const day = parseInt(d, 10); - const year = parseInt(y, 10); - if (month < 1 || month > 12 || day < 1 || day > 31 || year < 1900) return null; - - const withoutDate = raw.replace(dateMatch[0], ""); - const memberId = (withoutDate.match(/[a-zA-Z0-9]/g) ?? []).join(""); - if (!memberId) return null; - - return { - memberId, - display: `${m.padStart(2, "0")}/${d.padStart(2, "0")}/${y}`, - iso: `${y}-${m.padStart(2, "0")}-${d.padStart(2, "0")}`, - }; -} - const CHAT_STORAGE_KEY = "chatbot_messages"; const CHATBOT_JOB_TS_KEY = "chatbot_job_started_at"; @@ -158,9 +114,6 @@ export function ChatbotButton() { const [open, setOpen] = useState(false); const [step, setStep] = useState("menu"); const [messages, setMessages] = useState(loadSavedMessages); - const [pasteInput, setPasteInput] = useState(""); - const [parseError, setParseError] = useState(""); - const [eligibilityData, setEligibilityData] = useState(null); const [freeTextInput, setFreeTextInput] = useState(""); const [patientResult, setPatientResult] = useState(null); const [eligibilityIdData, setEligibilityIdData] = useState<{ memberId: string; dob: string; siteKey: string; autoCheck: string; patient: PatientResult | null; appointmentDate?: string | null } | null>(null); @@ -206,7 +159,6 @@ export function ChatbotButton() { const [pendingFiles, setPendingFiles] = useState([]); const [, setLocation] = useLocation(); const messagesEndRef = useRef(null); - const pasteRef = useRef(null); const freeTextRef = useRef(null); const fileInputRef = useRef(null); @@ -244,9 +196,6 @@ export function ChatbotButton() { }, [messages]); useEffect(() => { - if (step === "eligibility-input") { - setTimeout(() => pasteRef.current?.focus(), 50); - } if (step === "menu") { setTimeout(() => freeTextRef.current?.focus(), 50); } @@ -266,9 +215,6 @@ export function ChatbotButton() { // Resets step/data only — keeps message history const resetStep = () => { setStep("menu"); - setPasteInput(""); - setParseError(""); - setEligibilityData(null); setFreeTextInput(""); setPatientResult(null); setEligibilityIdData(null); @@ -300,7 +246,7 @@ export function ChatbotButton() { resetStep(); }; - const handleOptionSelect = (option: "eligibility" | "schedule" | "claims") => { + const handleOptionSelect = (option: "schedule" | "claims") => { if (option === "schedule") { addMsg("user", "Schedule an appointment"); addMsg("bot", "Opening the appointments page..."); @@ -309,67 +255,9 @@ export function ChatbotButton() { addMsg("user", "View claims"); addMsg("bot", "Opening the claims page..."); setTimeout(() => { setLocation("/claims"); setOpen(false); resetStep(); }, 600); - } else if (option === "eligibility") { - addMsg("user", "Check Eligibility"); - addMsg("bot", "Please enter the patient's Member ID and Date of Birth:"); - setStep("eligibility-input"); } }; - const handleEligibilitySubmit = () => { - const parsed = parseEligibilityInput(pasteInput); - if (!parsed) { - setParseError("Couldn't find both a Member ID and a date. Try: 123456789 01/15/1985"); - return; - } - setParseError(""); - const data: EligibilityData = { memberId: parsed.memberId, dob: parsed.display, dobISO: parsed.iso }; - setEligibilityData(data); - addMsg("user", pasteInput.trim()); - addMsg("bot", `Ready to check MassHealth eligibility for:\n• Member ID: ${parsed.memberId}\n• Date of Birth: ${parsed.display}\n\nShall I proceed?`); - setStep("eligibility-confirm"); - }; - - const handleConfirm = () => { - if (!eligibilityData) return; - addMsg("user", "Yes, check now"); - addMsg("bot", "Opening the eligibility check page with this patient..."); - sessionStorage.setItem("chatbot_eligibility", JSON.stringify({ - memberId: eligibilityData.memberId, - dob: eligibilityData.dobISO, - autoCheck: getAutoCheck(eligibilityData.dobISO), - })); - window.dispatchEvent(new CustomEvent("chatbot:eligibility-prefill")); - setTimeout(() => { setLocation("/insurance-status"); setOpen(false); resetStep(); }, 600); - }; - - const handleEligibilityFromPatient = () => { - if (!patientResult?.insuranceId || !patientResult?.dateOfBirth) return; - addMsg("user", "Check eligibility now"); - addMsg("bot", "Opening the eligibility check page..."); - prefillAndNavigate(patientResult.insuranceId, patientResult.dateOfBirth, getAutoCheck(patientResult.dateOfBirth)); - }; - - const handleEligibilityAndAppointmentFromPatient = async () => { - if (!patientResult?.insuranceId || !patientResult?.dateOfBirth) return; - addMsg("user", "Check eligibility & add to schedule (today)"); - addMsg("bot", "Creating appointment for today...", true); - try { - const res = await apiRequest("POST", "/api/ai/create-appointment-today", { - patientId: patientResult.id, - }); - const data = await res.json(); - if (!res.ok) { - replaceLastMsg(data.message ?? "Could not create appointment."); - return; - } - replaceLastMsg(`Appointment added at ${data.startTime} (${data.column ?? "Column A"}) — opening eligibility check page...`); - } catch { - replaceLastMsg("Could not create appointment — opening eligibility check page..."); - } - prefillAndNavigate(patientResult.insuranceId, patientResult.dateOfBirth, getAutoCheck(patientResult.dateOfBirth)); - }; - const prefillAndNavigate = (memberId: string, dobISO: string, autoCheck: string) => { sessionStorage.setItem("chatbot_eligibility", JSON.stringify({ memberId, dob: dobISO, autoCheck })); window.dispatchEvent(new CustomEvent("chatbot:eligibility-prefill")); @@ -728,14 +616,7 @@ export function ChatbotButton() { {/* Quick-action buttons (menu step) */} {step === "menu" && ( -
- +
)} - {/* Eligibility manual input */} - {step === "eligibility-input" && ( -
- -