users.js

14.85 KB
27/04/2025 15:13
JS
users.js
document.addEventListener('DOMContentLoaded', function() {
  // Initialize user management
  initUserManagement();

  // Event listeners
  document.getElementById('userSearch').addEventListener('input', filterUsers);
  document.getElementById('roleFilter').addEventListener('change', filterUsers);
  document.getElementById('statusFilter').addEventListener('change', filterUsers);
  document.getElementById('addUserBtn').addEventListener('click', showAddUserModal);
  document.getElementById('cancelUser').addEventListener('click', hideUserModal);
  document.getElementById('saveUser').addEventListener('click', saveUser);
  document.getElementById('userActivityFilter').addEventListener('change', loadActivityLog);
  document.getElementById('savePassword').addEventListener('click', changePassword);
  document.getElementById('cancelPassword').addEventListener('click', hidePasswordModal);

  // Close modals when clicking on X
  document.querySelectorAll('.close-modal').forEach(button => {
    button.addEventListener('click', function() {
      this.closest('.modal').classList.remove('show');
    });
  });
});

// Global variables
let users = [];
let currentPage = 1;
let totalPages = 1;
let itemsPerPage = 10;

// Initialize user management
async function initUserManagement() {
  try {
    // Check if current user is admin
    const userJson = localStorage.getItem('posUser');
    if (userJson) {
      const currentUser = JSON.parse(userJson);
      if (currentUser.role !== 'admin') {
        // Redirect non-admin users
        window.location.href = `${basePath}/admin/index.html`;
        return;
      }
    }

    // Load users
    await loadUsers();

    // Load initial activity log
    loadActivityLog();
  } catch (error) {
    console.error('Failed to initialize user management:', error);
    showNotification('Error loading user data', 'error');
  }
}

// Load users from API
async function loadUsers() {
  try {
    const response = await apiRequest('users/all');

    if (response.status === 'success') {
      users = response.data;
      renderUsers(users);
      populateUserActivityFilter();
    } else {
      showNotification(response.message || 'Failed to load users', 'error');
    }
  } catch (error) {
    console.error('Error loading users:', error);
    showNotification('Error loading users', 'error');
  }
}

// Render users table
function renderUsers(usersToRender) {
  const tableBody = document.querySelector('#usersTable tbody');
  tableBody.innerHTML = '';

  if (usersToRender.length === 0) {
    const row = document.createElement('tr');
    row.innerHTML = '<td colspan="7" class="text-center">No users found</td>';
    tableBody.appendChild(row);
    return;
  }

  usersToRender.forEach(user => {
    const row = document.createElement('tr');

    // Format last login date
    const lastLogin = user.last_login ? new Date(user.last_login).toLocaleString() : 'Never';

    row.innerHTML = `
      <td>${user.username}</td>
      <td>${user.full_name}</td>
      <td>${user.email}</td>
      <td><span class="badge badge-info">${user.role}</span></td>
      <td>
        <span class="badge ${user.status === 'active' ? 'badge-success' : 'badge-danger'}">
          ${user.status}
        </span>
      </td>
      <td>${lastLogin}</td>
      <td class="actions">
        <button class="btn btn-sm btn-info edit-user" data-id="${user.id}">
          <i class="icon-edit"></i>
        </button>
        <button class="btn btn-sm btn-warning change-password" data-id="${user.id}">
          <i class="icon-password"></i>
        </button>
        <button class="btn btn-sm btn-danger delete-user" data-id="${user.id}">
          <i class="icon-delete"></i>
        </button>
      </td>
    `;

    tableBody.appendChild(row);
  });

  // Add event listeners for action buttons
  document.querySelectorAll('.edit-user').forEach(button => {
    button.addEventListener('click', function() {
      const userId = this.dataset.id;
      editUser(userId);
    });
  });

  document.querySelectorAll('.change-password').forEach(button => {
    button.addEventListener('click', function() {
      const userId = this.dataset.id;
      showPasswordModal(userId);
    });
  });

  document.querySelectorAll('.delete-user').forEach(button => {
    button.addEventListener('click', function() {
      const userId = this.dataset.id;
      deleteUser(userId);
    });
  });
}

// Populate user filter for activity log
function populateUserActivityFilter() {
  const select = document.getElementById('userActivityFilter');

  // Clear existing options (except the first one)
  while (select.options.length > 1) {
    select.remove(1);
  }

  // Add users to the filter
  users.forEach(user => {
    const option = document.createElement('option');
    option.value = user.id;
    option.textContent = `${user.username} (${user.full_name})`;
    select.appendChild(option);
  });
}

