feat: save claim attachments to cloud storage and documents page
- Claim file uploads (chatbot or manual) now save to both the Cloud Storage patient folder and the Documents page via new POST /api/claims/upload-to-cloud endpoint - MH submit flow now calls uploadAttachmentsToLocalFolder (same as DDMA/United/Tufts) so chatbot-attached X-rays are persisted - Removed old /upload-attachments disk route and attachmentDiskStorage multer config; deleted uploads/patients/ folder - uploadAttachmentsToLocalFolder now points to /upload-to-cloud and sends patientId so the backend can create the patient folder Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -135,7 +135,7 @@ export function ChatbotButton() {
|
||||
const [eligibilityData, setEligibilityData] = useState<EligibilityData | null>(null);
|
||||
const [freeTextInput, setFreeTextInput] = useState("");
|
||||
const [patientResult, setPatientResult] = useState<PatientResult | null>(null);
|
||||
const [eligibilityIdData, setEligibilityIdData] = useState<{ memberId: string; dob: string; siteKey: string; autoCheck: string; patient: PatientResult | null } | null>(null);
|
||||
const [eligibilityIdData, setEligibilityIdData] = useState<{ memberId: string; dob: string; siteKey: string; autoCheck: string; patient: PatientResult | null; appointmentDate?: string | null } | null>(null);
|
||||
const [checkAndClaimData, setCheckAndClaimData] = useState<CheckAndClaimData | null>(null);
|
||||
const [clarificationData, setClarificationData] = useState<{ memberId: string; dob: string; patient: PatientResult | null; procedureNames: string[]; options: string[] } | null>(null);
|
||||
const [apptSelectionData, setApptSelectionData] = useState<{
|
||||
@@ -299,29 +299,32 @@ export function ChatbotButton() {
|
||||
prefillAndNavigate(eligibilityIdData.memberId, eligibilityIdData.dob, eligibilityIdData.autoCheck);
|
||||
};
|
||||
|
||||
const handleEligibilityAndAppointment = async () => {
|
||||
const handleEligibilityAndAppointment = async (targetDate?: string) => {
|
||||
if (!eligibilityIdData) return;
|
||||
addMsg("user", "Check eligibility & add to today's schedule");
|
||||
const dateLabel = targetDate
|
||||
? new Date(targetDate + "T00:00:00").toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })
|
||||
: "today";
|
||||
addMsg("user", `Check eligibility & add to schedule (${dateLabel})`);
|
||||
|
||||
if (!eligibilityIdData.patient) {
|
||||
// Patient not yet in DB — eligibility check will create them; flag for post-check appointment
|
||||
addMsg("bot", "Running eligibility check — will add patient and create today's appointment after...");
|
||||
sessionStorage.setItem("chatbot_appt_after_eligibility", JSON.stringify({ memberId: eligibilityIdData.memberId }));
|
||||
addMsg("bot", `Running eligibility check — will add patient and create appointment for ${dateLabel} after...`);
|
||||
sessionStorage.setItem("chatbot_appt_after_eligibility", JSON.stringify({ memberId: eligibilityIdData.memberId, date: targetDate ?? null }));
|
||||
prefillAndNavigate(eligibilityIdData.memberId, eligibilityIdData.dob, eligibilityIdData.autoCheck);
|
||||
return;
|
||||
}
|
||||
|
||||
addMsg("bot", "Creating appointment for today...", true);
|
||||
addMsg("bot", `Creating appointment for ${dateLabel}...`, true);
|
||||
try {
|
||||
const res = await apiRequest("POST", "/api/ai/create-appointment-today", {
|
||||
patientId: eligibilityIdData.patient.id,
|
||||
date: targetDate ?? undefined,
|
||||
});
|
||||
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...`);
|
||||
replaceLastMsg(`Appointment added at ${data.startTime} (${data.column ?? "Column A"}) for ${data.dateLabel} — opening eligibility check page...`);
|
||||
prefillAndNavigate(eligibilityIdData.memberId, eligibilityIdData.dob, eligibilityIdData.autoCheck);
|
||||
} catch {
|
||||
replaceLastMsg("Could not create appointment. Please try again.");
|
||||
@@ -393,6 +396,7 @@ export function ChatbotButton() {
|
||||
siteKey: data.actionData.siteKey,
|
||||
autoCheck: data.actionData.autoCheck,
|
||||
patient: data.actionData.patient ?? null,
|
||||
appointmentDate: data.actionData.appointmentDate ?? null,
|
||||
});
|
||||
setStep("eligibility-id-ready");
|
||||
return;
|
||||
@@ -694,11 +698,22 @@ export function ChatbotButton() {
|
||||
<Button
|
||||
size="sm"
|
||||
className="w-full h-8 text-xs bg-emerald-600 hover:bg-emerald-700 text-white"
|
||||
onClick={handleEligibilityAndAppointment}
|
||||
onClick={() => handleEligibilityAndAppointment()}
|
||||
>
|
||||
<Calendar className="h-3 w-3 mr-1" />
|
||||
Eligibility & Appointment
|
||||
Eligibility & Appointment Today
|
||||
</Button>
|
||||
{eligibilityIdData.appointmentDate && (
|
||||
<Button
|
||||
size="sm"
|
||||
className="w-full h-8 text-xs bg-teal-600 hover:bg-teal-700 text-white"
|
||||
onClick={() => handleEligibilityAndAppointment(eligibilityIdData!.appointmentDate!)}
|
||||
>
|
||||
<Calendar className="h-3 w-3 mr-1" />
|
||||
Eligibility & Appointment on{" "}
|
||||
{new Date(eligibilityIdData.appointmentDate + "T00:00:00").toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}
|
||||
</Button>
|
||||
)}
|
||||
<Button size="sm" variant="ghost" className="w-full h-8 text-xs" onClick={reset}>
|
||||
Cancel
|
||||
</Button>
|
||||
@@ -780,6 +795,7 @@ export function ChatbotButton() {
|
||||
siteKey: data.actionData.siteKey,
|
||||
autoCheck: data.actionData.autoCheck,
|
||||
patient: data.actionData.patient ?? null,
|
||||
appointmentDate: data.actionData.appointmentDate ?? null,
|
||||
});
|
||||
setStep("eligibility-id-ready");
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user