Buchungskalender: Rechnungen, Einstellungen und Funktionen-Kachel

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
knsoandClaude Opus 5.5 committed 2026-10-07 14:23:19 +00:00
1 parent 10fe9a2ae0
commit efeb99e214
8 files changed
+696 -11

No files matched your search

+52 -1
View File
@@ -260,6 +260,51 @@ function shopTile(projects, features) {
</article>`
}
/* Buchungskalender (Schluessel unterkunft): Kachel nur, wenn der Server die Funktion freigibt (unterkunft.verfuegbar der Antwort, Schalter
UNTERKUNFT_ENABLED); sonst gar keine Kachel. Die Ansicht #buchungen (buchungen.js) zeigt Anfrage und Stand; die Kachel kennt nur den Zustand
des Funktionsdokuments (projects[].features.unterkunft: off | ordered | setup | active | disabled), Preis aus features.unterkunft.priceLabel,
Rueckfall 199 €. */
const UNTERKUNFT_PREIS = '199 €'
const UNTERKUNFT_TEXT = 'Belegungskalender auf deiner Website, Anfragen freigeben, Rechnung und Online-Zahlung'
const unterkunftOf = (project) => project.features?.unterkunft || { state: 'off' }
function pickUnterkunftProject(projects) {
return projects.find((p) => unterkunftOf(p).state === 'active')
|| projects.find((p) => isSetup(unterkunftOf(p).state))
|| projects.find((p) => unterkunftOf(p).state === 'disabled')
|| projects[0]
}
function unterkunftTile(projects, features) {
const preis = textOr(features?.unterkunft?.priceLabel, UNTERKUNFT_PREIS)
const active = projects.filter((p) => unterkunftOf(p).state === 'active').length
const target = pickUnterkunftProject(projects)
const state = target ? unterkunftOf(target).state : 'off'
const knopf = (text) => `<button type="button" class="kb-btn-primary fn-tile-cta" data-view="buchungen" data-project="${esc(target.projectId)}">${text}</button>`
const ZUSTAENDE = {
off: [['Aus', 'off'], 'Buchungskalender anfragen'],
ordered: [['Zahlung offen', 'setup'], 'Zahlung offen'],
setup: [['In Einrichtung', 'setup'], 'In Einrichtung'],
active: [['Aktiv', 'on'], 'Buchungskalender öffnen'],
disabled: [['Abgeschaltet', 'off'], 'Buchungskalender ansehen'],
}
const [pill, knopfText] = ZUSTAENDE[state] || ZUSTAENDE.off
const action = target ? knopf(knopfText) : ''
let extra = ''
if (!target) extra = '<p class="fn-count">Sobald deine Website angelegt ist, kannst du den Buchungskalender anfragen.</p>'
else if (state === 'disabled') extra = '<p>Der Buchungskalender ist für diese Website abgeschaltet. Deine Buchungen kannst du noch ansehen.</p>'
const count = projects.length > 1 && active ? `<p class="fn-count">aktiv für ${active} von ${projects.length} Websites</p>` : ''
return `
<article class="fn-tile" data-fn-tile="unterkunft">
<div class="fn-tile-head">${svg('calendar')}<span class="fn-pill fn-pill-${pill[1]}">${pill[0]}</span></div>
<h3>Buchungskalender</h3>
<p>${UNTERKUNFT_TEXT}. ${esc(preis)} einmalig.</p>
${extra}
${count}
${action}
</article>`
}
/* Oeffnungszeiten live: Kachel nur, wenn der Schalter es erlaubt (zeiten.verfuegbar); sonst gibt es sie gar nicht (auch kein "Kommt bald").
Wie bei den anderen Funktionen steht sie inline, die Ansicht #zeiten (zeiten.js) laedt app.js. Alles, was sie zeigt, kommt mit der Liste
(GET /api/funktionen): zeiten (Angebot) mit inklusive (true: im laufenden, aktiven Wartungs-Abo enthalten, einschaltbar | false: sonst, dann
@@ -386,12 +431,13 @@ const soonTile = (icon, title, text) => `
export async function initFunktionen(root) {
if (!root) return
const { projects = [], termine, features, shop, zeiten } = await request('/api/funktionen')
const { projects = [], termine, features, shop, zeiten, unterkunft } = await request('/api/funktionen')
root.innerHTML = `
<div class="fn-tiles">
${newsTile(projects, newsOffer(features).price)}
${termine?.verfuegbar ? termineTile(projects, termine) : soonTile('calendar', 'Terminplaner', TERMINE_TEXT)}
${shop?.verfuegbar ? shopTile(projects, features) : ''}
${unterkunft?.verfuegbar === true ? unterkunftTile(projects, features) : ''}
${zeiten?.verfuegbar === true ? zeitenTile(projects, zeiten) : ''}
${analyseTile(projects)}
</div>`
@@ -407,6 +453,11 @@ export async function initFunktionen(root) {
const body = document.getElementById('webshop-body')
if (body) body.dataset.wunschProjekt = ev.currentTarget.dataset.project
})
// Die Buchungskalender-Ansicht liest das gewaehlte Projekt aus ihrem Behaelter (buchungen.js, initBuchungen)
root.querySelector('[data-fn-tile="unterkunft"] .fn-tile-cta[data-project]')?.addEventListener('click', (ev) => {
const body = document.getElementById('buchungen-body')
if (body) body.dataset.wunschProjekt = ev.currentTarget.dataset.project
})
// Die Zeiten-Ansicht liest Projekt und Weg (Behalten) aus ihrem Behaelter (zeiten.js, initZeiten); der Klick steigt danach zum Navigationshandler auf
root.querySelector('[data-fn-tile="zeiten"]')?.addEventListener('click', (ev) => {
const knopf = ev.target?.closest?.('button[data-view="zeiten"]')