//API const API_BASE_URL = "http://localhost:3001/api"; //Login async function loginUser(username, password) { try { const response = await fetch(`${API_BASE_URL}/auth/login`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username, password }), }); 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 (err) { return { success: false, error: "Нет соединения с сервером" }; } } document.getElementById("loginForm").addEventListener("submit", async (e) => { e.preventDefault(); const username = document.getElementById("username").value; const password = document.getElementById("password").value; // Call backend login const result = await loginUser(username, password); if (result.success) { // Save user/token in JS (or localStorage) currentUser = result.user; localStorage.setItem("token", result.token); document.getElementById("loginScreen").classList.add("hidden"); if (result.user.role === "admin") { showAdminInterface(); } else { showUserInterface(); } showNotification("Успешная авторизация!"); } else { const errorDiv = document.getElementById("loginError"); errorDiv.textContent = result.error; errorDiv.classList.remove("hidden"); } }); document.addEventListener("DOMContentLoaded", async () => { const token = localStorage.getItem("token"); if (token) { // Try to get user info from backend try { const response = await fetch(`${API_BASE_URL}/auth/me`, { headers: { Authorization: `Bearer ${token}`, }, }); if (response.ok) { const data = await response.json(); currentUser = data.user; document.getElementById("loginScreen").classList.add("hidden"); if (currentUser.role === "admin") { showAdminInterface(); } else { showUserInterface(); } } else { // Token invalid/expired localStorage.removeItem("token"); document.getElementById("loginScreen").classList.remove("hidden"); } } catch (err) { showNotification("Нет соединения с сервером", "error"); } } else { // No token, show login screen document.getElementById("loginScreen").classList.remove("hidden"); } }); function logout() { currentUser = null; localStorage.removeItem("token"); // Show login screen, hide other interfaces document.getElementById("loginScreen").classList.remove("hidden"); document.getElementById("userInterface").classList.add("hidden"); document.getElementById("adminInterface").classList.add("hidden"); document.getElementById("loginForm").reset(); document.getElementById("loginError").classList.add("hidden"); showNotification("Вы вышли из системы", "info"); } document.getElementById("logoutBtn").addEventListener("click", logout); document.getElementById("adminLogoutBtn").addEventListener("click", logout); //Users //GET all users (admin only) async function getAllUsers() { const token = localStorage.getItem("token"); try { const response = await fetch(`${API_BASE_URL}/users`, { method: "GET", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, }); const data = await response.json(); if (response.ok) { return { success: true, users: data.users }; } else { return { success: false, error: data.error || data.message || "Ошибка получения пользователей", }; } } catch (err) { return { success: false, error: "Нет соединения с сервером" }; } } let usersList = []; async function loadUsers() { const tbody = document.getElementById("usersTableBody"); tbody.innerHTML = ""; const result = await getAllUsers(); console.log("getAllUsers result:", result); if (!result.success) { showNotification(result.error, "error"); return; } const users = result.users; usersList = users; users.forEach((user) => { const userStores = user.stores .map((storeId) => { const store = database.stores.find((s) => s.id === storeId); return store ? store.name : "Нет доступа"; }) .join(", ") || "Нет доступа"; const row = document.createElement("tr"); row.className = "hover:bg-gray-50"; row.innerHTML = ` ${user.id} ${user.username} ${user.role === "admin" ? "Администратор" : "Сотрудник"} ${userStores} `; tbody.appendChild(row); }); if (users.length === 0) { 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 = `
`; 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) ); } //Reports //GET all reports async function getReports() { const token = localStorage.getItem("token"); try { const response = await fetch(`${API_BASE_URL}/reports`, { method: "GET", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, }); const data = await response.json(); if (response.ok) { return { success: true, reports: data.reports }; } else { return { success: false, error: data.error || data.message || "Ошибка получения отчетов", }; } } catch (err) { return { success: false, error: "Нет соединения с сервером" }; } } async function loadReports() { const tbody = document.getElementById("reportsTableBody"); const filterStore = document.getElementById("filterStore"); const result = await getReports(); console.log("getReports() result:", result); window.reportsList = result.success ? result.reports : []; if (!result.success) { showNotification(result.error || "Ошибка загрузки отчетов", "error"); return; } const reports = result.reports; // Build a map storeId => storeName from all reports const storeMap = {}; reports.forEach((r) => { if (r.storeId && r.storeName) { storeMap[r.storeId] = r.storeName; } }); // Get unique [storeId, storeName] pairs sorted alphabetically const storesWithReports = Object.entries(storeMap) .map(([id, name]) => ({ id, name })) .sort((a, b) => a.name.localeCompare(b.name)); filterStore.innerHTML = ` ${storesWithReports .map((store) => ``) .join("")} `; tbody.innerHTML = ""; reports.forEach((report) => { const store = database.stores.find((s) => s.id === report.storeId); // Fallback for username if user might be missing from local array: const user = database.users.find((u) => u.id === report.userId); const profit = (Number(report.totalIncome) || 0) - (Number(report.totalExpenses) || 0); const row = document.createElement("tr"); row.className = "hover:bg-gray-50"; row.innerHTML = ` ${ report.reportDate || report.date || "" } ${ report.storeName || report.storeId } €${Number( report.totalIncome ).toFixed(2)} €${Number( report.totalExpenses ).toFixed(2)} €${profit.toFixed(2)} ${ user ? user.username : report.userId } ${report.isVerified ? "Проверен" : "Не проверен"} `; tbody.appendChild(row); }); setupReportsFilters(); } // Use global array for backend reports function viewReport(reportId) { if (!window.reportsList) { showNotification("Reports not loaded yet!", "error"); return; } const report = window.reportsList.find((r) => r.id === reportId); if (report) { showReportModal(report, true); } else { showNotification("Report not found!", "error"); } } //create report // createReport(data) //edit report // updateReport(id, data) //accept report (admin only) // verifyReport(id) //delete report // deleteReport(id)