Add service center card interactions
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -1167,6 +1167,39 @@ button.is-busy {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.service-list-card,
|
||||
.service-card {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.service-list-card {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
min-height: auto;
|
||||
padding: 12px;
|
||||
color: var(--text);
|
||||
background: var(--soft);
|
||||
border: 1px solid var(--line);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.service-card {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
margin-top: 12px;
|
||||
padding: 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.service-actions {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.summary-card::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user