aboutsummaryrefslogtreecommitdiff
path: root/admin/src/components/CheckboxListDefaultInput.tsx
blob: ffd055137b39fe5b631f3fda29f28fd4ab30e1da (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import type { ReactNode } from 'react';

import { Box, Field, MultiSelect, MultiSelectOption, Typography } from '@strapi/design-system';
import { useIntl } from 'react-intl';

type CheckboxListDefaultInputProps = {
  name: string;
  value?: unknown;
  onChange: (eventOrPath: { target: { name: string; value: string[] } }, value?: unknown) => void;
  intlLabel?: {
    id: string;
    defaultMessage: string;
    values?: Record<string, string | number | boolean | null | undefined>;
  };
  description?: {
    id: string;
    defaultMessage: string;
    values?: Record<string, string | number | boolean | null | undefined>;
  };
  labelAction?: ReactNode;
  required?: boolean;
  disabled?: boolean;
  error?: string;
  modifiedData?: {
    enum?: string[];
    options?: {
      enum?: string[];
    };
  };
};

const normalizeValue = (value: unknown): string[] => {
  if (Array.isArray(value)) {
    return value.filter((item): item is string => typeof item === 'string');
  }

  if (typeof value === 'string' && value.length > 0) {
    return [value];
  }

  return [];
};

const CheckboxListDefaultInput = ({
  name,
  value,
  onChange,
  intlLabel,
  description,
  labelAction,
  required = false,
  disabled = false,
  error,
  modifiedData,
}: CheckboxListDefaultInputProps) => {
  const { formatMessage } = useIntl();
  const enumValues = Array.isArray(modifiedData?.options?.enum)
    ? modifiedData.options.enum
    : Array.isArray(modifiedData?.enum)
      ? modifiedData.enum
      : [];
  const selectedValues = normalizeValue(value);
  const uniqueValues = Array.from(
    new Set(enumValues.filter((option) => typeof option === 'string' && option.trim().length > 0))
  );

  const label = intlLabel
    ? formatMessage(intlLabel, intlLabel.values ?? {})
    : name;
  const hint = description ? formatMessage(description, description.values ?? {}) : undefined;

  const handleChange = (nextValues: string[] | undefined) => {
    onChange({
      target: {
        name,
        value: Array.isArray(nextValues) ? nextValues : [],
      },
    });
  };

  return (
    <Field.Root name={name} hint={hint} error={error} required={required}>
      <Field.Label action={labelAction}>{label}</Field.Label>
      {uniqueValues.length > 0 ? (
        <Box paddingTop={1}>
          <MultiSelect
            aria-label={label}
            disabled={disabled}
            id={name}
            name={name}
            onChange={handleChange}
            placeholder={formatMessage({
              id: 'checkbox-list.default.placeholder',
              defaultMessage: 'Select default values',
            })}
            value={selectedValues}
            withTags
          >
            {uniqueValues.map((option) => (
              <MultiSelectOption key={option} value={option}>
                {option}
              </MultiSelectOption>
            ))}
          </MultiSelect>
        </Box>
      ) : (
        <Box paddingTop={1}>
          <Typography variant="pi" textColor="neutral500">
            {formatMessage({
              id: 'checkbox-list.field.empty',
              defaultMessage: 'No values configured yet.',
            })}
          </Typography>
        </Box>
      )}
      <Field.Error />
      <Field.Hint />
    </Field.Root>
  );
};

export { CheckboxListDefaultInput };