@inseefr/lunatic 3.6.5 → 3.6.7

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.
Files changed (69) hide show
  1. package/README.md +25 -0
  2. package/components/CheckboxGroup/CustomCheckboxGroup.d.ts +1 -1
  3. package/components/CheckboxGroup/CustomCheckboxGroup.js.map +1 -1
  4. package/components/Loop/Loop.d.ts +1 -1
  5. package/components/Loop/Loop.js +5 -27
  6. package/components/Loop/Loop.js.map +1 -1
  7. package/components/Loop/utils.d.ts +8 -0
  8. package/components/Loop/utils.js +65 -0
  9. package/components/Loop/utils.js.map +1 -0
  10. package/components/RosterForLoop/RosterForLoop.js +4 -27
  11. package/components/RosterForLoop/RosterForLoop.js.map +1 -1
  12. package/components/Roundabout/CustomRoundabout.js +2 -2
  13. package/components/Roundabout/CustomRoundabout.js.map +1 -1
  14. package/components/Roundabout/roundabout.spec.js +22 -0
  15. package/components/Roundabout/roundabout.spec.js.map +1 -1
  16. package/components/shared/Checkbox/CheckboxOption.d.ts +4 -2
  17. package/components/shared/Checkbox/CheckboxOption.js.map +1 -1
  18. package/components/shared/Radio/RadioGroup.d.ts +1 -1
  19. package/components/shared/Radio/RadioGroup.js.map +1 -1
  20. package/esm/components/CheckboxGroup/CustomCheckboxGroup.d.ts +1 -1
  21. package/esm/components/CheckboxGroup/CustomCheckboxGroup.js.map +1 -1
  22. package/esm/components/Loop/Loop.d.ts +1 -1
  23. package/esm/components/Loop/Loop.js +5 -28
  24. package/esm/components/Loop/Loop.js.map +1 -1
  25. package/esm/components/Loop/utils.d.ts +8 -0
  26. package/esm/components/Loop/utils.js +62 -0
  27. package/esm/components/Loop/utils.js.map +1 -0
  28. package/esm/components/RosterForLoop/RosterForLoop.js +5 -29
  29. package/esm/components/RosterForLoop/RosterForLoop.js.map +1 -1
  30. package/esm/components/Roundabout/CustomRoundabout.js +2 -2
  31. package/esm/components/Roundabout/CustomRoundabout.js.map +1 -1
  32. package/esm/components/Roundabout/roundabout.spec.js +22 -0
  33. package/esm/components/Roundabout/roundabout.spec.js.map +1 -1
  34. package/esm/components/shared/Checkbox/CheckboxOption.d.ts +4 -2
  35. package/esm/components/shared/Checkbox/CheckboxOption.js.map +1 -1
  36. package/esm/components/shared/Radio/RadioGroup.d.ts +1 -1
  37. package/esm/components/shared/Radio/RadioGroup.js.map +1 -1
  38. package/esm/use-lunatic/commons/compile-controls.js +33 -7
  39. package/esm/use-lunatic/commons/compile-controls.js.map +1 -1
  40. package/esm/use-lunatic/props/propIterations.js +12 -1
  41. package/esm/use-lunatic/props/propIterations.js.map +1 -1
  42. package/esm/use-lunatic/reducer/controls/check-base-control.js.map +1 -1
  43. package/package.json +16 -3
  44. package/src/components/CheckboxGroup/CustomCheckboxGroup.tsx +1 -0
  45. package/src/components/Loop/Loop.tsx +6 -35
  46. package/src/components/Loop/utils.test.ts +39 -0
  47. package/src/components/Loop/utils.ts +73 -0
  48. package/src/components/RosterForLoop/RosterForLoop.tsx +3 -33
  49. package/src/components/Roundabout/CustomRoundabout.tsx +11 -1
  50. package/src/components/Roundabout/roundabout.spec.tsx +38 -0
  51. package/src/components/shared/Checkbox/CheckboxOption.tsx +3 -2
  52. package/src/components/shared/Radio/RadioGroup.tsx +1 -0
  53. package/src/stories/behaviour/controls/controls.stories.tsx +12 -3
  54. package/src/stories/behaviour/controls/data-standalone-loop.json +17 -0
  55. package/src/stories/behaviour/controls/source-standalone-loop.json +5503 -0
  56. package/src/stories/loop/source-paginated.json +1 -1
  57. package/src/stories/roundabout/roundabout.stories.tsx +13 -0
  58. package/src/stories/roundabout/sourceWithControl.json +613 -0
  59. package/src/use-lunatic/commons/compile-controls.ts +60 -11
  60. package/src/use-lunatic/props/propIterations.ts +30 -15
  61. package/src/use-lunatic/reducer/controls/check-base-control.ts +0 -1
  62. package/src/use-lunatic/use-lunatic-bug.test.ts +42 -0
  63. package/tsconfig.build.tsbuildinfo +1 -1
  64. package/use-lunatic/commons/compile-controls.js +31 -7
  65. package/use-lunatic/commons/compile-controls.js.map +1 -1
  66. package/use-lunatic/props/propIterations.js +12 -1
  67. package/use-lunatic/props/propIterations.js.map +1 -1
  68. package/use-lunatic/reducer/controls/check-base-control.js.map +1 -1
  69. /package/src/stories/behaviour/controls/{source-loop.json → source-roster-for-loop.json} +0 -0
