Condition.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import React, { useState, useEffect, FC, useMemo } from 'react';
  2. import { Theme, IconButton, TextField, SelectChangeEvent } from '@mui/material';
  3. import { makeStyles } from '@mui/styles';
  4. import CloseIcon from '@mui/icons-material/Close';
  5. import { ConditionProps } from './Types';
  6. import CustomSelector from '../customSelector/CustomSelector';
  7. import { LOGICAL_OPERATORS, DataTypeStringEnum } from '@/consts';
  8. import { formatValue, checkValue } from './utils';
  9. import { FieldObject } from '@server/types';
  10. const Condition: FC<ConditionProps> = props => {
  11. const {
  12. onDelete,
  13. triggerChange,
  14. fields = [],
  15. id = '',
  16. initData,
  17. className = '',
  18. ...others
  19. } = props;
  20. const [operator, setOperator] = useState(
  21. initData?.op || LOGICAL_OPERATORS[0].value
  22. );
  23. const [conditionField, setConditionField] = useState<FieldObject>(
  24. initData?.field || fields[0] || {}
  25. );
  26. const [jsonKeyValue, setJsonKeyValue] = useState(initData?.jsonKey || '');
  27. const [conditionValue, setConditionValue] = useState(
  28. initData?.originValue || ''
  29. );
  30. const [isValueLegal, setIsValueLegal] = useState(
  31. initData?.isCorrect || false
  32. );
  33. const [isKeyLegal, setIsKeyLegal] = useState(initData?.isCorrect || false);
  34. /**
  35. * Check condition's value by field's and operator's type.
  36. * Trigger condition change event.
  37. */
  38. useEffect(() => {
  39. const type = conditionField?.data_type;
  40. const conditionValueWithNoSpace = conditionValue.replaceAll(' ', '');
  41. let isKeyLegal = false;
  42. let isLegal = checkValue({
  43. value: conditionValueWithNoSpace,
  44. type,
  45. operator,
  46. });
  47. // if type is json, check the json key is valid
  48. if (type === DataTypeStringEnum.JSON) {
  49. isKeyLegal = jsonKeyValue.trim() !== '';
  50. }
  51. setIsKeyLegal(isKeyLegal);
  52. setIsValueLegal(isLegal);
  53. triggerChange(id, {
  54. field: conditionField,
  55. op: operator,
  56. jsonKey: jsonKeyValue,
  57. value: formatValue(conditionValue, type, operator),
  58. originValue: conditionValue,
  59. isCorrect:
  60. isLegal &&
  61. ((type === DataTypeStringEnum.JSON && isKeyLegal) ||
  62. type !== DataTypeStringEnum.JSON),
  63. id,
  64. });
  65. // No need for 'id' and 'triggerChange'.
  66. // eslint-disable-next-line react-hooks/exhaustive-deps
  67. }, [conditionField, operator, conditionValue, jsonKeyValue]);
  68. const classes = useStyles();
  69. const logicalOperators = useMemo(() => {
  70. if (conditionField.data_type === DataTypeStringEnum.Bool) {
  71. const data = LOGICAL_OPERATORS.filter(v => v.value === '==');
  72. setOperator(data[0].value);
  73. // bool only support ==
  74. return data;
  75. }
  76. return LOGICAL_OPERATORS;
  77. }, [conditionField]);
  78. // Logic operator input change.
  79. const handleOpChange = (event: SelectChangeEvent<unknown>) => {
  80. setOperator(event.target.value);
  81. };
  82. // Field Name input change.
  83. const handleFieldNameChange = (event: SelectChangeEvent<unknown>) => {
  84. const value = event.target.value;
  85. const target = fields.find(field => field.name === value);
  86. target && setConditionField(target);
  87. };
  88. // Value input change.
  89. const handleValueChange = (event: React.ChangeEvent<HTMLInputElement>) => {
  90. const value = event.target.value;
  91. setConditionValue(value);
  92. };
  93. // Value JSON change.
  94. const handleJSONKeyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
  95. const value = event.target.value;
  96. setJsonKeyValue(value);
  97. };
  98. return (
  99. <div className={`${classes.wrapper} ${className}`} {...others}>
  100. <CustomSelector
  101. label={conditionField.data_type}
  102. value={conditionField?.name}
  103. onChange={handleFieldNameChange}
  104. options={fields.map(i => ({ value: i.name, label: i.name }))}
  105. variant="filled"
  106. wrapperClass={classes.fieldName}
  107. />
  108. {conditionField?.data_type === DataTypeStringEnum.JSON ? (
  109. <TextField
  110. className={classes.key}
  111. label="key"
  112. variant="filled"
  113. value={jsonKeyValue}
  114. // size="small"
  115. onChange={handleJSONKeyChange}
  116. error={!isKeyLegal}
  117. />
  118. ) : null}
  119. <CustomSelector
  120. label="Logic"
  121. value={operator}
  122. onChange={handleOpChange}
  123. options={logicalOperators}
  124. variant="filled"
  125. wrapperClass={classes.logic}
  126. />
  127. <TextField
  128. className={classes.value}
  129. label="Value"
  130. variant="filled"
  131. value={conditionValue}
  132. onChange={handleValueChange}
  133. error={!isValueLegal}
  134. />
  135. <IconButton
  136. aria-label="close"
  137. className={classes.closeButton}
  138. onClick={onDelete}
  139. size="small"
  140. >
  141. <CloseIcon />
  142. </IconButton>
  143. </div>
  144. );
  145. };
  146. Condition.displayName = 'Condition';
  147. const useStyles = makeStyles((theme: Theme) => ({
  148. root: {},
  149. wrapper: {
  150. minWidth: '466px',
  151. minHeight: '62px',
  152. background: theme.palette.background.paper,
  153. padding: theme.spacing(1.5, 2),
  154. display: 'flex',
  155. flexDirection: 'row',
  156. alignItems: 'center',
  157. },
  158. closeButton: {},
  159. fieldName: {
  160. minHeight: '38px',
  161. minWidth: '130px',
  162. },
  163. logic: { minHeight: '38px', minWidth: '100px', margin: '0 24px' },
  164. key: { minHeight: '38px', width: '150px', margin: '0 0' },
  165. value: { minHeight: '38px', minWidth: '130px' },
  166. }));
  167. export default Condition;