@aehrc/smart-forms-renderer 0.9.2 → 0.10.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/.swcrc +11 -0
- package/lib/components/FormComponents/GroupItem/NextTabButtonWrapper.js +5 -5
- package/lib/components/FormComponents/GroupItem/NextTabButtonWrapper.js.map +1 -1
- package/lib/components/FormComponents/RepeatGroup/DeleteItemButton.js +1 -1
- package/lib/components/FormComponents/RepeatItem/RemoveItemButton.d.ts +10 -0
- package/lib/components/FormComponents/RepeatItem/RemoveItemButton.js +30 -0
- package/lib/components/FormComponents/RepeatItem/RemoveItemButton.js.map +1 -0
- package/lib/components/FormComponents/RepeatItem/RepeatField.js +2 -2
- package/lib/components/FormComponents/SingleItem/SingleItem.js +2 -2
- package/lib/components/FormComponents/SingleItem/SingleItem.js.map +1 -1
- package/lib/components/FormComponents/Tables/GroupTable.d.ts +1 -2
- package/lib/components/FormComponents/Tables/GroupTable.js +44 -59
- package/lib/components/FormComponents/Tables/GroupTable.js.map +1 -1
- package/lib/components/FormComponents/Tables/GroupTableBody.d.ts +17 -0
- package/lib/components/FormComponents/Tables/GroupTableBody.js +48 -0
- package/lib/components/FormComponents/Tables/GroupTableBody.js.map +1 -0
- package/lib/components/FormComponents/Tables/GroupTableRow.d.ts +18 -5
- package/lib/components/FormComponents/Tables/GroupTableRow.js +17 -25
- package/lib/components/FormComponents/Tables/GroupTableRow.js.map +1 -1
- package/lib/components/FormComponents/Tables/GroupTableRowCells.d.ts +11 -0
- package/lib/components/FormComponents/Tables/GroupTableRowCells.js +57 -0
- package/lib/components/FormComponents/Tables/GroupTableRowCells.js.map +1 -0
- package/lib/components/FormComponents/Tables/GroupTableRows.d.ts +17 -0
- package/lib/components/FormComponents/Tables/GroupTableRows.js +45 -0
- package/lib/components/FormComponents/Tables/GroupTableRows.js.map +1 -0
- package/lib/components/FormComponents/Tables/GroupTableTestRow.d.ts +22 -0
- package/lib/components/FormComponents/Tables/GroupTableTestRow.js +43 -0
- package/lib/components/FormComponents/Tables/GroupTableTestRow.js.map +1 -0
- package/lib/components/FormComponents/Tables/GroupTableView.d.ts +21 -0
- package/lib/components/FormComponents/Tables/GroupTableView.js +65 -0
- package/lib/components/FormComponents/Tables/GroupTableView.js.map +1 -0
- package/lib/components/FormComponents/Tables/RemoveRowButton.d.ts +10 -0
- package/lib/components/FormComponents/Tables/RemoveRowButton.js +32 -0
- package/lib/components/FormComponents/Tables/RemoveRowButton.js.map +1 -0
- package/lib/components/FormComponents/Tables/SelectRowButton.d.ts +7 -0
- package/lib/components/FormComponents/Tables/SelectRowButton.js +26 -0
- package/lib/components/FormComponents/Tables/SelectRowButton.js.map +1 -0
- package/lib/components/FormComponents/Tables/Table.styles.d.ts +8 -0
- package/lib/components/FormComponents/Tables/Table.styles.js +17 -0
- package/lib/components/FormComponents/Tables/Table.styles.js.map +1 -1
- package/lib/components/Renderer/BaseRenderer.js +5 -6
- package/lib/components/Renderer/BaseRenderer.js.map +1 -1
- package/lib/components/Renderer/FormBodyCollapsible.js +4 -4
- package/lib/components/Renderer/FormBodyCollapsible.js.map +1 -1
- package/lib/components/Renderer/FormBodyTabbed.js +3 -3
- package/lib/components/Renderer/FormBodyTabbed.js.map +1 -1
- package/lib/components/Tabs/CompleteTabButton.js +2 -2
- package/lib/components/Tabs/CompleteTabButton.js.map +1 -1
- package/lib/components/Tabs/FormBodySingleTab.js +2 -2
- package/lib/components/Tabs/FormBodySingleTab.js.map +1 -1
- package/lib/components/Tabs/FormBodyTabList.js +4 -4
- package/lib/components/Tabs/FormBodyTabList.js.map +1 -1
- package/lib/hooks/useDecimalCalculatedExpression.js +2 -2
- package/lib/hooks/useDecimalCalculatedExpression.js.map +1 -1
- package/lib/hooks/useHidden.js +4 -4
- package/lib/hooks/useHidden.js.map +1 -1
- package/lib/hooks/useInitialiseGroupTable.d.ts +2 -2
- package/lib/hooks/useInitialiseGroupTable.js.map +1 -1
- package/lib/hooks/useInitialiseRenderer.js +11 -14
- package/lib/hooks/useInitialiseRenderer.js.map +1 -1
- package/lib/hooks/useIntegerCalculatedExpression.js +2 -2
- package/lib/hooks/useIntegerCalculatedExpression.js.map +1 -1
- package/lib/hooks/useMinimalStringCalculatedExpression.js +25 -13
- package/lib/hooks/useStringCalculatedExpression.js +2 -2
- package/lib/hooks/useStringCalculatedExpression.js.map +1 -1
- package/lib/hooks/useTerminologyServerQuery.js +3 -4
- package/lib/hooks/useTerminologyServerQuery.js.map +1 -1
- package/lib/hooks/useValueSetCodings.js +10 -12
- package/lib/hooks/useValueSetCodings.js.map +1 -1
- package/lib/index.js +19 -20
- package/lib/index.js.map +1 -1
- package/lib/interfaces/groupTable.interface.d.ts +1 -1
- package/lib/setup-jest.js +1 -0
- package/lib/setup-jest.js.map +1 -0
- package/lib/stores/index.d.ts +4 -3
- package/lib/stores/index.js +4 -3
- package/lib/stores/index.js.map +1 -1
- package/lib/stores/questionnaireResponseStore.d.ts +28 -0
- package/lib/stores/questionnaireResponseStore.js +64 -0
- package/lib/stores/questionnaireResponseStore.js.map +1 -0
- package/lib/stores/questionnaireStore.d.ts +65 -0
- package/lib/stores/questionnaireStore.js +172 -0
- package/lib/stores/questionnaireStore.js.map +1 -0
- package/lib/stores/smartConfigStore.d.ts +25 -0
- package/lib/stores/smartConfigStore.js +30 -0
- package/lib/stores/smartConfigStore.js.map +1 -0
- package/lib/stores/terminologyServerStore.d.ts +14 -0
- package/lib/stores/terminologyServerStore.js +26 -0
- package/lib/stores/terminologyServerStore.js.map +1 -0
- package/lib/stores/useQuestionnaireResponseStore.d.ts +14 -2
- package/lib/stores/useQuestionnaireResponseStore.js +4 -2
- package/lib/stores/useQuestionnaireResponseStore.js.map +1 -1
- package/lib/stores/useQuestionnaireStore.d.ts +30 -2
- package/lib/stores/useQuestionnaireStore.js +4 -2
- package/lib/stores/useQuestionnaireStore.js.map +1 -1
- package/lib/stories/MedicalHistoryTable.stories.js +49 -0
- package/lib/stories/MedicalHistoryTable.stories.js.map +1 -0
- package/lib/stories/SmartFormsRenderer.stories.js +103 -0
- package/lib/stories/SmartFormsRenderer.stories.js.map +1 -0
- package/lib/theme/overrides/Table.d.ts +1 -0
- package/lib/theme/overrides/Table.js +2 -1
- package/lib/theme/overrides/Table.js.map +1 -1
- package/lib/utils/calculatedExpression.js +1 -2
- package/lib/utils/calculatedExpression.js.map +1 -1
- package/lib/utils/groupTable.d.ts +3 -0
- package/lib/utils/groupTable.js +29 -0
- package/lib/utils/groupTable.js.map +1 -0
- package/package.json +10 -5
- package/src/components/FormComponents/GroupItem/NextTabButtonWrapper.tsx +5 -5
- package/src/components/FormComponents/RepeatGroup/DeleteItemButton.tsx +1 -1
- package/src/components/FormComponents/RepeatItem/{DeleteItemButton.tsx → RemoveItemButton.tsx} +4 -4
- package/src/components/FormComponents/RepeatItem/RepeatField.tsx +2 -2
- package/src/components/FormComponents/SingleItem/SingleItem.tsx +2 -2
- package/src/components/FormComponents/Tables/GroupTable.tsx +71 -120
- package/src/components/FormComponents/Tables/GroupTableBody.tsx +116 -0
- package/src/components/FormComponents/Tables/GroupTableRow.tsx +89 -49
- package/src/components/FormComponents/Tables/GroupTableRowCells.tsx +87 -0
- package/src/components/FormComponents/Tables/GroupTableView.tsx +169 -0
- package/src/components/FormComponents/Tables/{DeleteRowButton.tsx → RemoveRowButton.tsx} +7 -7
- package/src/components/FormComponents/Tables/SelectRowButton.tsx +37 -0
- package/src/components/FormComponents/Tables/Table.styles.tsx +25 -0
- package/src/components/Renderer/BaseRenderer.tsx +5 -6
- package/src/components/Renderer/FormBodyCollapsible.tsx +4 -5
- package/src/components/Renderer/FormBodyTabbed.tsx +3 -3
- package/src/components/Tabs/CompleteTabButton.tsx +2 -2
- package/src/components/Tabs/FormBodySingleTab.tsx +2 -3
- package/src/components/Tabs/FormBodyTabList.tsx +4 -4
- package/src/hooks/useDecimalCalculatedExpression.ts +2 -2
- package/src/hooks/useHidden.ts +4 -4
- package/src/hooks/useInitialiseGroupTable.ts +3 -3
- package/src/hooks/useInitialiseRenderer.ts +17 -18
- package/src/hooks/useIntegerCalculatedExpression.ts +2 -2
- package/src/hooks/useStringCalculatedExpression.ts +2 -2
- package/src/hooks/useTerminologyServerQuery.ts +3 -4
- package/src/hooks/useValueSetCodings.ts +10 -12
- package/src/index.ts +19 -20
- package/src/interfaces/groupTable.interface.ts +1 -1
- package/src/stores/index.ts +7 -3
- package/src/stores/questionnaireResponseStore.ts +83 -0
- package/src/stores/{useQuestionnaireStore.ts → questionnaireStore.ts} +7 -6
- package/src/stores/smartConfigStore.ts +45 -0
- package/src/stores/{useTerminologyServerStore.ts → terminologyServerStore.ts} +5 -4
- package/src/stories/MedicalHistoryTable.stories.tsx +61 -0
- package/src/stories/SmartFormsRenderer.stories.ts +15 -5
- package/src/stories/assets/QItems-and-QRItems/QR_GTableMedicalHistory.json +80 -0
- package/src/stories/assets/QItems-and-QRItems/Q_GTableMedicalHistory.json +109 -0
- package/src/stories/assets/Qs-and-QRs/QDev715.json +16081 -0
- package/src/theme/overrides/Table.ts +2 -1
- package/src/utils/calculatedExpression.ts +1 -2
- package/src/utils/groupTable.ts +37 -0
- package/src/stores/useQuestionnaireResponseStore.ts +0 -63
- package/src/stores/useSmartConfigStore.ts +0 -27
- /package/src/stories/assets/{Q715.json → Qs-and-QRs/Q715.json} +0 -0
- /package/src/stories/assets/{QTestGrid.json → Qs-and-QRs/QTestGrid.json} +0 -0
- /package/src/stories/assets/{R715.json → Qs-and-QRs/R715.json} +0 -0
- /package/src/stories/assets/{RTestGrid.json → Qs-and-QRs/RTestGrid.json} +0 -0
|
@@ -17,65 +17,105 @@
|
|
|
17
17
|
|
|
18
18
|
import React from 'react';
|
|
19
19
|
import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4';
|
|
20
|
-
import { createEmptyQrGroup, updateQrItemsInGroup } from '../../../utils/qrItem';
|
|
21
|
-
import SingleItem from '../SingleItem/SingleItem';
|
|
22
|
-
import { getQrItemsIndex } from '../../../utils/mapItem';
|
|
23
|
-
import { StandardTableCell } from './Table.styles';
|
|
24
20
|
import type {
|
|
25
21
|
PropsWithParentIsReadOnlyAttribute,
|
|
26
|
-
|
|
22
|
+
PropsWithShowMinimalViewAttribute
|
|
27
23
|
} from '../../../interfaces/renderProps.interface';
|
|
24
|
+
import { TableRowProps } from '@mui/material/TableRow';
|
|
25
|
+
import SelectRowButton from './SelectRowButton';
|
|
26
|
+
import GroupTableRowCells from './GroupTableRowCells';
|
|
27
|
+
import RemoveRowButton from './RemoveRowButton';
|
|
28
|
+
import { GroupTableRowModel } from '../../../interfaces/groupTable.interface';
|
|
29
|
+
import DragIndicator from '@mui/icons-material/DragIndicator';
|
|
30
|
+
import TableCell from '@mui/material/TableCell';
|
|
31
|
+
import Box from '@mui/material/Box';
|
|
32
|
+
import { Draggable } from 'react-beautiful-dnd';
|
|
33
|
+
import { StyledGroupTableRow } from './Table.styles';
|
|
28
34
|
|
|
29
|
-
interface
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
interface GroupTableRowProps
|
|
36
|
+
extends PropsWithShowMinimalViewAttribute,
|
|
37
|
+
PropsWithParentIsReadOnlyAttribute,
|
|
38
|
+
TableRowProps {
|
|
39
|
+
nanoId: string;
|
|
40
|
+
index: number;
|
|
41
|
+
tableQItem: QuestionnaireItem;
|
|
42
|
+
answeredQrItem: QuestionnaireResponseItem;
|
|
43
|
+
nullableQrItem: QuestionnaireResponseItem | null;
|
|
44
|
+
readOnly: boolean;
|
|
45
|
+
hoverDisabled: boolean;
|
|
46
|
+
tableRows: GroupTableRowModel[];
|
|
47
|
+
itemIsSelected: boolean;
|
|
48
|
+
selectedIds: string[];
|
|
32
49
|
qItemsIndexMap: Record<string, number>;
|
|
50
|
+
onRowChange: (newQrRow: QuestionnaireResponseItem, index: number) => void;
|
|
51
|
+
onRemoveRow: (index: number) => void;
|
|
52
|
+
onSelectRow: (nanoId: string) => void;
|
|
33
53
|
}
|
|
34
54
|
|
|
35
|
-
function GroupTableRow(props:
|
|
36
|
-
const {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
function GroupTableRow(props: GroupTableRowProps) {
|
|
56
|
+
const {
|
|
57
|
+
nanoId,
|
|
58
|
+
index,
|
|
59
|
+
tableQItem,
|
|
60
|
+
answeredQrItem,
|
|
61
|
+
nullableQrItem,
|
|
62
|
+
readOnly,
|
|
63
|
+
hoverDisabled,
|
|
64
|
+
tableRows,
|
|
65
|
+
itemIsSelected,
|
|
66
|
+
qItemsIndexMap,
|
|
67
|
+
showMinimalView,
|
|
68
|
+
parentIsReadOnly,
|
|
69
|
+
onRowChange,
|
|
70
|
+
onRemoveRow,
|
|
71
|
+
onSelectRow
|
|
72
|
+
} = props;
|
|
53
73
|
|
|
54
74
|
return (
|
|
55
|
-
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
<Draggable draggableId={nanoId} index={index}>
|
|
76
|
+
{(draggableProvided, snapshot) => (
|
|
77
|
+
<StyledGroupTableRow
|
|
78
|
+
itemIsDragged={snapshot.isDragging}
|
|
79
|
+
itemIsSelected={itemIsSelected}
|
|
80
|
+
hoverDisabled={hoverDisabled}
|
|
81
|
+
hover={!hoverDisabled}
|
|
82
|
+
ref={draggableProvided.innerRef}
|
|
83
|
+
{...draggableProvided.draggableProps}>
|
|
84
|
+
{showMinimalView ? null : (
|
|
85
|
+
<>
|
|
86
|
+
<TableCell padding="checkbox">
|
|
87
|
+
<Box
|
|
88
|
+
display="flex"
|
|
89
|
+
alignItems="center"
|
|
90
|
+
justifyContent="center"
|
|
91
|
+
{...draggableProvided.dragHandleProps}>
|
|
92
|
+
<DragIndicator fontSize="small" />
|
|
93
|
+
</Box>
|
|
94
|
+
</TableCell>
|
|
95
|
+
<SelectRowButton
|
|
96
|
+
isSelected={itemIsSelected}
|
|
97
|
+
onSelectItem={() => onSelectRow(nanoId)}
|
|
98
|
+
/>
|
|
99
|
+
</>
|
|
100
|
+
)}
|
|
101
|
+
<GroupTableRowCells
|
|
102
|
+
qItem={tableQItem}
|
|
103
|
+
qrItem={answeredQrItem}
|
|
104
|
+
qItemsIndexMap={qItemsIndexMap}
|
|
105
|
+
parentIsReadOnly={parentIsReadOnly}
|
|
106
|
+
onQrItemChange={(newQrGroup) => onRowChange(newQrGroup, index)}
|
|
107
|
+
/>
|
|
108
|
+
{showMinimalView ? null : (
|
|
109
|
+
<RemoveRowButton
|
|
110
|
+
nullableQrItem={nullableQrItem}
|
|
111
|
+
numOfRows={tableRows.length}
|
|
112
|
+
readOnly={readOnly}
|
|
113
|
+
onRemoveItem={() => onRemoveRow(index)}
|
|
74
114
|
/>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
115
|
+
)}
|
|
116
|
+
</StyledGroupTableRow>
|
|
117
|
+
)}
|
|
118
|
+
</Draggable>
|
|
79
119
|
);
|
|
80
120
|
}
|
|
81
121
|
|
|
@@ -0,0 +1,87 @@
|
|
|
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 React from 'react';
|
|
19
|
+
import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4';
|
|
20
|
+
import { createEmptyQrGroup, updateQrItemsInGroup } from '../../../utils/qrItem';
|
|
21
|
+
import SingleItem from '../SingleItem/SingleItem';
|
|
22
|
+
import { getQrItemsIndex } from '../../../utils/mapItem';
|
|
23
|
+
import { StandardTableCell } from './Table.styles';
|
|
24
|
+
import type {
|
|
25
|
+
PropsWithParentIsReadOnlyAttribute,
|
|
26
|
+
PropsWithQrItemChangeHandler
|
|
27
|
+
} from '../../../interfaces/renderProps.interface';
|
|
28
|
+
import { TableRowProps } from '@mui/material/TableRow';
|
|
29
|
+
|
|
30
|
+
interface GroupTableRowCellsProps
|
|
31
|
+
extends PropsWithQrItemChangeHandler,
|
|
32
|
+
PropsWithParentIsReadOnlyAttribute,
|
|
33
|
+
TableRowProps {
|
|
34
|
+
qItem: QuestionnaireItem;
|
|
35
|
+
qrItem: QuestionnaireResponseItem | null;
|
|
36
|
+
qItemsIndexMap: Record<string, number>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function GroupTableRowCells(props: GroupTableRowCellsProps) {
|
|
40
|
+
const { qItem, qrItem, qItemsIndexMap, parentIsReadOnly, onQrItemChange, ...tableRowProps } =
|
|
41
|
+
props;
|
|
42
|
+
|
|
43
|
+
const rowItems = qItem.item;
|
|
44
|
+
const row = qrItem && qrItem.item ? qrItem : createEmptyQrGroup(qItem);
|
|
45
|
+
const rowQrItems = row.item;
|
|
46
|
+
|
|
47
|
+
if (!rowItems || !rowQrItems) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function handleQrRowItemChange(newQrRowItem: QuestionnaireResponseItem) {
|
|
52
|
+
const qrRow: QuestionnaireResponseItem = { ...row };
|
|
53
|
+
updateQrItemsInGroup(newQrRowItem, null, qrRow, qItemsIndexMap);
|
|
54
|
+
onQrItemChange(qrRow);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const qrItemsByIndex = getQrItemsIndex(rowItems, rowQrItems, qItemsIndexMap);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<>
|
|
61
|
+
{rowItems.map((rowItem, index) => {
|
|
62
|
+
const qrItem = qrItemsByIndex[index];
|
|
63
|
+
|
|
64
|
+
if (Array.isArray(qrItem)) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<StandardTableCell key={index} numOfColumns={rowItems.length} isFirst={index === 0}>
|
|
70
|
+
<SingleItem
|
|
71
|
+
key={qItem.linkId}
|
|
72
|
+
qItem={rowItem}
|
|
73
|
+
qrItem={qrItem ?? null}
|
|
74
|
+
isRepeated={true}
|
|
75
|
+
isTabled={true}
|
|
76
|
+
showMinimalView={true}
|
|
77
|
+
parentIsReadOnly={parentIsReadOnly}
|
|
78
|
+
onQrItemChange={handleQrRowItemChange}
|
|
79
|
+
/>
|
|
80
|
+
</StandardTableCell>
|
|
81
|
+
);
|
|
82
|
+
})}
|
|
83
|
+
</>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export default GroupTableRowCells;
|
|
@@ -0,0 +1,169 @@
|
|
|
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 React from 'react';
|
|
19
|
+
import { QGroupContainerBox } from '../../Box.styles';
|
|
20
|
+
import TableContainer from '@mui/material/TableContainer';
|
|
21
|
+
import Paper from '@mui/material/Paper';
|
|
22
|
+
import Table from '@mui/material/Table';
|
|
23
|
+
import TableHead from '@mui/material/TableHead';
|
|
24
|
+
import TableRow from '@mui/material/TableRow';
|
|
25
|
+
import { HeaderTableCell } from './Table.styles';
|
|
26
|
+
import TableCell from '@mui/material/TableCell';
|
|
27
|
+
import TableBody from '@mui/material/TableBody';
|
|
28
|
+
import Typography from '@mui/material/Typography';
|
|
29
|
+
import LabelWrapper from '../ItemParts/ItemLabelWrapper';
|
|
30
|
+
import Divider from '@mui/material/Divider';
|
|
31
|
+
import AddRowButton from './AddRowButton';
|
|
32
|
+
import { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4';
|
|
33
|
+
import {
|
|
34
|
+
PropsWithParentIsReadOnlyAttribute,
|
|
35
|
+
PropsWithShowMinimalViewAttribute
|
|
36
|
+
} from '../../../interfaces/renderProps.interface';
|
|
37
|
+
import { GroupTableRowModel } from '../../../interfaces/groupTable.interface';
|
|
38
|
+
import GroupTableBody from './GroupTableBody';
|
|
39
|
+
import Checkbox from '@mui/material/Checkbox';
|
|
40
|
+
|
|
41
|
+
interface GroupTableViewProps
|
|
42
|
+
extends PropsWithShowMinimalViewAttribute,
|
|
43
|
+
PropsWithParentIsReadOnlyAttribute {
|
|
44
|
+
qItem: QuestionnaireItem;
|
|
45
|
+
qItemsIndexMap: Record<string, number>;
|
|
46
|
+
groupCardElevation: number;
|
|
47
|
+
readOnly: boolean;
|
|
48
|
+
tableRows: GroupTableRowModel[];
|
|
49
|
+
selectedIds: string[];
|
|
50
|
+
itemLabels: string[];
|
|
51
|
+
onAddRow: () => void;
|
|
52
|
+
onRowChange: (newQrRow: QuestionnaireResponseItem, index: number) => void;
|
|
53
|
+
onRemoveRow: (index: number) => void;
|
|
54
|
+
onSelectRow: (nanoId: string) => void;
|
|
55
|
+
onSelectAll: () => void;
|
|
56
|
+
onReorderRows: (newTableRows: GroupTableRowModel[]) => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function GroupTableView(props: GroupTableViewProps) {
|
|
60
|
+
const {
|
|
61
|
+
qItem,
|
|
62
|
+
qItemsIndexMap,
|
|
63
|
+
groupCardElevation,
|
|
64
|
+
readOnly,
|
|
65
|
+
tableRows,
|
|
66
|
+
selectedIds,
|
|
67
|
+
itemLabels,
|
|
68
|
+
showMinimalView,
|
|
69
|
+
parentIsReadOnly,
|
|
70
|
+
onAddRow,
|
|
71
|
+
onRowChange,
|
|
72
|
+
onRemoveRow,
|
|
73
|
+
onSelectRow,
|
|
74
|
+
onSelectAll,
|
|
75
|
+
onReorderRows
|
|
76
|
+
} = props;
|
|
77
|
+
|
|
78
|
+
if (showMinimalView) {
|
|
79
|
+
return (
|
|
80
|
+
<QGroupContainerBox cardElevation={groupCardElevation} isRepeated={false} py={1}>
|
|
81
|
+
<TableContainer component={Paper} elevation={groupCardElevation}>
|
|
82
|
+
<Table size="small">
|
|
83
|
+
<TableHead>
|
|
84
|
+
<TableRow>
|
|
85
|
+
{itemLabels.map((itemLabel) => (
|
|
86
|
+
<HeaderTableCell key={itemLabel} size="medium">
|
|
87
|
+
{itemLabel}
|
|
88
|
+
</HeaderTableCell>
|
|
89
|
+
))}
|
|
90
|
+
<TableCell />
|
|
91
|
+
</TableRow>
|
|
92
|
+
</TableHead>
|
|
93
|
+
<TableBody>
|
|
94
|
+
<GroupTableBody
|
|
95
|
+
tableQItem={qItem}
|
|
96
|
+
readOnly={readOnly}
|
|
97
|
+
tableRows={tableRows}
|
|
98
|
+
selectedIds={selectedIds}
|
|
99
|
+
qItemsIndexMap={qItemsIndexMap}
|
|
100
|
+
showMinimalView={showMinimalView}
|
|
101
|
+
parentIsReadOnly={parentIsReadOnly}
|
|
102
|
+
onRowChange={onRowChange}
|
|
103
|
+
onRemoveRow={onRemoveRow}
|
|
104
|
+
onSelectRow={onSelectRow}
|
|
105
|
+
onReorderRows={onReorderRows}
|
|
106
|
+
/>
|
|
107
|
+
</TableBody>
|
|
108
|
+
</Table>
|
|
109
|
+
</TableContainer>
|
|
110
|
+
</QGroupContainerBox>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<QGroupContainerBox cardElevation={groupCardElevation} isRepeated={false} py={3}>
|
|
116
|
+
{groupCardElevation !== 1 ? (
|
|
117
|
+
<>
|
|
118
|
+
<Typography
|
|
119
|
+
fontSize={13}
|
|
120
|
+
variant="h6"
|
|
121
|
+
color={readOnly ? 'text.secondary' : 'text.primary'}>
|
|
122
|
+
<LabelWrapper qItem={qItem} readOnly={readOnly} />
|
|
123
|
+
</Typography>
|
|
124
|
+
<Divider sx={{ my: 1 }} light />
|
|
125
|
+
</>
|
|
126
|
+
) : null}
|
|
127
|
+
<TableContainer component={Paper} elevation={groupCardElevation}>
|
|
128
|
+
<Table>
|
|
129
|
+
<caption>
|
|
130
|
+
<AddRowButton repeatGroups={tableRows} readOnly={readOnly} onAddItem={onAddRow} />
|
|
131
|
+
</caption>
|
|
132
|
+
<TableHead>
|
|
133
|
+
<TableRow>
|
|
134
|
+
<HeaderTableCell padding="checkbox" />
|
|
135
|
+
<HeaderTableCell padding="checkbox">
|
|
136
|
+
<Checkbox
|
|
137
|
+
color="primary"
|
|
138
|
+
size="small"
|
|
139
|
+
indeterminate={selectedIds.length > 0 && selectedIds.length < tableRows.length}
|
|
140
|
+
checked={tableRows.length > 0 && selectedIds.length === tableRows.length}
|
|
141
|
+
onChange={onSelectAll}
|
|
142
|
+
/>
|
|
143
|
+
</HeaderTableCell>
|
|
144
|
+
{itemLabels.map((itemLabel) => (
|
|
145
|
+
<HeaderTableCell key={itemLabel}>{itemLabel}</HeaderTableCell>
|
|
146
|
+
))}
|
|
147
|
+
<TableCell />
|
|
148
|
+
</TableRow>
|
|
149
|
+
</TableHead>
|
|
150
|
+
<GroupTableBody
|
|
151
|
+
tableQItem={qItem}
|
|
152
|
+
readOnly={readOnly}
|
|
153
|
+
tableRows={tableRows}
|
|
154
|
+
selectedIds={selectedIds}
|
|
155
|
+
qItemsIndexMap={qItemsIndexMap}
|
|
156
|
+
showMinimalView={showMinimalView}
|
|
157
|
+
parentIsReadOnly={parentIsReadOnly}
|
|
158
|
+
onRowChange={onRowChange}
|
|
159
|
+
onRemoveRow={onRemoveRow}
|
|
160
|
+
onSelectRow={onSelectRow}
|
|
161
|
+
onReorderRows={onReorderRows}
|
|
162
|
+
/>
|
|
163
|
+
</Table>
|
|
164
|
+
</TableContainer>
|
|
165
|
+
</QGroupContainerBox>
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export default GroupTableView;
|
|
@@ -23,22 +23,22 @@ import Tooltip from '@mui/material/Tooltip';
|
|
|
23
23
|
import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline';
|
|
24
24
|
import type { QuestionnaireResponseItem } from 'fhir/r4';
|
|
25
25
|
|
|
26
|
-
interface
|
|
26
|
+
interface RemoveRowButtonProps {
|
|
27
27
|
nullableQrItem: QuestionnaireResponseItem | null;
|
|
28
28
|
numOfRows: number;
|
|
29
29
|
readOnly: boolean;
|
|
30
|
-
|
|
30
|
+
onRemoveItem: () => void;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function
|
|
34
|
-
const { nullableQrItem, numOfRows, readOnly,
|
|
33
|
+
function RemoveRowButton(props: RemoveRowButtonProps) {
|
|
34
|
+
const { nullableQrItem, numOfRows, readOnly, onRemoveItem } = props;
|
|
35
35
|
|
|
36
36
|
const isDisabled = nullableQrItem === null || numOfRows === 1 || readOnly;
|
|
37
37
|
return (
|
|
38
38
|
<DeleteButtonTableCell>
|
|
39
|
-
<Tooltip title="
|
|
39
|
+
<Tooltip title="Remove item">
|
|
40
40
|
<span>
|
|
41
|
-
<IconButton size="small" color="error" disabled={isDisabled} onClick={
|
|
41
|
+
<IconButton size="small" color="error" disabled={isDisabled} onClick={onRemoveItem}>
|
|
42
42
|
<RemoveCircleOutlineIcon fontSize="small" />
|
|
43
43
|
</IconButton>
|
|
44
44
|
</span>
|
|
@@ -47,4 +47,4 @@ function DeleteRowButton(props: DeleteRowButtonProps) {
|
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
export default
|
|
50
|
+
export default RemoveRowButton;
|
|
@@ -0,0 +1,37 @@
|
|
|
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 React from 'react';
|
|
19
|
+
import Checkbox from '@mui/material/Checkbox';
|
|
20
|
+
import TableCell from '@mui/material/TableCell';
|
|
21
|
+
|
|
22
|
+
interface SelectRowButtonProps {
|
|
23
|
+
isSelected: boolean;
|
|
24
|
+
onSelectItem: () => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function SelectRowButton(props: SelectRowButtonProps) {
|
|
28
|
+
const { isSelected, onSelectItem } = props;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<TableCell padding="checkbox">
|
|
32
|
+
<Checkbox color="primary" size="small" checked={isSelected} onChange={onSelectItem} />
|
|
33
|
+
</TableCell>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default SelectRowButton;
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import { styled } from '@mui/material/styles';
|
|
19
19
|
import TableCell from '@mui/material/TableCell';
|
|
20
|
+
import TableRow from '@mui/material/TableRow';
|
|
21
|
+
import { grey } from '@mui/material/colors';
|
|
20
22
|
|
|
21
23
|
export const HeaderTableCell = styled(TableCell)(() => ({
|
|
22
24
|
fontSize: 13,
|
|
@@ -50,3 +52,26 @@ export const GridAnswerTableCell = styled(TableCell, {
|
|
|
50
52
|
paddingLeft: 5,
|
|
51
53
|
paddingRight: 5
|
|
52
54
|
}));
|
|
55
|
+
|
|
56
|
+
export const StyledGroupTableRow = styled(TableRow, {
|
|
57
|
+
shouldForwardProp: (prop) =>
|
|
58
|
+
prop !== 'itemIsDragged' && prop !== 'itemIsSelected' && prop !== 'hoverDisabled'
|
|
59
|
+
})<{ itemIsDragged: boolean; itemIsSelected: boolean; hoverDisabled: boolean }>(
|
|
60
|
+
({ theme, itemIsDragged, itemIsSelected, hoverDisabled }) => ({
|
|
61
|
+
backgroundColor: itemIsSelected ? '#f4f8ff' : '#fff',
|
|
62
|
+
...(hoverDisabled
|
|
63
|
+
? {}
|
|
64
|
+
: {
|
|
65
|
+
'&.MuiTableRow-root:hover': {
|
|
66
|
+
backgroundColor: itemIsSelected ? '#e9f1ff' : grey['50']
|
|
67
|
+
}
|
|
68
|
+
}),
|
|
69
|
+
...(itemIsDragged
|
|
70
|
+
? {
|
|
71
|
+
boxShadow: theme.customShadows.z8,
|
|
72
|
+
opacity: 1,
|
|
73
|
+
backgroundColor: itemIsSelected ? '#edf4ff' : '#fafafa'
|
|
74
|
+
}
|
|
75
|
+
: {})
|
|
76
|
+
})
|
|
77
|
+
);
|
|
@@ -20,18 +20,17 @@ import Container from '@mui/material/Container';
|
|
|
20
20
|
import Fade from '@mui/material/Fade';
|
|
21
21
|
import FormTopLevelItem from './FormTopLevelItem';
|
|
22
22
|
import type { QuestionnaireResponse, QuestionnaireResponseItem } from 'fhir/r4';
|
|
23
|
-
import useQuestionnaireStore from '../../stores
|
|
24
|
-
import useQuestionnaireResponseStore from '../../stores/useQuestionnaireResponseStore';
|
|
23
|
+
import { useQuestionnaireResponseStore, useQuestionnaireStore } from '../../stores';
|
|
25
24
|
import cloneDeep from 'lodash.clonedeep';
|
|
26
25
|
import { getQrItemsIndex, mapQItemsIndex } from '../../utils/mapItem';
|
|
27
26
|
import { updateQrItemsInGroup } from '../../utils/qrItem';
|
|
28
27
|
import type { QrRepeatGroup } from '../../interfaces/repeatGroup.interface';
|
|
29
28
|
|
|
30
29
|
function BaseRenderer() {
|
|
31
|
-
const sourceQuestionnaire = useQuestionnaireStore
|
|
32
|
-
const updateExpressions = useQuestionnaireStore
|
|
33
|
-
const updatableResponse = useQuestionnaireResponseStore
|
|
34
|
-
const updateResponse = useQuestionnaireResponseStore
|
|
30
|
+
const sourceQuestionnaire = useQuestionnaireStore.use.sourceQuestionnaire();
|
|
31
|
+
const updateExpressions = useQuestionnaireStore.use.updateExpressions();
|
|
32
|
+
const updatableResponse = useQuestionnaireResponseStore.use.updatableResponse();
|
|
33
|
+
const updateResponse = useQuestionnaireResponseStore.use.updateResponse();
|
|
35
34
|
|
|
36
35
|
const qItemsIndexMap = useMemo(() => mapQItemsIndex(sourceQuestionnaire), [sourceQuestionnaire]);
|
|
37
36
|
|
|
@@ -21,7 +21,7 @@ import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4';
|
|
|
21
21
|
import { getQrItemsIndex, mapQItemsIndex } from '../../utils/mapItem';
|
|
22
22
|
import { createEmptyQrGroup, updateQrItemsInGroup } from '../../utils/qrItem';
|
|
23
23
|
import type { PropsWithQrItemChangeHandler } from '../../interfaces/renderProps.interface';
|
|
24
|
-
import useQuestionnaireStore from '../../stores
|
|
24
|
+
import { useQuestionnaireStore } from '../../stores';
|
|
25
25
|
import FormBodySingleCollapsibleWrapper from './FormBodySingleCollapsibleWrapper';
|
|
26
26
|
|
|
27
27
|
interface FormBodyCollapsibleProps extends PropsWithQrItemChangeHandler {
|
|
@@ -32,10 +32,9 @@ interface FormBodyCollapsibleProps extends PropsWithQrItemChangeHandler {
|
|
|
32
32
|
function FormBodyCollapsibleWrapper(props: FormBodyCollapsibleProps) {
|
|
33
33
|
const { topLevelQItem, topLevelQRItem, onQrItemChange } = props;
|
|
34
34
|
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const switchTab = useQuestionnaireStore((state) => state.switchTab);
|
|
35
|
+
const tabs = useQuestionnaireStore.use.tabs();
|
|
36
|
+
const currentTab = useQuestionnaireStore.use.currentTabIndex();
|
|
37
|
+
const switchTab = useQuestionnaireStore.use.switchTab();
|
|
39
38
|
|
|
40
39
|
const indexMap: Record<string, number> = useMemo(
|
|
41
40
|
() => mapQItemsIndex(topLevelQItem),
|
|
@@ -25,7 +25,7 @@ import GroupItem from '../FormComponents/GroupItem/GroupItem';
|
|
|
25
25
|
import { createEmptyQrGroup, updateQrItemsInGroup } from '../../utils/qrItem';
|
|
26
26
|
import FormBodyTabListWrapper from '../Tabs/FormBodyTabListWrapper';
|
|
27
27
|
import type { PropsWithQrItemChangeHandler } from '../../interfaces/renderProps.interface';
|
|
28
|
-
import useQuestionnaireStore from '../../stores
|
|
28
|
+
import { useQuestionnaireStore } from '../../stores';
|
|
29
29
|
|
|
30
30
|
interface FormBodyTabbedProps extends PropsWithQrItemChangeHandler {
|
|
31
31
|
topLevelQItem: QuestionnaireItem;
|
|
@@ -35,8 +35,8 @@ interface FormBodyTabbedProps extends PropsWithQrItemChangeHandler {
|
|
|
35
35
|
function FormBodyTabbed(props: FormBodyTabbedProps) {
|
|
36
36
|
const { topLevelQItem, topLevelQRItem, onQrItemChange } = props;
|
|
37
37
|
|
|
38
|
-
const tabs = useQuestionnaireStore
|
|
39
|
-
const currentTab = useQuestionnaireStore
|
|
38
|
+
const tabs = useQuestionnaireStore.use.tabs();
|
|
39
|
+
const currentTab = useQuestionnaireStore.use.currentTabIndex();
|
|
40
40
|
|
|
41
41
|
const indexMap: Record<string, number> = useMemo(
|
|
42
42
|
() => mapQItemsIndex(topLevelQItem),
|
|
@@ -19,7 +19,7 @@ import React, { memo } from 'react';
|
|
|
19
19
|
import IconButton from '@mui/material/IconButton';
|
|
20
20
|
import Tooltip from '@mui/material/Tooltip';
|
|
21
21
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
|
22
|
-
import useQuestionnaireStore from '../../stores
|
|
22
|
+
import { useQuestionnaireStore } from '../../stores';
|
|
23
23
|
|
|
24
24
|
interface CompleteTabButtonProps {
|
|
25
25
|
tabLinkId: string;
|
|
@@ -29,7 +29,7 @@ interface CompleteTabButtonProps {
|
|
|
29
29
|
const CompleteTabButton = memo(function CompleteTabButton(props: CompleteTabButtonProps) {
|
|
30
30
|
const { tabLinkId, tabIsMarkedAsComplete } = props;
|
|
31
31
|
|
|
32
|
-
const markTabAsComplete = useQuestionnaireStore
|
|
32
|
+
const markTabAsComplete = useQuestionnaireStore.use.markTabAsComplete();
|
|
33
33
|
|
|
34
34
|
return (
|
|
35
35
|
<Tooltip title={tabIsMarkedAsComplete ? 'Mark as incomplete' : 'Complete tab'}>
|
|
@@ -20,8 +20,7 @@ import Box from '@mui/material/Box';
|
|
|
20
20
|
import ListItemButton from '@mui/material/ListItemButton';
|
|
21
21
|
import ListItemText from '@mui/material/ListItemText';
|
|
22
22
|
import Typography from '@mui/material/Typography';
|
|
23
|
-
|
|
24
|
-
import useQuestionnaireStore from '../../stores/useQuestionnaireStore';
|
|
23
|
+
import { useQuestionnaireStore } from '../../stores';
|
|
25
24
|
import type { QuestionnaireItem } from 'fhir/r4';
|
|
26
25
|
import ContextDisplayItem from '../FormComponents/ItemParts/ContextDisplayItem';
|
|
27
26
|
|
|
@@ -35,7 +34,7 @@ interface FormBodySingleTabProps {
|
|
|
35
34
|
const FormBodySingleTab = memo(function FormBodySingleTab(props: FormBodySingleTabProps) {
|
|
36
35
|
const { contextDisplayItems, selected, tabLabel, listIndex } = props;
|
|
37
36
|
|
|
38
|
-
const switchTab = useQuestionnaireStore
|
|
37
|
+
const switchTab = useQuestionnaireStore.use.switchTab();
|
|
39
38
|
|
|
40
39
|
function handleTabClick() {
|
|
41
40
|
switchTab(listIndex);
|
|
@@ -22,7 +22,7 @@ import { getShortText } from '../../utils/itemControl';
|
|
|
22
22
|
import type { QuestionnaireItem } from 'fhir/r4';
|
|
23
23
|
import FormBodySingleTab from './FormBodySingleTab';
|
|
24
24
|
import type { Tabs } from '../../interfaces/tab.interface';
|
|
25
|
-
import useQuestionnaireStore from '../../stores
|
|
25
|
+
import { useQuestionnaireStore } from '../../stores';
|
|
26
26
|
import { isTabHidden } from '../../utils/tabs';
|
|
27
27
|
|
|
28
28
|
interface FormBodyTabListProps {
|
|
@@ -37,9 +37,9 @@ const FormBodyTabList = memo(function FormBodyTabList(props: FormBodyTabListProp
|
|
|
37
37
|
const { topLevelItems, currentTabIndex, tabs, completedTabsCollapsed, allContextDisplayItems } =
|
|
38
38
|
props;
|
|
39
39
|
|
|
40
|
-
const enableWhenIsActivated = useQuestionnaireStore
|
|
41
|
-
const enableWhenItems = useQuestionnaireStore
|
|
42
|
-
const enableWhenExpressions = useQuestionnaireStore
|
|
40
|
+
const enableWhenIsActivated = useQuestionnaireStore.use.enableWhenIsActivated();
|
|
41
|
+
const enableWhenItems = useQuestionnaireStore.use.enableWhenItems();
|
|
42
|
+
const enableWhenExpressions = useQuestionnaireStore.use.enableWhenExpressions();
|
|
43
43
|
|
|
44
44
|
return (
|
|
45
45
|
<TransitionGroup>
|