All files / src/form/fields DynamicSelect.tsx

100% Statements 19/19
87.5% Branches 7/8
100% Functions 7/7
100% Lines 18/18

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              66x                         66x       78x 76x 76x 76x   76x 24x 24x   12x     12x   12x     76x 36x 8x       76x 76x             76x                                        
import React, { CSSProperties, ReactElement, useEffect, useState } from "react";
import { Select, Spin } from "antd";
import { fetchSelectOptions } from "@utils/FetchUtils";
import { FormInstance } from "antd/es/form";
import { getReadOnlyClass } from "@utils/ComponentUtils";
import { SuffixIcon } from '../../components';
 
const { Option } = Select;
 
interface DynamicSelectProps {
  style?: CSSProperties;
  mode?: "multiple" | "tags";
  dfKey: string;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  onChange: any;
  currentValue: string | Array<string> | number | Array<number>;
  form: FormInstance;
  updatable?: boolean;
}
 
const DynamicSelect = (props: DynamicSelectProps): ReactElement => {
  const {
    mode, style, updatable, dfKey, onChange,
    form, currentValue
  } = props;
  const [options, setOptions] = useState<Array<string | number>>([] as Array<string | number>);
  const [loading, setLoading] = useState<boolean>(false);
  const disabled = (updatable == null) ? false : !updatable;
 
  useEffect(() => {
    setLoading(true);
    fetchSelectOptions(dfKey)
      .then((options: Array<string | number>) => {
        return options;
      })
      .then((options: Array<string | number>) => {
        setOptions(options);
      })
      .then(() => setLoading(false));
  }, [dfKey]);
 
  useEffect(() => {
    if (options?.length > 0) {
      form.setFieldsValue({ [dfKey]: currentValue });
    }
  }, [dfKey, currentValue, options, form]);
 
  const optElem = options?.map(opt => <Option key={opt} value={opt}>{opt}</Option>);
  const className = `df_${mode == null ? "single" : mode}`;
 
  // **** Attention ****
  // zIndex of the select dropdown should higher than the zIndex of modal(by
  // default 1051) because the dropdown might be displayed on a modal
  // https://stackoverflow.com/questions/53926911/antd-select-not-working-inside-a-full-screen-dialog
  // Set in app.less by .ant-select-dropdown
  return loading ? <Spin size="small" /> : (
    <Select
      className={`${className} ${getReadOnlyClass(updatable)}`}
      mode={mode}
      style={style}
      onChange={onChange}
      defaultValue={currentValue}
      disabled={disabled}
      showSearch={true}
      suffixIcon={<SuffixIcon updatable={updatable} />}
      allowClear={true}
      showArrow={true}
      dropdownStyle={{ zIndex: 2000 }}
    >
      {optElem}
    </Select>
  );
};
 
export default DynamicSelect;