feat: gate registration behind 16 March 2026 19:00 opening date
- Add REGISTRATION_OPENS_AT const in lib/opening.ts as single source of truth - Add useRegistrationOpen hook with live 1s countdown ticker - Add CountdownBanner component (DD/HH/MM/SS) with canvas-confetti on open - EventRegistrationForm shows countdown instead of form while closed - Login page hides/disables signup while closed; login always available - WatcherForm AccountModal guards signUp call as defence-in-depth Closes #2
This commit is contained in:
45
apps/web/src/lib/useRegistrationOpen.ts
Normal file
45
apps/web/src/lib/useRegistrationOpen.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { REGISTRATION_OPENS_AT } from "./opening";
|
||||
|
||||
interface RegistrationOpenState {
|
||||
isOpen: boolean;
|
||||
days: number;
|
||||
hours: number;
|
||||
minutes: number;
|
||||
seconds: number;
|
||||
}
|
||||
|
||||
function compute(): RegistrationOpenState {
|
||||
const diff = REGISTRATION_OPENS_AT.getTime() - Date.now();
|
||||
if (diff <= 0) {
|
||||
return { isOpen: true, days: 0, hours: 0, minutes: 0, seconds: 0 };
|
||||
}
|
||||
const totalSeconds = Math.floor(diff / 1000);
|
||||
const days = Math.floor(totalSeconds / 86400);
|
||||
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
||||
const seconds = totalSeconds % 60;
|
||||
return { isOpen: false, days, hours, minutes, seconds };
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns live countdown state to {@link REGISTRATION_OPENS_AT}.
|
||||
* Ticks every second; clears the interval once registration is open.
|
||||
*/
|
||||
export function useRegistrationOpen(): RegistrationOpenState {
|
||||
const [state, setState] = useState<RegistrationOpenState>(compute);
|
||||
|
||||
useEffect(() => {
|
||||
if (state.isOpen) return;
|
||||
|
||||
const id = setInterval(() => {
|
||||
const next = compute();
|
||||
setState(next);
|
||||
if (next.isOpen) clearInterval(id);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(id);
|
||||
}, [state.isOpen]);
|
||||
|
||||
return state;
|
||||
}
|
||||
Reference in New Issue
Block a user