From 7345625ecdb70b7ed5ac47c7e496af4f0d0a908e Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Thu, 23 Apr 2026 08:23:22 -0400 Subject: [PATCH] feat(web): add formatDuration helper Renders seconds as mm:ss or h:mm:ss. Negative inputs clamp to 0:00 so a bad backend value doesn't crash the UI. --- web/src/lib/media/duration.test.ts | 33 ++++++++++++++++++++++++++++++ web/src/lib/media/duration.ts | 15 ++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 web/src/lib/media/duration.test.ts create mode 100644 web/src/lib/media/duration.ts diff --git a/web/src/lib/media/duration.test.ts b/web/src/lib/media/duration.test.ts new file mode 100644 index 00000000..91427e32 --- /dev/null +++ b/web/src/lib/media/duration.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, test } from 'vitest'; +import { formatDuration } from './duration'; + +describe('formatDuration', () => { + test('under a minute renders 0:SS', () => { + expect(formatDuration(42)).toBe('0:42'); + expect(formatDuration(5)).toBe('0:05'); + }); + + test('under an hour renders M:SS', () => { + expect(formatDuration(242)).toBe('4:02'); + expect(formatDuration(600)).toBe('10:00'); + }); + + test('at or above an hour renders H:MM:SS', () => { + expect(formatDuration(3600)).toBe('1:00:00'); + expect(formatDuration(3723)).toBe('1:02:03'); + expect(formatDuration(36000)).toBe('10:00:00'); + }); + + test('zero renders 0:00', () => { + expect(formatDuration(0)).toBe('0:00'); + }); + + test('negative values clamp to 0:00', () => { + expect(formatDuration(-1)).toBe('0:00'); + expect(formatDuration(-100)).toBe('0:00'); + }); + + test('fractional seconds floor', () => { + expect(formatDuration(61.9)).toBe('1:01'); + }); +}); diff --git a/web/src/lib/media/duration.ts b/web/src/lib/media/duration.ts new file mode 100644 index 00000000..90102f69 --- /dev/null +++ b/web/src/lib/media/duration.ts @@ -0,0 +1,15 @@ +// Formats a non-negative number of seconds as `mm:ss` when under an hour, +// `h:mm:ss` otherwise. Negative values clamp to zero (callers shouldn't +// pass them, but the UI shouldn't crash if they do). +export function formatDuration(seconds: number): string { + const total = Math.max(0, Math.floor(seconds)); + const h = Math.floor(total / 3600); + const m = Math.floor((total % 3600) / 60); + const s = total % 60; + const ss = String(s).padStart(2, '0'); + if (h > 0) { + const mm = String(m).padStart(2, '0'); + return `${h}:${mm}:${ss}`; + } + return `${m}:${ss}`; +}