feat(tasks): tid på en opgave, og et træk i kalenderen sætter den
Release / Build and publish image (push) Failing after 9m58s

Bedt om: "jeg vil have tid på opgaver, og jeg vil kunne justere dem i kalenderen."

Serveren kunne det hele i forvejen — `due_date` og `due_time` læses sammen og
bliver til et `due_datetime` i kontoens tidszone. Det var fladen, der ikke havde
nogen vej til at sige det.

**Et felt i opgaveruden.** Tomt, indtil nogen sætter det: en opgave uden
klokkeslæt er det almindelige, og et felt, der åbner på 00:00, påstår, at noget
skal ske ved midnat.

**Og en fejl, der lå og ventede.** Serveren læser en dato uden en tid som "ryd
tiden". Så et gem af datoen alene tog klokkeslættet med sig — man rettede dagen og
mistede timen — og det samme gjorde hvert eneste træk i kalenderen. Ingen af
delene sagde noget.

`reschedule` siger nu tiden højt, tre måder, fordi de to første ligner hinanden i
JavaScript og derfor skal skilles ad ét sted frem for at blive forvekslet fire:

    undefined   behold den, opgaven har   — månedens ruder, hvor der ingen tid er at læse
    ''          ryd den                   — heldagsbåndet
    'HH:MM'     sæt den                   — et sted på døgnet

**Hvor på søjlen man slipper, er klokkeslættet.** Målt mod søjlens egen kasse frem
for mod siden, så det bliver rigtigt uanset hvor gitteret sidder og hvor langt der
er rullet. Rundet til kvarter: minuttet under markøren er ikke en oplysning, nogen
har — pegefingeren er bredere end et minut — og 14:07 er et tal, der ser ud som om
det blev valgt.

Prøven går hele vejen: sæt tiden, genindlæs og se at serveren tog den, ret datoen
og se at timen bliver, find opgaven på sit klokkeslæt i ugegitteret, og træk den op
i båndet igen. To ting, den lærte undervejs, står skrevet ved den: et træk over
fire hundrede pixels skal gå i skridt, ellers har browseren for få mellemstationer
til at holde gesten i live — og klokken skal være tidlig, for klokken fjorten
ligger under skærmkanten, og at måle noget dernede ruller siden væk under målet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kristian Wind
2026-08-20 20:29:03 +02:00
co-authored by Claude Opus 5
parent e29fd04abd
commit ae673086bc
6 changed files with 244 additions and 20 deletions
+42 -3
View File
@@ -372,10 +372,35 @@ class AppState {
}
/** Puts a task on a day — dropping it on one, in Kommende or in a month grid. */
async reschedule(id, date) {
/**
* Flytter en opgave til en dag — og afgør, hvad der sker med klokkeslættet.
*
* Serveren læser `due_date` og `due_time` sammen: kommer datoen uden en tid,
* *ryddes* tiden. Det er den rigtige regel for et felt, man skriver i, og den
* forkerte for et træk i en kalender — en opgave, der stod klokken 14, mistede
* sit klokkeslæt ved at blive trukket til dagen efter, uden at nogen bad om
* det, og uden at noget sagde det.
*
* Så tiden siges nu højt, tre måder:
*
* time === undefined behold den, opgaven har
* time === '' ryd den — det er heldagsbåndet
* time === 'HH:MM' sæt den — det er et sted på døgnet
*
* `undefined` og `''` er med vilje to forskellige ting her. De ligner hinanden
* i JavaScript, og det er præcis derfor de skal skilles ad ét sted frem for at
* blive forvekslet fire steder.
*/
async reschedule(id, date, time) {
const previous = this.get(id);
if (!previous || previous.due_date === date) return;
await this.update(id, { due_date: date });
if (!previous) return;
const clock =
time === undefined ? (previous.due_datetime ? clockOf(previous.due_datetime) : '') : time;
if (previous.due_date === date && (previous.due_datetime ? clockOf(previous.due_datetime) : '') === clock) {
return;
}
await this.update(id, { due_date: date, due_time: clock });
}
async remove(id) {
@@ -729,6 +754,20 @@ class AppState {
* Only while it still carries a name the server gave it. Rename it and that is your
* name for it, in every language — the same rule as any other project.
*/
/**
* Klokkeslættet på en opgave, som "HH:MM" i den maskine, der ser på det.
*
* `Date` og ikke en strengudskæring: `due_datetime` kommer som UTC med et Z på,
* og de fjorten på et stempel er ikke klokken fjorten for den, der læser det.
* TaskRow viser tiden på nøjagtig samme måde, og de to steder skal vise det
* samme tal.
*/
export function clockOf(stamp) {
const at = new Date(stamp);
if (Number.isNaN(at.getTime())) return '';
return `${String(at.getHours()).padStart(2, '0')}:${String(at.getMinutes()).padStart(2, '0')}`;
}
const SYSTEM_INBOX_NAMES = new Set(['indbakke', 'inbox']);
export function projectName(project) {