import React, { useState, useEffect } from 'react'; import { UsersIcon, MagnifyingGlassIcon, UserPlusIcon, TrashIcon, CogIcon, PencilIcon, EnvelopeIcon, KeyIcon, ExclamationTriangleIcon } from '@heroicons/react/24/outline'; import { adminAPI } from '../../services/api'; import LoadingSpinner from '../../components/UI/LoadingSpinner'; import toast from 'react-hot-toast'; const AdminUsers = () => { const [users, setUsers] = useState([]); const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(''); const [roleFilter, setRoleFilter] = useState('all'); const [pagination, setPagination] = useState(null); const [currentPage, setCurrentPage] = useState(1); const [selectedUser, setSelectedUser] = useState(null); const [showRoleModal, setShowRoleModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [showInviteModal, setShowInviteModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [editFormData, setEditFormData] = useState({ firstName: '', lastName: '', email: '', role: '', newPassword: '', confirmPassword: '' }); const fetchUsers = async (page = 1) => { try { setLoading(true); const params = { page, limit: 20, ...(searchTerm && { search: searchTerm }), ...(roleFilter !== 'all' && { role: roleFilter }) }; const response = await adminAPI.getUsers(params); setUsers(response.data.data.users); setPagination(response.data.data.pagination); setCurrentPage(page); } catch (error) { console.error('Failed to fetch users:', error); toast.error('Failed to load users'); } finally { setLoading(false); } }; useEffect(() => { fetchUsers(1); }, [searchTerm, roleFilter]); const handleRoleChange = async (newRole) => { try { await adminAPI.updateUserRole(selectedUser.id, newRole); toast.success(`User role updated to ${newRole}`); setShowRoleModal(false); setSelectedUser(null); fetchUsers(currentPage); } catch (error) { console.error('Failed to update role:', error); toast.error('Failed to update user role'); } }; const handleDeleteUser = async () => { try { await adminAPI.deleteUser(selectedUser.id); toast.success('User deleted successfully'); setShowDeleteModal(false); setSelectedUser(null); fetchUsers(currentPage); } catch (error) { console.error('Failed to delete user:', error); toast.error('Failed to delete user'); } }; const handleEditUser = async (e) => { e.preventDefault(); // Validate password match if password is being changed if (editFormData.newPassword || editFormData.confirmPassword) { if (editFormData.newPassword !== editFormData.confirmPassword) { toast.error('Passwords do not match'); return; } if (editFormData.newPassword.length < 6) { toast.error('Password must be at least 6 characters long'); return; } } try { const updateData = { firstName: editFormData.firstName, lastName: editFormData.lastName, email: editFormData.email, role: editFormData.role, ...(editFormData.newPassword && { password: editFormData.newPassword }) }; await adminAPI.updateUser(selectedUser.id, updateData); toast.success('User updated successfully'); setShowEditModal(false); setSelectedUser(null); setEditFormData({ firstName: '', lastName: '', email: '', role: '', newPassword: '', confirmPassword: '' }); fetchUsers(currentPage); } catch (error) { console.error('Failed to update user:', error); toast.error('Failed to update user'); } }; const formatDate = (dateString) => { return new Date(dateString).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric' }); }; return (
Add, edit, and manage user accounts
| User | Role | Properties | Applications | Joined | Actions |
|---|---|---|---|---|---|
|
{user.firstName} {user.lastName}
{user.email}
|
{user.role} | {user.propertyCount} |
{user.applicationCount}
{user.lastApplication && (
Last: {formatDate(user.lastApplication)}
)}
|
{formatDate(user.createdAt)} |
|
Current role: {selectedUser.role}
Are you sure you want to delete {selectedUser.firstName} {selectedUser.lastName}? This action cannot be undone and will permanently remove all their data.
Feature coming soon: Send email invitations to new users.