From 0a634b6e203d60fdb77282063704c7333c991b9b Mon Sep 17 00:00:00 2001 From: Anton Date: Tue, 12 May 2026 21:49:04 +0300 Subject: [PATCH] feat: rebuild questionnaire2 with radio buttons and checkboxes --- questionnaire2.html | 479 ++++++++++++++++++++++++++++++++------------ script2.js | 167 ++++++++++----- 2 files changed, 464 insertions(+), 182 deletions(-) diff --git a/questionnaire2.html b/questionnaire2.html index 15a320b..d0a94d3 100644 --- a/questionnaire2.html +++ b/questionnaire2.html @@ -3,13 +3,118 @@ - - Sunset Pass — Уточняющий опросник + Saarijärven koirapuisto — Уточняющий опросник + -
@@ -18,29 +123,22 @@
-
Saarijärven koirapuisto — Уточняющий опросник
-
- -
-
-
-
-

Заполнено: 0 из 16

+

Заполнено: 0 из 24

@@ -50,189 +148,316 @@ - -
-
-

О воротах

-
-

Вы указали: оборудования нет, нужно закупить с нуля.

+ +
+

Как работает бронирование

- - + 1. Как устроены слоты времени? +
+ + + +
- - + 2. Можно ли взять несколько часов подряд одним бронированием? +
+ + + +
+
- - + 3. Что видит клиент в календаре? +
+ + +
- - + 4. Как далеко вперёд можно бронировать? +
+ + + + + +
+
+ +
+ 5. Клиент может сам отменить бронирование через приложение? +
+ + +
- +
-
-

Об оплате

-
-

Вы указали: онлайн.

- -
- - -
+

Оплата

- - + 6. Цена за один час аренды парка (€) +
+ + + + + +
+
- - + 7. Будут ли разные тарифы? +
+ + + + + +
- - + 8. При отмене за 24+ часа — что происходит с деньгами? +
+ + + + +
-
- - -
-
-

О бронировании

-
-

Вы указали: минимум 1 час, максимум 1 день.

- - -
- -
- - + 9. Нужен ли счёт-фактура (lasku) для корпоративных клиентов? +
+ + + +
- +
-
-

О PIN-коде и уведомлениях

+

PIN-код и ворота

+

Наше приложение будет автоматически генерировать PIN и отправлять его в систему замка. Нам важно знать какую систему вы планируете установить — чтобы подключить к ней наше приложение.

+ +
+ 10. Какую систему замка/ворот планируете установить? +
+ + + + + +
+
-

Вы указали: система генерирует PIN автоматически после оплаты.

- - + 11. PIN-код — сколько цифр? +
+ + + +
- - -
- -
- - + 12. Как клиент получает PIN после оплаты? +
+ + + + +
- -
-
-

Об управлении бронированиями

+ +
+

Уведомления

+ +
+ 13. Подтверждение бронирования клиенту сразу после оплаты? +
+ + + + +
- - + 14. Напоминание клиенту перед началом слота — за сколько? +
+ + + + +
- - + 15. Предупреждение когда время заканчивается — за сколько минут? +
+ + + + +
- - + 16. Вы (Сирпа) получаете уведомление о каждом новом бронировании? +
+ + + + +
- -
-
-

Юридическое

-
-

В Финляндии по закону ЕС (GDPR) сайт обязан иметь политику конфиденциальности.

+ +
+

Ваша панель управления

-
- - +
+ 17. Что хотите видеть в своей панели? (можно несколько) +
+ + + + + + +
+
+ +
+ 18. Нужна ли история клиентов (кто бронировал раньше)? +
+ + + +
- + +
+

Формат приложения

+ +
+ 19. Какой формат приложения? + +
+ +
+ + + +
+ +
+
+ +
+ 20. Язык приложения? +
+ + + +
+
+
+ +
-
-

О дизайне

-
-

Вы указали: название Saarijärven koirapuisto, логотипа пока нет.

+

Дизайн

-
- - +
+ 21. Логотип? +
+ + + + +
-
- - +
+ 22. Цвета и стиль сайта? +
+ + + + + +
+
- -
-
-

О формате продукта

-
-

Мы можем реализовать проект в нескольких вариантах:

+ +
+

Юридическое

+

