fix(zeit): über Mitternacht laufende Timer bleiben sichtbar (ENTWICKLUN-14)
ci / quality (push) Failing after 40s
ci / build (push) Has been skipped
deploy / deploy (push) Successful in 53s

Ein um 23:00 gestarteter, noch laufender Timer hatte Start-Datum = gestern und
fiel nach Mitternacht aus listToday/teamToday (Filter nach Start-Datum=heute) —
nur die TimerPill zeigte ihn noch.

- listToday/teamToday: Filter „overlapsToday" = heute gestartet ODER heute
  beendet (Mitternacht überschritten) ODER laufend → Eintrag bleibt sichtbar.
- Tages-Summen clampen den Anteil auf den heutigen Tag (berlinDayStartMs,
  DST-korrekt) → über Mitternacht gelaufene Blöcke werden nicht falsch zugezählt.
- ToDo-Titel werden tagesübergreifend serverseitig aufgelöst (time.now +
  listToday) → Task bleibt benannt, auch wenn das ToDo von gestern ist.
- Timeline zeigt das Start-Datum, wenn ein Eintrag nicht heute begonnen hat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Opus 4.8 committed 2026-06-06 17:29:47 +02:00
1 parent 040dd62735
commit 8fd72bcb69
5 files changed
+107 -34

No files matched your search

@@ -64,7 +64,7 @@ export function TimelineSection() {
<TimelineRow
key={e.id}
entry={e}
todoTitle={e.todoId ? todoTitles.get(e.todoId) : undefined}
todoTitle={e.todoTitle ?? (e.todoId ? todoTitles.get(e.todoId) : undefined)}
todos={todayQuery.data?.todos ?? []}
isEditing={editing === e.id}
onEdit={() => setEditing(e.id)}
@@ -92,6 +92,7 @@ type TimeEntryRow = {
endedAt: string | Date | null;
durationSeconds: number | null;
todoId: string | null;
todoTitle?: string | null;
category: string;
description: string | null;
};
@@ -237,6 +238,11 @@ function TimelineRow({
return (
<div className="group flex items-center gap-3 rounded-[var(--radius-md)] border border-[var(--color-border)] p-2.5 text-sm">
<div className="w-28 shrink-0 font-mono text-xs text-[var(--color-ink-muted)]">
{start.toDateString() !== new Date().toDateString() && (
<span className="mr-1 text-[var(--color-ink-faint)]">
{pad(start.getDate())}.{pad(start.getMonth() + 1)}.
</span>
)}
{pad(start.getHours())}:{pad(start.getMinutes())}
{end && (
<>
@@ -80,6 +80,7 @@ export function TimerPill() {
const isPause = active?.category === 'break';
const title = active
? active.description ||
active.todoTitle ||
(active.todoId
? todayQuery.data?.todos.find((t) => t.id === active.todoId)?.title ?? 'ToDo'
: CATEGORY_LABEL[active.category] ?? 'Timer')