Files
Webklar-Kundenbereich/public/auftrag-portal.js
T

85 lines
3.9 KiB
JavaScript

/* Abschnitt „Aufträge“ im Reiter Rechnungen des Kundenportals (geladen von app.js, loadCustomerOrders; request ist api aus app.js).
Kundentext kommt nur über textContent in die Seite. Alle Texte stehen in auftrag-ansicht.js; das Portal spricht in der Du-Form. */
import {
ANREDE_DU, agbPfad, darfBestaetigen, kartenMeta, sortiereAuftraege, statusAnzeige, texte,
} from './auftrag-ansicht.js'
import {
h, renderBestaetigtBlock, renderBestaetigung, renderDokumente, renderZusammenfassung,
} from './auftrag-dom.js'
export async function initAuftraege({ section, body, invoicesTitle, request, viewAs = false } = {}) {
if (!section || !body || typeof request !== 'function') return { sichtbar: false }
const t = texte(ANREDE_DU)
let eintraege = []
/** Bestätigen darf, wer der Server dafür freigibt; in der Kundenansicht zeigt die Oberfläche die offene AB mit gesperrtem Formular. */
const wirksam = (e) => darfBestaetigen(e) && (viewAs || e.kannBestaetigen === true)
async function ladeListe() {
const daten = await request('/api/auftraege')
if (daten?.aktiv !== true || !Array.isArray(daten.auftraege)) return []
return daten.auftraege.filter((e) => e && typeof e.id === 'string' && e.id !== '')
}
function karte(auftrag, offeneId) {
const kann = wirksam(auftrag)
const status = statusAnzeige({ ...auftrag, kannBestaetigen: kann })
const pfad = `/api/auftraege/${encodeURIComponent(auftrag.id)}`
async function senden(koerper) {
try {
const antwort = await request(`${pfad}/bestaetigen`, { method: 'POST', body: JSON.stringify(koerper) })
return antwort?.auftrag ? { ok: true, auftrag: antwort.auftrag } : { ok: false, status: 0, body: {} }
} catch (err) {
return { ok: false, status: Number(err?.status) || 0, body: { error: String(err?.message ?? '') } }
}
}
function nachErfolg(neu) {
eintraege = eintraege.map((alt) => (alt.id === auftrag.id ? { ...alt, ...neu, id: alt.id, kannBestaetigen: false } : alt))
zeichne(auftrag.id)
body.querySelector(`[data-auftrag="${CSS.escape(auftrag.id)}"] [data-bestaetigt]`)?.focus()
}
async function nachEnde() {
try {
eintraege = await ladeListe()
zeichne('')
} catch {
/* die Anzeige bleibt stehen */
}
}
return h('article', { class: 'ab-karte', 'data-auftrag': auftrag.id, 'data-status': auftrag.status || '' },
h('div', { class: 'ab-karte-kopf' },
h('div', null,
h('p', { class: 'ab-karte-nummer' }, h('strong', null, auftrag.nummer || '')),
auftrag.titel ? h('p', { class: 'ab-karte-titel' }, auftrag.titel) : null,
h('p', { class: 'ab-karte-meta' }, kartenMeta(auftrag))),
h('span', { class: `ab-pille ab-pille-${status.ton}` }, status.text)),
h('div', { class: 'ab-karte-aktionen' },
h('a', { class: 'ab-link', 'data-link': 'pdf', href: `${pfad}/pdf`, target: '_blank', rel: 'noopener noreferrer' }, t.kartePdf)),
h('details', { class: 'ab-details', open: kann || auftrag.id === offeneId },
h('summary', null, kann ? t.karteDetailsBestaetigen : t.karteDetails),
renderZusammenfassung(auftrag, { ebene: 4 }),
renderDokumente({ agbHref: agbPfad(auftrag.agbUrl) }),
renderBestaetigtBlock(auftrag, { anrede: ANREDE_DU }),
kann
? renderBestaetigung(auftrag, { senden, nachErfolg, nachEnde, gesperrt: viewAs ? t.ansichtsmodus : '', anrede: ANREDE_DU })
: null))
}
function zeichne(offeneId) {
body.replaceChildren(...sortiereAuftraege(eintraege.map((e) => ({ ...e, kannBestaetigen: wirksam(e) }))).map((e) => karte(eintraege.find((x) => x.id === e.id), offeneId)))
}
try {
eintraege = await ladeListe()
} catch {
return { sichtbar: false }
}
if (!eintraege.length) return { sichtbar: false }
zeichne('')
section.classList.remove('hidden')
invoicesTitle?.classList.remove('hidden')
return { sichtbar: true }
}