From 0bab369a6bc6a64bfd8fedd577e69eb27bfb1178 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Mon, 5 Oct 2026 07:37:35 +0200 Subject: Show time since done or lateness instead of the last-done date --- src/lib/shared/routine-metrics.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/lib/shared/routine-metrics.ts') diff --git a/src/lib/shared/routine-metrics.ts b/src/lib/shared/routine-metrics.ts index d3c1470..4417539 100644 --- a/src/lib/shared/routine-metrics.ts +++ b/src/lib/shared/routine-metrics.ts @@ -38,6 +38,15 @@ function maxInstant(instants: Temporal.Instant[]): Temporal.Instant | null { ); } +/** Whole UTC-calendar days from an instant to now, floored at 0. */ +function daysAgo(then: Temporal.Instant, now: Temporal.Instant): number { + const days = then + .toZonedDateTimeISO(UTC) + .toPlainDate() + .until(now.toZonedDateTimeISO(UTC).toPlainDate()).days; + return Math.max(0, days); +} + function parseCompletions( routineId: number, completions: CompletionInput[], @@ -75,6 +84,8 @@ export interface RoutineState { /** Spec text, as stored. */ frequency: string; lastDoneAt: string | null; + /** Whole UTC-calendar days since lastDoneAt (null when never done). */ + daysSinceDone: number | null; /** When the pending obligation must be done (window end for quotas). */ dueAt: string; /** Days past dueAt (0 while the deadline is still ahead). */ @@ -131,6 +142,7 @@ export function computeRoutineState( name: routine.name, frequency: routine.frequency, lastDoneAt: lastDone !== null ? iso(lastDone) : null, + daysSinceDone: lastDone !== null ? daysAgo(lastDone, now) : null, dueAt: iso(due), overdueDays: Math.floor(overdueRatio * days), overdueRatio, @@ -223,6 +235,7 @@ function quotaState( name: routine.name, frequency: routine.frequency, lastDoneAt: lastDone !== null ? iso(lastDone) : null, + daysSinceDone: lastDone !== null ? daysAgo(lastDone, now) : null, dueAt: iso(due), overdueDays: Math.max( 0, @@ -396,3 +409,17 @@ export const STATUS_LABELS: Record = { late: 'En retard', veryLate: 'Très en retard', }; + +/** Meta stamp next to the frequency: lateness past due, else time since done. */ +export function formatDoneAge( + state: Pick, +): string { + if (state.overdueDays > 0) { + const n = state.overdueDays; + return `${n} jour${n > 1 ? 's' : ''} de retard`; + } + if (state.daysSinceDone === null) return 'jamais fait'; + if (state.daysSinceDone === 0) return "fait aujourd'hui"; + if (state.daysSinceDone === 1) return 'fait hier'; + return `fait il y a ${state.daysSinceDone} jours`; +} -- cgit v1.3