project-booster-vue 8.115.7 → 8.116.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/appointment/PbAppointmentStartSection.vue +0 -16
- package/src/components/question/PbQuestion.vue +12 -60
- package/src/components/question/dimensions-input/PbDimensionsInput.vue +5 -1
- package/src/components/question/list-select/PbListSelect.vue +9 -60
- package/src/components/question/space-input/PbSpaceInput.vue +5 -1
- package/src/components/question/upload-document/PbUploadDocument.vue +10 -61
- package/src/components/restitution/PbRestitution.vue +9 -34
- package/src/components/restitution/PbRestitutionBody.vue +2 -38
- package/src/components/scenario/PbScenario-Features-Skippable-Event.stories.mdx +325 -0
- package/src/components/scenario/PbScenario.vue +6 -38
- package/src/components/scenario/scenarii/appointment-qualification-kitchen.json +3 -0
- package/src/service/scenarioConditionals.js +44 -0
- package/src/store/modules/appointmentQualificationStore.js +1 -0
package/package.json
CHANGED
|
@@ -68,22 +68,6 @@ export default {
|
|
|
68
68
|
nextStep: null,
|
|
69
69
|
});
|
|
70
70
|
},
|
|
71
|
-
computeNextStep(nextStep) {
|
|
72
|
-
let resultingNextStep;
|
|
73
|
-
|
|
74
|
-
if (nextStep?.conditionals) {
|
|
75
|
-
for (const conditional of nextStep.conditionals) {
|
|
76
|
-
if (this.areConditionsValid(conditional.conditions)) {
|
|
77
|
-
resultingNextStep = this.computeNextStep(conditional.nextStep);
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
} else {
|
|
82
|
-
resultingNextStep = nextStep;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return resultingNextStep;
|
|
86
|
-
},
|
|
87
71
|
},
|
|
88
72
|
};
|
|
89
73
|
</script>
|
|
@@ -257,6 +257,7 @@ import MLink from '../mozaic/link/MLink';
|
|
|
257
257
|
import PbCard from '../cards/PbCard';
|
|
258
258
|
import PbStickyFooter from '../sticky-footer/PbStickyFooter';
|
|
259
259
|
import { sortAnswers } from './sortAnswers';
|
|
260
|
+
import { areConditionsValid } from '../../service/scenarioConditionals';
|
|
260
261
|
|
|
261
262
|
const BACK_ICON =
|
|
262
263
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
|
|
@@ -391,7 +392,7 @@ export default {
|
|
|
391
392
|
|
|
392
393
|
if (this.payload?.answers) {
|
|
393
394
|
this.displayableAnswers = Object.values(this.payload?.answers).filter((answer) => {
|
|
394
|
-
return
|
|
395
|
+
return areConditionsValid(answer.conditions, this.answers, this.runtimeOptions);
|
|
395
396
|
});
|
|
396
397
|
}
|
|
397
398
|
|
|
@@ -406,7 +407,7 @@ export default {
|
|
|
406
407
|
for (const answerCode in this.payload.answers) {
|
|
407
408
|
if (
|
|
408
409
|
this.payload.answers[answerCode].selected &&
|
|
409
|
-
|
|
410
|
+
areConditionsValid(this.payload.answers[answerCode].conditions, this.answers, this.runtimeOptions)
|
|
410
411
|
) {
|
|
411
412
|
this.selectedAnswers[answerCode] = true;
|
|
412
413
|
}
|
|
@@ -445,35 +446,14 @@ export default {
|
|
|
445
446
|
);
|
|
446
447
|
},
|
|
447
448
|
isShowingFooter(viewModel) {
|
|
448
|
-
return viewModel.footer &&
|
|
449
|
+
return viewModel.footer && areConditionsValid(viewModel.footer.conditions, this.answers, this.runtimeOptions);
|
|
449
450
|
},
|
|
450
|
-
areConditionsValid(conditions) {
|
|
451
|
-
let valid = true;
|
|
452
|
-
|
|
453
|
-
if (conditions) {
|
|
454
|
-
valid = false;
|
|
455
|
-
for (const condition of conditions) {
|
|
456
|
-
try {
|
|
457
|
-
let conditionValid = new Function(
|
|
458
|
-
'isAnswerMatching',
|
|
459
|
-
'isAnswerContaining',
|
|
460
|
-
'answers',
|
|
461
|
-
'runtimeOptions',
|
|
462
|
-
`return ${condition}`,
|
|
463
|
-
).call(this, this.isAnswerMatching, this.isAnswerContaining, this.answers, this.runtimeOptions);
|
|
464
|
-
|
|
465
|
-
valid = valid || conditionValid;
|
|
466
|
-
} catch (error) {
|
|
467
|
-
console.error(error);
|
|
468
|
-
valid = valid || true;
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
451
|
|
|
473
|
-
return valid;
|
|
474
|
-
},
|
|
475
452
|
isAnswerDisabled(answer) {
|
|
476
|
-
return
|
|
453
|
+
return (
|
|
454
|
+
answer.viewModel.disabled &&
|
|
455
|
+
areConditionsValid(answer.viewModel.disabled.conditions, this.answers, this.runtimeOptions)
|
|
456
|
+
);
|
|
477
457
|
},
|
|
478
458
|
selectAnswer(stepCode, answer) {
|
|
479
459
|
if (this.isAnswerDisabled(answer)) {
|
|
@@ -499,7 +479,7 @@ export default {
|
|
|
499
479
|
*/
|
|
500
480
|
this.$emit(this.completedEventName, {
|
|
501
481
|
answers: [answer],
|
|
502
|
-
nextStep:
|
|
482
|
+
nextStep: answer.nextStep,
|
|
503
483
|
});
|
|
504
484
|
}
|
|
505
485
|
|
|
@@ -527,18 +507,6 @@ export default {
|
|
|
527
507
|
|
|
528
508
|
return selectedAnswersNumber;
|
|
529
509
|
},
|
|
530
|
-
// Function used by the scenario conditions
|
|
531
|
-
isAnswerMatching(questionCode, answerCode) {
|
|
532
|
-
return this?.answers[questionCode] && this?.answers[questionCode][0]?.code === answerCode;
|
|
533
|
-
},
|
|
534
|
-
isAnswerContaining(questionCode, answerCode) {
|
|
535
|
-
return (
|
|
536
|
-
this?.answers[questionCode] &&
|
|
537
|
-
this?.answers[questionCode].findIndex((elt) => {
|
|
538
|
-
return elt.code === answerCode;
|
|
539
|
-
}) > -1
|
|
540
|
-
);
|
|
541
|
-
},
|
|
542
510
|
validMultiSelect(multiSelectOptions) {
|
|
543
511
|
const answers = [];
|
|
544
512
|
|
|
@@ -550,14 +518,14 @@ export default {
|
|
|
550
518
|
|
|
551
519
|
this.$emit(this.completedEventName, {
|
|
552
520
|
answers: answers,
|
|
553
|
-
nextStep:
|
|
521
|
+
nextStep: multiSelectOptions.nextStep,
|
|
554
522
|
});
|
|
555
523
|
},
|
|
556
524
|
skipQuestion(button) {
|
|
557
525
|
this.initAnswersSelectedState(this.payload.answers);
|
|
558
526
|
this.$emit(this.completedEventName, {
|
|
559
|
-
answers: button.defaultAnswer ? [button.defaultAnswer] : [],
|
|
560
|
-
nextStep:
|
|
527
|
+
answers: button.isAnswer ? (button.defaultAnswer ? [button.defaultAnswer] : []) : null,
|
|
528
|
+
nextStep: button.nextStep,
|
|
561
529
|
});
|
|
562
530
|
},
|
|
563
531
|
resetMultiSelect(multiSelectOptions, answers) {
|
|
@@ -569,22 +537,6 @@ export default {
|
|
|
569
537
|
answer.selected = false;
|
|
570
538
|
});
|
|
571
539
|
},
|
|
572
|
-
computeNextStep(nextStep) {
|
|
573
|
-
let resultingNextStep;
|
|
574
|
-
|
|
575
|
-
if (nextStep?.conditionals) {
|
|
576
|
-
for (const conditional of nextStep.conditionals) {
|
|
577
|
-
if (this.areConditionsValid(conditional.conditions)) {
|
|
578
|
-
resultingNextStep = this.computeNextStep(conditional.nextStep);
|
|
579
|
-
break;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
} else {
|
|
583
|
-
resultingNextStep = nextStep;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
return resultingNextStep;
|
|
587
|
-
},
|
|
588
540
|
handleShowMoreClick() {
|
|
589
541
|
this.activateShowMoreAnimation();
|
|
590
542
|
this.showMore();
|
|
@@ -282,7 +282,11 @@ export default {
|
|
|
282
282
|
* @type {Event}
|
|
283
283
|
*/
|
|
284
284
|
emit(props.completedEventName, {
|
|
285
|
-
answers: props.payload?.skippable?.
|
|
285
|
+
answers: props.payload?.skippable?.isAnswer
|
|
286
|
+
? props.payload?.skippable?.defaultAnswer
|
|
287
|
+
? [props.payload?.skippable?.defaultAnswer]
|
|
288
|
+
: []
|
|
289
|
+
: null,
|
|
286
290
|
nextStep: props.payload?.skippable?.nextStep,
|
|
287
291
|
});
|
|
288
292
|
};
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
@click="skipQuestion"
|
|
55
55
|
/>
|
|
56
56
|
<m-button
|
|
57
|
-
v-if="hasSelectedAnswers || payload.multiSelect
|
|
57
|
+
v-if="hasSelectedAnswers || payload.multiSelect?.alwaysDisplayMultiSelectButton"
|
|
58
58
|
class="pb-list-select__validate-button"
|
|
59
59
|
size="m"
|
|
60
60
|
size-from-l="l"
|
|
@@ -204,7 +204,7 @@ export default {
|
|
|
204
204
|
return props.payload?.viewModel?.showMore?.position ?? 'center';
|
|
205
205
|
});
|
|
206
206
|
|
|
207
|
-
//
|
|
207
|
+
// Submit
|
|
208
208
|
const validateButtonProps = computed(() => {
|
|
209
209
|
let label, leftIcon, rightIcon;
|
|
210
210
|
|
|
@@ -253,52 +253,10 @@ export default {
|
|
|
253
253
|
*/
|
|
254
254
|
emit(props.completedEventName, {
|
|
255
255
|
answers: answersToSubmit,
|
|
256
|
-
nextStep:
|
|
256
|
+
nextStep: nextStep,
|
|
257
257
|
});
|
|
258
258
|
};
|
|
259
259
|
|
|
260
|
-
// Scenario management
|
|
261
|
-
const areConditionsValid = (conditions) => {
|
|
262
|
-
let valid = true;
|
|
263
|
-
|
|
264
|
-
if (conditions) {
|
|
265
|
-
valid = false;
|
|
266
|
-
for (const condition of conditions) {
|
|
267
|
-
try {
|
|
268
|
-
let conditionValid = new Function(
|
|
269
|
-
'isAnswerMatching',
|
|
270
|
-
'isAnswerContaining',
|
|
271
|
-
'answers',
|
|
272
|
-
'runtimeOptions',
|
|
273
|
-
`return ${condition}`,
|
|
274
|
-
).call(this, isAnswerMatching, isAnswerContaining, props.answers, props.runtimeOptions);
|
|
275
|
-
|
|
276
|
-
valid = valid || conditionValid;
|
|
277
|
-
} catch (error) {
|
|
278
|
-
console.error(error);
|
|
279
|
-
valid = valid || true;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
return valid;
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
const computeNextStep = (nextStep) => {
|
|
287
|
-
let resultingNextStep;
|
|
288
|
-
|
|
289
|
-
if (nextStep?.conditionals) {
|
|
290
|
-
for (const conditional of nextStep.conditionals) {
|
|
291
|
-
if (areConditionsValid(conditional.conditions)) {
|
|
292
|
-
resultingNextStep = computeNextStep(conditional.nextStep);
|
|
293
|
-
break;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
} else {
|
|
297
|
-
resultingNextStep = nextStep;
|
|
298
|
-
}
|
|
299
|
-
return resultingNextStep;
|
|
300
|
-
};
|
|
301
|
-
|
|
302
260
|
const skipQuestion = () => {
|
|
303
261
|
/**
|
|
304
262
|
* Emitted when step is completed
|
|
@@ -306,8 +264,12 @@ export default {
|
|
|
306
264
|
* @type {Event}
|
|
307
265
|
*/
|
|
308
266
|
emit(props.completedEventName, {
|
|
309
|
-
answers: props.payload
|
|
310
|
-
|
|
267
|
+
answers: props.payload?.skippable?.isAnswer
|
|
268
|
+
? props.payload?.skippable?.defaultAnswer
|
|
269
|
+
? [props.payload?.skippable?.defaultAnswer]
|
|
270
|
+
: []
|
|
271
|
+
: null,
|
|
272
|
+
nextStep: props.payload?.skippable?.nextStep,
|
|
311
273
|
});
|
|
312
274
|
};
|
|
313
275
|
|
|
@@ -322,19 +284,6 @@ export default {
|
|
|
322
284
|
);
|
|
323
285
|
};
|
|
324
286
|
|
|
325
|
-
const isAnswerMatching = (questionCode, answerCode) => {
|
|
326
|
-
return props.answers[questionCode] && props.answers[questionCode][0]?.code === answerCode;
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
const isAnswerContaining = (questionCode, answerCode) => {
|
|
330
|
-
return (
|
|
331
|
-
props.answers[questionCode] &&
|
|
332
|
-
props.answers[questionCode].findIndex((elt) => {
|
|
333
|
-
return elt.code === answerCode;
|
|
334
|
-
}) > -1
|
|
335
|
-
);
|
|
336
|
-
};
|
|
337
|
-
|
|
338
287
|
const getAnswerValue = (answerCode, path) => {
|
|
339
288
|
if (!props.answers[answerCode] || props.answers[answerCode].length === 0) {
|
|
340
289
|
return null;
|
|
@@ -249,7 +249,11 @@ export default {
|
|
|
249
249
|
* @type {Event}
|
|
250
250
|
*/
|
|
251
251
|
emit(props.completedEventName, {
|
|
252
|
-
answers: props.payload?.skippable?.
|
|
252
|
+
answers: props.payload?.skippable?.isAnswer
|
|
253
|
+
? props.payload?.skippable?.defaultAnswer
|
|
254
|
+
? [props.payload?.skippable?.defaultAnswer]
|
|
255
|
+
: []
|
|
256
|
+
: null,
|
|
253
257
|
nextStep: props.payload?.skippable?.nextStep,
|
|
254
258
|
});
|
|
255
259
|
};
|
|
@@ -186,11 +186,10 @@ import MIcon from '../../mozaic/icon/MIcon';
|
|
|
186
186
|
import MImage from '../../mozaic/image/MImage';
|
|
187
187
|
import MLink from '../../mozaic/link/MLink';
|
|
188
188
|
import PbCard from '../../cards/PbCard';
|
|
189
|
-
import { sortAnswers } from '.././sortAnswers';
|
|
190
189
|
import MDialog from '../../mozaic/dialog/MDialog';
|
|
191
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
192
190
|
import PbUploadDocumentForm from './PbUploadDocumentForm';
|
|
193
191
|
import PbStickyFooter from '../../sticky-footer/PbStickyFooter';
|
|
192
|
+
import { areConditionsValid } from '../../../service/scenarioConditionals';
|
|
194
193
|
|
|
195
194
|
const BACK_ICON =
|
|
196
195
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
|
|
@@ -327,7 +326,7 @@ export default {
|
|
|
327
326
|
updateDefaultAnswers() {
|
|
328
327
|
if (this.payload?.answers) {
|
|
329
328
|
this.displayableAnswers = Object.values(this.payload?.answers).filter((answer) => {
|
|
330
|
-
return
|
|
329
|
+
return areConditionsValid(answer.conditions, this.answers, this.runtimeOptions) && !answer.selected;
|
|
331
330
|
});
|
|
332
331
|
Object.values(this.payload?.answers).map((answer) => {
|
|
333
332
|
let found = false;
|
|
@@ -371,42 +370,20 @@ export default {
|
|
|
371
370
|
);
|
|
372
371
|
},
|
|
373
372
|
isShowingFooter(viewModel) {
|
|
374
|
-
return viewModel.footer &&
|
|
375
|
-
},
|
|
376
|
-
areConditionsValid(conditions) {
|
|
377
|
-
let valid = true;
|
|
378
|
-
|
|
379
|
-
if (conditions) {
|
|
380
|
-
valid = false;
|
|
381
|
-
for (const condition of conditions) {
|
|
382
|
-
try {
|
|
383
|
-
let conditionValid = new Function(
|
|
384
|
-
'isAnswerMatching',
|
|
385
|
-
'isAnswerContaining',
|
|
386
|
-
'answers',
|
|
387
|
-
'runtimeOptions',
|
|
388
|
-
`return ${condition}`,
|
|
389
|
-
).call(this, this.isAnswerMatching, this.isAnswerContaining, this.answers, this.runtimeOptions);
|
|
390
|
-
|
|
391
|
-
valid = valid || conditionValid;
|
|
392
|
-
} catch (error) {
|
|
393
|
-
console.error(error);
|
|
394
|
-
valid = valid || true;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return valid;
|
|
373
|
+
return viewModel.footer && areConditionsValid(viewModel.footer.conditions, this.answers, this.runtimeOptions);
|
|
400
374
|
},
|
|
375
|
+
|
|
401
376
|
isAnswerDisabled(answer) {
|
|
402
|
-
return
|
|
377
|
+
return (
|
|
378
|
+
answer.viewModel.disabled &&
|
|
379
|
+
areConditionsValid(answer.viewModel.disabled.conditions, this.answers, this.runtimeOptions)
|
|
380
|
+
);
|
|
403
381
|
},
|
|
404
382
|
selectAnswer(stepCode, answer) {
|
|
405
383
|
if (answer.code === 'ADD_DOCUMENT') {
|
|
406
384
|
this.$refs.pbUploadDocumentForm.$refs.pbDocumentUploadFormInput.click();
|
|
407
385
|
}
|
|
408
386
|
},
|
|
409
|
-
// Function used by the scenario conditions
|
|
410
387
|
getAnswerValue(answerCode, path) {
|
|
411
388
|
if (!this.answers[answerCode] || this.answers[answerCode].length === 0) {
|
|
412
389
|
return null;
|
|
@@ -414,28 +391,16 @@ export default {
|
|
|
414
391
|
|
|
415
392
|
return objectPath.get(this.answers[answerCode][0], path);
|
|
416
393
|
},
|
|
417
|
-
// Function used by the scenario conditions
|
|
418
|
-
isAnswerMatching(questionCode, answerCode) {
|
|
419
|
-
return this?.answers[questionCode] && this?.answers[questionCode][0]?.code === answerCode;
|
|
420
|
-
},
|
|
421
|
-
isAnswerContaining(questionCode, answerCode) {
|
|
422
|
-
return (
|
|
423
|
-
this?.answers[questionCode] &&
|
|
424
|
-
this?.answers[questionCode].findIndex((elt) => {
|
|
425
|
-
return elt.code === answerCode;
|
|
426
|
-
}) > -1
|
|
427
|
-
);
|
|
428
|
-
},
|
|
429
394
|
validMultiSelect(multiSelectOptions) {
|
|
430
395
|
this.$emit(this.completedEventName, {
|
|
431
396
|
answers: this.selectedDocuments,
|
|
432
|
-
nextStep:
|
|
397
|
+
nextStep: multiSelectOptions.nextStep,
|
|
433
398
|
});
|
|
434
399
|
},
|
|
435
400
|
skipQuestion(button) {
|
|
436
401
|
this.$emit(this.completedEventName, {
|
|
437
402
|
answers: this.selectedDocuments,
|
|
438
|
-
nextStep:
|
|
403
|
+
nextStep: button.nextStep,
|
|
439
404
|
});
|
|
440
405
|
},
|
|
441
406
|
resetMultiSelect(multiSelectOptions, answers) {
|
|
@@ -450,22 +415,6 @@ export default {
|
|
|
450
415
|
answer.selected = false;
|
|
451
416
|
});
|
|
452
417
|
},
|
|
453
|
-
computeNextStep(nextStep) {
|
|
454
|
-
let resultingNextStep;
|
|
455
|
-
|
|
456
|
-
if (nextStep?.conditionals) {
|
|
457
|
-
for (const conditional of nextStep.conditionals) {
|
|
458
|
-
if (this.areConditionsValid(conditional.conditions)) {
|
|
459
|
-
resultingNextStep = this.computeNextStep(conditional.nextStep);
|
|
460
|
-
break;
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
} else {
|
|
464
|
-
resultingNextStep = nextStep;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
return resultingNextStep;
|
|
468
|
-
},
|
|
469
418
|
handleShowMoreClick() {
|
|
470
419
|
this.activateShowMoreAnimation();
|
|
471
420
|
this.showMore();
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
:class="`pb-restitution pb-restitution--${componentTheme}`"
|
|
5
5
|
align-items="center"
|
|
6
6
|
direction="column"
|
|
7
|
-
:style="`min-height: ${
|
|
7
|
+
:style="`min-height: ${restitutionMinHeight};`"
|
|
8
8
|
ref="pbRestitution"
|
|
9
9
|
>
|
|
10
10
|
<m-link
|
|
@@ -78,6 +78,7 @@ import PbRestitutionBody from './PbRestitutionBody';
|
|
|
78
78
|
import PbProgressionPrice from '../progression-price/PbProgressionPrice';
|
|
79
79
|
import PbProjectItemSave from '../project-item-save/PbProjectItemSave';
|
|
80
80
|
import PbRestitutionExit from './PbRestitutionExit';
|
|
81
|
+
import { areConditionsValid } from '../../service/scenarioConditionals';
|
|
81
82
|
|
|
82
83
|
const BACK_ICON =
|
|
83
84
|
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_16px.svg';
|
|
@@ -165,6 +166,7 @@ export default {
|
|
|
165
166
|
notifications: [],
|
|
166
167
|
displayDialog: false,
|
|
167
168
|
dialogViewModel: null,
|
|
169
|
+
restitutionMinHeight: '100vh',
|
|
168
170
|
}),
|
|
169
171
|
|
|
170
172
|
computed: {
|
|
@@ -184,7 +186,7 @@ export default {
|
|
|
184
186
|
options: [],
|
|
185
187
|
};
|
|
186
188
|
formattedExitOptions.options = this.payload?.exitOptions?.options?.filter(
|
|
187
|
-
(option) => !option.conditions ||
|
|
189
|
+
(option) => !option.conditions || areConditionsValid(option.conditions, this.answers, this.runtimeOptions),
|
|
188
190
|
);
|
|
189
191
|
return formattedExitOptions;
|
|
190
192
|
},
|
|
@@ -200,7 +202,7 @@ export default {
|
|
|
200
202
|
if (this.payload?.callToActions) {
|
|
201
203
|
const saveAction = Object.values(this.payload.callToActions).find((cta) => {
|
|
202
204
|
return (
|
|
203
|
-
|
|
205
|
+
areConditionsValid(cta.conditions, this.answers, this.runtimeOptions) &&
|
|
204
206
|
cta.action?.type === 'MODAL' &&
|
|
205
207
|
cta.action?.component === 'PbProjectItemSave'
|
|
206
208
|
);
|
|
@@ -208,6 +210,9 @@ export default {
|
|
|
208
210
|
this.projectSaveItemPayload = saveAction ? saveAction.payload : {};
|
|
209
211
|
this.showSaveProjectItem = this.showSaveEstimate;
|
|
210
212
|
}
|
|
213
|
+
setTimeout(() => {
|
|
214
|
+
this.restitutionMinHeight = this.payload?.exitOptions ? 'auto' : this.minHeight;
|
|
215
|
+
}, 300);
|
|
211
216
|
},
|
|
212
217
|
|
|
213
218
|
mounted() {
|
|
@@ -219,41 +224,11 @@ export default {
|
|
|
219
224
|
updateDisplayedCta() {
|
|
220
225
|
if (this.payload?.callToActions) {
|
|
221
226
|
this.displayedCta = Object.values(this.payload.callToActions).filter((cta) => {
|
|
222
|
-
return
|
|
227
|
+
return areConditionsValid(cta.conditions, this.answers, this.runtimeOptions);
|
|
223
228
|
});
|
|
224
229
|
}
|
|
225
230
|
},
|
|
226
231
|
|
|
227
|
-
areConditionsValid(conditions) {
|
|
228
|
-
let valid = true;
|
|
229
|
-
|
|
230
|
-
if (conditions) {
|
|
231
|
-
valid = false;
|
|
232
|
-
for (const condition of conditions) {
|
|
233
|
-
try {
|
|
234
|
-
valid =
|
|
235
|
-
valid ||
|
|
236
|
-
new Function('isAnswerMatching', 'answers', 'runtimeOptions', `return ${condition}`).call(
|
|
237
|
-
this,
|
|
238
|
-
this.isAnswerMatching,
|
|
239
|
-
this.answers,
|
|
240
|
-
this.runtimeOptions,
|
|
241
|
-
);
|
|
242
|
-
} catch (error) {
|
|
243
|
-
console.error(error);
|
|
244
|
-
valid = valid || true;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return valid;
|
|
250
|
-
},
|
|
251
|
-
|
|
252
|
-
// Function used by the scenario conditions
|
|
253
|
-
isAnswerMatching(questionCode, answerCode) {
|
|
254
|
-
return this?.answers[questionCode] && this?.answers[questionCode][0]?.code === answerCode;
|
|
255
|
-
},
|
|
256
|
-
|
|
257
232
|
callAction(action) {
|
|
258
233
|
if (action.type === 'MODAL') {
|
|
259
234
|
if (action.component === 'PbProjectItemSave') {
|
|
@@ -72,6 +72,7 @@ import MLink from '../mozaic/link/MLink';
|
|
|
72
72
|
import { priceFormatter } from '../../service/priceFormatter';
|
|
73
73
|
import PbRestitutionBlock from './PbRestitutionBlock';
|
|
74
74
|
import MNotification from '../mozaic/notifications/MNotification';
|
|
75
|
+
import { areConditionsValid } from '../../service/scenarioConditionals';
|
|
75
76
|
|
|
76
77
|
export default {
|
|
77
78
|
name: 'PbRestitutionBody',
|
|
@@ -186,44 +187,7 @@ export default {
|
|
|
186
187
|
},
|
|
187
188
|
|
|
188
189
|
areConditionsValid(conditions) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (conditions) {
|
|
192
|
-
valid = false;
|
|
193
|
-
for (const condition of conditions) {
|
|
194
|
-
try {
|
|
195
|
-
let conditionValid = new Function(
|
|
196
|
-
'isAnswerMatching',
|
|
197
|
-
'isAnswerContaining',
|
|
198
|
-
'answers',
|
|
199
|
-
'runtimeOptions',
|
|
200
|
-
`return ${condition}`,
|
|
201
|
-
).call(this, this.isAnswerMatching, this.isAnswerContaining, this.answers, this.runtimeOptions);
|
|
202
|
-
|
|
203
|
-
valid = valid || conditionValid;
|
|
204
|
-
} catch (error) {
|
|
205
|
-
console.error(error);
|
|
206
|
-
valid = valid || true;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return valid;
|
|
212
|
-
},
|
|
213
|
-
|
|
214
|
-
// Function used by the scenario conditions
|
|
215
|
-
isAnswerMatching(questionCode, answerCode) {
|
|
216
|
-
return this?.answers && this?.answers[questionCode] && this?.answers[questionCode][0]?.code === answerCode;
|
|
217
|
-
},
|
|
218
|
-
|
|
219
|
-
isAnswerContaining(questionCode, answerCode) {
|
|
220
|
-
return (
|
|
221
|
-
this?.answers &&
|
|
222
|
-
this?.answers[questionCode] &&
|
|
223
|
-
this?.answers[questionCode].findIndex((elt) => {
|
|
224
|
-
return elt.code === answerCode;
|
|
225
|
-
}) > -1
|
|
226
|
-
);
|
|
190
|
+
return areConditionsValid(conditions, this.answers, this.runtimeOptions);
|
|
227
191
|
},
|
|
228
192
|
},
|
|
229
193
|
};
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { nestedAppDecorator } from '../../../.storybook/nested-app-decorator';
|
|
2
|
+
import { Anchor, Story, Preview, Meta, Props, ArgsTable, Source, Canvas } from '@storybook/addon-docs';
|
|
3
|
+
import PbScenario from './PbScenario';
|
|
4
|
+
import DEFAULT_PAYLOAD from './default-payload.json';
|
|
5
|
+
import { TemplateSandbox } from './PbScenario.stories.mdx';
|
|
6
|
+
|
|
7
|
+
<Meta
|
|
8
|
+
title="Project Booster/Scenario/ 🦠 PbScenario/Features/skippable answers"
|
|
9
|
+
component={PbScenario}
|
|
10
|
+
argTypes={{
|
|
11
|
+
scenarios: {
|
|
12
|
+
table: {
|
|
13
|
+
defaultValue: {
|
|
14
|
+
summary: 'object',
|
|
15
|
+
detail: JSON.stringify(DEFAULT_PAYLOAD, null, ' '),
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
control: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
onScenarioCompleted: {
|
|
23
|
+
action: 'Scenario completed',
|
|
24
|
+
table: { disable: true },
|
|
25
|
+
},
|
|
26
|
+
onScenarioEvent: {
|
|
27
|
+
action: 'Scenario event occured',
|
|
28
|
+
table: { disable: true },
|
|
29
|
+
},
|
|
30
|
+
}}
|
|
31
|
+
decorators={[nestedAppDecorator({}, [{ path: '/steps/:stepCode/previous/:answers', component: PbScenario }])]}
|
|
32
|
+
parameters={{
|
|
33
|
+
layout: 'fullscreen',
|
|
34
|
+
}}
|
|
35
|
+
/>
|
|
36
|
+
|
|
37
|
+
<Anchor storyId="project-booster-scenario-pbscenario-features--skippable-scenario" />
|
|
38
|
+
|
|
39
|
+
## Skippable with answer
|
|
40
|
+
|
|
41
|
+
Conditions can be applied to next steps:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"skippable": [
|
|
46
|
+
"isAnswer":true,
|
|
47
|
+
{
|
|
48
|
+
"label": "Skip"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
When the isAnswer is true the step-completed sended and the state history updated
|
|
55
|
+
|
|
56
|
+
export const skippableEventWithDefaultAnswerPayload = {
|
|
57
|
+
'__START__': {
|
|
58
|
+
code: '__START__',
|
|
59
|
+
type: 'SCENARIO',
|
|
60
|
+
stepCode: 'MAIN_SCENARIO',
|
|
61
|
+
},
|
|
62
|
+
'MAIN_SCENARIO': {
|
|
63
|
+
code: 'MAIN_SCENARIO',
|
|
64
|
+
type: 'SCENARIO',
|
|
65
|
+
stepCode: 'SCENARIO-1',
|
|
66
|
+
},
|
|
67
|
+
'SCENARIO-1': {
|
|
68
|
+
code: 'SCENARIO-1',
|
|
69
|
+
type: 'STEP',
|
|
70
|
+
component: 'PbQuestion',
|
|
71
|
+
payload: {
|
|
72
|
+
skippable: {
|
|
73
|
+
isAnswer: true,
|
|
74
|
+
defaultAnswer: {
|
|
75
|
+
code: 'NONE',
|
|
76
|
+
value: 'NONE',
|
|
77
|
+
},
|
|
78
|
+
label: 'Skip',
|
|
79
|
+
theme: 'bordered',
|
|
80
|
+
rightIcon:
|
|
81
|
+
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Right_24px.svg',
|
|
82
|
+
leftIcon:
|
|
83
|
+
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_24px.svg',
|
|
84
|
+
nextStep: {
|
|
85
|
+
code: '__END__',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
viewModel: {
|
|
89
|
+
label: 'The question title',
|
|
90
|
+
answersComponent: 'PbCard',
|
|
91
|
+
},
|
|
92
|
+
answers: {
|
|
93
|
+
'ANSWER-1': {
|
|
94
|
+
code: 'ANSWER-1',
|
|
95
|
+
viewModel: {
|
|
96
|
+
title: 'Answer 1',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
'ANSWER-2': {
|
|
100
|
+
code: 'ANSWER-2',
|
|
101
|
+
viewModel: {
|
|
102
|
+
title: 'Answer 2',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
'ANSWER-3': {
|
|
106
|
+
code: 'ANSWER-3',
|
|
107
|
+
viewModel: {
|
|
108
|
+
title: 'Answer 3',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
'ANSWER-4': {
|
|
112
|
+
code: 'ANSWER-4',
|
|
113
|
+
viewModel: {
|
|
114
|
+
title: 'Answer 4',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
nextStep: {
|
|
120
|
+
code: '__END__',
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
'__END__': {
|
|
124
|
+
code: '__END__',
|
|
125
|
+
type: 'STEP',
|
|
126
|
+
component: 'PbQuestion',
|
|
127
|
+
payload: {
|
|
128
|
+
viewModel: {
|
|
129
|
+
label: 'Fin',
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
<Source language="json" code={JSON.stringify(skippableEventWithDefaultAnswerPayload, null, ' ')} />
|
|
136
|
+
|
|
137
|
+
<Canvas>
|
|
138
|
+
<Story
|
|
139
|
+
name="Skippable event with default answer"
|
|
140
|
+
inline={false}
|
|
141
|
+
height="862px"
|
|
142
|
+
parameters={{ controls: { disable: true } }}
|
|
143
|
+
args={{ scenarios: skippableEventWithDefaultAnswerPayload, minHeight: '120vh' }}
|
|
144
|
+
>
|
|
145
|
+
{TemplateSandbox.bind({})}
|
|
146
|
+
</Story>
|
|
147
|
+
</Canvas>
|
|
148
|
+
|
|
149
|
+
export const skippableWithoutEventQuestionPayload = {
|
|
150
|
+
'__START__': {
|
|
151
|
+
code: '__START__',
|
|
152
|
+
type: 'SCENARIO',
|
|
153
|
+
stepCode: 'MAIN_SCENARIO',
|
|
154
|
+
},
|
|
155
|
+
'MAIN_SCENARIO': {
|
|
156
|
+
code: 'MAIN_SCENARIO',
|
|
157
|
+
type: 'SCENARIO',
|
|
158
|
+
stepCode: 'SCENARIO-1',
|
|
159
|
+
},
|
|
160
|
+
'SCENARIO-1': {
|
|
161
|
+
code: 'SCENARIO-1',
|
|
162
|
+
type: 'STEP',
|
|
163
|
+
component: 'PbQuestion',
|
|
164
|
+
payload: {
|
|
165
|
+
skippable: {
|
|
166
|
+
isAnswer: false,
|
|
167
|
+
label: 'Skip',
|
|
168
|
+
theme: 'bordered',
|
|
169
|
+
rightIcon:
|
|
170
|
+
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Right_24px.svg',
|
|
171
|
+
leftIcon:
|
|
172
|
+
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_24px.svg',
|
|
173
|
+
nextStep: {
|
|
174
|
+
code: '__END__',
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
viewModel: {
|
|
178
|
+
label: 'The question title',
|
|
179
|
+
answersComponent: 'PbCard',
|
|
180
|
+
},
|
|
181
|
+
answers: {
|
|
182
|
+
'ANSWER-1': {
|
|
183
|
+
code: 'ANSWER-1',
|
|
184
|
+
viewModel: {
|
|
185
|
+
title: 'Answer 1',
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
'ANSWER-2': {
|
|
189
|
+
code: 'ANSWER-2',
|
|
190
|
+
viewModel: {
|
|
191
|
+
title: 'Answer 2',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
'ANSWER-3': {
|
|
195
|
+
code: 'ANSWER-3',
|
|
196
|
+
viewModel: {
|
|
197
|
+
title: 'Answer 3',
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
'ANSWER-4': {
|
|
201
|
+
code: 'ANSWER-4',
|
|
202
|
+
viewModel: {
|
|
203
|
+
title: 'Answer 4',
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
nextStep: {
|
|
209
|
+
code: '__END__',
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
'__END__': {
|
|
213
|
+
code: '__END__',
|
|
214
|
+
type: 'STEP',
|
|
215
|
+
component: 'PbQuestion',
|
|
216
|
+
payload: {
|
|
217
|
+
viewModel: {
|
|
218
|
+
label: 'Fin',
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
<Source language="json" code={JSON.stringify(skippableWithoutEventQuestionPayload, null, ' ')} />
|
|
225
|
+
|
|
226
|
+
<Canvas>
|
|
227
|
+
<Story
|
|
228
|
+
name="Skippable without event"
|
|
229
|
+
inline={false}
|
|
230
|
+
height="862px"
|
|
231
|
+
parameters={{ controls: { disable: true } }}
|
|
232
|
+
args={{ scenarios: skippableWithoutEventQuestionPayload, minHeight: '120vh' }}
|
|
233
|
+
>
|
|
234
|
+
{TemplateSandbox.bind({})}
|
|
235
|
+
</Story>
|
|
236
|
+
</Canvas>
|
|
237
|
+
|
|
238
|
+
export const skippableEventWithEmptyArrayPayload = {
|
|
239
|
+
'__START__': {
|
|
240
|
+
code: '__START__',
|
|
241
|
+
type: 'SCENARIO',
|
|
242
|
+
stepCode: 'MAIN_SCENARIO',
|
|
243
|
+
},
|
|
244
|
+
'MAIN_SCENARIO': {
|
|
245
|
+
code: 'MAIN_SCENARIO',
|
|
246
|
+
type: 'SCENARIO',
|
|
247
|
+
stepCode: 'SCENARIO-1',
|
|
248
|
+
},
|
|
249
|
+
'SCENARIO-1': {
|
|
250
|
+
code: 'SCENARIO-1',
|
|
251
|
+
type: 'STEP',
|
|
252
|
+
component: 'PbQuestion',
|
|
253
|
+
payload: {
|
|
254
|
+
skippable: {
|
|
255
|
+
isAnswer: true,
|
|
256
|
+
label: 'Skip',
|
|
257
|
+
theme: 'bordered',
|
|
258
|
+
rightIcon:
|
|
259
|
+
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Right_24px.svg',
|
|
260
|
+
leftIcon:
|
|
261
|
+
'https://storage.googleapis.com/project-booster-media/mozaic-icons/svg/Navigation_Arrow_Arrow--Left_24px.svg',
|
|
262
|
+
nextStep: {
|
|
263
|
+
code: '__END__',
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
viewModel: {
|
|
267
|
+
label: 'The question title',
|
|
268
|
+
answersComponent: 'PbCard',
|
|
269
|
+
},
|
|
270
|
+
answers: {
|
|
271
|
+
'ANSWER-1': {
|
|
272
|
+
code: 'ANSWER-1',
|
|
273
|
+
viewModel: {
|
|
274
|
+
title: 'Answer 1',
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
'ANSWER-2': {
|
|
278
|
+
code: 'ANSWER-2',
|
|
279
|
+
viewModel: {
|
|
280
|
+
title: 'Answer 2',
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
'ANSWER-3': {
|
|
284
|
+
code: 'ANSWER-3',
|
|
285
|
+
viewModel: {
|
|
286
|
+
title: 'Answer 3',
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
'ANSWER-4': {
|
|
290
|
+
code: 'ANSWER-4',
|
|
291
|
+
viewModel: {
|
|
292
|
+
title: 'Answer 4',
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
nextStep: {
|
|
298
|
+
code: '__END__',
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
'__END__': {
|
|
302
|
+
code: '__END__',
|
|
303
|
+
type: 'STEP',
|
|
304
|
+
component: 'PbQuestion',
|
|
305
|
+
payload: {
|
|
306
|
+
viewModel: {
|
|
307
|
+
label: 'Fin',
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
<Source language="json" code={JSON.stringify(skippableEventWithEmptyArrayPayload, null, ' ')} />
|
|
314
|
+
|
|
315
|
+
<Canvas>
|
|
316
|
+
<Story
|
|
317
|
+
name="Skippable event with empty array"
|
|
318
|
+
inline={false}
|
|
319
|
+
height="862px"
|
|
320
|
+
parameters={{ controls: { disable: true } }}
|
|
321
|
+
args={{ scenarios: skippableEventWithEmptyArrayPayload, minHeight: '120vh' }}
|
|
322
|
+
>
|
|
323
|
+
{TemplateSandbox.bind({})}
|
|
324
|
+
</Story>
|
|
325
|
+
</Canvas>
|
|
@@ -89,6 +89,7 @@ import PbRestitution from '../restitution/PbRestitution';
|
|
|
89
89
|
import PbSmartProgressionPrice from '../progression-price/PbSmartProgressionPrice';
|
|
90
90
|
import PbSpaceInput from '../question/space-input/PbSpaceInput';
|
|
91
91
|
import PbUploadDocument from '../question/upload-document/PbUploadDocument';
|
|
92
|
+
import { areConditionsValid } from '../../service/scenarioConditionals';
|
|
92
93
|
|
|
93
94
|
export default {
|
|
94
95
|
name: 'PbScenario',
|
|
@@ -301,8 +302,10 @@ export default {
|
|
|
301
302
|
};
|
|
302
303
|
const handleStepCompleted = ({ answers, nextStep }) => {
|
|
303
304
|
disablePointerEvents();
|
|
304
|
-
|
|
305
|
-
|
|
305
|
+
if (answers) {
|
|
306
|
+
state.value.answers[state.value.displayedStep.code] = answers;
|
|
307
|
+
emitEventToPipeline('STEP-COMPLETED', answers);
|
|
308
|
+
}
|
|
306
309
|
|
|
307
310
|
if (!nextStep) {
|
|
308
311
|
nextStep = state.value.displayedStep?.nextStep;
|
|
@@ -444,7 +447,7 @@ export default {
|
|
|
444
447
|
|
|
445
448
|
if (nextStep?.conditionals) {
|
|
446
449
|
for (const conditional of nextStep.conditionals) {
|
|
447
|
-
if (areConditionsValid(conditional.conditions)) {
|
|
450
|
+
if (areConditionsValid(conditional.conditions, state.value.answers, props.runtimeOptions)) {
|
|
448
451
|
resultingNextStep = computeNextStep(conditional.nextStep);
|
|
449
452
|
break;
|
|
450
453
|
}
|
|
@@ -455,42 +458,7 @@ export default {
|
|
|
455
458
|
|
|
456
459
|
return resultingNextStep;
|
|
457
460
|
};
|
|
458
|
-
const areConditionsValid = (conditions) => {
|
|
459
|
-
let valid = true;
|
|
460
|
-
|
|
461
|
-
if (conditions) {
|
|
462
|
-
valid = false;
|
|
463
|
-
for (const condition of conditions) {
|
|
464
|
-
valid =
|
|
465
|
-
valid ||
|
|
466
|
-
new Function(
|
|
467
|
-
'isAnswerMatching',
|
|
468
|
-
'isAnswerContaining',
|
|
469
|
-
'answers',
|
|
470
|
-
'runtimeOptions',
|
|
471
|
-
`return ${condition}`,
|
|
472
|
-
).call(this, isAnswerMatching, isAnswerContaining, state.value.answers, props.runtimeOptions);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
461
|
|
|
476
|
-
return valid;
|
|
477
|
-
};
|
|
478
|
-
// Function used by the scenario conditions
|
|
479
|
-
const isAnswerMatching = (questionCode, answerCode) => {
|
|
480
|
-
return (
|
|
481
|
-
state.value.answers[questionCode] &&
|
|
482
|
-
state.value.answers[questionCode][0] &&
|
|
483
|
-
state.value.answers[questionCode][0].code === answerCode
|
|
484
|
-
);
|
|
485
|
-
};
|
|
486
|
-
const isAnswerContaining = (questionCode, answerCode) => {
|
|
487
|
-
return (
|
|
488
|
-
state.value.answers[questionCode] &&
|
|
489
|
-
state.value.answers[questionCode].findIndex((elt) => {
|
|
490
|
-
return elt.code === answerCode;
|
|
491
|
-
}) > -1
|
|
492
|
-
);
|
|
493
|
-
};
|
|
494
462
|
const stepAnimationName = () => {
|
|
495
463
|
const componentName = state.value.currentStep?.component;
|
|
496
464
|
let animationName = 'pb-scenario__step--slide';
|
|
@@ -295,6 +295,7 @@
|
|
|
295
295
|
},
|
|
296
296
|
"skippable": [
|
|
297
297
|
{
|
|
298
|
+
"isAnswer": true,
|
|
298
299
|
"label": "Ajouter un plan plus tard",
|
|
299
300
|
"theme": "text-primary",
|
|
300
301
|
"width": "full",
|
|
@@ -304,6 +305,7 @@
|
|
|
304
305
|
}
|
|
305
306
|
},
|
|
306
307
|
{
|
|
308
|
+
"isAnswer": true,
|
|
307
309
|
"label": "Ajouter un plan",
|
|
308
310
|
"theme": "solid",
|
|
309
311
|
"width": "full",
|
|
@@ -403,6 +405,7 @@
|
|
|
403
405
|
},
|
|
404
406
|
"skippable": [
|
|
405
407
|
{
|
|
408
|
+
"isAnswer": true,
|
|
406
409
|
"label": "Ajouter un plan plus tard",
|
|
407
410
|
"theme": "text-primary",
|
|
408
411
|
"width": "full",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
function Condition(answers, runtimeOptions, condition) {
|
|
2
|
+
this.answers = answers;
|
|
3
|
+
this.runtimeOptions = runtimeOptions;
|
|
4
|
+
this.condition = condition;
|
|
5
|
+
|
|
6
|
+
this.isAnswerMatching = (questionCode, answerCode) => {
|
|
7
|
+
return this.answers[questionCode] && this.answers[questionCode][0]?.code === answerCode;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
this.isAnswerContaining = (questionCode, answerCode) => {
|
|
11
|
+
return (
|
|
12
|
+
this.answers[questionCode] &&
|
|
13
|
+
this.answers[questionCode].findIndex((elt) => {
|
|
14
|
+
return elt.code === answerCode;
|
|
15
|
+
}) > -1
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
this.isValid = new Function(
|
|
20
|
+
'isAnswerMatching',
|
|
21
|
+
'isAnswerContaining',
|
|
22
|
+
'answers',
|
|
23
|
+
'runtimeOptions',
|
|
24
|
+
`return ${condition}`,
|
|
25
|
+
).call(this, this.isAnswerMatching, this.isAnswerContaining, this.answers, this.runtimeOptions);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const areConditionsValid = (conditions, answers, runtimeOptions) => {
|
|
29
|
+
let valid = true;
|
|
30
|
+
|
|
31
|
+
if (conditions) {
|
|
32
|
+
valid = false;
|
|
33
|
+
for (const condition of conditions) {
|
|
34
|
+
try {
|
|
35
|
+
valid = valid || new Condition(answers, runtimeOptions, condition).isValid;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error(error);
|
|
38
|
+
valid = valid || true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return valid;
|
|
44
|
+
};
|