From dee2d5e30b39bf90238724a347e08dbbd6be32f0 Mon Sep 17 00:00:00 2001 From: Kristian Wind Date: Thu, 20 Aug 2026 00:17:50 +0200 Subject: [PATCH] =?UTF-8?q?fix(faerdige):=20en=20opgave=20lukket=20efter?= =?UTF-8?q?=20midnat=20l=C3=A5=20under=20"I=20g=C3=A5r"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fundet af prøverne, som for første gang kørte forbi midnat. Dagen blev læst som `completed_at.slice(0, 10)` — de ti første tegn af et tidsstempel, der er i UTC. Overskriften sammenlignede med *lokal* dato. I dansk sommertid er de to ikke den samme dag i de første to timer efter midnat, så en opgave lukket 00.30 blev sat under "I går", indtil klokken blev to. Tyve timer i døgnet er de ens, hvilket er derfor prøven har været grøn hver eneste gang før. Dagen udregnes nu lokalt, som den overskrift den skal svare til. Og prøven for invitationslinket kunne kun bestå seks dage om ugen. Den ledte efter "males inden fredag" som én tekst, men hurtig tilføjelse læser "fredag" som forfaldsdatoen og tager ordet ud af titlen — tilbage står "males inden" plus et mærke, hvis ord skifter med ugedagen. Kørt på en torsdag hedder mærket "I morgen", og så fandt den ingenting. Prøven handler om invitationer, ikke om datoer, så den ser nu på titlen alene. Uddraget i notelisten viste `![](/api/v1/attachments/01a0…` for hver note med et billede i — den eneste tekst i listen, ingen havde skrevet. Co-Authored-By: Claude Opus 5 --- web/e2e/smoke.spec.js | 10 +++++++++- web/src/routes/faerdige/+page.svelte | 21 ++++++++++++++++++++- web/src/routes/noter/+page.svelte | 6 +++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/web/e2e/smoke.spec.js b/web/e2e/smoke.spec.js index 0bf9457..a968022 100644 --- a/web/e2e/smoke.spec.js +++ b/web/e2e/smoke.spec.js @@ -655,7 +655,15 @@ test('et invitationslink opretter kontoen og giver adgang til projektet', async await page.getByLabel('Ny opgave').fill('males inden fredag #Fælleshuset'); await page.getByLabel('Ny opgave').press('Enter'); - await page.getByText('males inden fredag', { exact: true }).click(); + // Titlen alene, ikke rækken med datomærket i. + // + // Hurtig tilføjelse læser "fredag" som forfaldsdatoen og tager ordet ud af + // titlen, så rækken er "males inden" plus et mærke, der siger hvornår. Mærkets + // ord skifter med ugedagen — "fredag", når der er langt, og "I morgen", når man + // kører prøven på en torsdag. Den her linje ledte efter hele rækken og fandt + // den derfor ikke én dag om ugen. Prøven handler om invitationer, ikke om + // datoer; den skal ikke vide hvilken dag det er. + await page.getByText('males inden', { exact: true }).click(); const drawer = page.getByRole('complementary', { name: 'Opgave' }); await drawer.getByLabel('Ansvarlig').selectOption({ label: 'Nabo' }); diff --git a/web/src/routes/faerdige/+page.svelte b/web/src/routes/faerdige/+page.svelte index 887d974..159d224 100644 --- a/web/src/routes/faerdige/+page.svelte +++ b/web/src/routes/faerdige/+page.svelte @@ -35,10 +35,29 @@ * A flat list of two hundred rows says when nothing. "I dag" and "I går" are * how anybody looking for something they just closed would describe it. */ + /** + * Dagen en opgave blev lukket, målt hvor personen står. + * + * Ikke `completed_at.slice(0, 10)`. Tidsstemplet er i UTC, og de ti første tegn + * er derfor UTC's dato — mens overskriften nedenfor sammenligner med *lokal* + * dato. I to timer efter midnat i dansk sommertid er de to ikke den samme dag, + * så en opgave lukket 00.30 lå under "I går", indtil klokken blev to. + * + * Fundet af prøven, som kørte forbi midnat for første gang. Den havde været + * grøn hver eneste gang før, fordi de to datoer er ens tyve timer i døgnet. + */ + const localDay = (iso) => { + if (!iso) return ''; + const d = new Date(iso); + if (Number.isNaN(d.getTime())) return ''; + const pad = (n) => String(n).padStart(2, '0'); + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; + }; + let days = $derived.by(() => { const groups = new Map(); for (const task of done) { - const key = (task.completed_at ?? '').slice(0, 10); + const key = localDay(task.completed_at); if (!groups.has(key)) groups.set(key, []); groups.get(key).push(task); } diff --git a/web/src/routes/noter/+page.svelte b/web/src/routes/noter/+page.svelte index 88283a1..67a12af 100644 --- a/web/src/routes/noter/+page.svelte +++ b/web/src/routes/noter/+page.svelte @@ -113,6 +113,10 @@ */ function plain(body) { return (body ?? '') + // Et billede har ingen ord i sig. Uden det her stod der + // "![](/api/v1/attachments/01a0…" i uddraget af hver note med et foto i, + // hvilket er den eneste tekst i listen, ingen har skrevet. + .replace(/!\[[^\]]*\]\([^)]*\)/g, '') .replace(/^#{1,6}\s+/gm, '') .replace(/^\s*[-*+]\s+/gm, '') .replace(/^\s*>\s?/gm, '') @@ -447,7 +451,7 @@ border: 0; background: none; padding: 2px var(--s1); - max-width: 11ch; + max-width: 13ch; } h1 {