From c7c1e338a3017af0fe511edafec817ab07126761 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 30 Sep 2026 10:24:18 +0000 Subject: [PATCH] Rechtliches: Abloesung am selben Tag, Kartenraster auf schmalen Bildschirmen Bei zwei gueltigen Versionen mit gleichem Beginn gilt die zuletzt angelegte; eine am selben Tag abgeloeste Version endet nie vor ihrem Beginn. Co-Authored-By: Claude Opus 5.5 --- src/components/legal/ProviderContractsTab.jsx | 2 +- src/lib/legal.js | 17 ++++++++++++++--- src/styles/global.css | 2 +- tests/legal.test.mjs | 12 ++++++++++++ 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/components/legal/ProviderContractsTab.jsx b/src/components/legal/ProviderContractsTab.jsx index 336932e..920fd92 100644 --- a/src/components/legal/ProviderContractsTab.jsx +++ b/src/components/legal/ProviderContractsTab.jsx @@ -15,7 +15,7 @@ function costLabel(c) { function termLabel(c) { if (c.termMonths === null || c.termMonths === undefined) return '–' if (c.termMonths === 0) return 'jederzeit kündbar' - const renew = c.renewalMonths ? `, verlängert um ${c.renewalMonths}` : ', endet danach' + const renew = c.renewalMonths ? `, dann je ${c.renewalMonths} Monate` : ', endet danach' return `${c.termMonths} Monate${renew}` } diff --git a/src/lib/legal.js b/src/lib/legal.js index 72462dd..29c2ca4 100644 --- a/src/lib/legal.js +++ b/src/lib/legal.js @@ -81,11 +81,22 @@ export function deadlineTone(result, today) { return 'normal' } -/** Aktuell gueltige Version; bei mehreren (z. B. halb gescheiterte Abloesung) die juengste. */ +// Tag vor dem neuen Beginn, aber nie vor dem eigenen Beginn (Abloesung am selben Tag). +function dayBeforeOrSame(nextFrom, ownFrom) { + const before = addDays(nextFrom, -1) + return ownFrom && before < ownFrom ? ownFrom : before +} + +const newness = (v) => `${v.validFrom || ''}|${v.$createdAt || ''}` + +/** + * Aktuell gueltige Version; bei mehreren (z. B. halb gescheiterte Abloesung) die mit dem + * juengsten validFrom, bei gleichem Datum die zuletzt angelegte. + */ export function currentVersion(versions) { return versions .filter((v) => v.status === 'current') - .reduce((best, v) => (!best || v.validFrom > best.validFrom ? v : best), null) + .reduce((best, v) => (!best || newness(v) > newness(best) ? v : best), null) } /** @@ -103,7 +114,7 @@ export function planNewVersion(versions, input) { const current = currentVersion(siblings) if (!current || input.validFrom >= current.validFrom) { const updates = current - ? [{ id: current.$id, patch: { status: 'superseded', validTo: addDays(input.validFrom, -1) } }] + ? [{ id: current.$id, patch: { status: 'superseded', validTo: dayBeforeOrSame(input.validFrom, current.validFrom) } }] : [] return { create: { ...input, validTo: null }, updates } } diff --git a/src/styles/global.css b/src/styles/global.css index eb90e1e..56adbd8 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -1110,7 +1110,7 @@ textarea.form-control { } /* --- Rechtliches --- */ -.legal-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: var(--sp-4); align-items: start; margin-top: var(--sp-4); } +.legal-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(360px, 100%), 1fr)); gap: var(--sp-4); align-items: start; margin-top: var(--sp-4); } .legal-grid > .legal-error { grid-column: 1 / -1; } .legal-doc-summary { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; cursor: pointer; } .legal-toggle { margin-left: auto; font-size: 13px; } diff --git a/tests/legal.test.mjs b/tests/legal.test.mjs index de7938d..292492a 100644 --- a/tests/legal.test.mjs +++ b/tests/legal.test.mjs @@ -124,3 +124,15 @@ test('formatDate', () => { assert.equal(formatDate(''), '–') assert.equal(formatDate(null), '–') }) + +test('currentVersion: bei gleichem validFrom gewinnt die zuletzt angelegte', () => { + const a = { ...v5, $id: 'a', validFrom: '2026-09-30', $createdAt: '2026-09-30T10:00:00.000Z' } + const b = { ...v5, $id: 'b', validFrom: '2026-09-30', $createdAt: '2026-09-30T11:00:00.000Z' } + assert.equal(currentVersion([a, b]).$id, 'b') + assert.equal(currentVersion([b, a]).$id, 'b') +}) + +test('Abloesung am selben Tag: validTo nie vor validFrom', () => { + const r = planNewVersion([v5], { documentKey: 'agb', version: 'v6', status: 'current', validFrom: '2026-05-01' }) + assert.deepEqual(r.updates, [{ id: 'v5', patch: { status: 'superseded', validTo: '2026-05-01' } }]) +})