// User management functionality // Load users async function loadUsers() { if (!config.isConfigured()) { showAlert('Please configure your API settings first.', 'warning'); return; } const container = document.getElementById('usersContainer'); container.innerHTML = '
Loading users...
'; try { const response = await apiClient.getUsers(); // Handle structured response - extract users array from response object const users = response.users || response; displayUsers(users); } catch (error) { handleApiError(error, 'loading users'); container.innerHTML = '
Failed to load users
'; } } // Display users function displayUsers(users) { const container = document.getElementById('usersContainer'); if (!users || users.length === 0) { container.innerHTML = `

No users found

Create your first user to get started!

`; return; } const usersHtml = `
${users.map(user => ` `).join('')}
Name Email Team Role Created Actions
${user.name.charAt(0).toUpperCase()}
${escapeHtml(user.name)}
${escapeHtml(user.email)} Loading... ${user.is_admin ? 'Admin' : 'User'} ${formatDate(user.created_at)}
`; container.innerHTML = usersHtml; // Load team names loadTeamNames(); } // Load team names for display async function loadTeamNames() { try { const response = await apiClient.getTeams(); // Handle structured response - extract teams array from response object const teams = response.teams || response; teams.forEach(team => { const teamBadges = document.querySelectorAll(`#team-${team.id}`); teamBadges.forEach(badge => { badge.textContent = team.name; }); }); } catch (error) { console.error('Failed to load team names:', error); } } // Show create user modal async function showCreateUserModal() { try { const response = await apiClient.getTeams(); // Handle structured response - extract teams array from response object const teams = response.teams || response; const modalBody = `
Minimum 8 characters
Admins can manage teams, users, and system settings
`; const modalFooter = ` `; const modal = createModal('createUserModal', 'Create New User', modalBody, modalFooter); // Handle form submission document.getElementById('createUserForm').addEventListener('submit', (e) => { e.preventDefault(); createUser(); }); modal.show(); // Focus on name field setTimeout(() => document.getElementById('userName').focus(), 100); } catch (error) { handleApiError(error, 'loading teams for user creation'); } } // Create user async function createUser() { const name = document.getElementById('userName').value.trim(); const email = document.getElementById('userEmail').value.trim(); const password = document.getElementById('userPassword').value; const teamId = document.getElementById('userTeam').value; const isAdmin = document.getElementById('userIsAdmin').checked; if (!name || !email || !password || !teamId) { showAlert('All fields are required', 'danger'); return; } if (password.length < 8) { showAlert('Password must be at least 8 characters long', 'danger'); return; } const createButton = document.querySelector('#createUserModal .btn-primary'); setLoadingState(createButton); try { await apiClient.createUser({ name, email, password, team_id: teamId, is_admin: isAdmin }); showAlert('User created successfully!', 'success'); // Close modal and refresh users bootstrap.Modal.getInstance(document.getElementById('createUserModal')).hide(); removeModal('createUserModal'); loadUsers(); } catch (error) { handleApiError(error, 'creating user'); } finally { setLoadingState(createButton, false); } } // View user details async function viewUser(userId) { try { const usersResponse = await apiClient.getUsers(); // Handle structured response - extract users array from response object const users = usersResponse.users || usersResponse; const user = users.find(u => u.id === userId); if (!user) { showAlert('User not found', 'danger'); return; } const teamsResponse = await apiClient.getTeams(); // Handle structured response - extract teams array from response object const teams = teamsResponse.teams || teamsResponse; const userTeam = teams.find(t => t.id === user.team_id); const modalBody = `
${user.name.charAt(0).toUpperCase()}
${escapeHtml(user.name)}

${escapeHtml(user.email)}

${user.is_admin ? 'Administrator' : 'User'}

User Information

Team: ${userTeam ? escapeHtml(userTeam.name) : 'Unknown'}

Created: ${formatDate(user.created_at)}

ID: ${user.id}

Permissions

Admin Access: ${user.is_admin ? 'Yes' : 'No'}

Status: Active

`; const modalFooter = ` `; const modal = createModal('viewUserModal', 'User Details', modalBody, modalFooter); modal.show(); } catch (error) { handleApiError(error, 'loading user details'); } } // Edit user async function editUser(userId) { try { const usersResponse = await apiClient.getUsers(); // Handle structured response - extract users array from response object const users = usersResponse.users || usersResponse; const user = users.find(u => u.id === userId); if (!user) { showAlert('User not found', 'danger'); return; } const teamsResponse = await apiClient.getTeams(); // Handle structured response - extract teams array from response object const teams = teamsResponse.teams || teamsResponse; const modalBody = `
Leave blank to keep current password
`; const modalFooter = ` `; const modal = createModal('editUserModal', 'Edit User', modalBody, modalFooter); // Handle form submission document.getElementById('editUserForm').addEventListener('submit', (e) => { e.preventDefault(); saveUserChanges(userId); }); modal.show(); } catch (error) { handleApiError(error, 'loading user for editing'); } } // Save user changes async function saveUserChanges(userId) { const name = document.getElementById('editUserName').value.trim(); const email = document.getElementById('editUserEmail').value.trim(); const teamId = document.getElementById('editUserTeam').value; const isAdmin = document.getElementById('editUserIsAdmin').checked; const password = document.getElementById('editUserPassword').value; if (!name || !email || !teamId) { showAlert('Name, email, and team are required', 'danger'); return; } const saveButton = document.querySelector('#editUserModal .btn-primary'); setLoadingState(saveButton); try { const updateData = { name, email, team_id: teamId, is_admin: isAdmin }; if (password) { if (password.length < 8) { showAlert('Password must be at least 8 characters long', 'danger'); return; } updateData.password = password; } await apiClient.updateUser(userId, updateData); showAlert('User updated successfully!', 'success'); // Close modal and refresh users bootstrap.Modal.getInstance(document.getElementById('editUserModal')).hide(); removeModal('editUserModal'); loadUsers(); // Close view modal if open const viewModal = document.getElementById('viewUserModal'); if (viewModal) { bootstrap.Modal.getInstance(viewModal)?.hide(); removeModal('viewUserModal'); } } catch (error) { handleApiError(error, 'updating user'); } finally { setLoadingState(saveButton, false); } } // Delete user function deleteUser(userId) { confirmAction('Are you sure you want to delete this user? This action cannot be undone.', async () => { try { await apiClient.deleteUser(userId); showAlert('User deleted successfully!', 'success'); loadUsers(); // Close any open modals const modals = ['viewUserModal', 'editUserModal']; modals.forEach(modalId => { const modalElement = document.getElementById(modalId); if (modalElement) { bootstrap.Modal.getInstance(modalElement)?.hide(); removeModal(modalId); } }); } catch (error) { handleApiError(error, 'deleting user'); } }); } // Add CSS for avatar circles document.addEventListener('DOMContentLoaded', () => { const style = document.createElement('style'); style.textContent = ` .avatar-circle { width: 32px; height: 32px; border-radius: 50%; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 14px; } .avatar-circle-large { width: 80px; height: 80px; border-radius: 50%; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 32px; } `; document.head.appendChild(style); });