feat: auto-populate patient fields from member ID on eligibility page

When a member ID is typed on the insurance eligibility page, debounced
lookup fills in date of birth, first name, and last name if the patient
already exists in the database.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gitead
2026-05-08 14:30:29 -04:00
parent 9908e5b5fd
commit e9296c68f9
7 changed files with 81 additions and 8 deletions

View File

@@ -11,7 +11,7 @@ import {
} from "@/components/ui/select";
import { useToast } from "@/hooks/use-toast";
import { apiRequest, queryClient } from "@/lib/queryClient";
import { Send, ArrowLeft, FileText, Globe, Bot, UserPlus } from "lucide-react";
import { Send, ArrowLeft, FileText, Globe, Bot, UserPlus, CalendarX } from "lucide-react";
import { Switch } from "@/components/ui/switch";
import type { Patient, Communication } from "@repo/db/types";
import { format, isToday, isYesterday, parseISO } from "date-fns";
@@ -266,7 +266,7 @@ export function MessageThread({ patient, onBack, appointmentInfo }: MessageThrea
);
const messagesEndRef = useRef<HTMLDivElement>(null);
const [handOffToAI, setHandOffToAI] = useState(true);
const [pendingStartFlow, setPendingStartFlow] = useState<"new_patient" | null>(null);
const [pendingStartFlow, setPendingStartFlow] = useState<"new_patient" | "reschedule" | null>(null);
useQuery<{ enabled: boolean }>({
queryKey: ["/api/twilio/ai-handoff", patient.id],
@@ -277,7 +277,7 @@ export function MessageThread({ patient, onBack, appointmentInfo }: MessageThrea
onSuccess: (data: { enabled: boolean }) => setHandOffToAI(data.enabled),
} as any);
const { data: aiChatTemplates } = useQuery<{ newPatientGreeting: string } | null>({
const { data: aiChatTemplates } = useQuery<{ newPatientGreeting: string; rescheduleGreeting: string } | null>({
queryKey: ["/api/ai/chat-templates"],
queryFn: async () => {
const res = await apiRequest("GET", "/api/ai/chat-templates");
@@ -434,6 +434,11 @@ export function MessageThread({ patient, onBack, appointmentInfo }: MessageThrea
"Hi! My name is Lisa, the dedicated AI assistant at our dental office. I can help you schedule an appointment, check your insurance, and answer general questions 24/7. How can I help you today?";
setMessageText(greeting);
setPendingStartFlow("new_patient");
} else if (key === "__reschedule__") {
const greeting = aiChatTemplates?.rescheduleGreeting ||
"Hi! My name is Lisa, the dedicated AI assistant at our dental office. I can help you find a new appointment time that works for you. Would you like to reschedule your appointment?";
setMessageText(greeting);
setPendingStartFlow("reschedule");
} else {
const tpl = templates.find((t) => t.key === key);
if (tpl) { setMessageText(tpl.body); setPendingStartFlow(null); }
@@ -451,6 +456,13 @@ export function MessageThread({ patient, onBack, appointmentInfo }: MessageThrea
Schedule a New Patient
</span>
</SelectItem>
{/* Reschedule patients — uses AI Reschedule Greeting */}
<SelectItem value="__reschedule__" className="text-xs font-medium text-primary">
<span className="flex items-center gap-1.5">
<CalendarX className="h-3 w-3" />
Reschedule Patients
</span>
</SelectItem>
<div className="my-1 border-t" />
{templates.map((t) => (
<SelectItem key={t.key} value={t.key} className="text-xs">
@@ -469,6 +481,14 @@ export function MessageThread({ patient, onBack, appointmentInfo }: MessageThrea
</div>
)}
{/* Reschedule flow indicator */}
{pendingStartFlow === "reschedule" && (
<div className="flex items-center gap-1 text-xs text-primary bg-primary/5 border border-primary/20 rounded px-2 py-0.5">
<CalendarX className="h-3 w-3" />
Reschedule flow
</div>
)}
{/* AI handoff toggle */}
<div className="flex items-center gap-1.5 ml-auto">
<Bot className={`h-3.5 w-3.5 flex-shrink-0 ${handOffToAI ? "text-primary" : "text-muted-foreground"}`} />