(function () { 'use strict'; var apiUrl = 'https://auth.xiot.pro/api/v2/entry'; var tokenKey = 'xiot_calculator_integrator_jwt'; var activeProjectIdKey = 'xiot_calculator_active_project_id'; var activeProjectNameKey = 'xiot_calculator_active_project_name'; var authToken = localStorage.getItem(tokenKey) || ''; var challengeId = ''; var pendingEmail = ''; function byId(id) { return document.getElementById(id); } function api(func, data) { data = data || {}; data.func = func; if (authToken) { data.jwt = authToken; } var options = { method: 'POST', credentials: 'omit', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify(data) }; return fetch(apiUrl, options).then(function (response) { return response.json().catch(function () { throw new Error('Сервер вернул некорректный ответ.'); }).then(function (payload) { if (!response.ok || payload.ok === false) { throw new Error(payload.detail || payload.message || 'Не удалось выполнить запрос.'); } return payload; }); }); } function setMessage(element, text, isError) { element.textContent = text || ''; element.classList.toggle('is-error', Boolean(isError)); } function setAuthenticated(email) { window.XiotCalculatorIntegratorAuthenticated = Boolean(email); byId('login-open-btn').hidden = Boolean(email); byId('logout-btn').hidden = !email; byId('feedback-open-btn').hidden = !email; byId('project-save-btn').hidden = !email; byId('projects-open-btn').hidden = !email; byId('account-user').hidden = !email; byId('account-user').textContent = email ? 'Интегратор: ' + email : ''; window.dispatchEvent(new CustomEvent('xiot-calculator-auth-changed', { detail: { authenticated: Boolean(email), email: email || '' } })); } function escapeHtml(value) { return String(value || '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function formatProjectDate(timestamp) { if (!timestamp) { return ''; } return new Date(timestamp * 1000).toLocaleString('ru-RU'); } function openModal(modal) { modal.hidden = false; document.body.style.overflow = 'hidden'; var focusable = modal.querySelector('input, select, textarea, button'); if (focusable) { window.setTimeout(function () { focusable.focus(); }, 0); } } function closeModal(modal) { modal.hidden = true; document.body.style.overflow = ''; } function currentCalculatorState() { try { return JSON.parse(localStorage.getItem('xiot_work_calc_state_v1') || '{}'); } catch (error) { return {}; } } function setActiveProject(project) { if (!project || !project.id) { localStorage.removeItem(activeProjectIdKey); localStorage.removeItem(activeProjectNameKey); return; } localStorage.setItem(activeProjectIdKey, project.id); localStorage.setItem(activeProjectNameKey, project.name || 'Проект'); } function renderProjects(projects) { var target = byId('projects-list'); if (!projects.length) { target.innerHTML = '
Сохранённых проектов пока нет.
'; return; } target.innerHTML = projects.map(function (project) { return '
' + '
' + escapeHtml(project.name) + '' + 'Изменён: ' + escapeHtml(formatProjectDate(project.updated_at)) + '
' + '
' + '' + '' + '' + '' + '
'; }).join(''); } function refreshProjects() { setMessage(byId('projects-message'), 'Загружаем проекты…'); return api('calculator_project_list').then(function (result) { renderProjects(result.projects || []); setMessage(byId('projects-message'), ''); return result.projects || []; }).catch(function (error) { setMessage(byId('projects-message'), error.message, true); throw error; }); } function saveProject(projectId, name) { return api('calculator_project_save', { project_id: projectId || '', name: name, state: currentCalculatorState() }).then(function (result) { setActiveProject(result.project); return result; }); } function initialise() { var loginModal = byId('login-modal'); var feedbackModal = byId('feedback-modal'); var projectsModal = byId('projects-modal'); var emailForm = byId('email-form'); var codeForm = byId('code-form'); var loginMessage = byId('login-message'); var feedbackResult = byId('feedback-message-result'); var projectsMessage = byId('projects-message'); document.querySelectorAll('[data-account-close]').forEach(function (element) { element.addEventListener('click', function () { closeModal(element.closest('.account-modal')); }); }); byId('login-open-btn').addEventListener('click', function () { setMessage(loginMessage, ''); openModal(loginModal); }); byId('feedback-open-btn').addEventListener('click', function () { setMessage(feedbackResult, ''); openModal(feedbackModal); }); byId('projects-open-btn').addEventListener('click', function () { var state = currentCalculatorState(); byId('project-name').value = state.objectName || 'Новый проект'; openModal(projectsModal); refreshProjects().catch(function () {}); }); byId('project-save-btn').addEventListener('click', function () { var button = byId('project-save-btn'); var projectId = localStorage.getItem(activeProjectIdKey) || ''; var projectName = localStorage.getItem(activeProjectNameKey) || ''; if (!projectId || !projectName) { var state = currentCalculatorState(); byId('project-name').value = state.objectName || 'Новый проект'; openModal(projectsModal); refreshProjects().catch(function () {}); return; } button.disabled = true; saveProject(projectId, projectName).then(function () { button.textContent = 'Сохранено'; window.setTimeout(function () { button.textContent = 'Сохранить проект'; }, 1500); }).catch(function (error) { window.alert(error.message); }).then(function () { button.disabled = false; }); }); byId('project-create-form').addEventListener('submit', function (event) { event.preventDefault(); var submit = event.currentTarget.querySelector('[type="submit"]'); var name = byId('project-name').value.trim(); submit.disabled = true; setMessage(projectsMessage, 'Сохраняем проект…'); saveProject('', name).then(function (result) { setMessage(projectsMessage, result.message || 'Проект сохранён'); return refreshProjects(); }).catch(function (error) { setMessage(projectsMessage, error.message, true); }).then(function () { submit.disabled = false; }); }); byId('projects-list').addEventListener('click', function (event) { var row = event.target.closest('[data-project-id]'); if (!row) { return; } var projectId = row.dataset.projectId; var projectName = row.dataset.projectName; if (event.target.closest('[data-project-open]')) { setMessage(projectsMessage, 'Открываем проект…'); api('calculator_project_get', { project_id: projectId }).then(function (result) { localStorage.setItem('xiot_work_calc_state_v1', JSON.stringify(result.project.state || {})); localStorage.removeItem('CalcInputData'); setActiveProject(result.project); window.location.reload(); }).catch(function (error) { setMessage(projectsMessage, error.message, true); }); return; } if (event.target.closest('[data-project-copy]')) { var copyName = window.prompt('Введите название копии проекта:', projectName + ' — копия'); if (copyName === null) { return; } copyName = copyName.trim(); if (!copyName) { window.alert('Название проекта не может быть пустым.'); return; } if (copyName.length > 160) { window.alert('Название проекта должно быть не длиннее 160 символов.'); return; } setMessage(projectsMessage, 'Создаём копию…'); api('calculator_project_get', { project_id: projectId }).then(function (result) { return api('calculator_project_save', { project_id: '', name: copyName, state: result.project.state || {} }); }).then(function () { setMessage(projectsMessage, 'Копия создана'); return refreshProjects(); }).catch(function (error) { setMessage(projectsMessage, error.message, true); }); return; } if (event.target.closest('[data-project-rename]')) { var newName = window.prompt('Введите новое название проекта:', projectName); if (newName === null) { return; } newName = newName.trim(); if (!newName) { window.alert('Название проекта не может быть пустым.'); return; } if (newName.length > 160) { window.alert('Название проекта должно быть не длиннее 160 символов.'); return; } if (newName === projectName) { return; } setMessage(projectsMessage, 'Переименовываем проект…'); api('calculator_project_get', { project_id: projectId }).then(function (result) { return api('calculator_project_save', { project_id: projectId, name: newName, state: result.project.state || {} }); }).then(function (result) { if (localStorage.getItem(activeProjectIdKey) === projectId) { setActiveProject(result.project); } setMessage(projectsMessage, 'Проект переименован'); return refreshProjects(); }).catch(function (error) { setMessage(projectsMessage, error.message, true); }); return; } if (event.target.closest('[data-project-delete]')) { if (!window.confirm('Удалить проект «' + projectName + '»?')) { return; } setMessage(projectsMessage, 'Удаляем проект…'); api('calculator_project_delete', { project_id: projectId }).then(function () { if (localStorage.getItem(activeProjectIdKey) === projectId) { setActiveProject(null); } setMessage(projectsMessage, 'Проект удалён'); return refreshProjects(); }).catch(function (error) { setMessage(projectsMessage, error.message, true); }); } }); byId('change-email-btn').addEventListener('click', function () { emailForm.hidden = false; codeForm.hidden = true; byId('login-email').focus(); setMessage(loginMessage, ''); }); emailForm.addEventListener('submit', function (event) { event.preventDefault(); var submit = emailForm.querySelector('[type="submit"]'); pendingEmail = byId('login-email').value.trim().toLowerCase(); submit.disabled = true; setMessage(loginMessage, 'Отправляем код…'); api('calculator_auth_start', { email: pendingEmail }).then(function (result) { challengeId = result.challenge_id || ''; emailForm.hidden = true; codeForm.hidden = false; byId('login-code').value = ''; byId('login-code').focus(); setMessage(loginMessage, result.message || 'Если адрес разрешён, код отправлен.'); }).catch(function (error) { setMessage(loginMessage, error.message, true); }).then(function () { submit.disabled = false; }); }); codeForm.addEventListener('submit', function (event) { event.preventDefault(); var submit = codeForm.querySelector('[type="submit"]'); submit.disabled = true; setMessage(loginMessage, 'Проверяем код…'); api('calculator_auth_verify', { challenge_id: challengeId, code: byId('login-code').value.trim() }).then(function (result) { authToken = result.jwt || ''; localStorage.setItem(tokenKey, authToken); setAuthenticated(result.email); closeModal(loginModal); }).catch(function (error) { setMessage(loginMessage, error.message, true); }).then(function () { submit.disabled = false; }); }); byId('logout-btn').addEventListener('click', function () { authToken = ''; localStorage.removeItem(tokenKey); setActiveProject(null); setAuthenticated(''); }); byId('feedback-form').addEventListener('submit', function (event) { event.preventDefault(); var form = event.currentTarget; var submit = form.querySelector('[type="submit"]'); var includeContext = byId('feedback-context').checked; submit.disabled = true; setMessage(feedbackResult, 'Отправляем обращение…'); api('calculator_feedback', { category: byId('feedback-category').value, subject: byId('feedback-subject').value.trim(), message: byId('feedback-message').value.trim(), context: includeContext ? { calculator: currentCalculatorState(), page: window.location.href, userAgent: navigator.userAgent } : null }).then(function (result) { form.reset(); byId('feedback-context').checked = true; setMessage(feedbackResult, result.message || 'Обращение отправлено.'); }).catch(function (error) { setMessage(feedbackResult, error.message, true); }).then(function () { submit.disabled = false; }); }); document.addEventListener('keydown', function (event) { if (event.key === 'Escape') { document.querySelectorAll('.account-modal:not([hidden])').forEach(closeModal); } }); if (!authToken) { setAuthenticated(''); return; } api('calculator_auth_status').then(function (result) { setAuthenticated(result.authenticated ? result.email : ''); }).catch(function () { authToken = ''; localStorage.removeItem(tokenKey); setActiveProject(null); setAuthenticated(''); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialise); } else { initialise(); } }());