feat(worker): server-authoritative Stopwatch screen with active-session recovery
This commit is contained in:
19
apps/worker/src/lib/stopwatch.test.ts
Normal file
19
apps/worker/src/lib/stopwatch.test.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { elapsedSeconds, formatTime } from './stopwatch';
|
||||
|
||||
describe('stopwatch logic', () => {
|
||||
it('formats seconds as HH:MM:SS', () => {
|
||||
expect(formatTime(0)).toBe('00:00:00');
|
||||
expect(formatTime(65)).toBe('00:01:05');
|
||||
expect(formatTime(3661)).toBe('01:01:01');
|
||||
});
|
||||
|
||||
it('computes elapsed seconds since start excluding paused time', () => {
|
||||
expect(elapsedSeconds(1000, 6000, 0)).toBe(5);
|
||||
expect(elapsedSeconds(1000, 6000, 2000)).toBe(3);
|
||||
});
|
||||
|
||||
it('never returns a negative elapsed value', () => {
|
||||
expect(elapsedSeconds(5000, 1000, 0)).toBe(0);
|
||||
});
|
||||
});
|
||||
16
apps/worker/src/lib/stopwatch.ts
Normal file
16
apps/worker/src/lib/stopwatch.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// Pure timing helpers for the Stopwatch screen — server-authoritative elapsed.
|
||||
// Elapsed is computed from the server start_time (wall-clock), not a tick counter,
|
||||
// so it survives backgrounding. Pause accumulates paused time client-side.
|
||||
|
||||
export function formatTime(totalSeconds: number): string {
|
||||
const s = Math.max(0, Math.floor(totalSeconds));
|
||||
const h = Math.floor(s / 3600);
|
||||
const m = Math.floor((s % 3600) / 60);
|
||||
const sec = s % 60;
|
||||
return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
// elapsed seconds since startMs, excluding accumulated paused ms, evaluated at nowMs.
|
||||
export function elapsedSeconds(startMs: number, nowMs: number, pausedMs: number): number {
|
||||
return Math.max(0, Math.floor((nowMs - startMs - pausedMs) / 1000));
|
||||
}
|
||||
Reference in New Issue
Block a user