'use client'; import React, { useEffect, useState, useMemo, useRef } from 'react'; import { Users, Plus, Search, Trash2, Edit, Eye, Loader2, X, EyeOff, CheckCircle2, AlertTriangle, UserCheck, ChevronDown, Settings, Filter, FileSpreadsheet, Download, RefreshCw, CheckSquare, Square, Mail, Phone } from 'lucide-react'; import { userService, UserResponse, UserCreate, UserUpdate } from '@/services/api/userService'; import { rolePermissionService } from '@/services/api/rolePermissionService'; import { format } from 'date-fns'; import { toast } from 'sonner'; import { SlideOver } from '@/components/ui/SlideOver'; import { ViewModeToggle } from '@/components/ui/ViewModeToggle'; import { StatsSparklineCard, datesToSparkline, weekOverWeekChange } from '@/components/ui/StatsSparklineCard'; import { CustomSelect } from '@/components/ui/CustomSelect'; import { TablePagination, useClientPagination } from '@/components/ui/TablePagination'; import { PhoneInput } from '@/components/ui/PhoneInput'; import { validatePhone, validateEmail } from '@/lib/validation'; // Master data lookup mapped to seeded backend database IDs const ROLES = [ { id: '01KXRF5VQ1GQ58RDRX45BY9X1D', name: 'Super Admin' }, { id: '01KXRF5VQ2X83NF2950KTMZT45', name: 'Admin' }, { id: '01KXRF5VQ2X83NF2950KTMZT46', name: 'Technician' }, { id: '01KXRF5VQ3QPM1CJZ679R152CQ', name: 'Sales' }, { id: '01KXRF5VQ4Z7YXKKX83VSR532Q', name: 'Customer Support' }, ]; const DEPARTMENTS = [ { id: '01KXRF5VQ5NB1GN907TGZZ3C9Q', name: 'Administration' }, { id: '01KXRF5VQ6D0NJC1RT6422QT0Y', name: 'Technical Repair' }, { id: '01KXRF5VQ6D0NJC1RT6422QT0Z', name: 'Sales & Billing' }, { id: '01KXRF5VQ74CRWS1951WETKC38', name: 'Support Desk' }, ]; const DESIGNATIONS = [ { id: '01KXRF5VQ8GXRR9JEMNW6VS215', name: 'General Administrator' }, { id: '01KXRF5VQ92Q2DA0VED445M6PJ', name: 'Senior Technician' }, { id: '01KXRF5VQ92Q2DA0VED445M6PK', name: 'Junior Technician' }, { id: '01KXRF5VQ92Q2DA0VED445M6PM', name: 'Billing Representative' }, ]; const GENDERS = ['Male', 'Female', 'Other', 'Prefer not to say']; // Highlight match function const highlightMatch = (text: string, query: string) => { if (!query) return text; const parts = text.split(new RegExp(`(${query})`, 'gi')); return ( <> {parts.map((part, index) => part.toLowerCase() === query.toLowerCase() ? ( {part} ) : ( part ) )} ); }; export default function UsersPage() { const [users, setUsers] = useState([]); const [loading, setLoading] = useState(true); const [isSubmitting, setIsSubmitting] = useState(false); // Search and Sort const [search, setSearch] = useState(''); const [sortOption, setSortOption] = useState('recently_added'); // ascending, descending, recently_added // Filter States const [showFilters, setShowFilters] = useState(false); const [filterRole, setFilterRole] = useState(''); const [filterDept, setFilterDept] = useState(''); const [filterStatus, setFilterStatus] = useState('all'); // all, active, inactive const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); const [viewMode, setViewMode] = useState<'table' | 'grid'>('table'); const [draftRole, setDraftRole] = useState(''); const [draftDept, setDraftDept] = useState(''); const [draftStatus, setDraftStatus] = useState('all'); const [draftStartDate, setDraftStartDate] = useState(''); const [draftEndDate, setDraftEndDate] = useState(''); const filterRef = useRef(null); // Row Selection const [selectedIds, setSelectedIds] = useState([]); const [mockSubscriptions, setMockSubscriptions] = useState([ { id: 'SUB-RAZOR-9082', name: 'Premium ERP Support Plan' }, { id: 'SUB-RAZOR-1249', name: 'Standard Technical SLA Plan' }, { id: 'SUB-RAZOR-8821', name: 'Basic Helpdesk SLA Plan' } ]); const [selectedSubId, setSelectedSubId] = useState('SUB-RAZOR-9082'); // Column Visibility const [visibleColumns, setVisibleColumns] = useState>({ index: true, employee: true, roleDept: true, emailPhone: true, designation: true, status: true, verified: true, createdAt: true, actions: true, }); // Modals state const [showAddModal, setShowAddModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [showViewModal, setShowViewModal] = useState(false); const [deleteId, setDeleteId] = useState(null); const [showBulkDeleteModal, setShowBulkDeleteModal] = useState(false); const [isSoftDelete, setIsSoftDelete] = useState(true); // Selected user for View or Edit const [selectedUser, setSelectedUser] = useState(null); // Form states const [addForm, setAddForm] = useState({ first_name: '', last_name: '', display_name: '', email: '', phone: '', password: '', gender: 'Prefer not to say', dob: '', role_id: ROLES[1].id, department_id: DEPARTMENTS[0].id, designation_id: DESIGNATIONS[0].id, manager_id: '', }); const [editForm, setEditForm] = useState({ first_name: '', last_name: '', display_name: '', email: '', phone: '', password: '', gender: 'Prefer not to say', dob: '', role_id: '', department_id: '', designation_id: '', manager_id: '', }); const [showPassword, setShowPassword] = useState(false); const [formErrors, setFormErrors] = useState>({}); const [availableRoles, setAvailableRoles] = useState<{ id: string; name: string }[]>(ROLES); const fetchUsers = async () => { setLoading(true); try { const data = await userService.getAll(0, 100); setUsers(data); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to fetch users'; toast.error(message); } try { const dynRoles = await rolePermissionService.getRoles(); if (dynRoles && dynRoles.length > 0) { setAvailableRoles(dynRoles.map(r => ({ id: r.role_id, name: r.role_name }))); } } catch {} setLoading(false); }; useEffect(() => { fetchUsers(); }, []); useEffect(() => { if (!showFilters) return; const onPointerDown = (event: MouseEvent) => { if (!filterRef.current?.contains(event.target as Node)) { setShowFilters(false); } }; document.addEventListener('mousedown', onPointerDown); return () => document.removeEventListener('mousedown', onPointerDown); }, [showFilters]); const getRoleName = (id: string) => availableRoles.find(r => r.id === id || r.name.toLowerCase() === id.toLowerCase())?.name || id || 'Unknown'; const getDeptName = (id: string) => DEPARTMENTS.find(d => d.id === id)?.name || 'Unknown'; const getDesigName = (id: string) => DESIGNATIONS.find(d => d.id === id)?.name || 'Unknown'; // Validation Form Checks const validateForm = (data: Partial, isEdit = false): boolean => { const errors: Record = {}; if (!data.first_name || data.first_name.trim().length < 2) { errors.first_name = 'First name must be at least 2 characters'; } const emailErr = validateEmail(data.email || '', true); if (emailErr) errors.email = emailErr; const phoneErr = validatePhone(data.phone || '', true); if (phoneErr) errors.phone = phoneErr; if (!isEdit) { const password = data.password || ''; if (password.length < 6) { errors.password = 'Password must be at least 6 characters'; } else if (!/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(password)) { errors.password = 'Password must contain uppercase, lowercase, and a number'; } } if (!data.role_id) errors.role_id = 'Role is required'; if (!data.department_id) errors.department_id = 'Department is required'; if (!data.designation_id) errors.designation_id = 'Designation is required'; setFormErrors(errors); return Object.keys(errors).length === 0; }; // Submit Handlers const handleAddSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!validateForm(addForm)) return; try { setIsSubmitting(true); const payload = { ...addForm }; if (!payload.display_name) payload.display_name = `${payload.first_name}`; payload.last_name = payload.display_name; // Mapped to backend User Name requirements if (!payload.dob) delete payload.dob; if (!payload.manager_id) delete payload.manager_id; await userService.create(payload); toast.success(payload.display_name ? `User "${payload.display_name}" created` : 'User created'); setShowAddModal(false); // Reset form setAddForm({ first_name: '', last_name: '', display_name: '', email: '', phone: '', password: '', gender: 'Prefer not to say', dob: '', role_id: ROLES[1].id, department_id: DEPARTMENTS[0].id, designation_id: DESIGNATIONS[0].id, manager_id: '', }); fetchUsers(); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to create user'; toast.error(message); } finally { setIsSubmitting(false); } }; const handleEditClick = (user: UserResponse) => { setSelectedUser(user); setEditForm({ first_name: user.first_name, last_name: user.last_name, display_name: user.display_name || '', email: user.email, phone: user.phone, password: '', gender: user.gender || 'Prefer not to say', dob: user.dob || '', role_id: user.role_id, department_id: user.department_id, designation_id: user.designation_id, manager_id: user.manager_id || '', }); setFormErrors({}); setShowEditModal(true); }; const handleEditSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!selectedUser) return; if (!validateForm(editForm, true)) return; try { setIsSubmitting(true); const payload: UserUpdate = { first_name: editForm.first_name, last_name: editForm.first_name, // Sync display/last name requirements display_name: editForm.display_name || undefined, email: editForm.email, phone: editForm.phone, gender: editForm.gender, dob: editForm.dob || undefined, role_id: editForm.role_id, department_id: editForm.department_id, designation_id: editForm.designation_id, manager_id: editForm.manager_id || undefined, }; if (editForm.password && editForm.password.trim().length > 0) { payload.password = editForm.password; } await userService.update(selectedUser.user_id, payload); toast.success('User details saved'); setShowEditModal(false); fetchUsers(); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to update user'; toast.error(message); } finally { setIsSubmitting(false); } }; const handleViewClick = (user: UserResponse) => { setSelectedUser(user); setShowViewModal(true); }; const handleDelete = async (userId: string) => { try { await userService.delete(userId); toast.success('User moved to deleted'); setDeleteId(null); fetchUsers(); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to delete user'; toast.error(message); } }; // Bulk deletion const handleBulkDelete = async () => { if (selectedIds.length === 0) return; try { setLoading(true); await Promise.all(selectedIds.map(id => userService.delete(id))); toast.success(`Deleted ${selectedIds.length} ${selectedIds.length === 1 ? 'user' : 'users'}`); setSelectedIds([]); setShowBulkDeleteModal(false); fetchUsers(); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to delete selected users'; toast.error(message); setLoading(false); } }; // Bulk assign mock subscription const handleBulkAssignSubscription = () => { if (selectedIds.length === 0) return; const subName = mockSubscriptions.find(s => s.id === selectedSubId)?.name; toast.success(`Assigned ${selectedIds.length} ${selectedIds.length === 1 ? 'user' : 'users'} to ${subName || 'subscription'}`); setSelectedIds([]); }; // Bulk remove mock subscription const handleBulkRemoveSubscription = () => { if (selectedIds.length === 0) return; const subName = mockSubscriptions.find(s => s.id === selectedSubId)?.name || 'subscription'; toast.success(`Removed ${subName} from ${selectedIds.length} ${selectedIds.length === 1 ? 'user' : 'users'}`); setSelectedIds([]); }; // Toggle selection const handleSelectRow = (id: string) => { setSelectedIds(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id] ); }; const handleSelectAll = (filteredList: UserResponse[]) => { const filteredUserIds = filteredList.map(u => u.user_id); const allSelected = filteredUserIds.every(id => selectedIds.includes(id)); if (allSelected) { setSelectedIds(prev => prev.filter(id => !filteredUserIds.includes(id))); } else { setSelectedIds(prev => Array.from(new Set([...prev, ...filteredUserIds]))); } }; // Client-side Export Methods const handleExportCSV = (selectedOnly = false) => { const listToExport = selectedOnly ? users.filter(u => selectedIds.includes(u.user_id)) : users; if (listToExport.length === 0) { toast.warning(selectedOnly ? 'No selected users to export' : 'No users to export'); return; } const headers = ['S.No', 'Employee Code', 'First Name', 'Last Name', 'Email', 'Phone', 'Role', 'Department', 'Designation', 'Status', 'Verified', 'Created At']; const rows = listToExport.map((u, i) => [ i + 1, u.employee_code || '—', u.first_name, u.last_name, u.email, u.phone, getRoleName(u.role_id), getDeptName(u.department_id), getDesigName(u.designation_id), u.is_active ? 'Active' : 'Inactive', `Email:${u.email_verified ? 'Yes' : 'No'} Phone:${u.phone_verified ? 'Yes' : 'No'}`, format(new Date(u.created_at), 'yyyy-MM-dd') ]); const csvContent = [headers.join(','), ...rows.map(e => e.map(val => `"${val}"`).join(','))].join('\n'); const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.setAttribute('href', url); link.setAttribute('download', `ifixkart_users_${selectedOnly ? 'selected_' : 'all_'}${format(new Date(), 'yyyyMMdd')}.csv`); document.body.appendChild(link); link.click(); document.body.removeChild(link); toast.success(`Downloaded ${listToExport.length} ${listToExport.length === 1 ? 'user' : 'users'} as CSV`); }; const handleExportPDF = (selectedOnly = false) => { const listToExport = selectedOnly ? users.filter(u => selectedIds.includes(u.user_id)) : users; if (listToExport.length === 0) { toast.warning(selectedOnly ? 'No selected users to export' : 'No users to export'); return; } const printWindow = window.open('', '_blank'); if (!printWindow) { toast.error('Allow pop-ups to open the users print preview'); return; } const html = ` iFixKart Staff Directory PDF Export

