All files / src/form/fields DynamicCheckboxAndRadio.tsx

95.65% Statements 22/23
88.88% Branches 16/18
87.5% Functions 7/8
95.65% Lines 22/23

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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                                  66x 18x 18x 18x 18x   18x 6x   6x     6x       18x           18x 12x 6x 5x   1x 1x         18x   18x           18x                       4x                             20x                 18x        
import React, { CSSProperties, ReactElement, useEffect, useState } from "react";
import { Checkbox, Col, Row, Spin, Radio } from "antd";
import { fetchSelectOptions } from "@utils/FetchUtils";
import { FormInstance } from "antd/es/form";
import { CheckboxOptionType } from "antd/lib/checkbox/Group";
 
interface DynamicCheckboxProps {
  style?: CSSProperties;
  dfKey: string;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  onChange: any;
  currentValue: string | Array<string> | number | Array<number>;
  form: FormInstance;
  updatable?: boolean;
  type: "checkbox" | "radio";
}
 
const DynamicCheckboxAndRadio = (props: DynamicCheckboxProps): ReactElement => {
  const { style, updatable, dfKey, onChange, form, currentValue, type } = props;
  const [options, setOptions] = useState<Array<CheckboxOptionType | string>>([] as Array<CheckboxOptionType | string>);
  const [loading, setLoading] = useState<boolean>(true);
  const disabled = (updatable == null) ? false : !updatable;
 
  useEffect(() => {
    fetchSelectOptions(dfKey)
      .then((options: Array<CheckboxOptionType | string>) => {
        setOptions(options);
      }).catch(e => {
        console.error(`Failed to get select options of dynamic field ${dfKey}: ${e}`);
      }).finally(() => setLoading(false));
  }, [dfKey]);
 
  const isValidCurrentValue = (
    currentValue == null ||
    typeof currentValue === 'string' ||
    typeof currentValue === 'number' ||
    Array.isArray(currentValue)
  );
 
  useEffect(() => {
    if (options?.length > 0) {
      if (isValidCurrentValue) {
        form.setFieldsValue({ [dfKey]: currentValue });
      } else {
        console.warn(`value ${currentValue} is not valid value for dynamic checkbox`);
        form.setFieldsValue({ [dfKey]: undefined });
      }
    }
  }, [dfKey, currentValue, options, form, isValidCurrentValue]);
 
  const className = `df_${type}`;
 
  const radioStyle = {
    display: 'block',
    height: '30px',
    lineHeight: '30px',
  };
 
  const content = (type === 'checkbox') ? (
    <Checkbox.Group
      className={className}
      /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
      // @ts-ignore
      defaultValue={isValidCurrentValue ? currentValue : undefined}
      style={style}
      onChange={onChange}
      disabled={disabled}
    >
      <Row>
        {options?.map(opt => (
          <Col key={opt.toString()} span={24}>
            <Checkbox value={opt}>{opt}</Checkbox>
          </Col>)
        )}
      </Row>
    </Checkbox.Group>
  ) : (
      <Radio.Group
        className={className}
        defaultValue={currentValue == null ? "" : currentValue.toString()}
        style={style}
        onChange={onChange}
        disabled={disabled}
      >
        {options?.map(opt => {
          return (
            <Radio key={opt.toString()} style={radioStyle} value={opt}>
              {opt}
            </Radio>
          );
        })}
      </Radio.Group>
    );
 
  return loading ? <Spin size="small" /> : content;
};
 
export default DynamicCheckboxAndRadio;