// @flow import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import isFinite from 'lodash/isFinite'; import isInteger from 'lodash/isInteger'; import classNames from 'classnames'; import IconClose from '../../../../icons/general/IconClose'; import Tooltip from '../../../../components/tooltip'; import IconAlertDefault from '../../../../icons/general/IconAlertDefault'; import SingleSelectField from '../../../../components/select-field/SingleSelectField'; import ValueField from './ValueField'; import messages from '../../messages'; import { AND, COLUMN, COLUMN_OPERATORS, DATE, ENUM, FLOAT, MULTI_SELECT, NUMBER, OPERATOR, OR, STRING, } from '../../constants'; import type { ColumnType, ConditionType, ConditionValueType, ConnectorType, OperatorOptionType, OperatorType, OptionType, } from '../../flowTypes'; import '../../styles/Condition.scss'; type Props = { columns?: Array, condition: ConditionType, deleteCondition: (index: number) => void, hasUserSubmitted: boolean, index: number, onColumnChange: (condition: ConditionType, columnId: string) => void, onConnectorChange: (option: OptionType) => void, onOperatorChange: (conditionId: string, value: OperatorType) => void, onValueChange: (conditionId: string, values: Array) => void, selectedConnector: ConnectorType, }; const deleteButtonIconHeight = 18; const deleteButtonIconWidth = 18; const Condition = ({ hasUserSubmitted, columns, condition, deleteCondition, onColumnChange, onOperatorChange, onValueChange, index, selectedConnector, onConnectorChange, }: Props) => { const onDeleteButtonClick = () => { deleteCondition(index); }; const handleColumnChange = (option: OptionType) => { const { value: columnId } = option; onColumnChange(condition, columnId); }; const handleOperatorChange = (option: OperatorOptionType) => { const { id } = condition; const { value } = option; onOperatorChange(id, value); }; const handleValueChange = (values: Array) => { const { id } = condition; onValueChange(id, values); }; const getColumnOperators = () => { const { columnId } = condition; const column = columns && columns.find(c => c.id === columnId); const type = column && column.type; if (!type) { return []; } return COLUMN_OPERATORS[type]; }; const getColumnOptions = () => { const { columnId } = condition; const column = columns && columns.find(c => c.id === columnId); if (column && column.options) { return column.options.map(option => { const { key } = option; return { displayText: key, value: key, }; }); } return []; }; const validateValue = (values: Array, type: string) => { switch (type) { case NUMBER: return isInteger(Number(values[0])); case FLOAT: return isFinite(Number(values[0])); default: break; } return true; }; const getErrorMessage = () => { const { values, columnId } = condition; const column = columns && columns.find(c => c.id === columnId); const type = column && column.type; const isValueEmpty = values.length === 0; let isValueValid = false; if (!isValueEmpty && type) { isValueValid = validateValue(values, type); } /** * isValueValid handles the error case when the user tries to enter an invalid input in either a * number type field or a float type field * * (!hasUserSubmitted && !isValueSet) handles the error case when a user presses on the Apply button * but the input field is empty */ if (isValueValid || (!hasUserSubmitted && isValueEmpty)) { return null; } let messageText; switch (type) { case STRING: messageText = messages.tooltipEnterValueError; break; case NUMBER: messageText = !isValueValid ? messages.tooltipInvalidNumberError : messages.tooltipEnterValueError; break; case FLOAT: messageText = !isValueValid ? messages.tooltipInvalidFloatError : messages.tooltipEnterValueError; break; case DATE: messageText = messages.tooltipSelectDateError; break; case ENUM: messageText = messages.tooltipSelectValueError; break; case MULTI_SELECT: messageText = messages.tooltipSelectValueError; break; default: break; } return messageText && ; }; const renderDeleteButton = () => { return (
); }; const renderConnectorField = () => { const connectorOptions = [AND, OR].map(connector => ({ displayText: connector, value: connector, })); return (
{index === 0 ? (

) : ( )}
); }; const renderColumnField = () => { const { columnId } = condition; const columnOptions = columns && columns.map(column => { const { displayName, id, type } = column; return { displayText: displayName, type, value: id, }; }); return (
); }; const renderOperatorField = () => { const { operator } = condition; const columnOperators = getColumnOperators(); const operatorOptions = columnOperators.map(_operator => { const { displayText, key } = _operator; return { displayText, value: key, }; }); return (
); }; const renderValueField = () => { const column = columns && columns.find(c => c.id === condition.columnId); if (!column) { throw new Error('Expected Column'); } const valueOptions = getColumnOptions(); const error = getErrorMessage(); const classnames = classNames('condition-value-dropdown-container', { 'show-error': error, }); return (
); }; const renderErrorIcon = () => { const error = getErrorMessage(); return ( error && (
) ); }; return (
{renderDeleteButton()} {renderConnectorField()} {renderColumnField()} {renderOperatorField()} {renderValueField()} {renderErrorIcon()}
); }; export default Condition;