· 6 years ago · Oct 16, 2019, 10:48 AM
1import React from 'react';
2import PropTypes from 'prop-types';
3import { connect } from 'react-redux';
4import uuidV4 from 'uuid/v4';
5
6import { InputGroup } from '../../../../../components';
7
8import ConditionGroup from './ConditionGroup';
9import Accordion from '../../../../Accordion';
10import { defaultCondition, actionSelectOptionsIds, rowFieldNames } from '../../../constants';
11
12import { selectTabBlockConfig } from '../../../actions';
13
14import './style/style.css';
15import OtherPeriods from './timeConditionOtherPeriods';
16
17/**
18 * This function represents the Configuration Tab of the API.
19 *
20 * @param {Object} props - Object with props of the component.
21 * @param {Object} props.translations - The translations.
22 *
23 * @returns {Object} Returns the JSX.
24 */
25class ConditionSet extends React.Component {
26 constructor(props) {
27 super(props);
28
29 this.bind();
30 this.rowUuidTest = '';
31
32 this.rowRules = {
33 condition: row => this.props.plugin.startValidation(this.rowFieldNames.condition, row.uuid).setValue(row.condition).isRequired(true).end(),
34 };
35
36 this.rowFieldNames = {
37 label: rowFieldNames.LABEL,
38 condition: rowFieldNames.CONDITION,
39 action: rowFieldNames.ACTION,
40 varOps: rowFieldNames.VAROPS,
41 playSsml: rowFieldNames.TTS,
42 continue: rowFieldNames.CONTINUE,
43 ddiOrExtension: rowFieldNames.DDI_OR_EXTENSION,
44 queueId: rowFieldNames.QUEUE_ID,
45 alternateAction: rowFieldNames.ALTERNATE_ACTION,
46 };
47
48 this.props.plugin.registerOnSubmitAction((end) => {
49 this.props.plugin.values.forEach((row) => {
50 if (!row.label) {
51 this.handleDeleteConditon(row);
52 }
53
54 row.condition.forEach((condition) => {
55 const error = (row.label && this.rowRules.condition(condition)) || {};
56 const existsError = !!Object.keys(error.result || {}).filter(elem => error.result[elem] === false).length;
57 if (existsError) {
58 this.expandAccordion && this.expandAccordion(row.uuid);
59 this.props.selectTabBlockConfig(this.props.flowUuid, 'CONDITIONS');
60 }
61 });
62 });
63 end();
64 });
65 }
66
67 componentDidMount() {
68 const newConditionSet = this.props.blockConfigs[this.props.flowUuid]
69 && this.props.blockConfigs[this.props.flowUuid].tab
70 && this.props.blockConfigs[this.props.flowUuid].tab.originOfTheClick === 'CLICK_ADD_CONDITIONSET_BLOCK';
71
72 if (newConditionSet) {
73 !this.didMoutActions && this.handleAddNewCondition();
74 this.didMoutActions = this.props.plugin.didMoutActions(this.handleAddNewCondition);
75 }
76 }
77
78 /**
79 * This function runs a given rule on the rowRules object.
80 *
81 * @param {string} column - The column to run rule for.
82 * @param {Object} row - The row ro run the rule
83 */
84 runRowRules(column, row) {
85 this.rowRules[column] && this.rowRules[column](row);
86 }
87
88 /**
89 * This function adds one new temporal rule to the condition row.
90 *
91 * @param {string} parentRowUuid - The condition row uuid.
92 * @param {Object} row - The new row.
93 */
94 handleOnAddTemporalCondition(parentRowUuid, row) {
95 this.props.plugin.addRow(row, {
96 parentRowKey: this.rowFieldNames.condition,
97 parentRowUuid,
98 });
99 }
100
101 /**
102 * This function edits one temporal rule on one condition row on the condition column
103 *
104 * @param {string} parentRowUuid - The condition row uuid.
105 * @param {any} value - The value to be updated.
106 * @param {string} temporalConditionUuid - The uuid of the value to be updated
107 */
108 handleOnEditTemporalCondition(parentRowUuid, value, temporalConditionUuid) {
109 this.props.plugin.editRow(temporalConditionUuid, this.rowFieldNames.condition, value, {
110 parentRowKey: this.rowFieldNames.condition,
111 parentRowUuid,
112 });
113
114 const newRow = { uuid: temporalConditionUuid, [this.rowFieldNames.condition]: value };
115 this.runRowRules(this.rowFieldNames.condition, newRow);
116 }
117
118 /**
119 * This funtion deletes one temporal rule from one given condition row.
120 *
121 * @param {string} parentRowUuid - The condition row uuid.
122 * @param {string} temporalConditionUuid - The uuid of the temporal conditon to be deleted
123 */
124 handleOnDeleteTemporalCondition(parentRowUuid, temporalConditionUuid) {
125 this.props.plugin.deleteRow(temporalConditionUuid, {
126 parentRowKey: this.rowFieldNames.condition,
127 parentRowUuid,
128 });
129 }
130
131 /**
132 * Handles the add of one new condition row.
133 */
134 handleAddNewCondition() {
135 const uuid = uuidV4();
136
137 this.rowUuidTest = uuid;
138 this.props.plugin.values.forEach((elem) => {
139 if (!elem.label) {
140 this.props.plugin.deleteRow(elem.uuid);
141 }
142 });
143
144 this.props.plugin.addRow({
145 uuid,
146 label: '',
147 condition: [{
148 uuid: uuidV4(),
149 condition: defaultCondition.message,
150 }],
151 action: '',
152 varOps: '',
153 playSsml: '',
154 continue: false,
155 }).then(() => {
156 this.empty = uuid;
157 this.expandAccordion(uuid);
158 this.scrollIntoView(uuid);
159
160 this.props.plugin.values.forEach((row) => {
161 if (row.uuid === uuid) {
162 return;
163 }
164 this.collapseAccordion(row.uuid);
165 });
166 });
167 }
168
169 /**
170 * Handle the change on one conditon set item.
171 *
172 * @param {string} column - The column key.
173 * @param {any} value - The value of the condition to edit.
174 * @param {Object} row - The coplete row where the conditon is.
175 */
176 handleEditCondition(column, value, row) {
177 if (this.rowUuidTest === row.uuid) {
178 this.rowUuidTest = '';
179 }
180 const newRow = { ...row, [column]: value };
181 this.runRowRules(column, newRow);
182 this.props.plugin.editRow(row.uuid, column, value);
183 }
184
185 /**
186 * Handle the full condition delete.
187 *
188 * @param {Object} condition - The condition to be deleted.
189 * @param {Object} condition.uuid - The condition uuid to be deleted
190 */
191 handleDeleteConditon(condition) {
192 this.props.plugin.deleteRow(condition.uuid);
193 }
194
195 /**
196 * This function is used to handle the value change in the action select.
197 *
198 * @param {string} uuid - String with the row uuid.
199 * @param {string} value - String with the selected value.
200 */
201 handleActionSelectOnChange(uuid, value) {
202 this.props.plugin.editRow(uuid, this.rowFieldNames.action, value);
203 }
204
205 /**
206 * This function is used to get the action select options with the respective ids and
207 * translated name.
208 *
209 * @returns {Object} - Object with the select options.
210 */
211 getSelectActionObject() {
212 const actionSelectOptions = Object.values(actionSelectOptionsIds);
213
214 return actionSelectOptions.map(option => ({
215 id: option,
216 name: this.props.translations[option],
217 }));
218 }
219
220 /**
221 * Builds the accordeons dataset based on the plugin
222 * data.
223 *
224 * @param {Object} datasource - The plugin datasource.
225 */
226 accordeons(datasource) {
227 const others = {
228 uuid: 'otherPeriods',
229 label: this.props.translations.groupTitles.label,
230 content: <OtherPeriods
231 title={this.props.translations.groupTitles.label}
232 placeholder={this.props.translations.groupTitles.otherPeriods}
233 />,
234 number: null,
235 };
236 return [others, ...datasource].map(row => ({
237 uuid: row.uuid,
238 top: row.label,
239 number: row.number,
240 content: row.content || (
241 <ConditionGroup
242 fieldNames={this.rowFieldNames}
243 handleChange={this.handleEditCondition}
244 validateStates={this.props.plugin.validationStates}
245 values={row}
246 titles={this.props.translations.groupTitles}
247 placeholders={this.props.translations.placeholders}
248 isTimeConditionSet={this.props.isTimeConditionSet}
249 // eslint-disable-next-line react/jsx-no-bind
250 onAddTemporalCondition={this.handleOnAddTemporalCondition.bind(this, row.uuid)}
251 // eslint-disable-next-line react/jsx-no-bind
252 onEditTemporalCondition={this.handleOnEditTemporalCondition.bind(this, row.uuid)}
253 // eslint-disable-next-line react/jsx-no-bind
254 onDeleteTemporalCondition={this.handleOnDeleteTemporalCondition.bind(this, row.uuid)}
255 // eslint-disable-next-line react/jsx-no-bind
256 onActionSelectChange={this.handleActionSelectOnChange.bind(this, row.uuid)}
257 actionSelectOptions={this.getSelectActionObject()}
258 />
259 ),
260 }));
261 }
262
263 /**
264 * Handle the onDrop the condition.
265 *
266 * @param {Object} fromRow - Object with row to move.
267 * @param {Object} toRow - Object with destination of the row.
268 */
269 handleOnDrop(fromRow, toRow) {
270 this.props.plugin.moveRow(fromRow.uuid, toRow.uuid);
271 }
272
273 /**
274 * Binds all the methods with this context.
275 */
276 bind() {
277 this.accordeons = this.accordeons.bind(this);
278
279 this.handleAddNewCondition = this.handleAddNewCondition.bind(this);
280 this.handleEditCondition = this.handleEditCondition.bind(this);
281 this.handleDeleteConditon = this.handleDeleteConditon.bind(this);
282
283 this.handleOnAddTemporalCondition = this.handleOnAddTemporalCondition.bind(this);
284 this.handleOnEditTemporalCondition = this.handleOnEditTemporalCondition.bind(this);
285 this.handleOnDeleteTemporalCondition = this.handleOnDeleteTemporalCondition.bind(this);
286 this.handleOnDrop = this.handleOnDrop.bind(this);
287 }
288
289 render() {
290 return (
291 <InputGroup
292 title={this.props.translations.title}
293 className="gof-blockCardForm-textTitles"
294 >
295 <Accordion
296 id="conditionset_accordion"
297 data={this.accordeons(this.props.plugin.values)}
298 onDelete={this.handleDeleteConditon}
299 onClickAdd={this.handleAddNewCondition}
300 onDrop={this.handleOnDrop}
301 interface={(int) => {
302 this.expandAccordion = int.expand;
303 this.collapseAccordion = int.collapse;
304 this.scrollIntoView = int.scrollIntoView;
305 }}
306 />
307 </InputGroup>
308 );
309 }
310}
311
312ConditionSet.propTypes = {
313 plugin: PropTypes.object.isRequired,
314 translations: PropTypes.object.isRequired,
315 isTimeConditionSet: PropTypes.bool,
316};
317
318ConditionSet.defaultProps = {
319 isTimeConditionSet: false,
320};
321
322const mapStateToProps = state => ({
323 blockConfigs: state.flowConstructorPage.blockConfig,
324});
325
326const mapDispatchToProps = dispatch => ({
327 selectTabBlockConfig: (flowUuid, tabId) => dispatch(selectTabBlockConfig(flowUuid, tabId)),
328});
329
330export default connect(mapStateToProps, mapDispatchToProps)(ConditionSet);