/ ui / src / components / FormTextareaArray.tsx
FormTextareaArray.tsx
 1  import {
 2    Box,
 3    FormControl,
 4    FormErrorMessage,
 5    FormLabel,
 6    FormHelperText,
 7    Textarea,
 8    FormControlProps,
 9  } from '@chakra-ui/react';
10  import { Controller, UseFormReturn, FieldError } from 'react-hook-form';
11  
12  interface FormTextareaArrayProps {
13    name: string;
14    label: string;
15    defaultValue?: number;
16    description?: string;
17    hint?: string;
18    // @todo: fix type
19    control: UseFormReturn['control'] | any;
20    controlVariant?: FormControlProps['variant'];
21  }
22  
23  function formatErrors(errors: FieldError[]): string | null {
24    if (!errors || !errors.length) return null;
25    const unique = errors.reduce((acc, curr) => {
26      if (!curr.message) return acc;
27      if (!acc[curr.message]) acc[curr.message] = 1;
28      else acc[curr.message] += 1;
29      return acc;
30    }, {} as { [key: string]: number });
31    const str = Object.entries(unique).reduce((acc, [message, count], i) => {
32      if (i === 0) return `${message} (${count})`;
33      return acc + '\n' + `${message} (${count})`;
34    }, '');
35    return str;
36  }
37  
38  const FormTextareaArray = ({
39    name,
40    label,
41    hint,
42    control,
43    controlVariant,
44  }: FormTextareaArrayProps) => {
45    return (
46      <Box maxW={680} mb={10}>
47        <Controller
48          control={control}
49          name={name}
50          render={({
51            field: { onChange, onBlur, value, name, ref },
52            fieldState: { error },
53          }) => {
54            return (
55              <FormControl mt={2} isInvalid={!!error} variant={controlVariant}>
56                <FormLabel htmlFor={name}>{label}</FormLabel>
57                <FormHelperText>{hint}</FormHelperText>
58                <Box
59                  display="flex"
60                  flexDirection="row"
61                  mt={3}
62                  alignItems="center"
63                >
64                  <Textarea
65                    size="md"
66                    colorScheme="green"
67                    onBlur={onBlur}
68                    onChange={(e) => {
69                      onBlur();
70                      onChange(e.target.value.split('\n'));
71                    }}
72                    ref={ref}
73                    value={Array.isArray(value) ? value.join('\n') : []}
74                    name={name}
75                  />
76                </Box>
77                <FormErrorMessage whiteSpace="pre-line">
78                  {error?.message
79                    ? error.message
80                    : (error as unknown as FieldError[])?.length
81                    ? formatErrors(error as unknown as FieldError[])
82                    : null}
83                </FormErrorMessage>
84              </FormControl>
85            );
86          }}
87        />
88      </Box>
89    );
90  };
91  
92  export default FormTextareaArray;