Sửa lỗi quản lí users, chỉnh sửa users

This commit is contained in:
2026-06-08 21:30:03 +07:00
parent 6dfc811292
commit fadfb6ba09
7 changed files with 376 additions and 35 deletions
+177 -13
View File
@@ -277,13 +277,13 @@ function checkAuthStatus() {
const avatarInitials = document.getElementById('avatar-initials');
if (token && username) {
authGuest.style.display = 'none'; // Hide login form
if (authGuest) authGuest.style.display = 'none'; // Hide login form
authLoggedIn.style.display = 'block'; // Show welcome message and buttons
avatarInitials.innerText = username.charAt(0).toUpperCase();
// Chỉ hiển thị các NÚT BẤM menu admin trong sidebar
// Hiển thị các nút dành cho admin (Chủ sở hữu/Admin tối cao)
const adminButtons = document.querySelectorAll('.dashboard-tabs .admin-only');
if (role === 'Chủ sở hữu' || role === 'admin') {
if (role === 'admin' || role === 'Chủ sở hữu') {
adminButtons.forEach(btn => btn.style.display = 'block');
} else {
adminButtons.forEach(btn => btn.style.display = 'none');
@@ -344,15 +344,66 @@ async function handleLogin() {
}
}
/**
* Chuyển đổi giữa chế độ Đăng nhập và Đăng ký trong dropdown
*/
window.switchAuthMode = function(mode) {
const loginSection = document.getElementById('login-section');
const registerSection = document.getElementById('register-section');
const loginBtn = document.getElementById('tab-login-btn');
const registerBtn = document.getElementById('tab-register-btn');
if (mode === 'login') {
loginSection.style.display = 'block';
registerSection.style.display = 'none';
loginBtn.classList.add('active');
registerBtn.classList.remove('active');
} else {
loginSection.style.display = 'none';
registerSection.style.display = 'block';
loginBtn.classList.remove('active');
registerBtn.classList.add('active');
}
};
/**
* Handles user registration
*/
async function handleRegister() {
const username = document.getElementById('username-input').value.trim();
const password = document.getElementById('password-input').value.trim();
const errorMsg = document.getElementById('reg-error-msg');
if (errorMsg) errorMsg.style.display = 'none';
if (!username || !password) {
alert('Please fill in both fields');
const fullName = document.getElementById('reg-fullname').value.trim();
const email = document.getElementById('reg-email').value.trim();
const username = document.getElementById('reg-username').value.trim();
const password = document.getElementById('reg-password').value;
const confirm = document.getElementById('reg-confirm').value;
const agree = document.getElementById('reg-agree').checked;
// Kiểm tra các trường trống
if (!fullName || !email || !username || !password || !confirm) {
if (errorMsg) {
errorMsg.innerText = 'Vui lòng điền đầy đủ thông tin';
errorMsg.style.display = 'block';
}
return;
}
// Kiểm tra mật khẩu khớp nhau
if (password !== confirm) {
if (errorMsg) {
errorMsg.innerText = 'Mật khẩu xác nhận không khớp';
errorMsg.style.display = 'block';
}
return;
}
// Kiểm tra đồng ý quy định
if (!agree) {
if (errorMsg) {
errorMsg.innerText = 'Bạn phải đồng ý với quy định của trang';
errorMsg.style.display = 'block';
}
return;
}
@@ -360,15 +411,26 @@ async function handleRegister() {
const response = await fetch(`${API_BASE_URL}/auth/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password, role: 'Thành viên' })
body: JSON.stringify({
fullName,
email,
username,
password,
agreedToRules: agree,
role: 'Thành viên'
})
});
const data = await response.json();
if (!response.ok) throw new Error(data.message || 'Registration failed');
if (!response.ok) throw new Error(data.message || 'Đăng ký thất bại');
showNotification('Registration successful! You can now log in.', 'success');
showNotification('Đăng ký thành công! Bạn có thể đăng nhập ngay bây giờ.', 'success');
switchAuthMode('login'); // Tự động chuyển về tab đăng nhập sau khi thành công
} catch (error) {
showNotification(error.message, 'error');
if (errorMsg) {
errorMsg.innerText = error.message;
errorMsg.style.display = 'block';
}
}
}
@@ -654,7 +716,7 @@ async function loadScenes() {
const ownerId = scene.createdBy?._id || scene.createdBy || scene.owner?._id || scene.owner;
// Phân quyền: Admin hoặc Chủ sở hữu Scene
const isAdmin = userRole === 'Chủ sở hữu' || userRole === 'admin';
const isAdmin = userRole === 'admin' || userRole === 'Chủ sở hữu';
if (isAdmin || (currentUserId && ownerId && ownerId.toString() === currentUserId.toString())) {
handleEditDeleteScene(scene);
} else {
@@ -1312,6 +1374,105 @@ async function loadMyScenes() {
}
}
/**
* Tải danh sách người dùng dành cho Admin tối cao
*/
async function loadAdminUsers() {
const token = localStorage.getItem('jwt');
const container = document.getElementById('admin-users-list');
if (!container) return;
container.innerHTML = '<p>Đang tải danh sách người dùng...</p>';
try {
const res = await fetch(`${API_BASE_URL}/admin/users`, {
headers: { 'Authorization': `Bearer ${token}` }
});
const users = await res.json();
if (!res.ok) throw new Error(users.message);
let html = `
<table class="admin-table">
<thead>
<tr>
<th>Họ tên</th>
<th>Username</th>
<th>Email</th>
<th>Quyền hạn</th>
<th>Reset Password</th>
<th>Thao tác</th>
</tr>
</thead>
<tbody>
`;
users.forEach(user => {
html += `
<tr>
<td><input type="text" id="adm-fn-${user._id}" value="${user.fullName || ''}"></td>
<td><strong>${user.username}</strong></td>
<td><input type="email" id="adm-em-${user._id}" value="${user.email || ''}"></td>
<td>
<select id="adm-role-${user._id}">
<option value="user" ${user.role === 'user' ? 'selected' : ''}>User</option>
<option value="editor" ${user.role === 'editor' ? 'selected' : ''}>Editor</option>
<option value="moderator" ${user.role === 'moderator' ? 'selected' : ''}>Moderator</option>
<option value="admin" ${user.role === 'admin' ? 'selected' : ''}>Admin</option>
</select>
</td>
<td><input type="password" id="adm-pw-${user._id}" placeholder="Mật khẩu mới"></td>
<td>
<button class="edit-btn-small" onclick="updateUserByAdmin('${user._id}')">Lưu</button>
<button class="delete-btn-small" onclick="deleteUserByAdmin('${user._id}')">Xóa</button>
</td>
</tr>
`;
});
html += '</tbody></table>';
container.innerHTML = html;
} catch (e) {
container.innerHTML = `<p style="color:red">Lỗi: ${e.message}</p>`;
}
}
window.updateUserByAdmin = async function(userId) {
const token = localStorage.getItem('jwt');
const payload = {
fullName: document.getElementById(`adm-fn-${userId}`).value,
email: document.getElementById(`adm-em-${userId}`).value,
role: document.getElementById(`adm-role-${userId}`).value,
password: document.getElementById(`adm-pw-${userId}`).value
};
try {
const res = await fetch(`${API_BASE_URL}/admin/users/${userId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify(payload)
});
const data = await res.json();
if (!res.ok) throw new Error(data.message);
showNotification(data.message, 'success');
loadAdminUsers();
} catch (e) { showNotification(e.message, 'error'); }
};
window.deleteUserByAdmin = async function(userId) {
if (!confirm('Xóa vĩnh viễn người dùng này?')) return;
const token = localStorage.getItem('jwt');
try {
const res = await fetch(`${API_BASE_URL}/admin/users/${userId}`, {
method: 'DELETE',
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await res.json();
if (!res.ok) throw new Error(data.message);
showNotification(data.message, 'success');
loadAdminUsers();
} catch (e) { showNotification(e.message, 'error'); }
};
/**
* Tải và hiển thị kho ảnh/media của người dùng
*/
@@ -1373,7 +1534,7 @@ async function loadMyAssets() {
}
// Add delete button and its event listener
if (asset.uploadedBy === currentUserId || (isTrash && userRole === 'Chủ sở hữu')) {
if (asset.uploadedBy === currentUserId || (isTrash && (userRole === 'admin' || userRole === 'Chủ sở hữu'))) {
const deleteButton = document.createElement('button');
deleteButton.className = 'delete-btn-small';
deleteButton.innerText = 'Xóa';
@@ -1764,6 +1925,9 @@ function openDashboardTab(tabName) {
if (tabName === 'media-library') {
loadMyAssets();
}
if (tabName === 'user-management') {
loadAdminUsers();
}
}
// Đánh dấu nút tab được chọn là active