53 lines
1.6 KiB
TypeScript
53 lines
1.6 KiB
TypeScript
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' | 'unauthorized',
|
|
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);
|
|
}
|
|
|
|
export const LED_COLOR_BY_STATE: Readonly<Record<EventState, string>> = {
|
|
running: 'var(--color-success)',
|
|
countdown: 'var(--color-warning)',
|
|
stopped: 'var(--color-danger)',
|
|
unconfigured: 'var(--color-secondary)',
|
|
};
|
|
|
|
export function ledBackgroundColor(state: EventState): string {
|
|
return LED_COLOR_BY_STATE[state];
|
|
}
|