@inseefr/lunatic 0.3.2-experimental → 0.3.3-experimental

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.
@@ -79,7 +79,7 @@ const paginated = storiesOf('Questionnaire/Paginated', module).addDecorator(
79
79
  );
80
80
 
81
81
  paginated.addWithJSX('Calculated Variables', () => (
82
- <OrchestratorSplit
82
+ <Orchestrator
83
83
  id="props"
84
84
  source={calcVar}
85
85
  missing={boolean('Missing', false)}
@@ -157,7 +157,7 @@ paginated.addWithJSX('Logement - S2', () => (
157
157
  ));
158
158
 
159
159
  paginated.addWithJSX('Simpsons', () => (
160
- <OrchestratorSplit
160
+ <Orchestrator
161
161
  id="props"
162
162
  source={simpsons}
163
163
  missing={boolean('Missing', false)}
@@ -6,14 +6,16 @@ function getStoreInfoRequired() {
6
6
  return {};
7
7
  }
8
8
 
9
+ const defaultFeatures = ['VTL'];
10
+
9
11
  const OrchestratorForStories = ({
10
12
  source,
11
13
  suggesters,
12
- data = {},
14
+ data,
13
15
  management = false,
14
16
  pagination = false,
15
17
  modalForControls = false,
16
- features = ['VTL'],
18
+ features = defaultFeatures,
17
19
  bindings: initialBindings,
18
20
  initialPage = '1',
19
21
  getStoreInfo = getStoreInfoRequired,
@@ -6,14 +6,16 @@ function getStoreInfoRequired() {
6
6
  return {};
7
7
  }
8
8
 
9
+ const defaultFeatures = ['VTL'];
10
+
9
11
  const OrchestratorForStories = ({
10
12
  source,
11
13
  suggesters,
12
- data = {},
14
+ data,
13
15
  management = false,
14
16
  pagination = false,
15
17
  modalForControls = false,
16
- features = ['VTL'],
18
+ features = defaultFeatures,
17
19
  bindings: initialBindings,
18
20
  initialPage = '1',
19
21
  getStoreInfo = getStoreInfoRequired,
@@ -1,158 +1,158 @@
1
- {
2
- "components": [
3
- { "id": "1", "componentType": "Sequence", "depth": 1 },
4
- {
5
- "id": "2",
6
- "componentType": "Input",
7
- "response": {
8
- "name": "inputOk",
9
- "values": {
10
- "PREVIOUS": null,
11
- "COLLECTED": "My input",
12
- "FORCED": null,
13
- "EDITED": "My new input",
14
- "INPUTED": null
15
- }
16
- },
17
- "depth": 1
18
- },
19
- {
20
- "id": "3",
21
- "componentType": "CheckboxGroup",
22
- "responses": [
23
- {
24
- "response": {
25
- "name": "check1",
26
- "values": {
27
- "PREVIOUS": null,
28
- "COLLECTED": true,
29
- "FORCED": null,
30
- "EDITED": null,
31
- "INPUTED": null
32
- }
33
- }
34
- },
35
- {
36
- "response": {
37
- "name": "check2",
38
- "values": {
39
- "PREVIOUS": null,
40
- "COLLECTED": false,
41
- "FORCED": true,
42
- "EDITED": null,
43
- "INPUTED": null
44
- }
45
- }
46
- }
47
- ],
48
- "depth": 1
49
- },
50
- {
51
- "id": "4",
52
- "componentType": "Table",
53
- "cells": [
54
- [
55
- { "label": "label", "depth": 1 },
56
- {
57
- "componentType": "Radio",
58
- "response": {
59
- "name": "table11",
60
- "values": {
61
- "PREVIOUS": null,
62
- "COLLECTED": "1",
63
- "FORCED": null,
64
- "EDITED": null,
65
- "INPUTED": null
66
- }
67
- },
68
- "depth": 1
69
- }
70
- ]
71
- ],
72
- "depth": 1
73
- },
74
- {
75
- "id": "5",
76
- "componentType": "RosterForLoop",
77
- "components": [
78
- {
79
- "componentType": "Input",
80
- "response": {
81
- "name": "Roster",
82
- "values": {
83
- "PREVIOUS": [null],
84
- "COLLECTED": ["ok"],
85
- "FORCED": [null],
86
- "EDITED": [null],
87
- "INPUTED": [null]
88
- }
89
- },
90
- "depth": 2
91
- }
92
- ],
93
- "depth": 1
94
- }
95
- ],
96
- "variables": {
97
- "EXTERNAL": { "VAR_EXTERNAL": "Value VAR_EXTERNAL" },
98
- "CALCULATED": {
99
- "Test": {
100
- "expression": "inputOk || \" ok\"",
101
- "value": "My new input ok",
102
- "bindingDependencies": ["inputOk"]
103
- }
104
- },
105
- "COLLECTED": {
106
- "inputOk": {
107
- "componentRef": "2",
108
- "values": {
109
- "PREVIOUS": null,
110
- "COLLECTED": "My input",
111
- "FORCED": null,
112
- "EDITED": "My new input",
113
- "INPUTED": null
114
- }
115
- },
116
- "check1": {
117
- "componentRef": "3",
118
- "values": {
119
- "PREVIOUS": null,
120
- "COLLECTED": true,
121
- "FORCED": null,
122
- "EDITED": null,
123
- "INPUTED": null
124
- }
125
- },
126
- "check2": {
127
- "componentRef": "3",
128
- "values": {
129
- "PREVIOUS": null,
130
- "COLLECTED": false,
131
- "FORCED": true,
132
- "EDITED": null,
133
- "INPUTED": null
134
- }
135
- },
136
- "table11": {
137
- "componentRef": "4",
138
- "values": {
139
- "PREVIOUS": null,
140
- "COLLECTED": "1",
141
- "FORCED": null,
142
- "EDITED": null,
143
- "INPUTED": null
144
- }
145
- },
146
- "Roster": {
147
- "componentRef": "5",
148
- "values": {
149
- "PREVIOUS": [null],
150
- "COLLECTED": ["ok"],
151
- "FORCED": [null],
152
- "EDITED": [null],
153
- "INPUTED": [null]
154
- }
155
- }
156
- }
157
- }
158
- }
1
+ {
2
+ "components": [
3
+ { "id": "1", "componentType": "Sequence", "depth": 1 },
4
+ {
5
+ "id": "2",
6
+ "componentType": "Input",
7
+ "response": {
8
+ "name": "inputOk",
9
+ "values": {
10
+ "PREVIOUS": null,
11
+ "COLLECTED": "My input",
12
+ "FORCED": null,
13
+ "EDITED": "My new input",
14
+ "INPUTED": null
15
+ }
16
+ },
17
+ "depth": 1
18
+ },
19
+ {
20
+ "id": "3",
21
+ "componentType": "CheckboxGroup",
22
+ "responses": [
23
+ {
24
+ "response": {
25
+ "name": "check1",
26
+ "values": {
27
+ "PREVIOUS": null,
28
+ "COLLECTED": true,
29
+ "FORCED": null,
30
+ "EDITED": null,
31
+ "INPUTED": null
32
+ }
33
+ }
34
+ },
35
+ {
36
+ "response": {
37
+ "name": "check2",
38
+ "values": {
39
+ "PREVIOUS": null,
40
+ "COLLECTED": false,
41
+ "FORCED": true,
42
+ "EDITED": null,
43
+ "INPUTED": null
44
+ }
45
+ }
46
+ }
47
+ ],
48
+ "depth": 1
49
+ },
50
+ {
51
+ "id": "4",
52
+ "componentType": "Table",
53
+ "cells": [
54
+ [
55
+ { "label": "label", "depth": 1 },
56
+ {
57
+ "componentType": "Radio",
58
+ "response": {
59
+ "name": "table11",
60
+ "values": {
61
+ "PREVIOUS": null,
62
+ "COLLECTED": "1",
63
+ "FORCED": null,
64
+ "EDITED": null,
65
+ "INPUTED": null
66
+ }
67
+ },
68
+ "depth": 1
69
+ }
70
+ ]
71
+ ],
72
+ "depth": 1
73
+ },
74
+ {
75
+ "id": "5",
76
+ "componentType": "RosterForLoop",
77
+ "components": [
78
+ {
79
+ "componentType": "Input",
80
+ "response": {
81
+ "name": "Roster",
82
+ "values": {
83
+ "PREVIOUS": [null],
84
+ "COLLECTED": ["ok"],
85
+ "FORCED": [null],
86
+ "EDITED": [null],
87
+ "INPUTED": [null]
88
+ }
89
+ },
90
+ "depth": 2
91
+ }
92
+ ],
93
+ "depth": 1
94
+ }
95
+ ],
96
+ "variables": {
97
+ "EXTERNAL": { "VAR_EXTERNAL": "Value VAR_EXTERNAL" },
98
+ "CALCULATED": {
99
+ "Test": {
100
+ "expression": "inputOk || \" ok\"",
101
+ "value": "My new input ok",
102
+ "bindingDependencies": ["inputOk"]
103
+ }
104
+ },
105
+ "COLLECTED": {
106
+ "inputOk": {
107
+ "componentRef": "2",
108
+ "values": {
109
+ "PREVIOUS": null,
110
+ "COLLECTED": "My input",
111
+ "FORCED": null,
112
+ "EDITED": "My new input",
113
+ "INPUTED": null
114
+ }
115
+ },
116
+ "check1": {
117
+ "componentRef": "3",
118
+ "values": {
119
+ "PREVIOUS": null,
120
+ "COLLECTED": true,
121
+ "FORCED": null,
122
+ "EDITED": null,
123
+ "INPUTED": null
124
+ }
125
+ },
126
+ "check2": {
127
+ "componentRef": "3",
128
+ "values": {
129
+ "PREVIOUS": null,
130
+ "COLLECTED": false,
131
+ "FORCED": true,
132
+ "EDITED": null,
133
+ "INPUTED": null
134
+ }
135
+ },
136
+ "table11": {
137
+ "componentRef": "4",
138
+ "values": {
139
+ "PREVIOUS": null,
140
+ "COLLECTED": "1",
141
+ "FORCED": null,
142
+ "EDITED": null,
143
+ "INPUTED": null
144
+ }
145
+ },
146
+ "Roster": {
147
+ "componentRef": "5",
148
+ "values": {
149
+ "PREVIOUS": [null],
150
+ "COLLECTED": ["ok"],
151
+ "FORCED": [null],
152
+ "EDITED": [null],
153
+ "INPUTED": [null]
154
+ }
155
+ }
156
+ }
157
+ }
158
+ }
@@ -1,16 +1,12 @@
1
1
  const getBindingsDependenciesCalculated = (variables) => {
2
2
  if (!variables) return {};
3
- return variables.reduce(
4
- (acc, { variableType, name, bindingDependencies, shapeFrom }) => {
5
- if (variableType === 'CALCULATED')
6
- if (shapeFrom && bindingDependencies)
7
- return { ...acc, [name]: [...bindingDependencies, shapeFrom] };
8
- if (bindingDependencies) return { ...acc, [name]: bindingDependencies };
9
- if (shapeFrom) return { ...acc, [name]: [shapeFrom] };
10
- return acc;
11
- },
12
- {}
13
- );
3
+ return variables.reduce((acc, { name, bindingDependencies, shapeFrom }) => {
4
+ if (shapeFrom && bindingDependencies)
5
+ return { ...acc, [name]: [...bindingDependencies, shapeFrom] };
6
+ if (bindingDependencies) return { ...acc, [name]: bindingDependencies };
7
+ if (shapeFrom) return { ...acc, [name]: [shapeFrom] };
8
+ return acc;
9
+ }, {});
14
10
  };
15
11
 
16
12
  const getAllDeps = (deps) => (variablesCalcDeps) => {
@@ -24,20 +20,51 @@ const getAllDeps = (deps) => (variablesCalcDeps) => {
24
20
  }, []);
25
21
  };
26
22
 
23
+ const getNestedVarsInFilterOrControl = (element) => {
24
+ if (element && Array.isArray(element?.bindingDependencies))
25
+ return element?.bindingDependencies;
26
+ return [];
27
+ };
28
+
29
+ const getNestedVarsInComponent = (component) => {
30
+ const {
31
+ componentType,
32
+ bindingDependencies = [],
33
+ conditionFilter,
34
+ controls = [],
35
+ } = component;
36
+ var bindings = [
37
+ ...bindingDependencies, // bindingDependencies of Component
38
+ ...getNestedVarsInFilterOrControl(conditionFilter), // bindingDependencies of its conditionFilter
39
+ ...controls.reduce(
40
+ (acc, c) => [...acc, ...getNestedVarsInFilterOrControl(c)],
41
+ []
42
+ ), // bindingDependencies of its controls
43
+ ];
44
+
45
+ if (componentType === 'Loop') {
46
+ const { components, loopDependencies } = component;
47
+ if (Array.isArray(loopDependencies))
48
+ bindings = [...bindings, ...loopDependencies];
49
+ if (Array.isArray(components)) {
50
+ bindings = components.reduce(
51
+ (acc, c) => [...acc, ...getNestedVarsInComponent(c)],
52
+ [...bindings]
53
+ );
54
+ }
55
+ }
56
+
57
+ return bindings;
58
+ };
59
+
27
60
  const getNestedVars =
28
61
  (components = []) =>
29
62
  (variables) => {
30
63
  const variableCalculatedDependencies =
31
64
  getBindingsDependenciesCalculated(variables);
32
65
  const depsVarsTemp = components
33
- .reduce((acc, comp) => {
34
- const { bindingDependencies, conditionFilter } = comp;
35
- var superBind = [];
36
- if (Array.isArray(bindingDependencies))
37
- superBind = [...superBind, ...bindingDependencies];
38
- if (Array.isArray(conditionFilter?.bindingDependencies))
39
- superBind = [...superBind, ...conditionFilter.bindingDependencies];
40
- return [...acc, ...superBind];
66
+ .reduce((acc, c) => {
67
+ return [...acc, ...getNestedVarsInComponent(c)];
41
68
  }, [])
42
69
  .filter((v, i, a) => a.indexOf(v) === i);
43
70
  return getAllDeps(depsVarsTemp)(variableCalculatedDependencies).filter(
@@ -46,7 +73,6 @@ const getNestedVars =
46
73
  };
47
74
 
48
75
  const getUsefullVariablesFromSource = (variables) => (nestedVars) => {
49
- if (!variables) return true;
50
76
  return variables.filter(({ variableType, name }) => {
51
77
  if (variableType === 'CALCULATED' && !nestedVars.includes(name))
52
78
  return false;
@@ -60,18 +86,24 @@ export const getSplitQuestionnaireSource = (source) => {
60
86
  const { components, variables, ...rest } = source;
61
87
  var split = [];
62
88
  var currentComponents = [];
63
- components.map((c, i) => {
64
- const { componentType } = c;
89
+ var previousPage = null;
90
+ components.map((c) => {
91
+ const { componentType, page } = c;
65
92
  // splitting by Sequence or Loop
66
- if (componentType === 'Sequence' || componentType === 'Loop') {
93
+ if (
94
+ (componentType === 'Sequence' || componentType === 'Loop') &&
95
+ previousPage !== page
96
+ ) {
67
97
  if (currentComponents.length > 0) split.push(currentComponents);
68
98
  currentComponents = [c];
69
99
  } else {
70
100
  currentComponents.push(c);
71
101
  }
102
+ previousPage = page;
72
103
  return null;
73
104
  });
74
105
  if (currentComponents.length > 0) split.push(currentComponents);
106
+
75
107
  return split.reduce((prev, currentSource) => {
76
108
  const firstPage = currentSource[0].page;
77
109
  const maxPage = currentSource[currentSource.length - 1].page;
@@ -17,13 +17,17 @@ import { useFilterComponents } from './filter-components';
17
17
  import { loadSuggesters } from '../../store-tools/auto-load';
18
18
  import { getCollectedStateByValueType, getState } from '..';
19
19
 
20
+ const defaultData = {};
21
+ const defaultPreferences = [COLLECTED];
22
+ const defaultFeatures = ['VTL'];
23
+
20
24
  const useLunaticSplit = (
21
25
  source,
22
- data,
26
+ data = defaultData,
23
27
  {
24
28
  savingType = COLLECTED,
25
- preferences = [COLLECTED],
26
- features = ['VTL'],
29
+ preferences = defaultPreferences,
30
+ features = defaultFeatures,
27
31
  management = false,
28
32
  pagination = false,
29
33
  modalForControls = false,
@@ -38,37 +42,48 @@ const useLunaticSplit = (
38
42
  console.log('useLunaticSplit');
39
43
  var start = new Date().getTime();
40
44
  }
45
+ const fullQuestionnaire = useMemo(
46
+ () => mergeQuestionnaireAndData(source)(data),
47
+ [source, data]
48
+ );
41
49
  const sources = useMemo(() => getSplitQuestionnaireSource(source), [source]);
50
+ const allData = useMemo(
51
+ () => getState(fullQuestionnaire),
52
+ [fullQuestionnaire]
53
+ );
54
+ const [allBindings, setAllBindings] = useState(() =>
55
+ getBindings(fullQuestionnaire)
56
+ );
57
+
42
58
  const rootPagesOfSource = useMemo(
43
59
  () => getRootPageInSources(sources),
44
60
  [sources]
45
61
  );
46
62
 
47
- const [sourceIndice, setSourceIndice] = useState(0);
48
- const [lunaticData, setLunaticData] = useState(data || {});
63
+ const [sourceIndex, setSourceIndex] = useState(0);
64
+ const [lunaticData, setLunaticData] = useState(allData);
49
65
 
50
66
  const [initPage, setInitPage] = useState(false);
51
67
  const featuresWithoutMD = features.filter((f) => f !== 'MD');
52
68
 
53
69
  const [questionnaire, setQuestionnaire] = useState(() =>
54
- mergeQuestionnaireAndData(sources[sourceIndice])(lunaticData)
70
+ mergeQuestionnaireAndData(sources[sourceIndex])(lunaticData)
55
71
  );
56
72
  const [bindings, setBindings] = useState(() => getBindings(questionnaire));
57
- const [allBindings, setAllBindings] = useState(bindings);
58
73
 
59
74
  const [wantedPage, setWantedPage] = useState(null);
60
75
 
61
76
  // updating current source
62
77
  useEffect(() => {
63
78
  setInitPage(false);
64
- const newQ = mergeQuestionnaireAndData(sources[sourceIndice])(lunaticData);
79
+ const newQ = mergeQuestionnaireAndData(sources[sourceIndex])(lunaticData);
65
80
  setQuestionnaire(newQ);
66
81
  const bind = getBindings(newQ);
67
82
  setBindings(bind);
68
83
  setAllBindings({ ...allBindings, ...bind });
69
84
 
70
85
  // eslint-disable-next-line react-hooks/exhaustive-deps
71
- }, [sources, sourceIndice]);
86
+ }, [sources, sourceIndex]);
72
87
 
73
88
  const getBindingsSplit = (quest) => {
74
89
  const bind = getBindings(quest);
@@ -141,14 +156,14 @@ const useLunaticSplit = (
141
156
 
142
157
  const isFirstPage = page === firstPage;
143
158
  const isLastPage = page === maxPage;
144
- const isFirstSource = sourceIndice === 0;
145
- const isLastSource = sourceIndice === sources.length - 1;
159
+ const isFirstSource = sourceIndex === 0;
160
+ const isLastSource = sourceIndex === sources.length - 1;
146
161
 
147
162
  const goSplitNext = () => {
148
163
  if (!isLastSource) {
149
164
  const stateData = getState(questionnaire);
150
165
  setLunaticData(mergeStateData(lunaticData, stateData));
151
- setSourceIndice(sourceIndice + 1);
166
+ setSourceIndex(sourceIndex + 1);
152
167
  }
153
168
  };
154
169
 
@@ -189,7 +204,7 @@ const useLunaticSplit = (
189
204
  if (!isFirstSource) {
190
205
  const stateData = getState(questionnaire);
191
206
  setLunaticData(mergeStateData(lunaticData, stateData));
192
- setSourceIndice(sourceIndice - 1);
207
+ setSourceIndex(sourceIndex - 1);
193
208
  }
194
209
  };
195
210
 
@@ -233,7 +248,7 @@ const useLunaticSplit = (
233
248
  (newPage) => {
234
249
  const p = newPage?.split('.')[0];
235
250
  const index = rootPagesOfSource.findIndex((pages) => pages.includes(p));
236
- if (index === sourceIndice) {
251
+ if (index === sourceIndex) {
237
252
  setPage(newPage);
238
253
  setWantedPage(null);
239
254
  } else {
@@ -241,10 +256,10 @@ const useLunaticSplit = (
241
256
  setWantedPage(newPage);
242
257
  const stateData = getState(questionnaire);
243
258
  setLunaticData(mergeStateData(lunaticData, stateData));
244
- setSourceIndice(index);
259
+ setSourceIndex(index);
245
260
  }
246
261
  },
247
- [lunaticData, questionnaire, rootPagesOfSource, sourceIndice]
262
+ [lunaticData, questionnaire, rootPagesOfSource, sourceIndex]
248
263
  );
249
264
 
250
265
  useEffect(() => {
@@ -252,13 +267,12 @@ const useLunaticSplit = (
252
267
  if (wantedPage) {
253
268
  setPage(wantedPage);
254
269
  setWantedPage(null);
255
- setInitPage(true);
256
270
  } else {
257
271
  const getNewInitPage = () => {
258
272
  if (flow === FLOW_NEXT) {
259
273
  const tempPage =
260
- sourceIndice - 1 > 0
261
- ? sources[sourceIndice - 1].maxPage
274
+ sourceIndex - 1 > 0
275
+ ? sources[sourceIndex - 1].maxPage
262
276
  : sources[0].maxPage;
263
277
  return getPage({
264
278
  components: questionnaire.components,
@@ -270,8 +284,8 @@ const useLunaticSplit = (
270
284
  });
271
285
  } else if (flow === FLOW_PREVIOUS) {
272
286
  const tempPage =
273
- sourceIndice + 1 < sources.length - 1
274
- ? sources[sourceIndice + 1].firstPage
287
+ sourceIndex + 1 < sources.length - 1
288
+ ? sources[sourceIndex + 1].firstPage
275
289
  : sources[sources.length - 1].firstPage;
276
290
  return getPage({
277
291
  components: questionnaire.components,
@@ -289,12 +303,12 @@ const useLunaticSplit = (
289
303
  else {
290
304
  const newPage = getNewInitPage();
291
305
  if (!newPage) {
292
- if (flow === FLOW_NEXT) setSourceIndice(sourceIndice + 1);
293
- else setSourceIndice(sourceIndice - 1);
306
+ if (flow === FLOW_NEXT) setSourceIndex(sourceIndex + 1);
307
+ else setSourceIndex(sourceIndex - 1);
294
308
  } else setPage(newPage);
295
309
  }
296
- setInitPage(true);
297
310
  }
311
+ setInitPage(true);
298
312
  }
299
313
  }, [
300
314
  initPage,
@@ -305,7 +319,7 @@ const useLunaticSplit = (
305
319
  page,
306
320
  featuresWithoutMD,
307
321
  management,
308
- sourceIndice,
322
+ sourceIndex,
309
323
  sources,
310
324
  flow,
311
325
  wantedPage,
@@ -13,13 +13,17 @@ import { COLLECTED } from '../../../constants';
13
13
  import { useFilterComponents } from './filter-components';
14
14
  import { loadSuggesters } from '../../store-tools/auto-load';
15
15
 
16
+ const defaultData = {};
17
+ const defaultPreferences = [COLLECTED];
18
+ const defaultFeatures = ['VTL'];
19
+
16
20
  const useLunatic = (
17
21
  source,
18
- data,
22
+ data = defaultData,
19
23
  {
20
24
  savingType = COLLECTED,
21
- preferences = [COLLECTED],
22
- features = ['VTL'],
25
+ preferences = defaultPreferences,
26
+ features = defaultFeatures,
23
27
  management = false,
24
28
  pagination = false,
25
29
  modalForControls = false,