@aehrc/smart-forms-renderer 0.13.2 → 0.14.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 (109) 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/OpenChoiceItems/OpenChoiceAutocompleteField.js +2 -2
  47. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceAutocompleteField.js.map +1 -1
  48. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerOptionField.js +2 -2
  49. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerOptionField.js.map +1 -1
  50. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetField.d.ts +2 -1
  51. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetField.js +7 -4
  52. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetField.js.map +1 -1
  53. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetItem.js +3 -3
  54. package/lib/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetItem.js.map +1 -1
  55. package/lib/components/FormComponents/SingleItem/SingleItemSwitcher.js +28 -16
  56. package/lib/components/FormComponents/SingleItem/SingleItemSwitcher.js.map +1 -1
  57. package/lib/components/FormComponents/SliderItem/SliderField.js +2 -1
  58. package/lib/components/FormComponents/SliderItem/SliderField.js.map +1 -1
  59. package/lib/components/FormComponents/Textfield.styles.d.ts +1 -0
  60. package/lib/components/FormComponents/Textfield.styles.js +2 -1
  61. package/lib/components/FormComponents/Textfield.styles.js.map +1 -1
  62. package/lib/components/FormComponents/TimeItem/TimeField.js +2 -1
  63. package/lib/components/FormComponents/TimeItem/TimeField.js.map +1 -1
  64. package/lib/hooks/UseFileDrop.d.ts +10 -0
  65. package/lib/hooks/UseFileDrop.js +40 -0
  66. package/lib/hooks/UseFileDrop.js.map +1 -0
  67. package/lib/hooks/useAttachmentUrlValidation.d.ts +2 -0
  68. package/lib/hooks/useAttachmentUrlValidation.js +27 -0
  69. package/lib/hooks/useAttachmentUrlValidation.js.map +1 -0
  70. package/lib/hooks/useValueSetCodings.d.ts +5 -1
  71. package/lib/hooks/useValueSetCodings.js +1 -1
  72. package/lib/hooks/useValueSetCodings.js.map +1 -1
  73. package/lib/utils/fileUtils.d.ts +3 -0
  74. package/lib/utils/fileUtils.js +64 -0
  75. package/lib/utils/fileUtils.js.map +1 -0
  76. package/lib/utils/validateQuestionnaire.d.ts +3 -5
  77. package/lib/utils/validateQuestionnaire.js +8 -5
  78. package/lib/utils/validateQuestionnaire.js.map +1 -1
  79. package/package.json +3 -1
  80. package/src/components/FormComponents/AttachmentItem/AttachmentField.tsx +96 -0
  81. package/src/components/FormComponents/AttachmentItem/AttachmentFieldWrapper.tsx +87 -0
  82. package/src/components/FormComponents/AttachmentItem/AttachmentFileCollector.tsx +101 -0
  83. package/src/components/FormComponents/AttachmentItem/AttachmentFileDropBox.styles.ts +31 -0
  84. package/src/components/FormComponents/AttachmentItem/AttachmentFileDropBox.tsx +66 -0
  85. package/src/components/FormComponents/AttachmentItem/AttachmentItem.tsx +123 -0
  86. package/src/components/FormComponents/AttachmentItem/AttachmentUrlField.tsx +78 -0
  87. package/src/components/FormComponents/ChoiceItems/ChoiceAutocompleteField.tsx +3 -3
  88. package/src/components/FormComponents/ChoiceItems/ChoiceCheckboxAnswerValueSetFields.tsx +6 -4
  89. package/src/components/FormComponents/ChoiceItems/ChoiceCheckboxAnswerValueSetItem.tsx +3 -3
  90. package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetFields.tsx +7 -4
  91. package/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerValueSetItem.tsx +3 -3
  92. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionFields.tsx +2 -1
  93. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetFields.tsx +9 -6
  94. package/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerValueSetItem.tsx +3 -3
  95. package/src/components/FormComponents/DateItem/DateField.tsx +2 -1
  96. package/src/components/FormComponents/DateTimeItem/DateTimeField.tsx +2 -1
  97. package/src/components/FormComponents/OpenChoiceItems/OpenChoiceAutocompleteField.tsx +2 -2
  98. package/src/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerOptionField.tsx +2 -2
  99. package/src/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetField.tsx +9 -6
  100. package/src/components/FormComponents/OpenChoiceItems/OpenChoiceSelectAnswerValueSetItem.tsx +3 -3
  101. package/src/components/FormComponents/SingleItem/SingleItemSwitcher.tsx +67 -31
  102. package/src/components/FormComponents/SliderItem/SliderField.tsx +2 -1
  103. package/src/components/FormComponents/Textfield.styles.ts +3 -1
  104. package/src/components/FormComponents/TimeItem/TimeField.tsx +2 -1
  105. package/src/hooks/UseFileDrop.ts +53 -0
  106. package/src/hooks/useAttachmentUrlValidation.ts +27 -0
  107. package/src/hooks/useValueSetCodings.ts +10 -2
  108. package/src/utils/fileUtils.ts +66 -0
  109. package/src/utils/validateQuestionnaire.ts +17 -13
