/ ui / src / components / FormWizard.tsx
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;