/** * OnboardingWizard — Step-based onboarding flow for new Claw3D users. * * Renders a modal overlay with step navigation, progress indicator, * and content slots for each onboarding phase. Designed to be mounted * at the app root and dismissed once complete or skipped. */ import { useCallback, useMemo, useState } from "react"; import { ArrowLeft, ArrowRight, X } from "lucide-react"; import { getNextStep, getPrevStep, getStepIndex, ONBOARDING_STEPS, type OnboardingStepId, } from "@/features/onboarding/types"; import { WelcomeStep } from "@/features/onboarding/components/WelcomeStep"; import { PrerequisitesStep } from "@/features/onboarding/components/PrerequisitesStep"; import { ConnectStep } from "@/features/onboarding/components/ConnectStep"; import { AgentsStep } from "@/features/onboarding/components/AgentsStep"; import { CompleteStep } from "@/features/onboarding/components/CompleteStep"; export type OnboardingWizardProps = { /** Whether the gateway is currently connected. */ gatewayConnected: boolean; /** Number of agents discovered. */ agentCount: number; /** Gateway URL (for the connect step). */ gatewayUrl: string; /** Gateway token (for the connect step). */ token: string; /** Callbacks for the connect step. */ onGatewayUrlChange: (value: string) => void; onTokenChange: (value: string) => void; onConnect: () => void; /** Called when the user finishes or dismisses the wizard. */ onComplete: () => void; /** Connection error message, if any. */ connectionError: string | null; /** Whether we're currently connecting. */ connecting: boolean; }; export const OnboardingWizard = ({ gatewayConnected, agentCount, gatewayUrl, token, onGatewayUrlChange, onTokenChange, onConnect, onComplete, connectionError, connecting, }: OnboardingWizardProps) => { const [currentStep, setCurrentStep] = useState("welcome"); const [completedSteps, setCompletedSteps] = useState>( new Set(), ); const stepIndex = useMemo(() => getStepIndex(currentStep), [currentStep]); const currentStepDef = ONBOARDING_STEPS[stepIndex]; const totalSteps = ONBOARDING_STEPS.length; const markComplete = useCallback( (stepId: OnboardingStepId) => { setCompletedSteps((prev) => { const next = new Set(prev); next.add(stepId); return next; }); }, [], ); const goNext = useCallback(() => { markComplete(currentStep); const next = getNextStep(currentStep); if (next) { setCurrentStep(next); } else { onComplete(); } }, [currentStep, markComplete, onComplete]); const goPrev = useCallback(() => { const prev = getPrevStep(currentStep); if (prev) setCurrentStep(prev); }, [currentStep]); const canGoNext = useMemo(() => { // Connect step requires gateway connection before proceeding if (currentStep === "connect" && !gatewayConnected) return false; return true; }, [currentStep, gatewayConnected]); const renderStepContent = () => { switch (currentStep) { case "welcome": return ; case "prerequisites": return ; case "connect": return ( ); case "agents": return ; case "complete": return ; default: return null; } }; return (
{/* Header */}

{currentStepDef?.title ?? "Onboarding"}

{currentStepDef?.description}

{/* Progress bar */}
{ONBOARDING_STEPS.map((step, idx) => (
))}
{/* Step content */}
{renderStepContent()}
{/* Footer navigation */}
{stepIndex > 0 ? ( ) : null}
{stepIndex + 1} / {totalSteps} {currentStep === "complete" ? ( ) : ( )}
); };