Buchungskalender: im Abo-Modell Anfrage ohne Preis und Einschalten nach der Zusage
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
28da4180bd
commit
5f3d8f3e96
4 files changed
+122
-23
No files matched your search
+20
-14
@@ -16,21 +16,27 @@ const artWert = (a) => (a === 'monteur' ? 'monteurzimmer' : a)
|
||||
const labelVon = (liste, key) => liste.find(([k]) => k === key)?.[1] || ''
|
||||
const enc = encodeURIComponent
|
||||
|
||||
/** Angaben der Anfrage als Definitionsliste (nur Text). */
|
||||
export function anfrageListe(a) {
|
||||
const s = a && typeof a === 'object' ? a : {}
|
||||
const portale = (Array.isArray(s.portale) ? s.portale : []).map((p) => labelVon(PORTALE, p)).filter(Boolean).join(', ')
|
||||
const zeilen = [
|
||||
['Art der Unterkunft', labelVon(ARTEN, artWert(s.art))],
|
||||
['Anzahl Einheiten', Number.isInteger(s.einheiten) ? String(s.einheiten) : ''],
|
||||
/** Angaben der Anfrage als Zeilen [{ name, wert }] (Definitionsliste und Gruppe der Einschalt-Seite); ohne Objekt leer. */
|
||||
export function anfrageZeilen(a) {
|
||||
if (a === null || typeof a !== 'object') return []
|
||||
const portale = (Array.isArray(a.portale) ? a.portale : []).map((p) => labelVon(PORTALE, p)).filter(Boolean).join(', ')
|
||||
return [
|
||||
['Art der Unterkunft', labelVon(ARTEN, artWert(a.art))],
|
||||
['Anzahl Einheiten', Number.isInteger(a.einheiten) ? String(a.einheiten) : ''],
|
||||
['Portale', portale || 'keine'],
|
||||
['Nachricht', text(s.nachricht)],
|
||||
].filter(([, wert]) => wert !== '')
|
||||
return h('dl', { class: 'sh-fakten' }, zeilen.map(([name, wert]) => h('div', null, h('dt', null, name), h('dd', null, wert))))
|
||||
['Nachricht', text(a.nachricht)],
|
||||
].filter(([, wert]) => wert !== '').map(([name, wert]) => ({ name, wert }))
|
||||
}
|
||||
|
||||
/** Formular „Buchungskalender anfragen“ in root; nachSenden(anfrage) wird nach dem Speichern aufgerufen (die Ansicht zeichnet sich neu). */
|
||||
export function renderAnfrageFormular(root, { projectId, vorgabe = null, preis = KALENDER_PREIS, nachSenden } = {}) {
|
||||
/** Angaben der Anfrage als Definitionsliste (nur Text). */
|
||||
export const anfrageListe = (a) => h('dl', { class: 'sh-fakten' }, anfrageZeilen(a).map(({ name, wert }) => h('div', null, h('dt', null, name), h('dd', null, wert))))
|
||||
|
||||
/**
|
||||
* Formular „Buchungskalender anfragen“ in root; nachSenden(anfrage) wird nach dem Speichern aufgerufen (die Ansicht zeichnet sich neu).
|
||||
* modell === 'abo': die Stichpunkte nennen „Im Wartungs-Abo enthalten.“ statt des Preises und „einschalten“ statt „bestellen“.
|
||||
*/
|
||||
export function renderAnfrageFormular(root, { projectId, vorgabe = null, preis = KALENDER_PREIS, nachSenden, modell } = {}) {
|
||||
const abo = modell === 'abo'
|
||||
const v = vorgabe && typeof vorgabe === 'object' ? vorgabe : {}
|
||||
const art = h('select', null, [h('option', { value: '' }, 'Bitte wählen …'), ...ARTEN.map(([w, n]) => h('option', { value: w }, n))])
|
||||
art.value = ARTEN.some(([k]) => k === artWert(v.art)) ? artWert(v.art) : ''
|
||||
@@ -91,10 +97,10 @@ export function renderAnfrageFormular(root, { projectId, vorgabe = null, preis =
|
||||
h('h3', null, 'Buchungskalender anfragen'),
|
||||
h('p', null, 'Mit dem Buchungskalender zeigst du auf deiner Website, wann deine Unterkunft frei ist. Gäste fragen direkt an, du gibst frei, und die Rechnung entsteht automatisch.'),
|
||||
h('ul', null,
|
||||
h('li', null, `${preis} einmalig für den Einbau in deine Website.`),
|
||||
h('li', null, abo ? 'Im Wartungs-Abo enthalten.' : `${preis} einmalig für den Einbau in deine Website.`),
|
||||
h('li', null, 'Belegungskalender mit Abgleich zu Booking.com und Airbnb (über iCal).'),
|
||||
h('li', null, 'Rechnung in deinem Namen und optional Online-Zahlung auf dein eigenes Stripe-Konto.'),
|
||||
h('li', null, 'Wir sehen uns deine Anfrage kurz an. Erst nach unserer Zusage kannst du bestellen.')))
|
||||
h('li', null, abo ? 'Wir sehen uns deine Anfrage kurz an. Erst nach unserer Zusage kannst du einschalten.' : 'Wir sehen uns deine Anfrage kurz an. Erst nach unserer Zusage kannst du bestellen.')))
|
||||
const karte = h('section', { class: 'kb-panel sh-anfrage' }, erklaerung, form)
|
||||
root.replaceChildren(karte)
|
||||
return karte
|
||||
|
||||
+21
-8
@@ -5,8 +5,8 @@
|
||||
Helfer: shop-dom.js (h, request, Karten), Styles: buchungen.css (bk-) und shop.css (sh-). Fremdtext nur ueber textContent. */
|
||||
|
||||
import { fehlerKarte, h, infoKarte, request } from './shop-dom.js'
|
||||
import { statusKarte } from './funktion-bestellen.js'
|
||||
import { anfrageKarte, renderAnfrageFormular } from './buchungen-anfrage.js'
|
||||
import { renderEinschaltSeite, statusKarte } from './funktion-bestellen.js'
|
||||
import { anfrageKarte, anfrageZeilen, renderAnfrageFormular } from './buchungen-anfrage.js'
|
||||
import { meldeReiter, reiterEintraege } from './fn-reiter.js'
|
||||
|
||||
/** Die Reiter: jeder ein Modul mit render(panel, ctx), erst beim ersten Oeffnen geladen. */
|
||||
@@ -34,22 +34,22 @@ const istAbo = (s) => s.modell === 'abo'
|
||||
const keineReiter = (s) => { if (istAbo(s)) meldeReiter(s.root, { eintraege: [] }) }
|
||||
const zustandVon = (projekt) => projekt?.features?.unterkunft?.state || 'off'
|
||||
|
||||
export function initBuchungen(root, { projectId } = {}) {
|
||||
export function initBuchungen(root, { projectId, einschalten } = {}) {
|
||||
if (!root) return Promise.resolve()
|
||||
const wunsch = projectId || root.dataset?.wunschProjekt || '' // die Kachel in Funktionen legt ihr Projekt hier ab
|
||||
if (root.dataset) delete root.dataset.wunschProjekt
|
||||
return starte(root, wunsch)
|
||||
return starte(root, wunsch, einschalten)
|
||||
}
|
||||
|
||||
async function starte(root, projectId) {
|
||||
async function starte(root, projectId, einschalten) {
|
||||
if (projectId) auswahl.projectId = projectId
|
||||
const s = { root, projects: [], modell: undefined, projekt: null, status: null, lauf: 0, buehne: null, meldungEl: null }
|
||||
const s = { root, projects: [], modell: undefined, projekt: null, status: null, lauf: 0, buehne: null, meldungEl: null, einschalten }
|
||||
S = s
|
||||
let funktionen
|
||||
try {
|
||||
funktionen = await request('/api/funktionen')
|
||||
} catch (err) {
|
||||
if (S === s) root.replaceChildren(fehlerKarte(err.message, () => starte(root, auswahl.projectId)))
|
||||
if (S === s) root.replaceChildren(fehlerKarte(err.message, () => starte(root, auswahl.projectId, einschalten)))
|
||||
return
|
||||
}
|
||||
if (S !== s) return
|
||||
@@ -136,7 +136,19 @@ function zeigeAnfrage(s, { status, aktuell }) {
|
||||
const ansicht = status?.anfrage
|
||||
// nach einem 409 bleibt die Meldung des Servers sichtbar, waehrend die Ansicht neu laedt
|
||||
const neuLaden = async (o) => { await zeigeProjekt(s); if (o?.meldung && S === s) zeigeMeldung(s, o.meldung, 'fehler') }
|
||||
if (ansicht?.status === 'angenommen') {
|
||||
if (ansicht?.status === 'angenommen' && istAbo(s)) {
|
||||
// Abo-Modell: die Zusage fuehrt zum Einschalten (kein Preis, keine Haken, keine Bestellung)
|
||||
const wurzel = h('div', { class: 'sh-wurzel' })
|
||||
s.buehne.replaceChildren(wurzel)
|
||||
renderEinschaltSeite(wurzel, {
|
||||
ctx: { projectId, aktuell },
|
||||
daten: { offen: [], kundenansicht: false },
|
||||
key: 'unterkunft',
|
||||
zusammenfassung: () => (ansicht.anfrage ? [{ schritt: 'anfrage', titel: 'Deine Anfrage', zeilen: anfrageZeilen(ansicht.anfrage).map(({ name, wert }) => `${name}: ${wert}`) }] : []),
|
||||
einschalten: s.einschalten,
|
||||
nachEinschalten: () => zeigeProjekt(s),
|
||||
})
|
||||
} else if (ansicht?.status === 'angenommen') {
|
||||
s.buehne.replaceChildren(infoKarte('Deine Anfrage wurde angenommen', 'Wir melden uns bei dir mit den nächsten Schritten zur Bestellung.', { chat: true }))
|
||||
} else if (ansicht?.status === 'offen') {
|
||||
s.buehne.replaceChildren(anfrageKarte(ansicht, { projectId, neuLaden }))
|
||||
@@ -149,6 +161,7 @@ function zeigeAnfrage(s, { status, aktuell }) {
|
||||
projectId,
|
||||
vorgabe: ansicht?.anfrage || null,
|
||||
preis: textOr(s.projekt?.features?.unterkunft?.priceLabel) || '199 €',
|
||||
modell: s.modell,
|
||||
nachSenden: async (_a, o) => { s.neueAnfrage = false; if (aktuell()) await neuLaden(o) },
|
||||
})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user