@@ -24,13 +24,28 @@ type InterpretedLoopComponent = DeepTranslateExpression<
24
24
  componentType: 'Loop' | 'RosterForLoop';
25
25
  }
26
26
  >;
27
+ type InterpretedRoundaboutComponent = DeepTranslateExpression<
28
+ ComponentDefinition & {
29
+ componentType: 'Roundabout';
30
+ }
31
+ >;
27
32
 
33
+ /**
34
+ * Check if the component is a Loop or a RosterForLoop
35
+ */
28
36
  const isLoopComponent = (
29
37
  component: ComponentDefinition | InterpretedComponent
30
38
  ): component is InterpretedLoopComponent => {
31
- return ['Loop', 'RosterForLoop', 'Roundabout'].includes(
32
- component.componentType
33
- );
39
+ return ['Loop', 'RosterForLoop'].includes(component.componentType);
40
+ };
41
+
42
+ /**
43
+ * Check if the component is a Roundabout
44
+ */
45
+ const isRoundaboutComponent = (
46
+ component: ComponentDefinition | InterpretedComponent
47
+ ): component is InterpretedRoundaboutComponent => {
48
+ return component.componentType === 'Roundabout';
34
49
  };
35
50
 
36
51
  const isQuestionComponent = (
@@ -63,7 +78,11 @@ function checkComponents(
63
78
  }
64
79
  }
65
80
 
66
- // For loop, inspect children
81
+ // For Loop and RosterForLoop, inspect iterations for row controls
82
+ if (isRoundaboutComponent(component))
83
+ errors = checkRoundabout(state, component, errors);
84
+
85
+ // For Loop and RosterForLoop, inspect children
67
86
  if (isLoopComponent(component))
68
87
  errors = checkLoop(state, component, errors);
69
88
 
@@ -75,6 +94,22 @@ function checkComponents(
75
94
  return errors;
76
95
  }
77
96
 
