Terminplaner TP2: Fragebogen-Schritte 4 bis 8 und Bestellseite
- public/termine-fragebogen.js: Schritt 4 Zeiten (je Person/Platz wochenplanFeld, Bundesland ohne Vorauswahl mit leerer erster Option, "An Feiertagen geschlossen" im PATCH, danach PUT mit bundeslandGewaehlt; darunter abwesenheiten und sonderoeffnungen mit eigenem Container und eigenem zeichne, damit ungespeicherte Zeiten bleiben), Schritt 5 Regeln (Sammelknopf Alle sofort buchbar / Alle nur als Anfrage mit buchungsartFuerAlle und buchungsartLage, regeln, storno mit Muster nach Absagefrist, rechtliches, zahlung), Schritt 6 Gastfelder, Schritt 7 mit gemeinsamem leseAbschnitte, Schritt 8 Website (betrieb nur Telefon und vier Links, Einbauwuensche Modus/Knopftext/Stelle/Gestaltung/Bemerkung im PUT, Hinweis auf Mehrwuensche nach Stunden); danach renderBestellen. Platzhalter-Schritt entfernt. - termine.css: Klassen der Schritte 4 bis 8 - Tests: termineView (Importe, PATCH/PUT nur an erlaubten Stellen, Bundesland ohne Vorauswahl im Quelltext), termineFragebogenView (Verhalten mit Fake-DOM fuer die Schritte 4 bis 8, Schluesselmengen, Bestellseite nach Schritt 8) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9bf5ec09f8
commit
8d628ef906
4 files changed
+939
-34
No files matched your search
+249
-23
@@ -7,14 +7,20 @@
|
||||
Feldern ist ein <form>; „Weiter“ (verdrahte) macht genau EINEN PATCH ueber den neuerSpeicher des Schritts (termine-speichern.js, der einzige
|
||||
PATCH-Weg; nur wenn der Schritt Felder hat) und danach PUT /fragebogen mit dem Schritt in bestaetigt (bestaetige, der einzige PUT). Fehler stehen am
|
||||
Feld (setzeFehler); beim Wechsel bekommt die Ueberschrift des Schritts den Fokus. Kundenansicht (daten.kundenansicht): PATCH bleibt moeglich, es gibt
|
||||
keinen PUT, denn Schritte bestaetigt nur der Kunde selbst. Die Schritte 4, 5, 6 und 8 traegt C9b in BAU nach. Texte der Kunden kommen nur ueber
|
||||
value/textContent in die Seite (h aus termine-dom.js), nie als HTML. */
|
||||
keinen PUT, denn Schritte bestaetigt nur der Kunde selbst. Die Schritte bauen auf den Abschnitten der Reiter auf (wochenplanFeld, abwesenheiten,
|
||||
sonderoeffnungen, betrieb, darstellung, regeln, gastFelder, erinnerung, storno, rechtliches, zahlung); hier steht nur, was der Fragebogen daraus macht.
|
||||
Nach Schritt 8 kommt die Bestellseite (renderBestellen). Texte der Kunden kommen nur ueber value/textContent in die Seite (h aus termine-dom.js),
|
||||
nie als HTML. */
|
||||
|
||||
import { FRAGEBOGEN_SCHRITTE, LIMITS, MAX, ersterOffenerSchritt, preisAnzeige, ressourcenAusNamen, schrittStatus } from './termine-view.js'
|
||||
import { allgemeinerFehler, feld, frage, h, hakenFeld, setzeFehler, zeigeFehler } from './termine-dom.js'
|
||||
import { neuerSpeicher } from './termine-speichern.js'
|
||||
import {
|
||||
BUNDESLAENDER, FRAGEBOGEN_SCHRITTE, LIMITS, MAX, buchungsartFuerAlle, buchungsartLage, ersterOffenerSchritt, preisAnzeige, ressourcenAusNamen, schrittStatus,
|
||||
} from './termine-view.js'
|
||||
import { abschnitt, allgemeinerFehler, feld, frage, h, hakenFeld, setzeFehler, zeigeFehler } from './termine-dom.js'
|
||||
import { neuerSpeicher, stelleVon } from './termine-speichern.js'
|
||||
import { render as renderLeistungen } from './termine-tab-leistungen.js'
|
||||
import { betrieb, darstellung, erinnerung } from './termine-tab-einstellungen.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'
|
||||
|
||||
const BESTELLEN = 'bestellen'
|
||||
@@ -41,6 +47,28 @@ const WER_ARTEN = [
|
||||
['plaetze', 'Plätze', 'Gebucht werden Plätze oder Räume, zum Beispiel Stühle oder Zimmer.'],
|
||||
]
|
||||
|
||||
// Schritt 4: ohne Wahl des Bundeslands geht es nicht weiter (der Serverstandard RP im Entwurf ist keine Wahl)
|
||||
const LAND_FEHLT = 'Bitte wähle das Bundesland deines Betriebs. Danach richten sich die Feiertage.'
|
||||
|
||||
// Schritt 5: Lage der Buchungsarten aller Leistungen (Schluessel wie buchungsartLage) und die zwei Sammelknoepfe
|
||||
const LAGE_TEXT = {
|
||||
sofort: 'Alle Leistungen sind sofort buchbar.',
|
||||
anfrage: 'Alle Leistungen sind nur als Anfrage buchbar.',
|
||||
gemischt: 'Die Leistungen sind gemischt: je Leistung sofort buchbar oder nur als Anfrage.',
|
||||
}
|
||||
const SAMMEL_ARTEN = [['sofort', 'Alle sofort buchbar'], ['anfrage', 'Alle nur als Anfrage']]
|
||||
|
||||
// Schritt 8: Einbauwuensche (Werte und Grenzen wie normalisiereFragebogen auf dem Server)
|
||||
const EINBAU_MODI = [
|
||||
['inline', 'Direkt auf der Seite', 'Der Terminplaner steht offen an der Stelle, die du uns nennst.'],
|
||||
['knopf', 'Hinter einem Knopf', 'Gäste klicken auf einen Knopf, dann öffnet sich der Terminplaner.'],
|
||||
]
|
||||
const EINBAU_MAX = { knopfText: 40, stelle: 300, gestaltung: 1000, bemerkung: 1000 }
|
||||
const MODUS_FEHLT = 'Bitte wähle, ob der Terminplaner direkt auf deiner Seite oder hinter einem Knopf erscheint.'
|
||||
const KNOPFTEXT_FEHLT = 'Bitte gib an, was auf dem Knopf stehen soll, hinter dem sich der Terminplaner öffnet.'
|
||||
const MEHRWUENSCHE = 'Der Einbau umfasst den Terminplaner an einer Stelle deiner Website. Ein zweites Widget, Knöpfe für einzelne Leistungen und ein Sonderdesign gehen nach Stunden.'
|
||||
const WEBSITE_NUR = ['telefon', 'impressumUrl', 'datenschutzUrl', 'agbUrl', 'websiteUrl']
|
||||
|
||||
const istObjekt = (wert) => wert !== null && typeof wert === 'object' && !Array.isArray(wert)
|
||||
|
||||
/* ---------------------------------------------------------------- Gerüst --- */
|
||||
@@ -78,10 +106,10 @@ export function renderFragebogen(root, ctx) {
|
||||
|
||||
/** Schritt zeigen (=> sein Element). fokus: die Ueberschrift bekommt den Fokus, so wie bei jedem Wechsel; der erste Aufruf nimmt keinen. */
|
||||
function zeige(key, { fokus = true } = {}) {
|
||||
const ziel = darfHin(key) ? key : 'branche'
|
||||
const ziel = TITEL.has(key) && darfHin(key) ? key : 'branche'
|
||||
angezeigt = ziel
|
||||
zeichneLeiste()
|
||||
const el = ziel === BESTELLEN ? bestellseite() : (BAU[ziel] ?? schrittOhneInhalt)(baueT(ziel))
|
||||
const el = ziel === BESTELLEN ? bestellseite() : BAU[ziel](baueT(ziel))
|
||||
inhalt.replaceChildren(el)
|
||||
const kopf = fokus ? el.querySelector('h3') : null
|
||||
if (kopf) {
|
||||
@@ -189,6 +217,20 @@ function zeigeNeu(t, text) {
|
||||
if (form) setzeFehler(form, { _: text })
|
||||
}
|
||||
|
||||
/**
|
||||
* aendere() fuer Schritte aus Abschnitten der Einstellungen (jeder ist { el, lese(entwurf, fehler) }): jeder liest seine Felder in den Entwurf.
|
||||
* Eingaben, die kein Feld versteht, stehen danach am Feld und nichts wird gesendet (false). Das Pruefen im Einzelnen bleibt Sache des Servers.
|
||||
*/
|
||||
function leseAbschnitte(form, abschnitte) {
|
||||
return (entwurf) => {
|
||||
const fehler = {}
|
||||
for (const a of abschnitte) a.lese(entwurf, fehler)
|
||||
if (Object.keys(fehler).length === 0) return true
|
||||
zeigeFehler(form, { fehler })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------- Schritt 1: Branche und Betrieb --- */
|
||||
/**
|
||||
* Radiogruppe der Branchen aus daten.branchen. Der Gesundheitsbereich zeigt den Erklaertext und KEINEN Knopf (es geht nie eine Anfrage raus), jede andere
|
||||
@@ -470,33 +512,217 @@ function schrittLeistungen(t) {
|
||||
return wurzel
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------- Schritt 4: Zeiten --- */
|
||||
/**
|
||||
* Je Person und Platz ein Wochenplan (wochenplanFeld), dazu Bundesland OHNE Vorauswahl (leere erste Option; gewaehlt ist nur, was der Kunde schon
|
||||
* ausdruecklich gewaehlt hatte) und „An Feiertagen geschlossen“: alles im PATCH dieses Schritts, danach der PUT mit bundeslandGewaehlt.
|
||||
* Darunter Abwesenheiten und Sonderoeffnungen aus dem Reiter „Team & Plaetze“: sie speichern selbst und haben deshalb einen eigenen Container mit
|
||||
* eigenem zeichne, damit das Neuzeichnen nach dem Speichern die ungespeicherten Zeiten im Formular darueber nicht verliert. Der Speicher ist derselbe
|
||||
* wie im Schritt (ein Speichern zur Zeit, eine Version).
|
||||
*/
|
||||
function schrittZeiten(t) {
|
||||
const { ctx } = t
|
||||
const e = ctx.daten.einstellung
|
||||
const wurzel = rahmen(t, 'Wann kann bei dir gebucht werden? Trag für jede Person und jeden Platz die Zeiten ein und wähle dein Bundesland. Urlaub und besondere Öffnungstage trägst du weiter unten ein, sie werden sofort gespeichert.')
|
||||
const sp = neuerSpeicher(ctx, wurzel, t.neuZeichnen)
|
||||
const plaene = (e.ressourcen || []).map((r, i) => ({ r, plan: wochenplanFeld(r, `ressourcen.${i}`) }))
|
||||
const vorgabe = ctx.daten.fragebogen?.bundeslandGewaehlt === true ? e.bundesland : ''
|
||||
const land = h('select', null,
|
||||
h('option', { value: '' }, 'Bitte wählen'),
|
||||
BUNDESLAENDER.map(([key, name]) => h('option', { value: key, selected: key === vorgabe }, name)))
|
||||
const geschlossen = h('input', { type: 'checkbox', checked: e.feiertageGeschlossen !== false })
|
||||
const form = schrittForm(t,
|
||||
plaene.length > 0
|
||||
? plaene.map(({ r, plan }) => h('div', { class: 'kb-panel tm-fb-person', 'data-ressource': r.id }, h('h4', null, `${r.name}${r.aktiv === false ? ' (nicht aktiv)' : ''}`), plan.el))
|
||||
: h('p', { class: 'tm-leer' }, 'Es gibt noch keine Person und keinen Platz. Lege sie im Schritt „Wer wird gebucht“ an.'),
|
||||
abschnitt('Bundesland und Feiertage', null,
|
||||
feld('bundesland', 'Bundesland', land, 'Danach richten sich die gesetzlichen Feiertage. Bitte wähle es ausdrücklich aus.'),
|
||||
hakenFeld('feiertageGeschlossen', geschlossen, 'An Feiertagen geschlossen', 'Dann kann an gesetzlichen Feiertagen niemand buchen. Eine Sonderöffnung geht vor.')),
|
||||
allgemeinerFehler(),
|
||||
knoepfe(t))
|
||||
|
||||
let gelesen = []
|
||||
verdrahte(t, form, sp, {
|
||||
pruefe: () => {
|
||||
const fehler = {}
|
||||
const plaeneGelesen = []
|
||||
for (const { r, plan } of plaene) {
|
||||
const ergebnis = plan.lese()
|
||||
if (ergebnis.fehler) Object.assign(fehler, ergebnis.fehler)
|
||||
else plaeneGelesen.push([r.id, ergebnis.plan])
|
||||
}
|
||||
if (land.value === '') fehler.bundesland = LAND_FEHLT
|
||||
if (Object.keys(fehler).length > 0) return fehler
|
||||
gelesen = plaeneGelesen
|
||||
return null
|
||||
},
|
||||
aendere: (entwurf) => {
|
||||
for (const [id, plan] of gelesen) {
|
||||
const stelle = stelleVon(entwurf.ressourcen, id, form, 'Diese Person oder dieser Platz')
|
||||
if (stelle < 0) return false
|
||||
entwurf.ressourcen[stelle].plan = plan
|
||||
}
|
||||
entwurf.bundesland = land.value
|
||||
entwurf.feiertageGeschlossen = geschlossen.checked
|
||||
return true
|
||||
},
|
||||
fragebogen: (f) => { f.bundeslandGewaehlt = true },
|
||||
})
|
||||
|
||||
const ausnahmen = h('div', { class: 'tm-fb-ausnahmen' })
|
||||
const at = { ctx, sp, wurzel: ausnahmen, zeichne: () => ausnahmen.replaceChildren(abwesenheiten(at), sonderoeffnungen(at)) }
|
||||
at.zeichne()
|
||||
wurzel.append(sp.konflikt, form, ausnahmen)
|
||||
return wurzel
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------- Schritt 5: Regeln --- */
|
||||
/**
|
||||
* Sammelknopf „Alle sofort buchbar“ / „Alle nur als Anfrage“: zeigt die Lage der Leistungen (buchungsartLage) und merkt sich die Wahl; geschrieben wird
|
||||
* sie mit „Weiter“ in den PATCH des Schritts (buchungsartFuerAlle auf dem frischen Stand), ein Klick allein ruft nichts auf. => { el, lese(entwurf) }.
|
||||
*/
|
||||
function buchungsartSammel(e) {
|
||||
const leistungen = e.leistungen || []
|
||||
let gewaehlt = null // null: der Kunde hat nichts gewaehlt, die Leistungen bleiben, wie sie sind
|
||||
const lage = h('p', { class: 'tm-hinweis', role: 'status' })
|
||||
const tasten = SAMMEL_ARTEN.map(([art, text]) => h('button', {
|
||||
type: 'button', class: 'kb-btn-outline', 'data-aktion': `alle-${art}`, onclick: () => { gewaehlt = art; zeige() },
|
||||
}, text))
|
||||
function zeige() {
|
||||
const jetzt = buchungsartLage(gewaehlt === null ? leistungen : buchungsartFuerAlle(leistungen, gewaehlt))
|
||||
lage.setAttribute('data-lage', jetzt)
|
||||
lage.textContent = `${LAGE_TEXT[jetzt]}${gewaehlt === null ? '' : ' Gespeichert wird mit „Weiter“.'}`
|
||||
SAMMEL_ARTEN.forEach(([art], i) => tasten[i].setAttribute('aria-pressed', String(jetzt === art)))
|
||||
}
|
||||
zeige()
|
||||
const el = abschnitt('Buchungsart',
|
||||
'Sollen deine Gäste sofort buchen können oder nur eine Anfrage stellen, die du bestätigst? Das gilt für alle Leistungen zugleich. Einzelne Leistungen änderst du im Schritt „Leistungen“.',
|
||||
lage,
|
||||
h('div', { class: 'tm-fb-sammel', role: 'group', 'aria-label': 'Buchungsart für alle Leistungen' }, tasten))
|
||||
return { el, lese(entwurf) { if (gewaehlt !== null) entwurf.leistungen = buchungsartFuerAlle(entwurf.leistungen, gewaehlt) } }
|
||||
}
|
||||
|
||||
function schrittRegeln(t) {
|
||||
const { ctx } = t
|
||||
const e = ctx.daten.einstellung
|
||||
const wurzel = rahmen(t, 'Lege fest, wie deine Gäste buchen, was bei Absagen gilt und wie sie bezahlen.')
|
||||
const sp = neuerSpeicher(ctx, wurzel, t.neuZeichnen)
|
||||
const sammel = buchungsartSammel(e)
|
||||
const regelnAbschnitt = regeln(e)
|
||||
// das Muster der Stornobedingungen folgt der Frist, die im Feld „Selbst absagen bis“ steht (auch ungespeichert)
|
||||
const abschnitte = [regelnAbschnitt, storno(ctx, e, regelnAbschnitt.absage), rechtliches(e), zahlung(e)]
|
||||
const form = schrittForm(t, sammel.el, abschnitte.map((a) => a.el), allgemeinerFehler(), knoepfe(t))
|
||||
verdrahte(t, form, sp, { aendere: leseAbschnitte(form, [sammel, ...abschnitte]) })
|
||||
wurzel.append(sp.konflikt, form)
|
||||
return wurzel
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------- Schritt 6: Gastfelder --- */
|
||||
function schrittGastfelder(t) {
|
||||
const { ctx } = t
|
||||
const wurzel = rahmen(t, 'Was möchtest du von deinen Gästen wissen? Name und E-Mail-Adresse brauchen wir immer.')
|
||||
const sp = neuerSpeicher(ctx, wurzel, t.neuZeichnen)
|
||||
const gast = gastFelder(ctx, ctx.daten.einstellung)
|
||||
const form = schrittForm(t, gast.el, allgemeinerFehler(), knoepfe(t))
|
||||
verdrahte(t, form, sp, { aendere: leseAbschnitte(form, [gast]) })
|
||||
wurzel.append(sp.konflikt, form)
|
||||
return wurzel
|
||||
}
|
||||
|
||||
/* ------------------------------------------------- Schritt 7: Benachrichtigung --- */
|
||||
function schrittBenachrichtigung(t) {
|
||||
const { ctx } = t
|
||||
const wurzel = rahmen(t, 'Wohin sollen die Nachrichten zu Terminen gehen, wie sprichst du deine Gäste an und bekommen Gäste eine Erinnerung?')
|
||||
const sp = neuerSpeicher(ctx, wurzel, t.neuZeichnen)
|
||||
const e = ctx.daten.einstellung
|
||||
// aus dem Betrieb nur die E-Mail-Adresse: sie ist die einzige Adresse fuer Nachrichten und auch Reply-To
|
||||
const abschnitte = [betrieb(ctx, e, { nur: ['email'], titel: 'Deine E-Mail-Adresse', hinweis: null }), darstellung(e), erinnerung(e)]
|
||||
const form = schrittForm(t, abschnitte.map((a) => a.el), allgemeinerFehler(), knoepfe(t))
|
||||
verdrahte(t, form, sp, {
|
||||
aendere: (entwurf) => {
|
||||
const fehler = {}
|
||||
for (const a of abschnitte) a.lese(entwurf, fehler)
|
||||
if (Object.keys(fehler).length === 0) return true
|
||||
zeigeFehler(form, { fehler })
|
||||
return false
|
||||
verdrahte(t, form, sp, { aendere: leseAbschnitte(form, abschnitte) })
|
||||
wurzel.append(sp.konflikt, form)
|
||||
return wurzel
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------- Schritt 8: Website --- */
|
||||
/**
|
||||
* Einbauwuensche: Modus (direkt auf der Seite / hinter einem Knopf, ohne Vorauswahl), Knopftext (nur bei Knopf), Stelle, Gestaltung, Bemerkung und der
|
||||
* Hinweis, was nach Stunden geht. einbau = fragebogen.einbau (darf fehlen). => { el, pruefe(), wert() }: pruefe() => null oder { feld: text }, wert() =>
|
||||
* das Objekt fuer fragebogen.einbau (bei „direkt auf der Seite“ ohne Knopftext). Die Texte kuerzt und bereinigt der Server.
|
||||
*/
|
||||
function einbauWuensche(einbau) {
|
||||
const alt = istObjekt(einbau) ? einbau : {}
|
||||
const textVon = (name) => (typeof alt[name] === 'string' ? alt[name] : '')
|
||||
const eingaben = []
|
||||
const radios = EINBAU_MODI.map(([wert, name, beschreibung]) => {
|
||||
const radio = h('input', { type: 'radio', name: 'termine-einbau-modus', value: wert, checked: alt.modus === wert })
|
||||
radio.addEventListener('change', zeigeKnopfFeld)
|
||||
eingaben.push(radio)
|
||||
return h('label', { class: 'tm-vorlage' }, radio, h('span', null, h('strong', null, name), h('small', null, beschreibung)))
|
||||
})
|
||||
const gewaehlt = () => eingaben.find((radio) => radio.checked)?.value ?? null
|
||||
const knopfText = h('input', { type: 'text', maxlength: String(EINBAU_MAX.knopfText), autocomplete: 'off', value: textVon('knopfText') })
|
||||
const knopfFeld = feld('einbau.knopfText', 'Text auf dem Knopf', knopfText, 'Zum Beispiel „Termin buchen“.')
|
||||
const mehrzeilig = (name) => h('textarea', { rows: '3', maxlength: String(EINBAU_MAX[name]), autocomplete: 'off' }, textVon(name))
|
||||
const stelle = mehrzeilig('stelle')
|
||||
const gestaltung = mehrzeilig('gestaltung')
|
||||
const bemerkung = mehrzeilig('bemerkung')
|
||||
function zeigeKnopfFeld() { knopfFeld.hidden = gewaehlt() !== 'knopf' }
|
||||
zeigeKnopfFeld()
|
||||
|
||||
const el = abschnitt('Einbau auf deiner Website', 'Wir bauen den Terminplaner für dich in deine Website ein. Sag uns, wie und wo er erscheinen soll.',
|
||||
h('fieldset', { class: 'tm-gruppe-felder', 'data-feld': 'einbau.modus', tabindex: '-1' },
|
||||
h('legend', { class: 'tm-label' }, 'So erscheint der Terminplaner'),
|
||||
h('div', { class: 'tm-vorlagen-liste' }, radios),
|
||||
h('p', { class: 'tm-fehler', 'data-fehler': 'einbau.modus', role: 'alert' })),
|
||||
knopfFeld,
|
||||
feld('einbau.stelle', 'Wo auf deiner Website soll er stehen?', stelle, 'Beschreibe die Stelle in Worten, zum Beispiel „auf der Seite Kontakt unter dem Text“.'),
|
||||
feld('einbau.gestaltung', 'Wünsche zur Gestaltung (optional)', gestaltung, 'Farben, Schrift, Stil: Wir passen den Terminplaner an deine Website an.'),
|
||||
feld('einbau.bemerkung', 'Bemerkung (optional)', bemerkung),
|
||||
h('p', { class: 'tm-hinweis', 'data-hinweis': 'einbau-mehr' }, MEHRWUENSCHE))
|
||||
el.classList.add('tm-fb-einbau')
|
||||
|
||||
return {
|
||||
el,
|
||||
pruefe() {
|
||||
const modus = gewaehlt()
|
||||
if (modus === null) return { 'einbau.modus': MODUS_FEHLT }
|
||||
if (modus === 'knopf' && knopfText.value.trim() === '') return { 'einbau.knopfText': KNOPFTEXT_FEHLT }
|
||||
return null
|
||||
},
|
||||
wert() {
|
||||
const modus = gewaehlt()
|
||||
return { modus, knopfText: modus === 'knopf' ? knopfText.value.trim() : '', stelle: stelle.value, gestaltung: gestaltung.value, bemerkung: bemerkung.value }
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function schrittWebsite(t) {
|
||||
const { ctx } = t
|
||||
const wurzel = rahmen(t, 'Zum Schluss: Wie erreichen dich Gäste, und wie soll der Terminplaner auf deiner Website erscheinen?')
|
||||
const sp = neuerSpeicher(ctx, wurzel, t.neuZeichnen)
|
||||
// aus dem Betrieb Telefon (Ausweichweg fuer Gaeste) und die Links; Name, Anschrift und E-Mail stehen in den Schritten 1 und 7
|
||||
const angaben = betrieb(ctx, ctx.daten.einstellung, {
|
||||
nur: WEBSITE_NUR,
|
||||
titel: 'Telefon und Links',
|
||||
hinweis: 'Das Telefon ist der Ausweichweg für Gäste. Impressum und Datenschutzerklärung brauchen wir, weil der Terminplaner Gäste darauf verweist.',
|
||||
})
|
||||
const einbau = einbauWuensche(ctx.daten.fragebogen?.einbau)
|
||||
const form = schrittForm(t, angaben.el, einbau.el, allgemeinerFehler(), knoepfe(t))
|
||||
let gewuenscht = null
|
||||
verdrahte(t, form, sp, {
|
||||
pruefe: () => {
|
||||
const fehler = einbau.pruefe()
|
||||
if (fehler === null) gewuenscht = einbau.wert()
|
||||
return fehler
|
||||
},
|
||||
aendere: (entwurf) => { angaben.lese(entwurf); return true },
|
||||
fragebogen: (f) => { f.einbau = gewuenscht },
|
||||
})
|
||||
wurzel.append(sp.konflikt, form)
|
||||
return wurzel
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------ Schritte ohne Inhalt --- */
|
||||
/** Platz fuer die Schritte, die C9b nachtraegt (4, 5, 6, 8): Ueberschrift, Hinweis und Zurueck, aber nichts zu bestaetigen. */
|
||||
function schrittOhneInhalt(t) {
|
||||
const wurzel = rahmen(t, 'Dieser Schritt ist noch nicht verfügbar.')
|
||||
wurzel.append(knoepfe(t, { mitWeiter: false }))
|
||||
return wurzel
|
||||
const BAU = {
|
||||
branche: schrittBranche, wer: schrittWer, leistungen: schrittLeistungen, zeiten: schrittZeiten, regeln: schrittRegeln,
|
||||
gastfelder: schrittGastfelder, benachrichtigung: schrittBenachrichtigung, website: schrittWebsite,
|
||||
}
|
||||
|
||||
const BAU = { branche: schrittBranche, wer: schrittWer, leistungen: schrittLeistungen, benachrichtigung: schrittBenachrichtigung }
|
||||
@@ -258,6 +258,15 @@
|
||||
.tm-fb-branche { display: flex; align-items: center; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; }
|
||||
.tm-fb-branche p { margin: 0; }
|
||||
.tm-fb-aufbewahrung { margin-top: 18px; }
|
||||
/* Schritte 4 bis 8: ein Wochenplan je Person, Urlaub und Sonderoeffnungen unter dem Formular, Sammelknopf, Einbauwuensche */
|
||||
.tm-fb-person > h4 { margin: 0 0 4px; font-size: 14.5px; overflow-wrap: anywhere; }
|
||||
.tm-fb-person .tm-wochenplan { margin-top: 0; }
|
||||
.tm-fb-ausnahmen { margin-top: 28px; }
|
||||
.tm-fb-ausnahmen > * + * { margin-top: 16px; }
|
||||
.tm-fb-sammel { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
|
||||
.tm-fb-sammel [aria-pressed='true'] { color: #fff; background: var(--kb-purple-soft); border-color: var(--kb-purple-line); }
|
||||
.tm-fb-einbau .tm-vorlagen-liste { margin-bottom: 4px; }
|
||||
.tm-fb-einbau .tm-feld textarea { min-height: 76px; }
|
||||
|
||||
/* ----------------------------------------------------------------- Handy --- */
|
||||
@media (max-width: 880px), (pointer: coarse) {
|
||||
@@ -295,6 +304,7 @@
|
||||
.tm-feed { padding: 12px; }
|
||||
.tm-frage-knoepfe > * { flex: 1 1 auto; }
|
||||
.tm-bestellen-aktion { justify-items: stretch; }
|
||||
.tm-fb-sammel > * { flex: 1 1 auto; }
|
||||
.tm-rechtstext { max-height: 260px; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) { #view-termine * { transition: none !important; animation: none !important; } }
|
||||
Reference in new issue
Block a user