53 lines
1.7 KiB
TypeScript
53 lines
1.7 KiB
TypeScript
export type PageTitleError = 'required' | 'maxlength' | null;
|
|
|
|
export function pageTitleError(value: string | null | undefined, maxLength = 120): PageTitleError {
|
|
const v = value ?? '';
|
|
if (v.trim().length === 0) return 'required';
|
|
if (v.length > maxLength) return 'maxlength';
|
|
return null;
|
|
}
|
|
|
|
export function normalizePageTitle(value: string): string {
|
|
return value.trim();
|
|
}
|
|
|
|
export type EventDerivedState = 'running' | 'countdown' | 'stopped' | 'unconfigured';
|
|
|
|
export function deriveEventState(start: string, end: string): EventDerivedState {
|
|
if (!start || !end) return 'unconfigured';
|
|
const s = Date.parse(start);
|
|
const e = Date.parse(end);
|
|
if (!Number.isFinite(s) || !Number.isFinite(e)) return 'unconfigured';
|
|
const now = Date.now();
|
|
if (now < s) return 'countdown';
|
|
if (now >= s && now < e) return 'running';
|
|
return 'stopped';
|
|
}
|
|
|
|
export function endAfterStartValidator(group: any): { endBeforeStart: true } | null {
|
|
const start = group.get?.('eventStartUtc')?.value;
|
|
const end = group.get?.('eventEndUtc')?.value;
|
|
if (!start || !end) return null;
|
|
const s = Date.parse(start);
|
|
const e = Date.parse(end);
|
|
if (Number.isFinite(s) && Number.isFinite(e) && e <= s) {
|
|
return { endBeforeStart: true };
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function toDatetimeLocal(iso: string): string {
|
|
if (!iso) return '';
|
|
const d = new Date(iso);
|
|
if (Number.isNaN(d.getTime())) return '';
|
|
const pad = (n: number) => String(n).padStart(2, '0');
|
|
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}T${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}`;
|
|
}
|
|
|
|
export function toIsoUtc(local: string): string {
|
|
if (!local) return '';
|
|
const d = new Date(local);
|
|
if (Number.isNaN(d.getTime())) return local;
|
|
return d.toISOString();
|
|
}
|