Öffnungszeiten: Plan-löschen-Rückfrage zählt die Ausnahmen beim Öffnen

Der Hinweis „Die N Ausnahmen, die nur für diesen Plan gelten, werden mit gelöscht“
wurde beim Bauen der Karte berechnet und war nach dem Speichern einer Ausnahme
veraltet. Er wird jetzt beim Öffnen der Rückfrage aus dem aktuellen Stand gelesen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-05 06:23:56 +00:00
1 parent f01ed15247
commit 242fbb01e5
3 files changed
+68 -9

No files matched your search

+12 -7
View File
@@ -273,17 +273,22 @@ function planKarte(t, plan) {
const speichern = h('button', { type: 'submit', class: 'kb-btn-primary', 'data-aktion': 'speichern' }, 'Speichern')
const grund = daten && !nurLesen ? planLoeschenGrund(daten, plan.id) : null
const mitAusnahmen = daten ? (daten.ausnahmen || []).filter((a) => a?.plan === plan.id).length : 0
// Wie viele Ausnahmen nur fuer diesen Plan gelten, steht erst beim Oeffnen der Rueckfrage fest: Ausnahmen zeichnen die Karte nicht neu
const mitAusnahmen = () => (Array.isArray(ctx.stand.daten?.ausnahmen) ? ctx.stand.daten.ausnahmen : []).filter((a) => a?.plan === plan.id).length
const loeschenText = () => {
const n = mitAusnahmen()
return [
LOESCHEN_WARNUNG,
n === 0 ? '' : n === 1
? 'Die eine Ausnahme, die nur für diesen Plan gilt, wird mit gelöscht.'
: `Die ${n} Ausnahmen, die nur für diesen Plan gelten, werden mit gelöscht.`,
]
}
const entfernen = daten && !nurLesen && grund === null ? entfernenKnopf(sp, {
knopfText: 'Plan löschen',
ja: 'Ja, löschen',
titel: `Zeitplan „${plan.name}“ löschen?`,
text: [
LOESCHEN_WARNUNG,
mitAusnahmen === 0 ? '' : mitAusnahmen === 1
? 'Die eine Ausnahme, die nur für diesen Plan gilt, wird mit gelöscht.'
: `Die ${mitAusnahmen} Ausnahmen, die nur für diesen Plan gelten, werden mit gelöscht.`,
],
text: loeschenText,
fehlerPfad: p,
// Ausnahmen, die nur fuer diesen Plan galten, haetten danach keinen Plan mehr (R10): sie gehen mit
aendere: (entwurf) => {
+4 -2
View File
@@ -185,7 +185,7 @@ export function nachSpeichern(t, meldung, selektor, neuZeichnen = () => t.zeichn
}
/**
* Knopf mit Rueckfrage in der Seite (kein confirm()): Titel, Erklaerung (text, ein Text oder eine Liste von Absaetzen), Platz fuer den Fehler
* Knopf mit Rueckfrage in der Seite (kein confirm()): Titel, Erklaerung (text: ein Text, eine Liste von Absaetzen oder eine Funktion, die beides beim Oeffnen liefert), Platz fuer den Fehler
* des Servers, Knoepfe. aendere(entwurf) entfernt den Eintrag, nachher() laeuft nach dem erfolgreichen Speichern (der Abschnitt zeichnet neu).
* Abbrechen schliesst die Rueckfrage und der Fokus geht zum Knopf zurueck. => { knopf, box }: der Aufrufer setzt beide NEBEN sein Formular, nicht
* hinein (ein submit der Rueckfrage stiege sonst ins aeussere Formular auf).
@@ -195,7 +195,9 @@ export function entfernenKnopf(sp, { knopfText = 'Entfernen', ja = 'Ja, entferne
const knopf = h('button', { type: 'button', class: 'kb-btn-outline tm-gefahr', 'data-aktion': 'entfernen' }, knopfText)
knopf.addEventListener('click', () => {
const { zeile } = knopfZeile(ja, () => { box.replaceChildren(); knopf.focus() })
const absaetze = (Array.isArray(text) ? text : [text]).filter(Boolean).map((t) => h('p', null, t))
// text darf eine Funktion sein: sie liest den Stand erst jetzt, beim Oeffnen (die Karte kann aelter sein als eine Ausnahme, die inzwischen dazukam)
const gesagt = typeof text === 'function' ? text() : text
const absaetze = (Array.isArray(gesagt) ? gesagt : [gesagt]).filter(Boolean).map((t) => h('p', null, t))
const rueckfrage = frage(titel,
...absaetze,
fehlerPfad ? h('p', { class: 'tm-fehler', 'data-fehler': fehlerPfad, role: 'alert' }) : null,
+52
View File
@@ -794,6 +794,58 @@ test('Plan hinzufügen, Hauptplan wechseln und Plan löschen zeichnen die Planli
assert.match(fx.text(feldIn(fx, urlaubsformular(fx, root), 'plan')), /Lieferdienst/)
}))
test('Plan löschen: die Rückfrage zählt die Ausnahmen des Plans beim Öffnen, auch wenn sie erst nach dem Zeichnen der Karte dazukamen oder wegfielen', mitDom({}, async (fx) => {
const { root } = await oeffne(fx, { start: stand(daten({ plaene: [plan(P1), plan(P2)] })) })
const loeschenOeffnen = async () => {
await fx.klick(fx.finde(planKarte(fx, root, P2), '[data-aktion="entfernen"]'))
return fx.finde(planKarte(fx, root, P2), '.tm-frage-box')
}
const abbrechen = (frage) => fx.klick(fx.finde(frage, 'button[type="button"]'))
assert.doesNotMatch(fx.text(await loeschenOeffnen()), /nur für diesen Plan/, 'noch keine Ausnahme des Plans')
await abbrechen(fx.finde(planKarte(fx, root, P2), '.tm-frage-box'))
// ein Sondertag „nur Küche“ kommt dazu: die Karte des Plans wird dabei nicht neu gezeichnet
const karte = planKarte(fx, root, P2)
await fx.klick(fx.finde(root, '[data-werkzeug="sondertag-neu"]'))
const form = fx.finde(root, 'form[aria-label="Sondertag eintragen"]')
const tag = tagPlus(HEUTE, 14)
await fx.setze(feldIn(fx, form, 'von'), tag)
await fx.setze(feldIn(fx, form, 'plan'), P2)
const sonder = { id: 'x_sonder001', art: 'sondertag', von: tag, bis: tag, text: '', modus: 'zu', fenster: [], plan: P2 }
fx.antworten.push(antwort(daten({ plaene: [plan(P1), plan(P2)], ausnahmen: [sonder] }), 4))
await fx.klick(fx.finde(form, 'button[type="submit"]'))
assert.equal(puts(fx)[0].body.daten.ausnahmen[0].plan, P2)
assert.equal(planKarte(fx, root, P2), karte, 'die Karte blieb stehen')
const frage = await loeschenOeffnen()
assert.match(fx.text(frage), /Die eine Ausnahme, die nur für diesen Plan gilt, wird mit gelöscht/)
assert.ok(fx.text(frage).includes('Steht dieser Plan auf deiner Website, zeigt sie dort wieder die feste Tabelle.'))
await abbrechen(frage)
// der Sondertag wird wieder entfernt: der Hinweis verschwindet
const zeile = fx.finde(root, 'li[data-id="x_sonder001"]')
await fx.klick(fx.finde(zeile, '[data-aktion="bearbeiten"]'))
await fx.klick(fx.finde(zeile, '[data-aktion="entfernen"]'))
fx.antworten.push(antwort(daten({ plaene: [plan(P1), plan(P2)] }), 5))
await fx.klick(fx.finde(fx.finde(zeile, '.tm-frage-box'), 'button[type="submit"]'))
assert.equal(planKarte(fx, root, P2), karte)
assert.doesNotMatch(fx.text(await loeschenOeffnen()), /nur für diesen Plan/, 'ohne Ausnahme kein Hinweis mehr')
await abbrechen(fx.finde(planKarte(fx, root, P2), '.tm-frage-box'))
// und der Plan wird tatsächlich mit seinen Ausnahmen gelöscht, wenn eine dazukam
const noch = { ...sonder, id: 'x_sonder002' }
await fx.klick(fx.finde(root, '[data-werkzeug="sondertag-neu"]'))
const form2 = fx.finde(root, 'form[aria-label="Sondertag eintragen"]')
await fx.setze(feldIn(fx, form2, 'von'), tag)
await fx.setze(feldIn(fx, form2, 'plan'), P2)
fx.antworten.push(antwort(daten({ plaene: [plan(P1), plan(P2)], ausnahmen: [noch] }), 6))
await fx.klick(fx.finde(form2, 'button[type="submit"]'))
const frage2 = await loeschenOeffnen()
assert.match(fx.text(frage2), /Die eine Ausnahme/)
fx.antworten.push(antwort(daten({ plaene: [plan(P1)] }), 7))
await fx.klick(fx.finde(frage2, 'button[type="submit"]'))
assert.deepEqual(puts(fx).at(-1).body.daten.ausnahmen, [], 'die Ausnahme des Plans ging mit')
}))
test('Plan umbenennen: die Liste der Ausnahmen nennt den neuen Namen, sonst bleibt sie stehen', mitDom({}, async (fx) => {
const ausnahme = { ...kurzerUrlaub('x_kueche01', 'Nur Küche'), plan: P2 }
const { root } = await oeffne(fx, { start: stand(daten({ plaene: [plan(P1), plan(P2)], ausnahmen: [ausnahme] })) })