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.";
});
}
});