Kundenansicht neu E-Fix F1 (Nachkorrektur): Widerrufsstreifen auf den Bestellseiten ausgeblendet
Auf Abo bestellen, Wechsel, Zusatzspeicher und Übernahmegutschrift fehlt der feste Widerrufsstreifen, damit Kerninfo und Knopf "Zahlungspflichtig bestellen" auch bei Privatkunden in laufender Frist auf 375x667 auf einem Bildschirm stehen (Spec Abschnitt 4). Auf den Hauptseiten bleibt er (Spec 5.2), "Vertrag widerrufen" bleibt im Konto und unter Verträge erreichbar. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c5f1d9545c
commit
5cd49d6a4a
6 files changed
+84
-13
No files matched your search
@@ -41,22 +41,33 @@ export function fruehesteFrist(daten) {
|
||||
return zeiten.sort((a, b) => Date.parse(a) - Date.parse(b))[0] ?? ''
|
||||
}
|
||||
|
||||
/** Streifen in `wurzel` füllen: setze(daten) zeigt ihn, setze(null) versteckt ihn. Am Körper steht `kn-hat-streifen`, solange er sichtbar ist. */
|
||||
/**
|
||||
* Streifen in `wurzel` füllen: setze(daten) nimmt die Fristen (null: keine), erlaube(ok) sagt, ob die gezeigte Seite den Streifen tragen darf
|
||||
* (nicht die Bestellseiten, siehe zeigtWiderrufsstreifen). Sichtbar ist er nur mit Fristen auf einer erlaubten Seite; am Körper steht dann `kn-hat-streifen`.
|
||||
*/
|
||||
export function baueStreifen(wurzel, { koerper = document.body } = {}) {
|
||||
wurzel.classList.add('kn-streifen')
|
||||
wurzel.setAttribute('role', 'region')
|
||||
wurzel.setAttribute('aria-label', 'Widerrufsfrist')
|
||||
let stand = null
|
||||
let erlaubt = true
|
||||
const zeichne = () => {
|
||||
leeren(wurzel)
|
||||
if (!stand || !erlaubt) {
|
||||
wurzel.hidden = true
|
||||
koerper.classList.remove('kn-hat-streifen')
|
||||
return
|
||||
}
|
||||
wurzel.append(streifenText(fruehesteFrist(stand)), ' · ', h('a', { class: 'kn-streifen-link', href: '/widerrufen.html' }, 'Widerrufen'))
|
||||
wurzel.hidden = false
|
||||
koerper.classList.add('kn-hat-streifen')
|
||||
}
|
||||
return {
|
||||
setze(daten) {
|
||||
leeren(wurzel)
|
||||
if (!daten) {
|
||||
wurzel.hidden = true
|
||||
koerper.classList.remove('kn-hat-streifen')
|
||||
return
|
||||
}
|
||||
wurzel.append(streifenText(fruehesteFrist(daten)), ' · ', h('a', { class: 'kn-streifen-link', href: '/widerrufen.html' }, 'Widerrufen'))
|
||||
wurzel.hidden = false
|
||||
koerper.classList.add('kn-hat-streifen')
|
||||
setze(daten) { stand = daten || null; zeichne() },
|
||||
erlaube(ok) {
|
||||
if ((ok !== false) === erlaubt) return
|
||||
erlaubt = ok !== false
|
||||
zeichne()
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
import { h, leeren, text } from './dom.js'
|
||||
import { api as apiStandard } from './api.js'
|
||||
import * as routerStandard from './router.js'
|
||||
import { BEREICHE, FUNKTIONS_ETAGEN, hashFuerAnsicht, hashFuerRoute, elternVon, titelFuer } from './routen.js'
|
||||
import { BEREICHE, FUNKTIONS_ETAGEN, hashFuerAnsicht, hashFuerRoute, elternVon, titelFuer, zeigtWiderrufsstreifen } from './routen.js'
|
||||
import { HANDY_ABFRAGE, baueNavigation, beobachteTastatur, leisteSichtbar } from './leiste.js'
|
||||
import { baueEtage } from './etage.js'
|
||||
import { erzeugeZaehler } from './zaehler.js'
|
||||
@@ -192,6 +192,7 @@ export async function starteHuelle({ win = window, doc = document, api = apiStan
|
||||
} else etage.schliesse()
|
||||
navigation.setzeAktiv(route.bereich)
|
||||
navigation.setzeEtage(Boolean(route.etage))
|
||||
streifen.erlaube(zeigtWiderrufsstreifen(route)) // Bestellseiten: Kerninfo und Knopf auf einem Bildschirm, ohne den festen Streifen
|
||||
text(el('kn-kopf-titel'), titel)
|
||||
text(el('kn-ansage'), titel)
|
||||
if (route.bereich === 'chat') zaehler.setzeChat(0)
|
||||
|
||||
@@ -106,3 +106,17 @@ export function elternVon(route, herkunft = '') {
|
||||
export function titelFuer(route) {
|
||||
return TITEL_ETAGE[route.etage] ?? TITEL_BEREICH[route.bereich] ?? ''
|
||||
}
|
||||
|
||||
/** Etagen, auf denen etwas bestellt wird: Abo bestellen, Wechsel und die Übernahmegutschrift. Dazu der Reiter E-Mail der Verträge (Zusatzspeicher). */
|
||||
const BESTELL_ETAGEN = ['bestellen', 'wechsel', 'gutschrift']
|
||||
|
||||
/**
|
||||
* Steht auf dieser Seite der Widerrufsstreifen? Nicht auf den Bestellseiten: Dort müssen Kerninfo und Knopf „Zahlungspflichtig bestellen“ auf einem
|
||||
* Bildschirm stehen (Spec Abschnitt 4), und der feste Streifen nähme am Handy 44 px davon weg. Er gehört auf die Hauptseiten (Spec 5.2);
|
||||
* „Vertrag widerrufen“ bleibt im Konto und unter Verträge erreichbar. Ohne Route: ja.
|
||||
*/
|
||||
export function zeigtWiderrufsstreifen(route) {
|
||||
if (!route) return true
|
||||
if (BESTELL_ETAGEN.includes(route.etage)) return false
|
||||
return !(route.bereich === 'vertraege' && route.reiter === 'email')
|
||||
}
|
||||
@@ -47,3 +47,18 @@ test('Streifen: ohne gültiges Datum steht ein allgemeiner Text, mehrere Fristen
|
||||
assert.deepEqual([w.getAttribute('role'), w.getAttribute('aria-label'), w.classList.contains('kn-streifen')], ['region', 'Widerrufsfrist', true])
|
||||
} finally { fx.restore() }
|
||||
})
|
||||
|
||||
test('baueStreifen.erlaube: auf Bestellseiten versteckt, Körperklasse weg; ein neuer Stand erscheint dort nicht, danach zeigt er den letzten Stand', () => {
|
||||
const fx = installFakeDom()
|
||||
try {
|
||||
const w = h('div', { hidden: true }); const s = baueStreifen(w)
|
||||
const sichtbar = () => [w.hidden, fx.document.body.classList.contains('kn-hat-streifen')]
|
||||
s.setze(FRIST); assert.deepEqual(sichtbar(), [false, true])
|
||||
s.erlaube(false); assert.deepEqual([...sichtbar(), fx.text(w)], [true, false, '']) // Bestellseite: weg, auch der Platz unten
|
||||
s.setze({ ...FRIST, fruehestesEnde: '2026-10-30T10:00:00Z' }); assert.deepEqual(sichtbar(), [true, false]) // ein Neuladen der Fristen bringt ihn dort nicht zurück
|
||||
s.erlaube(true); assert.deepEqual([...sichtbar(), fx.text(w)], [false, true, 'Widerrufsfrist bis 30.10. · Widerrufen']) // zurück auf einer Hauptseite
|
||||
s.setze(null); s.erlaube(false); s.erlaube(true); assert.deepEqual(sichtbar(), [true, false]) // ohne Frist bleibt er in jedem Fall weg
|
||||
const wt = h('div', { hidden: true }); const t = baueStreifen(wt); t.erlaube(false); t.setze(FRIST) // erst die Seite, dann die Daten
|
||||
assert.deepEqual([wt.hidden, fx.document.body.classList.contains('kn-hat-streifen')], [true, false])
|
||||
} finally { fx.restore() }
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
import { test } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { BEREICHE, ROUTEN, routeAusHash, hashFuerRoute, hashFuerAnsicht, startHash, ankerKette, elternVon, titelFuer } from '../public/neu/routen.js'
|
||||
import { BEREICHE, ROUTEN, routeAusHash, hashFuerRoute, hashFuerAnsicht, startHash, ankerKette, elternVon, titelFuer, zeigtWiderrufsstreifen } from '../public/neu/routen.js'
|
||||
|
||||
const FAELLE = [ // Alte Links (Review Focus 1)
|
||||
['', { bereich: 'website', query: '' }],
|
||||
@@ -59,3 +59,15 @@ test('ankerKette, elternVon, titelFuer', () => {
|
||||
assert.deepEqual(elternVon(r('#passwort'), '#chat'), { bereich: 'chat', query: '' }); assert.equal(elternVon(r('#passwort')).bereich, 'website'); assert.equal(elternVon(r('#chat')), null)
|
||||
assert.deepEqual(['#termine', '#zeiten', '#bestellen-wartung', '#passwort', '#chat'].map((h) => titelFuer(r(h))), ['Terminplaner', 'Öffnungszeiten', 'Abo bestellen', 'Passwort ändern', 'Chat'])
|
||||
})
|
||||
|
||||
// E-Fix F1 (Nachkorrektur): Auf den Bestellseiten stehen Kerninfo und Knopf auf einem Bildschirm; der Widerrufsstreifen gehört auf die Hauptseiten (Spec 5.2)
|
||||
test('zeigtWiderrufsstreifen: nicht auf Abo bestellen, Wechsel, Zusatzspeicher und Gutschrift; auf allen anderen Seiten schon', () => {
|
||||
const ohne = ['#bestellen-wartung', '#bestellen-hosting', '#wechsel', '#speicher', '#gutschrift', '#wechsel?x=1', '#bestellen-hosting?abo=cancel']
|
||||
for (const hash of ohne) assert.equal(zeigtWiderrufsstreifen(routeAusHash(hash)), false, hash)
|
||||
const mit = ['', '#projekt', '#fortschritt', '#passwort', '#funktionen', '#entdecken', '#news', '#termine', '#webshop', '#buchungen', '#zeiten', '#analyse', '#chat', '#vertraege', '#abo', '#wartung', '#rechnungen', '#stunden']
|
||||
for (const hash of mit) assert.equal(zeigtWiderrufsstreifen(routeAusHash(hash)), true, hash)
|
||||
assert.equal(zeigtWiderrufsstreifen(undefined), true) // ohne Route nichts verstecken
|
||||
// jede Etage der Tabelle ist entschieden: versteckt sind genau die Bestellseiten
|
||||
const versteckt = [...new Set(Object.values(ROUTEN).filter((r) => !zeigtWiderrufsstreifen(r)).map((r) => r.etage ?? `reiter:${r.reiter}`))].sort()
|
||||
assert.deepEqual(versteckt, ['bestellen', 'gutschrift', 'reiter:email', 'wechsel'])
|
||||
})
|
||||
@@ -132,6 +132,24 @@ test('M1: Widerrufsstreifen und Pille werden nach Kauf, Wechsel oder Speicher-Pl
|
||||
assert.equal(n(), n0 + 3); assert.equal(b.el('kn-streifen').hidden, true); assert.doesNotMatch(b.fx.text(b.el('kn-konto-wurzel')), /Frist läuft/)
|
||||
})
|
||||
|
||||
test('E-Fix F1 (Nachkorrektur): auf den Bestellseiten (Abo bestellen, Wechsel, Zusatzspeicher, Gutschrift) ist der Widerrufsstreifen weg, auf den Hauptseiten da; ein Neuladen der Fristen ändert daran nichts', async () => {
|
||||
const frist = { fristen: [{ quelle: 'abschluss', bezeichnung: 'Abo', bis: '2026-10-21T21:59:59.999Z' }], fruehestesEnde: '2026-10-21T21:59:59.999Z', anzeigen: true }
|
||||
const karte = { ...KARTE_KUNDE, '/api/fristen': frist }
|
||||
const b = await boot({ hash: '#wechsel', karte }) // Einstieg direkt auf der Bestellseite
|
||||
const zustand = () => [b.el('kn-streifen').hidden, b.fx.document.body.classList.contains('kn-hat-streifen')]
|
||||
assert.deepEqual(zustand(), [true, false])
|
||||
await b.zeige('#vertraege', 'push'); assert.deepEqual(zustand(), [false, true]); assert.equal(b.fx.text(b.el('kn-streifen')), 'Widerrufsfrist bis 21.10. · Widerrufen')
|
||||
for (const hash of ['#bestellen-wartung', '#bestellen-hosting', '#wechsel', '#speicher', '#gutschrift']) {
|
||||
await b.zeige('#abo', 'push'); assert.deepEqual(zustand(), [false, true], `Hauptseite vor ${hash}`)
|
||||
await b.zeige(hash, 'push'); assert.deepEqual(zustand(), [true, false], hash)
|
||||
b.doc.dispatchEvent(new CustomEvent('kn:zaehler-neu', { detail: { was: 'vertraege' } })); await b.fx.ruhe() // Frist neu geladen (z. B. nach Zusatzspeicher)
|
||||
assert.deepEqual(zustand(), [true, false], `${hash} nach dem Neuladen der Fristen`)
|
||||
}
|
||||
await b.zeige('#chat', 'push'); assert.deepEqual(zustand(), [false, true])
|
||||
// "Vertrag widerrufen" bleibt im Konto erreichbar (mit der Pille "Frist läuft")
|
||||
assert.match(b.fx.text(b.el('kn-konto-wurzel')), /Vertrag widerrufen/)
|
||||
})
|
||||
|
||||
test('Zähler: Verträge laden beim Betreten und bei kn:zaehler-neu (document) neu; der Chat-Zähler fällt beim Öffnen des Chats weg', async () => {
|
||||
const b = await boot({ hash: '', karte: { ...KARTE_KUNDE, '/api/chat/unread-count': { unread: 3 } } }); const n = (pfad) => b.log.filter((l) => l[1] === pfad).length
|
||||
const i0 = n('/api/invoices'); const chatTab = () => b.fx.finde(b.el('kn-zeile-haupt'), '[role=tab][aria-label="Chat, 3 ungelesen"]')
|
||||
|
||||
Reference in new issue
Block a user