import React, { useState, useEffect } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; import { TopAppBar } from "@/components/layout/top-app-bar"; import { Sidebar } from "@/components/layout/sidebar"; import { StaffTable } from "@/components/staffs/staff-table"; import { useToast } from "@/hooks/use-toast"; import { Card, CardContent } from "@/components/ui/card"; import { StaffUncheckedCreateInputObjectSchema } from "@repo/db/usedSchemas"; import { z } from "zod"; import { apiRequest, queryClient } from "@/lib/queryClient"; import { StaffForm } from "@/components/staffs/staff-form"; import { DeleteConfirmationDialog } from "@/components/ui/deleteDialog"; import { CredentialForm } from "@/components/settings/InsuranceCredForm"; import { CredentialTable } from "@/components/settings/insuranceCredTable"; // Correctly infer Staff type from zod schema type Staff = z.infer; export default function SettingsPage() { const { toast } = useToast(); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); // Modal and editing staff state const [modalOpen, setModalOpen] = useState(false); const [credentialModalOpen, setCredentialModalOpen] = useState(false); const [editingStaff, setEditingStaff] = useState(null); const toggleMobileMenu = () => setIsMobileMenuOpen((prev) => !prev); // Fetch staff data const { data: staff = [], isLoading, isError, error, } = useQuery({ queryKey: ["/api/staffs/"], queryFn: async () => { const res = await apiRequest("GET", "/api/staffs/"); if (!res.ok) { throw new Error("Failed to fetch staff"); } return res.json(); }, staleTime: 1000 * 60 * 5, // 5 minutes cache }); // Add Staff mutation const addStaffMutate = useMutation< Staff, // Return type Error, // Error type Omit // Variables >({ mutationFn: async (newStaff: Omit) => { const res = await apiRequest("POST", "/api/staffs/", newStaff); if (!res.ok) { const errorData = await res.json().catch(() => null); throw new Error(errorData?.message || "Failed to add staff"); } return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/staffs/"] }); toast({ title: "Staff Added", description: "Staff member added successfully.", variant: "default", }); }, onError: (error: any) => { toast({ title: "Error", description: error?.message || "Failed to add staff", variant: "destructive", }); }, }); // Update Staff mutation const updateStaffMutate = useMutation< Staff, Error, { id: number; updatedFields: Partial } >({ mutationFn: async ({ id, updatedFields, }: { id: number; updatedFields: Partial; }) => { const res = await apiRequest("PUT", `/api/staffs/${id}`, updatedFields); if (!res.ok) { const errorData = await res.json().catch(() => null); throw new Error(errorData?.message || "Failed to update staff"); } return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/staffs/"] }); toast({ title: "Staff Updated", description: "Staff member updated successfully.", variant: "default", }); }, onError: (error: any) => { toast({ title: "Error", description: error?.message || "Failed to update staff", variant: "destructive", }); }, }); // Delete Staff mutation const deleteStaffMutation = useMutation({ mutationFn: async (id: number) => { const res = await apiRequest("DELETE", `/api/staffs/${id}`); if (!res.ok) { const errorData = await res.json().catch(() => null); throw new Error(errorData?.message || "Failed to delete staff"); } return id; }, onSuccess: () => { setIsDeleteStaffOpen(false); queryClient.invalidateQueries({ queryKey: ["/api/staffs/"] }); toast({ title: "Staff Removed", description: "Staff member deleted.", variant: "default", }); }, onError: (error: any) => { toast({ title: "Error", description: error?.message || "Failed to delete staff", variant: "destructive", }); }, }); // Extract mutation states for modal control and loading const isAdding = addStaffMutate.status === "pending"; const isAddSuccess = addStaffMutate.status === "success"; const isUpdating = updateStaffMutate.status === "pending"; const isUpdateSuccess = updateStaffMutate.status === "success"; // Open Add modal const openAddStaffModal = () => { setEditingStaff(null); setModalOpen(true); }; // Open Edit modal const openEditStaffModal = (staff: Staff) => { setEditingStaff(staff); setModalOpen(true); }; // Handle form submit for Add or Edit const handleFormSubmit = (formData: Omit) => { if (editingStaff) { // Editing existing staff if (editingStaff.id === undefined) { toast({ title: "Error", description: "Staff ID is missing", variant: "destructive", }); return; } updateStaffMutate.mutate({ id: editingStaff.id, updatedFields: formData, }); } else { addStaffMutate.mutate(formData); } }; const handleModalCancel = () => { setModalOpen(false); }; // Close modal on successful add/update useEffect(() => { if (isAddSuccess || isUpdateSuccess) { setModalOpen(false); } }, [isAddSuccess, isUpdateSuccess]); const [isDeleteStaffOpen, setIsDeleteStaffOpen] = useState(false); const [currentStaff, setCurrentStaff] = useState( 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", }); } }; const handleViewStaff = (staff: Staff) => alert( `Viewing staff member:\n${staff.name} (${staff.email || "No email"})` ); // MANAGE USER const [usernameUser, setUsernameUser] = useState(""); //fetch user const { data: currentUser, isLoading: isUserLoading, isError: isUserError, error: userError, } = useQuery({ queryKey: ["/api/users/"], queryFn: async () => { const res = await apiRequest("GET", "/api/users/"); if (!res.ok) throw new Error("Failed to fetch user"); return res.json(); }, }); // Populate fields after fetch useEffect(() => { if (currentUser) { setUsernameUser(currentUser.username); } }, [currentUser]); //update user mutation const updateUserMutate = useMutation({ mutationFn: async ( updates: Partial<{ username: string; password: string }> ) => { if (!currentUser?.id) throw new Error("User not loaded"); const res = await apiRequest( "PUT", `/api/users/${currentUser.id}`, updates ); if (!res.ok) { const errorData = await res.json().catch(() => null); throw new Error(errorData?.error || "Failed to update user"); } return res.json(); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["/api/users/"] }); toast({ title: "Updated", description: "Your profile has been updated.", variant: "default", }); }, onError: (err: any) => { toast({ title: "Error", description: err?.message || "Failed to update user", variant: "destructive", }); }, }); return (
{isError && (

{(error as Error)?.message || "Failed to load staff data."}

)} setIsDeleteStaffOpen(false)} entityName={currentStaff?.name} />
{/* Modal Overlay */} {modalOpen && (

{editingStaff ? "Edit Staff" : "Add Staff"}

)}

User Settings

{isUserLoading ? (

Loading user...

) : isUserError ? (

{(userError as Error)?.message}

) : (
{ e.preventDefault(); const formData = new FormData(e.currentTarget); const password = formData.get("password")?.toString().trim() || undefined; updateUserMutate.mutate({ username: usernameUser?.trim() || undefined, password: password || undefined, }); }} >
setUsernameUser(e.target.value)} className="mt-1 p-2 border rounded w-full" />

Leave blank to keep current password.

)}
{/* Credential Section */}

Saved Credentials

{credentialModalOpen && currentUser?.id && ( setCredentialModalOpen(false)} /> )}
); }