feat: CRUD user added

This commit is contained in:
Angie
2025-07-25 01:24:14 +02:00
parent dd53d10b38
commit c659ca9574
2 changed files with 213 additions and 73 deletions

View File

@@ -135,6 +135,8 @@ async function getAllUsers() {
}
}
let usersList = [];
async function loadUsers() {
const tbody = document.getElementById("usersTableBody");
tbody.innerHTML = "";
@@ -149,6 +151,7 @@ async function loadUsers() {
}
const users = result.users;
usersList = users;
users.forEach((user) => {
const userStores =
@@ -194,3 +197,143 @@ async function loadUsers() {
showNotification("Нет пользователей для отображения", "info");
}
}
//add user
async function createUser(userData) {
const token = localStorage.getItem("token");
try {
const response = await fetch(`${API_BASE_URL}/users`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(userData),
});
const data = await response.json();
if (response.ok) {
return { success: true, ...data };
} else {
return {
success: false,
error:
data.error ||
(data.errors && data.errors[0]?.msg) ||
"Ошибка создания пользователя",
};
}
} catch {
return { success: false, error: "Нет соединения с сервером" };
}
}
//edit user
async function updateUser(userId, userData) {
const token = localStorage.getItem("token");
try {
const response = await fetch(`${API_BASE_URL}/users/${userId}`, {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(userData),
});
const data = await response.json();
if (response.ok) {
return { success: true };
} else {
return {
success: false,
error:
data.error ||
(data.errors && data.errors[0]?.msg) ||
"Ошибка обновления пользователя",
};
}
} catch {
return { success: false, error: "Нет соединения с сервером" };
}
}
// 1. Create modal on-demand if missing
function ensureConfirmModal() {
if (document.getElementById("confirmModal")) return;
const modal = document.createElement("div");
modal.id = "confirmModal";
modal.className =
"hidden fixed inset-0 z-50 bg-black bg-opacity-30 flex items-center justify-center";
modal.innerHTML = `
<div class="bg-white rounded-lg shadow-lg p-8 max-w-sm w-full relative">
<div id="confirmModalText" class="text-lg text-gray-700 mb-6"></div>
<div class="flex justify-end space-x-4">
<button id="confirmModalOk" class="px-5 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700">Удалить</button>
<button id="confirmModalCancel" class="px-5 py-2 bg-gray-300 text-gray-700 rounded-lg hover:bg-gray-400">Отмена</button>
</div>
</div>
`;
document.body.appendChild(modal);
}
// 2. Show confirm modal
function showConfirmModal(message, onConfirm) {
ensureConfirmModal();
const modal = document.getElementById("confirmModal");
const text = document.getElementById("confirmModalText");
const okBtn = document.getElementById("confirmModalOk");
const cancelBtn = document.getElementById("confirmModalCancel");
text.textContent = message;
modal.classList.remove("hidden");
function cleanup() {
modal.classList.add("hidden");
okBtn.removeEventListener("click", okHandler);
cancelBtn.removeEventListener("click", cancelHandler);
}
function okHandler() {
cleanup();
onConfirm();
}
function cancelHandler() {
cleanup();
}
okBtn.addEventListener("click", okHandler);
cancelBtn.addEventListener("click", cancelHandler);
}
// 3. API call to delete user
async function apiDeleteUser(userId) {
const token = localStorage.getItem("token");
try {
const response = await fetch(`${API_BASE_URL}/users/${userId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
});
const data = await response.json();
if (response.ok) {
showNotification("Пользователь удален!");
loadUsers();
updateDashboard();
} else {
showNotification(data.error || "Ошибка удаления пользователя", "error");
}
} catch {
showNotification("Нет соединения с сервером", "error");
}
}
// 4. UI trigger: delete user with modal
function deleteUser(userId) {
showConfirmModal("Вы уверены, что хотите удалить этого пользователя?", () =>
apiDeleteUser(userId)
);
}

View File

@@ -135,6 +135,7 @@ generateTestData();
function showNotification(message, type = "success") {
const notification = document.getElementById("notification");
const notificationText = document.getElementById("notificationText");
if (!notification || !notificationText) return;
notificationText.textContent = message;
notification.className = `fixed top-4 right-4 z-50 animate-fade-in`;
@@ -1445,45 +1446,39 @@ document.addEventListener("DOMContentLoaded", function () {
// Редактирование пользователя
function editUser(userId) {
editingUserId = userId;
showUserEditModal();
const user = usersList.find((u) => u.id === userId);
showUserEditModal(user);
}
// Показ модального окна редактирования пользователя
function showUserEditModal() {
function showUserEditModal(user) {
const modal = document.getElementById("userEditModal");
const title = document.getElementById("userModalTitle");
const form = document.getElementById("userEditForm");
if (editingUserId) {
const user = database.users.find((u) => u.id === editingUserId);
title.textContent = "Редактирование пользователя";
document.getElementById("userLogin").value = user.username;
document.getElementById("userPassword").value = "";
document.getElementById("userRole").value = user.role;
} else {
title.textContent = "Добавление пользователя";
form.reset();
}
// If editingUserId, it's an edit; else, it's add
title.textContent = editingUserId
? "Редактирование пользователя"
: "Добавление пользователя";
document.getElementById("userLogin").value = (user && user.username) || "";
document.getElementById("userPassword").value = "";
document.getElementById("userRole").value = (user && user.role) || "employee";
// Загрузка чекбоксов магазинов
const storesContainer = document.getElementById("userStoresAccess");
storesContainer.innerHTML = "";
database.stores.forEach((store) => {
const isChecked = editingUserId
? database.users
.find((u) => u.id === editingUserId)
.stores.includes(store.id)
: false;
const isChecked = user && user.stores && user.stores.includes(store.id);
const checkbox = document.createElement("label");
checkbox.className = "flex items-center";
checkbox.innerHTML = `
<input type="checkbox" value="${store.id}" ${
<input type="checkbox" value="${store.id}" ${
isChecked ? "checked" : ""
} class="mr-2">
<span>${store.name}</span>
`;
<span>${store.name}</span>
`;
storesContainer.appendChild(checkbox);
});
@@ -1506,78 +1501,80 @@ document.addEventListener("DOMContentLoaded", function () {
}
});
function saveUser() {
const login = document.getElementById("userLogin").value;
//save user for create and update
async function saveUser() {
const login = document.getElementById("userLogin").value.trim();
const password = document.getElementById("userPassword").value;
const role = document.getElementById("userRole").value;
const selectedStores = Array.from(
document.querySelectorAll(
'#userStoresAccess input[type="checkbox"]:checked'
)
).map((cb) => parseInt(cb.value));
if (!login) {
showNotification("Заполните логин!", "error");
return;
}
// Получение выбранных магазинов
const selectedStores = [];
document
.querySelectorAll('#userStoresAccess input[type="checkbox"]:checked')
.forEach((cb) => {
selectedStores.push(parseInt(cb.value));
});
// Always build userData
const userData = {
username: login,
role: role,
storeIds: selectedStores,
};
if (password) userData.password = password;
if (editingUserId) {
// Редактирование
const userIndex = database.users.findIndex((u) => u.id === editingUserId);
database.users[userIndex].username = login;
if (password) {
database.users[userIndex].password = password;
}
database.users[userIndex].role = role;
database.users[userIndex].stores = selectedStores;
showNotification("Пользователь обновлен!");
} else {
// Добавление
// Determine CREATE or EDIT
let result;
if (!editingUserId) {
if (!password) {
showNotification("Укажите пароль для нового пользователя!", "error");
return;
}
const newId = Math.max(...database.users.map((u) => u.id)) + 1;
database.users.push({
id: newId,
username: login,
password: password,
role: role,
stores: selectedStores,
});
showNotification("Пользователь добавлен!");
// CREATE
result = await createUser(userData);
if (result.success) {
showNotification("Пользователь добавлен!");
}
} else {
// EDIT
result = await updateUser(editingUserId, userData);
if (result.success) {
showNotification("Пользователь обновлен!");
}
editingUserId = null;
}
hideModal("userEditModal");
loadUsers();
updateDashboard();
// After save: UI update or error
if (result && result.success) {
hideModal("userEditModal");
loadUsers();
updateDashboard();
} else if (result) {
showNotification(result.error || "Ошибка операции", "error");
}
}
// Удаление пользователя
function deleteUser(userId) {
const user = database.users.find((u) => u.id === userId);
const userReports = database.reports.filter((r) => r.userId === userId);
// function deleteUser(userId) {
// const user = database.users.find((u) => u.id === userId);
// const userReports = database.reports.filter((r) => r.userId === userId);
let message = `Вы уверены, что хотите удалить пользователя "${user.username}"?`;
if (userReports.length > 0) {
message += `\n\nВнимание! У этого пользователя есть ${userReports.length} связанных отчетов. Они также будут удалены.`;
}
// let message = `Вы уверены, что хотите удалить пользователя "${user.username}"?`;
// if (userReports.length > 0) {
// message += `\n\nВнимание! У этого пользователя есть ${userReports.length} связанных отчетов. Они также будут удалены.`;
// }
if (confirm(message)) {
database.users = database.users.filter((u) => u.id !== userId);
database.reports = database.reports.filter((r) => r.userId !== userId);
loadUsers();
loadReports();
updateDashboard();
showNotification("Пользователь и связанные отчеты удалены!");
}
}
// if (confirm(message)) {
// database.users = database.users.filter((u) => u.id !== userId);
// database.reports = database.reports.filter((r) => r.userId !== userId);
// loadUsers();
// loadReports();
// updateDashboard();
// showNotification("Пользователь и связанные отчеты удалены!");
// }
// }
// === УПРАВЛЕНИЕ МАГАЗИНАМИ ===