PURPOSE
Sequential reward popup overlay. Renders the front item from rewardQueueStore as a centered modal popup with source label, icon, and amount/label. Auto-dismisses after 2 seconds, or dismisses immediately on tap/click of the backdrop. Mounted once in Layout.tsx and is always present, becoming visible whenever the queue is non-empty.
OWNS
- The popup DOM overlay (full-viewport fixed div at
zIndex: 9999). - The inner popup card (gradient background, border, rounded corners, shadow).
- The auto-dismiss
setTimeoutreference stored intimerRef. - Inline keyframe animations
fadeInandpopIninjected via a<style>tag. - The
AUTO_DISMISS_MSconstant (2000 ms). - Visual layout: source label, icon, reward label (with formatted amount), and “tap to continue” hint.
READS FROM
useRewardQueueStore— pullsisShowing,current, anddismissselectors.current()— returns the front reward item (withid,source,icon,amount,label).
PUSHES TO
dismiss()on the reward queue store — invoked by the auto-dismiss timer and by backdrop click.
DOES NOT
- Does not push or enqueue reward items (read-only consumer of the queue).
- Does not handle multiple items simultaneously (renders only the front item).
- Does not persist anything or talk to Supabase/network.
- Does not animate icons or render reward-type-specific visuals beyond the icon string.
- Does not block input outside the popup beyond the backdrop overlay.
- Does not call
dismisswhen clicking on the inner popup card (click propagation is stopped).
Signals
- Mount/queue-change effect keyed on
isShowinganditem?.id— sets a fresh auto-dismiss timer per item and clears it on unmount or item swap. - Backdrop click handler — calls
dismiss(). - Inner card click handler —
stopPropagationto prevent accidental dismiss when interacting with the card.
Entry points
RewardPopup()— named React function component export. Takes no props.
Pattern notes
- Always-mounted overlay pattern: renders
nullwhenisShowingis false or no current item exists, so it can sit inLayout.tsxpermanently without conditional mounting. - Per-item timer reset is achieved by including
item?.idin the effect dependency array, so each new front-of-queue item gets its own 2-second window. - Inline styles only — no CSS module, no external stylesheet. Keyframes are injected via a child
<style>tag inside the overlay. - Backdrop-vs-card click separation uses
stopPropagationon the inner card, keeping the dismiss-on-backdrop UX while preserving card interactivity. - Amount formatting uses
toLocaleString()and is prefixed with+only whenamount > 0; zero-amount rewards render label only. - Font family
'Cal Sans', cursiveis used for the source label and reward label.