AI Implementation feature(857): Authenticated Shell: Header, Quick Tabs and Change Password (#14)

This commit was merged in pull request #14.
This commit is contained in:
2026-07-21 22:26:47 +00:00
parent 8dc8cee769
commit b6dbfcc511
46 changed files with 2705 additions and 211 deletions
@@ -0,0 +1,38 @@
export type EventState = 'running' | 'countdown' | 'stopped' | 'unconfigured';
export interface EventStatePayload {
state: EventState;
serverNowUtc: string;
eventStartUtc: string | null;
eventEndUtc: string | null;
secondsToStart: number | null;
secondsToEnd: number | null;
}
export interface EventSourceLike {
addEventListener(type: 'open' | 'message' | 'error', listener: (ev: MessageEvent | Event) => void): void;
close(): void;
}
export function formatDdHhMm(totalSeconds: number): string {
if (!Number.isFinite(totalSeconds) || totalSeconds < 0) return '00:00:00';
const s = Math.floor(totalSeconds);
const days = Math.floor(s / 86400);
const hours = Math.floor((s % 86400) / 3600);
const minutes = Math.floor((s % 3600) / 60);
const pad = (n: number) => n.toString().padStart(2, '0');
return `${pad(days)}:${pad(hours)}:${pad(minutes)}`;
}
export function deriveCountdownText(
state: EventState,
secondsToStart: number | null,
secondsToEnd: number | null,
): string {
if (state === 'unconfigured') return '';
if (state === 'stopped') return 'Event ended';
if (state === 'countdown') {
return secondsToStart == null ? '00:00:00' : formatDdHhMm(secondsToStart);
}
return secondsToEnd == null ? '00:00:00' : formatDdHhMm(secondsToEnd);
}