/* ============================================================ Заявка на замер — менеджер создаёт, замерщику в инбокс ============================================================ */ const MeasurementRequest = (function () { let root = null; let state = { client_name: "", client_phone: "", address: "", assigned_to_tg_id: "", // Одно поле «Примечание» — рекомендации по дате замера + особенности. // Замерщик увидит это в карточке заявки и согласует точное время с клиентом. preferred_note: "", }; let measurers = []; async function _fetchWithTimeout(url, body, timeoutMs = 15000) { const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), timeoutMs); try { const res = await fetch(url, { method: "POST", signal: ctrl.signal, headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); return await res.json(); } catch (e) { if (e.name === "AbortError") throw new Error("Сервер не отвечает — попробуйте ещё раз"); throw e; } finally { clearTimeout(timer); } } function mount(container) { root = container; document.body.classList.remove("has-bottom-nav"); const oldNav = document.getElementById("bottom-nav"); if (oldNav) oldNav.remove(); state = { client_name: "", client_phone: "", address: "", assigned_to_tg_id: "", preferred_note: "", }; // Prefill из карточки клиента (sessionStorage перед navigate) try { const raw = sessionStorage.getItem("prefillClient"); if (raw) { const pre = JSON.parse(raw); if (pre.name) state.client_name = pre.name; if (pre.phone) state.client_phone = pre.phone; sessionStorage.removeItem("prefillClient"); } } catch (e) {} render(); loadMeasurers(); } function render() { if (!root) return; root.innerHTML = ""; root.appendChild(headerEl("Новая заявка на замер", "#/")); const form = el(`

Заявка
на замер

Заполните данные клиента — замерщик получит уведомление в Telegram и согласует дату.

`); root.appendChild(form); bindInputs(form); form.querySelector("#submit").addEventListener("click", () => onSubmit(form)); } function bindInputs(node) { node.querySelectorAll("[data-bind]").forEach(inp => { inp.addEventListener("input", e => { state[e.target.dataset.bind] = e.target.value; }); inp.addEventListener("change", e => { state[e.target.dataset.bind] = e.target.value; }); }); } async function loadMeasurers() { try { const data = await _fetchWithTimeout(`${BACKEND_URL}/api/staff_list`, { initData: tg?.initData || "", role: "measurer", }); measurers = data.staff || []; const sel = document.getElementById("measurerSelect"); const hint = document.getElementById("measurerHint"); if (!sel) return; if (!measurers.length) { sel.innerHTML = ``; sel.disabled = true; if (hint) hint.textContent = "Сначала выдайте кому-нибудь роль measurer через /grant_role"; return; } sel.disabled = false; sel.innerHTML = `` + measurers.map(m => ``).join(""); } catch (e) { const sel = document.getElementById("measurerSelect"); if (sel) sel.innerHTML = ``; } } async function onSubmit(form) { const btn = form.querySelector("#submit"); const result = form.querySelector("#submitResult"); // Валидация form.querySelector("#errName").textContent = ""; form.querySelector("#errPhone").textContent = ""; const name = (state.client_name || "").trim(); const phone = (state.client_phone || "").trim(); if (!name) { form.querySelector("#errName").textContent = "Укажите имя клиента"; return; } if (phone.replace(/\D/g, "").length < 10) { form.querySelector("#errPhone").textContent = "Слишком короткий номер"; return; } btn.disabled = true; btn.innerHTML = ' создаём...'; result.innerHTML = ""; try { const data = await _fetchWithTimeout(`${BACKEND_URL}/api/measurement_request`, { initData: tg?.initData || "", initDataUnsafe: tg?.initDataUnsafe || null, client_name: name, client_phone: phone, address: state.address || "", assigned_to_tg_id: state.assigned_to_tg_id || "", preferred_note: state.preferred_note || "", preferred_type: "tbd", }); if (data.error) { result.innerHTML = `
Ошибка: ${data.error}
`; btn.disabled = false; btn.textContent = "Попробовать снова"; return; } haptic && haptic("success"); const assignedTo = state.assigned_to_tg_id ? measurers.find(m => String(m.tg_id) === String(state.assigned_to_tg_id)) : null; result.innerHTML = `
${ICONS.check}
Заявка создана
ID #${(data.id || "").slice(0, 6)}${assignedTo ? " · Замерщик уведомлён в Telegram" : " · Без назначения"}
`; form.querySelector("#newOne")?.addEventListener("click", () => mount(root)); form.querySelector("#toHome")?.addEventListener("click", () => { location.hash = ""; if (typeof routeByHash === "function") routeByHash(); }); } catch (e) { result.innerHTML = `
Сеть: ${e.message}
`; btn.disabled = false; btn.textContent = "Попробовать снова"; } } function headerEl(title, backHref) { const h = el(`
${escHtml(title)}
`); h.querySelector(".podbor-back").addEventListener("click", () => { if (backHref) location.hash = backHref; else { location.hash = ""; if (typeof routeByHash === "function") routeByHash(); } }); return h; } function escHtml(s) { return String(s == null ? "" : s) .replace(/&/g, "&").replace(//g, ">").replace(/"/g, """); } function escAttr(s) { return escHtml(s); } return { mount }; })();