Terminplaner: Portal-Ansicht Leistungen, Team, Einstellungen
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
650919b022
commit
0b75b31009
15 files changed
+2479
-79
No files matched your search
+33
-24
@@ -1,15 +1,19 @@
|
||||
/* Terminplaner im Kundenbereich (ES-Modul; app.js laedt es erst beim Oeffnen der Ansicht #termine). Das ist die Huelle:
|
||||
initTermine(rootEl, { projectId }): Projektauswahl, Vorlagenauswahl beim ersten Oeffnen, Reiter-Geruest und die Meldung ueber den Reitern.
|
||||
Die Reiter stehen in REITER: jeder ist ein Modul mit render(panel, ctx) => void | Promise (Termine: termine-tab-termine.js; Leistungen,
|
||||
Team & Plaetze und Einstellungen (Aufgabe 21b) ersetzen dort nur ihren Platzhalter).
|
||||
ctx = { s, projectId, daten, nurLesen, auswahl, aktuell(), api, meldung, zumReiter, neuLaden }: Zustand und Pruefung "bin ich noch
|
||||
aktuell?" bekommen die Reiter nur ueber ctx, nie ueber Modulvariablen. daten ist die Antwort von GET /api/termine/einstellungen,
|
||||
nurLesen gilt fuer abgeschaltete Funktionen. Server: server/routes/termine.js. Tage sind Berliner Kalendertage 'JJJJ-MM-TT';
|
||||
Die Reiter stehen in REITER: jeder ist ein Modul mit render(panel, ctx) => void | Promise (termine-tab-termine.js, termine-tab-leistungen.js,
|
||||
termine-tab-team.js, termine-tab-einstellungen.js; die drei letzten speichern ueber termine-speichern.js).
|
||||
ctx = { s, projectId, daten, nurLesen, auswahl, aktuell(), api, meldung, hinweise, zumReiter, neuLaden }: Zustand und Pruefung "bin ich noch
|
||||
aktuell?" bekommen die Reiter nur ueber ctx, nie ueber Modulvariablen. daten ist die Antwort von GET /api/termine/einstellungen
|
||||
(die Reiter, die speichern, halten daten.einstellung und daten.version aktuell), nurLesen gilt fuer abgeschaltete Funktionen,
|
||||
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 { exportUrl, fehlerKarte, h, infoKarte, request } from './termine-dom.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'
|
||||
import { render as renderTeam } from './termine-tab-team.js'
|
||||
import { render as renderEinstellungen } from './termine-tab-einstellungen.js'
|
||||
|
||||
// Auswahl bleibt beim Wechsel zwischen Funktionen und Terminplaner erhalten (der Tag nicht: er beginnt immer bei heute)
|
||||
const auswahl = { projectId: '', reiter: 'termine', ansicht: 'tag', filter: 'alle' }
|
||||
@@ -61,7 +65,7 @@ const ladeDaten = (projectId) => request(`/api/termine/einstellungen?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 ',
|
||||
h('a', { href: exportUrl(projectId), download: 'termine.csv' }, 'exportieren'),
|
||||
exportLink(projectId, 'exportieren'),
|
||||
'.')
|
||||
|
||||
/**
|
||||
@@ -131,16 +135,12 @@ function zeigeVorlagen(s, { projekt, aktuell }) {
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- Reiter-Gerüst --- */
|
||||
const platzhalter = (titel, text) => (panel) => {
|
||||
panel.replaceChildren(h('div', { class: 'kb-panel tm-info' }, h('h3', null, titel), h('p', null, text)))
|
||||
}
|
||||
|
||||
/** key, Beschriftung, Funktion (panel, ctx). Aufgabe 21b ersetzt die Platzhalter, sonst bleibt alles wie es ist. */
|
||||
/** key, Beschriftung, Funktion (panel, ctx). */
|
||||
const REITER = [
|
||||
{ key: 'termine', label: 'Termine', render: renderTermine },
|
||||
{ key: 'leistungen', label: 'Leistungen', render: platzhalter('Leistungen', 'Hier legst du bald fest, was deine Kundschaft buchen kann – mit Dauer, Preis und Reihenfolge.') },
|
||||
{ key: 'team', label: 'Team & Plätze', render: platzhalter('Team & Plätze', 'Hier pflegst du bald Personen und Plätze mit ihren Zeiten, Urlaub und Kalender-Links.') },
|
||||
{ key: 'einstellungen', label: 'Einstellungen', render: platzhalter('Einstellungen', 'Hier ändern wir bald Betriebsangaben, Regeln und Texte für deine Gäste.') },
|
||||
{ key: 'leistungen', label: 'Leistungen', render: renderLeistungen },
|
||||
{ key: 'team', label: 'Team & Plätze', render: renderTeam },
|
||||
{ key: 'einstellungen', label: 'Einstellungen', render: renderEinstellungen },
|
||||
]
|
||||
|
||||
/**
|
||||
@@ -177,26 +177,35 @@ function zeigeReiter(s, { projekt, aktuell }) {
|
||||
? request(`/api/termine${pfad}?${new URLSearchParams({ projectId })}`, { method })
|
||||
: request(`/api/termine${pfad}`, { method, body: { projectId, ...body } })),
|
||||
},
|
||||
meldung: (text, art) => zeigeMeldung(s, text, art),
|
||||
// eine Meldung, die erst nach dem Wechsel der Website oder der Ansicht eintrifft, gehoert nicht mehr auf diese Seite
|
||||
meldung: (text, art) => { if (aktuell()) zeigeMeldung(s, text, art) },
|
||||
hinweise: () => { if (aktuell()) zeichneHinweise() },
|
||||
zumReiter: (key) => waehleReiter(key),
|
||||
neuLaden: async () => {
|
||||
const daten = await ladeDaten(projectId)
|
||||
if (aktuell()) {
|
||||
s.daten = daten
|
||||
ctx.daten = daten
|
||||
zeichneHinweise()
|
||||
}
|
||||
return daten
|
||||
},
|
||||
}
|
||||
|
||||
const hinweise = []
|
||||
if (nurLesen) {
|
||||
hinweise.push(hinweisAbgeschaltet(projectId))
|
||||
} 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.`),
|
||||
h('button', { type: 'button', class: 'kb-btn-outline', onclick: () => waehleReiter('einstellungen') }, 'Zu den Einstellungen')))
|
||||
// Hinweisleiste: abgeschaltet, oder Pflichtangaben fuer Gaeste fehlen (GET /einstellungen: fehlt). Sie folgt s.daten.
|
||||
const hinweisBox = h('div', { class: 'tm-hinweise' })
|
||||
function zeichneHinweise() {
|
||||
const hinweise = []
|
||||
if (nurLesen) {
|
||||
hinweise.push(hinweisAbgeschaltet(projectId))
|
||||
} 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.`),
|
||||
h('button', { type: 'button', class: 'kb-btn-outline', onclick: () => waehleReiter('einstellungen') }, 'Zu den Einstellungen')))
|
||||
}
|
||||
hinweisBox.replaceChildren(...hinweise)
|
||||
}
|
||||
zeichneHinweise()
|
||||
|
||||
const panel = h('div', { class: 'tm-panel', role: 'tabpanel', id: 'tm-panel', tabindex: '0' })
|
||||
const knoepfe = REITER.map((r) => h('button', {
|
||||
@@ -229,7 +238,7 @@ function zeigeReiter(s, { projekt, aktuell }) {
|
||||
.catch((err) => { if (aktuell()) panel.replaceChildren(fehlerKarte(err.message, () => waehleReiter(reiter.key))) })
|
||||
}
|
||||
|
||||
s.buehne.replaceChildren(...hinweise, s.meldungEl, leiste, panel)
|
||||
s.buehne.replaceChildren(hinweisBox, s.meldungEl, leiste, panel)
|
||||
waehleReiter(auswahl.reiter)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user