import { useState, useEffect } from 'react'; import type { ReactElement } from 'react'; import { Layout } from '@/components/layout/Layout'; import { PrimaryButton, StatusBadge, ActionDropdown, NewUserModal, ViewUserModal, EditUserModal, DeleteConfirmationModal, DataTable, Pagination, FilterDropdown, type Column, } from '@/components/shared'; import { Plus, Download, ArrowUpDown } from 'lucide-react'; import { userService } from '@/services/user-service'; import type { User } from '@/types/user'; import { showToast } from '@/utils/toast'; // Helper function to get user initials const getUserInitials = (firstName: string, lastName: string): string => { return `${firstName[0]}${lastName[0]}`.toUpperCase(); }; // Helper function to format date const formatDate = (dateString: string): string => { const date = new Date(dateString); return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); }; // Helper function to get status badge variant const getStatusVariant = (status: string): 'success' | 'failure' | 'process' => { switch (status.toLowerCase()) { case 'active': return 'success'; case 'pending_verification': return 'process'; case 'inactive': return 'failure'; case 'deleted': return 'failure'; case 'suspended': return 'process'; default: return 'success'; } }; const Users = (): ReactElement => { const [users, setUsers] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [isCreating, setIsCreating] = useState(false); // Pagination state const [currentPage, setCurrentPage] = useState(1); const [limit, setLimit] = useState(5); const [pagination, setPagination] = useState<{ page: number; limit: number; total: number; totalPages: number; hasMore: boolean; }>({ page: 1, limit: 5, total: 0, totalPages: 1, hasMore: false, }); // Filter state const [statusFilter, setStatusFilter] = useState(null); const [orderBy, setOrderBy] = useState(null); // View, Edit, Delete modals const [viewModalOpen, setViewModalOpen] = useState(false); const [editModalOpen, setEditModalOpen] = useState(false); const [deleteModalOpen, setDeleteModalOpen] = useState(false); const [selectedUserId, setSelectedUserId] = useState(null); const [selectedUserName, setSelectedUserName] = useState(''); const [isUpdating, setIsUpdating] = useState(false); const [isDeleting, setIsDeleting] = useState(false); const fetchUsers = async ( page: number, itemsPerPage: number, status: string | null = null, sortBy: string[] | null = null ): Promise => { try { setIsLoading(true); setError(null); const response = await userService.getAll(page, itemsPerPage, status, sortBy); if (response.success) { setUsers(response.data); setPagination(response.pagination); } else { setError('Failed to load users'); } } catch (err: any) { setError(err?.response?.data?.error?.message || 'Failed to load users'); } finally { setIsLoading(false); } }; useEffect(() => { fetchUsers(currentPage, limit, statusFilter, orderBy); }, [currentPage, limit, statusFilter, orderBy]); const handleCreateUser = async (data: { email: string; password: string; first_name: string; last_name: string; status: 'active' | 'suspended' | 'deleted'; auth_provider: 'local'; role_id: string; }): Promise => { try { setIsCreating(true); const response = await userService.create(data); const message = response.message || `User created successfully`; const description = response.message ? undefined : `${data.first_name} ${data.last_name} has been added`; showToast.success(message, description); setIsModalOpen(false); await fetchUsers(currentPage, limit, statusFilter, orderBy); } catch (err: any) { throw err; } finally { setIsCreating(false); } }; // View user handler const handleViewUser = (userId: string): void => { setSelectedUserId(userId); setViewModalOpen(true); }; // Edit user handler const handleEditUser = (userId: string, userName: string): void => { setSelectedUserId(userId); setSelectedUserName(userName); setEditModalOpen(true); }; // Update user handler const handleUpdateUser = async ( id: string, data: { email: string; first_name: string; last_name: string; status: 'active' | 'suspended' | 'deleted'; tenant_id: string; role_id: string; } ): Promise => { try { setIsUpdating(true); const response = await userService.update(id, data); const message = response.message || `User updated successfully`; const description = response.message ? undefined : `${data.first_name} ${data.last_name} has been updated`; showToast.success(message, description); setEditModalOpen(false); setSelectedUserId(null); await fetchUsers(currentPage, limit, statusFilter, orderBy); } catch (err: any) { throw err; } finally { setIsUpdating(false); } }; // Delete user handler const handleDeleteUser = (userId: string, userName: string): void => { setSelectedUserId(userId); setSelectedUserName(userName); setDeleteModalOpen(true); }; // Confirm delete handler const handleConfirmDelete = async (): Promise => { if (!selectedUserId) return; try { setIsDeleting(true); await userService.delete(selectedUserId); setDeleteModalOpen(false); setSelectedUserId(null); setSelectedUserName(''); await fetchUsers(currentPage, limit, statusFilter, orderBy); } catch (err: any) { throw err; } finally { setIsDeleting(false); } }; // Load user for view/edit const loadUser = async (id: string): Promise => { const response = await userService.getById(id); return response.data; }; // Define table columns const columns: Column[] = [ { key: 'name', label: 'User Name', render: (user) => (
{getUserInitials(user.first_name, user.last_name)}
{user.first_name} {user.last_name}
), mobileLabel: 'Name', }, { key: 'email', label: 'Email', render: (user) => {user.email}, }, { key: 'status', label: 'Status', render: (user) => ( {user.status} ), }, { key: 'auth_provider', label: 'Auth Provider', render: (user) => ( {user.auth_provider} ), }, { key: 'created_at', label: 'Joined Date', render: (user) => ( {formatDate(user.created_at)} ), mobileLabel: 'Joined', }, { key: 'actions', label: 'Actions', align: 'right', render: (user) => (
handleViewUser(user.id)} onEdit={() => handleEditUser(user.id, `${user.first_name} ${user.last_name}`)} onDelete={() => handleDeleteUser(user.id, `${user.first_name} ${user.last_name}`)} />
), }, ]; // Mobile card renderer const mobileCardRenderer = (user: User) => (
{getUserInitials(user.first_name, user.last_name)}

