@aehrc/smart-forms-renderer 0.33.0 → 0.34.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 (61) hide show
  1. package/lib/components/FormComponents/GroupItem/GroupAccordion.styles.d.ts +20 -0
  2. package/lib/components/FormComponents/GroupItem/GroupAccordion.styles.js +12 -0
  3. package/lib/components/FormComponents/GroupItem/GroupAccordion.styles.js.map +1 -0
  4. package/lib/components/FormComponents/GroupItem/GroupHeading.js +3 -2
  5. package/lib/components/FormComponents/GroupItem/GroupHeading.js.map +1 -1
  6. package/lib/components/FormComponents/GroupItem/GroupItem.js +2 -15
  7. package/lib/components/FormComponents/GroupItem/GroupItem.js.map +1 -1
  8. package/lib/components/FormComponents/GroupItem/GroupItem.styles.d.ts +1 -1
  9. package/lib/components/FormComponents/GroupItem/GroupItemSwitcher.d.ts +1 -2
  10. package/lib/components/FormComponents/GroupItem/GroupItemSwitcher.js +1 -1
  11. package/lib/components/FormComponents/GroupItem/GroupItemSwitcher.js.map +1 -1
  12. package/lib/components/FormComponents/GroupItem/GroupItemView.d.ts +16 -0
  13. package/lib/components/FormComponents/GroupItem/GroupItemView.js +62 -0
  14. package/lib/components/FormComponents/GroupItem/GroupItemView.js.map +1 -0
  15. package/lib/components/FormComponents/ItemParts/ItemLabelText.js +20 -6
  16. package/lib/components/FormComponents/ItemParts/ItemLabelText.js.map +1 -1
  17. package/lib/components/FormComponents/ItemParts/ItemLabelWrapper.js +4 -2
  18. package/lib/components/FormComponents/ItemParts/ItemLabelWrapper.js.map +1 -1
  19. package/lib/components/FormComponents/RepeatGroup/RepeatGroup.js +2 -37
  20. package/lib/components/FormComponents/RepeatGroup/RepeatGroup.js.map +1 -1
  21. package/lib/components/FormComponents/RepeatGroup/RepeatGroupView.d.ts +20 -0
  22. package/lib/components/FormComponents/RepeatGroup/RepeatGroupView.js +91 -0
  23. package/lib/components/FormComponents/RepeatGroup/RepeatGroupView.js.map +1 -0
  24. package/lib/components/FormComponents/SingleItem/SingleItem.js +13 -4
  25. package/lib/components/FormComponents/SingleItem/SingleItem.js.map +1 -1
  26. package/lib/components/FormComponents/SingleItem/SingleNestedItems.js +11 -7
  27. package/lib/components/FormComponents/SingleItem/SingleNestedItems.js.map +1 -1
  28. package/lib/components/Renderer/FormBodySingleCollapsible.js +5 -4
  29. package/lib/components/Renderer/FormBodySingleCollapsible.js.map +1 -1
  30. package/lib/theme/overrides/Accordion.js +1 -1
  31. package/lib/theme/overrides/Accordion.js.map +1 -1
  32. package/lib/utils/itemControl.d.ts +1 -0
  33. package/lib/utils/itemControl.js +9 -0
  34. package/lib/utils/itemControl.js.map +1 -1
  35. package/lib/utils/qItem.d.ts +2 -0
  36. package/lib/utils/qItem.js +14 -0
  37. package/lib/utils/qItem.js.map +1 -1
  38. package/package.json +3 -2
  39. package/src/components/FormComponents/GroupItem/GroupAccordion.styles.ts +12 -0
  40. package/src/components/FormComponents/GroupItem/GroupHeading.tsx +3 -3
  41. package/src/components/FormComponents/GroupItem/GroupItem.tsx +15 -39
  42. package/src/components/FormComponents/GroupItem/GroupItemSwitcher.tsx +2 -2
  43. package/src/components/FormComponents/GroupItem/GroupItemView.tsx +163 -0
  44. package/src/components/FormComponents/ItemParts/ItemLabelText.tsx +22 -11
  45. package/src/components/FormComponents/ItemParts/ItemLabelWrapper.tsx +8 -1
  46. package/src/components/FormComponents/RepeatGroup/RepeatGroup.tsx +11 -82
  47. package/src/components/FormComponents/RepeatGroup/RepeatGroupView.tsx +202 -0
  48. package/src/components/FormComponents/SingleItem/SingleItem.tsx +40 -11
  49. package/src/components/FormComponents/SingleItem/SingleNestedItems.tsx +24 -19
  50. package/src/components/Renderer/FormBodySingleCollapsible.tsx +7 -9
  51. package/src/stories/assets/questionnaires/QAdvancedControlAppearance.ts +333 -3
  52. package/src/stories/assets/questionnaires/QAdvancedTextApperance.ts +29 -0
  53. package/src/stories/assets/questionnaires/QDisplay.ts +82 -0
  54. package/src/stories/assets/questionnaires/QMbs715Tester.ts +32888 -0
  55. package/src/stories/itemTypes/Display.stories.tsx +11 -1
  56. package/src/stories/sdc/AdvancedControlAppearance.stories.tsx +26 -1
  57. package/src/stories/sdc/AdvancedTextAppearance.stories.tsx +7 -0
  58. package/src/stories/testing/Mbs715Tester.stories.tsx +57 -0
  59. package/src/theme/overrides/Accordion.ts +1 -1
  60. package/src/utils/itemControl.ts +14 -0
  61. package/src/utils/qItem.ts +24 -0
