@aehrc/smart-forms-renderer 0.10.5 → 0.11.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/lib/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.d.ts +19 -0
- package/lib/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.js +46 -0
- package/lib/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.js.map +1 -0
- package/lib/components/FormComponents/ChoiceItems/ChoiceAutocompleteItem.js +5 -27
- package/lib/components/FormComponents/ChoiceItems/ChoiceAutocompleteItem.js.map +1 -1
- package/lib/components/FormComponents/GridGroup/GridTable.d.ts +1 -2
- package/lib/components/FormComponents/Tables/GroupTable.js +1 -0
- package/lib/components/FormComponents/Tables/GroupTable.js.map +1 -1
- package/lib/hooks/useHidden.js +2 -2
- package/lib/hooks/useHidden.js.map +1 -1
- package/lib/hooks/useInitialiseRenderer.js +1 -1
- package/lib/hooks/useInitialiseRenderer.js.map +1 -1
- package/lib/hooks/useRenderingExtensions.js +4 -2
- package/lib/hooks/useRenderingExtensions.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +3 -8
- package/lib/index.js.map +1 -1
- package/lib/stores/questionnaireStore.js +1 -1
- package/lib/stores/questionnaireStore.js.map +1 -1
- package/lib/utils/choice.d.ts +4 -4
- package/lib/utils/choice.js +31 -40
- package/lib/utils/choice.js.map +1 -1
- package/lib/utils/initialise.d.ts +1 -2
- package/lib/utils/initialise.js +91 -34
- package/lib/utils/initialise.js.map +1 -1
- package/lib/utils/qItem.js +2 -2
- package/lib/utils/qItem.js.map +1 -1
- package/lib/utils/qrItem.d.ts +1 -9
- package/lib/utils/qrItem.js +0 -47
- package/lib/utils/qrItem.js.map +1 -1
- package/lib/utils/tabs.d.ts +0 -7
- package/lib/utils/tabs.js +4 -17
- package/lib/utils/tabs.js.map +1 -1
- package/lib/utils/valueSet.d.ts +1 -1
- package/package.json +12 -14
- package/src/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.tsx +126 -0
- package/src/components/FormComponents/ChoiceItems/ChoiceAutocompleteItem.tsx +25 -76
- package/src/components/FormComponents/GridGroup/GridTable.tsx +2 -2
- package/src/components/FormComponents/Tables/GroupTable.tsx +2 -0
- package/src/hooks/useHidden.ts +2 -2
- package/src/hooks/useInitialiseRenderer.ts +1 -1
- package/src/hooks/useRenderingExtensions.ts +2 -2
- package/src/index.ts +3 -9
- package/src/stores/questionnaireStore.ts +1 -1
- package/src/utils/choice.ts +38 -27
- package/src/utils/initialise.ts +379 -0
- package/src/utils/qItem.ts +2 -2
- package/src/utils/qrItem.ts +1 -63
- package/src/utils/tabs.ts +3 -22
- package/src/utils/valueSet.ts +1 -1
- package/src/hooks/useBackToTop.ts +0 -29
- package/src/utils/initialiseForm.ts +0 -91
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 Commonwealth Scientific and Industrial Research
|
|
3
|
+
* Organisation (CSIRO) ABN 41 687 119 230.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { evaluateInitialEnableWhenExpressions } from './enableWhenExpression';
|
|
19
|
+
import { getFirstVisibleTab } from './tabs';
|
|
20
|
+
import type {
|
|
21
|
+
Expression,
|
|
22
|
+
Questionnaire,
|
|
23
|
+
QuestionnaireItem,
|
|
24
|
+
QuestionnaireItemInitial,
|
|
25
|
+
QuestionnaireResponse,
|
|
26
|
+
QuestionnaireResponseItem,
|
|
27
|
+
QuestionnaireResponseItemAnswer
|
|
28
|
+
} from 'fhir/r4';
|
|
29
|
+
import type { EnableWhenExpression, EnableWhenItems } from '../interfaces/enableWhen.interface';
|
|
30
|
+
import type { Tabs } from '../interfaces/tab.interface';
|
|
31
|
+
import { assignPopulatedAnswersToEnableWhen } from './enableWhen';
|
|
32
|
+
import type { CalculatedExpression } from '../interfaces/calculatedExpression.interface';
|
|
33
|
+
import { evaluateInitialCalculatedExpressions } from './calculatedExpression';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Initialise a conformant questionnaireResponse from a given questionnaire
|
|
37
|
+
* optionally takes in an existing questionnaireResponse to be initialised
|
|
38
|
+
*
|
|
39
|
+
* @author Sean Fong
|
|
40
|
+
*/
|
|
41
|
+
export function initialiseQuestionnaireResponse(
|
|
42
|
+
questionnaire: Questionnaire,
|
|
43
|
+
questionnaireResponse?: QuestionnaireResponse
|
|
44
|
+
) {
|
|
45
|
+
if (!questionnaireResponse) {
|
|
46
|
+
questionnaireResponse = {
|
|
47
|
+
resourceType: 'QuestionnaireResponse',
|
|
48
|
+
status: 'in-progress'
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!questionnaireResponse.status) {
|
|
53
|
+
questionnaireResponse.status = 'in-progress';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const firstTopLevelItem = questionnaire?.item?.[0];
|
|
57
|
+
if (firstTopLevelItem && !questionnaireResponse.item) {
|
|
58
|
+
const initialItems = readItemInitialValues(questionnaire);
|
|
59
|
+
|
|
60
|
+
questionnaireResponse.item =
|
|
61
|
+
initialItems && initialItems.length > 0
|
|
62
|
+
? initialItems
|
|
63
|
+
: [
|
|
64
|
+
{
|
|
65
|
+
linkId: firstTopLevelItem.linkId,
|
|
66
|
+
text: firstTopLevelItem.text,
|
|
67
|
+
item: []
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!questionnaireResponse.questionnaire) {
|
|
73
|
+
questionnaireResponse.questionnaire = setQuestionnaireReference(questionnaire);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return questionnaireResponse;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function setQuestionnaireReference(questionnaire: Questionnaire) {
|
|
80
|
+
// Use {url}|{version} - the ideal way
|
|
81
|
+
if (questionnaire.url) {
|
|
82
|
+
let questionnaireReference = questionnaire.url;
|
|
83
|
+
if (questionnaire.version) {
|
|
84
|
+
questionnaireReference += '|' + questionnaire.version;
|
|
85
|
+
}
|
|
86
|
+
return questionnaireReference;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// If no url exists, use Questionnaire/{id}
|
|
90
|
+
if (questionnaire.id) {
|
|
91
|
+
return `Questionnaire/${questionnaire.id}`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return '';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function readItemInitialValues(questionnaire: Questionnaire) {
|
|
98
|
+
if (!questionnaire.item || questionnaire.item.length === 0) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const topLevelQrItems: QuestionnaireResponseItem[] = [];
|
|
103
|
+
for (const topLevelQItem of questionnaire.item) {
|
|
104
|
+
const updatedTopLevelQRItem = readItemInitialValueRecursive(topLevelQItem);
|
|
105
|
+
|
|
106
|
+
if (Array.isArray(updatedTopLevelQRItem)) {
|
|
107
|
+
if (updatedTopLevelQRItem.length > 0) {
|
|
108
|
+
topLevelQrItems.push(...updatedTopLevelQRItem);
|
|
109
|
+
}
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (updatedTopLevelQRItem) {
|
|
114
|
+
topLevelQrItems.push(updatedTopLevelQRItem);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (topLevelQrItems.length === 0) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return topLevelQrItems;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function readItemInitialValueRecursive(
|
|
126
|
+
qItem: QuestionnaireItem
|
|
127
|
+
): QuestionnaireResponseItem[] | QuestionnaireResponseItem | null {
|
|
128
|
+
const childQItems = qItem.item;
|
|
129
|
+
if (childQItems && childQItems.length > 0) {
|
|
130
|
+
// TODO No support for multiple rows at the moment
|
|
131
|
+
if (qItem.type === 'group' && qItem.repeats) {
|
|
132
|
+
const initialItemsFromRepeatGroup = getInitialValueAnswersFromRepeatGroup(qItem);
|
|
133
|
+
return createNewRepeatGroupQuestionnaireResponseItem(qItem, initialItemsFromRepeatGroup);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const initialQRItems: QuestionnaireResponseItem[] = [];
|
|
137
|
+
for (const childQItem of childQItems) {
|
|
138
|
+
const initialChildQRItemOrItems = readItemInitialValueRecursive(childQItem);
|
|
139
|
+
|
|
140
|
+
if (Array.isArray(initialChildQRItemOrItems)) {
|
|
141
|
+
if (initialChildQRItemOrItems.length > 0) {
|
|
142
|
+
initialQRItems.push(...initialChildQRItemOrItems);
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (initialChildQRItemOrItems) {
|
|
148
|
+
initialQRItems.push(initialChildQRItemOrItems);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let qrItem = createNewQuestionnaireResponseItem(qItem, getInitialValueAnswers(qItem));
|
|
153
|
+
|
|
154
|
+
if (initialQRItems.length > 0) {
|
|
155
|
+
if (!qrItem) {
|
|
156
|
+
qrItem = {
|
|
157
|
+
linkId: qItem.linkId,
|
|
158
|
+
text: qItem.text
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
qrItem.item = initialQRItems;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return qrItem;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return createNewQuestionnaireResponseItem(qItem, getInitialValueAnswers(qItem));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function getInitialValueAnswers(qItem: QuestionnaireItem): QuestionnaireResponseItemAnswer[] {
|
|
171
|
+
// For answerOption.initialSelected
|
|
172
|
+
if (qItem.type === 'choice' && qItem.answerOption) {
|
|
173
|
+
return qItem.answerOption
|
|
174
|
+
.filter((option) => option.initialSelected)
|
|
175
|
+
.map((option): QuestionnaireResponseItemAnswer | null => {
|
|
176
|
+
if (option.valueCoding) {
|
|
177
|
+
return {
|
|
178
|
+
valueCoding: option.valueCoding
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (option.valueString) {
|
|
183
|
+
return {
|
|
184
|
+
valueString: option.valueString
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (option.valueInteger) {
|
|
189
|
+
return {
|
|
190
|
+
valueInteger: option.valueInteger
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return null;
|
|
195
|
+
})
|
|
196
|
+
.filter((item): item is QuestionnaireResponseItemAnswer => !!item);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// For item.initial
|
|
200
|
+
const initialValues = qItem.initial;
|
|
201
|
+
if (!initialValues) {
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return initialValues
|
|
206
|
+
.map((initialValue) => initialValueSwitcher(initialValue))
|
|
207
|
+
.filter((item): item is QuestionnaireResponseItemAnswer => item !== null);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function getInitialValueAnswersFromRepeatGroup(qItem: QuestionnaireItem) {
|
|
211
|
+
if (!qItem.item) {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return qItem.item
|
|
216
|
+
.map((childQItem): QuestionnaireResponseItem => {
|
|
217
|
+
return {
|
|
218
|
+
linkId: childQItem.linkId,
|
|
219
|
+
...(childQItem.text ? { text: childQItem.text } : {}),
|
|
220
|
+
answer: getInitialValueAnswers(childQItem)
|
|
221
|
+
};
|
|
222
|
+
})
|
|
223
|
+
.filter((childQRItem) => childQRItem.answer && childQRItem.answer.length > 0);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function initialValueSwitcher(
|
|
227
|
+
initialValue: QuestionnaireItemInitial
|
|
228
|
+
): QuestionnaireResponseItemAnswer | null {
|
|
229
|
+
if (initialValue.valueBoolean) {
|
|
230
|
+
return { valueBoolean: initialValue.valueBoolean };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (initialValue.valueDecimal) {
|
|
234
|
+
return { valueDecimal: initialValue.valueDecimal };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (initialValue.valueInteger) {
|
|
238
|
+
return { valueInteger: initialValue.valueInteger };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (initialValue.valueDate) {
|
|
242
|
+
return { valueDate: initialValue.valueDate };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (initialValue.valueDateTime) {
|
|
246
|
+
return { valueDateTime: initialValue.valueDateTime };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (initialValue.valueTime) {
|
|
250
|
+
return { valueTime: initialValue.valueTime };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (initialValue.valueString) {
|
|
254
|
+
return { valueString: initialValue.valueString };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (initialValue.valueUri) {
|
|
258
|
+
return { valueUri: initialValue.valueUri };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (initialValue.valueAttachment) {
|
|
262
|
+
return { valueAttachment: initialValue.valueAttachment };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (initialValue.valueCoding) {
|
|
266
|
+
return { valueCoding: initialValue.valueCoding };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (initialValue.valueQuantity) {
|
|
270
|
+
return { valueQuantity: initialValue.valueQuantity };
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (initialValue.valueReference) {
|
|
274
|
+
return { valueReference: initialValue.valueReference };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function createNewQuestionnaireResponseItem(
|
|
281
|
+
qItem: QuestionnaireItem,
|
|
282
|
+
initialValueAnswers: QuestionnaireResponseItemAnswer[]
|
|
283
|
+
): QuestionnaireResponseItem | null {
|
|
284
|
+
if (initialValueAnswers.length === 0) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// If item is non-repeating, only take the first initial value
|
|
289
|
+
if (!qItem.repeats) {
|
|
290
|
+
initialValueAnswers = [initialValueAnswers[0]];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
linkId: qItem.linkId,
|
|
295
|
+
text: qItem.text,
|
|
296
|
+
answer: initialValueAnswers
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function createNewRepeatGroupQuestionnaireResponseItem(
|
|
301
|
+
qItem: QuestionnaireItem,
|
|
302
|
+
initialValueItems: QuestionnaireResponseItem[]
|
|
303
|
+
): QuestionnaireResponseItem | null {
|
|
304
|
+
if (initialValueItems.length === 0) {
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
linkId: qItem.linkId,
|
|
310
|
+
text: qItem.text,
|
|
311
|
+
item: initialValueItems
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface initialFormFromResponseParams {
|
|
316
|
+
questionnaireResponse: QuestionnaireResponse;
|
|
317
|
+
enableWhenItems: EnableWhenItems;
|
|
318
|
+
enableWhenExpressions: Record<string, EnableWhenExpression>;
|
|
319
|
+
calculatedExpressions: Record<string, CalculatedExpression>;
|
|
320
|
+
variablesFhirPath: Record<string, Expression[]>;
|
|
321
|
+
tabs: Tabs;
|
|
322
|
+
fhirPathContext: Record<string, any>;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export function initialiseFormFromResponse(params: initialFormFromResponseParams): {
|
|
326
|
+
initialEnableWhenItems: EnableWhenItems;
|
|
327
|
+
initialEnableWhenLinkedQuestions: Record<string, string[]>;
|
|
328
|
+
initialEnableWhenExpressions: Record<string, EnableWhenExpression>;
|
|
329
|
+
initialCalculatedExpressions: Record<string, CalculatedExpression>;
|
|
330
|
+
firstVisibleTab: number;
|
|
331
|
+
updatedFhirPathContext: Record<string, any>;
|
|
332
|
+
} {
|
|
333
|
+
const {
|
|
334
|
+
questionnaireResponse,
|
|
335
|
+
enableWhenItems,
|
|
336
|
+
enableWhenExpressions,
|
|
337
|
+
calculatedExpressions,
|
|
338
|
+
variablesFhirPath,
|
|
339
|
+
tabs
|
|
340
|
+
} = params;
|
|
341
|
+
let updatedFhirPathContext = params.fhirPathContext;
|
|
342
|
+
|
|
343
|
+
const { initialisedItems, linkedQuestions } = assignPopulatedAnswersToEnableWhen(
|
|
344
|
+
enableWhenItems,
|
|
345
|
+
questionnaireResponse
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
const evaluateInitialEnableWhenExpressionsResult = evaluateInitialEnableWhenExpressions({
|
|
349
|
+
initialResponse: questionnaireResponse,
|
|
350
|
+
enableWhenExpressions: enableWhenExpressions,
|
|
351
|
+
variablesFhirPath: variablesFhirPath,
|
|
352
|
+
existingFhirPathContext: updatedFhirPathContext
|
|
353
|
+
});
|
|
354
|
+
const { initialEnableWhenExpressions } = evaluateInitialEnableWhenExpressionsResult;
|
|
355
|
+
updatedFhirPathContext = evaluateInitialEnableWhenExpressionsResult.updatedFhirPathContext;
|
|
356
|
+
|
|
357
|
+
const evaluateInitialCalculatedExpressionsResult = evaluateInitialCalculatedExpressions({
|
|
358
|
+
initialResponse: questionnaireResponse,
|
|
359
|
+
calculatedExpressions: calculatedExpressions,
|
|
360
|
+
variablesFhirPath: variablesFhirPath,
|
|
361
|
+
existingFhirPathContext: updatedFhirPathContext
|
|
362
|
+
});
|
|
363
|
+
const { initialCalculatedExpressions } = evaluateInitialCalculatedExpressionsResult;
|
|
364
|
+
updatedFhirPathContext = evaluateInitialEnableWhenExpressionsResult.updatedFhirPathContext;
|
|
365
|
+
|
|
366
|
+
const firstVisibleTab =
|
|
367
|
+
Object.keys(tabs).length > 0
|
|
368
|
+
? getFirstVisibleTab(tabs, initialisedItems, initialEnableWhenExpressions)
|
|
369
|
+
: 0;
|
|
370
|
+
|
|
371
|
+
return {
|
|
372
|
+
initialEnableWhenItems: initialisedItems,
|
|
373
|
+
initialEnableWhenLinkedQuestions: linkedQuestions,
|
|
374
|
+
initialEnableWhenExpressions,
|
|
375
|
+
initialCalculatedExpressions,
|
|
376
|
+
firstVisibleTab,
|
|
377
|
+
updatedFhirPathContext
|
|
378
|
+
};
|
|
379
|
+
}
|
package/src/utils/qItem.ts
CHANGED
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import type { Extension, Questionnaire, QuestionnaireItem } from 'fhir/r4';
|
|
19
|
-
import { hasHiddenExtension } from './itemControl';
|
|
20
19
|
import { getChoiceControlType } from './choice';
|
|
21
20
|
import { ChoiceItemControl, OpenChoiceItemControl } from '../interfaces/choice.enum';
|
|
22
21
|
import { getOpenChoiceControlType } from './openChoice';
|
|
23
22
|
import type { EnableWhenExpression, EnableWhenItems } from '../interfaces/enableWhen.interface';
|
|
23
|
+
import { structuredDataCapture } from 'fhir-sdc-helpers';
|
|
24
24
|
|
|
25
25
|
interface isHiddenParams {
|
|
26
26
|
questionnaireItem: QuestionnaireItem;
|
|
@@ -39,7 +39,7 @@ interface isHiddenParams {
|
|
|
39
39
|
export function isHidden(params: isHiddenParams): boolean {
|
|
40
40
|
const { questionnaireItem, enableWhenIsActivated, enableWhenItems, enableWhenExpressions } =
|
|
41
41
|
params;
|
|
42
|
-
if (
|
|
42
|
+
if (structuredDataCapture.getHidden(questionnaireItem)) {
|
|
43
43
|
return true;
|
|
44
44
|
}
|
|
45
45
|
|
package/src/utils/qrItem.ts
CHANGED
|
@@ -15,72 +15,10 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import type {
|
|
19
|
-
Questionnaire,
|
|
20
|
-
QuestionnaireItem,
|
|
21
|
-
QuestionnaireResponse,
|
|
22
|
-
QuestionnaireResponseItem
|
|
23
|
-
} from 'fhir/r4';
|
|
18
|
+
import type { QuestionnaireItem, QuestionnaireResponse, QuestionnaireResponseItem } from 'fhir/r4';
|
|
24
19
|
|
|
25
20
|
import type { QrRepeatGroup } from '../interfaces/repeatGroup.interface';
|
|
26
21
|
|
|
27
|
-
/**
|
|
28
|
-
* Initialise a conformant questionnaireResponse from a given questionnaire
|
|
29
|
-
* optionally takes in an existing questionnaireResponse to be initialised
|
|
30
|
-
*
|
|
31
|
-
* @author Sean Fong
|
|
32
|
-
*/
|
|
33
|
-
export function initialiseQuestionnaireResponse(
|
|
34
|
-
questionnaire: Questionnaire,
|
|
35
|
-
questionnaireResponse?: QuestionnaireResponse
|
|
36
|
-
) {
|
|
37
|
-
if (!questionnaireResponse) {
|
|
38
|
-
questionnaireResponse = {
|
|
39
|
-
resourceType: 'QuestionnaireResponse',
|
|
40
|
-
status: 'in-progress'
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (!questionnaireResponse.status) {
|
|
45
|
-
questionnaireResponse.status = 'in-progress';
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const firstTopLevelItem = questionnaire?.item?.[0];
|
|
49
|
-
if (firstTopLevelItem && !questionnaireResponse.item) {
|
|
50
|
-
questionnaireResponse.item = [
|
|
51
|
-
{
|
|
52
|
-
linkId: firstTopLevelItem.linkId,
|
|
53
|
-
text: firstTopLevelItem.text,
|
|
54
|
-
item: []
|
|
55
|
-
}
|
|
56
|
-
];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (!questionnaireResponse.questionnaire) {
|
|
60
|
-
questionnaireResponse.questionnaire = setQuestionnaireReference(questionnaire);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return questionnaireResponse;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function setQuestionnaireReference(questionnaire: Questionnaire) {
|
|
67
|
-
// Use {url}|{version} - the ideal way
|
|
68
|
-
if (questionnaire.url) {
|
|
69
|
-
let questionnaireReference = questionnaire.url;
|
|
70
|
-
if (questionnaire.version) {
|
|
71
|
-
questionnaireReference += '|' + questionnaire.version;
|
|
72
|
-
}
|
|
73
|
-
return questionnaireReference;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// If no url exists, use Questionnaire/{id}
|
|
77
|
-
if (questionnaire.id) {
|
|
78
|
-
return `Questionnaire/${questionnaire.id}`;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return '';
|
|
82
|
-
}
|
|
83
|
-
|
|
84
22
|
/**
|
|
85
23
|
* Remove items with no answers from a given questionnaireResponse
|
|
86
24
|
* Also remove any starting or trailing whitespace from valueStrings
|
package/src/utils/tabs.ts
CHANGED
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
import type { Tabs } from '../interfaces/tab.interface';
|
|
19
19
|
import type { EnableWhenExpression, EnableWhenItems } from '../interfaces/enableWhen.interface';
|
|
20
20
|
import type { Coding, QuestionnaireItem } from 'fhir/r4';
|
|
21
|
-
import {
|
|
21
|
+
import { isSpecificItemControl } from './itemControl';
|
|
22
22
|
import { isHidden, isHiddenByEnableWhens } from './qItem';
|
|
23
|
+
import { structuredDataCapture } from 'fhir-sdc-helpers';
|
|
23
24
|
|
|
24
25
|
export function getFirstVisibleTab(
|
|
25
26
|
tabs: Tabs,
|
|
@@ -134,7 +135,7 @@ export function constructTabsWithProperties(
|
|
|
134
135
|
tabs[qItem.linkId] = {
|
|
135
136
|
tabIndex: i,
|
|
136
137
|
isComplete: false,
|
|
137
|
-
isHidden:
|
|
138
|
+
isHidden: structuredDataCapture.getHidden(qItem) ?? false
|
|
138
139
|
};
|
|
139
140
|
}
|
|
140
141
|
return tabs;
|
|
@@ -201,26 +202,6 @@ export function getNextVisibleTabIndex(params: getNextVisibleTabIndexParams): nu
|
|
|
201
202
|
|
|
202
203
|
return nextTabIndex;
|
|
203
204
|
}
|
|
204
|
-
/**
|
|
205
|
-
*
|
|
206
|
-
* Get index of first visible tab
|
|
207
|
-
*
|
|
208
|
-
* @author Sean Fong
|
|
209
|
-
*/
|
|
210
|
-
export function getFirstVisibleTabIndex(
|
|
211
|
-
tabs: Tabs,
|
|
212
|
-
enableWhenIsActivated: boolean,
|
|
213
|
-
enableWhenItems: EnableWhenItems,
|
|
214
|
-
enableWhenExpressions: Record<string, EnableWhenExpression>
|
|
215
|
-
): number | undefined {
|
|
216
|
-
const tabsWithVisibility = constructTabsWithVisibility({
|
|
217
|
-
tabs,
|
|
218
|
-
enableWhenIsActivated,
|
|
219
|
-
enableWhenItems,
|
|
220
|
-
enableWhenExpressions
|
|
221
|
-
});
|
|
222
|
-
return tabsWithVisibility.findIndex((tab) => tab.isVisible);
|
|
223
|
-
}
|
|
224
205
|
|
|
225
206
|
/**
|
|
226
207
|
*
|
package/src/utils/valueSet.ts
CHANGED
|
@@ -28,8 +28,8 @@ import type {
|
|
|
28
28
|
} from 'fhir/r4';
|
|
29
29
|
import * as FHIR from 'fhirclient';
|
|
30
30
|
import type { FhirResourceString } from '../interfaces/populate.interface';
|
|
31
|
-
import type { ValueSetPromise } from '../interfaces/valueSet.interface';
|
|
32
31
|
import type { VariableXFhirQuery } from '../interfaces/variables.interface';
|
|
32
|
+
import type { ValueSetPromise } from '../interfaces/valueSet.interface';
|
|
33
33
|
|
|
34
34
|
const VALID_VALUE_SET_URL_REGEX =
|
|
35
35
|
/https?:\/\/(www\.)?[-\w@:%.+~#=]{2,256}\.[a-z]{2,4}\b([-@\w:%+.~#?&/=]*ValueSet[-@\w:%+.~#?&/=]*)/;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2023 Commonwealth Scientific and Industrial Research
|
|
3
|
-
* Organisation (CSIRO) ABN 41 687 119 230.
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import { useEffect } from 'react';
|
|
19
|
-
import { useLocation } from 'react-router-dom';
|
|
20
|
-
|
|
21
|
-
function useBackToTop() {
|
|
22
|
-
const { pathname } = useLocation();
|
|
23
|
-
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
window.scrollTo(0, 0);
|
|
26
|
-
}, [pathname]);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export default useBackToTop;
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2023 Commonwealth Scientific and Industrial Research
|
|
3
|
-
* Organisation (CSIRO) ABN 41 687 119 230.
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import { evaluateInitialEnableWhenExpressions } from './enableWhenExpression';
|
|
19
|
-
import { getFirstVisibleTab } from './tabs';
|
|
20
|
-
import type { Expression, QuestionnaireResponse } from 'fhir/r4';
|
|
21
|
-
import type { EnableWhenExpression, EnableWhenItems } from '../interfaces/enableWhen.interface';
|
|
22
|
-
import type { Tabs } from '../interfaces/tab.interface';
|
|
23
|
-
import { assignPopulatedAnswersToEnableWhen } from './enableWhen';
|
|
24
|
-
import type { CalculatedExpression } from '../interfaces/calculatedExpression.interface';
|
|
25
|
-
import { evaluateInitialCalculatedExpressions } from './calculatedExpression';
|
|
26
|
-
|
|
27
|
-
interface initialFormFromResponseParams {
|
|
28
|
-
questionnaireResponse: QuestionnaireResponse;
|
|
29
|
-
enableWhenItems: EnableWhenItems;
|
|
30
|
-
enableWhenExpressions: Record<string, EnableWhenExpression>;
|
|
31
|
-
calculatedExpressions: Record<string, CalculatedExpression>;
|
|
32
|
-
variablesFhirPath: Record<string, Expression[]>;
|
|
33
|
-
tabs: Tabs;
|
|
34
|
-
fhirPathContext: Record<string, any>;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function initialiseFormFromResponse(params: initialFormFromResponseParams): {
|
|
38
|
-
initialEnableWhenItems: EnableWhenItems;
|
|
39
|
-
initialEnableWhenLinkedQuestions: Record<string, string[]>;
|
|
40
|
-
initialEnableWhenExpressions: Record<string, EnableWhenExpression>;
|
|
41
|
-
initialCalculatedExpressions: Record<string, CalculatedExpression>;
|
|
42
|
-
firstVisibleTab: number;
|
|
43
|
-
updatedFhirPathContext: Record<string, any>;
|
|
44
|
-
} {
|
|
45
|
-
const {
|
|
46
|
-
questionnaireResponse,
|
|
47
|
-
enableWhenItems,
|
|
48
|
-
enableWhenExpressions,
|
|
49
|
-
calculatedExpressions,
|
|
50
|
-
variablesFhirPath,
|
|
51
|
-
tabs
|
|
52
|
-
} = params;
|
|
53
|
-
let updatedFhirPathContext = params.fhirPathContext;
|
|
54
|
-
|
|
55
|
-
const { initialisedItems, linkedQuestions } = assignPopulatedAnswersToEnableWhen(
|
|
56
|
-
enableWhenItems,
|
|
57
|
-
questionnaireResponse
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
const evaluateInitialEnableWhenExpressionsResult = evaluateInitialEnableWhenExpressions({
|
|
61
|
-
initialResponse: questionnaireResponse,
|
|
62
|
-
enableWhenExpressions: enableWhenExpressions,
|
|
63
|
-
variablesFhirPath: variablesFhirPath,
|
|
64
|
-
existingFhirPathContext: updatedFhirPathContext
|
|
65
|
-
});
|
|
66
|
-
const { initialEnableWhenExpressions } = evaluateInitialEnableWhenExpressionsResult;
|
|
67
|
-
updatedFhirPathContext = evaluateInitialEnableWhenExpressionsResult.updatedFhirPathContext;
|
|
68
|
-
|
|
69
|
-
const evaluateInitialCalculatedExpressionsResult = evaluateInitialCalculatedExpressions({
|
|
70
|
-
initialResponse: questionnaireResponse,
|
|
71
|
-
calculatedExpressions: calculatedExpressions,
|
|
72
|
-
variablesFhirPath: variablesFhirPath,
|
|
73
|
-
existingFhirPathContext: updatedFhirPathContext
|
|
74
|
-
});
|
|
75
|
-
const { initialCalculatedExpressions } = evaluateInitialCalculatedExpressionsResult;
|
|
76
|
-
updatedFhirPathContext = evaluateInitialEnableWhenExpressionsResult.updatedFhirPathContext;
|
|
77
|
-
|
|
78
|
-
const firstVisibleTab =
|
|
79
|
-
Object.keys(tabs).length > 0
|
|
80
|
-
? getFirstVisibleTab(tabs, initialisedItems, initialEnableWhenExpressions)
|
|
81
|
-
: 0;
|
|
82
|
-
|
|
83
|
-
return {
|
|
84
|
-
initialEnableWhenItems: initialisedItems,
|
|
85
|
-
initialEnableWhenLinkedQuestions: linkedQuestions,
|
|
86
|
-
initialEnableWhenExpressions,
|
|
87
|
-
initialCalculatedExpressions,
|
|
88
|
-
firstVisibleTab,
|
|
89
|
-
updatedFhirPathContext
|
|
90
|
-
};
|
|
91
|
-
}
|