@@ -0,0 +1,66 @@
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 { Box, Typography } from '@mui/material';
19
+ import useFileDrop from '../../../hooks/UseFileDrop';
20
+ import { AttachmentFileDropBoxWrapper } from './AttachmentFileDropBox.styles';
21
+ import React from 'react';
22
+ import type { PropsWithIsTabledAttribute } from '../../../interfaces/renderProps.interface';
23
+ import { getFileSize } from '../../../utils/fileUtils';
24
+
25
+ export interface AttachmentFileDropBoxProps extends PropsWithIsTabledAttribute {
26
+ file: File | null;
27
+ onDrop: (item: { files: any[] }) => void;
28
+ errorMessage: string;
29
+ }
30
+
31
+ function AttachmentFileDropBox(props: AttachmentFileDropBoxProps) {
32
+ const { file, onDrop, errorMessage, isTabled } = props;
33
+
34
+ const { canDrop, isOver, dropTarget } = useFileDrop(onDrop);
35
+
36
+ const isActive = canDrop && isOver;
37
+
38
+ let boxMessage = 'No file selected';
39
+ if (isActive) {
40
+ boxMessage = 'Release to drop file';
41
+ } else if (errorMessage) {
42
+ boxMessage = errorMessage;
43
+ } else if (file) {
44
+ boxMessage = file.name;
45
+ }
46
+
47
+ return (
48
+ <AttachmentFileDropBoxWrapper
49
+ ref={dropTarget}
50
+ display="flex"
51
+ isActive={isActive}
52
+ isTabled={isTabled}>
53
+ <Box p={1.5}>
54
+ <Typography>{boxMessage}</Typography>
55
+ {file ? (
56
+ <Box pt={1}>
57
+ <Typography fontSize={10}>Size: {getFileSize(file.size.toString() ?? '0')}</Typography>
58
+ <Typography fontSize={10}>Type: {file.type}</Typography>
59
+ </Box>
60
+ ) : null}
61
+ </Box>
62
+ </AttachmentFileDropBoxWrapper>
63
+ );
64
+ }
65
+
66
+ export default AttachmentFileDropBox;
@@ -0,0 +1,123 @@
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, { useCallback, useState } from 'react';
19
+ import type {
20
+ PropsWithIsRepeatedAttribute,
21
+ PropsWithIsTabledAttribute,
22
+ PropsWithParentIsReadOnlyAttribute,
23
+ PropsWithQrItemChangeHandler
24
+ } from '../../../interfaces/renderProps.interface';
25
+ import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4';
26
+ import debounce from 'lodash.debounce';
27
+ import { createEmptyQrItem } from '../../../utils/qrItem';
28
+ import { DEBOUNCE_DURATION } from '../../../utils/debounce';
29
+ import useStringInput from '../../../hooks/useStringInput';
30
+ import useReadOnly from '../../../hooks/useReadOnly';
31
+ import AttachmentFieldWrapper from './AttachmentFieldWrapper';
32
+ import { HTML5Backend } from 'react-dnd-html5-backend';
33
+ import { DndProvider } from 'react-dnd';
34
+ import { createAttachmentAnswer } from '../../../utils/fileUtils';
35
+
36
+ export interface AttachmentValues {
37
+ uploadedFile: File | null;
38
+ url: string;
39
+ fileName: string;
40
+ }
41
+
42
+ interface AttachmentItemProps
43
+ extends PropsWithQrItemChangeHandler,
44
+ PropsWithIsRepeatedAttribute,
45
+ PropsWithIsTabledAttribute,
46
+ PropsWithParentIsReadOnlyAttribute {
47
+ qItem: QuestionnaireItem;
48
+ qrItem: QuestionnaireResponseItem | null;
49
+ }
50
+
51
+ function AttachmentItem(props: AttachmentItemProps) {
52
+ const { qItem, qrItem, isRepeated, isTabled, parentIsReadOnly, onQrItemChange } = props;
53
+
54
+ const readOnly = useReadOnly(qItem, parentIsReadOnly);
55
+
56
+ // Init input value
57
+ let valueString = '';
58
+ if (qrItem?.answer && qrItem?.answer[0].valueString) {
59
+ valueString = qrItem.answer[0].valueString;
60
+ }
61
+ const [uploadedFile, setUploadedFile] = useState<File | null>(null);
62
+ const [url, setUrl] = useStringInput(valueString);
63
+ const [fileName, setFileName] = useStringInput(valueString);
64
+
65
+ // Event handlers
66
+ async function handleUploadFile(newUploadedFile: File | null) {
67
+ setUploadedFile(newUploadedFile);
68
+
69
+ const attachment = await createAttachmentAnswer(newUploadedFile, url, fileName);
70
+ if (attachment) {
71
+ onQrItemChange({
72
+ ...createEmptyQrItem(qItem),
73
+ answer: [{ valueAttachment: attachment }]
74
+ });
75
+ } else {
76
+ onQrItemChange(createEmptyQrItem(qItem));
77
+ }
78
+ }
79
+
80
+ async function handleUrlChange(newUrl: string) {
81
+ setUrl(newUrl);
82
+ await updateQrItemWithDebounce(uploadedFile, newUrl, fileName);
83
+ }
84
+
85
+ async function handleFileNameChange(newFileName: string) {
86
+ setFileName(newFileName);
87
+ await updateQrItemWithDebounce(uploadedFile, url, newFileName);
88
+ }
89
+
90
+ // eslint-disable-next-line react-hooks/exhaustive-deps
91
+ const updateQrItemWithDebounce = useCallback(
92
+ debounce(async (file: File | null, url: string, fileName: string) => {
93
+ const attachment = await createAttachmentAnswer(file, url, fileName);
94
+
95
+ if (attachment) {
96
+ onQrItemChange({
97
+ ...createEmptyQrItem(qItem),
98
+ answer: [{ valueAttachment: attachment }]
99
+ });
100
+ } else {
101
+ onQrItemChange(createEmptyQrItem(qItem));
102
+ }
103
+ }, DEBOUNCE_DURATION),
104
+ [onQrItemChange, qItem]
105
+ ); // Dependencies are tested, debounce is causing eslint to not recognise dependencies
106
+
107
+ return (
108
+ <DndProvider backend={HTML5Backend} context={window}>
109
+ <AttachmentFieldWrapper
110
+ qItem={qItem}
111
+ attachmentValues={{ uploadedFile: uploadedFile, url: url, fileName: fileName }}
112
+ readOnly={readOnly}
113
+ isRepeated={isRepeated}
114
+ isTabled={isTabled}
115
+ onUploadFile={handleUploadFile}
116
+ onUrlChange={handleUrlChange}
117
+ onFileNameChange={handleFileNameChange}
118
+ />
119
+ </DndProvider>
120
+ );
121
+ }
122
+
123
+ export default AttachmentItem;
@@ -0,0 +1,78 @@
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 { PropsWithIsTabledAttribute } from '../../../interfaces/renderProps.interface';
20
+ import { StandardTextField } from '../Textfield.styles';
21
+ import Typography from '@mui/material/Typography';
22
+ import Box from '@mui/material/Box';
23
+ import Stack from '@mui/material/Stack';
24
+ import useAttachmentUrlValidation from '../../../hooks/useAttachmentUrlValidation';
25
+ import InputAdornment from '@mui/material/InputAdornment';
26
+ import Tooltip from '@mui/material/Tooltip';
27
+ import CheckIcon from '@mui/icons-material/Check';
28
+ import DangerousIcon from '@mui/icons-material/Dangerous';
29
+
30
+ interface AttachmentUrlFieldProps extends PropsWithIsTabledAttribute {
31
+ linkId: string;
32
+ url: string;
33
+ readOnly: boolean;
34
+ onUrlChange: (url: string) => void;
35
+ }
36
+
37
+ function AttachmentUrlField(props: AttachmentUrlFieldProps) {
38
+ const { linkId, url, readOnly, isTabled, onUrlChange } = props;
39
+
40
+ const urlIsValid = useAttachmentUrlValidation(url);
41
+
42
+ return (
43
+ <Box>
44
+ <Typography variant="body2">URL</Typography>
45
+ <Stack direction="row" alignItems="center">
46
+ <StandardTextField
47
+ fullWidth
48
+ isTabled={isTabled}
49
+ id={linkId}
50
+ value={url}
51
+ onChange={(event) => onUrlChange(event.target.value)}
52
+ disabled={readOnly}
53
+ size="small"
54
+ data-test="q-item-attachment-field"
55
+ InputProps={{
56
+ endAdornment: (
57
+ <InputAdornment position="end">
58
+ {url != '' ? (
59
+ <Tooltip title={urlIsValid ? 'URL is valid!' : 'Invalid URL'} placement="right">
60
+ <Box mt={0.5}>
61
+ {urlIsValid ? (
62
+ <CheckIcon color="success" fontSize="small" />
63
+ ) : (
64
+ <DangerousIcon color="error" fontSize="small" />
65
+ )}
66
+ </Box>
67
+ </Tooltip>
68
+ ) : null}
69
+ </InputAdornment>
70
+ )
71
+ }}
72
+ />
73
+ </Stack>
74
+ </Box>
75
+ );
76
+ }
77
+
78
+ export default AttachmentUrlField;
@@ -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: {
@@ -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
  </>