Confetti does not fire when registration opens on page load #5

Closed
opened 2026-03-11 09:35:04 +00:00 by zias · 0 comments
Owner

Bug

Confetti never plays for users who visit the site after registration has already opened.

Root cause

The confetti logic lives in CountdownBanner (apps/web/src/components/homepage/CountdownBanner.tsx):

useEffect(() => {
    if (isOpen && !confettiFired.current) {
        confettiFired.current = true;
        fireConfetti();
    }
}, [isOpen]);

This useEffect only fires when isOpen transitions from false to true (i.e. the dependency array changes). When a user opens the page after REGISTRATION_OPENS_AT has already passed, useRegistrationOpen() returns isOpen: true on the very first render. React never sees a false → true change, so the effect never fires.

On top of that, EventRegistrationForm skips rendering <CountdownBanner> entirely when isOpen is already true, so the component never even mounts.

The confetti only works for users who had the page open before the registration timer hit zero.

Fix

Move the confetti logic out of CountdownBanner and into EventRegistrationForm, where it can fire on first mount when isOpen is already true, as well as on the live false → true transition.

// EventRegistrationForm.tsx
const { isOpen } = useRegistrationOpen();
const confettiFired = useRef(false);

useEffect(() => {
    if (isOpen && !confettiFired.current) {
        confettiFired.current = true;
        fireConfetti();
    }
}, [isOpen]);

Because EventRegistrationForm is always mounted (it renders either the countdown or the real form), its useEffect runs on mount regardless of whether isOpen starts as true or flips later. The confettiFired ref still ensures it fires exactly once per session.

The fireConfetti function and the confettiFired ref can then be removed from CountdownBanner.

## Bug Confetti never plays for users who visit the site **after** registration has already opened. ## Root cause The confetti logic lives in `CountdownBanner` (`apps/web/src/components/homepage/CountdownBanner.tsx`): ```ts useEffect(() => { if (isOpen && !confettiFired.current) { confettiFired.current = true; fireConfetti(); } }, [isOpen]); ``` This `useEffect` only fires when `isOpen` **transitions** from `false` to `true` (i.e. the dependency array changes). When a user opens the page after `REGISTRATION_OPENS_AT` has already passed, `useRegistrationOpen()` returns `isOpen: true` on the very first render. React never sees a `false → true` change, so the effect never fires. On top of that, `EventRegistrationForm` skips rendering `<CountdownBanner>` entirely when `isOpen` is already `true`, so the component never even mounts. The confetti only works for users who had the page open **before** the registration timer hit zero. ## Fix Move the confetti logic out of `CountdownBanner` and into `EventRegistrationForm`, where it can fire on **first mount** when `isOpen` is already `true`, as well as on the live `false → true` transition. ```ts // EventRegistrationForm.tsx const { isOpen } = useRegistrationOpen(); const confettiFired = useRef(false); useEffect(() => { if (isOpen && !confettiFired.current) { confettiFired.current = true; fireConfetti(); } }, [isOpen]); ``` Because `EventRegistrationForm` is always mounted (it renders either the countdown or the real form), its `useEffect` runs on mount regardless of whether `isOpen` starts as `true` or flips later. The `confettiFired` ref still ensures it fires exactly once per session. The `fireConfetti` function and the `confettiFired` ref can then be removed from `CountdownBanner`.
zias closed this issue 2026-03-11 09:43:48 +00:00
zias reopened this issue 2026-03-11 09:43:58 +00:00
zias referenced this issue from a commit 2026-03-11 09:44:38 +00:00
zias closed this issue 2026-03-11 09:44:38 +00:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: zias/kunstenkamp#5