341 lines
9.5 KiB
JavaScript
341 lines
9.5 KiB
JavaScript
// User Management JavaScript
|
|
|
|
let usersData = [];
|
|
let userModal;
|
|
let passwordModal;
|
|
|
|
const rolePermissions = {
|
|
Cashier: ["View Products", "Process Orders", "View Customers"],
|
|
Accountant: [
|
|
"View Products",
|
|
"View Orders",
|
|
"View Reports",
|
|
"View Financial Data",
|
|
],
|
|
Admin: [
|
|
"Manage Products",
|
|
"Manage Portfolio",
|
|
"Manage Blog",
|
|
"Manage Pages",
|
|
"Manage Users",
|
|
"View Reports",
|
|
],
|
|
MasterAdmin: [
|
|
"Full System Access",
|
|
"Manage Settings",
|
|
"Manage Users",
|
|
"Manage All Content",
|
|
"View Logs",
|
|
"System Configuration",
|
|
],
|
|
};
|
|
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
userModal = new bootstrap.Modal(document.getElementById("userModal"));
|
|
passwordModal = new bootstrap.Modal(document.getElementById("passwordModal"));
|
|
checkAuth().then((authenticated) => {
|
|
if (authenticated) {
|
|
loadUsers();
|
|
}
|
|
});
|
|
});
|
|
|
|
async function loadUsers() {
|
|
try {
|
|
const response = await fetch("/api/admin/users", {
|
|
credentials: "include",
|
|
});
|
|
const data = await response.json();
|
|
if (data.success) {
|
|
usersData = data.users;
|
|
renderUsers(usersData);
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to load users:", error);
|
|
}
|
|
}
|
|
|
|
function renderUsers(users) {
|
|
const tbody = document.getElementById("usersTableBody");
|
|
if (users.length === 0) {
|
|
tbody.innerHTML = `
|
|
<tr><td colspan="8" class="text-center p-4">
|
|
<i class="bi bi-inbox" style="font-size: 3rem; color: #ccc;"></i>
|
|
<p class="mt-3 text-muted">No users found</p>
|
|
<button class="btn btn-primary" onclick="showCreateUser()">
|
|
<i class="bi bi-person-plus"></i> Create First User
|
|
</button>
|
|
</td></tr>`;
|
|
return;
|
|
}
|
|
|
|
tbody.innerHTML = users
|
|
.map(
|
|
(u) => `
|
|
<tr>
|
|
<td>${u.id}</td>
|
|
<td><strong>${escapeHtml(u.name)}</strong></td>
|
|
<td>${escapeHtml(u.email)}</td>
|
|
<td>@${escapeHtml(u.username)}</td>
|
|
<td><span class="role-badge role-${u.role
|
|
.toLowerCase()
|
|
.replace(" ", "-")}">${u.role}</span></td>
|
|
<td><span class="badge ${u.isactive ? "badge-success" : "badge-danger"}">
|
|
${u.isactive ? "Active" : "Disabled"}</span></td>
|
|
<td>${formatDate(u.createdat)}</td>
|
|
<td>
|
|
<button class="btn btn-sm btn-info" onclick="editUser(${
|
|
u.id
|
|
})" title="Edit User">
|
|
<i class="bi bi-pencil"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-warning" onclick="showChangePassword(${
|
|
u.id
|
|
}, '${escapeHtml(u.name)}')" title="Change Password">
|
|
<i class="bi bi-key"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-danger" onclick="deleteUser(${
|
|
u.id
|
|
}, '${escapeHtml(u.name)}')" title="Delete User">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>`
|
|
)
|
|
.join("");
|
|
}
|
|
|
|
function filterUsers() {
|
|
const searchTerm = document.getElementById("searchInput").value.toLowerCase();
|
|
const filtered = usersData.filter(
|
|
(u) =>
|
|
u.name.toLowerCase().includes(searchTerm) ||
|
|
u.email.toLowerCase().includes(searchTerm) ||
|
|
u.username.toLowerCase().includes(searchTerm)
|
|
);
|
|
renderUsers(filtered);
|
|
}
|
|
|
|
function showCreateUser() {
|
|
document.getElementById("modalTitle").textContent = "Create New User";
|
|
document.getElementById("userForm").reset();
|
|
document.getElementById("userId").value = "";
|
|
document.getElementById("userActive").checked = true;
|
|
document.getElementById("userPasswordNeverExpires").checked = false;
|
|
document.getElementById("userRole").value = "Cashier";
|
|
updatePermissionsPreview();
|
|
userModal.show();
|
|
}
|
|
|
|
async function editUser(id) {
|
|
try {
|
|
const response = await fetch(`/api/admin/users/${id}`, {
|
|
credentials: "include",
|
|
});
|
|
const data = await response.json();
|
|
if (data.success) {
|
|
const user = data.user;
|
|
document.getElementById("modalTitle").textContent = "Edit User";
|
|
document.getElementById("userId").value = user.id;
|
|
document.getElementById("userName").value = user.name;
|
|
document.getElementById("userUsername").value = user.username;
|
|
document.getElementById("userEmail").value = user.email;
|
|
document.getElementById("userPassword").value = "";
|
|
document.getElementById("userPasswordConfirm").value = "";
|
|
document.getElementById("userRole").value = user.role;
|
|
document.getElementById("userActive").checked = user.isactive;
|
|
document.getElementById("userPasswordNeverExpires").checked =
|
|
user.passwordneverexpires || false;
|
|
updatePermissionsPreview();
|
|
userModal.show();
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to load user:", error);
|
|
showError("Failed to load user details");
|
|
}
|
|
}
|
|
|
|
async function saveUser() {
|
|
const id = document.getElementById("userId").value;
|
|
const password = document.getElementById("userPassword").value;
|
|
const passwordConfirm = document.getElementById("userPasswordConfirm").value;
|
|
|
|
// Password validation (only for new users or when changing password)
|
|
if (!id || password) {
|
|
if (!password) {
|
|
showError("Password is required for new users");
|
|
return;
|
|
}
|
|
if (password !== passwordConfirm) {
|
|
showError("Passwords do not match");
|
|
return;
|
|
}
|
|
if (password.length < 8) {
|
|
showError("Password must be at least 8 characters long");
|
|
return;
|
|
}
|
|
}
|
|
|
|
const formData = {
|
|
name: document.getElementById("userName").value,
|
|
username: document.getElementById("userUsername").value,
|
|
email: document.getElementById("userEmail").value,
|
|
role: document.getElementById("userRole").value,
|
|
isactive: document.getElementById("userActive").checked,
|
|
passwordneverexpires: document.getElementById("userPasswordNeverExpires")
|
|
.checked,
|
|
};
|
|
|
|
if (password) {
|
|
formData.password = password;
|
|
}
|
|
|
|
if (!formData.name || !formData.username || !formData.email) {
|
|
showError("Please fill in all required fields");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const url = id ? `/api/admin/users/${id}` : "/api/admin/users";
|
|
const method = id ? "PUT" : "POST";
|
|
const response = await fetch(url, {
|
|
method: method,
|
|
headers: { "Content-Type": "application/json" },
|
|
credentials: "include",
|
|
body: JSON.stringify(formData),
|
|
});
|
|
|
|
const data = await response.json();
|
|
if (data.success) {
|
|
showSuccess(
|
|
id ? "User updated successfully" : "User created successfully"
|
|
);
|
|
userModal.hide();
|
|
loadUsers();
|
|
} else {
|
|
showError(data.message || "Failed to save user");
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to save user:", error);
|
|
showError("Failed to save user");
|
|
}
|
|
}
|
|
|
|
function showChangePassword(id, name) {
|
|
document.getElementById("passwordUserId").value = id;
|
|
document.getElementById("passwordUserName").value = name;
|
|
document.getElementById("passwordUserDisplay").textContent = name;
|
|
document.getElementById("passwordForm").reset();
|
|
passwordModal.show();
|
|
}
|
|
|
|
async function changePassword() {
|
|
const id = document.getElementById("passwordUserId").value;
|
|
const newPassword = document.getElementById("newPassword").value;
|
|
const confirmPassword = document.getElementById("confirmNewPassword").value;
|
|
|
|
if (!newPassword || !confirmPassword) {
|
|
showError("Please enter and confirm the new password");
|
|
return;
|
|
}
|
|
|
|
if (newPassword !== confirmPassword) {
|
|
showError("Passwords do not match");
|
|
return;
|
|
}
|
|
|
|
if (newPassword.length < 8) {
|
|
showError("Password must be at least 8 characters long");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`/api/admin/users/${id}/password`, {
|
|
method: "PUT",
|
|
headers: { "Content-Type": "application/json" },
|
|
credentials: "include",
|
|
body: JSON.stringify({ password: newPassword }),
|
|
});
|
|
|
|
const data = await response.json();
|
|
if (data.success) {
|
|
showSuccess("Password changed successfully");
|
|
passwordModal.hide();
|
|
} else {
|
|
showError(data.message || "Failed to change password");
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to change password:", error);
|
|
showError("Failed to change password");
|
|
}
|
|
}
|
|
|
|
async function deleteUser(id, name) {
|
|
if (
|
|
!confirm(
|
|
`Are you sure you want to delete user "${name}"? This action cannot be undone.`
|
|
)
|
|
)
|
|
return;
|
|
|
|
try {
|
|
const response = await fetch(`/api/admin/users/${id}`, {
|
|
method: "DELETE",
|
|
credentials: "include",
|
|
});
|
|
const data = await response.json();
|
|
if (data.success) {
|
|
showSuccess("User deleted successfully");
|
|
loadUsers();
|
|
} else {
|
|
showError(data.message || "Failed to delete user");
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to delete user:", error);
|
|
showError("Failed to delete user");
|
|
}
|
|
}
|
|
|
|
function updatePermissionsPreview() {
|
|
const role = document.getElementById("userRole").value;
|
|
const permissions = rolePermissions[role] || [];
|
|
const container = document.getElementById("permissionsPreview");
|
|
|
|
container.innerHTML = permissions
|
|
.map(
|
|
(perm) => `
|
|
<div class="permission-item active">
|
|
<i class="bi bi-check-circle-fill" style="color: #10b981; margin-right: 8px;"></i>
|
|
<span>${perm}</span>
|
|
</div>
|
|
`
|
|
)
|
|
.join("");
|
|
}
|
|
|
|
function escapeHtml(text) {
|
|
const map = {
|
|
"&": "&",
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'",
|
|
};
|
|
return text.replace(/[&<>"']/g, (m) => map[m]);
|
|
}
|
|
|
|
function formatDate(dateString) {
|
|
return new Date(dateString).toLocaleDateString("en-US", {
|
|
year: "numeric",
|
|
month: "short",
|
|
day: "numeric",
|
|
});
|
|
}
|
|
|
|
function showSuccess(message) {
|
|
alert(message);
|
|
}
|
|
function showError(message) {
|
|
alert("Error: " + message);
|
|
}
|