import { initThemePicker, initHighContrastToggle, initThemeToggle, applyTheme, getTheme } from "/static/js/wesp-theme.js"; import { DEFAULT_PASSWORD_MIN_LEN, validateCredentialChange, } from "/static/js/wesp-user-credentials.js"; export function createRecipesAuthSettingsController({ notyf }) { let settingsModalClickHandler = null; let settingsEscapeHandler = null; let syncDispenserNames = []; let passwordMinLen = DEFAULT_PASSWORD_MIN_LEN; function escapeHtmlSyncSettings(value) { if (value == null) return ""; const div = document.createElement("div"); div.textContent = String(value); return div.innerHTML; } function closeSettings() { const modal = document.getElementById("settingsModal"); if (!modal) return; modal.style.display = "none"; document.body.style.overflow = ""; const form = document.getElementById("settingsForm"); if (form) form.reset(); const credForm = document.getElementById("credentialsForm"); if (credForm) credForm.style.display = "none"; const userCard = document.querySelector(".settings-user-card--clickable"); if (userCard) userCard.classList.remove("open"); const syncForm = document.getElementById("syncSettingsForm"); if (syncForm) syncForm.style.display = "none"; const syncCard = document.querySelector(".settings-sync-card--clickable"); if (syncCard) syncCard.classList.remove("open"); if (settingsModalClickHandler) { modal.removeEventListener("click", settingsModalClickHandler); settingsModalClickHandler = null; } if (settingsEscapeHandler) { document.removeEventListener("keydown", settingsEscapeHandler); settingsEscapeHandler = null; } } async function openSettings(event) { if (event) event.preventDefault(); try { const response = await fetch("/api/auth/get_current_credentials"); const data = await response.json(); if (data.status === "success") { const oldLogin = document.getElementById("oldLogin"); const oldPassword = document.getElementById("oldPassword"); if (oldLogin) oldLogin.value = data.login || ""; if (oldPassword) oldPassword.value = ""; } } catch (error) { console.error("Ошибка загрузки текущих учетных данных:", error); } const modal = document.getElementById("settingsModal"); if (!modal) return; modal.style.display = "block"; document.body.style.overflow = "hidden"; initThemePicker(); initHighContrastToggle(); if (settingsModalClickHandler) { modal.removeEventListener("click", settingsModalClickHandler); } if (settingsEscapeHandler) { document.removeEventListener("keydown", settingsEscapeHandler); } settingsModalClickHandler = (e) => { if (e.target === modal) closeSettings(); }; settingsEscapeHandler = (e) => { if (e.key === "Escape" && modal.style.display === "block") closeSettings(); }; modal.addEventListener("click", settingsModalClickHandler); document.addEventListener("keydown", settingsEscapeHandler); } async function checkAuth() { try { const response = await fetch("/api/auth/check"); const data = await response.json(); if (data.status === "success" && data.authenticated) { const userInfo = document.getElementById("userInfo"); const userLogin = document.getElementById("userLogin"); const mobileUserInfo = document.getElementById("mobileUserInfo"); const canOpenAdmin = Boolean(data.is_superuser); window.WESP_CAN_LAB = Boolean(data.can_lab); window.WespLabAccess?.apply?.(window.WESP_CAN_LAB); const rules = data.user_rules || {}; passwordMinLen = Number(rules.password_min_len) || DEFAULT_PASSWORD_MIN_LEN; if (userLogin) userLogin.textContent = data.user_login; if (userInfo) { userInfo.style.cursor = canOpenAdmin ? "pointer" : ""; userInfo.title = canOpenAdmin ? "Открыть админ-панель" : ""; userInfo.onclick = canOpenAdmin ? () => { window.location.href = "/admin"; } : null; } if (mobileUserInfo) { mobileUserInfo.innerHTML = ` ${data.user_login}`; mobileUserInfo.style.cursor = canOpenAdmin ? "pointer" : ""; mobileUserInfo.title = canOpenAdmin ? "Открыть админ-панель" : ""; mobileUserInfo.onclick = canOpenAdmin ? () => { window.location.href = "/admin"; } : null; } } else { window.location.href = "/login"; } return data; } catch (error) { console.error("Ошибка проверки авторизации:", error); window.location.href = "/login"; return null; } } async function logout() { try { const response = await fetch("/api/auth/logout", { method: "POST", headers: { "Content-Type": "application/json" }, }); const data = await response.json(); if (data.status === "success") { window.location.href = "/"; } else { notyf.error("Ошибка при выходе из системы"); } } catch (error) { console.error("Ошибка при выходе:", error); notyf.error("Ошибка при выходе из системы"); } } function setupMobileMenu() { const hamburgerMenu = document.getElementById("hamburgerMenu"); const mobileMenuOverlay = document.getElementById("mobileMenuOverlay"); const closeMenu = document.getElementById("closeMenu"); const mobileUserInfo = document.getElementById("mobileUserInfo"); if (!hamburgerMenu || !mobileMenuOverlay || !closeMenu) return; hamburgerMenu.addEventListener("click", () => { mobileMenuOverlay.classList.add("active"); hamburgerMenu.classList.add("active"); document.body.style.overflow = "hidden"; const userInfo = document.getElementById("userInfo"); if (userInfo && mobileUserInfo) { mobileUserInfo.textContent = userInfo.textContent || ""; } }); const closeMobileMenu = () => { mobileMenuOverlay.classList.remove("active"); hamburgerMenu.classList.remove("active"); document.body.style.overflow = ""; }; closeMenu.addEventListener("click", closeMobileMenu); mobileMenuOverlay.addEventListener("click", (e) => { if (e.target === mobileMenuOverlay) closeMobileMenu(); }); document.addEventListener("keydown", (e) => { if (e.key === "Escape" && mobileMenuOverlay.classList.contains("active")) { closeMobileMenu(); } }); const mobileMenuItems = document.querySelectorAll(".mobile-menu-item"); mobileMenuItems.forEach((item) => { item.addEventListener("click", () => { setTimeout(closeMobileMenu, 300); }); }); } async function loadSyncClientsSettings() { const listEl = document.getElementById("syncClientsListSettings"); const emptyEl = document.getElementById("syncClientsEmptySettings"); if (!listEl) return; listEl.innerHTML = ""; if (emptyEl) emptyEl.style.display = "none"; try { const [clientsRes, namesRes] = await Promise.all([ fetch("/api/sync/clients"), fetch("/api/feed_dispensers/names"), ]); const clients = clientsRes.ok ? await clientsRes.json() : []; syncDispenserNames = namesRes.ok ? await namesRes.json() : []; if (!clients || clients.length === 0) { if (emptyEl) { emptyEl.style.display = "block"; emptyEl.textContent = "Нет подключенных клиентов"; } return; } clients.forEach((client) => { const displayLabel = client.display_name || client.client_name || client.node_id; const item = document.createElement("div"); item.className = "settings-sync-client-item"; item.dataset.nodeId = client.node_id; item.dataset.displayName = displayLabel || ""; item.innerHTML = `${escapeHtmlSyncSettings(displayLabel)}` + '
' + ' ' + '' + "
"; listEl.appendChild(item); }); } catch (error) { if (emptyEl) { emptyEl.style.display = "block"; emptyEl.textContent = "Не удалось загрузить список клиентов"; } } } function editSyncClientSettings(btn) { const item = btn && btn.closest ? btn.closest(".settings-sync-client-item") : null; const nodeId = item ? item.dataset.nodeId : null; const currentName = item ? item.dataset.displayName || "" : ""; if (!item || !nodeId) return; let selectHtml = ''; syncDispenserNames.forEach((name) => { const escaped = escapeHtmlSyncSettings(name); selectHtml += ``; }); item.innerHTML = '
' + '' + ` ` + ` ` + '' + "
"; const sel = document.getElementById(`syncEditSelect_${nodeId}`); if (sel && currentName) sel.value = currentName; } function saveSyncClientDisplayName(nodeId) { const sel = document.getElementById(`syncEditSelect_${nodeId}`); const displayName = sel ? (sel.value || "").trim() : ""; fetch(`/api/sync/clients/${encodeURIComponent(nodeId)}/display_name`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ display_name: displayName || null }), }) .then((r) => r.json()) .then((data) => { if (data.error) { notyf.error(data.error); return; } notyf.success(displayName ? "Имя сохранено" : "Имя сброшено"); loadSyncClientsSettings(); }) .catch(() => notyf.error("Не удалось сохранить настройки клиента")); } async function deleteSyncClientSettings(btn) { const item = btn && btn.closest ? btn.closest(".settings-sync-client-item") : null; const nodeId = item ? item.dataset.nodeId : null; if (!nodeId) return; const ok = globalThis.WespKioskDialog ? await globalThis.WespKioskDialog.confirm("Удалить этого клиента из синхронизации?") : globalThis.confirm("Удалить этого клиента из синхронизации?"); if (!ok) return; fetch(`/api/sync/clients/${encodeURIComponent(nodeId)}`, { method: "DELETE" }) .then((r) => r.json()) .then((data) => { if (data.error) { notyf.error(data.error); return; } notyf.success(data.message || "Клиент удалён"); loadSyncClientsSettings(); }) .catch(() => notyf.error("Не удалось сохранить настройки клиента")); } function toggleCredentialsForm() { const credForm = document.getElementById("credentialsForm"); const userCard = document.querySelector(".settings-user-card--clickable"); if (!credForm) return; const isOpen = credForm.style.display !== "none"; credForm.style.display = isOpen ? "none" : "block"; if (userCard) userCard.classList.toggle("open", !isOpen); } function toggleSyncForm() { const syncForm = document.getElementById("syncSettingsForm"); const syncCard = document.querySelector(".settings-sync-card--clickable"); if (!syncForm) return; const isOpen = syncForm.style.display !== "none"; syncForm.style.display = isOpen ? "none" : "block"; if (syncCard) syncCard.classList.toggle("open", !isOpen); if (!isOpen) loadSyncClientsSettings(); } async function changeCredentials() { const oldLogin = (document.getElementById("oldLogin")?.value || "").trim(); const oldPassword = document.getElementById("oldPassword")?.value || ""; const newLogin = (document.getElementById("newLogin")?.value || "").trim(); const newPassword = document.getElementById("newPassword")?.value || ""; const confirmPassword = document.getElementById("confirmPassword")?.value || ""; const wantsCredChange = !!(newLogin || newPassword || confirmPassword.trim()); if (!wantsCredChange) { notyf.success("Настройки сохранены"); closeSettings(); return; } const validationError = validateCredentialChange({ oldLogin, oldPassword, newLogin, newPassword, confirmPassword, passwordMinLen, }); if (validationError) { notyf.error(validationError); return; } try { const response = await fetch("/api/auth/change_credentials", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ old_login: oldLogin, old_password: oldPassword, new_login: newLogin, new_password: newPassword, confirm_password: confirmPassword, }), }); const data = await response.json(); if (data.status === "success") { notyf.success(data.message); closeSettings(); const userLogin = document.getElementById("userLogin"); const mobileUserInfo = document.getElementById("mobileUserInfo"); if (userLogin) userLogin.textContent = newLogin; if (mobileUserInfo) { mobileUserInfo.innerHTML = ` ${newLogin}`; } } else { notyf.error(data.message); } } catch (error) { console.error("Ошибка при изменении учетных данных:", error); notyf.error("Ошибка при изменении учетных данных"); } } applyTheme(getTheme()); return { checkAuth, logout, setupMobileMenu, openSettings, closeSettings, toggleSyncForm, loadSyncClientsSettings, editSyncClientSettings, saveSyncClientDisplayName, deleteSyncClientSettings, toggleCredentialsForm, changeCredentials, initThemePicker, initHighContrastToggle, initThemeToggle, }; }