Add 'Verify campaigns' as a third onboarding role
Extend OnboardingRole and StartSignupOptions to include 'verifier', add a third RoleCard to the role picker, and wire the pick handler to branch on the new role. For now the verifier pick routes to the public /organizations onboarding tool; a later commit replaces this with a captive sub-flow.
This commit is contained in:
@@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
BadgeCheck,
|
||||
Bitcoin,
|
||||
Download,
|
||||
Eye,
|
||||
@@ -129,18 +130,22 @@ function CaptiveOverlay() {
|
||||
}
|
||||
}, [step, user, cancel, goTo]);
|
||||
|
||||
// Role pick is the final step. Picking a role both records the choice
|
||||
// (used by the role-pick CTA labels) and navigates to the matching
|
||||
// surface: creator → campaign-creation form, donor → full campaign grid
|
||||
// (`/campaigns`, not `/`, so they land on the browse-everything view
|
||||
// rather than the curated home with its own marketing hero). No separate
|
||||
// outro / celebration screen.
|
||||
// Role pick is the final step for creator/donor. Picking a role both
|
||||
// records the choice (used by the role-pick CTA labels) and navigates to
|
||||
// the matching surface: creator → campaign-creation form, donor → full
|
||||
// campaign grid (`/campaigns`, not `/`, so they land on the
|
||||
// browse-everything view rather than the curated home with its own
|
||||
// marketing hero). The verifier role does not navigate away — it branches
|
||||
// into the captive verifier sub-flow (wired up in a later step); for now
|
||||
// it routes to the public /organizations onboarding tool.
|
||||
const handleRolePick = useCallback(
|
||||
(next: 'creator' | 'donor') => {
|
||||
(next: 'creator' | 'donor' | 'verifier') => {
|
||||
setContextRole(next);
|
||||
cancel();
|
||||
if (next === 'creator') {
|
||||
navigate('/campaigns/new');
|
||||
} else if (next === 'verifier') {
|
||||
navigate('/organizations');
|
||||
} else {
|
||||
navigate('/campaigns');
|
||||
}
|
||||
@@ -273,7 +278,7 @@ function CaptiveOverlay() {
|
||||
|
||||
interface RoleStepProps {
|
||||
role: OnboardingRole;
|
||||
onPick: (role: 'creator' | 'donor') => void;
|
||||
onPick: (role: 'creator' | 'donor' | 'verifier') => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,6 +315,14 @@ function RoleStep({ role, onPick }: RoleStepProps) {
|
||||
selected={role === 'donor'}
|
||||
onClick={() => onPick('donor')}
|
||||
/>
|
||||
<RoleCard
|
||||
icon={<BadgeCheck className="h-5 w-5 md:h-6 md:w-6 text-primary" />}
|
||||
title={t('onboarding.role.verifier.title')}
|
||||
description={t('onboarding.role.verifier.description')}
|
||||
finderNote={t('onboarding.role.verifier.finderNote')}
|
||||
selected={role === 'verifier'}
|
||||
onClick={() => onPick('verifier')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -32,7 +32,7 @@ export function OnboardingProvider({ children }: { children: ReactNode }) {
|
||||
// animation. We re-seed on the next startSignup().
|
||||
}, []);
|
||||
|
||||
const setRole = useCallback((next: 'creator' | 'donor') => {
|
||||
const setRole = useCallback((next: 'creator' | 'donor' | 'verifier') => {
|
||||
setRoleState(next);
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
/**
|
||||
* The two top-level roles a new user can pick during onboarding. Drives
|
||||
* downstream copy (creator vs. donor framing) and the role-pick CTA target
|
||||
* (creator → /campaigns/new, donor → /campaigns).
|
||||
* The top-level roles a new user can pick during onboarding. Drives
|
||||
* downstream copy (creator vs. donor vs. verifier framing) and the
|
||||
* role-pick behavior:
|
||||
* - `creator` → navigate to /campaigns/new
|
||||
* - `donor` → navigate to /campaigns
|
||||
* - `verifier`→ stay captive and branch into the verifier sub-flow
|
||||
* (org identity → org bio → publish statement → how-to-verify)
|
||||
*
|
||||
* `null` before the user has answered the role-picker step.
|
||||
*/
|
||||
export type OnboardingRole = 'creator' | 'donor' | null;
|
||||
export type OnboardingRole = 'creator' | 'donor' | 'verifier' | null;
|
||||
|
||||
/** Options to pre-seed when invoking the captive flow from a specific CTA. */
|
||||
export interface StartSignupOptions {
|
||||
@@ -15,7 +19,7 @@ export interface StartSignupOptions {
|
||||
* Pre-fill the role picker. CTAs that semantically already imply a role
|
||||
* (e.g. "Start a campaign") can skip the role step by passing this.
|
||||
*/
|
||||
role?: 'creator' | 'donor';
|
||||
role?: 'creator' | 'donor' | 'verifier';
|
||||
}
|
||||
|
||||
export interface OnboardingContextValue {
|
||||
@@ -29,7 +33,7 @@ export interface OnboardingContextValue {
|
||||
* finishes or explicitly bails out. */
|
||||
cancel: () => void;
|
||||
/** Update the selected role from inside the flow (role-picker step). */
|
||||
setRole: (role: 'creator' | 'donor') => void;
|
||||
setRole: (role: 'creator' | 'donor' | 'verifier') => void;
|
||||
}
|
||||
|
||||
export const OnboardingContext = createContext<OnboardingContextValue | undefined>(undefined);
|
||||
|
||||
@@ -104,6 +104,11 @@
|
||||
"title": "Give to campaigns",
|
||||
"description": "Support causes with Bitcoin.",
|
||||
"finderNote": "Your donation goes straight to the organizer's wallet."
|
||||
},
|
||||
"verifier": {
|
||||
"title": "Verify campaigns",
|
||||
"description": "Vouch for campaigns you've checked out, as an organization.",
|
||||
"finderNote": "Donors see your badge on campaigns you trust."
|
||||
}
|
||||
},
|
||||
"keygen": {
|
||||
|
||||
Reference in New Issue
Block a user