/*! WEBklar Aufträge: öffentliche Bestätigungsseite (auftrag.html#t=, Rückfall ?t=). Link aus der Mail K31. * Der Token steht nur in der Adresse, in Links und im Speicher der Seite, nie in Text, Ansage, Fehlermeldung oder Protokoll. * Keine Cookies (credentials: 'omit'), kein Browserspeicher, keine Drittanfragen. Alle Texte stehen in auftrag-ansicht.js (Sie-Form) * und kommen nur über textContent in die Seite. */ import { KONTAKT, agbPfad, darfBestaetigen, pdfPfad, statusAnzeige, texte, tokenAusAdresse, zustandAusAntwort, } from './auftrag-ansicht.js' import { h, renderBestaetigtBlock, renderBestaetigung, renderDokumente, renderZusammenfassung } from './auftrag-dom.js' /** Einzige Anfrage der Seite: { status, body }; jeder Fehler des Netzes ist Status 0 (nie die Meldung des Browsers weiterreichen). */ async function anfrage(token, aktion, { method = 'GET', body } = {}) { try { const antwort = await fetch(`/api/auftrag/${encodeURIComponent(token)}${aktion ? `/${aktion}` : ''}`, { method, credentials: 'omit', headers: body ? { 'Content-Type': 'application/json' } : {}, body: body ? JSON.stringify(body) : undefined, }) const daten = await antwort.json().catch(() => ({})) return { status: antwort.status, body: daten !== null && typeof daten === 'object' ? daten : {} } } catch { return { status: 0, body: {} } } } export async function initAuftragsseite({ root, ansage, suche = '', hash = '' }) { const t = texte() const token = tokenAusAdresse(suche, hash) const sage = (text) => { ansage.textContent = text } const zeige = (zustand, ...kinder) => { root.dataset.zustand = zustand root.setAttribute('aria-busy', zustand === 'laedt' ? 'true' : 'false') root.replaceChildren(...kinder.filter(Boolean)) } const kontakt = () => h('p', { class: 'ab-kontakt' }, t.kontaktVor, ' ', h('a', { href: `mailto:${KONTAKT.email}` }, KONTAKT.email), ' oder ', h('a', { href: `tel:${KONTAKT.telefon.replace(/\D/g, '')}` }, KONTAKT.telefon), '.') function zeigeZustand({ zustand, titel, text }) { zeige(zustand, h('h1', { class: 'ab-h1', 'data-titel': true, tabindex: '-1' }, titel), h('p', { class: 'ab-text' }, text), zustand === 'limit' ? null : kontakt(), zustand === 'limit' || zustand === 'fehler' ? h('button', { type: 'button', class: 'ab-knopf', 'data-aktion': 'erneut', onclick: () => lade() }, t.erneut) : null) sage(titel) } async function senden(koerper) { const { status, body } = await anfrage(token, 'bestaetigen', { method: 'POST', body: koerper }) if (status === 200 && body.auftrag) return { ok: true, auftrag: body.auftrag } return { ok: false, status: status === 200 ? 0 : status, body } } function zeigeAuftrag(auftrag) { const bestaetigt = Boolean(auftrag.bestaetigtAm) const offen = darfBestaetigen(auftrag) const status = statusAnzeige({ ...auftrag, kannBestaetigen: offen }) zeige(bestaetigt ? 'bestaetigt' : 'offen', h('p', { class: `ab-pille ab-pille-${status.ton}` }, status.text), h('h1', { class: 'ab-h1', 'data-titel': true, tabindex: '-1' }, bestaetigt ? t.titelBestaetigt : `${t.titelOffen} ${auftrag.nummer || ''}`.trim()), bestaetigt ? null : h('p', { class: 'ab-intro' }, t.intro), renderBestaetigtBlock(auftrag), renderZusammenfassung(auftrag), h('section', { class: 'ab-abschnitt' }, h('h2', { class: 'ab-h2' }, t.unterlagen), renderDokumente({ pdfHref: pdfPfad(token), agbHref: agbPfad(auftrag.agbUrl) })), offen ? renderBestaetigung(auftrag, { senden, nachErfolg: (neu) => { zeigeAuftrag(neu) sage(t.titelBestaetigt) root.querySelector('[data-bestaetigt]')?.focus() }, nachEnde: (code, antwortBody) => zeigeZustand(zustandAusAntwort(code, antwortBody)), }) : null) } async function lade() { if (!token) { zeigeZustand(zustandAusAntwort(404, {})) return } zeige('laedt', h('p', { class: 'ab-laden' }, t.laedt)) const { status, body } = await anfrage(token, '') if (status === 200 && body.auftrag) { zeigeAuftrag(body.auftrag) sage(t.geladen) } else { zeigeZustand(zustandAusAntwort(status === 200 ? 0 : status, body)) } } await lade() } if (typeof document !== 'undefined' && document.getElementById('ab-wurzel')) { initAuftragsseite({ root: document.getElementById('ab-wurzel'), ansage: document.getElementById('ab-ansage'), suche: window.location.search, hash: window.location.hash, }) }