По закону ЕС (GDPR) любой финский сайт обязан иметь политику конфиденциальности и правила использования.

-
- Вариант 1 — Простой сайт (быстро, дёшево)
- Сайт на финском: календарь слотов, онлайн-оплата, PIN по email. Работает на любом телефоне через браузер. +
+ 23. Правила пользования парком — кто составляет? +
+ + + + +
-
- Вариант 2 — Продвинутый сайт (рекомендуем)
- То же + SMS-уведомления, напоминания перед концом слота, панель управления для вас (блокировка дат, просмотр бронирований, статистика). -
- -
- Вариант 3 — Сайт + мобильное приложение (максимум)
- То же + приложение для iOS и Android. PIN приходит в приложение, уведомления через приложение. Самый удобный вариант для клиентов. -
- -
- - +
+ 24. Политика конфиденциальности (GDPR) — кто составляет? +
+ + + + +
- +
-
-

Ваши контактные данные

-
+

Ваши контактные данные

@@ -249,11 +474,10 @@

После отправки мы свяжемся с вами в течение 1-2 рабочих дней.

-
- +
Предпросмотр
@@ -262,7 +486,6 @@
-
diff --git a/script2.js b/script2.js index 2d9507b..aca1d0c 100644 --- a/script2.js +++ b/script2.js @@ -1,29 +1,37 @@ -// ─── Поля прогресса ─────────────────────────────────────────────────────────── -const TRACKED_FIELDS = [ - 'gate_type','gate_electricity','gate_internet','gate_camera', - 'payment_provider','price_per_hour','price_tiers','invoice', - 'closing_time','advance_booking', - 'pin_delivery','time_warning','park_signal', - 'admin_view','block_dates','support_phone', - 'product_choice' -]; +const TOTAL = 24; -// ─── Инициализация ──────────────────────────────────────────────────────────── document.addEventListener('DOMContentLoaded', function () { updateProgress(); - updatePreview(); document.getElementById('client_email').addEventListener('input', function () { document.getElementById('_replyto').value = this.value; }); document.getElementById('_replyto').value = document.getElementById('client_email').value; + document.getElementById('questionnaireForm').addEventListener('change', function () { + updateProgress(); + updatePreview(); + handleConditionals(); + }); + document.getElementById('questionnaireForm').addEventListener('input', function () { updateProgress(); updatePreview(); }); - document.getElementById('questionnaireForm').addEventListener('submit', function () { + document.getElementById('questionnaireForm').addEventListener('submit', function (e) { + // Собрать чекбоксы в одно скрытое поле + const checked = [...document.querySelectorAll('input[name="admin_features"]:checked')].map(el => el.value); + let hidden = document.getElementById('admin_features_combined'); + if (!hidden) { + hidden = document.createElement('input'); + hidden.type = 'hidden'; + hidden.id = 'admin_features_combined'; + hidden.name = 'admin_features_combined'; + document.getElementById('questionnaireForm').appendChild(hidden); + } + hidden.value = checked.join(', '); + const now = new Date(); const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; const offsetMin = -now.getTimezoneOffset(); @@ -42,67 +50,118 @@ document.addEventListener('DOMContentLoaded', function () { }) + ' (UTC+3, Финляндия)'; }, true); - document.getElementById('btnSave').addEventListener('click', function () { - showFlash('Сохранено!'); - }); + handleConditionals(); }); -// ─── Прогресс ───────────────────────────────────────────────────────────────── -function updateProgress() { - let filled = 0; - TRACKED_FIELDS.forEach(name => { - const el = document.getElementById(name); - if (el && el.value.trim()) filled++; +function handleConditionals() { + // Показать поле "свой вариант" для радио с value="other"/"limited" + const conditionals = [ + { radio: 'price_per_hour', value: 'other', inputId: 'price_other' }, + { radio: 'lock_system', value: 'other', inputId: 'lock_other' }, + { radio: 'design_style', value: 'other', inputId: 'design_other' }, + { radio: 'multi_hour', value: 'limited', inputId: 'multi_hour_limit' }, + ]; + + conditionals.forEach(({ radio, value, inputId }) => { + const selected = document.querySelector(`input[name="${radio}"]:checked`); + const input = document.getElementById(inputId); + if (!input) return; + if (selected && selected.value === value) { + input.classList.add('visible'); + } else { + input.classList.remove('visible'); + } }); - const total = TRACKED_FIELDS.length; - const pct = Math.round((filled / total) * 100); - document.getElementById('progressFill').style.width = pct + '%'; - document.getElementById('progressText').textContent = `Заполнено: ${filled} из ${total}`; } -// ─── Предпросмотр ───────────────────────────────────────────────────────────── +function updateProgress() { + const radioGroups = [ + 'slot_type','multi_hour','calendar_view','advance_booking','self_cancel', + 'price_per_hour','price_tiers','refund_policy','invoice', + 'lock_system','pin_length','pin_delivery', + 'booking_confirm','reminder_before','time_warning','admin_notify', + 'client_history', + 'product_format','language', + 'logo','design_style', + 'terms','privacy' + ]; + + let filled = 0; + + // Радио (23 группы) + radioGroups.forEach(name => { + if (document.querySelector(`input[name="${name}"]:checked`)) filled++; + }); + + // Чекбокс (1 группа) + if (document.querySelector('input[name="admin_features"]:checked')) filled++; + + const pct = Math.round((filled / TOTAL) * 100); + document.getElementById('progressFill').style.width = pct + '%'; + document.getElementById('progressText').textContent = `Заполнено: ${filled} из ${TOTAL}`; +} + function updatePreview() { const container = document.getElementById('previewContent'); - const sections = document.querySelectorAll('.section'); + const labels = { + slot_type: 'Тип слотов', + multi_hour: 'Несколько часов подряд', + calendar_view: 'Вид календаря', + advance_booking: 'Бронирование вперёд', + self_cancel: 'Самостоятельная отмена', + price_per_hour: 'Цена за час', + price_tiers: 'Тарифы', + refund_policy: 'Возврат при отмене', + invoice: 'Счёт-фактура', + lock_system: 'Система замка', + pin_length: 'Длина PIN', + pin_delivery: 'Доставка PIN', + booking_confirm: 'Подтверждение бронирования', + reminder_before: 'Напоминание перед слотом', + time_warning: 'Предупреждение о конце', + admin_notify: 'Уведомления для вас', + client_history: 'История клиентов', + product_format: 'Формат приложения', + language: 'Язык', + logo: 'Логотип', + design_style: 'Стиль дизайна', + terms: 'Правила пользования', + privacy: 'Политика конфиденциальности', + }; + let html = ''; - sections.forEach(section => { - const title = section.querySelector('h2'); - const questions = section.querySelectorAll('.question'); - let sectionHtml = ''; - - questions.forEach(q => { - const input = q.querySelector('textarea, input[type="text"], input[type="email"], input[type="tel"]'); - const label = q.querySelector('label'); - if (!input || !label) return; - const val = input.value.trim(); - if (val) { - sectionHtml += `
-
${label.textContent.trim()}
-
${escapeHtml(val)}
-
`; - } - }); - - if (sectionHtml && title) { - html += `
-
${title.textContent.trim()}
- ${sectionHtml} + Object.entries(labels).forEach(([name, label]) => { + const checked = document.querySelector(`input[name="${name}"]:checked`); + if (checked) { + const spanText = checked.closest('label').querySelector('span')?.textContent || checked.value; + html += `
+
${label}
+
${escapeHtml(spanText)}
`; } }); + // Чекбоксы + const checkedBoxes = [...document.querySelectorAll('input[name="admin_features"]:checked')]; + if (checkedBoxes.length > 0) { + const vals = checkedBoxes.map(el => el.closest('label').querySelector('span')?.textContent || el.value).join(', '); + html += `
+
Панель управления
+
${escapeHtml(vals)}
+
`; + } + container.innerHTML = html || '

Начните заполнять форму — здесь появится предпросмотр

'; } -// ─── Flash ──────────────────────────────────────────────────────────────────── +function escapeHtml(str) { + return str.replace(/&/g,'&').replace(//g,'>'); +} + function showFlash(msg) { const el = document.getElementById('flash'); el.textContent = msg; el.classList.add('show'); setTimeout(() => el.classList.remove('show'), 2500); } - -function escapeHtml(str) { - return str.replace(/&/g,'&').replace(//g,'>'); -}