import { useCallback, useMemo, useState } from 'react'; import { FolderPlus, X } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import ErrorBanner from './components/ErrorBanner'; import StepConfiguration from './components/StepConfiguration'; import StepReview from './components/StepReview'; import StepTypeSelection from './components/StepTypeSelection'; import WizardFooter from './components/WizardFooter'; import WizardProgress from './components/WizardProgress'; import { useGithubTokens } from './hooks/useGithubTokens'; import { cloneWorkspaceWithProgress, createWorkspaceRequest } from './data/workspaceApi'; import { isCloneWorkflow, shouldShowGithubAuthentication } from './utils/pathUtils'; import type { TokenMode, WizardFormState, WizardStep, WorkspaceType } from './types'; type ProjectCreationWizardProps = { onClose: () => void; onProjectCreated?: (project?: Record) => void; }; const initialFormState: WizardFormState = { workspaceType: 'existing', workspacePath: '', githubUrl: '', tokenMode: 'stored', selectedGithubToken: '', newGithubToken: '', }; export default function ProjectCreationWizard({ onClose, onProjectCreated, }: ProjectCreationWizardProps) { const { t } = useTranslation(); const [step, setStep] = useState(1); const [formState, setFormState] = useState(initialFormState); const [isCreating, setIsCreating] = useState(false); const [error, setError] = useState(null); const [cloneProgress, setCloneProgress] = useState(''); const shouldLoadTokens = step === 2 && shouldShowGithubAuthentication(formState.workspaceType, formState.githubUrl); const autoSelectToken = useCallback((tokenId: string) => { setFormState((previous) => ({ ...previous, selectedGithubToken: tokenId })); }, []); const { tokens: availableTokens, loading: loadingTokens, loadError: tokenLoadError, selectedTokenName, } = useGithubTokens({ shouldLoad: shouldLoadTokens, selectedTokenId: formState.selectedGithubToken, onAutoSelectToken: autoSelectToken, }); // Keep cross-step values in this component; local UI state lives in child components. const updateField = useCallback((key: K, value: WizardFormState[K]) => { setFormState((previous) => ({ ...previous, [key]: value })); }, []); const updateWorkspaceType = useCallback( (workspaceType: WorkspaceType) => updateField('workspaceType', workspaceType), [updateField], ); const updateTokenMode = useCallback( (tokenMode: TokenMode) => updateField('tokenMode', tokenMode), [updateField], ); const handleNext = useCallback(() => { setError(null); if (step === 1) { if (!formState.workspaceType) { setError(t('projectWizard.errors.selectType')); return; } setStep(2); return; } if (step === 2) { if (!formState.workspacePath.trim()) { setError(t('projectWizard.errors.providePath')); return; } setStep(3); } }, [formState.workspacePath, formState.workspaceType, step, t]); const handleBack = useCallback(() => { setError(null); setStep((previousStep) => (previousStep > 1 ? ((previousStep - 1) as WizardStep) : previousStep)); }, []); const handleCreate = useCallback(async () => { setIsCreating(true); setError(null); setCloneProgress(''); try { const shouldCloneRepository = isCloneWorkflow(formState.workspaceType, formState.githubUrl); if (shouldCloneRepository) { const project = await cloneWorkspaceWithProgress( { workspacePath: formState.workspacePath, githubUrl: formState.githubUrl, tokenMode: formState.tokenMode, selectedGithubToken: formState.selectedGithubToken, newGithubToken: formState.newGithubToken, }, { onProgress: setCloneProgress, }, ); onProjectCreated?.(project); onClose(); return; } const project = await createWorkspaceRequest({ workspaceType: formState.workspaceType, path: formState.workspacePath.trim(), }); onProjectCreated?.(project); onClose(); } catch (createError) { const errorMessage = createError instanceof Error ? createError.message : t('projectWizard.errors.failedToCreate'); setError(errorMessage); } finally { setIsCreating(false); } }, [formState, onClose, onProjectCreated, t]); const shouldCloneRepository = useMemo( () => isCloneWorkflow(formState.workspaceType, formState.githubUrl), [formState.githubUrl, formState.workspaceType], ); return (

{t('projectWizard.title')}

{error && } {step === 1 && ( )} {step === 2 && ( updateField('workspacePath', workspacePath)} onGithubUrlChange={(githubUrl) => updateField('githubUrl', githubUrl)} onTokenModeChange={updateTokenMode} onSelectedGithubTokenChange={(selectedGithubToken) => updateField('selectedGithubToken', selectedGithubToken) } onNewGithubTokenChange={(newGithubToken) => updateField('newGithubToken', newGithubToken) } onAdvanceToConfirm={() => setStep(3)} /> )} {step === 3 && ( )}
); }