feat(issue-17): add onboarding wizard for new users (#26)
* feat(issue-17): add onboarding wizard for new users
Adds a step-based onboarding wizard that guides new users through their
first Claw3D setup: welcome, prerequisites, gateway connection, agent
discovery, and a completion screen.
Architecture:
src/features/onboarding/ (new feature module):
- types.ts: Step definitions, navigation helpers (getNextStep/getPrevStep)
- useOnboardingState.ts: localStorage-backed persistence hook
- index.ts: Barrel exports for clean imports
- components/OnboardingWizard.tsx: Main wizard container with step
navigation, progress bar, and modal overlay
- components/WelcomeStep.tsx: Feature highlights grid
- components/PrerequisitesStep.tsx: Checklist with links/commands
- components/ConnectStep.tsx: Compact gateway connection form
- components/AgentsStep.tsx: Agent discovery feedback
- components/CompleteStep.tsx: Final screen with CTA
Design decisions:
- Modular step system: new steps can be added by extending
OnboardingStepId and registering a component in the switch
- localStorage persistence: wizard shows once per browser, resettable
from settings (future: wire into Studio settings API)
- Connect step gates forward navigation: users cannot skip connection
- Follows Claw3D conventions: feature-first module, no shared state
pollution, Tailwind utility classes, lucide-react icons
- Does NOT modify existing routes or components — zero-risk integration
(parent wiring left to maintainer preference)
Integration guide (for maintainer):
1. Import { OnboardingWizard, useOnboardingState } from the module
2. Add useOnboardingState() to the root layout or agents page
3. Render <OnboardingWizard /> when showOnboarding is true
4. Pass gateway connection props from existing store
tests/unit/onboardingTypes.test.ts (13 tests):
- Step structure validation, navigation helpers, ordering
tests/unit/onboardingState.test.ts (5 tests):
- localStorage persistence, show/hide/reset lifecycle
Addresses #17
* fix(onboarding): wire wizard launch into office UI
Mount the onboarding wizard in OfficeScreen and add a settings action that can re-open it so the new-user flow is reachable and testable.
Made-with: Cursor
---------
Co-authored-by: Neo <neo@openclaw.ai>
Co-authored-by: iamlukethedev <lucas.guilherme@smartwayslfl.com>
This commit is contained in:
committed by
GitHub
parent
ac30f71db0
commit
c2cbdeec44
@@ -85,6 +85,10 @@ import { SkillsMarketplacePanel } from "@/features/office/components/panels/Skil
|
||||
import { useOfficeSkillsMarketplace } from "@/features/office/hooks/useOfficeSkillsMarketplace";
|
||||
import { useOfficeStandupController } from "@/features/office/hooks/useOfficeStandupController";
|
||||
import { useRunLog } from "@/features/office/hooks/useRunLog";
|
||||
import {
|
||||
OnboardingWizard,
|
||||
useOnboardingState,
|
||||
} from "@/features/onboarding";
|
||||
import { useFinalizedAssistantReplyListener } from "@/hooks/useFinalizedAssistantReplyListener";
|
||||
import { useStudioOfficePreference } from "@/hooks/useStudioOfficePreference";
|
||||
import { useStudioVoiceRepliesPreference } from "@/hooks/useStudioVoiceRepliesPreference";
|
||||
@@ -758,6 +762,9 @@ export function OfficeScreen({
|
||||
const [activeSidebarTab, setActiveSidebarTab] =
|
||||
useState<HQSidebarTab>("inbox");
|
||||
const router = useRouter();
|
||||
const { showOnboarding, completeOnboarding, resetOnboarding } =
|
||||
useOnboardingState();
|
||||
const [forceShowOnboarding, setForceShowOnboarding] = useState(false);
|
||||
const {
|
||||
loaded: officeTitleLoaded,
|
||||
title: officeTitle,
|
||||
@@ -789,6 +796,15 @@ export function OfficeScreen({
|
||||
voiceId: voiceRepliesPreference.voiceId,
|
||||
speed: voiceRepliesPreference.speed,
|
||||
});
|
||||
const showOnboardingWizard = showOnboarding || forceShowOnboarding;
|
||||
const handleOpenOnboarding = useCallback(() => {
|
||||
resetOnboarding();
|
||||
setForceShowOnboarding(true);
|
||||
}, [resetOnboarding]);
|
||||
const handleCompleteOnboarding = useCallback(() => {
|
||||
completeOnboarding();
|
||||
setForceShowOnboarding(false);
|
||||
}, [completeOnboarding]);
|
||||
|
||||
const handleAvatarProfileSave = useCallback(
|
||||
(agentId: string, profile: AgentAvatarProfile) => {
|
||||
@@ -2795,6 +2811,7 @@ export function OfficeScreen({
|
||||
settingsCoordinator,
|
||||
}}
|
||||
onGatewayDisconnect={disconnect}
|
||||
onOpenOnboarding={handleOpenOnboarding}
|
||||
feedEvents={feedEvents}
|
||||
gatewayStatus={status}
|
||||
runCountByAgentId={runCountByAgentId}
|
||||
@@ -2924,6 +2941,23 @@ export function OfficeScreen({
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showOnboardingWizard ? (
|
||||
<OnboardingWizard
|
||||
gatewayConnected={status === "connected"}
|
||||
agentCount={state.agents.length}
|
||||
gatewayUrl={gatewayUrl}
|
||||
token={token}
|
||||
onGatewayUrlChange={setGatewayUrl}
|
||||
onTokenChange={setToken}
|
||||
onConnect={() => {
|
||||
void connect();
|
||||
}}
|
||||
onComplete={handleCompleteOnboarding}
|
||||
connectionError={gatewayError}
|
||||
connecting={status === "connecting"}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showOpenClawConsole ? (
|
||||
<section className="pointer-events-auto fixed bottom-3 left-3 z-30 flex w-[520px] max-w-[calc(100vw-1.5rem)] flex-col overflow-hidden rounded border border-cyan-500/25 bg-black/78 shadow-2xl backdrop-blur">
|
||||
<div className="flex items-center justify-between border-b border-cyan-500/15 px-3 py-2 font-mono text-[11px] uppercase tracking-[0.18em] text-cyan-200/80">
|
||||
|
||||
Reference in New Issue
Block a user