// Oeffentliche Erklaerungsseiten: Kuendigung (§ 312k BGB) und Widerruf (§ 356a BGB). // Ohne Login erreichbar, Formular sofort sichtbar (keine Zwischenschritte). // Der Kunde waehlt den Vertrag (Kuendigung: Abo oder nur der Zusatzspeicher, ganz oder mit Paketzahl) bzw. die // Bestellung (Widerruf: Abschluss, Wechsel, Zusatzspeicher); die Auswahl geht in den Request und steht in der // Bestaetigung. Nach dem Absenden: Bestaetigung mit Datum/Uhrzeit, speicher- und druckbar. function initLegalForm({ endpoint, fields }) { const form = document.getElementById('decl-form') const done = document.getElementById('done') const errEl = document.getElementById('form-error') const esc = (s) => String(s || '').replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c]) // Angemeldete Kunden nicht erneut identifizieren lassen: Felder vorbefuellen fetch('/api/auth/me', { credentials: 'same-origin' }) .then((r) => (r.ok ? r.json() : null)) .then((me) => { const c = me?.customer if (!c) return if (form.elements.name && !form.elements.name.value) form.elements.name.value = c.name || '' if (form.elements.email && !form.elements.email.value) form.elements.email.value = c.email || '' if (form.elements.customerNumber && !form.elements.customerNumber.value) form.elements.customerNumber.value = c.code || '' }) .catch(() => {}) const reasonWrap = document.getElementById('reason-wrap') form.querySelectorAll('[name="kind"]').forEach((r) => r.addEventListener('change', () => reasonWrap?.classList.toggle('hidden', form.elements.kind.value !== 'ausserordentlich')) ) const dateInput = document.getElementById('effective-date') form.querySelectorAll('[name="when"]').forEach((r) => r.addEventListener('change', () => { const onDate = form.elements.when.value === 'datum' dateInput?.classList.toggle('hidden', !onDate) if (onDate) dateInput?.focus() }) ) // Nur der Zusatzspeicher: Paketzahl abfragen; der Zeitpunkt entfaellt (Ende des Abrechnungsmonats) const storageOnly = () => form.elements.contract?.value === 'zusatzspeicher' const packagesWrap = document.getElementById('packages-wrap') const whenWrap = document.getElementById('when-wrap') form.querySelectorAll('[name="contract"]').forEach((r) => r.addEventListener('change', () => { packagesWrap?.classList.toggle('hidden', !storageOnly()) whenWrap?.classList.toggle('hidden', storageOnly()) }) ) form.addEventListener('submit', async (ev) => { ev.preventDefault() errEl.classList.add('hidden') const payload = {} for (const f of fields) payload[f] = String(form.elements[f]?.value ?? '').trim() if (form.elements.when?.value === 'datum' && !storageOnly()) payload.effective = dateInput?.value || '' if (form.elements.contract && !storageOnly()) delete payload.packages const btn = form.querySelector('button[type="submit"]') btn.disabled = true try { const res = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }) const data = await res.json().catch(() => ({})) if (!res.ok) throw new Error(data.error || `Fehler ${res.status}`) const at = new Date(data.receivedAt).toLocaleString('de-DE', { dateStyle: 'full', timeStyle: 'medium' }) document.getElementById('done-at').textContent = at // Zeile "Vertrag": die gewaehlte Beschriftung (data-text des Radioknopfs) statt eines festen Namens const rows = [] for (const f of fields) { if (f === 'effective') continue if (f === 'packages') { if (storageOnly()) rows.push(['Pakete', payload.packages ? `${payload.packages} Paket(e) zu je 5 GB` : 'alle gebuchten Pakete']) continue } if (!payload[f]) continue const label = form.querySelector(`[data-label-for="${f}"]`)?.dataset.label || f const value = form.querySelector(`[name="${f}"]:checked`)?.dataset.text || payload[f] rows.push([label, value]) } if (form.elements.when) { rows.push(['Zeitpunkt', storageOnly() ? 'zum Ende des laufenden Abrechnungsmonats' : payload.effective ? `zum ${new Date(payload.effective + 'T12:00:00').toLocaleDateString('de-DE')} (Ende des dann laufenden Abrechnungsmonats)` : 'zum nächstmöglichen Zeitpunkt']) } document.getElementById('done-list').innerHTML = rows.map(([k, v]) => `
${esc(k)}
${esc(v)}
`).join('') form.classList.add('hidden') done.classList.remove('hidden') window.scrollTo({ top: 0, behavior: 'smooth' }) } catch (err) { errEl.textContent = err.message errEl.classList.remove('hidden') btn.disabled = false } }) document.getElementById('print-btn')?.addEventListener('click', () => window.print()) }