97
+ function checkRoundabout(
98
+ state: StateForControls,
99
+ component: InterpretedRoundaboutComponent,
100
+ errors: Record<string, LunaticError[]>
101
+ ) {
102
+ const rowControls = component.controls?.filter((c) => c.type === 'ROW');
103
+ if (rowControls?.length) {
104
+ errors = checkComponentInLoop(
105
+ state,
106
+ { ...component, controls: rowControls },
107
+ errors
108
+ );
109
+ }
110
+ return errors;
111
+ }
112
+
78
113
  function checkLoop(
79
114
  state: StateForControls,
80
115
  component: InterpretedLoopComponent,
@@ -101,14 +136,12 @@ function checkControls(
101
136
  ): LunaticError[] {
102
137
  return controls
103
138
  .map((control) => {
104
- switch (control.type) {
105
- case 'roundabout':
106
- return checkRoundaboutControl(control, executeExpression);
107
- default:
108
- return checkBaseControl(control, executeExpression, pager);
139
+ if (control.type === 'roundabout') {
140
+ return checkRoundaboutControl(control, executeExpression);
109
141
  }
142
+ return checkBaseControl(control, executeExpression, pager);
110
143
  })
111
- .filter((error) => error !== undefined) as LunaticError[];
144
+ .filter((error) => error !== undefined);
112
145
  }
113
146
 
114
147
  /**
@@ -152,7 +185,10 @@ function computeIterations(
152
185
  */
153
186
  function checkComponentInLoop(
154
187
  state: StateForControls,
155
- component: ComponentDefinition | InterpretedLoopComponent,
188
+ component:
189
+ | ComponentDefinition
190
+ | InterpretedLoopComponent
191
+ | InterpretedRoundaboutComponent,
156
192
  errors: Record<string, LunaticError[]>
157
193
  ): Record<string, LunaticError[]> {
158
194
  // For Question, loop over children
@@ -181,6 +217,19 @@ function checkComponentInLoop(
181
217
  if (!('controls' in component) || !component.controls) {
182
218
  continue;
183
219
  }
220
+
221
+ // For Roundabout, we don't check controls for iterations that are disabled
222
+ if (component.componentType === 'Roundabout' && component.item.disabled) {
223
+ const isIterationDisabled = state.executeExpression(
224
+ { value: component.item.disabled?.value, type: 'VTL' },
225
+ iterationPager
226
+ );
227
+
228
+ if (isIterationDisabled) {
229
+ continue;
230
+ }
231
+ }
232
+
184
233
  // The component is filtered on this iteration, skip it
185
234
  if (
186
235
  // conditionFilter can be the interpreted expression, or the object representing the expression
@@ -32,20 +32,35 @@ export function getIterationsProp(
32
32
 
33
33
  // Iterations expression is not present on the component definition
34
34
  // infer it from the value of child components
35
- return (definition.components as LunaticComponentDefinition[]).reduce(
36
- (acc, component) => {
37
- if (!hasResponse(component)) {
38
- return acc;
39
- }
40
- const value = state.variables.get(
41
- component.response.name,
42
- isNumber(state.pager.iteration) ? [state.pager.iteration] : undefined
43
- );
44
- if (Array.isArray(value) && value.length > acc) {
45
- return value.length;
46
- }
35
+
36
+ return getFlatComponentsInLoop(definition).reduce((acc, component) => {
37
+ if (!hasResponse(component)) {
47
38
  return acc;
48
- },
49
- 0
50
- );
39
+ }
40
+ const value = state.variables.get(
41
+ component.response.name,
42
+ isNumber(state.pager.iteration) ? [state.pager.iteration] : undefined
43
+ );
44
+ if (Array.isArray(value) && value.length > acc) {
45
+ return value.length;
46
+ }
47
+ return acc;
48
+ }, 0);
49
+ }
50
+
51
+ function getFlatComponentsInLoop(
52
+ definition: LunaticComponentDefinition
53
+ ): LunaticComponentDefinition[] {
54
+ if (
55
+ definition.componentType !== 'RosterForLoop' &&
56
+ definition.componentType !== 'Loop'
57
+ ) {
58
+ return [definition];
59
+ }
60
+
61
+ return definition.components.reduce((acc, component) => {
62
+ if (component.componentType === 'Question')
63
+ return [...acc, ...component.components];
64
+ return [...acc, component];
65
+ }, [] as LunaticComponentDefinition[]);
51
66
  }
@@ -21,7 +21,6 @@ export function checkBaseControl(
21
21
  const result = executeExpression(control, {
22
22
  iteration: linksIterations ?? iteration,
23
23
  });
24
-
25
24
  try {
26
25
  /**
27
26
  * Currently, the controls are lifted when the condition is false.
@@ -0,0 +1,42 @@
1
+ import { act, renderHook } from '@testing-library/react';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ import loopControlSource from '../stories/behaviour/controls/source-standalone-loop.json';
5
+ import surveyUnit from '../stories/behaviour/controls/data-standalone-loop.json';
6
+ import { useLunatic } from './use-lunatic';
7
+
8
+ describe('use-lunatic()', () => {
9
+ /**
10
+ * This test should be succeded after make some improvment
11
+ * See: comment above useEffect of src/components/Loop/utils.ts > useLoopUtils
12
+ */
13
+ it.skip('should compile errors correctly', () => {
14
+ const { result } = renderHook(() =>
15
+ useLunatic(loopControlSource, surveyUnit.data)
16
+ );
17
+ act(() => {
18
+ result.current.goToPage({ page: '3' });
19
+ });
20
+ const { currentErrors } = result.current.compileControls();
21
+ expect(currentErrors).not.toBeUndefined();
22
+ expect(Object.keys(currentErrors!).length).toEqual(6);
23
+ });
24
+ it('should compile errors correctly 2', () => {
25
+ const { result } = renderHook(() =>
26
+ useLunatic(loopControlSource, {
27
+ COLLECTED: {
28
+ PRES_SAL: { COLLECTED: ['1', null, '2', null, null, null] },
29
+ },
30
+ ...surveyUnit.data,
31
+ })
32
+ );
33
+ act(() => {
34
+ result.current.goToPage({ page: '3' });
35
+ });
36
+ act(() => {
37
+ const { currentErrors } = result.current.compileControls();
38
+ expect(currentErrors).not.toBeUndefined();
39
+ expect(Object.keys(currentErrors!).length).toEqual(4);
40
+ });
41
+ });
42
+ });