Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/Badges/badge.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const BADGES: Record<string, BadgeMeta> = {
description: 'They found the Arbiverse booth. We found them. Mutual onboarding achieved.',
},
// Rebranded from "Card Pioneer" to "Founding Pioneer". Backend still emits the
// CARD_PIONEER code (it also gates grandfathered card access + cashback), so we
// CARD_PIONEER code (it also gates grandfathered card access + rewards), so we
// keep the code and only repoint the FE asset/copy/name. Existing holders now
// render the Founding Pioneer badge. (Same pattern as SUPPORT_SURVIVOR below.)
CARD_PIONEER: {
Expand Down
8 changes: 4 additions & 4 deletions src/constants/analytics.consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export const ANALYTICS_EVENTS = {
// ── Home ──
BALANCE_VISIBILITY_TOGGLED: 'balance_visibility_toggled',

// ── Error / Churn ──
// ── Error ──
BACKEND_ERROR_SHOWN: 'backend_error_shown',
BACKEND_ERROR_RETRY: 'backend_error_retry',
BACKEND_ERROR_LOGOUT: 'backend_error_logout',
Expand Down Expand Up @@ -183,9 +183,9 @@ export const ANALYTICS_EVENTS = {
CARD_FLOW_EARLY_ACCESS_GRANTED: 'card_flow_early_access_granted',
// Outer-gate fail: user landed on /card without /shhhhh early access pre-launch.
CARD_FLOW_GATED: 'card_flow_gated',
// Home launch CTA (shown to everyone post-public-launch who has no active card).
// viewed = banner became visible; clicked = tapped through to /card;
// dismissed = tapped the X. Click and dismiss both hide it permanently.
// Home Carousel CTA for card launch (shown to everyone post-public-launch who
// has no active card). viewed = CTA became visible; clicked = tapped through
// to /card; dismissed = tapped the X. Click and dismiss both hide it permanently.
CARD_LAUNCH_CTA_VIEWED: 'card_launch_cta_viewed',
CARD_LAUNCH_CTA_CLICKED: 'card_launch_cta_clicked',
CARD_LAUNCH_CTA_DISMISSED: 'card_launch_cta_dismissed',
Expand Down
14 changes: 9 additions & 5 deletions src/hooks/useActivationStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'
export type ActivationStep = 'verify' | 'deposit' | 'card' | 'outbound' | 'completed'

interface ActivationStatus {
/** whether user has completed activation funnel (kyc + first outbound tx) */
/** whether user has activated (≥1 spend: card spend or QR spend on Mercado Pago/Pix) */
isActivated: boolean
/** timestamp of activation, null if not yet activated */
activatedAt: string | null
Expand All @@ -31,14 +31,18 @@ const CARD_DISMISSED_STORAGE_KEY = 'peanut_card_activation_dismissed'
* derives the user's activation status for gating rewards/referral UI.
*
* activation funnel: registered → verified → funded → card → activated
* (activated = kyc approved + ≥1 outbound transaction with fees)
* (activated = ≥1 SPEND transaction: card spend or QR spend on Mercado Pago/Pix —
* other outbound tx kinds like send links, offramps and withdrawals no longer
* count; the BE computes `isActivated`/`activationMilestone` on /users/me and
* this hook just consumes them, so it inherits the definition automatically)
*
* The `card` step only appears when the user is eligible for a Rain card
* (hasCardAccess) but doesn't have an active one yet, and hasn't dismissed
* it via "Maybe later". Otherwise the funnel skips straight to outbound.
* it via "Maybe later". Otherwise the funnel skips straight to the spend step
* (`outbound` — step id kept for continuity, it now means "make your first spend").
*
* before backend ships isActivated, falls back to treating all users as activated
* so no UI breaks during the transition.
* if the BE omits isActivated (bug/outage), falls back to false so gated UI
* (rewards/referral) stays hidden rather than leaking.
*/
export function useActivationStatus(): ActivationStatus {
const { user } = useAuth()
Expand Down
Loading