"use strict"; // ---------- Обратная связь по порталу ---------- // Неприметная ссылка внизу каждой страницы открывает короткую форму. Ответы видят только администраторы портала (#/feedback). const FB_KIND = { idea: "💡 Идея", bug: "🐞 Ошибка", other: "💬 Другое" }; const FB_STATUS = { new: "Новое", taken: "В работе", done: "Сделано", rejected: "Не будем делать" }; function feedbackFooter() { const foot = document.getElementById("appfoot"); if (!foot) return; foot.replaceChildren(me ? h("a", { href: "javascript:void 0", class: "fblink", onclick: openFeedback }, "Предложить улучшение портала или сообщить об ошибке") : ""); } function openFeedback() { if (document.querySelector(".fbmodal")) return; const st = { kind: "idea", text: "" }; const kinds = h("div", { class: "row" }); const drawKinds = () => kinds.replaceChildren(...Object.entries(FB_KIND).map(([k, t]) => h("button", { type: "button", class: "chipf" + (st.kind === k ? " on" : ""), onclick: () => { st.kind = k; drawKinds(); } }, t))); drawKinds(); const text = h("textarea", { rows: 5, maxlength: 4000, placeholder: "Что улучшить или что не работает? Где именно, как повторить." }); const close = () => wrap.remove(); const wrap = h("div", { class: "fbmodal", onclick: e => { if (e.target === wrap) close(); } }, h("div", { class: "card" }, h("h2", { style: "margin-top:0" }, "Обратная связь по порталу"), h("p", { class: "small muted" }, "Сообщение получат администраторы портала. Раздел, где вы сейчас, подставится сам."), kinds, h("div", { style: "margin-top:8px" }, text), h("div", { class: "row", style: "margin-top:10px" }, h("button", { onclick: guard(async () => { if (text.value.trim().length < 3) throw new Error("Опишите идею или проблему"); await api("POST", "/feedback", { kind: st.kind, text: text.value, page: (location.hash || "#/").slice(0, 200), client: "web" }); close(); toast("Спасибо! Сообщение отправлено"); }) }, "Отправить"), h("button", { class: "sec", onclick: close }, "Отмена")))); document.body.append(wrap); text.focus(); } async function feedbackPage(which) { if (!me.portal_admin) throw new Error("Доступно только администраторам портала"); const status = which === "all" ? "" : which === "done" ? "done" : "open"; const list = await api("GET", "/feedback" + (status ? "?status=" + status : "")); const card = f => { const sel = h("select", {}, ...Object.entries(FB_STATUS).map(([k, t]) => h("option", { value: k, selected: f.status === k }, t))); const ans = h("textarea", { rows: 2, placeholder: "Заметка: что решили, что сделано" }, f.answer); return h("div", { class: "card fbcard fb-" + f.status }, h("div", { class: "row" }, h("b", { style: "flex:1" }, FB_KIND[f.kind] || f.kind), h("span", { class: "badge" }, FB_STATUS[f.status] || f.status)), h("div", { class: "small muted" }, [fmt(f.created_at), f.user_name || "—", f.page ? "раздел " + f.page : "", { web: "сайт", m: "мобильная версия", android: "приложение" }[f.client] || f.client].filter(Boolean).join(" · ")), h("div", { style: "margin-top:6px;white-space:pre-wrap" }, f.text), f.answered_by_name ? h("div", { class: "small muted", style: "margin-top:4px" }, `Обновил ${f.answered_by_name}, ${fmt(f.answered_at)}`) : null, h("div", { class: "grid", style: "margin-top:8px" }, field("Статус", sel), field("Заметка", ans)), h("div", { class: "row", style: "margin-top:8px" }, h("button", { class: "sm", onclick: guard(async () => { await api("PATCH", `/feedback/${f.id}`, { status: sel.value, answer: ans.value }); toast("Сохранено"); feedbackPage(which); }) }, "Сохранить"), h("button", { class: "sec sm", onclick: guard(async () => { if (confirm("Удалить сообщение?")) { await api("DELETE", `/feedback/${f.id}`); feedbackPage(which); } }) }, "Удалить"))); }; fill($app, h("h1", {}, "Обратная связь по порталу"), tabs([["#/feedback", "Открытые"], ["#/feedback/done", "Сделано"], ["#/feedback/all", "Все"]], which === "all" ? "#/feedback/all" : which === "done" ? "#/feedback/done" : "#/feedback"), h("p", { class: "small muted" }, "Идеи и замечания сотрудников. Видят только администраторы портала. Ссылка на форму — внизу каждой страницы и в меню приложения."), ...(list.length ? list.map(card) : [h("div", { class: "card muted" }, "Сообщений нет")])); }