@@ -18,11 +18,13 @@
18
18
  import React, { memo } from 'react';
19
19
  import type { QuestionnaireItem } from 'fhir/r4';
20
20
  import { getMarkdownString, getXHtmlString } from '../../../utils/itemControl';
21
- import parse from 'html-react-parser';
21
+ import { default as htmlParse } from 'html-react-parser';
22
22
  import Box from '@mui/material/Box';
23
23
  import ReactMarkdown from 'react-markdown';
24
24
  import Typography from '@mui/material/Typography';
25
25
  import useDisplayCqfAndCalculatedExpression from '../../../hooks/useDisplayCqfAndCalculatedExpression';
26
+ import { structuredDataCapture } from 'fhir-sdc-helpers';
27
+ import { default as styleParse } from 'style-to-js';
26
28
 
27
29
  interface ItemLabelTextProps {
28
30
  qItem: QuestionnaireItem;
@@ -32,21 +34,18 @@ interface ItemLabelTextProps {
32
34
  const ItemLabelText = memo(function ItemLabelText(props: ItemLabelTextProps) {
33
35
  const { qItem, readOnly } = props;
34
36
 
37
+ let labelText = qItem.text ?? '';
38
+
35
39
  // Use calculatedExpressionString if available
36
- const calculatedExpressionString = useDisplayCqfAndCalculatedExpression(qItem);
40
+ const calculatedExpressionString = useDisplayCqfAndCalculatedExpression(qItem) ?? '';
37
41
  if (calculatedExpressionString) {
38
- return (
39
- <Typography color={readOnly ? 'text.disabled' : 'text.primary'} sx={{ mt: 0.25 }}>
40
- {calculatedExpressionString}
41
- </Typography>
42
- );
42
+ labelText = calculatedExpressionString;
43
43
  }
44
44
 
45
45
  // parse xHTML if found
46
46
  const xHtmlString = getXHtmlString(qItem);
47
-
48
47
  if (xHtmlString) {
49
- return <Box>{parse(xHtmlString)}</Box>;
48
+ return <Box>{htmlParse(xHtmlString)}</Box>;
50
49
  }
51
50
 
52
51
  // parse markdown if found
@@ -59,14 +58,26 @@ const ItemLabelText = memo(function ItemLabelText(props: ItemLabelTextProps) {
59
58
  );
60
59
  }
61
60
 
61
+ // labelText is empty, return null
62
+ if (!labelText) {
63
+ return null;
64
+ }
65
+
66
+ // parse styles if found
67
+ const stylesString = structuredDataCapture.getStyle(qItem._text);
68
+ if (stylesString) {
69
+ const styles = styleParse(stylesString);
70
+ return <div style={styles}>{labelText}</div>;
71
+ }
72
+
62
73
  if (qItem.type === 'group') {
63
- return <>{qItem.text}</>;
74
+ return <>{labelText}</>;
64
75
  }
65
76
 
66
77
  // parse regular text
67
78
  return (
68
79
  <Typography color={readOnly ? 'text.disabled' : 'text.primary'} sx={{ mt: 0.25 }}>
69
- {qItem.text}
80
+ {labelText}
70
81
  </Typography>
71
82
  );
72
83
  });
@@ -24,6 +24,7 @@ import ItemLabelText from './ItemLabelText';
24
24
  import Tooltip from '@mui/material/Tooltip';
25
25
  import Typography from '@mui/material/Typography';
26
26
  import useRenderingExtensions from '../../../hooks/useRenderingExtensions';
27
+ import Iconify from '../../Iconify/Iconify';
27
28
 
28
29
  interface LabelWrapperProps {
29
30
  qItem: QuestionnaireItem;
@@ -54,13 +55,19 @@ function ItemLabelWrapper(props: LabelWrapperProps) {
54
55
  }
55
56
  }}>
56
57
  <span>
57
- <Box display="flex" columnGap={0.4} justifyContent="space-between">
58
+ <Box display="flex" columnGap={0.4} justifyContent="space-between" alignItems="center">
58
59
  {required ? (
59
60
  <Typography color="red" sx={{ ml: -1.15 }}>
60
61
  *
61
62
  </Typography>
62
63
  ) : null}
63
64
  <ItemLabelText qItem={qItem} readOnly={readOnly} />
65
+ {displayFlyover !== '' ? (
66
+ <Iconify
67
+ icon="mdi:information-outline"
68
+ sx={{ height: 16, width: 16, mt: 0.25, ml: 0.25, color: 'text.secondary' }}
69
+ />
70
+ ) : null}
64
71
  </Box>
65
72
  </span>
66
73
  </Tooltip>
@@ -24,21 +24,11 @@ import type {
24
24
  } from '../../../interfaces/renderProps.interface';
25
25
  import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4';
26
26
  import useInitialiseRepeatGroups from '../../../hooks/useInitialiseRepeatGroups';
27
- import { QGroupContainerBox } from '../../Box.styles';
28
- import Card from '@mui/material/Card';
29
- import Collapse from '@mui/material/Collapse';
30
- import Divider from '@mui/material/Divider';
31
- import { TransitionGroup } from 'react-transition-group';
32
- import { createEmptyQrItem } from '../../../utils/qrItem';
33
27
  import { nanoid } from 'nanoid';
34
- import RepeatGroupItem from './RepeatGroupItem';
35
- import AddItemButton from './AddItemButton';
36
- import LabelWrapper from '../ItemParts/ItemLabelWrapper';
37
28
  import cloneDeep from 'lodash.clonedeep';
38
- import useReadOnly from '../../../hooks/useReadOnly';
39
- import Typography from '@mui/material/Typography';
40
29
  import { useQuestionnaireStore } from '../../../stores';
41
30
  import useRepeatGroups from '../../../hooks/useRepeatGroups';
31
+ import RepeatGroupView from './RepeatGroupView';
42
32
 
43
33
  interface RepeatGroupProps
44
34
  extends PropsWithQrRepeatGroupChangeHandler,
@@ -68,8 +58,6 @@ function RepeatGroup(props: RepeatGroupProps) {
68
58
 
69
59
  const mutateRepeatEnableWhenItems = useQuestionnaireStore.use.mutateRepeatEnableWhenItems();
70
60
 
71
- const readOnly = useReadOnly(qItem, parentIsReadOnly);
72
-
73
61
  const initialRepeatGroups = useInitialiseRepeatGroups(qItem, qrItems);
74
62
 
75
63
  const [repeatGroups, setRepeatGroups] = useRepeatGroups(initialRepeatGroups);
@@ -122,76 +110,17 @@ function RepeatGroup(props: RepeatGroupProps) {
122
110
  ]);
123
111
  }
