@aehrc/smart-forms-renderer 0.40.0 → 0.40.2

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 (108) hide show
  1. package/lib/components/FormComponents/ItemParts/ItemFieldGrid.js +6 -2
  2. package/lib/components/FormComponents/ItemParts/ItemFieldGrid.js.map +1 -1
  3. package/lib/components/FormComponents/RepeatGroup/RepeatGroup.js +3 -3
  4. package/lib/components/FormComponents/RepeatGroup/RepeatGroup.js.map +1 -1
  5. package/lib/components/FormComponents/RepeatGroup/RepeatGroupView.js +6 -6
  6. package/lib/components/FormComponents/RepeatGroup/RepeatGroupView.js.map +1 -1
  7. package/lib/components/FormComponents/RepeatItem/RepeatItem.js +5 -5
  8. package/lib/components/FormComponents/RepeatItem/RepeatItem.js.map +1 -1
  9. package/lib/components/FormComponents/Tables/GroupTable.js +10 -10
  10. package/lib/components/FormComponents/Tables/GroupTable.js.map +1 -1
  11. package/lib/components/FormComponents/Tables/GroupTableBody.d.ts +1 -1
  12. package/lib/components/FormComponents/Tables/GroupTableBody.js +3 -3
  13. package/lib/components/FormComponents/Tables/GroupTableBody.js.map +1 -1
  14. package/lib/components/FormComponents/Tables/GroupTableRow.d.ts +1 -1
  15. package/lib/components/FormComponents/Tables/GroupTableRow.js +4 -4
  16. package/lib/components/FormComponents/Tables/GroupTableRow.js.map +1 -1
  17. package/lib/components/FormComponents/Tables/GroupTableView.d.ts +1 -1
  18. package/lib/components/Renderer/FormTopLevelItem.js +13 -1
  19. package/lib/components/Renderer/FormTopLevelItem.js.map +1 -1
  20. package/lib/hooks/useDateValidation.js +2 -2
  21. package/lib/hooks/useDateValidation.js.map +1 -1
  22. package/lib/hooks/useGroupTableRows.d.ts +1 -1
  23. package/lib/hooks/useGroupTableRows.js +3 -3
  24. package/lib/hooks/useGroupTableRows.js.map +1 -1
  25. package/lib/hooks/useInitialiseGroupTable.d.ts +1 -1
  26. package/lib/hooks/useInitialiseGroupTable.js +10 -16
  27. package/lib/hooks/useInitialiseGroupTable.js.map +1 -1
  28. package/lib/hooks/useInitialiseRepeatAnswers.d.ts +1 -1
  29. package/lib/hooks/useInitialiseRepeatAnswers.js +9 -12
  30. package/lib/hooks/useInitialiseRepeatAnswers.js.map +1 -1
  31. package/lib/hooks/useInitialiseRepeatGroups.d.ts +2 -2
  32. package/lib/hooks/useInitialiseRepeatGroups.js +11 -20
  33. package/lib/hooks/useInitialiseRepeatGroups.js.map +1 -1
  34. package/lib/hooks/useRepeatGroups.js +6 -2
  35. package/lib/hooks/useRepeatGroups.js.map +1 -1
  36. package/lib/index.d.ts +1 -1
  37. package/lib/index.js +1 -1
  38. package/lib/index.js.map +1 -1
  39. package/lib/interfaces/groupTable.interface.d.ts +1 -1
  40. package/lib/interfaces/repeatGroup.interface.d.ts +1 -1
  41. package/lib/theme/palette.js +0 -4
  42. package/lib/theme/palette.js.map +1 -1
  43. package/lib/utils/groupTable.js +1 -1
  44. package/lib/utils/groupTable.js.map +1 -1
  45. package/lib/utils/index.d.ts +1 -1
  46. package/lib/utils/index.js +1 -1
  47. package/lib/utils/index.js.map +1 -1
  48. package/lib/utils/manageForm.d.ts +7 -0
  49. package/lib/utils/manageForm.js +15 -1
  50. package/lib/utils/manageForm.js.map +1 -1
  51. package/lib/utils/repeatId.d.ts +4 -0
  52. package/lib/utils/repeatId.js +93 -0
  53. package/lib/utils/repeatId.js.map +1 -0
  54. package/package.json +1 -1
  55. package/src/components/FormComponents/ItemParts/ItemFieldGrid.tsx +8 -2
  56. package/src/components/FormComponents/RepeatGroup/RepeatGroup.tsx +3 -3
  57. package/src/components/FormComponents/RepeatGroup/RepeatGroupView.tsx +6 -6
  58. package/src/components/FormComponents/RepeatItem/RepeatItem.tsx +7 -5
  59. package/src/components/FormComponents/Tables/GroupTable.tsx +13 -10
  60. package/src/components/FormComponents/Tables/GroupTableBody.tsx +5 -5
  61. package/src/components/FormComponents/Tables/GroupTableRow.tsx +5 -5
  62. package/src/components/FormComponents/Tables/GroupTableView.tsx +1 -1
  63. package/src/components/Renderer/FormTopLevelItem.tsx +33 -1
  64. package/src/hooks/useDateValidation.tsx +2 -2
  65. package/src/hooks/useGroupTableRows.ts +3 -3
  66. package/src/hooks/useInitialiseGroupTable.ts +13 -17
  67. package/src/hooks/useInitialiseRepeatAnswers.ts +9 -12
  68. package/src/hooks/useInitialiseRepeatGroups.ts +14 -25
  69. package/src/hooks/useRepeatGroups.ts +8 -4
  70. package/src/index.ts +1 -0
  71. package/src/interfaces/groupTable.interface.ts +1 -1
  72. package/src/interfaces/repeatGroup.interface.ts +1 -1
  73. package/src/stories/assets/questionnaires/QIdRemoverDebugger.ts +161 -0
  74. package/src/stories/storybookWrappers/BuildFormButtonForStorybook.tsx +1 -1
  75. package/src/stories/storybookWrappers/IdRemoverButtonForStorybook.tsx +51 -0
  76. package/src/stories/storybookWrappers/IdRemoverDebuggerWrapperForStorybook.tsx +84 -0
  77. package/src/stories/testing/IdRemoverDebuggerWrapper.stories.tsx +39 -0
  78. package/src/tests/extractObservation.test.ts +2 -5
  79. package/src/theme/palette.ts +0 -4
  80. package/src/utils/groupTable.ts +1 -1
  81. package/src/utils/index.ts +7 -1
  82. package/src/utils/manageForm.ts +28 -1
  83. package/src/utils/repeatId.ts +123 -0
  84. package/CHANGELOG.md +0 -43
  85. package/lib/hooks/useRepeatAnswers.d.ts +0 -4
  86. package/lib/hooks/useRepeatAnswers.js +0 -34
  87. package/lib/hooks/useRepeatAnswers.js.map +0 -1
  88. package/lib/interfaces/repeatItem.interface.d.ts +0 -5
  89. package/lib/interfaces/repeatItem.interface.js +0 -2
  90. package/lib/interfaces/repeatItem.interface.js.map +0 -1
  91. package/lib/utils/answerExpression.d.ts +0 -18
  92. package/lib/utils/answerExpression.js +0 -133
  93. package/lib/utils/answerExpression.js.map +0 -1
  94. package/lib/utils/dynamicValueSet.d.ts +0 -5
  95. package/lib/utils/dynamicValueSet.js +0 -96
  96. package/lib/utils/dynamicValueSet.js.map +0 -1
  97. package/lib/utils/fhirpathAsyncUtils/fhirpath-async.d.ts +0 -14
  98. package/lib/utils/fhirpathAsyncUtils/fhirpath-async.js +0 -639
  99. package/lib/utils/fhirpathAsyncUtils/fhirpath-async.js.map +0 -1
  100. package/lib/utils/fhirpathAsyncUtils/outcome-utils.d.ts +0 -3
  101. package/lib/utils/fhirpathAsyncUtils/outcome-utils.js +0 -41
  102. package/lib/utils/fhirpathAsyncUtils/outcome-utils.js.map +0 -1
  103. package/lib/utils/questionnaireStoreUtils/extractPreferredTerminologyServerUrls.d.ts +0 -3
  104. package/lib/utils/questionnaireStoreUtils/extractPreferredTerminologyServerUrls.js +0 -34
  105. package/lib/utils/questionnaireStoreUtils/extractPreferredTerminologyServerUrls.js.map +0 -1
  106. package/lib/utils/updateQr.d.ts +0 -9
  107. package/lib/utils/updateQr.js +0 -55
  108. package/lib/utils/updateQr.js.map +0 -1
