import { useState, useEffect, type ReactElement } from "react"; import { useSelector } from "react-redux"; import { PrimaryButton, StatusBadge, ActionDropdown, DataTable, Pagination, FilterDropdown, DeleteConfirmationModal, type Column, } from "@/components/shared"; import { NewDesignationModal, EditDesignationModal, ViewDesignationModal, } from "@/components/shared/DesignationModals"; import { Plus, Search } from "lucide-react"; import { designationService } from "@/services/designation-service"; import type { Designation, CreateDesignationRequest, UpdateDesignationRequest, } from "@/types/designation"; import { showToast } from "@/utils/toast"; import type { RootState } from "@/store/store"; interface DesignationsTableProps { tenantId?: string | null; // If provided, use this tenantId (Super Admin mode) compact?: boolean; // Compact mode for tabs showHeader?: boolean; } const DesignationsTable = ({ tenantId: propsTenantId, compact = false, showHeader = true, }: DesignationsTableProps): ReactElement => { const reduxTenantId = useSelector((state: RootState) => state.auth.tenantId); const effectiveTenantId = propsTenantId || reduxTenantId; const [designations, setDesignations] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); // Pagination state const [currentPage, setCurrentPage] = useState(1); const [limit, setLimit] = useState(compact ? 10 : 5); // Filter state const [activeOnly, setActiveOnly] = useState(false); const [searchQuery, setSearchQuery] = useState(""); const [debouncedSearchQuery, setDebouncedSearchQuery] = useState(""); // Modal states const [isNewModalOpen, setIsNewModalOpen] = useState(false); const [isEditModalOpen, setIsEditModalOpen] = useState(false); const [isViewModalOpen, setIsViewModalOpen] = useState(false); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [selectedDesignation, setSelectedDesignation] = useState(null); const [isActionLoading, setIsActionLoading] = useState(false); const fetchDesignations = async () => { try { setIsLoading(true); setError(null); const response = await designationService.list(effectiveTenantId, { active_only: activeOnly, search: debouncedSearchQuery, }); if (response.success) { setDesignations(response.data); } else { setError("Failed to load designations"); } } catch (err: any) { setError( err?.response?.data?.error?.message || "Failed to load designations", ); } finally { setIsLoading(false); } }; // Debouncing search query useEffect(() => { const timer = setTimeout(() => { setDebouncedSearchQuery(searchQuery); }, 500); return () => clearTimeout(timer); }, [searchQuery]); useEffect(() => { fetchDesignations(); }, [effectiveTenantId, activeOnly, debouncedSearchQuery]); const handleCreate = async (data: CreateDesignationRequest) => { try { setIsActionLoading(true); const response = await designationService.create(data, effectiveTenantId); if (response.success) { showToast.success("Designation created successfully"); setIsNewModalOpen(false); fetchDesignations(); } } catch (err: any) { showToast.error( err?.response?.data?.error?.message || "Failed to create designation", ); } finally { setIsActionLoading(false); } }; const handleUpdate = async (id: string, data: UpdateDesignationRequest) => { try { setIsActionLoading(true); const response = await designationService.update( id, data, effectiveTenantId, ); if (response.success) { showToast.success("Designation updated successfully"); setIsEditModalOpen(false); fetchDesignations(); } } catch (err: any) { showToast.error( err?.response?.data?.error?.message || "Failed to update designation", ); } finally { setIsActionLoading(false); } }; const handleDelete = async () => { if (!selectedDesignation) return; try { setIsActionLoading(true); const response = await designationService.delete( selectedDesignation.id, effectiveTenantId, ); if (response.success) { showToast.success("Designation deleted successfully"); setIsDeleteModalOpen(false); fetchDesignations(); } } catch (err: any) { showToast.error( err?.response?.data?.error?.message || "Failed to delete designation", ); } finally { setIsActionLoading(false); } }; // Client-side pagination logic const totalItems = designations.length; const totalPages = Math.ceil(totalItems / limit); const paginatedData = designations.slice( (currentPage - 1) * limit, currentPage * limit, ); const columns: Column[] = [ { key: "name", label: "Designation Name", render: (desig) => ( {desig.name} ), }, { key: "code", label: "Code", render: (desig) => ( {desig.code} ), }, { key: "level", label: "Level", render: (desig) => ( {desig.level} ), }, { key: "sort_order", label: "Order", render: (desig) => ( {desig.sort_order} ), }, { key: "user_count", label: "Users", render: (desig) => ( {desig.user_count || 0} ), }, { key: "status", label: "Status", render: (desig) => ( {desig.is_active ? "Active" : "Inactive"} ), }, { key: "actions", label: "Actions", align: "right", render: (desig) => (
{ setSelectedDesignation(desig); setIsViewModalOpen(true); }} onEdit={() => { setSelectedDesignation(desig); setIsEditModalOpen(true); }} onDelete={() => { setSelectedDesignation(desig); setIsDeleteModalOpen(true); }} />
), }, ]; return (
{showHeader && (
setSearchQuery(e.target.value)} />
setActiveOnly(value === "active")} />
setIsNewModalOpen(true)} > New Designation
)} desig.id} isLoading={isLoading} error={error} emptyMessage="No designations found" /> {totalItems > 0 && ( { setLimit(newLimit); setCurrentPage(1); }} /> )} setIsNewModalOpen(false)} onSubmit={handleCreate} isLoading={isActionLoading} /> { setIsEditModalOpen(false); setSelectedDesignation(null); }} designation={selectedDesignation} onSubmit={handleUpdate} isLoading={isActionLoading} /> { setIsViewModalOpen(false); setSelectedDesignation(null); }} designation={selectedDesignation} /> { setIsDeleteModalOpen(false); setSelectedDesignation(null); }} onConfirm={handleDelete} title="Delete Designation" message="Are you sure you want to delete this designation? This action cannot be undone." itemName={selectedDesignation?.name || ""} isLoading={isActionLoading} />
); }; export default DesignationsTable;