From ba21262854f27051309d75cb92489be4c89ffe60 Mon Sep 17 00:00:00 2001 From: James Pattinson Date: Mon, 10 Nov 2025 19:35:37 +0000 Subject: [PATCH] User search and edit --- frontend/src/pages/Dashboard.tsx | 355 ++++++++++++++++++++- frontend/src/services/membershipService.ts | 6 +- 2 files changed, 354 insertions(+), 7 deletions(-) diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 5627703..6f20761 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -16,6 +16,11 @@ const Dashboard: React.FC = () => { const [loading, setLoading] = useState(true); const [showMembershipSetup, setShowMembershipSetup] = useState(false); const [showProfileEdit, setShowProfileEdit] = useState(false); + const [searchTerm, setSearchTerm] = useState(''); + const [selectedUser, setSelectedUser] = useState(null); + const [showUserDetails, setShowUserDetails] = useState(false); + const [isEditingUser, setIsEditingUser] = useState(false); + const [editFormData, setEditFormData] = useState>({}); useEffect(() => { if (!authService.isAuthenticated()) { @@ -130,6 +135,76 @@ const Dashboard: React.FC = () => { } }; + const filteredUsers = allUsers.filter(user => { + const fullName = `${user.first_name} ${user.last_name}`.toLowerCase(); + const email = user.email.toLowerCase(); + const search = searchTerm.toLowerCase(); + return fullName.includes(search) || email.includes(search); + }); + + const handleUserClick = (user: User) => { + setSelectedUser(user); + setEditFormData({ + first_name: user.first_name, + last_name: user.last_name, + email: user.email, + phone: user.phone || '', + address: user.address || '' + }); + setShowUserDetails(true); + setIsEditingUser(false); + }; + + const handleCloseUserDetails = () => { + setSelectedUser(null); + setShowUserDetails(false); + setIsEditingUser(false); + setEditFormData({}); + }; + + const handleEditUser = () => { + setIsEditingUser(true); + }; + + const handleCancelEdit = () => { + setIsEditingUser(false); + if (selectedUser) { + setEditFormData({ + first_name: selectedUser.first_name, + last_name: selectedUser.last_name, + email: selectedUser.email, + phone: selectedUser.phone || '', + address: selectedUser.address || '' + }); + } + }; + + const handleSaveUser = async () => { + if (!selectedUser) return; + + try { + await userService.updateUser(selectedUser.id, editFormData); + // Refresh data + await loadData(); + setIsEditingUser(false); + // Update selected user with new data + const updatedUser = allUsers.find(u => u.id === selectedUser.id); + if (updatedUser) { + setSelectedUser(updatedUser); + } + } catch (error) { + console.error('Failed to update user:', error); + alert('Failed to update user. Please try again.'); + } + }; + + const handleFormChange = (field: keyof User, value: string) => { + setEditFormData(prev => ({ + ...prev, + [field]: value + })); + }; + const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString('en-GB', { day: 'numeric', @@ -345,6 +420,23 @@ const Dashboard: React.FC = () => {

User Management

+ {/* Search Input */} +
+ setSearchTerm(e.target.value)} + style={{ + width: '100%', + padding: '8px 12px', + border: '1px solid #ddd', + borderRadius: '4px', + fontSize: '14px' + }} + /> +
+ @@ -357,8 +449,12 @@ const Dashboard: React.FC = () => { - {allUsers.map(u => ( - + {filteredUsers.map(u => ( + handleUserClick(u)} + >
{u.first_name} {u.last_name} {u.email} @@ -384,7 +480,10 @@ const Dashboard: React.FC = () => { {u.role === 'member' && ( + )} + + + + + {/* User Profile */} +
+

Profile Information

+ {isEditingUser ? ( +
+
+ + handleFormChange('first_name', e.target.value)} + style={{ + padding: '6px 8px', + border: '1px solid #ddd', + borderRadius: '4px', + fontSize: '14px' + }} + /> +
+
+ + handleFormChange('last_name', e.target.value)} + style={{ + padding: '6px 8px', + border: '1px solid #ddd', + borderRadius: '4px', + fontSize: '14px' + }} + /> +
+
+ + handleFormChange('email', e.target.value)} + style={{ + padding: '6px 8px', + border: '1px solid #ddd', + borderRadius: '4px', + fontSize: '14px' + }} + /> +
+
+ + handleFormChange('phone', e.target.value)} + style={{ + padding: '6px 8px', + border: '1px solid #ddd', + borderRadius: '4px', + fontSize: '14px' + }} + /> +
+
+ +