diff --git a/public/zeiten-plaene.js b/public/zeiten-plaene.js index ddb2a7f..a133cc6 100644 --- a/public/zeiten-plaene.js +++ b/public/zeiten-plaene.js @@ -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) => { diff --git a/public/zeiten-speichern.js b/public/zeiten-speichern.js index 3077e0f..e6f800f 100644 --- a/public/zeiten-speichern.js +++ b/public/zeiten-speichern.js @@ -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, diff --git a/test/zeitenEditor.test.js b/test/zeitenEditor.test.js index 797b63d..92e47ee 100644 --- a/test/zeitenEditor.test.js +++ b/test/zeitenEditor.test.js @@ -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] })) })