@@ -512,6 +586,9 @@ document.addEventListener('DOMContentLoaded', function() {
loadWebhookSettings();
loadWebhookQueueStatus();
break;
+ case 'users':
+ loadUsers();
+ break;
case 'audit':
loadAuditLog();
break;
@@ -528,6 +605,177 @@ document.addEventListener('DOMContentLoaded', function() {
break;
}
});
+
+// User Management Functions
+async function loadUsers() {
+ try {
+ const response = await fetch('api.php?action=admin_users_list', {
+ headers: { 'X-CSRF-Token': CSRF_TOKEN }
+ });
+ const data = await response.json();
+
+ if (!data.success) {
+ throw new Error(data.error || 'Failed to load users');
+ }
+
+ const tbody = document.getElementById('usersTableBody');
+ if (data.users.length === 0) {
+ tbody.innerHTML = '
| No users found. Add a user above. |
';
+ return;
+ }
+
+ tbody.innerHTML = data.users.map(user => `
+
+ | ${escapeHtml(user.email)} |
+ ${user.display_name ? escapeHtml(user.display_name) : '-'} |
+
+
+ ${user.role === 'admin' ? 'Admin' : 'Staff'}
+
+ |
+
+
+ ${user.active == 1 ? 'Active' : 'Inactive'}
+
+ |
+ ${formatDate(user.created_at)} |
+
+
+
+
+
+ |
+
+ `).join('');
+ } catch (error) {
+ console.error('Error loading users:', error);
+ showNotification('Failed to load users: ' + error.message, 'error');
+ }
+}
+
+async function addUser() {
+ const email = document.getElementById('newUserEmail').value.trim();
+ const displayName = document.getElementById('newUserDisplayName').value.trim();
+ const role = document.getElementById('newUserRole').value;
+
+ if (!email) {
+ showNotification('Please enter an email address', 'error');
+ return;
+ }
+
+ try {
+ const response = await fetch('api.php?action=admin_user_save', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRF-Token': CSRF_TOKEN
+ },
+ body: JSON.stringify({
+ email: email,
+ display_name: displayName || null,
+ role: role
+ })
+ });
+
+ const data = await response.json();
+
+ if (!data.success) {
+ throw new Error(data.error || 'Failed to add user');
+ }
+
+ showNotification('User added successfully', 'success');
+ document.getElementById('newUserEmail').value = '';
+ document.getElementById('newUserDisplayName').value = '';
+ document.getElementById('newUserRole').value = 'staff';
+ loadUsers();
+ } catch (error) {
+ console.error('Error adding user:', error);
+ showNotification('Failed to add user: ' + error.message, 'error');
+ }
+}
+
+async function toggleUser(userId) {
+ try {
+ const response = await fetch('api.php?action=admin_user_toggle', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRF-Token': CSRF_TOKEN
+ },
+ body: JSON.stringify({ id: userId })
+ });
+
+ const data = await response.json();
+
+ if (!data.success) {
+ throw new Error(data.error || 'Failed to toggle user status');
+ }
+
+ showNotification('User status updated', 'success');
+ loadUsers();
+ } catch (error) {
+ console.error('Error toggling user:', error);
+ showNotification('Failed to toggle user: ' + error.message, 'error');
+ }
+}
+
+async function deleteUser(userId, email) {
+ if (!confirm(`Are you sure you want to delete the user "${email}"? This action cannot be undone.`)) {
+ return;
+ }
+
+ try {
+ const response = await fetch('api.php?action=admin_user_delete', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-CSRF-Token': CSRF_TOKEN
+ },
+ body: JSON.stringify({ id: userId })
+ });
+
+ const data = await response.json();
+
+ if (!data.success) {
+ throw new Error(data.error || 'Failed to delete user');
+ }
+
+ showNotification('User deleted successfully', 'success');
+ loadUsers();
+ } catch (error) {
+ console.error('Error deleting user:', error);
+ showNotification('Failed to delete user: ' + error.message, 'error');
+ }
+}
+
+function escapeHtml(text) {
+ if (!text) return '';
+ const div = document.createElement('div');
+ div.textContent = text;
+ return div.innerHTML;
+}
+
+function formatDate(dateStr) {
+ if (!dateStr) return '-';
+ const date = new Date(dateStr);
+ return date.toLocaleDateString('en-GB', {
+ day: '2-digit',
+ month: 'short',
+ year: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit'
+ });
+}