document.addEventListener('DOMContentLoaded', function () { const serviceSelect = document.getElementById('service'); const itemsContainer = document.getElementById('serviceItems'); const reparaturBox = document.getElementById('reparatur-box'); const reparaturListe = document.getElementById('reparatur-liste'); const priceContainer = document.getElementById('preis-gesamt'); const anfahrtSelect = document.getElementById('anfahrt'); const abholungHinweis = document.getElementById('abholung-hinweis'); const abholungZeitfenster = document.getElementById('abholung-zeitfenster'); const abholdatumSelect = document.getElementById('abholdatum'); const abholzeitSelect = document.getElementById('abholzeit'); const biketypSelect = document.getElementById('biketyp'); const katCity = document.getElementById('kat-city'); const katGravel = document.getElementById('kat-gravel'); const kategorieBox = document.getElementById('kategorie-box'); const preisHidden = document.getElementById('preis_gesamt_hidden'); const feedbackBox = document.getElementById('feedback'); let additionalPickupCost = 0; let servicesList = []; let pakete = {}; let lastBase = 0; let reservierungen = {}; fetch("https://luigivelo.ch/assets/reservierungen.json") .then(res => res.json()) .then(data => { reservierungen = data; }) .catch(() => { reservierungen = {}; }); function updateFinalPrice(base) { lastBase = base; const total = base + additionalPickupCost; priceContainer.textContent = `Geschätzter Preis: CHF ${total}`; if (preisHidden) preisHidden.value = total; } function updateTotal(base = 0) { let total = base; document.querySelectorAll('#reparatur-liste input').forEach(input => { const preis = parseFloat(input.dataset.price); if (input.type === 'number') { const menge = Math.min(parseInt(input.value || 0), parseInt(input.max)); total += preis * menge; } else if (input.checked) { total += preis; } }); updateFinalPrice(total); } function handleServiceChange() { const selected = serviceSelect.value; const paketName = selected; itemsContainer.innerHTML = ''; reparaturListe.innerHTML = ''; reparaturBox.style.display = 'none'; priceContainer.textContent = ''; document.getElementById("serviceDauer").style.display = 'none'; let base = 0; if (selected) { document.getElementById('abholung-box').style.display = 'block'; } if (paketName && pakete[paketName]) { const paket = pakete[paketName]; const ids = paket.leistungen || []; const dauer = paket.dauer || null; const ul = document.createElement('ul'); ids.forEach(id => { const item = servicesList.find(s => s.id === id); if (item) { const li = document.createElement('li'); li.textContent = item.name; ul.appendChild(li); base += item.preis; } }); itemsContainer.appendChild(ul); if (dauer) { const dauerBox = document.getElementById("serviceDauer"); dauerBox.style.display = 'block'; dauerBox.textContent = `Dauer: ca. ${dauer} Arbeitstage`; } updateFinalPrice(paket.preis || Math.round(base * 0.8)); return; } if (selected === 'Reparatur') { reparaturBox.style.display = 'block'; const grouped = {}; for (const s of servicesList) { if (!s.system) continue; if (!grouped[s.system]) grouped[s.system] = []; grouped[s.system].push(s); } const sortedSystems = Object.keys(grouped).sort((a, b) => a.localeCompare(b, 'de') ); sortedSystems.forEach(system => { const h2 = document.createElement('h2'); h2.textContent = system.charAt(0).toUpperCase() + system.slice(1); h2.className = 'system-heading'; reparaturListe.appendChild(h2); grouped[system].forEach((service, idx) => { if (/hinten/.test(service.name)) return; const wrapper = document.createElement('div'); wrapper.className = idx % 2 === 0 ? 'row-even' : 'row-odd'; const label = document.createElement('label'); let name = service.name.replace(/\(vorne\)/i, '').trim(); label.textContent = `(${service.id}) ${name} – CHF ${service.preis}`; if (service.multiplicable) { const input = document.createElement('input'); input.type = 'number'; input.min = 0; input.max = 2; input.value = 0; input.dataset.price = service.preis; input.addEventListener('input', () => updateTotal(0)); wrapper.appendChild(label); wrapper.appendChild(document.createElement('br')); wrapper.appendChild(input); } else { const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.dataset.price = service.preis; checkbox.addEventListener('change', () => updateTotal(0)); wrapper.appendChild(checkbox); wrapper.appendChild(label); } reparaturListe.appendChild(wrapper); }); }); } } fetch('assets/services.json') .then(res => res.json()) .then(data => { servicesList = data.services || []; pakete = data.pakete || {}; serviceSelect.addEventListener('change', handleServiceChange); // Activar selección automática por URL (s01/s02/reparatur) const urlParams = new URLSearchParams(window.location.search); const preselected = urlParams.get("typ"); if (preselected) { const map = { "reparatur": "Reparatur", "s01": "Service – Velo mit Felgenbremsen", "s02": "Service – Velo mit Scheibenbremsen" }; const match = map[preselected.toLowerCase()]; if (match) { serviceSelect.value = match; handleServiceChange(); } } }) .catch(err => { console.error("Fehler beim Laden von services.json", err); feedbackBox.textContent = "Warnung: Services konnten nicht geladen werden."; }); if (anfahrtSelect) { anfahrtSelect.addEventListener('change', function () { const selected = anfahrtSelect.value; if (selected === 'abholen') { additionalPickupCost = 40; abholungHinweis.style.display = 'block'; abholungZeitfenster.style.display = 'block'; abholdatumSelect.required = true; abholzeitSelect.required = true; populatePickupDates(); } else { additionalPickupCost = 0; abholungHinweis.style.display = 'none'; abholungZeitfenster.style.display = 'none'; abholdatumSelect.required = false; abholzeitSelect.required = false; } if (serviceSelect.value === 'Reparatur') { updateTotal(0); } else { updateFinalPrice(lastBase); } }); } function populatePickupDates() { abholdatumSelect.innerHTML = ''; const today = new Date(); for (let i = 2; i <= 14; i++) { const d = new Date(); d.setDate(today.getDate() + i); const day = d.getDay(); if (day === 1 || day === 3) { const iso = d.toISOString().split('T')[0]; const label = d.toLocaleDateString('de-CH', { weekday: 'long', day: '2-digit', month: '2-digit' }); const opt = document.createElement('option'); opt.value = iso; opt.textContent = label; abholdatumSelect.appendChild(opt); } } abholdatumSelect.addEventListener('change', updateAvailableTimesForPickupDate); } function updateAvailableTimesForPickupDate() { const dateStr = abholdatumSelect.value; if (!dateStr) return; const selectedDate = new Date(dateStr); const weekday = selectedDate.getDay(); const bereits = reservierungen[dateStr] || []; const zeiten = []; function verfuegbar(code) { return bereits.filter(z => z === code).length < 2; } if (weekday === 1) { if (verfuegbar("nachmittag1")) zeiten.push(["14:00–16:00", "nachmittag1"]); if (verfuegbar("nachmittag2")) zeiten.push(["16:00–18:00", "nachmittag2"]); } if (weekday === 3) { if (verfuegbar("morgen1")) zeiten.push(["08:00–10:00", "morgen1"]); if (verfuegbar("morgen2")) zeiten.push(["10:00–12:00", "morgen2"]); if (verfuegbar("nachmittag1")) zeiten.push(["14:00–16:00", "nachmittag1"]); if (verfuegbar("nachmittag2")) zeiten.push(["16:00–18:00", "nachmittag2"]); } abholzeitSelect.innerHTML = ''; if (zeiten.length === 0) { const opt = document.createElement("option"); opt.disabled = true; opt.textContent = "Keine freien Slots"; abholzeitSelect.appendChild(opt); } else { zeiten.forEach(([label, value]) => { const opt = document.createElement("option"); opt.value = value; opt.textContent = label; abholzeitSelect.appendChild(opt); }); } } if (biketypSelect) { biketypSelect.addEventListener('change', function () { const selected = biketypSelect.value; if (selected === 'normal') { kategorieBox.style.display = 'block'; katCity.style.display = 'block'; katGravel.style.display = 'none'; } else if (selected === 'ebike') { kategorieBox.style.display = 'block'; katCity.style.display = 'none'; katGravel.style.display = 'block'; } else { kategorieBox.style.display = 'none'; katCity.style.display = 'none'; katGravel.style.display = 'none'; } }); } const formElement = document.getElementById("terminForm"); if (formElement) { formElement.addEventListener("submit", function (e) { e.preventDefault(); feedbackBox.textContent = "Bitte warten ..."; grecaptcha.enterprise.ready(function () { grecaptcha.enterprise.execute("6LdCpWMrAAAAAFC4UjlljOScqP7wNFjf0ol6awVf", { action: "submit" }).then(function (token) { enviarFormulario(token); }); }); }); } function enviarFormulario(recaptchaToken) { const form = new FormData(document.getElementById("terminForm")); const formData = Object.fromEntries(form.entries()); if (!formData.service) { feedbackBox.textContent = "Bitte wähle eine Serviceart aus."; return; } const reparatur = []; const reparatur_quantities = {}; document.querySelectorAll("#reparatur-liste input").forEach(input => { const label = input.parentElement.querySelector("label")?.textContent?.split("–")[0]?.trim(); const preis = parseFloat(input.dataset.price); if (input.type === "checkbox" && input.checked) { reparatur.push(label); reparatur_quantities[label] = { preis, menge: 1 }; } else if (input.type === "number" && parseInt(input.value || 0) > 0) { reparatur.push(label); reparatur_quantities[label] = { preis, menge: parseInt(input.value) }; } }); const payload = { recaptchaToken, formData: { ...formData, reparatur, reparatur_quantities, } }; fetch("https://cc32uqjel8.execute-api.eu-central-1.amazonaws.com/version2/formular", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }) .then(res => res.json()) .then(data => { feedbackBox.textContent = data.message || "Danke! Bitte E-Mail bestätigen."; window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'form_termin_submitted', preis_gesamt: preisHidden?.value || 0, service: formData.service }); }) .catch(err => { feedbackBox.textContent = "Fehler beim Senden. Bitte später erneut versuchen."; }); } });