@aehrc/smart-forms-renderer 0.13.2 → 0.15.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 (143) hide show
  1. package/lib/components/FormComponents/AttachmentItem/AttachmentField.d.ts +13 -0
  2. package/lib/components/FormComponents/AttachmentItem/AttachmentField.js +39 -0
  3. package/lib/components/FormComponents/AttachmentItem/AttachmentField.js.map +1 -0
  4. package/lib/components/FormComponents/AttachmentItem/AttachmentFieldWrapper.d.ts +14 -0
  5. package/lib/components/FormComponents/AttachmentItem/AttachmentFieldWrapper.js +34 -0
  6. package/lib/components/FormComponents/AttachmentItem/AttachmentFieldWrapper.js.map +1 -0
  7. package/lib/components/FormComponents/AttachmentItem/AttachmentFileCollector.d.ts +8 -0
  8. package/lib/components/FormComponents/AttachmentItem/AttachmentFileCollector.js +61 -0
  9. package/lib/components/FormComponents/AttachmentItem/AttachmentFileCollector.js.map +1 -0
  10. package/lib/components/FormComponents/AttachmentItem/AttachmentFileDropBox.d.ts +11 -0
  11. package/lib/components/FormComponents/AttachmentItem/AttachmentFileDropBox.js +49 -0
  12. package/lib/components/FormComponents/AttachmentItem/AttachmentFileDropBox.js.map +1 -0
  13. package/lib/components/FormComponents/AttachmentItem/AttachmentFileDropBox.styles.d.ts +7 -0
  14. package/lib/components/FormComponents/AttachmentItem/AttachmentFileDropBox.styles.js +30 -0
  15. package/lib/components/FormComponents/AttachmentItem/AttachmentFileDropBox.styles.js.map +1 -0
  16. package/lib/components/FormComponents/AttachmentItem/AttachmentItem.d.ts +14 -0
  17. package/lib/components/FormComponents/AttachmentItem/AttachmentItem.js +86 -0
  18. package/lib/components/FormComponents/AttachmentItem/AttachmentItem.js.map +1 -0
  19. package/lib/components/FormComponents/AttachmentItem/AttachmentUrlField.d.ts +10 -0
  20. package/lib/components/FormComponents/AttachmentItem/AttachmentUrlField.js +39 -0
  21. package/lib/components/FormComponents/AttachmentItem/AttachmentUrlField.js.map +1 -0
  22. package/lib/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.d.ts +1 -1
  23. package/lib/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.js +2 -2
  24. package/lib/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.js.map +1 -1
  25. package/lib/components/FormComponents/ChoiceItems/ChoiceCheckboxAnswerValueSetFields.d.ts +2 -1
  26. package/lib/components/FormComponents/ChoiceItems/ChoiceCheckboxAnswerValueSetFields.js +6 -3
  27. package/lib/components/FormComponents/ChoiceItems/ChoiceCheckboxAnswerValueSetFields.js.map +1 -1
  28. package/lib/components/FormComponents/ChoiceItems/ChoiceCheckboxAnswerValueSetItem.js +3 -3
  29. package/lib/components/FormComponents/ChoiceItems/ChoiceCheckboxAnswerValueSetItem.js.map +1 -1
  30. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.d.ts +2 -1
  31. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.js +6 -3
  32. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.js.map +1 -1
  33. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.js +3 -3
  34. package/lib/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.js.map +1 -1
  35. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.js +2 -1
  36. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.js.map +1 -1
  37. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetFields.d.ts +2 -1
  38. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetFields.js +8 -5
  39. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetFields.js.map +1 -1
  40. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetItem.js +3 -3
  41. package/lib/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetItem.js.map +1 -1
  42. package/lib/components/FormComponents/DateItem/DateField.js +2 -1
  43. package/lib/components/FormComponents/DateItem/DateField.js.map +1 -1
  44. package/lib/components/FormComponents/DateTimeItem/DateTimeField.js +2 -1
  45. package/lib/components/FormComponents/DateTimeItem/DateTimeField.js.map +1 -1
  46. package/lib/components/FormComponents/GridGroup/GridRow.js +1 -1
  47. package/lib/components/FormComponents/GridGroup/GridRow.js.map +1 -1
  48. package/lib/components/FormComponents/GroupItem/GroupItemSwitcher.js +2 -2
  49. package/lib/components/FormComponents/GroupItem/GroupItemSwitcher.js.map +1 -1
  50. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceAutocompleteField.js +2 -2
  51. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceAutocompleteField.js.map +1 -1
  52. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerOptionField.js +2 -2
  53. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerOptionField.js.map +1 -1
  54. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetField.d.ts +2 -1
  55. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetField.js +7 -4
  56. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetField.js.map +1 -1
  57. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetItem.js +3 -3
  58. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetItem.js.map +1 -1
  59. package/lib/components/FormComponents/RepeatGroup/AddItemButton.js +2 -1
  60. package/lib/components/FormComponents/RepeatGroup/AddItemButton.js.map +1 -1
  61. package/lib/components/FormComponents/RepeatItem/AddItemButton.js +2 -1
  62. package/lib/components/FormComponents/RepeatItem/AddItemButton.js.map +1 -1
  63. package/lib/components/FormComponents/RepeatItem/RepeatField.d.ts +1 -0
  64. package/lib/components/FormComponents/RepeatItem/RepeatField.js +2 -2
  65. package/lib/components/FormComponents/RepeatItem/RepeatField.js.map +1 -1
  66. package/lib/components/FormComponents/RepeatItem/RepeatItem.d.ts +1 -0
  67. package/lib/components/FormComponents/RepeatItem/RepeatItem.js +3 -3
  68. package/lib/components/FormComponents/RepeatItem/RepeatItem.js.map +1 -1
  69. package/lib/components/FormComponents/SingleItem/SingleItem.d.ts +1 -0
  70. package/lib/components/FormComponents/SingleItem/SingleItem.js +15 -3
  71. package/lib/components/FormComponents/SingleItem/SingleItem.js.map +1 -1
  72. package/lib/components/FormComponents/SingleItem/SingleItemSwitcher.js +28 -16
  73. package/lib/components/FormComponents/SingleItem/SingleItemSwitcher.js.map +1 -1
  74. package/lib/components/FormComponents/SingleItem/SingleNestedItems.d.ts +10 -0
  75. package/lib/components/FormComponents/SingleItem/SingleNestedItems.js +52 -0
  76. package/lib/components/FormComponents/SingleItem/SingleNestedItems.js.map +1 -0
  77. package/lib/components/FormComponents/SliderItem/SliderField.js +2 -1
  78. package/lib/components/FormComponents/SliderItem/SliderField.js.map +1 -1
  79. package/lib/components/FormComponents/Tables/GroupTableRowCells.js +1 -1
  80. package/lib/components/FormComponents/Tables/GroupTableRowCells.js.map +1 -1
  81. package/lib/components/FormComponents/Textfield.styles.d.ts +1 -0
  82. package/lib/components/FormComponents/Textfield.styles.js +2 -1
  83. package/lib/components/FormComponents/Textfield.styles.js.map +1 -1
  84. package/lib/components/FormComponents/TimeItem/TimeField.js +2 -1
  85. package/lib/components/FormComponents/TimeItem/TimeField.js.map +1 -1
  86. package/lib/components/Renderer/FormTopLevelItem.js +1 -1
  87. package/lib/components/Renderer/FormTopLevelItem.js.map +1 -1
  88. package/lib/hooks/UseFileDrop.d.ts +10 -0
  89. package/lib/hooks/UseFileDrop.js +40 -0
  90. package/lib/hooks/UseFileDrop.js.map +1 -0
  91. package/lib/hooks/useAttachmentUrlValidation.d.ts +2 -0
  92. package/lib/hooks/useAttachmentUrlValidation.js +27 -0
  93. package/lib/hooks/useAttachmentUrlValidation.js.map +1 -0
  94. package/lib/hooks/useValueSetCodings.d.ts +5 -1
  95. package/lib/hooks/useValueSetCodings.js +1 -1
  96. package/lib/hooks/useValueSetCodings.js.map +1 -1
  97. package/lib/utils/fileUtils.d.ts +3 -0
  98. package/lib/utils/fileUtils.js +64 -0
  99. package/lib/utils/fileUtils.js.map +1 -0
  100. package/lib/utils/validateQuestionnaire.d.ts +3 -5
  101. package/lib/utils/validateQuestionnaire.js +8 -5
  102. package/lib/utils/validateQuestionnaire.js.map +1 -1
  103. package/package.json +3 -1
  104. package/src/components/FormComponents/AttachmentItem/AttachmentField.tsx +96 -0
  105. package/src/components/FormComponents/AttachmentItem/AttachmentFieldWrapper.tsx +87 -0
  106. package/src/components/FormComponents/AttachmentItem/AttachmentFileCollector.tsx +101 -0
  107. package/src/components/FormComponents/AttachmentItem/AttachmentFileDropBox.styles.ts +31 -0
  108. package/src/components/FormComponents/AttachmentItem/AttachmentFileDropBox.tsx +66 -0
  109. package/src/components/FormComponents/AttachmentItem/AttachmentItem.tsx +123 -0
  110. package/src/components/FormComponents/AttachmentItem/AttachmentUrlField.tsx +78 -0
  111. package/src/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.tsx +3 -3
  112. package/src/components/FormComponents/ChoiceItems/ChoiceCheckboxAnswerValueSetFields.tsx +6 -4
  113. package/src/components/FormComponents/ChoiceItems/ChoiceCheckboxAnswerValueSetItem.tsx +3 -3
  114. package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.tsx +7 -4
  115. package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.tsx +3 -3
  116. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.tsx +2 -1
  117. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetFields.tsx +9 -6
  118. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetItem.tsx +3 -3
  119. package/src/components/FormComponents/DateItem/DateField.tsx +2 -1
  120. package/src/components/FormComponents/DateTimeItem/DateTimeField.tsx +2 -1
  121. package/src/components/FormComponents/GridGroup/GridRow.tsx +1 -0
  122. package/src/components/FormComponents/GroupItem/GroupItemSwitcher.tsx +2 -0
  123. package/src/components/FormComponents/OpenChoiceItems/OpenChoiceAutocompleteField.tsx +2 -2
  124. package/src/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerOptionField.tsx +2 -2
  125. package/src/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetField.tsx +9 -6
  126. package/src/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetItem.tsx +3 -3
  127. package/src/components/FormComponents/RepeatGroup/AddItemButton.tsx +1 -1
  128. package/src/components/FormComponents/RepeatItem/AddItemButton.tsx +1 -1
  129. package/src/components/FormComponents/RepeatItem/RepeatField.tsx +3 -0
  130. package/src/components/FormComponents/RepeatItem/RepeatItem.tsx +5 -1
  131. package/src/components/FormComponents/SingleItem/SingleItem.tsx +47 -12
  132. package/src/components/FormComponents/SingleItem/SingleItemSwitcher.tsx +67 -31
  133. package/src/components/FormComponents/SingleItem/SingleNestedItems.tsx +91 -0
  134. package/src/components/FormComponents/SliderItem/SliderField.tsx +2 -1
  135. package/src/components/FormComponents/Tables/GroupTableRowCells.tsx +1 -0
  136. package/src/components/FormComponents/Textfield.styles.ts +3 -1
  137. package/src/components/FormComponents/TimeItem/TimeField.tsx +2 -1
  138. package/src/components/Renderer/FormTopLevelItem.tsx +1 -0
  139. package/src/hooks/UseFileDrop.ts +53 -0
  140. package/src/hooks/useAttachmentUrlValidation.ts +27 -0
  141. package/src/hooks/useValueSetCodings.ts +10 -2
  142. package/src/utils/fileUtils.ts +66 -0
  143. package/src/utils/validateQuestionnaire.ts +17 -13
