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 (

Manage Users

Add, edit, and manage user accounts

{/* Search and Filters */}
setSearchTerm(e.target.value)} className="pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 w-full" />
{loading ? (
) : ( <> {/* Users Table */}
{users.map((user) => ( ))}
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)}
{/* Pagination */} {pagination && pagination.totalPages > 1 && (
Showing page {pagination.currentPage} of {pagination.totalPages} ({pagination.totalUsers} total users)
)} )} {/* Role Change Modal */} {showRoleModal && selectedUser && (

Change Role for {selectedUser.firstName} {selectedUser.lastName}

Current role: {selectedUser.role}

{selectedUser.role !== 'user' && ( )} {selectedUser.role !== 'admin' && ( )}
)} {/* Delete Modal */} {showDeleteModal && selectedUser && (

Delete User

Are you sure you want to delete {selectedUser.firstName} {selectedUser.lastName}? This action cannot be undone and will permanently remove all their data.

)} {/* Edit User Modal */} {showEditModal && selectedUser && (

Edit User: {selectedUser.firstName} {selectedUser.lastName}

setEditFormData({ ...editFormData, firstName: e.target.value })} className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" required />
setEditFormData({ ...editFormData, lastName: e.target.value })} className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" required />
setEditFormData({ ...editFormData, email: e.target.value })} className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" required />

Password Reset (Optional)

setEditFormData({ ...editFormData, newPassword: e.target.value })} className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Leave blank to keep current password" />
setEditFormData({ ...editFormData, confirmPassword: e.target.value })} className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Confirm new password" />
)} {/* Invite User Modal */} {showInviteModal && (

Invite User

Feature coming soon: Send email invitations to new users.

)}
); }; export default AdminUsers;