@@ -0,0 +1,84 @@
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
+ // @ts-ignore
19
+ import React from 'react';
20
+ import type { Questionnaire, QuestionnaireResponse } from 'fhir/r4';
21
+ import { BaseRenderer } from '../../components';
22
+ import { QueryClientProvider } from '@tanstack/react-query';
23
+ import { RendererThemeProvider } from '../../theme';
24
+ import { useBuildForm, useRendererQueryClient } from '../../hooks';
25
+ import { STORYBOOK_TERMINOLOGY_SERVER_URL } from './globals';
26
+ import IdRemoverButtonForStorybook from './IdRemoverButtonForStorybook';
27
+ import { Grid } from '@mui/material';
28
+ import { useQuestionnaireResponseStore, useQuestionnaireStore } from '../../stores';
29
+
30
+ interface IdRemoverDebuggerWrapperForStorybookProps {
31
+ questionnaire: Questionnaire;
32
+ questionnaireResponse?: QuestionnaireResponse;
33
+ }
34
+
35
+ /**
36
+ * This is a wrapper which for debugging answer/item IDs in repeating items and groups.
37
+ * It features a button to remove answer/item IDs from the QuestionnaireResponse.
38
+ *
39
+ * @author Sean Fong
40
+ */
41
+ function IdRemoverDebuggerWrapperForStorybook(props: IdRemoverDebuggerWrapperForStorybookProps) {
42
+ const { questionnaire, questionnaireResponse } = props;
43
+
44
+ const queryClient = useRendererQueryClient();
45
+
46
+ const focusedLinkId = useQuestionnaireStore.use.focusedLinkId();
47
+ const updatableResponse = useQuestionnaireResponseStore.use.updatableResponse();
48
+
49
+ const isBuilding = useBuildForm(
50
+ questionnaire,
51
+ questionnaireResponse,
52
+ undefined,
53
+ STORYBOOK_TERMINOLOGY_SERVER_URL
54
+ );
55
+
56
+ if (isBuilding) {
57
+ return <div>Loading...</div>;
58
+ }
59
+
60
+ return (
61
+ <RendererThemeProvider>
62
+ <QueryClientProvider client={queryClient}>
63
+ <div>
64
+ <Grid container>
65
+ <Grid item xs={6}>
66
+ <IdRemoverButtonForStorybook
67
+ questionnaire={questionnaire}
68
+ questionnaireResponse={updatableResponse}
69
+ />
70
+ <BaseRenderer />
71
+ </Grid>
72
+ <Grid item xs={6}>
73
+ <pre>{JSON.stringify(focusedLinkId, null, 2)}</pre>
74
+ ----
75
+ <pre style={{ fontSize: 10 }}>{JSON.stringify(updatableResponse, null, 2)}</pre>
76
+ </Grid>
77
+ </Grid>
78
+ </div>
79
+ </QueryClientProvider>
80
+ </RendererThemeProvider>
81
+ );
82
+ }
83
+
84
+ export default IdRemoverDebuggerWrapperForStorybook;
@@ -0,0 +1,39 @@
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 { Meta, StoryObj } from '@storybook/react';
19
+ import IdRemoverDebuggerWrapperForStorybook from '../storybookWrappers/IdRemoverDebuggerWrapperForStorybook';
20
+ import { qMyPatient } from '../assets/questionnaires/QIdRemoverDebugger';
21
+
22
+ // More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
23
+ const meta = {
24
+ title: 'Component/Testing/ID Remover Debugger',
25
+ component: IdRemoverDebuggerWrapperForStorybook,
26
+ // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
27
+ tags: []
28
+ } satisfies Meta<typeof IdRemoverDebuggerWrapperForStorybook>;
29
+
30
+ export default meta;
31
+ type Story = StoryObj<typeof meta>;
32
+
33
+ // More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
34
+
35
+ export const MyPatient: Story = {
36
+ args: {
37
+ questionnaire: qMyPatient
38
+ }
39
+ };
@@ -1,10 +1,7 @@
1
1
  import type { Questionnaire, QuestionnaireResponse } from 'fhir/r4';