@@ -21,7 +21,7 @@ import CircularProgress from '@mui/material/CircularProgress';
21
21
  import Fade from '@mui/material/Fade';
22
22
  import Tooltip from '@mui/material/Tooltip';
23
23
  import type { Coding, QuestionnaireItem } from 'fhir/r4';
24
- import { StandardTextField } from '../Textfield.styles';
24
+ import { StandardTextField, TEXT_FIELD_WIDTH } from '../Textfield.styles';
25
25
  import SearchIcon from '@mui/icons-material/Search';
26
26
  import InfoIcon from '@mui/icons-material/Info';
27
27
  import WarningAmberIcon from '@mui/icons-material/WarningAmber';
@@ -32,7 +32,7 @@ import type {
32
32
  PropsWithIsTabledAttribute,
33
33
  PropsWithParentIsReadOnlyAttribute
34
34
  } from '../../../interfaces/renderProps.interface';
35
- import { AlertColor } from '@mui/material/Alert';
35
+ import type { AlertColor } from '@mui/material/Alert';
36
36
 
37
37
  interface ChoiceAutocompleteFieldsProps
38
38
  extends PropsWithIsTabledAttribute,
@@ -75,7 +75,7 @@ function ChoiceAutocompleteField(props: ChoiceAutocompleteFieldsProps) {
75
75
  clearOnEscape
76
76
  autoHighlight
77
77
  onChange={(_, newValue) => onValueChange(newValue)}
78
- sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160, flexGrow: 1 }}
78
+ sx={{ maxWidth: !isTabled ? TEXT_FIELD_WIDTH : 3000, minWidth: 160, flexGrow: 1 }}
79
79
  filterOptions={(x) => x}
