ConditionGroup.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import React, { useState, FC } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import { Theme } from '@mui/material';
  4. import { makeStyles } from '@mui/styles';
  5. import { ToggleButton, ToggleButtonGroup } from '@mui/lab';
  6. import ConditionItem from './Condition';
  7. import icons from '../icons/Icons';
  8. import CustomButton from '../customButton/CustomButton';
  9. import {
  10. ConditionGroupProps,
  11. BinaryLogicalOpProps,
  12. AddConditionProps,
  13. } from './Types';
  14. // "And & or" operator component.
  15. const BinaryLogicalOp: FC<BinaryLogicalOpProps> = props => {
  16. const { onChange, className, initValue = 'and' } = props;
  17. const [operator, setOperator] = useState(initValue);
  18. const handleChange = (
  19. event: React.MouseEvent<HTMLElement>,
  20. newOp: string
  21. ) => {
  22. if (newOp !== null) {
  23. setOperator(newOp);
  24. onChange(newOp);
  25. }
  26. };
  27. return (
  28. <>
  29. <div className={`${className} op-${operator}`}>
  30. <ToggleButtonGroup
  31. value={operator}
  32. exclusive
  33. onChange={handleChange}
  34. aria-label="Binary Logical Operator"
  35. >
  36. <ToggleButton value="and" aria-label="And">
  37. AND
  38. </ToggleButton>
  39. <ToggleButton value="or" aria-label="Or">
  40. OR
  41. </ToggleButton>
  42. </ToggleButtonGroup>
  43. <div className="op-split" />
  44. </div>
  45. </>
  46. );
  47. };
  48. // "+ Add condition" component.
  49. const AddCondition: FC<AddConditionProps> = props => {
  50. const { className, onClick } = props;
  51. const { t: searchTrans } = useTranslation('search');
  52. const AddIcon = icons.add;
  53. return (
  54. <CustomButton
  55. onClick={onClick}
  56. color="primary"
  57. className={className}
  58. startIcon={<AddIcon />}
  59. >
  60. {searchTrans('addCondition')}
  61. </CustomButton>
  62. );
  63. };
  64. // Condition group component which contains of BinaryLogicalOp, AddCondition and ConditionItem.
  65. const ConditionGroup = (props: ConditionGroupProps) => {
  66. const {
  67. fields = [],
  68. handleConditions = {},
  69. conditions: flatConditions = [],
  70. } = props;
  71. const {
  72. addCondition,
  73. removeCondition,
  74. changeBinaryLogicalOp,
  75. updateConditionData,
  76. } = handleConditions;
  77. const classes = useStyles();
  78. const generateClassName = (conditions: any, currentIndex: number) => {
  79. let className = '';
  80. if (currentIndex === 0 || conditions[currentIndex - 1].type === 'break') {
  81. className += 'radius-top';
  82. }
  83. if (
  84. currentIndex === conditions.length - 1 ||
  85. conditions[currentIndex + 1].type === 'break'
  86. ) {
  87. className ? (className = 'radius-all') : (className = 'radius-bottom');
  88. }
  89. return className;
  90. };
  91. // Generate condition items with operators and add condition btn.
  92. const generateConditionItems = (conditions: any[]) => {
  93. const conditionsLength = conditions.length;
  94. const results = conditions.reduce((prev: any, condition, currentIndex) => {
  95. if (currentIndex === conditionsLength - 1) {
  96. prev.push(
  97. <ConditionItem
  98. key={condition.id}
  99. id={condition.id}
  100. onDelete={() => {
  101. removeCondition(condition.id);
  102. }}
  103. fields={fields}
  104. triggerChange={updateConditionData}
  105. initData={condition?.data}
  106. className={generateClassName(conditions, currentIndex)}
  107. />
  108. );
  109. prev.push(
  110. <AddCondition
  111. key={`${condition.id}-add`}
  112. className={classes.addBtn}
  113. onClick={() => {
  114. addCondition(condition.id);
  115. }}
  116. />
  117. );
  118. } else if (condition.type === 'break') {
  119. prev.pop();
  120. prev.push(
  121. <AddCondition
  122. key={`${condition.id}-add`}
  123. className={classes.addBtn}
  124. onClick={() => {
  125. addCondition(condition.id, true);
  126. }}
  127. />
  128. );
  129. prev.push(
  130. <BinaryLogicalOp
  131. key={`${condition.id}-op`}
  132. onChange={newOp => {
  133. changeBinaryLogicalOp(newOp, condition.id);
  134. }}
  135. className={classes.binaryLogicOp}
  136. initValue="or"
  137. />
  138. );
  139. } else if (condition.type === 'condition') {
  140. prev.push(
  141. <ConditionItem
  142. key={condition.id}
  143. id={condition.id}
  144. onDelete={() => {
  145. removeCondition(condition.id);
  146. }}
  147. fields={fields}
  148. triggerChange={updateConditionData}
  149. initData={condition?.data}
  150. className={generateClassName(conditions, currentIndex)}
  151. />
  152. );
  153. prev.push(
  154. <BinaryLogicalOp
  155. key={`${condition.id}-op`}
  156. onChange={newOp => {
  157. changeBinaryLogicalOp(newOp, condition.id);
  158. }}
  159. className={classes.binaryLogicOp}
  160. />
  161. );
  162. }
  163. return prev;
  164. }, []);
  165. return results;
  166. };
  167. return (
  168. <div className={classes.wrapper}>
  169. {generateConditionItems(flatConditions)}
  170. {flatConditions?.length === 0 && (
  171. <AddCondition
  172. className={classes.addBtn}
  173. onClick={() => {
  174. addCondition();
  175. }}
  176. />
  177. )}
  178. </div>
  179. );
  180. };
  181. ConditionGroup.displayName = 'ConditionGroup';
  182. const useStyles = makeStyles((theme: Theme) => ({
  183. root: {},
  184. wrapper: {
  185. display: 'flex',
  186. flexDirection: 'column',
  187. alignItems: 'center',
  188. '& .op-or': {
  189. backgroundColor: 'unset',
  190. margin: '16px 0',
  191. },
  192. },
  193. addBtn: {},
  194. binaryLogicOp: {
  195. width: '100%',
  196. backgroundColor: '#FFFFFF',
  197. display: 'flex',
  198. flexDirection: 'row',
  199. alignItems: 'center',
  200. '& .op-split': {
  201. height: '1px',
  202. backgroundColor: '#E9E9ED',
  203. width: '100%',
  204. },
  205. '& button': {
  206. width: '42px',
  207. height: '32px',
  208. color: theme.palette.attuDark.main,
  209. },
  210. '& button.Mui-selected': {
  211. backgroundColor: theme.palette.primary.main,
  212. color: '#FFFFFF',
  213. },
  214. '& button.Mui-selected:hover': {
  215. backgroundColor: theme.palette.primary.main,
  216. color: '#FFFFFF',
  217. },
  218. },
  219. }));
  220. export default ConditionGroup;