import { useState, useRef } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; import { format, parse, isValid, parseISO } from "date-fns"; import { StatCard } from "@/components/ui/stat-card"; import { PatientTable } from "@/components/patients/patient-table"; import { AddPatientModal } from "@/components/patients/add-patient-modal"; import { AddAppointmentModal } from "@/components/appointments/add-appointment-modal"; import { Card, CardContent } from "@/components/ui/card"; 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 { Users, Calendar, CheckCircle, CreditCard, Plus, Clock, } from "lucide-react"; import { Link } from "wouter"; import { formatLocalDate, parseLocalDate } from "@/utils/dateUtils"; import { Appointment, InsertAppointment, InsertPatient, Patient, UpdateAppointment, } from "@repo/db/types"; import { QK_PATIENTS_BASE } from "@/components/patients/patient-table"; // Type for the ref to access modal methods type AddPatientModalRef = { shouldSchedule: boolean; shouldClaim: boolean; navigateToSchedule: (patientId: number) => void; navigateToClaim: (patientId: number) => void; }; export default function Dashboard() { const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [isAddPatientOpen, setIsAddPatientOpen] = useState(false); const [isAddAppointmentOpen, setIsAddAppointmentOpen] = useState(false); const [currentPatient, setCurrentPatient] = useState( undefined ); const [selectedAppointment, setSelectedAppointment] = useState< Appointment | undefined >(undefined); const { toast } = useToast(); const { user } = useAuth(); const addPatientModalRef = useRef(null); // Fetch patients const { data: patients = [], isLoading: isLoadingPatients } = useQuery< Patient[] >({ queryKey: ["/api/patients/"], queryFn: async () => { const res = await apiRequest("GET", "/api/patients/"); return res.json(); }, enabled: !!user, }); // Fetch appointments const { data: appointments = [] as Appointment[], isLoading: isLoadingAppointments, } = useQuery({ queryKey: ["/api/appointments/all"], queryFn: async () => { const res = await apiRequest("GET", "/api/appointments/all"); return res.json(); }, enabled: !!user, }); // Add patient mutation const addPatientMutation = useMutation({ mutationFn: async (patient: InsertPatient) => { const res = await apiRequest("POST", "/api/patients/", patient); return res.json(); }, onSuccess: (newPatient) => { setIsAddPatientOpen(false); queryClient.invalidateQueries({ queryKey: QK_PATIENTS_BASE }); toast({ title: "Success", description: "Patient added successfully!", variant: "default", }); if (addPatientModalRef.current?.shouldSchedule) { addPatientModalRef.current.navigateToSchedule(newPatient.id); } }, onError: (error) => { toast({ title: "Error", description: `Failed to add patient: ${error.message}`, variant: "destructive", }); }, }); const toggleMobileMenu = () => { setIsMobileMenuOpen(!isMobileMenuOpen); }; const handleAddPatient = (patient: InsertPatient) => { if (user) { addPatientMutation.mutate({ ...patient, userId: user.id, }); } }; const isLoading = isLoadingPatients || addPatientMutation.isPending; // Create/upsert appointment mutation const createAppointmentMutation = useMutation({ mutationFn: async (appointment: InsertAppointment) => { const res = await apiRequest( "POST", "/api/appointments/upsert", appointment ); return await res.json(); }, onSuccess: () => { setIsAddAppointmentOpen(false); toast({ title: "Success", description: "Appointment created successfully.", }); // Invalidate both appointments and patients queries queryClient.invalidateQueries({ queryKey: ["/api/appointments/all"] }); queryClient.invalidateQueries({ queryKey: ["/api/patients/"] }); }, onError: (error: Error) => { toast({ title: "Error", description: `Failed to create appointment: ${error.message}`, variant: "destructive", }); }, }); // Update appointment mutation const updateAppointmentMutation = useMutation({ mutationFn: async ({ id, appointment, }: { id: number; appointment: UpdateAppointment; }) => { const res = await apiRequest( "PUT", `/api/appointments/${id}`, appointment ); return await res.json(); }, onSuccess: () => { setIsAddAppointmentOpen(false); toast({ title: "Success", description: "Appointment updated successfully.", }); // Invalidate both appointments and patients queries queryClient.invalidateQueries({ queryKey: ["/api/appointments/all"] }); queryClient.invalidateQueries({ queryKey: ["/api/patients/"] }); }, onError: (error: Error) => { toast({ title: "Error", description: `Failed to update appointment: ${error.message}`, variant: "destructive", }); }, }); // Handle appointment submission (create or update) const handleAppointmentSubmit = ( appointmentData: InsertAppointment | UpdateAppointment ) => { if (selectedAppointment && typeof selectedAppointment.id === "number") { updateAppointmentMutation.mutate({ id: selectedAppointment.id, appointment: appointmentData as UpdateAppointment, }); } else { if (user) { createAppointmentMutation.mutate({ ...(appointmentData as InsertAppointment), userId: user.id, }); } } }; // Since we removed filters, just return all patients const today = formatLocalDate(new Date()); const todaysAppointments = appointments.filter((appointment) => { const parsedDate = parseLocalDate(appointment.date); return formatLocalDate(parsedDate) === today; }); // Count completed appointments today const completedTodayCount = todaysAppointments.filter((appointment) => { return appointment.status === "completed"; }).length; return (
{/* Quick Stats */}
{/* Today's Appointments Section */}

Today's Appointments

{todaysAppointments.length > 0 ? (
{todaysAppointments.map((appointment) => { const patient = patients.find( (p) => p.id === appointment.patientId ); return (

{patient ? `${patient.firstName} ${patient.lastName}` : "Unknown Patient"}

{`${format( parse( `${format(new Date(appointment.date), "yyyy-MM-dd")} ${appointment.startTime}`, "yyyy-MM-dd HH:mm", new Date() ), "hh:mm a" )} - ${format( parse( `${format(new Date(appointment.date), "yyyy-MM-dd")} ${appointment.endTime}`, "yyyy-MM-dd HH:mm", new Date() ), "hh:mm a" )}`} {appointment.type.charAt(0).toUpperCase() + appointment.type.slice(1)}
{appointment.status ? appointment.status.charAt(0).toUpperCase() + appointment.status.slice(1) : "Scheduled"} View All
); })}
) : (

No appointments today

You don't have any appointments scheduled for today.

)}
{/* Analytics Dashboard Section */}
{/* Patient Management Section */}
{/* Patient Header */}

Patient Management

{/* Patient Table */}
{/* Add/Edit Patient Modal */} {/* Add/Edit Appointment Modal */}
); }