124
112
 
125
- if (showMinimalView) {
126
- return (
127
- <QGroupContainerBox key={qItem.linkId} cardElevation={groupCardElevation} isRepeated={true}>
128
- <Card elevation={groupCardElevation} sx={{ p: 2 }}>
129
- {repeatGroups.map(({ nanoId, qrItem: nullableQrItem }, index) => {
130
- const answeredQrItem = createEmptyQrItem(qItem);
131
- if (nullableQrItem) {
132
- answeredQrItem.item = nullableQrItem.item;
133
- }
134
-
135
- return (
136
- <RepeatGroupItem
137
- key={nanoId}
138
- qItem={qItem}
139
- repeatGroupIndex={index}
140
- answeredQrItem={answeredQrItem}
141
- nullableQrItem={nullableQrItem}
142
- numOfRepeatGroups={repeatGroups.length}
143
- groupCardElevation={groupCardElevation + 1}
144
- showMinimalView={showMinimalView}
145
- parentIsReadOnly={parentIsReadOnly}
146
- onDeleteItem={() => handleDeleteItem(index)}
147
- onQrItemChange={(newQrItem) => handleAnswerChange(newQrItem, index)}
148
- />
149
- );
150
- })}
151
- </Card>
152
- </QGroupContainerBox>
153
- );
154
- }
155
-
156
113
  return (
157
- <QGroupContainerBox key={qItem.linkId} cardElevation={groupCardElevation} isRepeated={true}>
158
- <Card elevation={groupCardElevation} sx={{ p: 3, py: 2.5, mb: 3.5 }}>
159
- {qItem.text ? (
160
- <>
161
- <Typography variant="h6" color={readOnly ? 'text.secondary' : 'text.primary'}>
162
- <LabelWrapper qItem={qItem} readOnly={readOnly} />
163
- </Typography>
164
- <Divider sx={{ mt: 1, mb: 1.5 }} light />
165
- </>
166
- ) : null}
167
- <TransitionGroup>
168
- {repeatGroups.map(({ nanoId, qrItem: nullableQrItem }, index) => {
169
- const answeredQrItem = createEmptyQrItem(qItem);
170
- if (nullableQrItem) {
171
- answeredQrItem.item = nullableQrItem.item;
172
- }
173
-
174
- return (
175
- <Collapse key={nanoId} timeout={200}>
176
- <RepeatGroupItem
177
- qItem={qItem}
178
- repeatGroupIndex={index}
179
- answeredQrItem={answeredQrItem}
180
- nullableQrItem={nullableQrItem}
181
- numOfRepeatGroups={repeatGroups.length}
182
- groupCardElevation={groupCardElevation + 1}
183
- parentIsReadOnly={parentIsReadOnly}
184
- onDeleteItem={() => handleDeleteItem(index)}
185
- onQrItemChange={(newQrItem) => handleAnswerChange(newQrItem, index)}
186
- />
187
- </Collapse>
188
- );
189
- })}
190
- </TransitionGroup>
191
-
192
- <AddItemButton repeatGroups={repeatGroups} readOnly={readOnly} onAddItem={handleAddItem} />
193
- </Card>
194
- </QGroupContainerBox>
114
+ <RepeatGroupView
115
+ qItem={qItem}
116
+ repeatGroups={repeatGroups}
117
+ groupCardElevation={groupCardElevation}
118
+ showMinimalView={showMinimalView}
119
+ parentIsReadOnly={parentIsReadOnly}
120
+ onAnswerChange={handleAnswerChange}
121
+ onAddItem={handleAddItem}
122
+ onDeleteItem={handleDeleteItem}
123
+ />
195
124
  );
