@inseefr/lunatic 3.13.6-rc-fix-multimode.2 → 3.14.0-rc-delay-sequence-cleaning.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.
Files changed (56) hide show
  1. package/components/Duration/getDurationFromValue.d.ts +2 -2
  2. package/components/Duration/getDurationFromValue.js +7 -6
  3. package/components/Duration/getDurationFromValue.js.map +1 -1
  4. package/components/Suggester/SuggesterType.d.ts +3 -1
  5. package/components/shared/Combobox/ComboboxType.d.ts +2 -0
  6. package/esm/components/Duration/getDurationFromValue.d.ts +2 -2
  7. package/esm/components/Duration/getDurationFromValue.js +7 -6
  8. package/esm/components/Duration/getDurationFromValue.js.map +1 -1
  9. package/esm/components/Suggester/SuggesterType.d.ts +3 -1
  10. package/esm/components/shared/Combobox/ComboboxType.d.ts +2 -0
  11. package/esm/use-lunatic/commons/compile-controls.d.ts +5 -0
  12. package/esm/use-lunatic/commons/compile-controls.js +6 -1
  13. package/esm/use-lunatic/commons/compile-controls.js.map +1 -1
  14. package/esm/use-lunatic/commons/compile-controls.spec.d.ts +1 -0
  15. package/esm/use-lunatic/commons/compile-controls.spec.js +121 -0
  16. package/esm/use-lunatic/commons/compile-controls.spec.js.map +1 -0
  17. package/esm/use-lunatic/reducer/reducerInitializer.js +1 -1
  18. package/esm/use-lunatic/reducer/reducerInitializer.js.map +1 -1
  19. package/esm/utils/search/SearchInterface.d.ts +9 -1
  20. package/esm/utils/search/melauto.d.ts +4 -1
  21. package/esm/utils/search/melauto.js +17 -17
  22. package/esm/utils/search/melauto.js.map +1 -1
  23. package/esm/utils/search/melauto.spec.js +9 -13
  24. package/esm/utils/search/melauto.spec.js.map +1 -1
  25. package/package.json +13 -1
  26. package/src/components/Duration/getDurationFromValue.ts +10 -6
  27. package/src/components/Suggester/SuggesterType.ts +3 -1
  28. package/src/components/shared/Combobox/ComboboxType.ts +2 -0
  29. package/src/stories/behaviour/cleaning/cleaning.stories.tsx +7 -0
  30. package/src/stories/behaviour/cleaning/source-sequence.json +444 -0
  31. package/src/stories/behaviour/search/search.stories.tsx +258 -0
  32. package/src/stories/questionnaires/SRCV/data.json +116 -0
  33. package/src/stories/questionnaires/SRCV/source.json +69256 -0
  34. package/src/stories/questionnaires/SRCV/srcv.stories.tsx +23 -0
  35. package/src/use-lunatic/commons/compile-controls.spec.ts +136 -0
  36. package/src/use-lunatic/commons/compile-controls.ts +7 -1
  37. package/src/use-lunatic/reducer/reducerInitializer.tsx +1 -1
  38. package/src/use-lunatic/use-lunatic.test.ts +6 -2
  39. package/src/utils/search/SearchInterface.ts +10 -1
  40. package/src/utils/search/melauto.spec.ts +10 -13
  41. package/src/utils/search/melauto.ts +20 -13
  42. package/tsconfig.build.tsbuildinfo +1 -1
  43. package/use-lunatic/commons/compile-controls.d.ts +5 -0
  44. package/use-lunatic/commons/compile-controls.js +6 -0
  45. package/use-lunatic/commons/compile-controls.js.map +1 -1
  46. package/use-lunatic/commons/compile-controls.spec.d.ts +1 -0
  47. package/use-lunatic/commons/compile-controls.spec.js +123 -0
  48. package/use-lunatic/commons/compile-controls.spec.js.map +1 -0
  49. package/use-lunatic/reducer/reducerInitializer.js +1 -1
  50. package/use-lunatic/reducer/reducerInitializer.js.map +1 -1
  51. package/utils/search/SearchInterface.d.ts +9 -1
  52. package/utils/search/melauto.d.ts +4 -1
  53. package/utils/search/melauto.js +11 -14
  54. package/utils/search/melauto.js.map +1 -1
  55. package/utils/search/melauto.spec.js +9 -13
  56. package/utils/search/melauto.spec.js.map +1 -1