// Filter users based on search and filters
function filterUsers() {
  const searchTerm = document.getElementById('userSearch').value.toLowerCase();
  const roleFilter = document.getElementById('roleFilter').value;
  const statusFilter = document.getElementById('statusFilter').value;

  let filtered = [...users];

  // Apply search filter
  if (searchTerm) {
    filtered = filtered.filter(user => {
      return user.username.toLowerCase().includes(searchTerm) ||
        user.full_name.toLowerCase().includes(searchTerm) ||
        user.email.toLowerCase().includes(searchTerm);
    });
  }

  // Apply role filter
  if (roleFilter) {
    filtered = filtered.filter(user => user.role === roleFilter);
  }

  // Apply status filter
  if (statusFilter) {
    filtered = filtered.filter(user => user.status === statusFilter);
  }

  renderUsers(filtered);
}

// Show add user modal
function showAddUserModal() {
  // Reset form
  document.getElementById('userForm').reset();
  document.getElementById('userId').value = '';
  document.getElementById('userModalTitle').textContent = 'Add User';

  // Show password fields and make them required
  const passwordFields = document.querySelectorAll('.password-fields input');
  passwordFields.forEach(field => {
    field.required = true;
    field.disabled = false;
  });
  document.querySelector('.password-fields').style.display = 'flex';
  document.querySelector('.password-fields .form-hint').style.display = 'none';

  // Enable username field
  document.getElementById('username').disabled = false;

  // Set default status to active
  document.getElementById('status').value = 'active';

  // Show modal
  document.getElementById('userModal').classList.add('show');
}

// Show edit user modal
async function editUser(userId) {
  try {
    const response = await apiRequest(`users/user?id=${userId}`);

    if (response.status === 'success') {
      const user = response.data;

      // Fill form fields
      document.getElementById('userId').value = user.id;
      document.getElementById('username').value = user.username;
      document.getElementById('username').disabled = true; // Username cannot be changed
      document.getElementById('email').value = user.email;
      document.getElementById('fullName').value = user.full_name;
      document.getElementById('role').value = user.role;
      document.getElementById('status').value = user.status;

      // Hide password fields
      document.querySelector('.password-fields').style.display = 'none';
      const passwordFields = document.querySelectorAll('.password-fields input');
      passwordFields.forEach(field => {
        field.required = false;
        field.disabled = true;
      });

      // Update modal title
      document.getElementById('userModalTitle').textContent = 'Edit User';

      // Show modal
      document.getElementById('userModal').classList.add('show');
    } else {
      showNotification(response.message || 'Failed to load user details', 'error');
    }
  } catch (error) {
    console.error('Error loading user details:', error);
    showNotification('Error loading user details', 'error');
  }
}

// Hide user modal
function hideUserModal() {
  document.getElementById('userModal').classList.remove('show');
}

// Save user (create or update)
async function saveUser() {
  try {
    const userId = document.getElementById('userId').value;
    const isNewUser = !userId;

    // Validate form
    const form = document.getElementById('userForm');
    if (!form.checkValidity()) {
      form.reportValidity();
      return;
    }

    // Validate passwords match for new users
    if (isNewUser) {
      const password = document.getElementById('password').value;
      const confirmPassword = document.getElementById('confirmPassword').value;

      if (password !== confirmPassword) {
        showNotification('Passwords do not match', 'error');
        return;
      }
    }

    // Gather form data
    const userData = {
      username: document.getElementById('username').value,
      email: document.getElementById('email').value,
      full_name: document.getElementById('fullName').value,
      role: document.getElementById('role').value,
      status: document.getElementById('status').value
    };

    // Add password for new users
    if (isNewUser) {
      userData.password = document.getElementById('password').value;
    }

    let response;

    if (isNewUser) {
      // Create new user
      response = await apiRequest('users', 'POST', userData);
    } else {
      // Update existing user
      response = await apiRequest(`users/user?id=${userId}`, 'PUT', userData);
    }

    if (response.status === 'success') {
      showNotification(isNewUser ? 'User created successfully' : 'User updated successfully', 'success');
      hideUserModal();
      await loadUsers(); // Reload users
    } else {
      showNotification(response.message || 'Failed to save user', 'error');
    }
  } catch (error) {
    console.error('Error saving user:', error);
    showNotification('Error saving user', 'error');
  }
}

