From f30d010d59cedd3a0dc7e64c1e4abbde57f0bd66 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Wed, 21 May 2025 15:59:46 +0530 Subject: [PATCH] just brought --- apps/Frontend/src/App.tsx | 37 +- .../analytics/appointments-by-day.tsx | 50 +++ .../src/components/analytics/new-patients.tsx | 67 +++ .../src/components/layout/sidebar.tsx | 18 +- apps/Frontend/src/pages/claims-page.tsx | 255 +++++++++++ apps/Frontend/src/pages/dashboard.tsx | 8 + apps/Frontend/src/pages/payments-page.tsx | 414 ++++++++++++++++++ .../src/pages/preauthorizations-page.tsx | 350 +++++++++++++++ 8 files changed, 1185 insertions(+), 14 deletions(-) create mode 100644 apps/Frontend/src/components/analytics/appointments-by-day.tsx create mode 100644 apps/Frontend/src/components/analytics/new-patients.tsx create mode 100644 apps/Frontend/src/pages/claims-page.tsx create mode 100644 apps/Frontend/src/pages/payments-page.tsx create mode 100644 apps/Frontend/src/pages/preauthorizations-page.tsx diff --git a/apps/Frontend/src/App.tsx b/apps/Frontend/src/App.tsx index 882527d..ea3d114 100644 --- a/apps/Frontend/src/App.tsx +++ b/apps/Frontend/src/App.tsx @@ -1,37 +1,48 @@ import { Switch, Route } from "wouter"; +import React, { Suspense, lazy } from "react"; import { queryClient } from "./lib/queryClient"; import { QueryClientProvider } from "@tanstack/react-query"; import { Toaster } from "./components/ui/toaster"; import { TooltipProvider } from "./components/ui/tooltip"; -import NotFound from "./pages/not-found"; -import Dashboard from "./pages/dashboard"; -import AuthPage from "./pages/auth-page"; -import AppointmentsPage from "./pages/appointments-page"; -import PatientsPage from "./pages/patients-page"; import { ProtectedRoute } from "./lib/protected-route"; import { AuthProvider } from "./hooks/use-auth"; -import SettingsPage from "./pages/settings-page"; + +import Dashboard from "./pages/dashboard"; +const AuthPage = lazy(() => import("./pages/auth-page")); +const AppointmentsPage = lazy(() => import("./pages/appointments-page")); +const PatientsPage = lazy(() => import("./pages/patients-page")); +const SettingsPage = lazy(() => import("./pages/settings-page")); +const ClaimsPage = lazy(() => import("./pages/claims-page")); +const PreAuthorizationsPage = lazy(() => import("./pages/preauthorizations-page")); +const PaymentsPage = lazy(() => import("./pages/payments-page")); +const NotFound = lazy(() => import("./pages/not-found")); function Router() { return ( - - - - - - + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> ); } + function App() { return ( - + Loading...}> + + diff --git a/apps/Frontend/src/components/analytics/appointments-by-day.tsx b/apps/Frontend/src/components/analytics/appointments-by-day.tsx new file mode 100644 index 0000000..c00aa5f --- /dev/null +++ b/apps/Frontend/src/components/analytics/appointments-by-day.tsx @@ -0,0 +1,50 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, ResponsiveContainer, Tooltip } from "recharts"; + +interface AppointmentsByDayProps { + appointments: any[]; +} + +export function AppointmentsByDay({ appointments }: AppointmentsByDayProps) { + // Data processing for appointments by day + const daysOfWeek = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; + + // Initialize counts for each day + const countsByDay = daysOfWeek.map(day => ({ day, count: 0 })); + + // Count appointments by day of week + appointments.forEach(appointment => { + const date = new Date(appointment.date); + const dayOfWeek = date.getDay(); // 0 = Sunday, 1 = Monday, ... + const dayIndex = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // Adjust to make Monday first + countsByDay[dayIndex].count += 1; + }); + + return ( + + + Appointments by Day +

Distribution of appointments throughout the week

+
+ +
+ + + + + + [`${value} appointments`, "Count"]} + labelFormatter={(value) => `${value}`} + /> + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/apps/Frontend/src/components/analytics/new-patients.tsx b/apps/Frontend/src/components/analytics/new-patients.tsx new file mode 100644 index 0000000..a2d40e6 --- /dev/null +++ b/apps/Frontend/src/components/analytics/new-patients.tsx @@ -0,0 +1,67 @@ +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { LineChart, Line, XAxis, YAxis, CartesianGrid, ResponsiveContainer, Tooltip } from "recharts"; + +interface NewPatientsProps { + patients: any[]; +} + +export function NewPatients({ patients }: NewPatientsProps) { + // Get months for the chart + const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + + // Process patient data by registration month + const patientsByMonth = months.map(month => ({ name: month, count: 0 })); + + // Count new patients by month + patients.forEach(patient => { + const createdDate = new Date(patient.createdAt); + const monthIndex = createdDate.getMonth(); + patientsByMonth[monthIndex].count += 1; + }); + + // Add some sample data for visual effect if no patients + if (patients.length === 0) { + // Sample data pattern similar to the screenshot + const sampleData = [17, 12, 22, 16, 15, 17, 22, 28, 20, 16]; + sampleData.forEach((value, index) => { + if (index < patientsByMonth.length) { + patientsByMonth[index].count = value; + } + }); + } + + return ( + + + New Patients +

Monthly trend of new patient registrations

+
+ +
+ + + + + + [`${value} patients`, "Count"]} + labelFormatter={(value) => `${value}`} + /> + + + +
+
+
+ ); +} \ No newline at end of file diff --git a/apps/Frontend/src/components/layout/sidebar.tsx b/apps/Frontend/src/components/layout/sidebar.tsx index 8bc78bc..af85817 100644 --- a/apps/Frontend/src/components/layout/sidebar.tsx +++ b/apps/Frontend/src/components/layout/sidebar.tsx @@ -1,5 +1,6 @@ import { Link, useLocation } from "wouter"; -import { LayoutDashboard, Users, Calendar, FileText, Settings } from "lucide-react"; +import { LayoutDashboard, Users, Calendar, Settings, FileCheck, ClipboardCheck, CreditCard } from "lucide-react"; + import { cn } from "@/lib/utils"; interface SidebarProps { @@ -26,6 +27,21 @@ export function Sidebar({ isMobileOpen, setIsMobileOpen }: SidebarProps) { path: "/patients", icon: , }, + { + name: "Claims", + path: "/claims", + icon: , + }, + { + name: "Pre-authorizations", + path: "/preauthorizations", + icon: , + }, + { + name: "Payments", + path: "/payments", + icon: , + }, { name: "Settings", path: "/settings", diff --git a/apps/Frontend/src/pages/claims-page.tsx b/apps/Frontend/src/pages/claims-page.tsx new file mode 100644 index 0000000..710c1de --- /dev/null +++ b/apps/Frontend/src/pages/claims-page.tsx @@ -0,0 +1,255 @@ +import { useState, useEffect } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { TopAppBar } from "@/components/layout/top-app-bar"; +import { Sidebar } from "@/components/layout/sidebar"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { ClaimForm } from "@/components/claims/claim-form"; +import { useToast } from "@/hooks/use-toast"; +import { useAuth } from "@/hooks/use-auth"; +// import { Patient, Appointment } from "@shared/schema"; +import { PatientUncheckedCreateInputObjectSchema, AppointmentUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas"; +import { Plus, FileCheck, CheckCircle, Clock, AlertCircle } from "lucide-react"; +import { format } from "date-fns"; + +export default function ClaimsPage() { + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + const [isClaimFormOpen, setIsClaimFormOpen] = useState(false); + const [selectedPatient, setSelectedPatient] = useState(null); + const [selectedAppointment, setSelectedAppointment] = useState(null); + + const { toast } = useToast(); + const { user } = useAuth(); + + // Fetch patients + const { data: patients = [], isLoading: isLoadingPatients } = useQuery({ + queryKey: ["/api/patients"], + enabled: !!user, + }); + + // Fetch appointments + const { + data: appointments = [] as Appointment[], + isLoading: isLoadingAppointments + } = useQuery({ + queryKey: ["/api/appointments"], + enabled: !!user, + }); + + const toggleMobileMenu = () => { + setIsMobileMenuOpen(!isMobileMenuOpen); + }; + + const handleNewClaim = (patientId: number, appointmentId: number) => { + setSelectedPatient(patientId); + setSelectedAppointment(appointmentId); + setIsClaimFormOpen(true); + }; + + const closeClaim = () => { + setIsClaimFormOpen(false); + setSelectedPatient(null); + setSelectedAppointment(null); + }; + + // Get unique patients with appointments + const patientsWithAppointments = appointments.reduce((acc, appointment) => { + if (!acc.some(item => item.patientId === appointment.patientId)) { + const patient = patients.find(p => p.id === appointment.patientId); + if (patient) { + acc.push({ + patientId: patient.id, + patientName: `${patient.firstName} ${patient.lastName}`, + appointmentId: appointment.id, + insuranceProvider: patient.insuranceProvider || 'N/A', + insuranceId: patient.insuranceId || 'N/A', + lastAppointment: appointment.date + }); + } + } + return acc; + }, [] as Array<{ + patientId: number; + patientName: string; + appointmentId: number; + insuranceProvider: string; + insuranceId: string; + lastAppointment: string; + }>); + + return ( +
+ + +
+ + +
+ {/* Header */} +
+

Insurance Claims

+

Manage and submit insurance claims for patients

+
+ + {/* New Claims Section */} +
+
+
{ + if (patientsWithAppointments.length > 0) { + const firstPatient = patientsWithAppointments[0]; + handleNewClaim(firstPatient.patientId, firstPatient.appointmentId); + } else { + toast({ + title: "No patients available", + description: "There are no patients with appointments to create a claim", + }); + } + }} + > +

New Claims

+
+ +
+
+
+ + + + Recent Patients for Claims + + + {isLoadingPatients || isLoadingAppointments ? ( +
Loading patients data...
+ ) : patientsWithAppointments.length > 0 ? ( +
+ {patientsWithAppointments.map((item) => ( +
handleNewClaim(item.patientId, item.appointmentId)} + > +
+

{item.patientName}

+
+ Insurance: {item.insuranceProvider === 'delta' + ? 'Delta Dental' + : item.insuranceProvider === 'metlife' + ? 'MetLife' + : item.insuranceProvider === 'cigna' + ? 'Cigna' + : item.insuranceProvider === 'aetna' + ? 'Aetna' + : item.insuranceProvider} + + ID: {item.insuranceId} + + Last Visit: {new Date(item.lastAppointment).toLocaleDateString()} +
+
+
+ +
+
+ ))} +
+ ) : ( +
+ +

No eligible patients for claims

+

+ Patients with appointments will appear here for insurance claim processing +

+
+ )} +
+
+
+ + {/* Old Claims Section */} +
+
+