{user.first_name} {user.last_name}

{user.email}

handleViewUser(user.id)} onEdit={() => handleEditUser(user.id, `${user.first_name} ${user.last_name}`)} onDelete={() => handleDeleteUser(user.id, `${user.first_name} ${user.last_name}`)} />
Status:
{user.status}
Auth Provider:

{user.auth_provider}

Joined:

{formatDate(user.created_at)}

); return ( {/* Table Container */}
{/* Table Header with Filters */}
{/* Filters */}
{/* Status Filter */} { setStatusFilter(value as string | null); setCurrentPage(1); // Reset to first page when filter changes }} placeholder="All" /> {/* Sort Filter */} { setOrderBy(value as string[] | null); setCurrentPage(1); // Reset to first page when sort changes }} placeholder="Default" showIcon icon={} />
{/* Actions */}
{/* Export Button */} {/* New User Button */} setIsModalOpen(true)} > New User
{/* Data Table */} user.id} mobileCardRenderer={mobileCardRenderer} emptyMessage="No users found" isLoading={isLoading} error={error} /> {/* Table Footer with Pagination */} {pagination.total > 0 && ( { setCurrentPage(page); }} onLimitChange={(newLimit: number) => { setLimit(newLimit); setCurrentPage(1); // Reset to first page when limit changes }} /> )}
{/* New User Modal */} setIsModalOpen(false)} onSubmit={handleCreateUser} isLoading={isCreating} /> {/* View User Modal */} { setViewModalOpen(false); setSelectedUserId(null); }} userId={selectedUserId} onLoadUser={loadUser} /> {/* Edit User Modal */} { setEditModalOpen(false); setSelectedUserId(null); setSelectedUserName(''); }} userId={selectedUserId} onLoadUser={loadUser} onSubmit={handleUpdateUser} isLoading={isUpdating} /> {/* Delete Confirmation Modal */} { setDeleteModalOpen(false); setSelectedUserId(null); setSelectedUserName(''); }} onConfirm={handleConfirmDelete} title="Delete User" message="Are you sure you want to delete this user" itemName={selectedUserName} isLoading={isDeleting} />
); }; export default Users;