From d5d1a463b81df0642c623aac30b5ac30210833da Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 20 Apr 2026 21:22:59 +0200 Subject: [PATCH] feat(frontend): add relativeTimeDe helper for dashboard meta lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pure function with injectable now — lets the dashboard enrichment block render "vor 2 Min." / "vor 3 Std." / "vor 2 Tagen" without clock-based test flakiness. Reuses the existing comment_time_minutes / _hours / _days Paraglide keys, no new translations needed. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/lib/relativeTime.spec.ts | 34 +++++++++++++++++++++++++++ frontend/src/lib/relativeTime.ts | 8 +++++++ 2 files changed, 42 insertions(+) create mode 100644 frontend/src/lib/relativeTime.spec.ts create mode 100644 frontend/src/lib/relativeTime.ts diff --git a/frontend/src/lib/relativeTime.spec.ts b/frontend/src/lib/relativeTime.spec.ts new file mode 100644 index 00000000..9373986e --- /dev/null +++ b/frontend/src/lib/relativeTime.spec.ts @@ -0,0 +1,34 @@ +import { describe, it, expect } from 'vitest'; +import { relativeTimeDe } from './relativeTime'; + +const NOW = new Date('2026-04-20T12:00:00Z'); + +describe('relativeTimeDe', () => { + it('returns minutes for a gap under one hour', () => { + const from = new Date('2026-04-20T11:58:00Z'); + expect(relativeTimeDe(from, NOW)).toContain('2'); + expect(relativeTimeDe(from, NOW)).toMatch(/Minute/i); + }); + + it('returns hours for a gap between 1 and 24 hours', () => { + const from = new Date('2026-04-20T09:00:00Z'); + expect(relativeTimeDe(from, NOW)).toContain('3'); + expect(relativeTimeDe(from, NOW)).toMatch(/Stunde/i); + }); + + it('returns days for a gap of 24 hours or more', () => { + const from = new Date('2026-04-18T12:00:00Z'); + expect(relativeTimeDe(from, NOW)).toContain('2'); + expect(relativeTimeDe(from, NOW)).toMatch(/Tag/i); + }); + + it('rounds minutes to the nearest whole number', () => { + const from = new Date('2026-04-20T11:58:20Z'); + expect(relativeTimeDe(from, NOW)).toContain('2'); + }); + + it('handles zero gap as 0 minutes', () => { + expect(relativeTimeDe(NOW, NOW)).toMatch(/0/); + expect(relativeTimeDe(NOW, NOW)).toMatch(/Minute/i); + }); +}); diff --git a/frontend/src/lib/relativeTime.ts b/frontend/src/lib/relativeTime.ts new file mode 100644 index 00000000..1c78367a --- /dev/null +++ b/frontend/src/lib/relativeTime.ts @@ -0,0 +1,8 @@ +import * as m from '$lib/paraglide/messages.js'; + +export function relativeTimeDe(from: Date, now: Date = new Date()): string { + const minutes = Math.round((now.getTime() - from.getTime()) / 60_000); + if (minutes < 60) return m.comment_time_minutes({ count: minutes }); + if (minutes < 1440) return m.comment_time_hours({ count: Math.round(minutes / 60) }); + return m.comment_time_days({ count: Math.round(minutes / 1440) }); +}