Old Claims

+
+ + + + Submitted Claims History + + + {/* Sample Old Claims */} +
+ {patientsWithAppointments.slice(0, 3).map((item, index) => ( +
toast({ + title: "Claim Details", + description: `Viewing details for claim #${2000 + index}` + })} + > +
+

{item.patientName}

+
+ Claim #: {2000 + index} + + Submitted: {format(new Date(new Date().setDate(new Date().getDate() - (index * 15))), 'MMM dd, yyyy')} + + Amount: ${(Math.floor(Math.random() * 500) + 100).toFixed(2)} +
+
+
+ + {index === 0 ? ( + + + Pending + + ) : index === 1 ? ( + + + Approved + + ) : ( + + + Review + + )} + +
+
+ ))} + + {patientsWithAppointments.length === 0 && ( +
+ +

No claim history

+

+ Submitted insurance claims will appear here +

+
+ )} +
+
+
+
+
+
+ + {/* Claim Form Modal */} + {isClaimFormOpen && selectedPatient !== null && selectedAppointment !== null && ( + + )} +
+ ); +} \ No newline at end of file diff --git a/apps/Frontend/src/pages/dashboard.tsx b/apps/Frontend/src/pages/dashboard.tsx index eecf479..929a401 100644 --- a/apps/Frontend/src/pages/dashboard.tsx +++ b/apps/Frontend/src/pages/dashboard.tsx @@ -12,6 +12,8 @@ import { Button } from "@/components/ui/button"; import { useToast } from "@/hooks/use-toast"; import { useAuth } from "@/hooks/use-auth"; import { apiRequest, queryClient } from "@/lib/queryClient"; +import { AppointmentsByDay } from "@/components/analytics/appointments-by-day"; +import { NewPatients } from "@/components/analytics/new-patients"; import { AppointmentUncheckedCreateInputObjectSchema, PatientUncheckedCreateInputObjectSchema, @@ -542,6 +544,12 @@ export default function Dashboard() { + {/* Analytics Dashboard Section */} +
+ + +
+ {/* Patient Management Section */}
{/* Patient Header */} diff --git a/apps/Frontend/src/pages/payments-page.tsx b/apps/Frontend/src/pages/payments-page.tsx new file mode 100644 index 0000000..34fe645 --- /dev/null +++ b/apps/Frontend/src/pages/payments-page.tsx @@ -0,0 +1,414 @@ +import { useState } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { TopAppBar } from "@/components/layout/top-app-bar"; +import { Sidebar } from "@/components/layout/sidebar"; +import { Card, CardHeader, CardTitle, CardContent, CardFooter } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { useToast } from "@/hooks/use-toast"; +import { useAuth } from "@/hooks/use-auth"; +// import { Patient, Appointment } from "@repo/db/shared/schemas"; +import { Patient, Appointment } from "@repo/db/shared/schemas"; +import { + CreditCard, + Clock, + CheckCircle, + AlertCircle, + DollarSign, + Receipt, + Plus, + ArrowDown, + ReceiptText +} from "lucide-react"; +import { format } from "date-fns"; +import { + Table, + TableHeader, + TableBody, + TableRow, + TableHead, + TableCell +} from "@/components/ui/table"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; + +export default function PaymentsPage() { + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + const [paymentPeriod, setPaymentPeriod] = useState("all-time"); + const { toast } = useToast(); + const { user } = useAuth(); + + // Fetch patients + const { data: patients = [], isLoading: isLoadingPatients } = useQuery({ + queryKey: ["/api/patients"], + enabled: !!user, + }); + + // Fetch appointments + const { + data: appointments = [] as Appointment[], + isLoading: isLoadingAppointments + } = useQuery({ + queryKey: ["/api/appointments"], + enabled: !!user, + }); + + const toggleMobileMenu = () => { + setIsMobileMenuOpen(!isMobileMenuOpen); + }; + + // Sample payment data + const samplePayments = [ + { + id: "PMT-1001", + patientId: patients[0]?.id || 1, + amount: 75.00, + date: new Date(new Date().setDate(new Date().getDate() - 2)), + method: "Credit Card", + status: "completed", + description: "Co-pay for cleaning" + }, + { + id: "PMT-1002", + patientId: patients[0]?.id || 1, + amount: 150.00, + date: new Date(new Date().setDate(new Date().getDate() - 7)), + method: "Insurance", + status: "processing", + description: "Insurance claim for x-rays" + }, + { + id: "PMT-1003", + patientId: patients[0]?.id || 1, + amount: 350.00, + date: new Date(new Date().setDate(new Date().getDate() - 14)), + method: "Check", + status: "completed", + description: "Payment for root canal" + }, + { + id: "PMT-1004", + patientId: patients[0]?.id || 1, + amount: 120.00, + date: new Date(new Date().setDate(new Date().getDate() - 30)), + method: "Credit Card", + status: "completed", + description: "Filling procedure" + } + ]; + + // Sample outstanding balances + const sampleOutstanding = [ + { + id: "INV-5001", + patientId: patients[0]?.id || 1, + amount: 210.50, + dueDate: new Date(new Date().setDate(new Date().getDate() + 7)), + description: "Crown procedure", + created: new Date(new Date().setDate(new Date().getDate() - 10)), + status: "pending" + }, + { + id: "INV-5002", + patientId: patients[0]?.id || 1, + amount: 85.00, + dueDate: new Date(new Date().setDate(new Date().getDate() - 5)), + description: "Diagnostic & preventive", + created: new Date(new Date().setDate(new Date().getDate() - 20)), + status: "overdue" + } + ]; + + // Calculate summary data + const totalOutstanding = sampleOutstanding.reduce((sum, item) => sum + item.amount, 0); + const totalCollected = samplePayments + .filter(payment => payment.status === "completed") + .reduce((sum, payment) => sum + payment.amount, 0); + const pendingAmount = samplePayments + .filter(payment => payment.status === "processing") + .reduce((sum, payment) => sum + payment.amount, 0); + + const handleRecordPayment = (patientId: number, invoiceId?: string) => { + const patient = patients.find(p => p.id === patientId); + toast({ + title: "Payment form opened", + description: `Recording payment for ${patient?.firstName} ${patient?.lastName}${invoiceId ? ` (Invoice: ${invoiceId})` : ''}`, + }); + }; + + return ( +
+ + +
+ + +
+ {/* Header */} +
+
+

Payments

+

Manage patient payments and outstanding balances

+
+ +
+ + + +
+
+ + {/* Payment Summary Cards */} +
+ + + Outstanding Balance + + +
+ +
${totalOutstanding.toFixed(2)}
+
+

+ From {sampleOutstanding.length} outstanding invoices +

+
+
+ + + + Payments Collected + + +
+ +
${totalCollected.toFixed(2)}
+
+

+ From {samplePayments.filter(p => p.status === "completed").length} completed payments +

+
+
+ + + + Pending Payments + + +
+ +
${pendingAmount.toFixed(2)}
+
+

+ From {samplePayments.filter(p => p.status === "processing").length} pending transactions +

+
+
+
+ + {/* Outstanding Balances Section */} +
+
+

Outstanding Balances

+
+ + + + {sampleOutstanding.length > 0 ? ( + + + + Patient + Invoice + Description + Amount + Due Date + Status + Action + + + + {sampleOutstanding.map((invoice) => { + const patient = patients.find(p => p.id === invoice.patientId) || + { firstName: "Sample", lastName: "Patient" }; + + return ( + + + {patient.firstName} {patient.lastName} + + {invoice.id} + {invoice.description} + ${invoice.amount.toFixed(2)} + {format(invoice.dueDate, 'MMM dd, yyyy')} + + + {invoice.status === 'overdue' ? ( + <> + + Overdue + + ) : ( + <> + + Pending + + )} + + + + + + + ); + })} + +
+ ) : ( +
+ +

No outstanding balances

+

+ All patient accounts are current +

+
+ )} +
+ + {sampleOutstanding.length > 0 && ( + +
+ + Download statement +
+
+ Total: ${totalOutstanding.toFixed(2)} +
+
+ )} +
+
+ + {/* Recent Payments Section */} +
+
+

Recent Payments

+
+ + + + {samplePayments.length > 0 ? ( + + + + Patient + Payment ID + Description + Date + Amount + Method + Status + Action + + + + {samplePayments.map((payment) => { + const patient = patients.find(p => p.id === payment.patientId) || + { firstName: "Sample", lastName: "Patient" }; + + return ( + + + {patient.firstName} {patient.lastName} + + {payment.id} + {payment.description} + {format(payment.date, 'MMM dd, yyyy')} + ${payment.amount.toFixed(2)} + {payment.method} + + + {payment.status === 'completed' ? ( + <> + + Completed + + ) : ( + <> + + Processing + + )} + + + + + + + ); + })} + +
+ ) : ( +
+ +

No payment history

+

+ Payments will appear here once processed +

+
+ )} +
+
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/apps/Frontend/src/pages/preauthorizations-page.tsx b/apps/Frontend/src/pages/preauthorizations-page.tsx new file mode 100644 index 0000000..e750aff --- /dev/null +++ b/apps/Frontend/src/pages/preauthorizations-page.tsx @@ -0,0 +1,350 @@ +import { useState } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { TopAppBar } from "@/components/layout/top-app-bar"; +import { Sidebar } from "@/components/layout/sidebar"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { useToast } from "@/hooks/use-toast"; +import { useAuth } from "@/hooks/use-auth"; +// import { Patient, Appointment } from "@repo/db/shared/schemas"; +import { Patient, Appointment } from "@repo/db/shared/schemas"; +import { Plus, ClipboardCheck, Clock, CheckCircle, AlertCircle } from "lucide-react"; +import { format } from "date-fns"; + +export default function PreAuthorizationsPage() { + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + const [isPreAuthFormOpen, setIsPreAuthFormOpen] = useState(false); + const [selectedPatient, setSelectedPatient] = useState(null); + const [selectedProcedure, setSelectedProcedure] = useState(null); + + const { toast } = useToast(); + const { user } = useAuth(); + + // Fetch patients + const { data: patients = [], isLoading: isLoadingPatients } = useQuery({ + queryKey: ["/api/patients"], + enabled: !!user, + }); + + // Fetch appointments + const { + data: appointments = [] as Appointment[], + isLoading: isLoadingAppointments + } = useQuery({ + queryKey: ["/api/appointments"], + enabled: !!user, + }); + + const toggleMobileMenu = () => { + setIsMobileMenuOpen(!isMobileMenuOpen); + }; + + const handleNewPreAuth = (patientId: number, procedure: string) => { + setSelectedPatient(patientId); + setSelectedProcedure(procedure); + setIsPreAuthFormOpen(true); + + // Show a toast notification of success + const patient = patients.find(p => p.id === patientId); + toast({ + title: "Pre-authorization Request Started", + description: `Started pre-auth for ${patient?.firstName} ${patient?.lastName} - ${procedure}`, + }); + }; + + // Common dental procedures requiring pre-authorization + const dentalProcedures = [ + { code: "D2740", name: "Crown - porcelain/ceramic" }, + { code: "D2950", name: "Core buildup, including any pins" }, + { code: "D3330", name: "Root Canal - molar" }, + { code: "D4341", name: "Periodontal scaling & root planing" }, + { code: "D4910", name: "Periodontal maintenance" }, + { code: "D5110", name: "Complete denture - maxillary" }, + { code: "D6010", name: "Surgical placement of implant body" }, + { code: "D7240", name: "Removal of impacted tooth" }, + ]; + + // Get patients with active insurance + const patientsWithInsurance = patients.filter(patient => + patient.insuranceProvider && patient.insuranceId + ); + + // Sample pre-authorization data + const samplePreAuths = [ + { + id: "PA2023-001", + patientId: patientsWithInsurance[0]?.id || 1, + procedureCode: "D2740", + procedureName: "Crown - porcelain/ceramic", + requestDate: new Date(new Date().setDate(new Date().getDate() - 14)), + status: "approved", + approvalDate: new Date(new Date().setDate(new Date().getDate() - 7)), + expirationDate: new Date(new Date().setMonth(new Date().getMonth() + 6)), + }, + { + id: "PA2023-002", + patientId: patientsWithInsurance[0]?.id || 1, + procedureCode: "D3330", + procedureName: "Root Canal - molar", + requestDate: new Date(new Date().setDate(new Date().getDate() - 5)), + status: "pending", + approvalDate: null, + expirationDate: null, + }, + { + id: "PA2023-003", + patientId: patientsWithInsurance[0]?.id || 1, + procedureCode: "D7240", + procedureName: "Removal of impacted tooth", + requestDate: new Date(new Date().setDate(new Date().getDate() - 30)), + status: "denied", + approvalDate: null, + expirationDate: null, + denialReason: "Not medically necessary based on submitted documentation", + } + ]; + + return ( +
+ + +
+ + +
+ {/* Header */} +
+

Pre-authorizations

+

Manage insurance pre-authorizations for dental procedures

+
+ + {/* New Pre-Authorization Request Section */} +
+
+

New Pre-Authorization Request

+
+ + + + Recent Patients for Pre-Authorization + + + {isLoadingPatients ? ( +
Loading patients data...
+ ) : patientsWithInsurance.length > 0 ? ( +
+ {patientsWithInsurance.map((patient) => ( +
{ + setSelectedPatient(patient.id); + handleNewPreAuth( + patient.id, + dentalProcedures[Math.floor(Math.random() * 3)].name + ); + }} + > +
+

{patient.firstName} {patient.lastName}

+
+ Insurance: {patient.insuranceProvider === 'delta' + ? 'Delta Dental' + : patient.insuranceProvider === 'metlife' + ? 'MetLife' + : patient.insuranceProvider === 'cigna' + ? 'Cigna' + : patient.insuranceProvider === 'aetna' + ? 'Aetna' + : patient.insuranceProvider} + + ID: {patient.insuranceId} + + Procedure needed: {dentalProcedures[0].name} +
+
+
+ +
+
+ ))} +
+ ) : ( +
+ +

No patients with insurance

+

+ Add insurance information to patients to request pre-authorizations +

+
+ )} +
+
+
+ + {/* Pre-Authorization Submitted Section */} +
+
+

Pre-Authorization Submitted

+
+ + + + Pending Pre-Authorization Requests + + + {patientsWithInsurance.length > 0 ? ( +
+ {samplePreAuths.filter(auth => auth.status === 'pending').map((preAuth) => { + const patient = patients.find(p => p.id === preAuth.patientId) || + { firstName: "Unknown", lastName: "Patient" }; + + return ( +
toast({ + title: "Pre-Authorization Details", + description: `Viewing details for ${preAuth.id}` + })} + > +
+

{patient.firstName} {patient.lastName} - {preAuth.procedureName}

+
+ ID: {preAuth.id} + + Submitted: {format(preAuth.requestDate, 'MMM dd, yyyy')} + + Expected Response: {format(new Date(preAuth.requestDate.getTime() + 7 * 24 * 60 * 60 * 1000), 'MMM dd, yyyy')} +
+
+
+ + + + Pending + + +
+
+ ); + })} + + {samplePreAuths.filter(auth => auth.status === 'pending').length === 0 && ( +
+ +

No pending requests

+

+ Submitted pre-authorization requests will appear here +

+
+ )} +
+ ) : ( +
+ +

No pre-authorization history

+

+ Submitted pre-authorization requests will appear here +

+
+ )} +
+
+
+ + {/* Pre-Authorization Results Section */} +
+
+

