import type React from 'react'; import { useState } from 'react' import type { FC, ReactNode } from 'react'; import { Button } from '@lilith/ui-primitives'; import styled, { type DefaultTheme } from 'styled-components'; export interface FormStep { id: string; label: string; component: ReactNode; validate?: () => boolean | Promise; } export interface MultiStepFormProps { steps: FormStep[]; onComplete: () => void | Promise; onCancel?: () => void; showProgress?: boolean; } const FormContainer = styled.div` background: ${(props: { theme: DefaultTheme }) => props.theme.colors.surface}; border: 1px solid ${(props: { theme: DefaultTheme }) => props.theme.colors.border}; border-radius: ${(props: { theme: DefaultTheme }) => props.theme.borderRadius.lg}; overflow: hidden; `; const ProgressBar = styled.div` display: flex; background: ${(props: { theme: DefaultTheme }) => props.theme.colors.background}; border-bottom: 1px solid ${(props: { theme: DefaultTheme }) => props.theme.colors.border}; `; const ProgressStep = styled.div<{ $active: boolean; $completed: boolean }>` flex: 1; padding: ${(props: { theme: DefaultTheme }) => props.theme.spacing.md}; text-align: center; position: relative; font-size: ${(props: { theme: DefaultTheme }) => props.theme.typography.fontSize.sm}; font-weight: ${(props) => props.$active ? props.theme.typography.fontWeight.semibold : 'normal'}; color: ${(props) => { if (props.$completed) { return props.theme.colors.success; } if (props.$active) { return props.theme.colors.primary; } return props.theme.colors.text.secondary; }}; background: ${(props) => (props.$active ? `${props.theme.colors.primary}10` : 'transparent')}; &:not(:last-child)::after { content: '→'; position: absolute; right: -12px; top: 50%; transform: translateY(-50%); color: ${(props: { theme: DefaultTheme }) => props.theme.colors.text.secondary}; } `; const StepNumber = styled.div<{ $active: boolean; $completed: boolean }>` width: 28px; height: 28px; border-radius: 50%; background: ${(props) => { if (props.$completed) { return props.theme.colors.success; } if (props.$active) { return props.theme.colors.primary; } return props.theme.colors.surface; }}; border: 2px solid ${(props) => { if (props.$completed) { return props.theme.colors.success; } if (props.$active) { return props.theme.colors.primary; } return props.theme.colors.border; }}; color: ${(props) => props.$active || props.$completed ? 'white' : props.theme.colors.text.secondary}; display: flex; align-items: center; justify-content: center; margin: 0 auto ${(props: { theme: DefaultTheme }) => props.theme.spacing.xs}; font-size: ${(props: { theme: DefaultTheme }) => props.theme.typography.fontSize.sm}; font-weight: ${(props: { theme: DefaultTheme }) => props.theme.typography.fontWeight.bold}; `; const StepContent = styled.div` padding: ${(props: { theme: DefaultTheme }) => props.theme.spacing.xl}; min-height: 300px; `; const StepActions = styled.div` display: flex; justify-content: space-between; padding: ${(props: { theme: DefaultTheme }) => props.theme.spacing.lg}; border-top: 1px solid ${(props: { theme: DefaultTheme }) => props.theme.colors.border}; background: ${(props: { theme: DefaultTheme }) => props.theme.colors.background}; `; const ActionGroup = styled.div` display: flex; gap: ${(props: { theme: DefaultTheme }) => props.theme.spacing.sm}; `; export const MultiStepForm: FC = ({ steps, onComplete, onCancel, showProgress = true, }) => { const [currentStep, setCurrentStep] = useState(0); const [completedSteps, setCompletedSteps] = useState>(new Set()); const [isValidating, setIsValidating] = useState(false); const isFirstStep = currentStep === 0; const isLastStep = currentStep === steps.length - 1; const handleNext = async () => { const step = steps[currentStep]; if (!step) return; if (step.validate) { setIsValidating(true); try { const isValid = await step.validate(); if (!isValid) { setIsValidating(false); return; } } catch { setIsValidating(false); return; } setIsValidating(false); } setCompletedSteps((prev) => new Set(prev).add(currentStep)); if (isLastStep) { await onComplete(); } else { setCurrentStep(currentStep + 1); } }; const handleBack = () => { if (!isFirstStep) { setCurrentStep(currentStep - 1); } }; const handleStepClick = (stepIndex: number) => { // Allow clicking on completed steps or the next step if (completedSteps.has(stepIndex) || stepIndex === currentStep + 1) { setCurrentStep(stepIndex); } }; return ( {showProgress && ( {steps.map((step, index) => ( handleStepClick(index)} style={{ cursor: completedSteps.has(index) || index === currentStep + 1 ? 'pointer' : 'default', }} > {completedSteps.has(index) ? '✓' : index + 1} {step.label} ))} )} {steps[currentStep]?.component} {onCancel && ( )} {!isFirstStep && ( )} ); };