196
125
  }
197
126
 
@@ -0,0 +1,202 @@
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 React from 'react';
19
+ import type {
20
+ PropsWithParentIsReadOnlyAttribute,
21
+ PropsWithParentIsRepeatGroupAttribute,
22
+ PropsWithShowMinimalViewAttribute
23
+ } from '../../../interfaces/renderProps.interface';
24
+ import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4';
25
+ import { QGroupContainerBox } from '../../Box.styles';
26
+ import Card from '@mui/material/Card';
27
+ import Collapse from '@mui/material/Collapse';
28
+ import Divider from '@mui/material/Divider';
29
+ import { TransitionGroup } from 'react-transition-group';
30
+ import { createEmptyQrItem } from '../../../utils/qrItem';
31
+ import RepeatGroupItem from './RepeatGroupItem';
32
+ import AddItemButton from './AddItemButton';
33
+ import LabelWrapper from '../ItemParts/ItemLabelWrapper';
34
+ import Typography from '@mui/material/Typography';
35
+ import type { RepeatGroupSingle } from '../../../interfaces/repeatGroup.interface';
36
+ import useReadOnly from '../../../hooks/useReadOnly';
37
+ import { getGroupCollapsible } from '../../../utils/qItem';
38
+ import { GroupAccordion } from '../GroupItem/GroupAccordion.styles';
39
+ import AccordionSummary from '@mui/material/AccordionSummary';
40
+ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
41
+ import AccordionDetails from '@mui/material/AccordionDetails';
42
+
43
+ interface RepeatGroupViewProps
44
+ extends PropsWithShowMinimalViewAttribute,
45
+ PropsWithParentIsReadOnlyAttribute,
46
+ PropsWithParentIsRepeatGroupAttribute {
47
+ qItem: QuestionnaireItem;
48
+ repeatGroups: RepeatGroupSingle[];
49
+ groupCardElevation: number;
50
+ onAnswerChange: (newQrItem: QuestionnaireResponseItem, index: number) => void;
51
+ onAddItem: () => void;
52
+ onDeleteItem: (index: number) => void;
53
+ }
54
+
55
+ /**
56
+ * Main component to render a repeating, group Questionnaire item.
57
+ * Store and manages the state of multiple instances of GroupItem in a repeating group.
58
+ *
59
+ * @author Sean Fong
60
+ */
61
+ function RepeatGroupView(props: RepeatGroupViewProps) {
62
+ const {
63
+ qItem,
64
+ repeatGroups,
65
+ groupCardElevation,
66
+ showMinimalView,
67
+ parentIsReadOnly,
68
+ onAnswerChange,
69
+ onAddItem,
70
+ onDeleteItem
71
+ } = props;
72
+
73
+ const readOnly = useReadOnly(qItem, parentIsReadOnly);
74
+
75
+ if (showMinimalView) {
76
+ return (
77
+ <QGroupContainerBox key={qItem.linkId} cardElevation={groupCardElevation} isRepeated={true}>
78
+ <Card elevation={groupCardElevation} sx={{ p: 2 }}>
79
+ {repeatGroups.map(({ nanoId, qrItem: nullableQrItem }, index) => {
80
+ const answeredQrItem = createEmptyQrItem(qItem);
81
+ if (nullableQrItem) {
82
+ answeredQrItem.item = nullableQrItem.item;
83
+ }
84
+
85
+ return (
86
+ <RepeatGroupItem
87
+ key={nanoId}
88
+ qItem={qItem}
89
+ repeatGroupIndex={index}
90
+ answeredQrItem={answeredQrItem}
91
+ nullableQrItem={nullableQrItem}
92
+ numOfRepeatGroups={repeatGroups.length}
93
+ groupCardElevation={groupCardElevation + 1}
94
+ showMinimalView={showMinimalView}
95
+ parentIsReadOnly={parentIsReadOnly}
96
+ onDeleteItem={() => onDeleteItem(index)}
97
+ onQrItemChange={(newQrItem) => onAnswerChange(newQrItem, index)}
98
+ />
99
+ );
100
+ })}
101
+ </Card>
102
+ </QGroupContainerBox>
103
+ );
104
+ }
105
+
106
+ const groupIsCollapsible = getGroupCollapsible(qItem);
107
+ if (groupIsCollapsible) {
108
+ const isDefaultOpen = groupIsCollapsible === 'default-open';
109
+ return (
110
+ <GroupAccordion
111
+ disableGutters
112
+ defaultExpanded={isDefaultOpen}
113
+ elevation={groupCardElevation}
114
+ isRepeated={true}
115
+ slotProps={{
116
+ transition: { unmountOnExit: true, timeout: 250 }
117
+ }}>
118
+ <AccordionSummary expandIcon={<ExpandMoreIcon />} sx={{ minHeight: '28px' }}>
119
+ {qItem.text ? (
120
+ <>
121
+ <Typography variant="h6" color={readOnly ? 'text.secondary' : 'text.primary'}>
122
+ <LabelWrapper qItem={qItem} readOnly={readOnly} />
123
+ </Typography>
124
+ </>
125
+ ) : null}
126
+ </AccordionSummary>
127
+ <AccordionDetails sx={{ pt: 0 }}>
128
+ {qItem.text ? <Divider sx={{ mb: 1.5 }} light /> : null}
129
+ <TransitionGroup>
130
+ {repeatGroups.map(({ nanoId, qrItem: nullableQrItem }, index) => {
131
+ const answeredQrItem = createEmptyQrItem(qItem);
132
+ if (nullableQrItem) {
133
+ answeredQrItem.item = nullableQrItem.item;
134
+ }
135
+
136
+ return (
137
+ <Collapse key={nanoId} timeout={200}>
138
+ <RepeatGroupItem
139
+ qItem={qItem}
140
+ repeatGroupIndex={index}
141
+ answeredQrItem={answeredQrItem}
142
+ nullableQrItem={nullableQrItem}
143
+ numOfRepeatGroups={repeatGroups.length}
144
+ groupCardElevation={groupCardElevation + 1}
145
+ parentIsReadOnly={parentIsReadOnly}
146
+ onDeleteItem={() => onDeleteItem(index)}
147
+ onQrItemChange={(newQrItem) => onAnswerChange(newQrItem, index)}
148
+ />
149
+ </Collapse>
150
+ );
151
+ })}
152
+ </TransitionGroup>
153
+
154
+ <AddItemButton repeatGroups={repeatGroups} readOnly={readOnly} onAddItem={onAddItem} />
155
+ </AccordionDetails>
156
+ </GroupAccordion>
157
+ );
158
+ }
159
+
160
+ return (
161
+ <QGroupContainerBox key={qItem.linkId} cardElevation={groupCardElevation} isRepeated={true}>
162
+ <Card elevation={groupCardElevation} sx={{ p: 3, py: 2.5, mb: 3.5 }}>
163
+ {qItem.text ? (
164
+ <>
165
+ <Typography variant="h6" color={readOnly ? 'text.secondary' : 'text.primary'}>
166
+ <LabelWrapper qItem={qItem} readOnly={readOnly} />
167
+ </Typography>
168
+ <Divider sx={{ mt: 1, mb: 1.5 }} light />
169
+ </>
170
+ ) : null}
171
+ <TransitionGroup>
172
+ {repeatGroups.map(({ nanoId, qrItem: nullableQrItem }, index) => {
173
+ const answeredQrItem = createEmptyQrItem(qItem);
174
+ if (nullableQrItem) {
175
+ answeredQrItem.item = nullableQrItem.item;
176
+ }
177
+
178
+ return (
179
+ <Collapse key={nanoId} timeout={200}>
180
+ <RepeatGroupItem
181
+ qItem={qItem}
182
+ repeatGroupIndex={index}
183
+ answeredQrItem={answeredQrItem}
184
+ nullableQrItem={nullableQrItem}
185
+ numOfRepeatGroups={repeatGroups.length}
186
+ groupCardElevation={groupCardElevation + 1}
187
+ parentIsReadOnly={parentIsReadOnly}
188
+ onDeleteItem={() => onDeleteItem(index)}
189
+ onQrItemChange={(newQrItem) => onAnswerChange(newQrItem, index)}
190
+ />
191
+ </Collapse>
192
+ );
193
+ })}
194
+ </TransitionGroup>
195
+
196
+ <AddItemButton repeatGroups={repeatGroups} readOnly={readOnly} onAddItem={onAddItem} />
197
+ </Card>
198
+ </QGroupContainerBox>
199
+ );
200
+ }
201
+
202
+ export default RepeatGroupView;
@@ -15,7 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
 