// Delete user
async function deleteUser(userId) {
  // Don't allow deletion of self
  const userJson = localStorage.getItem('posUser');
  if (userJson) {
    const currentUser = JSON.parse(userJson);
    if (currentUser.id == userId) {
      showNotification('You cannot delete your own account', 'error');
      return;
    }
  }

  if (confirm('Are you sure you want to delete this user? This action cannot be undone.')) {
    try {
      const response = await apiRequest(`users/user?id=${userId}`, 'DELETE');

      if (response.status === 'success') {
        showNotification('User deleted successfully', 'success');
        await loadUsers(); // Reload users
      } else {
        showNotification(response.message || 'Failed to delete user', 'error');
      }
    } catch (error) {
      console.error('Error deleting user:', error);
      showNotification('Error deleting user', 'error');
    }
  }
}

// Show password change modal
function showPasswordModal(userId) {
  document.getElementById('passwordForm').reset();
  document.getElementById('passwordUserId').value = userId;
  document.getElementById('passwordModal').classList.add('show');
}

// Hide password change modal
function hidePasswordModal() {
  document.getElementById('passwordModal').classList.remove('show');
}

// Change user password
async function changePassword() {
  try {
    const userId = document.getElementById('passwordUserId').value;
    const newPassword = document.getElementById('newPassword').value;
    const confirmNewPassword = document.getElementById('confirmNewPassword').value;

    // Validate form
    const form = document.getElementById('passwordForm');
    if (!form.checkValidity()) {
      form.reportValidity();
      return;
    }

    // Validate passwords match
    if (newPassword !== confirmNewPassword) {
      showNotification('Passwords do not match', 'error');
      return;
    }

    const response = await apiRequest('users/change-password', 'POST', {
      user_id: userId,
      new_password: newPassword
    });

    if (response.status === 'success') {
      showNotification('Password changed successfully', 'success');
      hidePasswordModal();
    } else {
      showNotification(response.message || 'Failed to change password', 'error');
    }
  } catch (error) {
    console.error('Error changing password:', error);
    showNotification('Error changing password', 'error');
  }
}

// Load activity log
async function loadActivityLog() {
  try {
    const userId = document.getElementById('userActivityFilter').value;

    const params = new URLSearchParams({
      page: currentPage,
      limit: itemsPerPage
    });

    if (userId) {
      params.append('user_id', userId);
    }

    const response = await apiRequest(`users/activity-log?${params.toString()}`);

    if (response.status === 'success') {
      renderActivityLog(response.data.logs);
      totalPages = response.data.pagination.pages;
      renderPagination(response.data.pagination);
    } else {
      showNotification(response.message || 'Failed to load activity log', 'error');
    }
  } catch (error) {
    console.error('Error loading activity log:', error);
    showNotification('Error loading activity log', 'error');
  }
}

// Render activity log table
function renderActivityLog(logs) {
  const tableBody = document.querySelector('#activityLogTable tbody');
  tableBody.innerHTML = '';

  if (logs.length === 0) {
    const row = document.createElement('tr');
    row.innerHTML = '<td colspan="5" class="text-center">No activity logs found</td>';
    tableBody.appendChild(row);
    return;
  }

  logs.forEach(log => {
    const row = document.createElement('tr');

    // Format date
    const date = new Date(log.created_at).toLocaleString();

    row.innerHTML = `
      <td>${log.username}</td>
      <td>${log.action}</td>
      <td>${log.description || '-'}</td>
      <td>${log.ip_address}</td>
      <td>${date}</td>
    `;

    tableBody.appendChild(row);
  });
}

// Render pagination
function renderPagination(pagination) {
  const paginationContainer = document.getElementById('activityPagination');
  paginationContainer.innerHTML = '';

  if (pagination.pages <= 1) {
    return;
  }

  // Create pagination elements
  const prevBtn = document.createElement('button');
  prevBtn.classList.add('pagination-btn');
  prevBtn.disabled = pagination.page === 1;
  prevBtn.innerHTML = '<i class="icon-move_left"></i>';
  prevBtn.addEventListener('click', () => changePage(pagination.page - 1));

  const nextBtn = document.createElement('button');
  nextBtn.classList.add('pagination-btn');
  nextBtn.disabled = pagination.page === pagination.pages;
  nextBtn.innerHTML = '<i class="icon-move_right"></i>';
  nextBtn.addEventListener('click', () => changePage(pagination.page + 1));

  const pageInfo = document.createElement('span');
  pageInfo.classList.add('pagination-info');
  pageInfo.textContent = `Page ${pagination.page} of ${pagination.pages}`;

  paginationContainer.appendChild(prevBtn);
  paginationContainer.appendChild(pageInfo);
  paginationContainer.appendChild(nextBtn);
}

// Change activity log page
function changePage(page) {
  currentPage = page;
  loadActivityLog();
}