/* ============================================================
Экран «Мой профиль» — #/me
Работает для всех ролей: manager, staff, client
============================================================ */
const MeScreen = (function () {
function escHtml(s) {
return String(s == null ? "" : s)
.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """);
}
async function _fetchWithTimeout(url, body, ms = 15000) {
const ctrl = new AbortController();
const t = setTimeout(() => ctrl.abort(), ms);
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(t); }
}
function header(container) {
const h = document.createElement("header");
h.className = "podbor-header";
h.innerHTML = `
Мой профиль
`;
h.querySelector(".podbor-back").addEventListener("click", () => {
haptic && haptic("impact");
history.back();
});
container.appendChild(h);
}
function avatarBlock(initial, name, subtitle) {
return `
${escHtml(initial)}
${escHtml(name)}
${subtitle ? `
${escHtml(subtitle)}
` : ""}
`;
}
function roleChip(label, color) {
const colors = { gold: "#C5A55E", blue: "#3D7AB5", green: "#4A9E6A", muted: "var(--muted)" };
const c = colors[color] || colors.gold;
return `
${escHtml(label)}
`;
}
function renderManager(container, me) {
const u = me.user || {};
const statusLabel = me.status === "active" ? "✅ Активен" :
me.status === "trial" ? "🟡 Пробный" : "🔴 Неактивен";
const statusColor = me.status === "active" ? "green" :
me.status === "trial" ? "gold" : "muted";
const screen = document.createElement("div");
screen.className = "podbor-screen";
screen.innerHTML = `
${avatarBlock(u.avatar_initial || "?", u.full_name || "Менеджер", u.salon || "")}
Статус доступа
Статус
${roleChip(statusLabel, statusColor)}
${me.status_until ? `
Активен до${escHtml(me.status_until)}
` : ""}
${u.salon ? `
Салон${escHtml(u.salon)}
` : ""}
Быстрый переход
`;
screen.querySelectorAll("[data-href]").forEach(btn => {
btn.addEventListener("click", () => {
haptic && haptic("impact");
location.hash = btn.dataset.href;
});
});
container.appendChild(screen);
}
const EQUIPMENT_ITEMS = [
{ key: "tablet", label: "Планшет с ПО для замеров", icon: "📱" },
{ key: "laser_tape", label: "Лазерная рулетка (интеграция с ПО)", icon: "📡" },
{ key: "angle_meter", label: "Угломер", icon: "📐" },
{ key: "tape", label: "Обычная рулетка", icon: "📏" },
{ key: "laser_level", label: "Лазерный уровень", icon: "🔴" },
];
function renderStaffMe(container, me) {
const u = me.user || {};
const caps = me.capabilities || {};
const eqList = me.equipment || [];
const eqOk = me.equipment_ok !== false;
const chips = [
caps.measurer && roleChip("замерщик", "blue"),
caps.assembler && roleChip("сборщик", "green"),
].filter(Boolean).join("");
// Бейдж укомплектованности
const eqBadge = caps.measurer ? `
${eqOk ? "✅ Укомплектован — допуск к замерам открыт" : "⚠️ Не укомплектован — допуск ограничен"}
${!eqOk ? `
Заполните список оборудования ниже
` : ""}
` : "";
const screen = document.createElement("div");
screen.className = "podbor-screen";
screen.innerHTML = `
${avatarBlock(u.avatar_initial || "?", u.full_name || "Сотрудник", "")}
${chips}
${eqBadge}
Мои задачи
${caps.measurer ? `` : ""}
${caps.measurer ? `` : ""}
${caps.assembler ? `` : ""}
${caps.measurer ? `
Оборудование
Все 5 пунктов обязательны для допуска к замерам
` : ""}
`;
screen.querySelectorAll("[data-href]").forEach(btn => {
btn.addEventListener("click", () => {
haptic && haptic("impact");
location.hash = btn.dataset.href;
});
});
container.appendChild(screen);
// Чеклист оборудования
if (caps.measurer) {
const checklist = screen.querySelector("#eq-checklist");
EQUIPMENT_ITEMS.forEach(item => {
const checked = eqList.includes(item.key);
const row = document.createElement("label");
row.style.cssText = `display:flex;align-items:center;gap:10px;padding:10px 0;
border-bottom:1px solid var(--border);cursor:pointer;`;
row.innerHTML = `
${item.icon}
${escHtml(item.label)}
`;
checklist.appendChild(row);
});
// Кнопка сохранить
const saveBtn = screen.querySelector("#eq-save-btn");
const statusEl = screen.querySelector("#eq-status");
saveBtn.addEventListener("click", async () => {
haptic && haptic("impact");
saveBtn.disabled = true;
saveBtn.textContent = "Сохраняем…";
const selected = Array.from(checklist.querySelectorAll("input[data-key]:checked"))
.map(cb => cb.dataset.key);
try {
const res = await _fetchWithTimeout(`${BACKEND_URL}/api/equipment_save`, {
initData: typeof Platform !== "undefined" ? Platform.initData : (window.tg?.initData || ""),
initDataUnsafe: typeof Platform !== "undefined" ? Platform.initDataUnsafe : null,
equipment: selected,
});
if (res.ok) {
statusEl.style.color = res.equipment_ok ? "#27AE60" : "#E74C3C";
statusEl.textContent = res.equipment_ok
? "✅ Сохранено. Допуск открыт."
: "⚠️ Сохранено. Заполните все пункты для допуска.";
// Обновить бейдж
const badge = container.querySelector("#equipment-block")?.closest(".podbor-screen")?.querySelector("[style*='Укомплектован']") ||
container.querySelector("[style*='допуск']");
} else {
statusEl.style.color = "#E74C3C";
statusEl.textContent = "Ошибка: " + (res.error || "неизвестно");
}
} catch (e) {
statusEl.style.color = "#E74C3C";
statusEl.textContent = "Ошибка: " + e.message;
} finally {
saveBtn.disabled = false;
saveBtn.textContent = "Сохранить оборудование";
}
});
}
}
function renderClientMe(container, me) {
const u = me.user || {};
const mgr = me.manager || {};
const screen = document.createElement("div");
screen.className = "podbor-screen";
screen.innerHTML = `
${avatarBlock(u.avatar_initial || "?", u.full_name || "Клиент", "Личный кабинет")}
${mgr.full_name ? `
Мой менеджер
Имя${escHtml(mgr.full_name)}
${mgr.salon ? `
Салон${escHtml(mgr.salon)}
` : ""}
` : ""}
`;
screen.querySelectorAll("[data-href]").forEach(btn => {
btn.addEventListener("click", () => {
haptic && haptic("impact");
location.hash = btn.dataset.href;
});
});
container.appendChild(screen);
}
async function mount(container) {
container.innerHTML = "";
document.body.classList.remove("has-bottom-nav");
const oldNav = document.getElementById("bottom-nav");
if (oldNav) oldNav.remove();
header(container);
const loading = document.createElement("div");
loading.className = "loader-inline";
loading.innerHTML = ``;
container.appendChild(loading);
try {
const me = await _fetchWithTimeout(`${BACKEND_URL}/api/me`, {
initData: tg?.initData || "",
initDataUnsafe: tg?.initDataUnsafe || null,
});
loading.remove();
if (me.error) {
container.appendChild(el(`${escHtml(me.error)}
`));
return;
}
const role = me.role;
if (role === "manager" || me.roles?.includes("manager")) {
renderManager(container, me);
} else if (role === "staff") {
renderStaffMe(container, me);
} else {
renderClientMe(container, me);
}
} catch (e) {
loading.remove();
container.appendChild(el(`Ошибка: ${escHtml(e.message)}
`));
}
}
return { mount };
})();