Add service center card interactions

This commit is contained in:
VPN SaaS Dev
2026-05-14 19:43:51 +09:00
parent caa5f6d3db
commit a83f55c646
5 changed files with 190 additions and 3 deletions

View File

@@ -318,6 +318,7 @@ const state = {
allStats: null,
analytics: null,
serviceCenters: [],
publicServiceCenters: [],
vehicleScore: null,
vehicleTimeline: [],
achievements: [],
@@ -873,20 +874,24 @@ async function loadPublicServiceCenters() {
if (!root) return;
try {
const centers = await api("/service-centers/public");
state.publicServiceCenters = centers;
root.innerHTML = centers.length
? centers
.map(
(center) => `
<div class="stack-item">
<button class="stack-item service-list-card" type="button" data-service-card="${center.id}">
<strong>${center.display_name || center.name}</strong>
<small>${[center.city, center.address].filter(Boolean).join(", ") || "Адрес не указан"}</small>
<small>${center.specializations?.join(", ") || "Специализация не указана"}</small>
<span class="trust-badge">${center.rating_avg ? `${center.rating_avg}` : "Проверка пройдена"}</span>
</div>
</button>
`,
)
.join("")
: `<div class="empty">Проверенных СТО пока нет</div>`;
root.querySelectorAll("[data-service-card]").forEach((button) => {
button.addEventListener("click", () => openServiceCard(Number(button.dataset.serviceCard)));
});
} catch (error) {
root.innerHTML = `<div class="empty">Не удалось загрузить СТО</div>`;
}
@@ -895,7 +900,102 @@ async function loadPublicServiceCenters() {
function renderServiceReviews() {
const root = document.querySelector("#serviceReviews");
if (!root) return;
root.innerHTML = `<div class="empty">Отзывы доступны в карточке проверенного СТО. Выберите сервис в разделе «СТО».</div>`;
root.innerHTML = state.publicServiceCenters.length
? state.publicServiceCenters
.map((center) => `<button class="menu-row" type="button" data-service-card="${center.id}">${center.display_name || center.name}</button>`)
.join("")
: `<div class="empty">Откройте раздел «СТО», чтобы загрузить проверенные сервисы.</div>`;
root.querySelectorAll("[data-service-card]").forEach((button) => {
button.addEventListener("click", async () => {
await openDrawerSection("publicServicesSection");
await openServiceCard(Number(button.dataset.serviceCard));
});
});
}
async function openServiceCard(serviceCenterId) {
const card = document.querySelector("#serviceCard");
if (!card) return;
const [center, reviews] = await Promise.all([
api(`/service-centers/${serviceCenterId}`),
api(`/service-centers/${serviceCenterId}/reviews?limit=20`),
]);
card.classList.remove("hidden");
card.innerHTML = `
<div class="section-head">
<div>
<p class="eyebrow">СТО</p>
<h2>${center.display_name || center.name}</h2>
</div>
<span class="trust-badge">${center.rating_avg ? `${center.rating_avg} · ${center.reviews_count}` : "Проверенный сервис"}</span>
</div>
<div class="tip-card">
<strong>${[center.city, center.address].filter(Boolean).join(", ") || "Адрес не указан"}</strong><br />
<small>${center.phone || "Телефон не указан"}</small><br />
<span>${center.description || "Описание появится после заполнения карточки сервисом."}</span>
</div>
<div class="service-actions">
<button type="button" class="ghost-btn" id="attachServiceBtn">Привязать выбранное авто</button>
</div>
<form class="grid-form drawer-form" id="serviceReviewForm">
<label>
Оценка
<select name="rating">
<option value="5">5 · Отлично</option>
<option value="4">4 · Хорошо</option>
<option value="3">3 · Нормально</option>
<option value="2">2 · Есть проблемы</option>
<option value="1">1 · Плохо</option>
</select>
</label>
<label>
Отзыв
<input name="text" placeholder="Что понравилось или что улучшить" />
</label>
<button type="submit">Оставить отзыв</button>
</form>
<div class="stack-list">
${reviews.length
? reviews.map((review) => `
<div class="stack-item">
<strong>★ ${review.rating}</strong>
<small>${review.text || "Без текста"}</small>
${review.service_response ? `<small>Ответ СТО: ${review.service_response}</small>` : ""}
</div>
`).join("")
: `<div class="empty">Отзывов еще нет</div>`}
</div>
`;
card.querySelector("#serviceReviewForm").addEventListener("submit", async (event) => {
event.preventDefault();
const form = event.currentTarget;
await runAction(form.querySelector('button[type="submit"]'), "Сохраняю...", async () => {
const data = formData(form);
await api(`/service-centers/${serviceCenterId}/reviews`, {
method: "POST",
body: JSON.stringify({ rating: Number(data.rating), text: data.text || null }),
});
await openServiceCard(serviceCenterId);
await loadPublicServiceCenters();
toast("Сохранено");
haptic("success");
});
});
card.querySelector("#attachServiceBtn").addEventListener("click", async (event) => {
if (!state.selectedCarId) {
toast("Выбери автомобиль", "error");
return;
}
await runAction(event.currentTarget, "Сохраняю...", async () => {
await api(`/service-centers/${serviceCenterId}/vehicle-links/owner-attach`, {
method: "POST",
body: JSON.stringify({ car_id: state.selectedCarId, access_level: "basic" }),
});
toast("Авто привязано к СТО");
haptic("success");
});
});
card.scrollIntoView({ behavior: "smooth", block: "start" });
}
function trustLabel(level) {