Files
SkyArtShop/website/admin/js/users.js
Local Server 61929a5daf updateweb
2025-12-14 01:54:40 -06:00

353 lines
9.8 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("");
}
async function logout() {
try {
const response = await fetch("/api/admin/logout", {
method: "POST",
credentials: "include",
});
if (response.ok) window.location.href = "/admin/login.html";
} catch (error) {
console.error("Logout failed:", error);
}
}
function escapeHtml(text) {
const map = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': "&quot;",
"'": "&#039;",
};
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);
}