FormWizard.tsx
1 import { 2 Box, 3 Divider, 4 Flex, 5 Heading, 6 IconButton, 7 Text, 8 } from '@chakra-ui/react'; 9 import { MdOutlineModeStandby } from 'react-icons/md'; 10 import { MdCheckCircleOutline } from 'react-icons/md'; 11 import { MdOutlineErrorOutline } from 'react-icons/md'; 12 import { theme } from 'styles/theme'; 13 14 export interface FormWizardStep { 15 title: string; 16 key: string; 17 status: { 18 isDirty: boolean; 19 isValid: boolean; 20 }; 21 } 22 23 interface FormWizardProps { 24 title: string; 25 steps: FormWizardStep[]; 26 currentStep: number; 27 setStep: (step: number) => void; 28 componentMap: Record<string, React.FC<FormWizardContent>>; 29 } 30 31 export interface FormWizardContent { 32 formKey: FormWizardStep['key']; 33 currentStep: number; 34 setStep: (step: number) => void; 35 } 36 37 const iconBaseProps = { 38 size: 24, 39 fill: theme.colors.glass.white90, 40 }; 41 42 const FormWizard = ({ 43 title, 44 steps, 45 currentStep, 46 setStep, 47 componentMap, 48 }: FormWizardProps): JSX.Element => { 49 const currentFormKey = steps?.[currentStep]?.key; 50 const FormComponent = componentMap[currentFormKey]; 51 52 return ( 53 <Box p={7} m={7}> 54 <Heading as="h2" size="md"> 55 {title} 56 </Heading> 57 <Flex direction="row"> 58 {steps?.map(({ status: { isDirty, isValid }, title }, i) => { 59 const iconProps = 60 currentStep === i ? { ...iconBaseProps, size: 27 } : iconBaseProps; 61 return ( 62 <Box 63 width={100} 64 key={i} 65 mt="5" 66 display="flex" 67 flex={1} 68 flexDir="column" 69 justifyContent="center" 70 alignItems="center" 71 cursor="pointer" 72 onClick={() => setStep(i)} 73 > 74 <IconButton 75 aria-label={title} 76 icon={ 77 isDirty && isValid ? ( 78 <MdCheckCircleOutline {...iconProps} /> 79 ) : isDirty && !isValid ? ( 80 <MdOutlineErrorOutline {...iconProps} /> 81 ) : !isValid && currentStep > i ? ( 82 <MdOutlineErrorOutline {...iconProps} /> 83 ) : ( 84 <MdOutlineModeStandby {...iconProps} /> 85 ) 86 } 87 colorScheme={ 88 isDirty && isValid 89 ? 'green' 90 : currentStep > i 91 ? 'yellow' 92 : 'whiteAlpha' 93 } 94 isRound 95 isActive 96 /> 97 <Text 98 fontSize="sm" 99 align="center" 100 mt="1" 101 color={currentStep === i ? 'glass.white90' : 'glass.white70'} 102 > 103 {`${i + 1}. ${title}`} 104 </Text> 105 </Box> 106 ); 107 })} 108 </Flex> 109 <Divider orientation="horizontal" my={5} /> 110 <Flex direction="column" flexDirection="column"> 111 <Text fontSize="lg">{steps?.[currentStep].title}</Text> 112 <FormComponent 113 formKey={currentFormKey} 114 setStep={setStep} 115 currentStep={currentStep} 116 /> 117 </Flex> 118 </Box> 119 ); 120 }; 121 122 export default FormWizard;