167 lines
7.8 KiB
JavaScript
167 lines
7.8 KiB
JavaScript
/* Terminplaner im Kundenbereich: Aktionen auf Terminen mit Rueckfrage in der Seite (kein confirm()).
|
||
starteAktion(t, li, b, art, knopf) oeffnet die Rueckfrage unter dem Termin, fuehreAus schickt sie an /api/termine ab.
|
||
t ist der Zustand des Reiters "Termine": { ctx, offen, nachAenderung() } – nachAenderung laedt Liste und Zahl der Anfragen neu
|
||
(der Reiter setzt sie; so kennt dieses Modul den Reiter nicht). Fehler: 400 und belegte Zeit bleiben in der Rueckfrage,
|
||
alles andere erscheint als Meldung ueber den Reitern. */
|
||
|
||
import { MAX, ABSAGE_GRUENDE, datumKurz, heuteBerlin } from './termine-view.js'
|
||
import { allgemeinerFehler, feld, frage, h, knopfZeile, setzeFehler, zeigeFehler } from './termine-dom.js'
|
||
import { zeitWahl } from './termine-formulare.js'
|
||
|
||
export const AKTION_TEXT = {
|
||
annehmen: 'Annehmen', ablehnen: 'Ablehnen', verschieben: 'Verschieben', absagen: 'Absagen', nichterschienen: 'Nicht erschienen',
|
||
anonymisieren: 'Gastdaten löschen', entsperren: 'Sperre aufheben',
|
||
}
|
||
|
||
export function schliesseFrage(t, fokus = false) {
|
||
if (!t.offen) return
|
||
const { li, knopf } = t.offen
|
||
li.querySelector('[data-frage]')?.replaceChildren()
|
||
li.classList.remove('tm-offen')
|
||
t.offen = null
|
||
if (fokus && knopf?.isConnected) knopf.focus()
|
||
}
|
||
|
||
export function starteAktion(t, li, b, art, knopf) {
|
||
t.ctx.meldung('')
|
||
schliesseFrage(t)
|
||
const zu = () => schliesseFrage(t, true)
|
||
const fragen = { annehmen: frageAnnehmen, ablehnen: frageAblehnen, absagen: frageAbsagen, verschieben: frageVerschieben, nichterschienen: frageNichtErschienen, anonymisieren: frageAnonymisieren, entsperren: frageEntsperren }
|
||
const box = fragen[art](t, b, zu)
|
||
li.querySelector('[data-frage]').replaceChildren(box)
|
||
li.classList.add('tm-offen')
|
||
t.offen = { li, knopf, art }
|
||
// Fokus ins erste Eingabefeld; ohne Eingabefeld auf die Rueckfrage selbst, damit ein Enter nichts bestaetigt
|
||
const erster = box.querySelector('select, textarea, input') || box
|
||
erster.focus()
|
||
}
|
||
|
||
/**
|
||
* Aktion an die Schnittstelle schicken. erfolg = Text der Meldung. form = Rueckfrage-Formular fuer Fehler (400 und belegte Zeit
|
||
* bleiben dort), sonst Meldung ueber den Reitern; bei Fehlern, die auf einen geaenderten Stand deuten (404, 409), wird die Liste neu geladen.
|
||
*/
|
||
async function fuehreAus(t, b, body, erfolg, form, knopf) {
|
||
const { ctx } = t
|
||
knopf.disabled = true
|
||
try {
|
||
const entsperren = body.aktion === 'entsperren'
|
||
const antwort = entsperren
|
||
? await ctx.api.send('DELETE', `/buchungen/${encodeURIComponent(b.id)}`)
|
||
: await ctx.api.send('POST', `/buchungen/${encodeURIComponent(b.id)}/aktion`, body)
|
||
await t.nachAenderung() // erst die Liste, dann die Meldung: wer die Meldung sieht, sieht auch den neuen Stand
|
||
ctx.meldung(antwort.schon ? 'Das war schon so erledigt.' : erfolg)
|
||
} catch (err) {
|
||
const imFormular = form && (err.status === 400 || err.code === 'SLOT_VERGEBEN')
|
||
if (imFormular) {
|
||
zeigeFehler(form, err)
|
||
knopf.disabled = false
|
||
return
|
||
}
|
||
ctx.meldung(err.message, 'fehler')
|
||
if (err.status === 404 || err.status === 409) await t.nachAenderung()
|
||
else knopf.disabled = false
|
||
}
|
||
}
|
||
|
||
const mailHinweis = (b, text) => (b.gastEmail ? text : 'Der Gast bekommt keine E-Mail, weil keine Adresse hinterlegt ist.')
|
||
|
||
// Annehmen schliesst den Vertrag und verschickt die Bestaetigung (G02): wie jede Aktion erst nach einer Rueckfrage in der Seite
|
||
function frageAnnehmen(t, b, zu) {
|
||
const { ok, zeile } = knopfZeile('Annehmen', zu)
|
||
const form = frage('Anfrage annehmen?',
|
||
h('p', null, b.gastEmail
|
||
? `${b.gastName} bekommt eine Bestätigung per E-Mail. Mit dem Annehmen kommt der Termin zustande.`
|
||
: 'Der Gast bekommt keine E-Mail, weil keine Adresse hinterlegt ist. Mit dem Annehmen kommt der Termin zustande.'),
|
||
allgemeinerFehler(),
|
||
zeile)
|
||
const erfolg = b.gastEmail ? `Anfrage angenommen. ${b.gastName} bekommt eine Bestätigung per E-Mail.` : 'Anfrage angenommen.'
|
||
form.addEventListener('submit', () => fuehreAus(t, b, { aktion: 'annehmen' }, erfolg, form, ok))
|
||
return form
|
||
}
|
||
|
||
function frageAblehnen(t, b, zu) {
|
||
const nachricht = h('textarea', { rows: '3', maxlength: String(MAX.nachricht) })
|
||
const { ok, zeile } = knopfZeile('Anfrage ablehnen', zu)
|
||
const form = frage('Anfrage ablehnen?',
|
||
h('p', null, mailHinweis(b, 'Der Gast bekommt eine E-Mail, dass der Termin nicht möglich ist. Die Zeit wird wieder frei.')),
|
||
feld('nachricht', 'Nachricht an den Gast (optional)', nachricht),
|
||
allgemeinerFehler(),
|
||
zeile)
|
||
form.addEventListener('submit', () => fuehreAus(t, b, { aktion: 'ablehnen', nachricht: nachricht.value }, 'Anfrage abgelehnt.', form, ok))
|
||
return form
|
||
}
|
||
|
||
function frageAbsagen(t, b, zu) {
|
||
const grund = h('select', null, h('option', { value: '' }, 'Bitte wählen'), ABSAGE_GRUENDE.map((g) => h('option', { value: g }, g)))
|
||
const nachricht = h('textarea', { rows: '3', maxlength: String(MAX.nachricht) })
|
||
const { ok, zeile } = knopfZeile('Termin absagen', zu)
|
||
const form = frage('Termin absagen?',
|
||
h('p', null, mailHinweis(b, 'Der Gast bekommt eine E-Mail mit dem Grund. Die Zeit wird wieder frei.')),
|
||
feld('grund', 'Grund', grund),
|
||
feld('nachricht', 'Nachricht an den Gast (optional)', nachricht),
|
||
allgemeinerFehler(),
|
||
zeile)
|
||
form.addEventListener('submit', () => {
|
||
if (!grund.value) {
|
||
setzeFehler(form, { grund: 'Bitte wähle einen Grund aus.' })
|
||
grund.focus()
|
||
return
|
||
}
|
||
fuehreAus(t, b, { aktion: 'absagen', grund: grund.value, nachricht: nachricht.value }, 'Termin abgesagt.', form, ok)
|
||
})
|
||
return form
|
||
}
|
||
|
||
function frageNichtErschienen(t, b, zu) {
|
||
const { ok, zeile } = knopfZeile('Ja, nicht erschienen', zu)
|
||
const form = frage('Als „nicht erschienen“ markieren?',
|
||
h('p', null, 'Der Termin bleibt in der Liste und wird als „Nicht erschienen“ geführt. Der Gast bekommt keine E-Mail.'),
|
||
allgemeinerFehler(),
|
||
zeile)
|
||
form.addEventListener('submit', () => fuehreAus(t, b, { aktion: 'nichterschienen' }, 'Als „nicht erschienen“ markiert.', form, ok))
|
||
return form
|
||
}
|
||
|
||
function frageAnonymisieren(t, b, zu) {
|
||
const { ok, zeile } = knopfZeile('Gastdaten löschen', zu)
|
||
const form = frage('Gastdaten löschen?',
|
||
h('p', null, 'Name, E-Mail, Telefon und Nachricht werden gelöscht. Das lässt sich nicht rückgängig machen. Der Termin bleibt ohne Namen bestehen, die Links in alten E-Mails funktionieren danach nicht mehr.'),
|
||
allgemeinerFehler(),
|
||
zeile)
|
||
form.addEventListener('submit', () => fuehreAus(t, b, { aktion: 'anonymisieren' }, 'Gastdaten gelöscht.', form, ok))
|
||
return form
|
||
}
|
||
|
||
function frageEntsperren(t, b, zu) {
|
||
const { ok, zeile } = knopfZeile('Sperre aufheben', zu)
|
||
const form = frage('Sperre aufheben?',
|
||
h('p', null, 'Die Zeit ist danach wieder buchbar.'),
|
||
allgemeinerFehler(),
|
||
zeile)
|
||
form.addEventListener('submit', () => fuehreAus(t, b, { aktion: 'entsperren' }, 'Sperre aufgehoben.', form, ok))
|
||
return form
|
||
}
|
||
|
||
function frageVerschieben(t, b, zu) {
|
||
const { ctx } = t
|
||
const datum = h('input', { type: 'date', value: b.datum, min: heuteBerlin() })
|
||
const zeiten = zeitWahl(ctx, () => ({ ohne: b.id, tag: datum.value }))
|
||
const { ok, zeile } = knopfZeile('Verschieben', zu)
|
||
const form = frage('Termin verschieben',
|
||
h('p', null, mailHinweis(b, 'Der Gast bekommt eine E-Mail mit der neuen Zeit. Es gelten keine Fristen und kein Vorlauf.')),
|
||
feld('tag', 'Neuer Tag', datum),
|
||
zeiten.el,
|
||
allgemeinerFehler(),
|
||
zeile)
|
||
datum.addEventListener('change', () => zeiten.laden())
|
||
zeiten.laden()
|
||
form.addEventListener('submit', () => {
|
||
if (!zeiten.wert()) {
|
||
setzeFehler(form, { zeit: 'Bitte wähle eine Uhrzeit aus.' })
|
||
return
|
||
}
|
||
fuehreAus(t, b, { aktion: 'verschieben', tag: datum.value, zeit: zeiten.wert() }, `Termin verschoben auf ${datumKurz(datum.value)}, ${zeiten.wert()} Uhr.`, form, ok)
|
||
})
|
||
return form
|
||
}
|