iFixKart Staff Directory (${listToExport.length} Records)

Exported on: ${format(new Date(), 'yyyy-MM-dd HH:mm:ss')}

${listToExport.map((u, i) => ` `).join('')}
S.No Employee Code Name Email Phone Role & Dept Designation Status
${i + 1} ${u.employee_code || '—'} ${u.first_name} ${u.last_name} ${u.email} ${u.phone} ${getRoleName(u.role_id)} (${getDeptName(u.department_id)}) ${getDesigName(u.designation_id)} ${u.is_active ? 'Active' : 'Inactive'}
`; printWindow.document.write(html); printWindow.document.close(); toast.success(`Print preview opened for ${listToExport.length} ${listToExport.length === 1 ? 'user' : 'users'}`); }; // Filter & Search Logic const filteredUsers = useMemo(() => { return users.filter((u) => { // Search const q = search.toLowerCase(); const searchMatch = !search || ( u.first_name.toLowerCase().includes(q) || u.last_name.toLowerCase().includes(q) || `${u.first_name} ${u.last_name}`.toLowerCase().includes(q) || (u.display_name || '').toLowerCase().includes(q) || u.email.toLowerCase().includes(q) || u.phone.toLowerCase().includes(q) || (u.employee_code || '').toLowerCase().includes(q) || getRoleName(u.role_id).toLowerCase().includes(q) || getDeptName(u.department_id).toLowerCase().includes(q) ); // Dropdown/Accordion Filters const roleMatch = !filterRole || u.role_id === filterRole; const deptMatch = !filterDept || u.department_id === filterDept; const statusMatch = filterStatus === 'all' || (filterStatus === 'active' && u.is_active) || (filterStatus === 'inactive' && !u.is_active); // Date Range Match let dateMatch = true; if (startDate || endDate) { const createDate = new Date(u.created_at); if (startDate) { dateMatch = dateMatch && createDate >= new Date(startDate); } if (endDate) { dateMatch = dateMatch && createDate <= new Date(endDate); } } return searchMatch && roleMatch && deptMatch && statusMatch && dateMatch; }).sort((a, b) => { if (sortOption === 'ascending') { return a.first_name.localeCompare(b.first_name); } if (sortOption === 'descending') { return b.first_name.localeCompare(a.first_name); } // Default: recently added return new Date(b.created_at).getTime() - new Date(a.created_at).getTime(); }); }, [users, search, sortOption, filterRole, filterDept, filterStatus, startDate, endDate]); const pager = useClientPagination(filteredUsers); // Status Metrics const totalCount = users.length; const activeCount = users.filter(u => u.is_active).length; const inactiveCount = users.filter(u => !u.is_active).length; const filtersActive = Boolean(filterRole || filterDept || filterStatus !== 'all' || startDate || endDate); const allUserDates = useMemo(() => users.map((u) => u.created_at), [users]); const activeUserDates = useMemo( () => users.filter((u) => u.is_active).map((u) => u.created_at), [users] ); const inactiveUserDates = useMemo( () => users.filter((u) => !u.is_active).map((u) => u.created_at), [users] ); const dataCardShell = 'crm-radius-section border border-border bg-card shadow-[0_1px_3px_rgba(16,24,40,0.06)] overflow-hidden min-w-0'; const inputClass = 'w-full h-9 px-3 bg-card border border-border crm-radius-control text-[13px] text-foreground focus:outline-none focus:border-primary'; const labelClass = 'block text-[11px] font-semibold text-muted-foreground uppercase mb-1.5'; const primaryButton = 'inline-flex items-center justify-center gap-2 h-9 px-4 crm-radius-control bg-primary hover:bg-primary/90 text-white text-[13px] font-semibold cursor-pointer disabled:opacity-50'; const secondaryButton = 'inline-flex items-center justify-center gap-2 h-9 px-4 crm-radius-control border border-border bg-card text-foreground text-[13px] font-medium hover:bg-muted cursor-pointer disabled:opacity-50'; const renderStatusBadge = (active: boolean) => ( {active ? 'Active' : 'Inactive'} ); return (

Manage Users

{totalCount}
All records
{selectedIds.length > 0 && ( <>
Selected ({selectedIds.length})
)}
setFilterStatus('all')} /> setFilterStatus('active')} /> setFilterStatus('inactive')} />
{selectedIds.length > 0 && (
{selectedIds.length} selected
({ value: sub.id, label: sub.name }))} />
)}
{showFilters && (
({ value: r.id, label: r.name })), ]} />
({ value: d.id, label: d.name })), ]} />
setDraftStartDate(e.target.value)} className="w-1/2 h-9 px-2 crm-radius-control border border-border bg-card text-[12px] text-foreground" /> setDraftEndDate(e.target.value)} className="w-1/2 h-9 px-2 crm-radius-control border border-border bg-card text-[12px] text-foreground" />
)}
setSearch(e.target.value)} className="w-full h-9 pl-8 pr-3 crm-radius-control border border-border bg-card text-[13px] text-foreground placeholder:text-muted-foreground focus:outline-none focus:border-primary transition-colors" />
{Object.keys(visibleColumns).map(colKey => ( ))}
{viewMode === 'grid' ? ( loading ? (
) : filteredUsers.length === 0 ? (
{search ? 'No users match your search query' : 'No users created yet'}
) : (
{pager.items.map((user) => (
{user.first_name.charAt(0).toUpperCase()}{user.last_name.charAt(0).toUpperCase()}

{user.first_name} {user.last_name}

{getRoleName(user.role_id)}

{renderStatusBadge(user.is_active)}

{user.email}

{user.phone || '—'}

{getDeptName(user.department_id)} · {getDesigName(user.designation_id)}

))}
) ) : (
{visibleColumns.index && } {visibleColumns.employee && } {visibleColumns.roleDept && } {visibleColumns.emailPhone && } {visibleColumns.designation && } {visibleColumns.status && } {visibleColumns.verified && } {visibleColumns.createdAt && } {visibleColumns.actions && } {loading ? ( ) : filteredUsers.length === 0 ? ( ) : ( pager.items.map((user, index) => { const isSelected = selectedIds.includes(user.user_id); return ( {visibleColumns.index && ( )} {visibleColumns.employee && ( )} {visibleColumns.roleDept && ( )} {visibleColumns.emailPhone && ( )} {visibleColumns.designation && ( )} {visibleColumns.status && ( )} {visibleColumns.verified && ( )} {visibleColumns.createdAt && ( )} {visibleColumns.actions && ( )} ); }) )}
S.NoEmployeeRole & deptEmail & phoneDesignationStatusVerifiedCreatedActions

Loading users...

{search ? 'No users match your search query' : 'No users created yet'}

{(pager.page - 1) * pager.pageSize + index + 1}
{user.first_name.charAt(0).toUpperCase()}{user.last_name.charAt(0).toUpperCase()}

{highlightMatch(`${user.first_name} ${user.last_name}`, search)}

{user.employee_code || '—'}

{getRoleName(user.role_id)} {getDeptName(user.department_id)} {highlightMatch(user.email, search)} {highlightMatch(user.phone, search)} {getDesigName(user.designation_id)} {renderStatusBadge(user.is_active)}
Email: {user.email_verified ? 'Verified' : 'Pending'} Phone: {user.phone_verified ? 'Verified' : 'Pending'}
{format(new Date(user.created_at), 'yyyy-MM-dd')}
)}
!isSubmitting && setShowAddModal(false)} title="Add user" icon={} >
setAddForm({ ...addForm, first_name: e.target.value })} className={inputClass} /> {formErrors.first_name &&

{formErrors.first_name}

}
setAddForm({ ...addForm, display_name: e.target.value })} className={inputClass} />
setAddForm({ ...addForm, email: e.target.value })} className={inputClass} /> {formErrors.email &&

{formErrors.email}

}
setAddForm({ ...addForm, phone: val })} error={formErrors.phone} />
setAddForm({ ...addForm, password: e.target.value })} className={inputClass} /> {formErrors.password &&

{formErrors.password}

}
setAddForm({ ...addForm, role_id })} aria-label="Role" options={availableRoles.map((r) => ({ value: r.id, label: r.name }))} />
setAddForm({ ...addForm, department_id })} aria-label="Department" options={DEPARTMENTS.map((d) => ({ value: d.id, label: d.name }))} />
setAddForm({ ...addForm, designation_id })} aria-label="Designation" options={DESIGNATIONS.map((d) => ({ value: d.id, label: d.name }))} />
!isSubmitting && setShowEditModal(false)} title="Edit user" icon={} >
setEditForm({ ...editForm, first_name: e.target.value })} className={inputClass} /> {formErrors.first_name &&

{formErrors.first_name}

}
setEditForm({ ...editForm, display_name: e.target.value })} className={inputClass} />
setEditForm({ ...editForm, email: e.target.value })} className={inputClass} /> {formErrors.email &&

{formErrors.email}

}
setEditForm({ ...editForm, phone: val })} error={formErrors.phone} />
setEditForm({ ...editForm, password: e.target.value })} className={`${inputClass} pr-10`} />
{formErrors.password &&

{formErrors.password}

}
setEditForm({ ...editForm, dob: e.target.value })} className={inputClass} />
setEditForm({ ...editForm, role_id })} aria-label="Role" options={availableRoles.map((r) => ({ value: r.id, label: r.name }))} />
setEditForm({ ...editForm, department_id })} aria-label="Department" options={DEPARTMENTS.map((d) => ({ value: d.id, label: d.name }))} />
setEditForm({ ...editForm, designation_id })} aria-label="Designation" options={DESIGNATIONS.map((d) => ({ value: d.id, label: d.name }))} />
setShowViewModal(false)} title="User details" icon={} > {selectedUser && (
{selectedUser.first_name.charAt(0).toUpperCase()}{selectedUser.last_name.charAt(0).toUpperCase()}

{selectedUser.first_name} {selectedUser.last_name}

{selectedUser.display_name && (

Alias: {selectedUser.display_name}

)}

Code: {selectedUser.employee_code || '—'}

Role

{getRoleName(selectedUser.role_id)}

Department

{getDeptName(selectedUser.department_id)}

Designation

{getDesigName(selectedUser.designation_id)}

Status

{renderStatusBadge(selectedUser.is_active)}

Email

{selectedUser.email}

Phone

{selectedUser.phone}

)}
{deleteId && (
setDeleteId(null)} >
e.stopPropagation()} >

Delete user

This will soft-delete the staff profile and disable system access.

)} {showBulkDeleteModal && (
setShowBulkDeleteModal(false)} >
e.stopPropagation()} >

Delete selected users

Delete {selectedIds.length} selected staff profiles?

)}
); }