savenschedule working and delete issue in pateint page, add patint issue on dashboard and patient page
This commit is contained in:
@@ -14,7 +14,7 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Edit, Eye, MoreVertical } from "lucide-react";
|
||||
import { Delete, Edit, Eye, MoreVertical } from "lucide-react";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
@@ -39,9 +39,10 @@ interface PatientTableProps {
|
||||
patients: Patient[];
|
||||
onEdit: (patient: Patient) => void;
|
||||
onView: (patient: Patient) => void;
|
||||
onDelete: (patient: Patient) => void;
|
||||
}
|
||||
|
||||
export function PatientTable({ patients, onEdit, onView }: PatientTableProps) {
|
||||
export function PatientTable({ patients, onEdit, onView, onDelete }: PatientTableProps) {
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const patientsPerPage = 5;
|
||||
|
||||
@@ -167,6 +168,17 @@ export function PatientTable({ patients, onEdit, onView }: PatientTableProps) {
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<div className="flex justify-end space-x-2">
|
||||
<Button
|
||||
onClick={() =>
|
||||
onDelete(patient)
|
||||
}
|
||||
className="text-red-600 hover:text-red-900"
|
||||
aria-label="Delete Staff"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
>
|
||||
<Delete/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React, { useState } from "react";
|
||||
import { z } from "zod";
|
||||
import { StaffUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
import { Button } from "../ui/button";
|
||||
import { Delete, Edit } from "lucide-react";
|
||||
|
||||
type Staff = z.infer<typeof StaffUncheckedCreateInputObjectSchema>;
|
||||
|
||||
@@ -15,7 +17,7 @@ interface StaffTableProps {
|
||||
isError?: boolean;
|
||||
onAdd: () => void;
|
||||
onEdit: (staff: Staff) => void;
|
||||
onDelete: (id: number) => void;
|
||||
onDelete: (staff: Staff) => void;
|
||||
onView: (staff: Staff) => void;
|
||||
}
|
||||
|
||||
@@ -148,22 +150,27 @@ export function StaffTable({
|
||||
{formattedDate}
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium space-x-2">
|
||||
<button
|
||||
onClick={() => staff.id !== undefined && onEdit(staff)}
|
||||
className="text-blue-600 hover:text-blue-900"
|
||||
aria-label="Edit Staff"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
<button
|
||||
<Button
|
||||
onClick={() =>
|
||||
staff.id !== undefined && onDelete(staff.id)
|
||||
staff !== undefined && onDelete(staff)
|
||||
}
|
||||
className="text-red-600 hover:text-red-900"
|
||||
aria-label="Delete Staff"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
<Delete/>
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => staff.id !== undefined && onEdit(staff)}
|
||||
className="text-blue-600 hover:text-blue-900"
|
||||
aria-label="Edit Staff"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
>
|
||||
<Edit className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
36
apps/Frontend/src/components/ui/deleteDialog.tsx
Normal file
36
apps/Frontend/src/components/ui/deleteDialog.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
export const DeleteConfirmationDialog = ({
|
||||
isOpen,
|
||||
onConfirm,
|
||||
onCancel,
|
||||
patientName,
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
onConfirm: () => void;
|
||||
onCancel: () => void;
|
||||
patientName?: string;
|
||||
}) => {
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center z-50">
|
||||
<div className="bg-white p-6 rounded-md shadow-md w-[90%] max-w-md">
|
||||
<h2 className="text-xl font-semibold mb-4">Confirm Deletion</h2>
|
||||
<p>Are you sure you want to delete <strong>{patientName}</strong>?</p>
|
||||
<div className="mt-6 flex justify-end space-x-4">
|
||||
<button
|
||||
className="bg-gray-200 px-4 py-2 rounded hover:bg-gray-300"
|
||||
onClick={onCancel}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="bg-red-600 text-white px-4 py-2 rounded hover:bg-red-700"
|
||||
onClick={onConfirm}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useState, useRef} from "react";
|
||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||
import { format } from "date-fns";
|
||||
import { TopAppBar } from "@/components/layout/top-app-bar";
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { z } from "zod";
|
||||
import { DeleteConfirmationDialog } from "@/components/ui/deleteDialog";
|
||||
|
||||
//creating types out of schema auto generated.
|
||||
type Appointment = z.infer<typeof AppointmentUncheckedCreateInputObjectSchema>;
|
||||
@@ -82,10 +83,17 @@ const updatePatientSchema = (
|
||||
|
||||
type UpdatePatient = z.infer<typeof updatePatientSchema>;
|
||||
|
||||
// Type for the ref to access modal methods
|
||||
type AddPatientModalRef = {
|
||||
shouldSchedule: boolean;
|
||||
navigateToSchedule: (patientId: number) => void;
|
||||
};
|
||||
|
||||
export default function Dashboard() {
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
const [isAddPatientOpen, setIsAddPatientOpen] = useState(false);
|
||||
const [isViewPatientOpen, setIsViewPatientOpen] = useState(false);
|
||||
const [isDeletePatientOpen, setIsDeletePatientOpen] = useState(false);
|
||||
const [isAddAppointmentOpen, setIsAddAppointmentOpen] = useState(false);
|
||||
const [currentPatient, setCurrentPatient] = useState<Patient | undefined>(
|
||||
undefined
|
||||
@@ -96,6 +104,9 @@ export default function Dashboard() {
|
||||
|
||||
const { toast } = useToast();
|
||||
const { user } = useAuth();
|
||||
const addPatientModalRef = useRef<AddPatientModalRef | null>(null);
|
||||
|
||||
|
||||
|
||||
// Fetch patients
|
||||
const { data: patients = [], isLoading: isLoadingPatients } = useQuery<
|
||||
@@ -176,6 +187,31 @@ export default function Dashboard() {
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const deletePatientMutation = useMutation({
|
||||
mutationFn: async (id: number) => {
|
||||
const res = await apiRequest("DELETE", `/api/patients/${id}`);
|
||||
return;
|
||||
},
|
||||
onSuccess: () => {
|
||||
setIsDeletePatientOpen(false);
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/patients/"] });
|
||||
toast({
|
||||
title: "Success",
|
||||
description: "Patient deleted successfully!",
|
||||
variant: "default",
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
console.log(error)
|
||||
toast({
|
||||
title: "Error",
|
||||
description: `Failed to delete patient: ${error.message}`,
|
||||
variant: "destructive",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const toggleMobileMenu = () => {
|
||||
setIsMobileMenuOpen(!isMobileMenuOpen);
|
||||
};
|
||||
@@ -216,6 +252,28 @@ export default function Dashboard() {
|
||||
setIsViewPatientOpen(true);
|
||||
};
|
||||
|
||||
const handleDeletePatient = (patient: Patient) => {
|
||||
setCurrentPatient(patient);
|
||||
setIsDeletePatientOpen(true);
|
||||
};
|
||||
|
||||
const handleConfirmDeletePatient = async () => {
|
||||
if (currentPatient) {
|
||||
deletePatientMutation.mutate(currentPatient.id);
|
||||
} else {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "No patient selected for deletion.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const isLoading =
|
||||
isLoadingPatients ||
|
||||
addPatientMutation.isPending ||
|
||||
updatePatientMutation.isPending;
|
||||
|
||||
// Create appointment mutation
|
||||
const createAppointmentMutation = useMutation({
|
||||
mutationFn: async (appointment: InsertAppointment) => {
|
||||
@@ -491,19 +549,27 @@ export default function Dashboard() {
|
||||
patients={filteredPatients}
|
||||
onEdit={handleEditPatient}
|
||||
onView={handleViewPatient}
|
||||
onDelete={handleDeletePatient}
|
||||
/>
|
||||
|
||||
<DeleteConfirmationDialog
|
||||
isOpen={isDeletePatientOpen}
|
||||
onConfirm={handleConfirmDeletePatient}
|
||||
onCancel={() => setIsDeletePatientOpen(false)}
|
||||
patientName={currentPatient?.name}
|
||||
/>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{/* Add/Edit Patient Modal */}
|
||||
<AddPatientModal
|
||||
ref={addPatientModalRef}
|
||||
open={isAddPatientOpen}
|
||||
onOpenChange={setIsAddPatientOpen}
|
||||
onSubmit={currentPatient ? handleUpdatePatient : handleAddPatient}
|
||||
isLoading={
|
||||
addPatientMutation.isPending || updatePatientMutation.isPending
|
||||
}
|
||||
isLoading={isLoading}
|
||||
patient={currentPatient}
|
||||
/>
|
||||
|
||||
|
||||
@@ -24,6 +24,14 @@ import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas
|
||||
import { apiRequest, queryClient } from "@/lib/queryClient";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { z } from "zod";
|
||||
import { DeleteConfirmationDialog } from "@/components/ui/deleteDialog";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
|
||||
const PatientSchema = (
|
||||
PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
||||
@@ -64,6 +72,7 @@ export default function PatientsPage() {
|
||||
const { user } = useAuth();
|
||||
const [isAddPatientOpen, setIsAddPatientOpen] = useState(false);
|
||||
const [isViewPatientOpen, setIsViewPatientOpen] = useState(false);
|
||||
const [isDeletePatientOpen, setIsDeletePatientOpen] = useState(false);
|
||||
const [currentPatient, setCurrentPatient] = useState<Patient | undefined>(
|
||||
undefined
|
||||
);
|
||||
@@ -152,12 +161,35 @@ export default function PatientsPage() {
|
||||
},
|
||||
});
|
||||
|
||||
const deletePatientMutation = useMutation({
|
||||
mutationFn: async (id: number) => {
|
||||
const res = await apiRequest("DELETE", `/api/patients/${id}`);
|
||||
return;
|
||||
},
|
||||
onSuccess: () => {
|
||||
setIsDeletePatientOpen(false);
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/patients/"] });
|
||||
toast({
|
||||
title: "Success",
|
||||
description: "Patient deleted successfully!",
|
||||
variant: "default",
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
console.log(error);
|
||||
toast({
|
||||
title: "Error",
|
||||
description: `Failed to delete patient: ${error.message}`,
|
||||
variant: "destructive",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const toggleMobileMenu = () => {
|
||||
setIsMobileMenuOpen(!isMobileMenuOpen);
|
||||
};
|
||||
|
||||
const handleAddPatient = (patient: InsertPatient) => {
|
||||
// Add userId to the patient data
|
||||
if (user) {
|
||||
addPatientMutation.mutate({
|
||||
...patient,
|
||||
@@ -193,6 +225,23 @@ export default function PatientsPage() {
|
||||
setIsViewPatientOpen(true);
|
||||
};
|
||||
|
||||
const handleDeletePatient = (patient: Patient) => {
|
||||
setCurrentPatient(patient);
|
||||
setIsDeletePatientOpen(true);
|
||||
};
|
||||
|
||||
const handleConfirmDeletePatient = async () => {
|
||||
if (currentPatient) {
|
||||
deletePatientMutation.mutate(currentPatient.id);
|
||||
} else {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "No patient selected for deletion.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const isLoading =
|
||||
isLoadingPatients ||
|
||||
addPatientMutation.isPending ||
|
||||
@@ -370,10 +419,178 @@ export default function PatientsPage() {
|
||||
patients={filteredPatients}
|
||||
onEdit={handleEditPatient}
|
||||
onView={handleViewPatient}
|
||||
onDelete={handleDeletePatient}
|
||||
/>
|
||||
|
||||
<DeleteConfirmationDialog
|
||||
isOpen={isDeletePatientOpen}
|
||||
onConfirm={handleConfirmDeletePatient}
|
||||
onCancel={() => setIsDeletePatientOpen(false)}
|
||||
patientName={currentPatient?.name}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* View Patient Modal */}
|
||||
<Dialog open={isViewPatientOpen} onOpenChange={setIsViewPatientOpen}>
|
||||
<DialogContent className="sm:max-w-[600px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Patient Details</DialogTitle>
|
||||
<DialogDescription>
|
||||
Complete information about the patient.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{currentPatient && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="h-16 w-16 rounded-full bg-primary text-white flex items-center justify-center text-xl font-medium">
|
||||
{currentPatient.firstName.charAt(0)}
|
||||
{currentPatient.lastName.charAt(0)}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold">
|
||||
{currentPatient.firstName} {currentPatient.lastName}
|
||||
</h3>
|
||||
<p className="text-gray-500">
|
||||
Patient ID: {currentPatient.id.toString().padStart(4, "0")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 pt-4">
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900">
|
||||
Personal Information
|
||||
</h4>
|
||||
<div className="mt-2 space-y-2">
|
||||
<p>
|
||||
<span className="text-gray-500">Date of Birth:</span>{" "}
|
||||
{new Date(
|
||||
currentPatient.dateOfBirth
|
||||
).toLocaleDateString()}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Gender:</span>{" "}
|
||||
{currentPatient.gender.charAt(0).toUpperCase() +
|
||||
currentPatient.gender.slice(1)}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Status:</span>{" "}
|
||||
<span
|
||||
className={`${
|
||||
currentPatient.status === "active"
|
||||
? "text-green-600"
|
||||
: "text-amber-600"
|
||||
} font-medium`}
|
||||
>
|
||||
{currentPatient.status.charAt(0).toUpperCase() +
|
||||
currentPatient.status.slice(1)}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900">
|
||||
Contact Information
|
||||
</h4>
|
||||
<div className="mt-2 space-y-2">
|
||||
<p>
|
||||
<span className="text-gray-500">Phone:</span>{" "}
|
||||
{currentPatient.phone}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Email:</span>{" "}
|
||||
{currentPatient.email || "N/A"}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Address:</span>{" "}
|
||||
{currentPatient.address ? (
|
||||
<>
|
||||
{currentPatient.address}
|
||||
{currentPatient.city && `, ${currentPatient.city}`}
|
||||
{currentPatient.zipCode &&
|
||||
` ${currentPatient.zipCode}`}
|
||||
</>
|
||||
) : (
|
||||
"N/A"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900">Insurance</h4>
|
||||
<div className="mt-2 space-y-2">
|
||||
<p>
|
||||
<span className="text-gray-500">Provider:</span>{" "}
|
||||
{currentPatient.insuranceProvider
|
||||
? currentPatient.insuranceProvider === "delta"
|
||||
? "Delta Dental"
|
||||
: currentPatient.insuranceProvider === "metlife"
|
||||
? "MetLife"
|
||||
: currentPatient.insuranceProvider === "cigna"
|
||||
? "Cigna"
|
||||
: currentPatient.insuranceProvider === "aetna"
|
||||
? "Aetna"
|
||||
: currentPatient.insuranceProvider
|
||||
: "N/A"}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">ID:</span>{" "}
|
||||
{currentPatient.insuranceId || "N/A"}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Group Number:</span>{" "}
|
||||
{currentPatient.groupNumber || "N/A"}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Policy Holder:</span>{" "}
|
||||
{currentPatient.policyHolder || "Self"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="font-medium text-gray-900">
|
||||
Medical Information
|
||||
</h4>
|
||||
<div className="mt-2 space-y-2">
|
||||
<p>
|
||||
<span className="text-gray-500">Allergies:</span>{" "}
|
||||
{currentPatient.allergies || "None reported"}
|
||||
</p>
|
||||
<p>
|
||||
<span className="text-gray-500">Medical Conditions:</span>{" "}
|
||||
{currentPatient.medicalConditions || "None reported"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end space-x-2 pt-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setIsViewPatientOpen(false)}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setIsViewPatientOpen(false);
|
||||
handleEditPatient(currentPatient);
|
||||
}}
|
||||
>
|
||||
Edit Patient
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
|
||||
{/* Add/Edit Patient Modal */}
|
||||
<AddPatientModal
|
||||
ref={addPatientModalRef}
|
||||
@@ -382,17 +599,6 @@ export default function PatientsPage() {
|
||||
onSubmit={currentPatient ? handleUpdatePatient : handleAddPatient}
|
||||
isLoading={isLoading}
|
||||
patient={currentPatient}
|
||||
// Pass extracted info as a separate prop to avoid triggering edit mode
|
||||
extractedInfo={
|
||||
!currentPatient && extractedInfo
|
||||
? {
|
||||
firstName: extractedInfo.firstName || "",
|
||||
lastName: extractedInfo.lastName || "",
|
||||
dateOfBirth: extractedInfo.dateOfBirth || "",
|
||||
insuranceId: extractedInfo.insuranceId || "",
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { StaffUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
import { z } from "zod";
|
||||
import { apiRequest, queryClient } from "@/lib/queryClient";
|
||||
import { StaffForm } from "@/components/staffs/staff-form";
|
||||
import { DeleteConfirmationDialog } from "@/components/ui/deleteDialog";
|
||||
|
||||
// Correctly infer Staff type from zod schema
|
||||
type Staff = z.infer<typeof StaffUncheckedCreateInputObjectSchema>;
|
||||
@@ -120,6 +121,7 @@ export default function SettingsPage() {
|
||||
return id;
|
||||
},
|
||||
onSuccess: () => {
|
||||
setIsDeleteStaffOpen(false);
|
||||
queryClient.invalidateQueries({ queryKey: ["/api/staffs/"] });
|
||||
toast({
|
||||
title: "Staff Removed",
|
||||
@@ -188,14 +190,28 @@ export default function SettingsPage() {
|
||||
}
|
||||
}, [isAddSuccess, isUpdateSuccess]);
|
||||
|
||||
// Delete staff
|
||||
const handleDeleteStaff = (id: number) => {
|
||||
if (confirm("Are you sure you want to delete this staff member?")) {
|
||||
deleteStaffMutation.mutate(id);
|
||||
const [isDeleteStaffOpen, setIsDeleteStaffOpen] = useState(false);
|
||||
const [currentStaff, setCurrentStaff] = useState<Staff | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
const handleDeleteStaff = (staff: Staff) => {
|
||||
setCurrentStaff(staff);
|
||||
setIsDeleteStaffOpen(true);
|
||||
};
|
||||
|
||||
const handleConfirmDeleteStaff = async () => {
|
||||
if (currentStaff?.id) {
|
||||
deleteStaffMutation.mutate(currentStaff.id);
|
||||
} else {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "No Staff selected for deletion.",
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// View staff handler (just an alert for now)
|
||||
const handleViewStaff = (staff: Staff) =>
|
||||
alert(
|
||||
`Viewing staff member:\n${staff.name} (${staff.email || "No email"})`
|
||||
@@ -227,6 +243,13 @@ export default function SettingsPage() {
|
||||
{(error as Error)?.message || "Failed to load staff data."}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<DeleteConfirmationDialog
|
||||
isOpen={isDeleteStaffOpen}
|
||||
onConfirm={handleConfirmDeleteStaff}
|
||||
onCancel={() => setIsDeleteStaffOpen(false)}
|
||||
patientName={currentStaff?.name}
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user