2
2
 
3
- import {
4
- Extractable,
5
- extractObservationBased,
6
- mapQItemsExtractable
7
- } from '../utils/extractObservation';
3
+ import type { Extractable } from '../utils/extractObservation';
4
+ import { extractObservationBased, mapQItemsExtractable } from '../utils/extractObservation';
8
5
  import {
9
6
  observationResults,
10
7
  qExtractSample,
@@ -77,10 +77,6 @@ const palette: PaletteOptions = {
77
77
  secondary: grey['600'],
78
78
  disabled: grey['500']
79
79
  },
80
- background: {
81
- paper: '#fff',
82
- default: grey['50']
83
- },
84
80
  customBackground: {
85
81
  neutral: '#F4F6F8'
86
82
  },
@@ -32,6 +32,6 @@ export function reorderRows(
32
32
 
33
33
  export function getGroupTableItemsToUpdate(tableRows: GroupTableRowModel[], selectedIds: string[]) {
34
34
  return tableRows
35
- .filter((row) => selectedIds.includes(row.nanoId))
35
+ .filter((row) => selectedIds.includes(row.id))
36
36
  .flatMap((singleRow) => (singleRow.qrItem ? [cloneDeep(singleRow.qrItem)] : []));
37
37
  }
@@ -15,7 +15,13 @@
15
15
  * limitations under the License.
16
16
  */
17
17
 
18
- export { buildForm, destroyForm, getResponse, removeEmptyAnswersFromResponse } from './manageForm';
18
+ export {
19
+ buildForm,
20
+ destroyForm,
21
+ getResponse,
22
+ removeEmptyAnswersFromResponse,
23
+ removeInternalIdsFromResponse
24
+ } from './manageForm';
19
25
  export { initialiseQuestionnaireResponse } from './initialise';
20
26
  export { isSpecificItemControl } from './itemControl';
21
27
  export { isRepeatItemAndNotCheckbox } from './qItem';
@@ -9,6 +9,9 @@ import { initialiseQuestionnaireResponse } from './initialise';
9
9
  import { removeEmptyAnswers } from './removeEmptyAnswers';
10
10
  import { readEncounter, readPatient, readUser } from '../api/smartClient';
11
11
  import type Client from 'fhirclient/lib/Client';
12
+ import cloneDeep from 'lodash.clonedeep';
13
+ import { updateQuestionnaireResponse } from './genericRecursive';
14
+ import { removeInternalRepeatIdsRecursive } from './repeatId';
12
15
 
13
16
  /**
14
17
  * Build the form with an initial Questionnaire and an optional filled QuestionnaireResponse.
@@ -95,7 +98,11 @@ export async function initialiseFhirClient(fhirClient: Client): Promise<void> {
95
98
  * @author Sean Fong
96
99
  */
97
100
  export function getResponse(): QuestionnaireResponse {
98
- return questionnaireResponseStore.getState().updatableResponse;
101
+ const cleanResponse = removeInternalIdsFromResponse(
102
+ questionnaireStore.getState().sourceQuestionnaire,
103
+ questionnaireResponseStore.getState().updatableResponse
104
+ );
105
+ return cloneDeep(cleanResponse);
99
106
  }
100
107
 
101
108
  /**
@@ -122,6 +129,26 @@ export function removeEmptyAnswersFromResponse(
122
129
  });
123
130
  }
124
131
 
132
+ /**
133
+ * Remove all instances of item.answer.id from the filled QuestionnaireResponse.
134
+ * These IDs are used internally for rendering repeating items, and can be safely left out of the final response.
135
+ *
136
+ * @author Sean Fong
137
+ */
138
+ export function removeInternalIdsFromResponse(
139
+ questionnaire: Questionnaire,
140
+ questionnaireResponse: QuestionnaireResponse
141
+ ): QuestionnaireResponse {
142
+ const questionnaireResponseToUpdate = cloneDeep(questionnaireResponse);
143
+
144
+ return updateQuestionnaireResponse(
145
+ questionnaire,
146
+ questionnaireResponseToUpdate,
147
+ removeInternalRepeatIdsRecursive,
148
+ undefined
149
+ );
150
+ }
151
+
125
152
  /**
126
153
  * Check if a QuestionnaireResponseItem has either an item or an answer property.
127
154
  *
@@ -0,0 +1,123 @@
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 { nanoid } from 'nanoid';
19
+ import type {
20
+ QuestionnaireItem,
21
+ QuestionnaireResponseItem,
22
+ QuestionnaireResponseItemAnswer
23
+ } from 'fhir/r4';
24
+ import { getQrItemsIndex, mapQItemsIndex } from './mapItem';
25
+
26
+ export function generateNewRepeatId(linkId: string): string {
27
+ return `${linkId}-repeat-${nanoid()}`;
28
+ }
29
+
30
+ export function generateExistingRepeatId(linkId: string, index: number): string {
31
+ const paddedIndex = index.toString().padStart(6, '0');
32
+ return `${linkId}-repeat-${paddedIndex}`;
33
+ }
34
+
35
+ export function removeInternalRepeatIdsRecursive(
36
+ qItem: QuestionnaireItem,
37
+ qrItemOrItems: QuestionnaireResponseItem | QuestionnaireResponseItem[] | null
38
+ ): QuestionnaireResponseItem | QuestionnaireResponseItem[] | null {
39
+ // Process repeating group items separately
40
+ const hasMultipleAnswers = Array.isArray(qrItemOrItems);
41
+ if (hasMultipleAnswers) {
42
+ return removeInternalRepeatIdsFromRepeatGroup(qItem, qrItemOrItems);
43
+ }
44
+
45
+ // At this point qrItemOrItems is a single QuestionnaireResponseItem
46
+ const qrItem = qrItemOrItems;
47
+
48
+ // Process items with child items
49
+ const childQItems = qItem.item ?? [];
50
+ const childQrItems = qrItem?.item ?? [];
51
+ const updatedChildQrItems: QuestionnaireResponseItem[] = [];
52
+ if (childQItems.length > 0) {
53
+ const indexMap = mapQItemsIndex(qItem);
54
+ const qrItemsByIndex = getQrItemsIndex(childQItems, childQrItems, indexMap);
55
+
56
+ // Iterate child items
57
+ for (const [index, childQItem] of childQItems.entries()) {
58
+ const childQRItemOrItems = qrItemsByIndex[index];
59
+
60
+ const updatedChildQRItemOrItems = removeInternalRepeatIdsRecursive(
61
+ childQItem,
62
+ childQRItemOrItems ?? null
63
+ );
64
+
65
+ if (Array.isArray(updatedChildQRItemOrItems)) {
66
+ if (updatedChildQRItemOrItems.length > 0) {
67
+ updatedChildQrItems.push(...updatedChildQRItemOrItems);
68
+ }
69
+ continue;
70
+ }
71
+
72
+ if (updatedChildQRItemOrItems) {
73
+ updatedChildQrItems.push(updatedChildQRItemOrItems);
74
+ }
75
+ }
76
+ }
77
+
78
+ // Construct updated qrItem
79
+ return removeInternalRepeatIdsFromItem(qItem, qrItem, updatedChildQrItems);
80
+ }
81
+
82
+ function removeInternalRepeatIdsFromRepeatGroup(
83
+ qItem: QuestionnaireItem,
84
+ qrItems: QuestionnaireResponseItem[]
85
+ ) {
86
+ if (!qItem.item) {
87
+ return [];
88
+ }
89
+
90
+ return qrItems
91
+ .flatMap((childQrItem) => removeInternalRepeatIdsRecursive(qItem, childQrItem))
92
+ .filter((childQRItem): childQRItem is QuestionnaireResponseItem => !!childQRItem);
93
+ }
94
+
95
+ function removeInternalRepeatIdsFromItem(
96
+ qItem: QuestionnaireItem,
97
+ qrItem: QuestionnaireResponseItem | null,
98
+ childQrItems: QuestionnaireResponseItem[]
99
+ ): QuestionnaireResponseItem | null {
100
+ if (!qrItem) {
101
+ return null;
102
+ }
103
+
104
+ // Remove internal repeatId from all answers
105
+ const updatedAnswers: QuestionnaireResponseItemAnswer[] =
106
+ qrItem.answer
107
+ ?.map(
108
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
109
+ ({ id, ...rest }) => {
110
+ return {
111
+ ...rest
112
+ };
113
+ }
114
+ )
115
+ .filter((answer) => !!answer && Object.keys(answer).length > 0) ?? [];
116
+
117
+ return {
118
+ linkId: qItem.linkId,
119
+ ...(qItem.text && { text: qItem.text }),
120
+ ...(childQrItems.length > 0 && { item: childQrItems }),
121
+ ...(updatedAnswers.length > 0 && { answer: updatedAnswers })
122
+ };
123
+ }
package/CHANGELOG.md DELETED
@@ -1,43 +0,0 @@
1
- # Change log
2
-
3
- This log documents significant changes for the [@aehrc/smart-forms-renderer](https://www.npmjs.com/package/@aehrc/smart-forms-renderer). This project follows
4
- [Semantic Versioning](http://semver.org/).
5
-
6
- Changelog only includes changes from version 0.36.0 onwards.
7
-
8
- ## [0.39.0] - 2024-09-06
9
- ### Changed
10
- - Refactored `repeat` items so that it tracks item instances using the QuestionnaireResponse, instead of using React's `useState`.
11
-
12
- Note: This is a huge change for performance improvements, and was able to pass all the end-to-end and Chromatic tests - but please proceed carefully and test thoroughly before using this version in production.
13
-
14
- ### Fixed
15
- - Fixed an issue where `string` and `text` items were automatically removing inputted trailing whitespaces.
16
-
17
- ## [0.38.4] - 2024-08-29
18
- ### Fixed
19
- - Fixed support for item.initial and item.answerOption.initialSelected for repeating groups.
20
-
21
- ## [0.38.3] - 2024-08-23
22
- ### Added
23
- - Added support for non-repeating group table (`gtable`) items.
24
-
25
- ## [0.38.2] - 2024-08-21
26
- ### Added
27
- - Added support for `Quantity` items. See documentation and Storybook for more details.
28
-
29
- ## [0.37.2] - 2024-08-19
30
- ### Fixed
31
- - Fixed a @aehrc/sdc-populate library dependency issue.
32
-
33
- ## [0.37.1] - 2024-08-05
34
- ### Added
35
- - Added support for `page` UI Control code from https://hl7.org/fhir/extensions/ValueSet-questionnaire-item-control.html.
36
-
37
- ## [0.36.1] - 2024-07-23
38
- ### Added
39
- - Add support for `Coding` type in calculatedExpressions for choice and open-choice items.
40
-
41
- ## [0.36.0] - 2024-07-22
42
- ### Added
43
- - Add Save-Extract-Write functionality (StructureMap-based) in the "Save as Final" button in the Smart Forms app.
@@ -1,4 +0,0 @@
1
- import type { Dispatch, SetStateAction } from 'react';
2
- import type { RepeatAnswer } from '../interfaces/repeatItem.interface';
3
- declare function useRepeatAnswers(valueFromProps: RepeatAnswer[]): [RepeatAnswer[], Dispatch<SetStateAction<RepeatAnswer[]>>];
4
- export default useRepeatAnswers;
@@ -1,34 +0,0 @@
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
- import { useEffect, useState } from 'react';
18
- import _isEqual from 'lodash/isEqual';
19
- function useRepeatAnswers(valueFromProps) {
20
- const [repeatAnswers, setRepeatAnswers] = useState(valueFromProps);
21
- useEffect(() => {
22
- const valueFromPropsQRItemAnswers = valueFromProps.map((answer) => answer.answer);
23
- const repeatAnswersQRItemAnswers = repeatAnswers.map((answer) => answer.answer);
24
- if (!_isEqual(valueFromPropsQRItemAnswers, repeatAnswersQRItemAnswers)) {
25
- setRepeatAnswers(valueFromProps);
26
- }
27
- },
28
- // Only trigger this effect if prop value changes
29
- // eslint-disable-next-line react-hooks/exhaustive-deps
30
- [valueFromProps]);
31
- return [repeatAnswers, setRepeatAnswers];
32
- }
33
- export default useRepeatAnswers;
34
- //# sourceMappingURL=useRepeatAnswers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useRepeatAnswers.js","sourceRoot":"","sources":["../../src/hooks/useRepeatAnswers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,SAAS,gBAAgB,CACvB,cAA8B;IAE9B,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;IAEnE,SAAS,CACP,GAAG,EAAE;QACH,MAAM,2BAA2B,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAClF,MAAM,0BAA0B,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAEhF,IAAI,CAAC,QAAQ,CAAC,2BAA2B,EAAE,0BAA0B,CAAC,EAAE;YACtE,gBAAgB,CAAC,cAAc,CAAC,CAAC;SAClC;IACH,CAAC;IACD,iDAAiD;IACjD,uDAAuD;IACvD,CAAC,cAAc,CAAC,CACjB,CAAC;IAEF,OAAO,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;AAC3C,CAAC;AAED,eAAe,gBAAgB,CAAC"}
@@ -1,5 +0,0 @@
1
- import type { QuestionnaireResponseItemAnswer } from 'fhir/r4';
2
- export interface RepeatAnswer {
3
- nanoId: string;
4
- answer: QuestionnaireResponseItemAnswer | null;
5
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=repeatItem.interface.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"repeatItem.interface.js","sourceRoot":"","sources":["../../src/interfaces/repeatItem.interface.ts"],"names":[],"mappings":""}
@@ -1,18 +0,0 @@
1
- import type { AnswerExpression } from '../interfaces/answerExpression.interface';
2
- import { type Expression, type QuestionnaireResponse, type QuestionnaireResponseItem } from 'fhir/r4';
3
- interface EvaluateInitialAnswerExpressionsParams {
4
- initialResponse: QuestionnaireResponse;
5
- initialResponseItemMap: Record<string, QuestionnaireResponseItem[]>;
6
- answerExpressions: Record<string, AnswerExpression>;
7
- variablesFhirPath: Record<string, Expression[]>;
8
- existingFhirPathContext: Record<string, any>;
9
- }
10
- export declare function evaluateInitialAnswerExpressions(params: EvaluateInitialAnswerExpressionsParams): Promise<{
11
- initialAnswerExpressions: Record<string, AnswerExpression>;
12
- updatedFhirPathContext: Record<string, any>;
13
- }>;
14
- export declare function evaluateAnswerExpressions(fhirPathContext: Record<string, any>, answerExpressions: Record<string, AnswerExpression>): {
15
- answerExpsIsUpdated: boolean;
16
- updatedAnswerExpressions: Record<string, AnswerExpression>;
17
- };
18
- export {};
@@ -1,133 +0,0 @@
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
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
- return new (P || (P = Promise))(function (resolve, reject) {
20
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
- step((generator = generator.apply(thisArg, _arguments || [])).next());
24
- });
25
- };
26
- import fhirpath from 'fhirpath';
27
- import fhirpath_r4_model from 'fhirpath/fhir-context/r4';
28
- import _isEqual from 'lodash/isEqual';
29
- import cloneDeep from 'lodash.clonedeep';
30
- import { emptyResponse } from './emptyResource';
31
- import { createFhirPathContext, evaluateTerminologyLinkIdVariables } from './fhirpath';
32
- export function evaluateInitialAnswerExpressions(params) {
33
- return __awaiter(this, void 0, void 0, function* () {
34
- const { initialResponse, initialResponseItemMap, answerExpressions, variablesFhirPath, existingFhirPathContext } = params;
35
- // Return early if initialResponse is empty or there are no answer expressions to evaluate
36
- if (_isEqual(initialResponse, cloneDeep(emptyResponse)) ||
37
- Object.keys(answerExpressions).length === 0) {
38
- return {
39
- initialAnswerExpressions: answerExpressions,
40
- updatedFhirPathContext: existingFhirPathContext
41
- };
42
- }
43
- const initialAnswerExpressions = Object.assign({}, answerExpressions);
44
- let updatedFhirPathContext = yield createFhirPathContext(initialResponse, initialResponseItemMap, variablesFhirPath, existingFhirPathContext);
45
- // Perform initial evaluation of terminology variables
46
- for (const linkId in variablesFhirPath) {
47
- updatedFhirPathContext = yield evaluateTerminologyLinkIdVariables(linkId, variablesFhirPath, updatedFhirPathContext);
48
- }
49
- for (const linkId in initialAnswerExpressions) {
50
- const answerExpression = initialAnswerExpressions[linkId];
51
- try {
52
- const result = fhirpath.evaluate({}, answerExpression.expression, updatedFhirPathContext, fhirpath_r4_model);
53
- // Update calculatedExpressions if length of result array > 0
54
- // Only update when current calcExpression value is different from the result, otherwise it will result in an infinite loop as per issue #733
55
- if (result.length > 0 && !_isEqual(answerExpression.options, result)) {
56
- answerExpression.options = getAnswerOptionsFromResults(result);
57
- answerExpression.version = answerExpression.version + 1;
58
- }
59
- // Update calculatedExpression value to null if no result is returned
60
- if (result.length === 0 && !!answerExpression.options) {
61
- // Only update if current options is not empty
62
- if (answerExpression.options.length > 0) {
63
- answerExpression.options = [];
64
- answerExpression.version = answerExpression.version + 1;
65
- }
66
- }
67
- }
68
- catch (e) {
69
- console.warn(e.message, `LinkId: ${linkId}\nExpression: ${answerExpression.options}`);
70
- }
71
- initialAnswerExpressions[linkId] = answerExpression;
72
- }
73
- return {
74
- initialAnswerExpressions,
75
- updatedFhirPathContext
76
- };
77
- });
78
- }
79
- export function evaluateAnswerExpressions(fhirPathContext, answerExpressions) {
80
- const updatedAnswerExpressions = Object.assign({}, answerExpressions);
81
- let isUpdated = false;
82
- for (const linkId in answerExpressions) {
83
- const answerExpression = answerExpressions[linkId];
84
- try {
85
- const result = fhirpath.evaluate({}, answerExpression.expression, fhirPathContext, fhirpath_r4_model);
86
- // Update calculatedExpressions if length of result array > 0
87
- // Only update when current calcExpression value is different from the result, otherwise it will result in an infinite loop as per issue #733
88
- if (result.length > 0 && !_isEqual(answerExpression.options, result)) {
89
- isUpdated = true;
90
- answerExpression.options = getAnswerOptionsFromResults(result);
91
- answerExpression.version = answerExpression.version + 1;
92
- }
93
- // Update calculatedExpression value to null if no result is returned
94
- if (result.length === 0 && !!answerExpression.options) {
95
- // Only update if current options is not empty
96
- if (answerExpression.options.length > 0) {
97
- isUpdated = true;
98
- answerExpression.options = [];
99
- answerExpression.version = answerExpression.version + 1;
100
- }
101
- }
102
- }
103
- catch (e) {
104
- console.warn(e.message, `LinkId: ${linkId}\nExpression: ${answerExpression.options}`);
105
- }
106
- updatedAnswerExpressions[linkId] = answerExpression;
107
- }
108
- return {
109
- answerExpsIsUpdated: isUpdated,
110
- updatedAnswerExpressions: updatedAnswerExpressions
111
- };
112
- }
113
- function getAnswerOptionsFromResults(result) {
114
- if (!Array.isArray(result)) {
115
- return [];
116
- }
117
- return result
118
- .map((item) => {
119
- var _a;
120
- if (item.system && item.code) {
121
- return {
122
- valueCoding: {
123
- system: item.system,
124
- code: item.code,
125
- display: (_a = item.display) !== null && _a !== void 0 ? _a : undefined
126
- }
127
- };
128
- }
129
- return item;
130
- })
131
- .filter((item) => typeof item === 'object');
132
- }
133
- //# sourceMappingURL=answerExpression.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"answerExpression.js","sourceRoot":"","sources":["../../src/utils/answerExpression.ts"],"names":[],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import type { DynamicValueSet } from '../interfaces/valueSet.interface';
2
- export declare function evaluateDynamicValueSets(fhirPathContext: Record<string, any>, dynamicValueSets: Record<string, DynamicValueSet>): {
3
- dynamicValueSetsIsUpdated: boolean;
4
- updatedDynamicValueSets: Record<string, DynamicValueSet>;
5
- };