This commit is contained in:
@@ -423,11 +423,12 @@ function formData(form) {
|
||||
}
|
||||
|
||||
async function api(path, options = {}) {
|
||||
const headers = { "Content-Type": "application/json", ...authHeaders(options.headers || {}) };
|
||||
const { headers: optionHeaders = {}, ...fetchOptions } = options;
|
||||
const headers = { "Content-Type": "application/json", ...authHeaders(optionHeaders) };
|
||||
if (options.body instanceof FormData) delete headers["Content-Type"];
|
||||
const response = await fetch(`/api${path}`, {
|
||||
...fetchOptions,
|
||||
headers,
|
||||
...options,
|
||||
});
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
@@ -541,9 +542,47 @@ function hideAuthOverlay() {
|
||||
document.body.classList.remove("auth-required");
|
||||
}
|
||||
|
||||
const APPROVED_SERVICE_STATUSES = new Set(["approved", "verified"]);
|
||||
const STO_WORKPLACE_ROLES = new Set(["owner", "mechanic"]);
|
||||
const STO_CALENDAR_ROLES = new Set(["owner", "manager", "receptionist"]);
|
||||
|
||||
function isPlatformAdmin() {
|
||||
return ["admin", "verifier", "moderator"].includes(state.user?.platform_role);
|
||||
}
|
||||
|
||||
function approvedServiceCenters() {
|
||||
return state.serviceCenters.filter((center) => APPROVED_SERVICE_STATUSES.has(center.verification_status));
|
||||
}
|
||||
|
||||
function stoWorkplaceCenters() {
|
||||
return approvedServiceCenters().filter((center) => STO_WORKPLACE_ROLES.has(center.employee_role || "owner"));
|
||||
}
|
||||
|
||||
function stoCalendarCenters() {
|
||||
return approvedServiceCenters().filter((center) => STO_CALENDAR_ROLES.has(center.employee_role || "owner"));
|
||||
}
|
||||
|
||||
function canUseServiceProfile() {
|
||||
return state.serviceCenters.length > 0 || state.user?.platform_role === "service_owner" || isPlatformAdmin();
|
||||
}
|
||||
|
||||
function canOpenDrawerSection(sectionId) {
|
||||
if (sectionId === "adminSection") return isPlatformAdmin();
|
||||
if (sectionId === "mechanicWorkplaceSection") return stoWorkplaceCenters().length > 0;
|
||||
if (sectionId === "stoCalendarSection") return stoCalendarCenters().length > 0;
|
||||
if (sectionId === "servicePanelSection") return canUseServiceProfile();
|
||||
return true;
|
||||
}
|
||||
|
||||
function updateRoleVisibility() {
|
||||
const isAdmin = ["admin", "verifier", "moderator"].includes(state.user?.platform_role);
|
||||
const isAdmin = isPlatformAdmin();
|
||||
const hasWorkplace = stoWorkplaceCenters().length > 0;
|
||||
const hasCalendar = stoCalendarCenters().length > 0;
|
||||
const hasServiceProfile = canUseServiceProfile();
|
||||
document.querySelectorAll(".admin-only").forEach((node) => node.classList.toggle("hidden", !isAdmin));
|
||||
document.querySelectorAll(".sto-workplace-only").forEach((node) => node.classList.toggle("hidden", !hasWorkplace));
|
||||
document.querySelectorAll(".sto-calendar-only").forEach((node) => node.classList.toggle("hidden", !hasCalendar));
|
||||
document.querySelectorAll(".service-owner-only").forEach((node) => node.classList.toggle("hidden", !hasServiceProfile));
|
||||
}
|
||||
|
||||
function showTelegramOpenHint() {
|
||||
@@ -1051,17 +1090,20 @@ async function loadMyServiceCenters({ withTrust = false } = {}) {
|
||||
state.activeServiceCenterId = state.serviceCenters[0]?.id || null;
|
||||
}
|
||||
renderServiceProfileCard();
|
||||
updateRoleVisibility();
|
||||
return state.serviceCenters;
|
||||
}
|
||||
|
||||
function renderServiceProfileCard() {
|
||||
const card = document.querySelector("#serviceProfileCard");
|
||||
if (!card) return;
|
||||
const hasCenters = state.serviceCenters.length > 0;
|
||||
card.classList.toggle("hidden", !hasCenters);
|
||||
document.querySelectorAll(".sto-only").forEach((node) => node.classList.toggle("hidden", !hasCenters));
|
||||
if (!hasCenters) return;
|
||||
const center = state.serviceCenters.find((item) => item.id === state.activeServiceCenterId) || state.serviceCenters[0];
|
||||
updateRoleVisibility();
|
||||
const centers = stoWorkplaceCenters();
|
||||
const hasWorkplace = centers.length > 0;
|
||||
card.classList.toggle("hidden", !hasWorkplace);
|
||||
if (!hasWorkplace) return;
|
||||
const center = centers.find((item) => item.id === state.activeServiceCenterId) || centers[0];
|
||||
state.activeServiceCenterId = center.id;
|
||||
const role = serviceRoleLabel(center.employee_role || "owner");
|
||||
document.querySelector("#serviceProfileTitle").textContent = center.display_name || center.name || "Рабочее место";
|
||||
document.querySelector("#serviceProfileMeta").textContent = `${role} · ${serviceStatusLabel(center.verification_status)}`;
|
||||
@@ -1394,13 +1436,12 @@ async function loadStoCalendar() {
|
||||
if (!summary || !list) return;
|
||||
try {
|
||||
if (!state.serviceCenters.length) {
|
||||
const centers = await api("/service-centers/my");
|
||||
state.serviceCenters = centers;
|
||||
await loadMyServiceCenters();
|
||||
}
|
||||
const center = state.serviceCenters[0];
|
||||
const center = stoCalendarCenters()[0];
|
||||
if (!center) {
|
||||
summary.innerHTML = "";
|
||||
list.innerHTML = `<div class="empty">СТО пока не создано</div>`;
|
||||
list.innerHTML = `<div class="empty">Календарь доступен только сотрудникам подтвержденного СТО.</div>`;
|
||||
return;
|
||||
}
|
||||
const [dashboard, appointments] = await Promise.all([
|
||||
@@ -1459,18 +1500,21 @@ async function loadMechanicWorkplace() {
|
||||
if (!centerSelect || !summary || !list) return;
|
||||
try {
|
||||
if (!state.serviceCenters.length) await loadMyServiceCenters();
|
||||
if (!state.serviceCenters.length) {
|
||||
const centers = stoWorkplaceCenters();
|
||||
if (!centers.length) {
|
||||
centerSelect.innerHTML = "";
|
||||
summary.innerHTML = "";
|
||||
list.innerHTML = `<div class="empty">Сначала зарегистрируйте СТО или примите приглашение сотрудника.</div>`;
|
||||
list.innerHTML = `<div class="empty">Рабочее место доступно владельцу подтвержденного СТО и активным механикам.</div>`;
|
||||
return;
|
||||
}
|
||||
centerSelect.innerHTML = state.serviceCenters
|
||||
.filter((center) => centers.some((item) => item.id === center.id))
|
||||
.map((center) => `<option value="${center.id}">${escapeHtml(center.display_name || center.name)}</option>`)
|
||||
.join("");
|
||||
centerSelect.value = String(state.activeServiceCenterId || state.serviceCenters[0].id);
|
||||
const selectedCenter = centers.find((item) => item.id === state.activeServiceCenterId) || centers[0];
|
||||
centerSelect.value = String(selectedCenter.id);
|
||||
const serviceCenterId = Number(centerSelect.value);
|
||||
const center = state.serviceCenters.find((item) => item.id === serviceCenterId) || state.serviceCenters[0];
|
||||
const center = centers.find((item) => item.id === serviceCenterId) || centers[0];
|
||||
state.activeServiceCenterId = serviceCenterId;
|
||||
renderServiceProfileCard();
|
||||
|
||||
@@ -2552,7 +2596,13 @@ function mountEntryForms() {
|
||||
}
|
||||
|
||||
async function openDrawerSection(sectionId, options = {}) {
|
||||
if (!canOpenDrawerSection(sectionId)) {
|
||||
toast("Этот раздел недоступен для вашей роли", "error");
|
||||
haptic("error");
|
||||
sectionId = "carsSection";
|
||||
}
|
||||
document.querySelector("#userDrawer").classList.remove("hidden");
|
||||
const drawerContent = document.querySelector(".drawer-content");
|
||||
document.querySelectorAll(".drawer-section").forEach((section) => {
|
||||
section.classList.toggle("hidden", section.id !== sectionId);
|
||||
});
|
||||
@@ -2583,11 +2633,11 @@ async function openDrawerSection(sectionId, options = {}) {
|
||||
if (sectionId === "reviewsSection") renderServiceReviews();
|
||||
if (sectionId === "adminSection") await loadAdminPendingServices();
|
||||
if (options.expenseCategory) {
|
||||
openDrawerSection("expensesSection");
|
||||
await openDrawerSection("expensesSection");
|
||||
presetExpense(options.expenseCategory);
|
||||
return;
|
||||
}
|
||||
document.querySelector(`#${sectionId}`)?.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
if (drawerContent) drawerContent.scrollTo({ top: 0, behavior: "smooth" });
|
||||
}
|
||||
|
||||
function presetExpense(category) {
|
||||
@@ -2649,6 +2699,17 @@ document.querySelectorAll("[data-menu-section]").forEach((button) => {
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-open-sto-page]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
if (!stoWorkplaceCenters().length) {
|
||||
toast("Панель СТО доступна владельцу подтвержденного СТО и активным механикам", "error");
|
||||
haptic("error");
|
||||
return;
|
||||
}
|
||||
window.location.href = "/sto.html";
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector("#mechanicCenterSelect")?.addEventListener("change", async (event) => {
|
||||
state.activeServiceCenterId = Number(event.currentTarget.value);
|
||||
await runAction(event.currentTarget, "Обновляю рабочее место...", loadMechanicWorkplace);
|
||||
|
||||
Reference in New Issue
Block a user