@@ -0,0 +1,258 @@
1
+ import classNames from 'classnames';
2
+ import {
3
+ Orchestrator,
4
+ OrchestratorMeta,
5
+ type OrchestratorStory,
6
+ } from '../../utils/Orchestrator';
7
+ import D from '../../../i18n';
8
+
9
+ import { ComboboxOptionType } from '../../../components/shared/Combobox/ComboboxType';
10
+
11
+ import { Meta } from '@storybook/react';
12
+ import {
13
+ type ComponentProps,
14
+ type FormEventHandler,
15
+ useCallback,
16
+ useMemo,
17
+ useState,
18
+ } from 'react';
19
+ import { LunaticSource } from '../../../type.source';
20
+ import { useLocalStorage } from '../../../hooks/useLocalStorage';
21
+
22
+ type Props = {
23
+ option: ComboboxOptionType;
24
+ shouldDisplayOptionId?: boolean;
25
+ selected?: boolean;
26
+ };
27
+ const CustomComboboxOption = ({
28
+ option,
29
+ shouldDisplayOptionId = true,
30
+ selected,
31
+ }: Props) => {
32
+ const { id, value, label, score, melautoScore } = option;
33
+
34
+ const scoreValues = (
35
+ <span>{` [ Score: ${score} | MelautoScore: ${melautoScore} ] `}</span>
36
+ );
37
+
38
+ if (value === 'OTHER') {
39
+ return (
40
+ <div className={classNames('lunatic-combo-box-option', { selected })}>
41
+ <span className="label">
42
+ {`${D.SUGGESTER_NO_RESULT} : ${D.SUGGESTER_ARBITRARY} "${label}"`}
43
+ </span>
44
+ </div>
45
+ );
46
+ }
47
+ if (label) {
48
+ return (
49
+ <div className={classNames('lunatic-combo-box-option', { selected })}>
50
+ {shouldDisplayOptionId && (
51
+ <>
52
+ <span className="id">{id || value}</span>
53
+ <span> - </span>
54
+ </>
55
+ )}
56
+ <span className="label">{label}</span>
57
+ {scoreValues}
58
+ </div>
59
+ );
60
+ }
61
+ return (
62
+ <div className={classNames('lunatic-combo-box-option', { selected })}>
63
+ <span className="id">{id || value}</span>
64
+ {scoreValues}
65
+ </div>
66
+ );
67
+ };
68
+
69
+ const meta: Meta<typeof Orchestrator> = {
70
+ title: 'Behaviour/SearchScore',
71
+ ...OrchestratorMeta,
72
+ };
73
+
74
+ export default meta;
75
+
76
+ export const Default: OrchestratorStory = {
77
+ args: {
78
+ slots: {
79
+ ComboboxOption: CustomComboboxOption,
80
+ },
81
+ },
82
+ render(args) {
83
+ return <PasteOrchestrator {...args} />;
84
+ },
85
+ };
86
+
87
+ type Nomenclature = { name: string; uri: string };
88
+
89
+ type GetReferentiel = NonNullable<
90
+ ComponentProps<typeof Orchestrator>['getReferentiel']
91
+ >;
92
+
93
+ function PasteOrchestrator(
94
+ props: Readonly<ComponentProps<typeof Orchestrator>>
95
+ ) {
96
+ const [source, setSource, sourceAsString] =
97
+ useLocalStorage<LunaticSource | null>('story-source-search');
98
+ const [nomenclatures, setNomenclatures] = useLocalStorage<
99
+ Nomenclature[] | null
100
+ >('story-nomenclatures-search');
101
+
102
+ const getReferentiel = useCallback<GetReferentiel>(
103
+ async (name: string) => {
104
+ const nomenclature = (nomenclatures ?? []).find((n) => n.name === name);
105
+ if (!nomenclature) {
106
+ throw new Error(`Nomenclature "${name}" introuvable`);
107
+ }
108
+ const response = await fetch(nomenclature.uri);
109
+ if (!response.ok) {
110
+ throw new Error(
111
+ `Impossible de charger "${name}" (${response.status} ${response.statusText})`
112
+ );
113
+ }
114
+ return response.json();
115
+ },
116
+ [nomenclatures]
117
+ );
118
+
119
+ const extraTabs = useMemo(() => {
120
+ return [
121
+ {
122
+ label: 'Source & nomenclatures',
123
+ children: (
124
+ <FormForSourceAndNomenclatures
125
+ source={sourceAsString}
126
+ nomenclatures={nomenclatures ?? []}
127
+ onChange={(source: string, nomenclatures: Nomenclature[]) => {
128
+ setNomenclatures(JSON.stringify(nomenclatures));
129
+ setSource(source);
130
+ }}
131
+ />
132
+ ),
133
+ },
134
+ ];
135
+ }, [sourceAsString, nomenclatures, setSource, setNomenclatures]);
136
+
137
+ if (!source) {
138
+ return <>{extraTabs[0].children}</>;
139
+ }
140
+
141
+ const key = `${sourceAsString}-${JSON.stringify(nomenclatures)}`;
142
+
143
+ return (
144
+ <div key={key}>
145
+ <Orchestrator
146
+ {...props}
147
+ slots={{
148
+ ComboboxOption: CustomComboboxOption,
149
+ }}
150
+ source={source}
151
+ getReferentiel={getReferentiel}
152
+ extraTabs={extraTabs}
153
+ />
154
+ </div>
155
+ );
156
+ }
157
+
158
+ function FormForSourceAndNomenclatures(
159
+ props: Readonly<{
160
+ source: string;
161
+ nomenclatures: Nomenclature[];
162
+ onChange: (source: string, nomenclatures: Nomenclature[]) => void;
163
+ }>
164
+ ) {
165
+ const [items, setItems] = useState<Nomenclature[]>(props.nomenclatures);
166
+
167
+ const add = () => setItems((prev) => [...prev, { name: '', uri: '' }]);
168
+
169
+ const remove = (index: number) =>
170
+ setItems((prev) => prev.filter((_, i) => i !== index));
171
+
172
+ const update = (index: number, field: keyof Nomenclature, value: string) =>
173
+ setItems((prev) =>
174
+ prev.map((item, i) => (i === index ? { ...item, [field]: value } : item))
175
+ );
176
+
177
+ const onSubmit: FormEventHandler<HTMLFormElement> = (e) => {
178
+ e.preventDefault();
179
+ const data = new FormData(e.currentTarget);
180
+ if (data.has('source')) {
181
+ props.onChange(
182
+ data.get('source') as string,
183
+ items.filter((item) => item.name.trim() && item.uri.trim())
184
+ );
185
+ }
186
+ };
187
+
188
+ return (
189
+ <form onSubmit={onSubmit}>
190
+ <fieldset className="fieldset">
191
+ <legend className="fieldset-legend">Paste the source.json</legend>
192
+ <textarea
193
+ required
194
+ name="source"
195
+ defaultValue={props.source}
196
+ className="textarea w-full h-24"
197
+ placeholder="source.json content"
198
+ />
199
+ <div className="label">
200
+ The content of this textarea will be saved in your local storage to
201
+ persist between refreshes
202
+ </div>
203
+ </fieldset>
204
+ <fieldset className="fieldset">
205
+ <legend className="fieldset-legend">Nomenclatures</legend>
206
+ <div className="label">
207
+ Associate the nomenclature name (the one used in the source) with the
208
+ URL that returns a JSON array. The list is saved in local storage.
209
+ </div>
210
+
211
+ <ul className="flex flex-col gap-2 mt-2">
212
+ {items.map((item, index) => (
213
+ // biome-ignore lint/suspicious/noArrayIndexKey: liste éditable sans id stable
214
+ <li key={index} className="flex flex-row items-end gap-2">
215
+ <label className="flex flex-col flex-1">
216
+ <span className="label">Name</span>
217
+ <input
218
+ required
219
+ type="text"
220
+ className="input w-full"
221
+ placeholder="ex: L_COMMUNES"
222
+ value={item.name}
223
+ onChange={(e) => update(index, 'name', e.target.value)}
224
+ />
225
+ </label>
226
+ <label className="flex flex-col flex-[2]">
227
+ <span className="label">URI</span>
228
+ <input
229
+ required
230
+ type="url"
231
+ className="input w-full"
232
+ placeholder="https://.../nomenclature.json"
233
+ value={item.uri}
234
+ onChange={(e) => update(index, 'uri', e.target.value)}
235
+ />
236
+ </label>
237
+ <button
238
+ type="button"
239
+ className="btn btn-ghost"
240
+ title="Delete this nomenclature"
241
+ onClick={() => remove(index)}
242
+ >
243
+ ✕
244
+ </button>
245
+ </li>
246
+ ))}
247
+ </ul>
248
+
249
+ <button type="button" className="btn btn-secondary w-fit" onClick={add}>
250
+ Add a nomenclature
251
+ </button>
252
+ </fieldset>
253
+ <button className="btn btn-primary mt-2" type="submit">
254
+ Load
255
+ </button>
256
+ </form>
257
+ );
258
+ }
@@ -0,0 +1,116 @@
1
+ {
2
+ "id": "5a90586e-a2a3-4853-aa3a-f8ebd0f6e86b",
3
+ "questionnaireId": "4552-CAPI",
4
+ "personalization": [],
5
+ "data": {
6
+ "EXTERNAL": {
7
+ "ADR": "1 RUE DU GRAND CHENE 79200 PARTHENAY",
8
+ "TROPIQUE": "1"
9
+ },
10
+ "COLLECTED": {
11
+ "RESIND": [],
12
+ "LIENS": {
13
+ "COLLECTED": [
14
+ [
15
+ null,
16
+ "17",
17
+ "17"
18
+ ],
19
+ [
20
+ "17",
21
+ null,
22
+ "17"
23
+ ],
24
+ [
25
+ "17",
26
+ "17"
27
+ ]
28
+ ]
29
+ },
30
+ "T_NHAB": {
31
+ "COLLECTED": 3
32
+ },
33
+ "T_SEXE": {
34
+ "COLLECTED": [
35
+ "1",
36
+ "1",
37
+ "1"
38
+ ]
39
+ },
40
+ "T_STOC": {
41
+ "COLLECTED": "3"
42
+ },
43
+ "T_STOL": {
44
+ "COLLECTED": "2"
45
+ },
46
+ "T_LNAIS": {
47
+ "COLLECTED": [
48
+ "1",
49
+ "1",
50
+ "1"
51
+ ]
52
+ },
53
+ "T_UNLOG": {
54
+ "COLLECTED": [
55
+ "2",
56
+ "2",
57
+ "2"
58
+ ]
59
+ },
60
+ "DATE_ITW": {
61
+ "COLLECTED": "2027-03-01"
62
+ },
63
+ "T_PRENOM": {
64
+ "COLLECTED": [
65
+ "Lucas",
66
+ "Mathieu",
67
+ "Antoine"
68
+ ]
69
+ },
70
+ "T_TYPLOG": {
71
+ "COLLECTED": "1"
72
+ },
73
+ "T_DEPNAIS": {
74
+ "COLLECTED": [
75
+ "Seine-Saint-Denis",
76
+ "Seine-et-Marne",
77
+ "Seine-Maritime"
78
+ ]
79
+ },
80
+ "T_NATION1": {
81
+ "COLLECTED": [
82
+ true,
83
+ true,
84
+ true
85
+ ]
86
+ },
87
+ "T_NPIECES": {
88
+ "COLLECTED": 5
89
+ },
90
+ "T_SURFACE": {
91
+ "COLLECTED": 98
92
+ },
93
+ "T_TYPMAIS": {
94
+ "COLLECTED": "2"
95
+ },
96
+ "T_DATENAIS": {
97
+ "COLLECTED": [
98
+ "1998-02-19",
99
+ "1997-06-03",
100
+ "1999-06-14"
101
+ ]
102
+ },
103
+ "T_EMMENAGE": {
104
+ "COLLECTED": "2023"
105
+ },
106
+ "T_LOGPROPRI": {
107
+ "COLLECTED": "6"
108
+ }
109
+ }
110
+ },
111
+ "stateData": {
112
+ "state": "INIT",
113
+ "date": 1790865361892,
114
+ "currentPage": "1"
115
+ }
116
+ }