@aehrc/smart-forms-renderer 0.40.2 → 0.41.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/AttachmentItem/AttachmentItem.js +2 -3
- package/lib/components/FormComponents/AttachmentItem/AttachmentItem.js.map +1 -1
- package/lib/components/FormComponents/DateTimeItems/CustomDateItem/CustomDateItem.js +1 -2
- package/lib/components/FormComponents/DateTimeItems/CustomDateItem/CustomDateItem.js.map +1 -1
- package/lib/components/FormComponents/DateTimeItems/CustomDateTimeItem/CustomDateTimeItem.js +3 -4
- package/lib/components/FormComponents/DateTimeItems/CustomDateTimeItem/CustomDateTimeItem.js.map +1 -1
- package/lib/components/FormComponents/DecimalItem/DecimalItem.js +2 -3
- package/lib/components/FormComponents/DecimalItem/DecimalItem.js.map +1 -1
- package/lib/components/FormComponents/IntegerItem/IntegerItem.js +2 -3
- package/lib/components/FormComponents/IntegerItem/IntegerItem.js.map +1 -1
- package/lib/components/FormComponents/QuantityItem/QuantityItem.js +1 -2
- package/lib/components/FormComponents/QuantityItem/QuantityItem.js.map +1 -1
- package/lib/components/FormComponents/RepeatGroup/AddItemButton.d.ts +2 -2
- package/lib/components/FormComponents/RepeatGroup/RepeatGroup.js +2 -3
- package/lib/components/FormComponents/RepeatGroup/RepeatGroup.js.map +1 -1
- package/lib/components/FormComponents/RepeatGroup/RepeatGroupView.d.ts +2 -2
- package/lib/components/FormComponents/StringItem/StringItem.js +2 -3
- package/lib/components/FormComponents/StringItem/StringItem.js.map +1 -1
- package/lib/components/FormComponents/Tables/AddRowButton.d.ts +2 -2
- package/lib/components/FormComponents/Tables/GroupTable.js +3 -1
- package/lib/components/FormComponents/Tables/GroupTable.js.map +1 -1
- package/lib/components/FormComponents/TextItem/TextItem.js +2 -3
- package/lib/components/FormComponents/TextItem/TextItem.js.map +1 -1
- package/lib/components/FormComponents/UrlItem/UrlItem.js +2 -3
- package/lib/components/FormComponents/UrlItem/UrlItem.js.map +1 -1
- package/lib/components/Renderer/BaseRenderer.js +4 -3
- package/lib/components/Renderer/BaseRenderer.js.map +1 -1
- package/lib/hooks/useGroupTableRows.d.ts +4 -4
- package/lib/hooks/useGroupTableRows.js +3 -5
- package/lib/hooks/useGroupTableRows.js.map +1 -1
- package/lib/hooks/useInitialiseGroupTableRows.d.ts +4 -0
- package/lib/hooks/{useNumberInput.js → useInitialiseGroupTableRows.js} +16 -13
- package/lib/hooks/useInitialiseGroupTableRows.js.map +1 -0
- package/lib/hooks/useInitialiseRepeatGroups.d.ts +2 -2
- package/lib/interfaces/repeatGroup.interface.d.ts +1 -1
- package/lib/stores/questionnaireResponseStore.d.ts +3 -0
- package/lib/stores/questionnaireResponseStore.js +5 -0
- package/lib/stores/questionnaireResponseStore.js.map +1 -1
- package/lib/tests/test-data/removeIdSample.d.ts +3 -0
- package/lib/tests/test-data/removeIdSample.js +99 -0
- package/lib/tests/test-data/removeIdSample.js.map +1 -0
- package/lib/theme/Theme.js +0 -2
- package/lib/theme/Theme.js.map +1 -1
- package/lib/utils/calculatedExpression.js +4 -4
- package/lib/utils/calculatedExpression.js.map +1 -1
- package/lib/utils/extractObservation.d.ts +1 -0
- package/lib/utils/extractObservation.js +1 -1
- package/lib/utils/extractObservation.js.map +1 -1
- package/lib/utils/manageForm.js +1 -1
- package/lib/utils/manageForm.js.map +1 -1
- package/lib/utils/openChoice.js +3 -3
- package/lib/utils/openChoice.js.map +1 -1
- package/lib/utils/removeRepeatId.d.ts +2 -0
- package/lib/utils/removeRepeatId.js +85 -0
- package/lib/utils/removeRepeatId.js.map +1 -0
- package/lib/utils/repeatId.d.ts +0 -2
- package/lib/utils/repeatId.js +0 -68
- package/lib/utils/repeatId.js.map +1 -1
- package/lib/utils/repopulateItems.js +8 -8
- package/lib/utils/repopulateItems.js.map +1 -1
- package/package.json +6 -2
- package/src/components/FormComponents/AttachmentItem/AttachmentItem.tsx +2 -3
- package/src/components/FormComponents/DateTimeItems/CustomDateItem/CustomDateItem.tsx +1 -2
- package/src/components/FormComponents/DateTimeItems/CustomDateTimeItem/CustomDateTimeItem.tsx +3 -4
- package/src/components/FormComponents/DecimalItem/DecimalItem.tsx +2 -3
- package/src/components/FormComponents/IntegerItem/IntegerItem.tsx +2 -3
- package/src/components/FormComponents/QuantityItem/QuantityItem.tsx +1 -2
- package/src/components/FormComponents/RepeatGroup/AddItemButton.tsx +2 -2
- package/src/components/FormComponents/RepeatGroup/RepeatGroup.tsx +2 -3
- package/src/components/FormComponents/RepeatGroup/RepeatGroupView.tsx +2 -2
- package/src/components/FormComponents/StringItem/StringItem.tsx +2 -3
- package/src/components/FormComponents/Tables/AddRowButton.tsx +2 -2
- package/src/components/FormComponents/Tables/GroupTable.tsx +5 -5
- package/src/components/FormComponents/TextItem/TextItem.tsx +2 -3
- package/src/components/FormComponents/UrlItem/UrlItem.tsx +2 -3
- package/src/components/Renderer/BaseRenderer.tsx +4 -3
- package/src/hooks/useGroupTableRows.ts +4 -9
- package/src/hooks/{useInitialiseGroupTable.ts → useInitialiseGroupTableRows.ts} +15 -11
- package/src/hooks/useInitialiseRepeatGroups.ts +2 -2
- package/src/interfaces/repeatGroup.interface.ts +1 -1
- package/src/stores/questionnaireResponseStore.ts +7 -0
- package/src/stories/assets/questionnaires/QButtonTester.ts +117 -0
- package/src/stories/storybookWrappers/IdRemoverButtonForStorybook.tsx +3 -5
- package/{lib/hooks/useInitialiseGroupTable.js → src/tests/removeId.test.ts} +11 -14
- package/src/tests/test-data/removeIdSample.ts +101 -0
- package/src/theme/Theme.tsx +0 -2
- package/src/utils/calculatedExpression.ts +4 -4
- package/src/utils/extractObservation.ts +1 -1
- package/src/utils/manageForm.ts +1 -1
- package/src/utils/openChoice.ts +3 -3
- package/src/utils/removeRepeatId.ts +113 -0
- package/src/utils/repeatId.ts +0 -96
- package/src/utils/repopulateItems.ts +8 -8
- package/lib/hooks/useInitialiseGroupTable.d.ts +0 -4
- package/lib/hooks/useInitialiseGroupTable.js.map +0 -1
- package/lib/hooks/useNumberInput.d.ts +0 -3
- package/lib/hooks/useNumberInput.js.map +0 -1
- package/lib/hooks/useRepeatGroups.d.ts +0 -4
- package/lib/hooks/useRepeatGroups.js +0 -38
- package/lib/hooks/useRepeatGroups.js.map +0 -1
- package/lib/hooks/useStringInput.d.ts +0 -3
- package/lib/hooks/useStringInput.js +0 -32
- package/lib/hooks/useStringInput.js.map +0 -1
- package/src/hooks/useNumberInput.ts +0 -38
- package/src/hooks/useRepeatGroups.ts +0 -51
- package/src/hooks/useStringInput.ts +0 -39
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import type { QuestionnaireResponseItem } from 'fhir/r4';
|
|
19
|
-
import type {
|
|
19
|
+
import type { RepeatGroupSingleModel } from '../interfaces/repeatGroup.interface';
|
|
20
20
|
import { useMemo } from 'react';
|
|
21
21
|
import { generateExistingRepeatId, generateNewRepeatId } from '../utils/repeatId';
|
|
22
22
|
|
|
23
23
|
function useInitialiseRepeatGroups(
|
|
24
24
|
linkId: string,
|
|
25
25
|
qrItems: QuestionnaireResponseItem[]
|
|
26
|
-
):
|
|
26
|
+
): RepeatGroupSingleModel[] {
|
|
27
27
|
return useMemo(() => {
|
|
28
28
|
if (qrItems.length === 0) {
|
|
29
29
|
return [{ id: generateNewRepeatId(linkId), qrItem: null }];
|
|
@@ -30,12 +30,14 @@ import { createSelectors } from './selector';
|
|
|
30
30
|
import { validateQuestionnaire } from '../utils/validateQuestionnaire';
|
|
31
31
|
import { questionnaireStore } from './questionnaireStore';
|
|
32
32
|
import { createQuestionnaireResponseItemMap } from '../utils/questionnaireResponseStoreUtils/updatableResponseItems';
|
|
33
|
+
import { generateUniqueId } from '../utils/extractObservation';
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* QuestionnaireResponseStore properties and methods
|
|
36
37
|
* Properties can be accessed for fine-grain details.
|
|
37
38
|
* Methods are usually used internally, using them from an external source is not recommended.
|
|
38
39
|
*
|
|
40
|
+
* @property key - The React key of the questionnaireResponse, used internally for refreshing the BaseRenderer
|
|
39
41
|
* @property sourceResponse - The original response created when the form is first initialised i.e. empty, pre-populated, opened saved draft
|
|
40
42
|
* @property updatableResponse - The current state of the response that is being updated via form fields
|
|
41
43
|
* @property updatableResponseItems - Key-value pair of updatableResponse items `Record<linkId, QR.item(s)>`
|
|
@@ -53,6 +55,7 @@ import { createQuestionnaireResponseItemMap } from '../utils/questionnaireRespon
|
|
|
53
55
|
* @author Sean Fong
|
|
54
56
|
*/
|
|
55
57
|
export interface QuestionnaireResponseStoreType {
|
|
58
|
+
key: string;
|
|
56
59
|
sourceResponse: QuestionnaireResponse;
|
|
57
60
|
updatableResponse: QuestionnaireResponse;
|
|
58
61
|
updatableResponseItems: Record<string, QuestionnaireResponseItem[]>;
|
|
@@ -80,6 +83,7 @@ export interface QuestionnaireResponseStoreType {
|
|
|
80
83
|
*/
|
|
81
84
|
export const questionnaireResponseStore = createStore<QuestionnaireResponseStoreType>()(
|
|
82
85
|
(set, get) => ({
|
|
86
|
+
key: 'QR-initial-key',
|
|
83
87
|
sourceResponse: cloneDeep(emptyResponse),
|
|
84
88
|
updatableResponse: cloneDeep(emptyResponse),
|
|
85
89
|
updatableResponseItems: {},
|
|
@@ -108,6 +112,7 @@ export const questionnaireResponseStore = createStore<QuestionnaireResponseStore
|
|
|
108
112
|
});
|
|
109
113
|
|
|
110
114
|
set(() => ({
|
|
115
|
+
key: generateUniqueId('QR'),
|
|
111
116
|
sourceResponse: questionnaireResponse,
|
|
112
117
|
updatableResponse: questionnaireResponse,
|
|
113
118
|
updatableResponseItems: createQuestionnaireResponseItemMap(questionnaireResponse),
|
|
@@ -153,6 +158,7 @@ export const questionnaireResponseStore = createStore<QuestionnaireResponseStore
|
|
|
153
158
|
});
|
|
154
159
|
|
|
155
160
|
set(() => ({
|
|
161
|
+
key: generateUniqueId('QR'),
|
|
156
162
|
sourceResponse: savedResponse,
|
|
157
163
|
updatableResponse: savedResponse,
|
|
158
164
|
updatableResponseItems: createQuestionnaireResponseItemMap(savedResponse),
|
|
@@ -178,6 +184,7 @@ export const questionnaireResponseStore = createStore<QuestionnaireResponseStore
|
|
|
178
184
|
},
|
|
179
185
|
destroySourceResponse: () =>
|
|
180
186
|
set(() => ({
|
|
187
|
+
key: generateUniqueId('QR'),
|
|
181
188
|
sourceResponse: cloneDeep(emptyResponse),
|
|
182
189
|
updatableResponse: cloneDeep(emptyResponse),
|
|
183
190
|
updatableResponseItems: createQuestionnaireResponseItemMap(cloneDeep(emptyResponse)),
|
|
@@ -238,6 +238,67 @@ export const qButtonTester: Questionnaire = {
|
|
|
238
238
|
'https://healthterminologies.gov.au/fhir/ValueSet/australian-states-territories-2'
|
|
239
239
|
}
|
|
240
240
|
]
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
extension: [
|
|
244
|
+
{
|
|
245
|
+
url: 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-itemPopulationContext',
|
|
246
|
+
valueExpression: {
|
|
247
|
+
name: 'PostalAddressRepeat',
|
|
248
|
+
language: 'text/fhirpath',
|
|
249
|
+
expression: "%patient.address.where(type='postal')"
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
url: 'http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl',
|
|
254
|
+
valueCodeableConcept: {
|
|
255
|
+
coding: [
|
|
256
|
+
{
|
|
257
|
+
system: 'http://hl7.org/fhir/questionnaire-item-control',
|
|
258
|
+
code: 'gtable'
|
|
259
|
+
}
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
],
|
|
264
|
+
linkId: 'repeats-gtable',
|
|
265
|
+
type: 'group',
|
|
266
|
+
repeats: true,
|
|
267
|
+
text: 'Repeats Group Table Test',
|
|
268
|
+
item: [
|
|
269
|
+
{
|
|
270
|
+
extension: [
|
|
271
|
+
{
|
|
272
|
+
url: 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression',
|
|
273
|
+
valueExpression: {
|
|
274
|
+
language: 'text/fhirpath',
|
|
275
|
+
expression: '%PostalAddressRepeat.city'
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
],
|
|
279
|
+
linkId: 'repeats-gtable-string',
|
|
280
|
+
text: 'String',
|
|
281
|
+
type: 'string',
|
|
282
|
+
repeats: false
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
extension: [
|
|
286
|
+
{
|
|
287
|
+
url: 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression',
|
|
288
|
+
valueExpression: {
|
|
289
|
+
language: 'text/fhirpath',
|
|
290
|
+
expression: '%PostalAddressRepeat.state'
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
],
|
|
294
|
+
linkId: 'repeats-gtable-choice',
|
|
295
|
+
text: 'Choice',
|
|
296
|
+
type: 'choice',
|
|
297
|
+
repeats: false,
|
|
298
|
+
answerValueSet:
|
|
299
|
+
'https://healthterminologies.gov.au/fhir/ValueSet/australian-states-territories-2'
|
|
300
|
+
}
|
|
301
|
+
]
|
|
241
302
|
}
|
|
242
303
|
]
|
|
243
304
|
};
|
|
@@ -373,6 +434,62 @@ export const qrButtonTesterResponse: QuestionnaireResponse = {
|
|
|
373
434
|
]
|
|
374
435
|
}
|
|
375
436
|
]
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
linkId: 'repeats-gtable',
|
|
440
|
+
text: 'Repeats Group Table Test',
|
|
441
|
+
item: [
|
|
442
|
+
{
|
|
443
|
+
linkId: 'repeats-gtable-string',
|
|
444
|
+
text: 'String',
|
|
445
|
+
answer: [
|
|
446
|
+
{
|
|
447
|
+
valueString: 'Group Table String 1'
|
|
448
|
+
}
|
|
449
|
+
]
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
linkId: 'repeats-gtable-choice',
|
|
453
|
+
text: 'Choice',
|
|
454
|
+
answer: [
|
|
455
|
+
{
|
|
456
|
+
valueCoding: {
|
|
457
|
+
system:
|
|
458
|
+
'https://healthterminologies.gov.au/fhir/CodeSystem/australian-states-territories-1',
|
|
459
|
+
code: 'NSW'
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
]
|
|
463
|
+
}
|
|
464
|
+
]
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
linkId: 'repeats-gtable',
|
|
468
|
+
text: 'Repeats Group Table Test',
|
|
469
|
+
item: [
|
|
470
|
+
{
|
|
471
|
+
linkId: 'repeats-gtable-string',
|
|
472
|
+
text: 'String',
|
|
473
|
+
answer: [
|
|
474
|
+
{
|
|
475
|
+
valueString: 'Group Table String 2'
|
|
476
|
+
}
|
|
477
|
+
]
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
linkId: 'repeats-gtable-choice',
|
|
481
|
+
text: 'Choice',
|
|
482
|
+
answer: [
|
|
483
|
+
{
|
|
484
|
+
valueCoding: {
|
|
485
|
+
system:
|
|
486
|
+
'https://healthterminologies.gov.au/fhir/CodeSystem/australian-states-territories-1',
|
|
487
|
+
code: 'SA'
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
]
|
|
491
|
+
}
|
|
492
|
+
]
|
|
376
493
|
}
|
|
377
494
|
],
|
|
378
495
|
|
|
@@ -20,8 +20,7 @@ import React from 'react';
|
|
|
20
20
|
import type { Questionnaire, QuestionnaireResponse } from 'fhir/r4';
|
|
21
21
|
import { Box, IconButton, Tooltip } from '@mui/material';
|
|
22
22
|
import ContentCutIcon from '@mui/icons-material/ContentCut';
|
|
23
|
-
import {
|
|
24
|
-
import { removeInternalIdsFromResponse } from '../../utils/manageForm';
|
|
23
|
+
import { buildForm, removeInternalIdsFromResponse } from '../../utils/manageForm';
|
|
25
24
|
|
|
26
25
|
interface IdRemoverButtonProps {
|
|
27
26
|
questionnaire: Questionnaire;
|
|
@@ -31,10 +30,9 @@ interface IdRemoverButtonProps {
|
|
|
31
30
|
function IdRemoverButtonForStorybook(props: IdRemoverButtonProps) {
|
|
32
31
|
const { questionnaire, questionnaireResponse } = props;
|
|
33
32
|
|
|
34
|
-
const updateResponse = useQuestionnaireResponseStore.use.updateResponse();
|
|
35
|
-
|
|
36
33
|
async function handleRemoveIds() {
|
|
37
|
-
|
|
34
|
+
const updatedResponse = removeInternalIdsFromResponse(questionnaire, questionnaireResponse);
|
|
35
|
+
await buildForm(questionnaire, updatedResponse);
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
return (
|
|
@@ -14,17 +14,14 @@
|
|
|
14
14
|
* See the License for the specific language governing permissions and
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
export default useInitialiseGroupTable;
|
|
30
|
-
//# sourceMappingURL=useInitialiseGroupTable.js.map
|
|
17
|
+
|
|
18
|
+
import { expect, test } from '@jest/globals';
|
|
19
|
+
import { removeInternalIdsFromResponse } from '../utils';
|
|
20
|
+
import { qrRemoveIdResult, qrRemoveIdSample } from './test-data/removeIdSample';
|
|
21
|
+
import { qMyPatient } from '../stories/assets/questionnaires/QIdRemoverDebugger';
|
|
22
|
+
|
|
23
|
+
test('item.initial is properly pre-filled into QuestionnaireResponse', () => {
|
|
24
|
+
const outputResponse = removeInternalIdsFromResponse(qMyPatient, qrRemoveIdSample);
|
|
25
|
+
|
|
26
|
+
expect(outputResponse).toStrictEqual(qrRemoveIdResult);
|
|
27
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { QuestionnaireResponse } from 'fhir/r4';
|
|
2
|
+
|
|
3
|
+
export const qrRemoveIdSample: QuestionnaireResponse = {
|
|
4
|
+
resourceType: 'QuestionnaireResponse',
|
|
5
|
+
status: 'in-progress',
|
|
6
|
+
questionnaire: 'http://canshare.co.nz/questionnaire/myPatient1',
|
|
7
|
+
item: [
|
|
8
|
+
{
|
|
9
|
+
linkId: 'myPatient1',
|
|
10
|
+
text: 'myPatient1',
|
|
11
|
+
item: [
|
|
12
|
+
{
|
|
13
|
+
linkId: 'myPatient1.name',
|
|
14
|
+
text: 'name *',
|
|
15
|
+
item: [
|
|
16
|
+
{
|
|
17
|
+
linkId: 'myPatient1.name.first',
|
|
18
|
+
text: 'firstName *',
|
|
19
|
+
answer: [
|
|
20
|
+
{
|
|
21
|
+
id: 'myPatient1.name.first-repeat-000000',
|
|
22
|
+
valueString: '1st firstName 1.0'
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
linkId: 'myPatient1.name',
|
|
30
|
+
text: 'name *',
|
|
31
|
+
item: [
|
|
32
|
+
{
|
|
33
|
+
linkId: 'myPatient1.name.first',
|
|
34
|
+
text: 'firstName *',
|
|
35
|
+
answer: [
|
|
36
|
+
{
|
|
37
|
+
id: 'myPatient1.name.first-repeat-000000',
|
|
38
|
+
valueString: '2nd firstName 1.0'
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'myPatient1.name.first-repeat-O-r6YSxx81TBFf_yiHWk6',
|
|
42
|
+
valueString: '2nd firstName 2.0'
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: 'myPatient1.name.first-repeat-ZQR77gdy6utsT_JkbuHKc'
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const qrRemoveIdResult: QuestionnaireResponse = {
|
|
57
|
+
resourceType: 'QuestionnaireResponse',
|
|
58
|
+
status: 'in-progress',
|
|
59
|
+
questionnaire: 'http://canshare.co.nz/questionnaire/myPatient1',
|
|
60
|
+
item: [
|
|
61
|
+
{
|
|
62
|
+
linkId: 'myPatient1',
|
|
63
|
+
text: 'myPatient1',
|
|
64
|
+
item: [
|
|
65
|
+
{
|
|
66
|
+
linkId: 'myPatient1.name',
|
|
67
|
+
text: 'name *',
|
|
68
|
+
item: [
|
|
69
|
+
{
|
|
70
|
+
linkId: 'myPatient1.name.first',
|
|
71
|
+
text: 'firstName *',
|
|
72
|
+
answer: [
|
|
73
|
+
{
|
|
74
|
+
valueString: '1st firstName 1.0'
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
linkId: 'myPatient1.name',
|
|
82
|
+
text: 'name *',
|
|
83
|
+
item: [
|
|
84
|
+
{
|
|
85
|
+
linkId: 'myPatient1.name.first',
|
|
86
|
+
text: 'firstName *',
|
|
87
|
+
answer: [
|
|
88
|
+
{
|
|
89
|
+
valueString: '2nd firstName 1.0'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
valueString: '2nd firstName 2.0'
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
};
|
package/src/theme/Theme.tsx
CHANGED
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
StyledEngineProvider,
|
|
24
24
|
ThemeProvider as MUIThemeProvider
|
|
25
25
|
} from '@mui/material/styles';
|
|
26
|
-
import CssBaseline from '@mui/material/CssBaseline';
|
|
27
26
|
import palette from './palette';
|
|
28
27
|
import typography from './typography';
|
|
29
28
|
import CustomGlobalStyles from './customGlobalStyles';
|
|
@@ -102,7 +101,6 @@ export function RendererThemeProvider({ children }: { children: ReactNode }) {
|
|
|
102
101
|
return (
|
|
103
102
|
<StyledEngineProvider injectFirst>
|
|
104
103
|
<MUIThemeProvider theme={theme}>
|
|
105
|
-
<CssBaseline />
|
|
106
104
|
<CustomGlobalStyles />
|
|
107
105
|
{children}
|
|
108
106
|
</MUIThemeProvider>
|
|
@@ -27,7 +27,6 @@ import type {
|
|
|
27
27
|
QuestionnaireResponseItem,
|
|
28
28
|
QuestionnaireResponseItemAnswer
|
|
29
29
|
} from 'fhir/r4';
|
|
30
|
-
import _isEqual from 'lodash/isEqual';
|
|
31
30
|
import { emptyResponse } from './emptyResource';
|
|
32
31
|
import { createFhirPathContext } from './fhirpath';
|
|
33
32
|
import { getQrItemsIndex, mapQItemsIndex } from './mapItem';
|
|
@@ -35,6 +34,7 @@ import { updateQrItemsInGroup } from './qrItem';
|
|
|
35
34
|
import cloneDeep from 'lodash.clonedeep';
|
|
36
35
|
import dayjs from 'dayjs';
|
|
37
36
|
import { updateQuestionnaireResponse } from './genericRecursive';
|
|
37
|
+
import isEqual from 'lodash.isequal';
|
|
38
38
|
|
|
39
39
|
interface EvaluateInitialCalculatedExpressionsParams {
|
|
40
40
|
initialResponse: QuestionnaireResponse;
|
|
@@ -60,7 +60,7 @@ export function evaluateInitialCalculatedExpressions(
|
|
|
60
60
|
|
|
61
61
|
// Return early if initialResponse is empty or there are no calculated expressions to evaluate
|
|
62
62
|
if (
|
|
63
|
-
|
|
63
|
+
isEqual(initialResponse, cloneDeep(emptyResponse)) ||
|
|
64
64
|
Object.keys(calculatedExpressions).length === 0
|
|
65
65
|
) {
|
|
66
66
|
return {
|
|
@@ -93,7 +93,7 @@ export function evaluateInitialCalculatedExpressions(
|
|
|
93
93
|
);
|
|
94
94
|
|
|
95
95
|
// Only update calculatedExpressions if length of result array > 0
|
|
96
|
-
if (result.length > 0 && !
|
|
96
|
+
if (result.length > 0 && !isEqual(calcExpression.value, result[0])) {
|
|
97
97
|
calcExpression.value = result[0];
|
|
98
98
|
}
|
|
99
99
|
} catch (e) {
|
|
@@ -136,7 +136,7 @@ export function evaluateCalculatedExpressions(
|
|
|
136
136
|
|
|
137
137
|
// Update calculatedExpressions if length of result array > 0
|
|
138
138
|
// Only update when current calcExpression value is different from the result, otherwise it will result in an infinite loop as per issue #733
|
|
139
|
-
if (result.length > 0 && !
|
|
139
|
+
if (result.length > 0 && !isEqual(calcExpression.value, result[0])) {
|
|
140
140
|
isUpdated = true;
|
|
141
141
|
calcExpression.value = result[0];
|
|
142
142
|
}
|
package/src/utils/manageForm.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { readEncounter, readPatient, readUser } from '../api/smartClient';
|
|
|
11
11
|
import type Client from 'fhirclient/lib/Client';
|
|
12
12
|
import cloneDeep from 'lodash.clonedeep';
|
|
13
13
|
import { updateQuestionnaireResponse } from './genericRecursive';
|
|
14
|
-
import { removeInternalRepeatIdsRecursive } from './
|
|
14
|
+
import { removeInternalRepeatIdsRecursive } from './removeRepeatId';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Build the form with an initial Questionnaire and an optional filled QuestionnaireResponse.
|
package/src/utils/openChoice.ts
CHANGED
|
@@ -23,7 +23,7 @@ import type {
|
|
|
23
23
|
} from 'fhir/r4';
|
|
24
24
|
import { OpenChoiceItemControl } from '../interfaces/choice.enum';
|
|
25
25
|
import { isSpecificItemControl } from './itemControl';
|
|
26
|
-
import
|
|
26
|
+
import isEqual from 'lodash.isequal';
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Update open choice answer based on open label value
|
|
@@ -100,7 +100,7 @@ export function updateOpenLabelAnswer(
|
|
|
100
100
|
|
|
101
101
|
// Old open label answer equals to new open label answer
|
|
102
102
|
// This should not happen, but return oldQrItem
|
|
103
|
-
if (
|
|
103
|
+
if (isEqual(oldOpenLabelAnswer, newOpenLabelAnswer)) {
|
|
104
104
|
return oldQrItem;
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -122,7 +122,7 @@ export function getOldOpenLabelAnswer(
|
|
|
122
122
|
options: QuestionnaireItemAnswerOption[]
|
|
123
123
|
): QuestionnaireResponseItemAnswer | null {
|
|
124
124
|
const openLabelAnswer = answers.find(
|
|
125
|
-
(answer) => !options.some((option) =>
|
|
125
|
+
(answer) => !options.some((option) => isEqual(option, answer))
|
|
126
126
|
);
|
|
127
127
|
return openLabelAnswer ?? null;
|
|
128
128
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 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 type {
|
|
19
|
+
QuestionnaireItem,
|
|
20
|
+
QuestionnaireResponseItem,
|
|
21
|
+
QuestionnaireResponseItemAnswer
|
|
22
|
+
} from 'fhir/r4';
|
|
23
|
+
import { getQrItemsIndex, mapQItemsIndex } from './mapItem';
|
|
24
|
+
|
|
25
|
+
export function removeInternalRepeatIdsRecursive(
|
|
26
|
+
qItem: QuestionnaireItem,
|
|
27
|
+
qrItemOrItems: QuestionnaireResponseItem | QuestionnaireResponseItem[] | null
|
|
28
|
+
): QuestionnaireResponseItem | QuestionnaireResponseItem[] | null {
|
|
29
|
+
// Process repeating group items separately
|
|
30
|
+
const hasMultipleAnswers = Array.isArray(qrItemOrItems);
|
|
31
|
+
if (hasMultipleAnswers) {
|
|
32
|
+
return removeInternalRepeatIdsFromRepeatGroup(qItem, qrItemOrItems);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// At this point qrItemOrItems is a single QuestionnaireResponseItem
|
|
36
|
+
const qrItem = qrItemOrItems;
|
|
37
|
+
|
|
38
|
+
// Process items with child items
|
|
39
|
+
const childQItems = qItem.item ?? [];
|
|
40
|
+
const childQrItems = qrItem?.item ?? [];
|
|
41
|
+
const updatedChildQrItems: QuestionnaireResponseItem[] = [];
|
|
42
|
+
if (childQItems.length > 0) {
|
|
43
|
+
const indexMap = mapQItemsIndex(qItem);
|
|
44
|
+
const qrItemsByIndex = getQrItemsIndex(childQItems, childQrItems, indexMap);
|
|
45
|
+
|
|
46
|
+
// Iterate child items
|
|
47
|
+
for (const [index, childQItem] of childQItems.entries()) {
|
|
48
|
+
const childQRItemOrItems = qrItemsByIndex[index];
|
|
49
|
+
|
|
50
|
+
const updatedChildQRItemOrItems = removeInternalRepeatIdsRecursive(
|
|
51
|
+
childQItem,
|
|
52
|
+
childQRItemOrItems ?? null
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
if (Array.isArray(updatedChildQRItemOrItems)) {
|
|
56
|
+
if (updatedChildQRItemOrItems.length > 0) {
|
|
57
|
+
updatedChildQrItems.push(...updatedChildQRItemOrItems);
|
|
58
|
+
}
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (updatedChildQRItemOrItems) {
|
|
63
|
+
updatedChildQrItems.push(updatedChildQRItemOrItems);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Construct updated qrItem
|
|
69
|
+
return removeInternalRepeatIdsFromItem(qItem, qrItem, updatedChildQrItems);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function removeInternalRepeatIdsFromRepeatGroup(
|
|
73
|
+
qItem: QuestionnaireItem,
|
|
74
|
+
qrItems: QuestionnaireResponseItem[]
|
|
75
|
+
) {
|
|
76
|
+
if (!qItem.item) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return qrItems
|
|
81
|
+
.flatMap((childQrItem) => removeInternalRepeatIdsRecursive(qItem, childQrItem))
|
|
82
|
+
.filter((childQRItem): childQRItem is QuestionnaireResponseItem => !!childQRItem);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function removeInternalRepeatIdsFromItem(
|
|
86
|
+
qItem: QuestionnaireItem,
|
|
87
|
+
qrItem: QuestionnaireResponseItem | null,
|
|
88
|
+
childQrItems: QuestionnaireResponseItem[]
|
|
89
|
+
): QuestionnaireResponseItem | null {
|
|
90
|
+
if (!qrItem) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Remove internal repeatId from all answers
|
|
95
|
+
const updatedAnswers: QuestionnaireResponseItemAnswer[] =
|
|
96
|
+
qrItem.answer
|
|
97
|
+
?.map(
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
99
|
+
({ id, ...rest }) => {
|
|
100
|
+
return {
|
|
101
|
+
...rest
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
.filter((answer) => !!answer && Object.keys(answer).length > 0) ?? [];
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
linkId: qItem.linkId,
|
|
109
|
+
...(qItem.text && { text: qItem.text }),
|
|
110
|
+
...(childQrItems.length > 0 && { item: childQrItems }),
|
|
111
|
+
...(updatedAnswers.length > 0 && { answer: updatedAnswers })
|
|
112
|
+
};
|
|
113
|
+
}
|