Pre-Authorization Results

+
+ + + + Completed Pre-Authorization Requests + + + {patientsWithInsurance.length > 0 ? ( +
+ {samplePreAuths.filter(auth => auth.status !== 'pending').map((preAuth) => { + const patient = patients.find(p => p.id === preAuth.patientId) || + { firstName: "Unknown", lastName: "Patient" }; + + return ( +
toast({ + title: "Pre-Authorization Details", + description: `Viewing details for ${preAuth.id}` + })} + > +
+

{patient.firstName} {patient.lastName} - {preAuth.procedureName}

+
+ ID: {preAuth.id} + + Requested: {format(preAuth.requestDate, 'MMM dd, yyyy')} + {preAuth.status === 'approved' && ( + <> + + Expires: {format(preAuth.expirationDate as Date, 'MMM dd, yyyy')} + + )} + {preAuth.status === 'denied' && preAuth.denialReason && ( + <> + + Reason: {preAuth.denialReason} + + )} +
+
+
+ + {preAuth.status === 'approved' ? ( + + + Approved + + ) : ( + + + Denied + + )} + +
+
+ ); + })} + + {samplePreAuths.filter(auth => auth.status !== 'pending').length === 0 && ( +
+ +

No completed requests

+

+ Processed pre-authorization results will appear here +

+
+ )} +
+ ) : ( +
+ +

No pre-authorization results

+

+ Completed pre-authorization requests will appear here +

+
+ )} +
+
+
+
+
+
+ ); +} \ No newline at end of file