Split OnboardingContext into def + provider files
This commit is contained in:
+1
-1
@@ -18,7 +18,7 @@ import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { useNsecPasteGuard } from "@/hooks/useNsecPasteGuard";
|
||||
import type { AppConfig } from "@/contexts/AppContext";
|
||||
import { NWCProvider } from "@/contexts/NWCContext";
|
||||
import { OnboardingProvider } from "@/contexts/OnboardingContext";
|
||||
import { OnboardingProvider } from "@/contexts/OnboardingProvider";
|
||||
import { BuildConfigSchema, type BuildConfig } from "@/lib/schemas";
|
||||
import { secureStorage } from "@/lib/secureStorage";
|
||||
import AppRouter from "./AppRouter";
|
||||
|
||||
@@ -32,7 +32,7 @@ import { Textarea } from '@/components/ui/textarea';
|
||||
import { useCurrentUser } from '@/hooks/useCurrentUser';
|
||||
import { useLoginActions } from '@/hooks/useLoginActions';
|
||||
import { useNostrPublish } from '@/hooks/useNostrPublish';
|
||||
import { useOnboarding, type OnboardingRole } from '@/contexts/OnboardingContext';
|
||||
import { useOnboarding, type OnboardingRole } from '@/contexts/onboardingContextDef';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useUploadFile } from '@/hooks/useUploadFile';
|
||||
import { downloadTextFile } from '@/lib/downloadFile';
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
type NostrConnectStatus,
|
||||
} from '@/hooks/useLoginActions';
|
||||
import { useIsMobile } from '@/hooks/useIsMobile';
|
||||
import { useOnboarding } from '@/contexts/OnboardingContext';
|
||||
import { useOnboarding } from '@/contexts/onboardingContextDef';
|
||||
|
||||
interface AuthDialogProps {
|
||||
isOpen: boolean;
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useCallback, useState, type ReactNode } from 'react';
|
||||
|
||||
import {
|
||||
OnboardingContext,
|
||||
type OnboardingRole,
|
||||
type StartSignupOptions,
|
||||
} from './onboardingContextDef';
|
||||
|
||||
/**
|
||||
* Provides captive-onboarding state to the whole tree.
|
||||
*
|
||||
* Designed for Ditto-style "fullscreen overlay wraps the router" usage: any
|
||||
* CTA in the app calls `useOnboarding().startSignup()` and a sibling
|
||||
* `<OnboardingGate>` renders the overlay on top of `<AppRouter />`.
|
||||
*
|
||||
* The provider component lives in a separate file from `OnboardingContext` /
|
||||
* `useOnboarding` so the file containing the component has *only* component
|
||||
* exports — required for React Fast Refresh to work cleanly on this file.
|
||||
*/
|
||||
export function OnboardingProvider({ children }: { children: ReactNode }) {
|
||||
const [active, setActive] = useState(false);
|
||||
const [role, setRoleState] = useState<OnboardingRole>(null);
|
||||
|
||||
const startSignup = useCallback((options?: StartSignupOptions) => {
|
||||
setRoleState(options?.role ?? null);
|
||||
setActive(true);
|
||||
}, []);
|
||||
|
||||
const cancel = useCallback(() => {
|
||||
setActive(false);
|
||||
// Don't reset role here — let the consumer keep it through the close
|
||||
// animation. We re-seed on the next startSignup().
|
||||
}, []);
|
||||
|
||||
const setRole = useCallback((next: 'creator' | 'donor') => {
|
||||
setRoleState(next);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<OnboardingContext.Provider value={{ active, role, startSignup, cancel, setRole }}>
|
||||
{children}
|
||||
</OnboardingContext.Provider>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { createContext, useCallback, useContext, useState, type ReactNode } from 'react';
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
/**
|
||||
* The two top-level roles a new user can pick during onboarding. Drives
|
||||
* downstream copy (creator gets stronger nsec-wallet warnings; donor sees
|
||||
* lighter copy) and the outro CTA target (creator → /campaigns/new, donor → /).
|
||||
* downstream copy (creator vs. donor framing) and the role-pick CTA target
|
||||
* (creator → /campaigns/new, donor → /campaigns/all).
|
||||
*
|
||||
* `null` before the user has answered the role-picker step.
|
||||
*/
|
||||
@@ -13,8 +13,7 @@ export type OnboardingRole = 'creator' | 'donor' | null;
|
||||
export interface StartSignupOptions {
|
||||
/**
|
||||
* Pre-fill the role picker. CTAs that semantically already imply a role
|
||||
* (e.g. "Start a campaign" in the home hero) can skip the role step by
|
||||
* passing this. Without a role the flow asks on the second step.
|
||||
* (e.g. "Start a campaign") can skip the role step by passing this.
|
||||
*/
|
||||
role?: 'creator' | 'donor';
|
||||
}
|
||||
@@ -35,39 +34,6 @@ export interface OnboardingContextValue {
|
||||
|
||||
export const OnboardingContext = createContext<OnboardingContextValue | undefined>(undefined);
|
||||
|
||||
/**
|
||||
* Provides captive-onboarding state to the whole tree.
|
||||
*
|
||||
* Designed for Ditto-style "fullscreen overlay wraps the router" usage: any
|
||||
* CTA in the app calls `useOnboarding().startSignup()` and a sibling
|
||||
* `<OnboardingGate>` renders the overlay on top of `<AppRouter />`.
|
||||
*/
|
||||
export function OnboardingProvider({ children }: { children: ReactNode }) {
|
||||
const [active, setActive] = useState(false);
|
||||
const [role, setRoleState] = useState<OnboardingRole>(null);
|
||||
|
||||
const startSignup = useCallback((options?: StartSignupOptions) => {
|
||||
setRoleState(options?.role ?? null);
|
||||
setActive(true);
|
||||
}, []);
|
||||
|
||||
const cancel = useCallback(() => {
|
||||
setActive(false);
|
||||
// Don't reset role here — let the consumer keep it through the close
|
||||
// animation. We re-seed on the next startSignup().
|
||||
}, []);
|
||||
|
||||
const setRole = useCallback((next: 'creator' | 'donor') => {
|
||||
setRoleState(next);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<OnboardingContext.Provider value={{ active, role, startSignup, cancel, setRole }}>
|
||||
{children}
|
||||
</OnboardingContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the captive onboarding controller. Used by both consumers (CTAs
|
||||
* that trigger signup) and the gate itself.
|
||||
Reference in New Issue
Block a user