Terminplaner: im Abo-Modell Einschalten statt Bestellen, ohne Häkchen

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-16 18:39:54 +00:00
1 parent 364ded1662
commit b6f70a502a
3 files changed
+119 -7

No files matched your search

+11 -5
View File
@@ -21,12 +21,15 @@ import { render as renderLeistungen } from './termine-tab-leistungen.js'
import { wochenplanFeld } from './termine-tab-team.js'
import { abwesenheiten, sonderoeffnungen } from './termine-team-ausnahmen.js'
import { betrieb, darstellung, erinnerung, gastFelder, rechtliches, regeln, storno, zahlung } from './termine-tab-einstellungen.js'
import { renderBestellen } from './funktion-bestellen.js'
import { renderBestellen, renderEinschaltSeite } from './funktion-bestellen.js'
const BESTELLEN = 'bestellen'
const TITEL = new Map([...FRAGEBOGEN_SCHRITTE, [BESTELLEN, 'Prüfen und bestellen']])
const AUFBEWAHRUNG = 'Wir speichern deinen Entwurf bis zu 90 Tage nach deiner letzten Änderung.'
const KUNDENANSICHT = 'Du siehst den Fragebogen in der Kundenansicht. Angaben kannst du ändern, Schritte bestätigen und bestellen kann nur der Kunde selbst.'
// Abo-Modell (ctx.s.modell === 'abo'): Einschalten statt Bestellen (Texte E1 und F1)
const TITEL_ABO = 'Prüfen und einschalten'
const KUNDENANSICHT_ABO = 'Du siehst den Fragebogen in der Kundenansicht. Angaben kannst du ändern, Schritte bestätigen und einschalten kann nur der Kunde selbst.'
const GESUNDHEIT_TEXT = 'Für den Gesundheitsbereich ist der Terminplaner nicht verfügbar. Schon der Name einer Leistung oder ein Terminwunsch kann etwas über die Gesundheit deiner Gäste verraten, '
+ 'und solche Angaben sind besonders geschützt. Gehört dein Angebot nicht zum Gesundheitsbereich, wähle die Branche, die am besten passt. Fragen dazu beantworten wir dir im Chat.'
const WECHSEL_TEXT = 'Das ersetzt deine Leistungen, Zeiten und Regeln durch die Vorschläge der neuen Branche. Alle Bestätigungen gehen zurück, du bestätigst die Schritte danach noch einmal. '
@@ -73,11 +76,13 @@ const istObjekt = (wert) => wert !== null && typeof wert === 'object' && !Array.
/* ---------------------------------------------------------------- Gerüst --- */
export function renderFragebogen(root, ctx) {
const abo = ctx.s?.modell === 'abo'
const titelLetzter = abo ? TITEL_ABO : TITEL.get(BESTELLEN)
const stand = h('p', { class: 'tm-schritt-stand' })
const liste = h('ol', { class: 'tm-schritte' })
const inhalt = h('div', { class: 'tm-fb-inhalt' })
root.replaceChildren(h('div', { class: 'tm-fragebogen' },
ctx.daten.kundenansicht === true ? h('div', { class: 'tm-box tm-box-info', role: 'note' }, h('span', null, KUNDENANSICHT)) : null,
ctx.daten.kundenansicht === true ? h('div', { class: 'tm-box tm-box-info', role: 'note' }, h('span', null, abo ? KUNDENANSICHT_ABO : KUNDENANSICHT)) : null,
h('nav', { class: 'tm-fortschritt', 'aria-label': 'Fortschritt im Fragebogen' }, stand, liste),
inhalt,
h('p', { class: 'tm-hinweis tm-fb-aufbewahrung' }, AUFBEWAHRUNG)))
@@ -87,7 +92,7 @@ export function renderFragebogen(root, ctx) {
const darfHin = (key) => key === 'branche' || Boolean(ctx.daten.einstellung)
function zeichneLeiste() {
const eintraege = [...schrittStatus(ctx.daten.fragebogen), { key: BESTELLEN, titel: TITEL.get(BESTELLEN), erledigt: false }]
const eintraege = [...schrittStatus(ctx.daten.fragebogen), { key: BESTELLEN, titel: titelLetzter, erledigt: false }]
liste.replaceChildren(...eintraege.map(({ key, titel, erledigt }, i) => h('li', {
class: 'tm-schritt', 'data-schritt': key, 'data-erledigt': erledigt ? 'true' : null, 'aria-current': key === angezeigt ? 'step' : null,
}, h('button', { type: 'button', class: 'tm-schritt-knopf', disabled: !darfHin(key), onclick: () => { if (key !== angezeigt) zeige(key) } },
@@ -95,12 +100,13 @@ export function renderFragebogen(root, ctx) {
h('span', { class: 'tm-schritt-titel' }, titel),
erledigt ? h('span', { class: 'tm-sr' }, ' (erledigt)') : null))))
const nr = FRAGEBOGEN_SCHRITTE.findIndex(([key]) => key === angezeigt)
stand.textContent = nr < 0 ? TITEL.get(BESTELLEN) : `Schritt ${nr + 1} von ${FRAGEBOGEN_SCHRITTE.length}`
stand.textContent = nr < 0 ? titelLetzter : `Schritt ${nr + 1} von ${FRAGEBOGEN_SCHRITTE.length}`
}
function bestellseite() {
const seite = h('div', { class: 'tm-fb-bestellen' })
renderBestellen(seite, { ctx, daten: ctx.daten, zumSchritt: (key) => zeige(key) })
if (abo) renderEinschaltSeite(seite, { ctx, daten: ctx.daten, zumSchritt: (key) => zeige(key), key: 'termine', einschalten: ctx.einschalten, nachEinschalten: () => ctx.fertig() })
else renderBestellen(seite, { ctx, daten: ctx.daten, zumSchritt: (key) => zeige(key) })
return seite
}
+5 -2
View File
@@ -52,14 +52,14 @@ const istBestellt = (zustand) => zustand === 'ordered' || zustand === 'setup'
// Entwurf: Funktionsdokument im Zustand Aus mit siteKey (wie die Kachel in funktionen.js)
const hatEntwurf = (projekt) => zustandVon(projekt) === 'off' && Boolean(projekt?.features?.termine?.siteKey)
export async function initTermine(root, { projectId } = {}) {
export async function initTermine(root, { projectId, einschalten } = {}) {
if (!root) return
const rueckkehr = leseRueckkehr()
const wunsch = rueckkehr.projekt || projectId || root.dataset.wunschProjekt || '' // die Kachel in Funktionen legt ihr Projekt hier ab
delete root.dataset.wunschProjekt
if (wunsch) auswahl.projectId = wunsch
const { projects = [], termine, modell } = await request('/api/funktionen')
const s = { root, projects, termine: termine || null, modell, projekt: null, daten: null, tag: heuteBerlin(), nurLesen: false, lauf: 0, buehne: null, meldungEl: null, danke: false }
const s = { root, projects, termine: termine || null, modell, projekt: null, daten: null, tag: heuteBerlin(), nurLesen: false, lauf: 0, buehne: null, meldungEl: null, danke: false, einschalten }
S = s
if (!termine?.verfuegbar) {
keineReiter(s)
@@ -259,6 +259,7 @@ async function zeigeBestellung(s, { zustand, aktuell, bestellformular, meldung }
einrichtung: s.termine?.einrichtung,
danke,
kundenansicht: s.daten.kundenansicht === true,
modell: s.modell,
meldung: zustand === 'ordered' && meldung ? meldung.text : '', // die Meldung gilt nur, solange die Bestellung noch offen ist
}, { weiter: (fall) => ladeNeu(s, { bestellformular: fall?.bestellen === true, meldung: fall?.meldung ? { text: fall.meldung } : null }) })
}
@@ -339,6 +340,8 @@ export function baueCtx(s, { projekt, aktuell, hinweise = () => {}, zumReiter =
nurLesen: s.nurLesen,
auswahl,
aktuell,
einschalten: s.einschalten, // Ablauf des Einschaltens im Abo-Modell (Init-Option der Hülle), der Fragebogen mountet ihn im letzten Schritt
fertig: () => ladeNeu(s), // nach dem Einschalten: Ansicht neu zeichnen
api: {
get: (pfad, query = {}) => request(`/api/termine${pfad}?${new URLSearchParams({ projectId, ...query })}`),
send: (method, pfad, body = {}) => (method === 'DELETE'