feat: radio and select fields are filterable by options (#3136)
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ReactSelect from '../../../ReactSelect';
|
||||
import { getTranslation } from '../../../../../../utilities/getTranslation';
|
||||
import { Props } from './types';
|
||||
import { Option, OptionObject } from '../../../../../../fields/config/types';
|
||||
|
||||
const formatOptions = (options: Option[]): OptionObject[] => options.map((option) => {
|
||||
if (typeof option === 'object' && (option.value || option.value === '')) {
|
||||
return option;
|
||||
}
|
||||
|
||||
return {
|
||||
label: option,
|
||||
value: option,
|
||||
} as OptionObject;
|
||||
});
|
||||
|
||||
export const Select: React.FC<Props> = ({ onChange, value, options: optionsFromProps, operator }) => {
|
||||
const { i18n } = useTranslation();
|
||||
const [options, setOptions] = React.useState(formatOptions(optionsFromProps));
|
||||
|
||||
const isMulti = ['in', 'not_in'].includes(operator);
|
||||
let valueToRender;
|
||||
|
||||
if (isMulti && Array.isArray(value)) {
|
||||
valueToRender = value.map((val) => {
|
||||
const matchingOption = options.find((option) => option.value === val);
|
||||
return {
|
||||
label: matchingOption ? getTranslation(matchingOption.label, i18n) : val,
|
||||
value: matchingOption?.value ?? val,
|
||||
};
|
||||
});
|
||||
} else if (value) {
|
||||
const matchingOption = options.find((option) => option.value === value);
|
||||
valueToRender = {
|
||||
label: matchingOption ? getTranslation(matchingOption.label, i18n) : value,
|
||||
value: matchingOption?.value ?? value,
|
||||
};
|
||||
}
|
||||
|
||||
const onSelect = React.useCallback((selectedOption) => {
|
||||
let newValue;
|
||||
if (!selectedOption) {
|
||||
newValue = null;
|
||||
} else if (isMulti) {
|
||||
if (Array.isArray(selectedOption)) {
|
||||
newValue = selectedOption.map((option) => option.value);
|
||||
} else {
|
||||
newValue = [];
|
||||
}
|
||||
} else {
|
||||
newValue = selectedOption.value;
|
||||
}
|
||||
|
||||
onChange(newValue);
|
||||
}, [
|
||||
isMulti,
|
||||
onChange,
|
||||
]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setOptions(formatOptions(optionsFromProps));
|
||||
}, [optionsFromProps]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!isMulti && Array.isArray(value)) {
|
||||
onChange(value[0]);
|
||||
}
|
||||
}, [isMulti, onChange, value]);
|
||||
|
||||
return (
|
||||
<ReactSelect
|
||||
onChange={onSelect}
|
||||
value={valueToRender}
|
||||
options={options.map((option) => ({ ...option, label: getTranslation(option.label, i18n) }))}
|
||||
isMulti={isMulti}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Operator } from '../../../../../../types';
|
||||
import { Option } from '../../../../../../fields/config/types';
|
||||
|
||||
export type Props = {
|
||||
onChange: (val: string) => void,
|
||||
value: string,
|
||||
options: Option[]
|
||||
operator: Operator
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import Date from './Date';
|
||||
import Number from './Number';
|
||||
import Text from './Text';
|
||||
import Relationship from './Relationship';
|
||||
import { Select } from './Select';
|
||||
import useDebounce from '../../../../hooks/useDebounce';
|
||||
import { FieldCondition } from '../types';
|
||||
|
||||
@@ -17,6 +18,7 @@ const valueFields = {
|
||||
Number,
|
||||
Text,
|
||||
Relationship,
|
||||
Select,
|
||||
};
|
||||
|
||||
const baseClass = 'condition';
|
||||
@@ -56,7 +58,15 @@ const Condition: React.FC<Props> = (props) => {
|
||||
});
|
||||
}, [debouncedValue, dispatch, orIndex, andIndex]);
|
||||
|
||||
const ValueComponent = valueFields[activeField?.component] || valueFields.Text;
|
||||
const booleanSelect = ['exists'].includes(operatorValue) || activeField.props.type === 'checkbox';
|
||||
const ValueComponent = booleanSelect ? Select : (valueFields[activeField?.component] || valueFields.Text);
|
||||
|
||||
let selectOptions;
|
||||
if (booleanSelect) {
|
||||
selectOptions = ['true', 'false'];
|
||||
} else if ('options' in activeField?.props) {
|
||||
selectOptions = activeField.props.options;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
@@ -95,6 +105,7 @@ const Condition: React.FC<Props> = (props) => {
|
||||
DefaultComponent={ValueComponent}
|
||||
componentProps={{
|
||||
...activeField?.props,
|
||||
options: selectOptions,
|
||||
operator: operatorValue,
|
||||
value: internalValue,
|
||||
onChange: setInternalValue,
|
||||
|
||||
@@ -112,8 +112,12 @@ const fieldTypeConditions = {
|
||||
component: 'Relationship',
|
||||
operators: [...base],
|
||||
},
|
||||
radio: {
|
||||
component: 'Select',
|
||||
operators: [...base],
|
||||
},
|
||||
select: {
|
||||
component: 'Text',
|
||||
component: 'Select',
|
||||
operators: [...base],
|
||||
},
|
||||
checkbox: {
|
||||
|
||||
Reference in New Issue
Block a user