18
- import React, { useCallback } from 'react';
18
+ import React, { useCallback, useMemo } from 'react';
19
19
  import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4';
20
20
  import type {
21
21
  PropsWithIsRepeatedAttribute,
@@ -30,6 +30,9 @@ import SingleItemSwitcher from './SingleItemSwitcher';
30
30
  import useHidden from '../../../hooks/useHidden';
31
31
  import useReadOnly from '../../../hooks/useReadOnly';
32
32
  import SingleNestedItems from './SingleNestedItems';
33
+ import { GroupCard } from '../GroupItem/GroupItem.styles';
34
+ import { QGroupContainerBox } from '../../Box.styles';
35
+ import { shouldRenderNestedItems } from '../../../utils/itemControl';
33
36
 
34
37
  interface SingleItemProps
35
38
  extends PropsWithQrItemChangeHandler,
@@ -97,7 +100,10 @@ function SingleItem(props: SingleItemProps) {
97
100
  [qrItem, onQrItemChange]
98
101
  );
99
102
 
100
- const qItemHasNestedItems = !!qItem.item && qItem.item.length > 0;
103
+ const qItemHasNestedItems = useMemo(
104
+ () => !!qItem.item && qItem.item.length > 0 && shouldRenderNestedItems(qItem),
105
+ [qItem]
106
+ );
101
107
 
102
108
  const readOnly = useReadOnly(qItem, parentIsReadOnly);
103
109
  const itemIsHidden = useHidden(qItem, parentRepeatGroupIndex);
@@ -105,6 +111,38 @@ function SingleItem(props: SingleItemProps) {
105
111
  return null;
106
112
  }
107
113
 
114
+ if (qItemHasNestedItems) {
115
+ return (
116
+ <QGroupContainerBox
117
+ cardElevation={groupCardElevation}
118
+ isRepeated={isRepeated}
119
+ data-test="q-item-group-box">
120
+ <GroupCard elevation={groupCardElevation} isRepeated={isRepeated}>
121
+ <SingleItemSwitcher
122
+ qItem={qItem}
123
+ qrItem={qrItem}
124
+ isRepeated={isRepeated}
125
+ isTabled={isTabled}
126
+ showMinimalView={showMinimalView}
127
+ parentIsReadOnly={readOnly}
128
+ onQrItemChange={handleQrItemChange}
129
+ />
130
+ {qItemHasNestedItems ? (
131
+ <>
132
+ <SingleNestedItems
133
+ qItem={qItem}
134
+ qrItem={qrItem}
135
+ groupCardElevation={groupCardElevation}
136
+ parentIsReadOnly={readOnly}
137
+ onQrItemChange={handleQrItemChangeWithNestedItems}
138
+ />
139
+ </>
140
+ ) : null}
141
+ </GroupCard>
142
+ </QGroupContainerBox>
143
+ );
144
+ }
145
+
108
146
  return (
109
147
  <>
110
148
  <SingleItemSwitcher
@@ -116,15 +154,6 @@ function SingleItem(props: SingleItemProps) {
116
154
  parentIsReadOnly={readOnly}
117
155
  onQrItemChange={handleQrItemChange}
118
156
  />
119
- {qItemHasNestedItems ? (
120
- <SingleNestedItems
121
- qItem={qItem}
122
- qrItem={qrItem}
123
- groupCardElevation={groupCardElevation}
124
- parentIsReadOnly={readOnly}
125
- onQrItemChange={handleQrItemChangeWithNestedItems}
126
- />
127
- ) : null}
128
157
  </>
129
158
  );
130
159
  }
@@ -25,6 +25,7 @@ import type {
25
25
  PropsWithQrItemChangeHandler
26
26
  } from '../../../interfaces/renderProps.interface';
27
27
  import type { QrRepeatGroup } from '../../../interfaces/repeatGroup.interface';
28
+ import Box from '@mui/material/Box';
28
29
 
29
30
  interface SingleNestedItemsProps
30
31
  extends PropsWithQrItemChangeHandler,
@@ -63,27 +64,31 @@ function SingleNestedItems(props: SingleNestedItemsProps) {
63
64
  const qrItemsByIndex = getQrItemsIndex(qItems, qrItems, qItemsIndexMap);
64
65
 
65
66
  return (
66
- <>
67
- {qItems.map((qItem: QuestionnaireItem, i) => {
68
- const qrItemOrItems = qrItemsByIndex[i];
67
+ <Box display="flex">
68
+ <Box ml={1.5} />
69
+ <Box flexGrow={1}>
70
+ {qItems.map((qItem: QuestionnaireItem, i) => {
71
+ const qrItemOrItems = qrItemsByIndex[i];
69
72
 
70
- if (qItem.type === 'display') {
71
- return null;
72
- }
73
+ if (qItem.type === 'display') {
74
+ return null;
75
+ }
73
76
 
74
- return (
75
- <GroupItemSwitcher
76
- key={qItem.linkId}
77
- qItem={qItem}
78
- qrItemOrItems={qrItemOrItems}
79
- groupCardElevation={groupCardElevation}
80
- parentIsReadOnly={parentIsReadOnly}
81
- onQrItemChange={handleQrItemChange}
82
- onQrRepeatGroupChange={handleQrRepeatGroupChange}
83
- />
84
- );
85
- })}
86
- </>
77
+ return (
78
+ <GroupItemSwitcher
79
+ key={qItem.linkId}
80
+ qItem={qItem}
81
+ qrItemOrItems={qrItemOrItems}
82
+ groupCardElevation={groupCardElevation}
83
+ parentIsReadOnly={parentIsReadOnly}
84
+ onQrItemChange={handleQrItemChange}
85
+ onQrRepeatGroupChange={handleQrRepeatGroupChange}
86
+ />
87
+ );
88
+ })}
89
+ </Box>
90
+ <Box mr={2.25}></Box>
91
+ </Box>
87
92
  );
88
93
  }
89
94
 
@@ -21,7 +21,6 @@ import Accordion from '@mui/material/Accordion';
21
21
  import AccordionDetails from '@mui/material/AccordionDetails';
22
22
  import AccordionSummary from '@mui/material/AccordionSummary';
23
23
  import Box from '@mui/material/Box';
24
- import Tooltip from '@mui/material/Tooltip';
25
24
  import Typography from '@mui/material/Typography';
26
25
  import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
27
26
  import { getContextDisplays } from '../../utils/tabs';
@@ -46,17 +45,16 @@ const FormBodySingleCollapsible = memo(function FormBodySingleCollapsible(
46
45
 
47
46
  const collapsibleLabel = getShortText(qItem) ?? qItem.text ?? '';
48
47
 
48
+ const isExpanded = selectedIndex === index;
49
+
49
50
  return (
50
51
  <Accordion
51
- expanded={selectedIndex === index}
52
- TransitionProps={{ unmountOnExit: true, timeout: 250 }}
52
+ expanded={isExpanded}
53
+ slotProps={{
54
+ transition: { unmountOnExit: true, timeout: 250 }
55
+ }}
53
56
  onChange={() => onToggleExpand(index)}>
54
- <AccordionSummary
55
- expandIcon={
56
- <Tooltip title={'Expand'}>
57
- <ExpandMoreIcon />
58
- </Tooltip>
59
- }>
57
+ <AccordionSummary expandIcon={<ExpandMoreIcon />}>
60
58
  <Box display="flex" alignItems="center" justifyContent="space-between" width="100%" mr={3}>
61
59
  <Typography variant="subtitle2">{collapsibleLabel}</Typography>
62
60
  <Box display="flex" columnGap={0.5}>