import { useState, useEffect } from "react"; import { Box } from "ink"; import type { GitforestConfig } from "../../types/index.ts"; import { WelcomeStep } from "./WelcomeStep.tsx"; import { DirectoriesStep } from "./DirectoriesStep.tsx"; import { GitHubAuthStep } from "./GitHubAuthStep.tsx"; import { CompleteStep } from "./CompleteStep.tsx"; type Step = "welcome" | "directories" | "github" | "complete" | "done"; interface DirectoryConfig { path: string; maxDepth: number; label?: string; } interface GitHubAuthState { authenticated: boolean; user?: string; skipped: boolean; } export interface OnboardingWizardProps { onComplete: (config: GitforestConfig) => void; onCancel: () => void; onUnmount?: () => void; } export function OnboardingWizard({ onComplete, onCancel, onUnmount }: OnboardingWizardProps) { const [currentStep, setCurrentStep] = useState("welcome"); const [directories, setDirectories] = useState([]); const [githubAuth, setGithubAuth] = useState({ authenticated: false, skipped: false, }); const [isCreatingConfig, setIsCreatingConfig] = useState(false); const [configError, setConfigError] = useState(null); const handleWelcomeComplete = () => { setCurrentStep("directories"); }; const handleDirectoriesComplete = (dirs: DirectoryConfig[]) => { setDirectories(dirs); setCurrentStep("github"); }; const handleGitHubComplete = (auth: GitHubAuthState) => { setGithubAuth(auth); // Immediately create config, then show complete step setIsCreatingConfig(true); }; // Create config when GitHub step completes useEffect(() => { if (isCreatingConfig && currentStep === "github" && !configError) { void (async () => { try { const { createOnboardingConfig } = await import("../../config/onboarding.ts"); const config = await createOnboardingConfig({ directories, githubAuth: { authenticated: githubAuth.authenticated, user: githubAuth.user, }, }); // Config created successfully, show complete step setCurrentStep("complete"); setIsCreatingConfig(false); // Auto-complete after showing success, then exit setTimeout(() => { // Call onComplete first to ensure config is passed to parent onComplete(config); // Then unmount the component onUnmount?.(); }, 2000); } catch (error) { setConfigError(error instanceof Error ? error.message : "Failed to create config"); setIsCreatingConfig(false); } })(); } }, [isCreatingConfig, currentStep, directories, githubAuth, onComplete, configError]); const handleCancel = () => { onCancel(); // The parent waits on Ink's waitUntilExit(), so cancellation must tear // down the rendered wizard as well as setting the cancellation flag. onUnmount?.(); }; const handleBack = () => { switch (currentStep) { case "directories": setCurrentStep("welcome"); break; case "github": setCurrentStep("directories"); break; case "complete": setCurrentStep("github"); break; } }; return ( {currentStep === "welcome" && ( )} {currentStep === "directories" && ( )} {currentStep === "github" && ( )} {currentStep === "complete" && ( )} ); }