Refactor menu flows into dedicated pages
Some checks failed
ci / test (push) Has been cancelled

This commit is contained in:
VPN SaaS Dev
2026-05-16 11:59:09 +09:00
parent 01a69fc42d
commit ecfb5aa949
20 changed files with 2415 additions and 97 deletions

View File

@@ -1203,33 +1203,10 @@ async function openServiceCard(serviceCenterId) {
<div class="service-actions">
<button type="button" class="ghost-btn" id="attachServiceBtn">Привязать выбранное авто</button>
</div>
<form class="grid-form drawer-form" id="serviceBookingForm">
<label>
Услуга
<select name="service_type">
<option value="oil_change">Замена масла</option>
<option value="diagnostics">Диагностика</option>
<option value="maintenance">ТО</option>
<option value="tire_service">Шиномонтаж</option>
<option value="brakes">Тормоза</option>
<option value="repair">Ремонт</option>
<option value="other">Другое</option>
</select>
</label>
<label>
Дата
<input name="date" type="date" value="${today()}" />
</label>
<label>
Свободное окно
<select name="slot" id="bookingSlotSelect"></select>
</label>
<label>
Комментарий
<input name="customer_comment" placeholder="Что нужно сделать" />
</label>
<button type="submit">Записаться</button>
</form>
<div class="tip-card">
Запись вынесена на отдельную страницу: там можно выбрать автомобиль, услугу, дату и свободное окно без тесного меню.
<button type="button" class="wide-btn" data-page-link="/book_sto.html?service_center_id=${center.id}">Записаться в это СТО</button>
</div>
<form class="grid-form drawer-form" id="serviceReviewForm">
<label>
Оценка
@@ -1288,55 +1265,9 @@ async function openServiceCard(serviceCenterId) {
haptic("success");
});
});
const bookingForm = card.querySelector("#serviceBookingForm");
const reloadSlots = () => loadServiceBookingSlots(serviceCenterId, bookingForm);
bookingForm.querySelector('[name="service_type"]').addEventListener("change", reloadSlots);
bookingForm.querySelector('[name="date"]').addEventListener("change", reloadSlots);
bookingForm.addEventListener("submit", async (event) => {
event.preventDefault();
if (!state.selectedCarId) {
toast("Выбери автомобиль", "error");
return;
}
const data = formData(bookingForm);
if (!data.slot) {
toast("Выбери свободное окно", "error");
return;
}
await runAction(bookingForm.querySelector('button[type="submit"]'), "Создаю запись...", async () => {
await api("/appointments", {
method: "POST",
body: JSON.stringify({
service_center_id: serviceCenterId,
vehicle_id: state.selectedCarId,
service_type: data.service_type,
service_name: bookingServiceName(data.service_type),
requested_start_at: data.slot,
customer_comment: data.customer_comment || null,
}),
});
await loadAppointments();
toast("Заявка отправлена в СТО");
haptic("success");
});
});
await reloadSlots();
card.scrollIntoView({ behavior: "smooth", block: "start" });
}
function bookingServiceName(type) {
const names = {
oil_change: "Замена масла",
diagnostics: "Диагностика",
maintenance: "ТО",
tire_service: "Шиномонтаж",
brakes: "Тормоза",
repair: "Ремонт",
other: "Другое",
};
return names[type] || "Обслуживание";
}
function formatDateTime(value) {
if (!value) return "-";
const date = new Date(value);
@@ -1344,21 +1275,6 @@ function formatDateTime(value) {
return date.toLocaleString("ru-RU", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" });
}
async function loadServiceBookingSlots(serviceCenterId, form) {
const select = form.querySelector("#bookingSlotSelect");
const serviceType = form.querySelector('[name="service_type"]').value;
const date = form.querySelector('[name="date"]').value || today();
select.innerHTML = `<option value="">Загружаю...</option>`;
try {
const slots = await api(`/sto/${serviceCenterId}/available-slots?service_type=${encodeURIComponent(serviceType)}&date_from=${date}&date_to=${date}`);
select.innerHTML = slots.length
? slots.map((slot) => `<option value="${slot.start_at}">${formatDateTime(slot.start_at)}</option>`).join("")
: `<option value="">Нет свободных окон</option>`;
} catch (error) {
select.innerHTML = `<option value="">Слоты не загрузились</option>`;
}
}
async function loadAppointments() {
const root = document.querySelector("#appointmentsList");
if (!root) return;
@@ -2348,8 +2264,16 @@ async function applyInitialRoute() {
await loadSelectedCar();
}
if (section === "carProfile") {
await openDrawerSection("carProfileSection");
window.history.replaceState({}, "", window.location.pathname);
const target = carId ? `/car_profile.html?car_id=${carId}` : "/car_profile.html";
window.location.replace(target);
return;
}
if (section) {
const sectionId = `${section}Section`;
if (document.getElementById(sectionId)) {
await openDrawerSection(sectionId);
window.history.replaceState({}, "", window.location.pathname);
}
}
}
@@ -2789,6 +2713,13 @@ document.querySelectorAll("[data-menu-section]").forEach((button) => {
});
});
document.addEventListener("click", (event) => {
const link = event.target.closest("[data-page-link]");
if (!link) return;
event.preventDefault();
window.location.href = link.dataset.pageLink;
});
document.querySelectorAll("[data-open-sto-page]").forEach((button) => {
button.addEventListener("click", () => {
if (!stoWorkplaceCenters().length) {