import { useEffect, useRef, useState } from "react"; import { Card, CardHeader, CardTitle, CardContent, CardDescription, } from "@/components/ui/card"; import { DollarSign } from "lucide-react"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import PaymentsRecentTable from "@/components/payments/payments-recent-table"; import PaymentsOfPatientModal from "@/components/payments/payments-of-patient-table"; import PaymentOCRBlock from "@/components/payments/payment-ocr-block"; import { useLocation } from "wouter"; import { Patient, PaymentWithExtras } from "@repo/db/types"; import { apiRequest } from "@/lib/queryClient"; import { toast } from "@/hooks/use-toast"; import PaymentEditModal from "@/components/payments/payment-edit-modal"; export default function PaymentsPage() { const [paymentPeriod, setPaymentPeriod] = useState("all-time"); // for auto-open from appointment redirect const [location] = useLocation(); const [initialPatientForModal, setInitialPatientForModal] = useState(null); const [openPatientModalFromAppointment, setOpenPatientModalFromAppointment] = useState(false); // Payment edit modal state (opens directly when ?paymentId=) const [paymentIdToEdit, setPaymentIdToEdit] = useState(null); const [isEditModalOpen, setIsEditModalOpen] = useState(false); // small helper: remove query params silently const clearUrlParams = (params: string[]) => { try { const url = new URL(window.location.href); let changed = false; for (const p of params) { if (url.searchParams.has(p)) { url.searchParams.delete(p); changed = true; } } if (changed) window.history.replaceState({}, document.title, url.toString()); } catch (e) { // ignore } }; // case1: If payments page is opened via appointment-page, /payments?appointmentId=123 -> fetch patient and open modal useEffect(() => { const params = new URLSearchParams(window.location.search); const appointmentIdParam = params.get("appointmentId"); if (!appointmentIdParam) return; const appointmentId = Number(appointmentIdParam); if (!Number.isFinite(appointmentId) || appointmentId <= 0) return; let cancelled = false; (async () => { try { const res = await apiRequest( "GET", `/api/appointments/${appointmentId}/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 ${appointmentId}.`, variant: "destructive", }); } return; } const data = await res.json(); const patient = data?.patient ?? data; if (!cancelled && patient && patient.id) { setInitialPatientForModal(patient as Patient); setOpenPatientModalFromAppointment(true); // remove query param so reload won't re-open clearUrlParams(["appointmentId"]); } } catch (err) { if (!cancelled) { console.error("Error fetching patient for appointment:", err); } } })(); return () => { cancelled = true; }; }, [location]); // NEW: detect paymentId query param -> open edit modal (modal will fetch by id) useEffect(() => { const params = new URLSearchParams(window.location.search); const paymentIdParam = params.get("paymentId"); if (!paymentIdParam) return; const paymentId = Number(paymentIdParam); if (!Number.isFinite(paymentId) || paymentId <= 0) return; // Open modal with paymentId and clear params setPaymentIdToEdit(paymentId); setIsEditModalOpen(true); clearUrlParams(["paymentId", "patientId"]); }, [location]); return (
{/* Header */}

Payments

Manage patient payments and outstanding balances

{/* Payment Summary Cards */}
Outstanding Balance
$0

From 0 outstanding invoices

Payments Collected
${0}

From 0 completed payments

Pending Payments
$0

From 0 pending transactions

{/* Recent Payments table */} Payment's Records View and manage all recents patient's claims payments {/* Recent Payments by Patients*/} { // reset the local flags when modal is closed setOpenPatientModalFromAppointment(false); setInitialPatientForModal(null); }} /> {/* OCR Image Upload Section*/} {/* Payment Edit Modal — modal will fetch payment by id and handle its own save/update */} setIsEditModalOpen(v)} onClose={() => { setIsEditModalOpen(false); setPaymentIdToEdit(null); }} paymentId={paymentIdToEdit} />
); }