80
80
  renderInput={(params) => (
81
81
  <StandardTextField
@@ -23,18 +23,19 @@ import { StyledFormGroup } from '../Item.styles';
23
23
  import { StyledAlert } from '../../Alert.styles';
24
24
  import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
25
25
  import Typography from '@mui/material/Typography';
26
+ import type { TerminologyError } from '../../../hooks/useValueSetCodings';
26
27
 
27
28
  interface ChoiceCheckboxAnswerValueSetFieldsProps {
28
29
  codings: Coding[];
29
30
  answers: QuestionnaireResponseItemAnswer[];
30
31
  orientation: ChoiceItemOrientation;
31
32
  readOnly: boolean;
32
- serverError: Error | null;
33
+ terminologyError: TerminologyError;
33
34
  onCheckedChange: (newValue: string) => void;
34
35
  }
35
36
 
36
37
  function ChoiceCheckboxAnswerValueSetFields(props: ChoiceCheckboxAnswerValueSetFieldsProps) {
37
- const { codings, answers, orientation, readOnly, serverError, onCheckedChange } = props;
38
+ const { codings, answers, orientation, readOnly, terminologyError, onCheckedChange } = props;
38
39
 
39
40
  if (codings.length > 0) {
40
41
  return (
@@ -55,12 +56,13 @@ function ChoiceCheckboxAnswerValueSetFields(props: ChoiceCheckboxAnswerValueSetF
55
56
  );
56
57
  }
57
58
 
58
- if (serverError) {
59
+ if (terminologyError.error) {
59
60
  return (
60
61
  <StyledAlert color="error">
61
62
  <ErrorOutlineIcon color="error" sx={{ pr: 0.75 }} />
62
63
  <Typography variant="subtitle2">
63
- There was an error fetching options from the terminology server
64
+ There was an error fetching options from the terminology server for{' '}
65
+ {terminologyError.answerValueSet}
64
66
  </Typography>
65
67
  </StyledAlert>
66
68
  );
@@ -64,7 +64,7 @@ function ChoiceCheckboxAnswerValueSetItem(props: ChoiceCheckboxAnswerValueSetIte
64
64
  const { displayInstructions } = useRenderingExtensions(qItem);
65
65
 
66
66
  // Get codings/options from valueSet
67
- const { codings, serverError } = useValueSetCodings(qItem);
67
+ const { codings, terminologyError } = useValueSetCodings(qItem);
68
68
 
69
69
  // Event handlers
70
70
  function handleCheckedChange(changedValue: string) {
@@ -91,7 +91,7 @@ function ChoiceCheckboxAnswerValueSetItem(props: ChoiceCheckboxAnswerValueSetIte
91
91
  answers={answers}
92
92
  orientation={orientation}
93
93
  readOnly={readOnly}
94
- serverError={serverError}
94
+ terminologyError={terminologyError}
95
95
  onCheckedChange={handleCheckedChange}
96
96
  />
97
97
  <DisplayInstructions displayInstructions={displayInstructions} readOnly={readOnly} />
@@ -107,7 +107,7 @@ function ChoiceCheckboxAnswerValueSetItem(props: ChoiceCheckboxAnswerValueSetIte
107
107
  answers={answers}
108
108
  orientation={orientation}
109
109
  readOnly={readOnly}
110
- serverError={serverError}
110
+ terminologyError={terminologyError}
111
111
  onCheckedChange={handleCheckedChange}
112
112
  />
113
113
  </ItemFieldGrid>
@@ -23,6 +23,7 @@ import ChoiceRadioSingle from './ChoiceRadioSingle';
23
23
  import { StyledRadioGroup } from '../Item.styles';
24
24
  import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
25
25
  import { StyledAlert } from '../../Alert.styles';
26
+ import type { TerminologyError } from '../../../hooks/useValueSetCodings';
26
27
 
27
28
  interface ChoiceRadioAnswerValueSetFieldsProps {
28
29
  qItem: QuestionnaireItem;
@@ -30,12 +31,13 @@ interface ChoiceRadioAnswerValueSetFieldsProps {
30
31
  valueRadio: string | null;
31
32
  orientation: ChoiceItemOrientation;
32
33
  readOnly: boolean;
33
- serverError: Error | null;
34
+ terminologyError: TerminologyError;
34
35
  onCheckedChange: (newValue: string) => void;
35
36
  }
36
37
 
37
38
  function ChoiceRadioAnswerValueSetFields(props: ChoiceRadioAnswerValueSetFieldsProps) {
38
- const { qItem, codings, valueRadio, orientation, readOnly, serverError, onCheckedChange } = props;
39
+ const { qItem, codings, valueRadio, orientation, readOnly, terminologyError, onCheckedChange } =
40
+ props;
39
41
 
40
42
  if (codings.length > 0) {
41
43
  return (
@@ -59,12 +61,13 @@ function ChoiceRadioAnswerValueSetFields(props: ChoiceRadioAnswerValueSetFieldsP
59
61
  );
60
62
  }
61
63
 
62
- if (serverError) {
64
+ if (terminologyError.error) {
63
65
  return (
64
66
  <StyledAlert color="error">
65
67
  <ErrorOutlineIcon color="error" sx={{ pr: 0.75 }} />
66
68
  <Typography variant="subtitle2">
67
- There was an error fetching options from the terminology server
69
+ There was an error fetching options from the terminology server for{' '}
70
+ {terminologyError.answerValueSet}
68
71
  </Typography>
69
72
  </StyledAlert>
70
73
  );
@@ -54,7 +54,7 @@ function ChoiceRadioAnswerValueSetItem(props: ChoiceRadioAnswerValueSetItemProps
54
54
  }
55
55
 
56
56
  // Get codings/options from valueSet
57
- const { codings, serverError } = useValueSetCodings(qItem);
57
+ const { codings, terminologyError } = useValueSetCodings(qItem);
58
58
 
59
59
  function handleChange(newValue: string) {
60
60
  if (codings.length > 0) {
@@ -76,7 +76,7 @@ function ChoiceRadioAnswerValueSetItem(props: ChoiceRadioAnswerValueSetItemProps
76
76
  valueRadio={valueRadio}
77
77
  orientation={orientation}
78
78
  readOnly={readOnly}
79
- serverError={serverError}
79
+ terminologyError={terminologyError}
80
80
  onCheckedChange={handleChange}
81
81
  />
82
82
  );
@@ -91,7 +91,7 @@ function ChoiceRadioAnswerValueSetItem(props: ChoiceRadioAnswerValueSetItemProps
91
91
  valueRadio={valueRadio}
92
92
  orientation={orientation}
93
93
  readOnly={readOnly}
94
- serverError={serverError}
94
+ terminologyError={terminologyError}
95
95
  onCheckedChange={handleChange}
96
96
  />
97
97
  </ItemFieldGrid>
@@ -22,6 +22,7 @@ import Select from '@mui/material/Select';
22
22
  import type { QuestionnaireItem } from 'fhir/r4';
23
23
  import useRenderingExtensions from '../../../hooks/useRenderingExtensions';
24
24
  import type { PropsWithIsTabledAttribute } from '../../../interfaces/renderProps.interface';
25
+ import { TEXT_FIELD_WIDTH } from '../Textfield.styles';
25
26
 
26
27
  interface ChoiceSelectAnswerOptionFieldsProps extends PropsWithIsTabledAttribute {
27
28
  qItem: QuestionnaireItem;
@@ -45,7 +46,7 @@ function ChoiceSelectAnswerOptionFields(props: ChoiceSelectAnswerOptionFieldsPro
45
46
  placeholder={entryFormat}
46
47
  label={displayPrompt}
47
48
  endAdornment={<InputAdornment position={'end'}>{displayUnit}</InputAdornment>}
48
- sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160 }}
49
+ sx={{ maxWidth: !isTabled ? TEXT_FIELD_WIDTH : 3000, minWidth: 160 }}
49
50
  size="small"
50
51
  onChange={(e) => onSelectChange(e.target.value)}>
51
52
  {qItem.answerOption?.map((option, index) => {
@@ -17,25 +17,27 @@
17
17
 
18
18
  import React from 'react';
19
19
  import Autocomplete from '@mui/material/Autocomplete';
20
- import { StandardTextField } from '../Textfield.styles';
20
+ import { StandardTextField, TEXT_FIELD_WIDTH } from '../Textfield.styles';
21
21
  import { StyledAlert } from '../../Alert.styles';
22
22
  import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
23
23
  import Typography from '@mui/material/Typography';
24
24
  import type { Coding, QuestionnaireItem } from 'fhir/r4';
25
25
  import useRenderingExtensions from '../../../hooks/useRenderingExtensions';
26
26
  import type { PropsWithIsTabledAttribute } from '../../../interfaces/renderProps.interface';
27
+ import type { TerminologyError } from '../../../hooks/useValueSetCodings';
27
28
 
28
29
  interface ChoiceSelectAnswerValueSetFieldsProps extends PropsWithIsTabledAttribute {
29
30
  qItem: QuestionnaireItem;
30
31
  codings: Coding[];
31
32
  valueCoding: Coding | null;
32
- serverError: Error | null;
33
+ terminologyError: TerminologyError;
33
34
  readOnly: boolean;
34
35
  onSelectChange: (newValue: Coding | null) => void;
35
36
  }
36
37
 
37
38
  function ChoiceSelectAnswerValueSetFields(props: ChoiceSelectAnswerValueSetFieldsProps) {
38
- const { qItem, codings, valueCoding, serverError, readOnly, isTabled, onSelectChange } = props;
39
+ const { qItem, codings, valueCoding, terminologyError, readOnly, isTabled, onSelectChange } =
40
+ props;
39
41
 
40
42
  const { displayUnit, displayPrompt, entryFormat } = useRenderingExtensions(qItem);
41
43
 
@@ -49,7 +51,7 @@ function ChoiceSelectAnswerValueSetFields(props: ChoiceSelectAnswerValueSetField
49
51
  onChange={(_, newValue) => onSelectChange(newValue)}
50
52
  openOnFocus
51
53
  autoHighlight
52
- sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160, flexGrow: 1 }}
54
+ sx={{ maxWidth: !isTabled ? TEXT_FIELD_WIDTH : 3000, minWidth: 160, flexGrow: 1 }}
53
55
  size="small"
54
56
  disabled={readOnly}
55
57
  renderInput={(params) => (
@@ -74,12 +76,13 @@ function ChoiceSelectAnswerValueSetFields(props: ChoiceSelectAnswerValueSetField
74
76
  );
75
77
  }
76
78
 
77
- if (serverError) {
79
+ if (terminologyError.error) {
78
80
  return (
79
81
  <StyledAlert color="error">
80
82
  <ErrorOutlineIcon color="error" sx={{ pr: 0.75 }} />
81
83
  <Typography variant="subtitle2">
82
- There was an error fetching options from the terminology server
84
+ There was an error fetching options from the terminology server for{' '}
85
+ {terminologyError.answerValueSet}
83
86
  </Typography>
84
87
  </StyledAlert>
85
88
  );
@@ -53,7 +53,7 @@ function ChoiceSelectAnswerValueSetItem(props: ChoiceSelectAnswerValueSetItemPro
53
53
  }
54
54
 
55
55
  // Get codings/options from valueSet
56
- const { codings, serverError } = useValueSetCodings(qItem);
56
+ const { codings, terminologyError } = useValueSetCodings(qItem);
57
57
 
58
58
  valueCoding = useMemo(() => {
59
59
  const updatedValueCoding = codings.find(
@@ -94,7 +94,7 @@ function ChoiceSelectAnswerValueSetItem(props: ChoiceSelectAnswerValueSetItemPro
94
94
  qItem={qItem}
95
95
  codings={codings}
96
96
  valueCoding={valueCoding}
97
- serverError={serverError}
97
+ terminologyError={terminologyError}
98
98
  readOnly={readOnly}
99
99
  isTabled={isTabled}
100
100
  onSelectChange={handleChange}
@@ -109,7 +109,7 @@ function ChoiceSelectAnswerValueSetItem(props: ChoiceSelectAnswerValueSetItemPro
109
109
  qItem={qItem}
110
110
  codings={codings}
111
111
  valueCoding={valueCoding}
112
- serverError={serverError}
112
+ terminologyError={terminologyError}
113
113
  readOnly={readOnly}
114
114
  isTabled={isTabled}
115
115
  onSelectChange={handleChange}
@@ -20,6 +20,7 @@ import type { PropsWithIsTabledAttribute } from '../../../interfaces/renderProps
20
20
  import type { Dayjs } from 'dayjs';
21
21
  import { DatePicker as MuiDatePicker, LocalizationProvider } from '@mui/x-date-pickers';
22
22
  import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
23
+ import { TEXT_FIELD_WIDTH } from '../Textfield.styles';
23
24
 
24
25
  interface DateFieldProps extends PropsWithIsTabledAttribute {
25
26
  value: Dayjs | null;
@@ -39,7 +40,7 @@ function DateField(props: DateFieldProps) {
39
40
  value={value}
40
41
  disabled={readOnly}
41
42
  label={displayPrompt}
42
- sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160 }}
43
+ sx={{ maxWidth: !isTabled ? TEXT_FIELD_WIDTH : 3000, minWidth: 160 }}
43
44
  onChange={onDateChange}
44
45
  slotProps={{
45
46
  textField: {
@@ -21,6 +21,7 @@ import type { Dayjs } from 'dayjs';
21
21
  import { DateTimePicker as MuiDateTimePicker, LocalizationProvider } from '@mui/x-date-pickers';
22
22
  import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
23
23
  import Box from '@mui/material/Box';
24
+ import { TEXT_FIELD_WIDTH } from '../Textfield.styles';
24
25
 
25
26
  interface DateTimeFieldProps extends PropsWithIsTabledAttribute {
26
27
  value: Dayjs | null;
@@ -41,7 +42,7 @@ function DateTimeField(props: DateTimeFieldProps) {
41
42
  value={value}
42
43
  disabled={readOnly}
43
44
  label={displayPrompt}
44
- sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160 }}
45
+ sx={{ maxWidth: !isTabled ? TEXT_FIELD_WIDTH : 3000, minWidth: 160 }}
45
46
  onChange={onDateTimeChange}
46
47
  slotProps={{
47
48
  textField: {
@@ -85,6 +85,7 @@ function GridRow(props: GridRowProps) {
85
85
  qrItem={cellQrItem ?? null}
86
86
  isRepeated={true}
87
87
  isTabled={true}
88
+ groupCardElevation={1}
88
89
  showMinimalView={true}
89
90
  parentIsReadOnly={parentIsReadOnly}
90
91
  onQrItemChange={handleQrRowItemChange}
@@ -136,6 +136,7 @@ function GroupItemSwitcher(props: GroupItemSwitcherProps) {
136
136
  <RepeatItem
137
137
  qItem={qItem}
138
138
  qrItem={qrItem ?? null}
139
+ groupCardElevation={groupCardElevation + 1}
139
140
  parentIsReadOnly={parentIsReadOnly}
140
141
  onQrItemChange={onQrItemChange}
141
142
  />
@@ -163,6 +164,7 @@ function GroupItemSwitcher(props: GroupItemSwitcherProps) {
163
164
  qrItem={qrItem ?? null}
164
165
  isRepeated={false}
165
166
  isTabled={false}
167
+ groupCardElevation={groupCardElevation + 1}
166
168
  parentIsReadOnly={parentIsReadOnly}
167
169
  onQrItemChange={onQrItemChange}
168
170
  />
@@ -18,7 +18,7 @@
18
18
  import React from 'react';
19
19
  import Box from '@mui/material/Box';
20
20
  import Autocomplete from '@mui/material/Autocomplete';
21
- import { StandardTextField } from '../Textfield.styles';
21
+ import { StandardTextField, TEXT_FIELD_WIDTH } from '../Textfield.styles';
22
22
  import SearchIcon from '@mui/icons-material/Search';
23
23
  import CircularProgress from '@mui/material/CircularProgress';
24
24
  import Fade from '@mui/material/Fade';
@@ -80,7 +80,7 @@ function OpenChoiceAutocompleteField(props: OpenChoiceAutocompleteFieldProps) {
80
80
  clearOnEscape
81
81
  freeSolo
82
82
  autoHighlight
83
- sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 220, flexGrow: 1 }}
83
+ sx={{ maxWidth: !isTabled ? TEXT_FIELD_WIDTH : 3000, minWidth: 220, flexGrow: 1 }}
84
84
  onChange={(_, newValue) => onValueChange(newValue)}
85
85
  filterOptions={(x) => x}
86
86
  renderInput={(params) => (
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { getAnswerOptionLabel } from '../../../utils/openChoice';
3
- import { StandardTextField } from '../Textfield.styles';
3
+ import { StandardTextField, TEXT_FIELD_WIDTH } from '../Textfield.styles';
4
4
  import Autocomplete from '@mui/material/Autocomplete';
5
5
  import type { QuestionnaireItem, QuestionnaireItemAnswerOption } from 'fhir/r4';
6
6
  import type {
@@ -33,7 +33,7 @@ function OpenChoiceSelectAnswerOptionField(props: OpenChoiceSelectAnswerOptionFi
33
33
  onChange={(_, newValue) => onChange(newValue)}
34
34
  freeSolo
35
35
  autoHighlight
36
- sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160, flexGrow: 1 }}
36
+ sx={{ maxWidth: !isTabled ? TEXT_FIELD_WIDTH : 3000, minWidth: 160, flexGrow: 1 }}
37
37
  disabled={readOnly}
38
38
  size="small"
39
39
  renderInput={(params) => (
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import Autocomplete from '@mui/material/Autocomplete';
3
- import { StandardTextField } from '../Textfield.styles';
3
+ import { StandardTextField, TEXT_FIELD_WIDTH } from '../Textfield.styles';
4
4
  import Typography from '@mui/material/Typography';
5
5
  import type {
6
6
  PropsWithIsTabledAttribute,
@@ -8,6 +8,7 @@ import type {
8
8
  } from '../../../interfaces/renderProps.interface';
9
9
  import type { Coding, QuestionnaireItem } from 'fhir/r4';
10
10
  import useRenderingExtensions from '../../../hooks/useRenderingExtensions';
11
+ import type { TerminologyError } from '../../../hooks/useValueSetCodings';
11
12
 
12
13
  interface OpenChoiceSelectAnswerValueSetFieldProps
13
14
  extends PropsWithIsTabledAttribute,
@@ -15,13 +16,14 @@ interface OpenChoiceSelectAnswerValueSetFieldProps
15
16
  qItem: QuestionnaireItem;
16
17
  options: Coding[];
17
18
  valueSelect: Coding | null;
18
- serverError: Error | null;
19
+ terminologyError: TerminologyError;
19
20
  readOnly: boolean;
20
21
  onValueChange: (newValue: Coding | string | null) => void;
21
22
  }
22
23
 
23
24
  function OpenChoiceSelectAnswerValueSetField(props: OpenChoiceSelectAnswerValueSetFieldProps) {
24
- const { qItem, options, valueSelect, serverError, readOnly, isTabled, onValueChange } = props;
25
+ const { qItem, options, valueSelect, terminologyError, readOnly, isTabled, onValueChange } =
26
+ props;
25
27
 
26
28
  const { displayUnit, displayPrompt, entryFormat } = useRenderingExtensions(qItem);
27
29
 
@@ -36,7 +38,7 @@ function OpenChoiceSelectAnswerValueSetField(props: OpenChoiceSelectAnswerValueS
36
38
  onInputChange={(_, newValue) => onValueChange(newValue)}
37
39
  freeSolo
38
40
  autoHighlight
39
- sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160, flexGrow: 1 }}
41
+ sx={{ maxWidth: !isTabled ? TEXT_FIELD_WIDTH : 3000, minWidth: 160, flexGrow: 1 }}
40
42
  disabled={readOnly}
41
43
  size="small"
42
44
  renderInput={(params) => (
@@ -57,9 +59,10 @@ function OpenChoiceSelectAnswerValueSetField(props: OpenChoiceSelectAnswerValueS
57
59
  />
58
60
  )}
59
61
  />
60
- {serverError ? (
62
+ {terminologyError.error ? (
61
63
  <Typography variant="subtitle2">
62
- There was an error fetching options from the terminology server.
64
+ There was an error fetching options from the terminology server for{' '}
65
+ {terminologyError.answerValueSet}
63
66
  </Typography>
64
67
  ) : null}
65
68
  </>
@@ -52,7 +52,7 @@ function OpenChoiceSelectAnswerValueSetItem(props: OpenChoiceSelectAnswerValueSe
52
52
  }
53
53
 
54
54
  // Get codings/options from valueSet
55
- const { codings, serverError } = useValueSetCodings(qItem);
55
+ const { codings, terminologyError } = useValueSetCodings(qItem);
56
56
 
57
57
  // Event handlers
58
58
  function handleValueChange(newValue: Coding | string | null) {
@@ -79,7 +79,7 @@ function OpenChoiceSelectAnswerValueSetItem(props: OpenChoiceSelectAnswerValueSe
79
79
  qItem={qItem}
80
80
  options={codings}
81
81
  valueSelect={valueSelect}
82
- serverError={serverError}
82
+ terminologyError={terminologyError}
83
83
  isTabled={isTabled}
84
84
  readOnly={readOnly}
85
85
  onValueChange={handleValueChange}
@@ -94,7 +94,7 @@ function OpenChoiceSelectAnswerValueSetItem(props: OpenChoiceSelectAnswerValueSe
94
94
  qItem={qItem}
95
95
  options={codings}
96
96
  valueSelect={valueSelect}
97
- serverError={serverError}
97
+ terminologyError={terminologyError}
98
98
  isTabled={isTabled}
99
99
  readOnly={readOnly}
100
100
  onValueChange={handleValueChange}
@@ -30,7 +30,7 @@ interface AddItemButtonProps {
30
30
  function AddItemButton(props: AddItemButtonProps) {
31
31
  const { repeatGroups, readOnly, onAddItem } = props;
32
32
 
33
- const isDisabled = repeatGroups[repeatGroups.length - 1].qrItem === null || readOnly;
33
+ const isDisabled = repeatGroups[repeatGroups.length - 1]?.qrItem === null || readOnly;
34
34
 
35
35
  return (
36
36
  <Box display="flex" flexDirection="row-reverse">
@@ -30,7 +30,7 @@ interface AddItemButtonProps {
30
30
  function AddItemButton(props: AddItemButtonProps) {
31
31
  const { repeatAnswers, readOnly, onAddItem } = props;
32
32
 
33
- const isDisabled = repeatAnswers[repeatAnswers.length - 1].answer === null || readOnly;
33
+ const isDisabled = repeatAnswers[repeatAnswers.length - 1]?.answer === null || readOnly;
34
34
 
35
35
  return (
36
36
  <Box display="flex" flexDirection="row-reverse">
@@ -40,6 +40,7 @@ interface RepeatFieldProps
40
40
  qrItem: QuestionnaireResponseItem | null;
41
41
  answer: QuestionnaireResponseItemAnswer | null;
42
42
  numOfRepeatAnswers: number;
43
+ groupCardElevation: number;
43
44
  onDeleteAnswer: () => void;
44
45
  }
45
46
 
@@ -49,6 +50,7 @@ function RepeatField(props: RepeatFieldProps) {
49
50
  qrItem,
50
51
  answer,
51
52
  numOfRepeatAnswers,
53
+ groupCardElevation,
52
54
  parentIsReadOnly,
53
55
  showMinimalView,
54
56
  onDeleteAnswer,
@@ -65,6 +67,7 @@ function RepeatField(props: RepeatFieldProps) {
65
67
  qrItem={qrItem}
66
68
  isRepeated={qItem.repeats ?? false}
67
69
  isTabled={false}
70
+ groupCardElevation={groupCardElevation}
68
71
  showMinimalView={showMinimalView}
69
72
  parentIsReadOnly={parentIsReadOnly}
70
73
  onQrItemChange={onQrItemChange}
@@ -39,10 +39,12 @@ interface RepeatItemProps
39
39
  PropsWithParentIsReadOnlyAttribute {
40
40
  qItem: QuestionnaireItem;
41
41
  qrItem: QuestionnaireResponseItem | null;
42
+ groupCardElevation: number;
42
43
  }
43
44
 
44
45
  function RepeatItem(props: RepeatItemProps) {
45
- const { qItem, qrItem, showMinimalView, parentIsReadOnly, onQrItemChange } = props;
46
+ const { qItem, qrItem, groupCardElevation, showMinimalView, parentIsReadOnly, onQrItemChange } =
47
+ props;
46
48
 
47
49
  const readOnly = useReadOnly(qItem, parentIsReadOnly);
48
50
 
@@ -104,6 +106,7 @@ function RepeatItem(props: RepeatItemProps) {
104
106
  qrItem={repeatAnswerQrItem}
105
107
  answer={answer}
106
108
  numOfRepeatAnswers={repeatAnswers.length}
109
+ groupCardElevation={groupCardElevation}
107
110
  parentIsReadOnly={parentIsReadOnly}
108
111
  showMinimalView={showMinimalView}
109
112
  onDeleteAnswer={() => handleDeleteItem(index)}
@@ -132,6 +135,7 @@ function RepeatItem(props: RepeatItemProps) {
132
135
  qrItem={repeatAnswerQrItem}
133
136
  answer={answer}
134
137
  numOfRepeatAnswers={repeatAnswers.length}
138
+ groupCardElevation={groupCardElevation}
135
139
  parentIsReadOnly={parentIsReadOnly}
136
140
  showMinimalView={showMinimalView}
137
141
  onDeleteAnswer={() => handleDeleteItem(index)}
@@ -28,6 +28,7 @@ import { useQuestionnaireStore } from '../../../stores';
28
28
  import SingleItemSwitcher from './SingleItemSwitcher';
29
29
  import useHidden from '../../../hooks/useHidden';
30
30
  import useReadOnly from '../../../hooks/useReadOnly';
31
+ import SingleNestedItems from './SingleNestedItems';
31
32
 
32
33
  interface SingleItemProps
33
34
  extends PropsWithQrItemChangeHandler,
@@ -37,11 +38,20 @@ interface SingleItemProps
37
38
  PropsWithParentIsReadOnlyAttribute {
38
39
  qItem: QuestionnaireItem;
39
40
  qrItem: QuestionnaireResponseItem | null;
41
+ groupCardElevation: number;
40
42
  }
41
43
 
42
44
  function SingleItem(props: SingleItemProps) {
43
- const { qItem, qrItem, isRepeated, isTabled, showMinimalView, parentIsReadOnly, onQrItemChange } =
44
- props;
45
+ const {
46
+ qItem,
47
+ qrItem,
48
+ isRepeated,
49
+ isTabled,
50
+ groupCardElevation,
51
+ showMinimalView,
52
+ parentIsReadOnly,
53
+ onQrItemChange
54
+ } = props;
45
55
 
46
56
  const updateEnableWhenItem = useQuestionnaireStore.use.updateEnableWhenItem();
47
57
 
@@ -50,11 +60,25 @@ function SingleItem(props: SingleItemProps) {
50
60
  if (newQrItem.answer) {
51
61
  updateEnableWhenItem(qItem.linkId, newQrItem.answer);
52
62
  }
63
+
64
+ if (qrItem && qrItem.item && qrItem.item.length > 0) {
65
+ onQrItemChange({ ...newQrItem, item: qrItem.item });
66
+ } else {
67
+ onQrItemChange(newQrItem);
68
+ }
69
+ },
70
+ [updateEnableWhenItem, qItem.linkId, qrItem, onQrItemChange]
71
+ );
72
+
73
+ const handleQrItemChangeWithNestedItems = useCallback(
74
+ (newQrItem: QuestionnaireResponseItem) => {
53
75
  onQrItemChange(newQrItem);
54
76
  },
55
- [updateEnableWhenItem, onQrItemChange, qItem.linkId]
77
+ [onQrItemChange]
56
78
  );
57
79
 
80
+ const qItemHasNestedItems = !!qItem.item && qItem.item.length > 0;
81
+
58
82
  const readOnly = useReadOnly(qItem, parentIsReadOnly);
59
83
  const itemIsHidden = useHidden(qItem);
60
84
  if (itemIsHidden) {
@@ -62,15 +86,26 @@ function SingleItem(props: SingleItemProps) {
62
86
  }
63
87
 
64
88
  return (
65
- <SingleItemSwitcher
66
- qItem={qItem}
67
- qrItem={qrItem}
68
- isRepeated={isRepeated}
69
- isTabled={isTabled}
70
- showMinimalView={showMinimalView}
71
- parentIsReadOnly={readOnly}
72
- onQrItemChange={handleQrItemChange}
73
- />
89
+ <>
90
+ <SingleItemSwitcher
91
+ qItem={qItem}
92
+ qrItem={qrItem}
93
+ isRepeated={isRepeated}
94
+ isTabled={isTabled}
95
+ showMinimalView={showMinimalView}
96
+ parentIsReadOnly={readOnly}
97
+ onQrItemChange={handleQrItemChange}
98
+ />
99
+ {qItemHasNestedItems ? (
100
+ <SingleNestedItems
101
+ qItem={qItem}
102
+ qrItem={qrItem}
103
+ groupCardElevation={groupCardElevation}
104
+ parentIsReadOnly={readOnly}
105
+ onQrItemChange={handleQrItemChangeWithNestedItems}
106
+ />
107
+ ) : null}
108
+ </>
74
109
  );
75
110
  }
76
111