Terminplaner-Banner und Meldung nach Abschaltgrund mit Löschdatum

GET /api/termine/einstellungen liefert bei abgeschalteter Funktion
abgeschaltet { grund, seit, loeschungAm }. Die 409-Meldung bei
Schreibversuchen (Code abgeschaltet) und der Banner im Portal
unterscheiden Wartungs-Abo beendet, Abo vor der Einrichtung beendet und
die übrigen Gründe und nennen das Löschdatum, wenn es eines gibt.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-04 18:41:03 +00:00
1 parent d66dd60a76
commit 36b36bcc4d
7 files changed
+268 -26

No files matched your search

+19
View File
@@ -456,3 +456,22 @@ export function aktivSeitText(iso) {
if (!zeit || Number.isNaN(zeit.getTime())) return ''
return `Aktiv seit ${datumKurz(heuteBerlin(zeit))}`
}
/**
* Text des Banners einer abgeschalteten Funktion nach Abschaltgrund. abgeschaltet = { grund, seit, loeschungAm } aus GET /api/termine/einstellungen
* (grund: 'abo_ende' | 'abo_ende_vor_einrichtung' | 'team' | 'kunde_geloescht' | null, loeschungAm: 'JJJJ-MM-TT' oder null; null/fehlend = bisheriger Satz).
* Liefert { davor, danach, mitExport }: mit Export steht zwischen den Teilen der Export-Link ([davor, Link 'exportieren', danach]), ohne
* Export (nur wenn das Abo vor der Einrichtung endete: es gibt nichts zu exportieren) folgen die Teile direkt aufeinander.
* Das Loeschdatum steht nur da, wenn loeschungAm ein gueltiger Kalendertag ist. Du-Form; der Wortlaut ist ein Vorschlag fuer die Rechtsrunde.
*/
export function abschaltText(abgeschaltet) {
const { grund, loeschungAm } = abgeschaltet || {}
const loeschen = istTag(loeschungAm) ? ` Ab dem ${datumKurz(loeschungAm)} löschen wir die Daten.` : ''
if (grund === 'abo_ende_vor_einrichtung') {
return { davor: 'Der Terminplaner ist abgeschaltet, weil dein Wartungs-Abo endete, bevor der Terminplaner eingerichtet war.', danach: loeschen, mitExport: false }
}
const davor = grund === 'abo_ende'
? 'Der Terminplaner ist abgeschaltet, weil dein Wartungs-Abo beendet ist. Du kannst Termine nur noch ansehen und '
: 'Der Terminplaner ist für diese Website abgeschaltet. Du kannst Termine nur noch ansehen und '
return { davor, danach: `.${loeschen}`, mitExport: true }
}
+12 -8
View File
@@ -8,7 +8,7 @@
hinweise() zeichnet die Hinweisleiste ueber den Reitern neu (z. B. wenn Telefon und Anschrift nach dem Speichern nicht mehr fehlen). Server: server/routes/termine.js. Tage sind Berliner Kalendertage 'JJJJ-MM-TT';
gerechnet wird in termine-view.js. Helfer ohne Zustand: termine-dom.js. Styles: termine.css. */
import { fehltText, heuteBerlin } from './termine-view.js'
import { abschaltText, fehltText, heuteBerlin } from './termine-view.js'
import { exportLink, fehlerKarte, h, infoKarte, request } from './termine-dom.js'
import { render as renderTermine } from './termine-tab-termine.js'
import { render as renderLeistungen } from './termine-tab-leistungen.js'
@@ -62,11 +62,15 @@ function projektwahl(s) {
const ladeDaten = (projectId) => request(`/api/termine/einstellungen?projectId=${encodeURIComponent(projectId)}`)
/** Hinweis fuer abgeschaltete Funktionen: nur noch ansehen und exportieren. */
const hinweisAbgeschaltet = (projectId) => h('div', { class: 'tm-box tm-box-warn', role: 'note' },
'Der Terminplaner ist für diese Website abgeschaltet. Du kannst Termine nur noch ansehen und ',
exportLink(projectId, 'exportieren'),
'.')
/**
* Hinweis fuer abgeschaltete Funktionen: Grund, Loeschdatum und (ausser vor der Einrichtung) der Export-Link, der einzige Link im Hinweis.
* abgeschaltet: { grund, seit, loeschungAm } aus GET /einstellungen (fehlt bei einer aelteren Antwort: dann der bisherige Satz).
*/
function hinweisAbgeschaltet(projectId, abgeschaltet) {
const { davor, danach, mitExport } = abschaltText(abgeschaltet)
// ein einziger Textblock in der Flex-Zeile der Box, sonst zerfaellt der Satz in drei Spalten (Text, Link, Punkt)
return h('div', { class: 'tm-box tm-box-warn', role: 'note' }, h('span', null, davor, mitExport && exportLink(projectId, 'exportieren'), danach))
}
/**
* Je nach Zustand der Funktion: nicht freigeschaltet, Vorlage waehlen oder die Reiter. Jeder Aufruf zaehlt s.lauf hoch: die Antwort
@@ -95,7 +99,7 @@ async function zeigeProjekt(s) {
if (daten.einstellung) zeigeReiter(s, { projekt, aktuell })
else if (s.nurLesen) {
s.buehne.replaceChildren(
hinweisAbgeschaltet(projekt.projectId),
hinweisAbgeschaltet(projekt.projectId, daten.abgeschaltet),
infoKarte('Keine Termine eingerichtet', 'Für diese Website wurden keine Einstellungen und Termine angelegt.', { chat: true }))
} else zeigeVorlagen(s, { projekt, aktuell })
}
@@ -197,7 +201,7 @@ function zeigeReiter(s, { projekt, aktuell }) {
function zeichneHinweise() {
const hinweise = []
if (nurLesen) {
hinweise.push(hinweisAbgeschaltet(projectId))
hinweise.push(hinweisAbgeschaltet(projectId, s.daten.abgeschaltet))
} else if ((s.daten.fehlt || []).length) {
hinweise.push(h('div', { class: 'tm-box tm-box-warn', role: 'note' },
h('span', null, `Noch nicht buchbar: Es fehlt ${fehltText(s.daten.fehlt) || 'eine Angabe zu deinem Betrieb'}. Solange das fehlt, können Gäste über deine Website nicht buchen.`),