Files
Webklar-Kundenbereich/public/neu/bestell-bausteine.js
T

92 lines
4.4 KiB
JavaScript

/* Kundenansicht neu (P7): gemeinsame Bausteine der vier Bestellseiten (Abo bestellen, Wechsel, Zusatzspeicher, Gutschrift-Antrag).
Die Sätze kommen vom Server (GET /api/abo → bestelltexte); hier werden sie nur gezeichnet. Link-Texte stehen in der Vorlage in
eckigen Klammern, ihre Adressen daneben in urls. Jede Adresse läuft durch sicherLink; Kundentext wird nie als HTML gelesen.
Keine h1: den Titel meldet die Ansicht mit meldeTitel. */
import { h } from './dom.js'
import { K } from './ansicht-hilfen.js'
/** 'unternehmen' | 'privat': nur exakt 'unternehmen' (me.customer.kundenartWirksam, sonst daten.kundenart) ist Betrieb; alles andere privat (E4). */
export function kundenartVon(me, daten = null) {
return me?.customer?.kundenartWirksam === 'unternehmen' || daten?.kundenart === 'unternehmen' ? 'unternehmen' : 'privat'
}
/** Adresse nur, wenn sie ein Pfad auf derselben Herkunft ('/…', nicht '//…'), ein Anker ('#name…') oder http(s) ohne Zugangsdaten ist; sonst ''. */
export function sicherLink(url) {
if (typeof url !== 'string' || url === '') return ''
if (/[\s\u0000-\u001f\u007f\\]/.test(url)) return ''
if (/^\/(?![/\\])/.test(url)) return url
if (/^#[a-z][\w-]*(\?[\w=&.%-]*)?$/i.test(url)) return url
if (/^https?:\/\/[^/?#]+/i.test(url)) {
try {
const u = new URL(url)
return u.hostname !== '' && u.username === '' && u.password === '' ? url : ''
} catch {
return ''
}
}
return ''
}
/**
* 'Es gilt [A] und [B].' mit ['/a', '/b'] → Teile [{ text }, { text, href? }]. Die Markierungen bekommen der Reihe nach ihre Adresse;
* eine unsichere oder fehlende Adresse macht den Teil zu einem Teil ohne href. Eine offene Klammer bleibt Text.
*/
export function linkTeile(text, urls) {
const basis = typeof text === 'string' ? text : ''
const adressen = Array.isArray(urls) ? urls : []
const teile = []
let ab = 0
let nr = 0
const muster = /\[([^\]]*)\]/g
for (let m = muster.exec(basis); m; m = muster.exec(basis)) {
if (m.index > ab) teile.push({ text: basis.slice(ab, m.index) })
const href = sicherLink(adressen[nr])
nr += 1
teile.push(href ? { text: m[1], href } : { text: m[1] })
ab = m.index + m[0].length
}
if (ab < basis.length) teile.push({ text: basis.slice(ab) })
return teile
}
const ausserhalb = (href) => !href.startsWith('#')
/** <p id> mit den Links der Vorlage; '/…' und http(s) öffnen in neuem Tab (target _blank, rel noopener), '#…' bleibt im Fenster. */
export function baueLinkzeile({ text, urls } = {}, { id } = {}) {
const kinder = linkTeile(text, urls).map((t) =>
t.href ? h('a', { href: t.href, ...(ausserhalb(t.href) ? { target: '_blank', rel: 'noopener' } : {}) }, t.text) : t.text)
return h('p', { id, class: 'kn-linkzeile' }, kinder)
}
/** <p id>: „Du bestellst als Betrieb“ | „Du bestellst privat“, ' · ', dann der Hinweis zur Korrektur mit seinem Link. */
export function baueKundenartZeile(kundenart, texte, { id } = {}) {
const lage = kundenart === 'unternehmen' ? texte?.unternehmen : texte?.privat
const korrektur = linkTeile(texte?.korrektur?.text, texte?.korrektur?.urls).map((t) =>
t.href ? h('a', { href: t.href, ...(ausserhalb(t.href) ? { target: '_blank', rel: 'noopener' } : {}) }, t.text) : t.text)
return h('p', { id, class: 'kn-kundenart-zeile' }, lage, ' · ', korrektur)
}
/** Block „Was du bestellst“: zeilen [{ id?, label, text }] als Beschriftungsliste. Der Text ist immer Text. */
export function baueBlock(zeilen, { id } = {}) {
return h('dl', { id, class: 'kn-block' }, (zeilen || []).map((z) => h('div', { class: 'kn-block-zeile' }, h('dt', null, z.label), h('dd', { id: z.id }, z.text))))
}
const nichtLeer = (x) => typeof x === 'string' && x !== ''
/**
* true, wenn die Antwort den Wortlaut trägt: status, knopf und die Sätze der Seite (art 'abo' | 'wechsel' | 'speicher' | 'gutschrift').
* Ohne ihn zeigt keine Seite einen Bestellknopf.
*/
export function hatWortlaut(daten, art = 'abo') {
const t = daten?.bestelltexte
if (!t || typeof t !== 'object' || !nichtLeer(t.status) || !nichtLeer(t.knopf)) return false
if (art === 'gutschrift') return nichtLeer(t.gutschrift?.satz?.text) && nichtLeer(t.gutschrift?.knopf)
if (!nichtLeer(t[art]?.linkzeile?.text)) return false
if (art === 'wechsel') return nichtLeer(t.wechsel.haken) && nichtLeer(t.wechsel.gesperrt)
if (art === 'abo') return nichtLeer(t.abo.haken)
return true
}
export { K }