From 38353d35b66df757546361a2eb06119b8b517cf0 Mon Sep 17 00:00:00 2001 From: Sean Fong Date: Fri, 1 Sep 2023 11:56:06 +0930 Subject: [PATCH 1/4] Fix update populated properties --- .../src/features/prepopulate/hooks/usePopulate.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/smart-forms-app/src/features/prepopulate/hooks/usePopulate.tsx b/apps/smart-forms-app/src/features/prepopulate/hooks/usePopulate.tsx index deede3d75..adcc2c495 100644 --- a/apps/smart-forms-app/src/features/prepopulate/hooks/usePopulate.tsx +++ b/apps/smart-forms-app/src/features/prepopulate/hooks/usePopulate.tsx @@ -28,6 +28,10 @@ function usePopulate(spinnerIsLoading: boolean, onStopSpinner: () => void): void const sourceQuestionnaire = useQuestionnaireStore((state) => state.sourceQuestionnaire); const sourceResponse = useQuestionnaireResponseStore((state) => state.sourceResponse); + + const updatePopulatedProperties = useQuestionnaireStore( + (state) => state.updatePopulatedProperties + ); const updatableResponse = useQuestionnaireResponseStore((state) => state.updatableResponse); const setUpdatableResponseAsPopulated = useQuestionnaireResponseStore( @@ -70,7 +74,8 @@ function usePopulate(spinnerIsLoading: boolean, onStopSpinner: () => void): void (params: PopulateFormParams) => { const { populated, hasWarnings } = params; - setUpdatableResponseAsPopulated(populated); + const updatedResponse = updatePopulatedProperties(populated); + setUpdatableResponseAsPopulated(updatedResponse); onStopSpinner(); if (hasWarnings) { enqueueSnackbar( From a051c87ba43a1a3eddaa810a02c23e815157c7a2 Mon Sep 17 00:00:00 2001 From: Sean Fong Date: Fri, 1 Sep 2023 12:13:15 +0930 Subject: [PATCH 2/4] Remove unused old form components --- .../Collapsible/FormBodySingleCollapsible.tsx | 76 ------- .../FormBodySingleCollapsibleWrapper.tsx | 59 ----- .../FormPage/FormBodyCollapsible.tsx | 96 -------- .../components/FormPage/FormBodyTabbed.tsx | 106 --------- .../FormPage/FormRenderer/FormRenderer.tsx | 81 ------- .../FormPage/FormRenderer/FormTitle.tsx | 44 ---- .../components/FormPage/FormTopLevelItem.tsx | 92 -------- .../BooleanItem/BooleanField.tsx | 44 ---- .../BooleanItem/BooleanItem.tsx | 81 ------- .../QFormComponents/DateItem/DateField.tsx | 55 ----- .../QFormComponents/DateItem/DateItem.tsx | 94 -------- .../DateTimeItem/DateTimeField.tsx | 57 ----- .../DateTimeItem/DateTimeItem.tsx | 93 -------- .../DecimalItem/DecimalField.tsx | 75 ------- .../DecimalItem/DecimalItem.tsx | 152 ------------- .../DisplayItem/DisplayInstructions.styles.ts | 24 -- .../DisplayItem/DisplayInstructions.tsx | 38 ---- .../DisplayItem/DisplayItem.tsx | 43 ---- .../FormPage/QFormComponents/FieldGrid.tsx | 46 ---- .../QFormComponents/GridGroup/GridGroup.tsx | 92 -------- .../QFormComponents/GridGroup/GridRow.tsx | 88 -------- .../QFormComponents/GridGroup/GridTable.tsx | 76 ------- .../GroupItem/GroupHeading.tsx | 59 ----- .../GroupItem/GroupItem.styles.ts | 28 --- .../QFormComponents/GroupItem/GroupItem.tsx | 124 ----------- .../GroupItem/GroupItemSwitcher.tsx | 149 ------------- .../GroupItem/NextTabButton.tsx | 42 ---- .../GroupItem/NextTabButtonWrapper.tsx | 76 ------- .../IntegerItem/IntegerField.tsx | 75 ------- .../IntegerItem/IntegerItem.tsx | 140 ------------ .../FormPage/QFormComponents/Item.styles.tsx | 30 --- .../QItemChoice/QItemChoice.tsx | 129 ----------- .../QItemChoice/QItemChoiceAutocomplete.tsx | 178 --------------- .../QItemChoiceCheckboxAnswerOption.tsx | 130 ----------- .../QItemChoiceCheckboxAnswerValueSet.tsx | 125 ----------- .../QItemChoiceRadioAnswerOption.tsx | 124 ----------- .../QItemChoiceRadioAnswerValueSet.tsx | 128 ----------- .../QItemChoice/QItemChoiceRadioSingle.tsx | 40 ---- .../QItemChoiceSelectAnswerOption.tsx | 130 ----------- .../QItemChoiceSelectAnswerValueSet.tsx | 162 -------------- .../QItemOpenChoice/QItemOpenChoice.tsx | 103 --------- .../QItemOpenChoiceAutocomplete.tsx | 207 ------------------ .../QItemOpenChoiceCheckboxAnswerOption.tsx | 194 ---------------- .../QItemOpenChoiceRadioAnswerOption.tsx | 190 ---------------- .../QItemOpenChoiceSelectAnswerOption.tsx | 148 ------------- .../QItemOpenChoiceSelectAnswerValueSet.tsx | 137 ------------ .../QItemParts/ContextDisplayItem.tsx | 38 ---- .../QFormComponents/QItemParts/LabelText.tsx | 58 ----- .../QItemParts/LabelWrapper.tsx | 46 ---- .../QItemParts/QItemCheckboxSingle.tsx | 43 ---- .../QItemCheckboxSingleWithOpenLabel.tsx | 61 ------ .../QItemRadioButtonWithOpenLabel.tsx | 53 ----- .../RepeatGroup/AddItemButton.tsx | 46 ---- .../RepeatGroup/DeleteItemButton.tsx | 45 ---- .../RepeatGroup/RepeatGroup.tsx | 125 ----------- .../RepeatGroup/RepeatGroupItem.tsx | 65 ------ .../RepeatItem/AddItemButton.tsx | 47 ---- .../RepeatItem/DeleteItemButton.tsx | 45 ---- .../RepeatItem/RepeatField.tsx | 60 ----- .../RepeatItem/RepeatItem.styles.tsx | 32 --- .../QFormComponents/RepeatItem/RepeatItem.tsx | 116 ---------- .../QFormComponents/SingleItem/SingleItem.tsx | 62 ------ .../SingleItem/SingleItemSwitcher.tsx | 170 -------------- .../StringItem/StringField.tsx | 65 ------ .../QFormComponents/StringItem/StringItem.tsx | 118 ---------- .../Tables/DeleteRowButton.tsx | 46 ---- .../Tables/QItemGroupTable.tsx | 171 --------------- .../Tables/QItemGroupTableRow.tsx | 76 ------- .../QFormComponents/Tables/Table.styles.tsx | 51 ----- .../QFormComponents/TextItem/TextField.tsx | 73 ------ .../QFormComponents/TextItem/TextItem.tsx | 128 ----------- .../QFormComponents/Textfield.styles.tsx | 28 --- .../QFormComponents/TimeItem/TimeField.tsx | 53 ----- .../QFormComponents/TimeItem/TimeItem.tsx | 93 -------- .../QFormComponents/Typography.styles.ts | 24 -- .../QFormComponents/UrlItem/UrlField.tsx | 65 ------ .../QFormComponents/UrlItem/UrlItem.tsx | 118 ---------- .../components/FormPage/QRSavedSnackbar.tsx | 65 ------ .../FormPage/Tabs/CompleteTabButton.tsx | 42 ---- .../FormPage/Tabs/FormBodySingleTab.tsx | 67 ------ .../FormPage/Tabs/FormBodyTabList.tsx | 83 ------- .../src/stories/Component/DateItem.stories.ts | 74 ------- .../Component/SingleItemSwitcher.stories.ts | 118 ---------- .../src/stories/Component/TextItem.stories.ts | 72 ------ 84 files changed, 7202 deletions(-) delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/Collapsible/FormBodySingleCollapsible.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/Collapsible/FormBodySingleCollapsibleWrapper.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/FormBodyCollapsible.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/FormBodyTabbed.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/FormRenderer/FormRenderer.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/FormRenderer/FormTitle.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/FormTopLevelItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/BooleanItem/BooleanField.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/BooleanItem/BooleanItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateItem/DateField.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateItem/DateItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateTimeItem/DateTimeField.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateTimeItem/DateTimeItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DecimalItem/DecimalField.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DecimalItem/DecimalItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayInstructions.styles.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayInstructions.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/FieldGrid.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridGroup.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridRow.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridTable.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupHeading.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItem.styles.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItemSwitcher.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/NextTabButton.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/NextTabButtonWrapper.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/IntegerItem/IntegerField.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/IntegerItem/IntegerItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Item.styles.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoice.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceAutocomplete.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceCheckboxAnswerOption.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceCheckboxAnswerValueSet.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioAnswerOption.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioAnswerValueSet.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioSingle.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceSelectAnswerOption.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceSelectAnswerValueSet.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoice.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceAutocomplete.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceCheckboxAnswerOption.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceRadioAnswerOption.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceSelectAnswerOption.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceSelectAnswerValueSet.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/ContextDisplayItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/LabelText.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/LabelWrapper.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemCheckboxSingle.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemCheckboxSingleWithOpenLabel.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemRadioButtonWithOpenLabel.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/AddItemButton.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/DeleteItemButton.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/RepeatGroup.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/RepeatGroupItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/AddItemButton.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/DeleteItemButton.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatField.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatItem.styles.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/SingleItem/SingleItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/SingleItem/SingleItemSwitcher.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/StringItem/StringField.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/StringItem/StringItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/DeleteRowButton.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/QItemGroupTable.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/QItemGroupTableRow.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/Table.styles.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TextItem/TextField.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TextItem/TextItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Textfield.styles.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TimeItem/TimeField.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TimeItem/TimeItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Typography.styles.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/UrlItem/UrlField.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/UrlItem/UrlItem.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/QRSavedSnackbar.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/CompleteTabButton.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/FormBodySingleTab.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/FormBodyTabList.tsx delete mode 100644 apps/smart-forms-app/src/stories/Component/DateItem.stories.ts delete mode 100644 apps/smart-forms-app/src/stories/Component/SingleItemSwitcher.stories.ts delete mode 100644 apps/smart-forms-app/src/stories/Component/TextItem.stories.ts diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/Collapsible/FormBodySingleCollapsible.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/Collapsible/FormBodySingleCollapsible.tsx deleted file mode 100644 index cbb3826b9..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/Collapsible/FormBodySingleCollapsible.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ReactNode } from 'react'; -import { memo } from 'react'; -import { - Accordion, - AccordionDetails, - AccordionSummary, - Box, - Tooltip, - Typography -} from '@mui/material'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -import { getContextDisplays } from '../../../utils/tabs.ts'; -import type { QuestionnaireItem } from 'fhir/r4'; -import { getShortText } from '../../../utils/itemControl.ts'; -import ContextDisplayItem from '../QFormComponents/QItemParts/ContextDisplayItem.tsx'; - -interface FormBodySingleCollapsibleProps { - qItem: QuestionnaireItem; - index: number; - selectedIndex: number; - onToggleExpand: (index: number) => void; - children: ReactNode; -} - -const FormBodySingleCollapsible = memo(function FormBodySingleCollapsible( - props: FormBodySingleCollapsibleProps -) { - const { qItem, index, selectedIndex, onToggleExpand, children } = props; - - const contextDisplayItems = getContextDisplays(qItem); - - const collapsibleLabel = getShortText(qItem) ?? qItem.text ?? ''; - - return ( - onToggleExpand(index)}> - - - - }> - - {collapsibleLabel} - - {contextDisplayItems.map((item) => { - return ; - })} - - - - {children} - - ); -}); - -export default FormBodySingleCollapsible; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/Collapsible/FormBodySingleCollapsibleWrapper.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/Collapsible/FormBodySingleCollapsibleWrapper.tsx deleted file mode 100644 index 54de1f892..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/Collapsible/FormBodySingleCollapsibleWrapper.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import GroupItem from '../QFormComponents/GroupItem/GroupItem.tsx'; -import FormBodySingleCollapsible from './FormBodySingleCollapsible.tsx'; -import type { PropsWithQrItemChangeHandler } from '../../../types/renderProps.interface.ts'; -import useHidden from '../../../hooks/useHidden.ts'; - -interface FormBodySingleCollapsibleProps - extends PropsWithQrItemChangeHandler { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - index: number; - selectedIndex: number; - onToggleExpand: (index: number) => void; -} - -function FormBodySingleCollapsibleWrapper(props: FormBodySingleCollapsibleProps) { - const { qItem, qrItem, index, selectedIndex, onToggleExpand, onQrItemChange } = props; - - const itemIsHidden = useHidden(qItem); - if (itemIsHidden) { - return null; - } - - return ( - - - - ); -} - -export default FormBodySingleCollapsibleWrapper; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/FormBodyCollapsible.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/FormBodyCollapsible.tsx deleted file mode 100644 index 98c8e1edb..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/FormBodyCollapsible.tsx +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useMemo } from 'react'; -import { Stack } from '@mui/material'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { getQrItemsIndex, mapQItemsIndex } from '../../utils'; -import { updateQrGroup } from '../../utils/qrItem.ts'; -import type { PropsWithQrItemChangeHandler } from '../../types/renderProps.interface.ts'; -import useQuestionnaireStore from '../../../../stores/useQuestionnaireStore.ts'; -import FormBodySingleCollapsibleWrapper from './Collapsible/FormBodySingleCollapsibleWrapper.tsx'; - -interface FormBodyCollapsibleProps extends PropsWithQrItemChangeHandler { - topLevelQItem: QuestionnaireItem; - topLevelQRItem: QuestionnaireResponseItem; -} - -function FormBodyCollapsibleWrapper(props: FormBodyCollapsibleProps) { - const { topLevelQItem, topLevelQRItem, onQrItemChange } = props; - - const currentTab = useQuestionnaireStore((state) => state.currentTabIndex); - const tabs = useQuestionnaireStore((state) => state.tabs); - - const switchTab = useQuestionnaireStore((state) => state.switchTab); - - const indexMap: Record = useMemo( - () => mapQItemsIndex(topLevelQItem), - [topLevelQItem] - ); - - const qItems = topLevelQItem.item; - const qrItems = topLevelQRItem.item; - - function handleQrGroupChange(qrItem: QuestionnaireResponseItem) { - updateQrGroup(qrItem, null, topLevelQRItem, indexMap); - onQrItemChange(topLevelQRItem); - } - - if (!qItems || !qrItems) { - return <>Unable to load form; - } - - function handleToggleExpand(index: number) { - switchTab(currentTab === index ? -1 : index); - } - - if (!qItems || !qrItems) { - return <>Unable to load form; - } - - const qrItemsByIndex = getQrItemsIndex(qItems, qrItems, indexMap); - - return ( - - {qItems.map((qItem, i) => { - const qrItem = qrItemsByIndex[i]; - - const isNotRepeatGroup = !Array.isArray(qrItem); - const isTab = !!tabs[qItem.linkId]; - - if (!isTab || !isNotRepeatGroup) { - // Something has gone horribly wrong - return null; - } - - return ( - - ); - })} - - ); -} - -export default FormBodyCollapsibleWrapper; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/FormBodyTabbed.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/FormBodyTabbed.tsx deleted file mode 100644 index e68967b89..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/FormBodyTabbed.tsx +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useMemo } from 'react'; -import { Grid } from '@mui/material'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { TabContext, TabPanel } from '@mui/lab'; -import { getQrItemsIndex, mapQItemsIndex } from '../../utils'; -import GroupItem from './QFormComponents/GroupItem/GroupItem.tsx'; -import { updateQrGroup } from '../../utils/qrItem.ts'; -import FormBodyTabList from './Tabs/FormBodyTabList.tsx'; -import type { PropsWithQrItemChangeHandler } from '../../types/renderProps.interface.ts'; -import useQuestionnaireStore from '../../../../stores/useQuestionnaireStore.ts'; - -interface FormBodyTabbedProps extends PropsWithQrItemChangeHandler { - topLevelQItem: QuestionnaireItem; - topLevelQRItem: QuestionnaireResponseItem; -} - -function FormBodyTabbed(props: FormBodyTabbedProps) { - const { topLevelQItem, topLevelQRItem, onQrItemChange } = props; - - const tabs = useQuestionnaireStore((state) => state.tabs); - const currentTab = useQuestionnaireStore((state) => state.currentTabIndex); - - const indexMap: Record = useMemo( - () => mapQItemsIndex(topLevelQItem), - [topLevelQItem] - ); - - const qItems = topLevelQItem.item; - const qrItems = topLevelQRItem.item; - - function handleQrGroupChange(qrItem: QuestionnaireResponseItem) { - updateQrGroup(qrItem, null, topLevelQRItem, indexMap); - onQrItemChange(topLevelQRItem); - } - - if (!qItems || !qrItems) { - return <>Unable to load form; - } - - const qrItemsByIndex = getQrItemsIndex(qItems, qrItems, indexMap); - - return ( - - - - - - - - {qItems.map((qItem, i) => { - const qrItem = qrItemsByIndex[i]; - - const isNotRepeatGroup = !Array.isArray(qrItem); - const isTab = !!tabs[qItem.linkId]; - - if (!isTab || !isNotRepeatGroup) { - // Something has gone horribly wrong - return null; - } - - const isRepeated = qItem.repeats ?? false; - const tabIsMarkedAsComplete = tabs[qItem.linkId].isComplete ?? false; - - return ( - - - - ); - })} - - - - ); -} - -export default FormBodyTabbed; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/FormRenderer/FormRenderer.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/FormRenderer/FormRenderer.tsx deleted file mode 100644 index 91fff2057..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/FormRenderer/FormRenderer.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Container, Fade } from '@mui/material'; -import FormTopLevelItem from '../FormTopLevelItem.tsx'; -import type { QuestionnaireResponse, QuestionnaireResponseItem } from 'fhir/r4'; -import useQuestionnaireStore from '../../../../../stores/useQuestionnaireStore.ts'; -import useQuestionnaireResponseStore from '../../../../../stores/useQuestionnaireResponseStore.ts'; - -function FormRenderer() { - const sourceQuestionnaire = useQuestionnaireStore((state) => state.sourceQuestionnaire); - const updateExpressions = useQuestionnaireStore((state) => state.updateExpressions); - const updatableResponse = useQuestionnaireResponseStore((state) => state.updatableResponse); - const updateResponse = useQuestionnaireResponseStore((state) => state.updateResponse); - - function handleTopLevelQRItemChange(newTopLevelQItem: QuestionnaireResponseItem, index: number) { - if (!updatableResponse.item || updatableResponse.item.length === 0) { - return; - } - - const updatedItems = [...updatableResponse.item]; // Copy the original array of items - updatedItems[index] = newTopLevelQItem; // Modify the item at the specified index - - const updatedResponse: QuestionnaireResponse = { - ...updatableResponse, - item: updatedItems - }; - - updateExpressions(updatedResponse); - updateResponse(updatedResponse); - } - - const topLevelQItems = sourceQuestionnaire.item; - const topLevelQRItems = updatableResponse.item; - - if (!topLevelQItems) { - return <>Questionnaire does not have any items; - } - - return ( - - - {topLevelQItems.map((qItem, index) => { - const qrItem = topLevelQRItems - ? topLevelQRItems[index] - : { - linkId: qItem.linkId, - text: qItem.text - }; - - return ( - - handleTopLevelQRItemChange(newTopLevelQRItem, index) - } - /> - ); - })} - - - ); -} - -export default FormRenderer; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/FormRenderer/FormTitle.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/FormRenderer/FormTitle.tsx deleted file mode 100644 index 981741770..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/FormRenderer/FormTitle.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Questionnaire } from 'fhir/r4'; -import parse from 'html-react-parser'; -import { getXHtmlStringFromQuestionnaire } from '../../../utils/formTitle.ts'; -import { memo } from 'react'; -import { FormTitleWrapper } from '../../../../../components/Box/Box.styles.tsx'; -import { Typography } from '@mui/material'; - -interface FormTitleProps { - questionnaire: Questionnaire; -} - -const FormTitle = memo(function FormTitle(props: FormTitleProps) { - const { questionnaire } = props; - - const xHtmlString = getXHtmlStringFromQuestionnaire(questionnaire); - const formTitle = xHtmlString ? parse(xHtmlString) : questionnaire.title; - - return ( - - - {formTitle} - - - ); -}); - -export default FormTitle; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/FormTopLevelItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/FormTopLevelItem.tsx deleted file mode 100644 index f07e0288c..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/FormTopLevelItem.tsx +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import FormBodyTabbed from './FormBodyTabbed.tsx'; -import { containsTabs, isTabContainer } from '../../utils/tabs.ts'; -import GroupItem from './QFormComponents/GroupItem/GroupItem.tsx'; -import SingleItem from './QFormComponents/SingleItem/SingleItem.tsx'; -import type { PropsWithQrItemChangeHandler } from '../../types/renderProps.interface.ts'; -import FormBodyCollapsible from './FormBodyCollapsible.tsx'; -import useResponsive from '../../../../hooks/useResponsive.ts'; - -interface FormTopLevelItemProps extends PropsWithQrItemChangeHandler { - topLevelQItem: QuestionnaireItem; - topLevelQRItem: QuestionnaireResponseItem; -} - -function FormTopLevelItem(props: FormTopLevelItemProps) { - const { topLevelQItem, topLevelQRItem, onQrItemChange } = props; - - const itemIsTabContainer = isTabContainer(topLevelQItem); - const itemContainsTabs = containsTabs(topLevelQItem); - - const isDesktop = useResponsive('up', 'lg'); - - const itemIsGroup = topLevelQItem.type === 'group'; - - // If form is tabbed, it is rendered as a tabbed form - if (itemContainsTabs || itemIsTabContainer) { - if (isDesktop) { - return ( - - ); - } - - return ( - - ); - } - - // If form is untabbed, it is rendered as a regular group - if (itemIsGroup) { - return ( - - ); - } - - // Otherwise, it is rendered as a non-group item - return ( - - ); -} - -export default FormTopLevelItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/BooleanItem/BooleanField.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/BooleanItem/BooleanField.tsx deleted file mode 100644 index ea49262fc..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/BooleanItem/BooleanField.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Checkbox, FormControlLabel } from '@mui/material'; -import { memo } from 'react'; - -interface BooleanFieldProps { - checked: boolean; - readOnly: boolean; - onCheckedChange: (newChecked: boolean) => void; -} -const BooleanField = memo(function BooleanField(props: BooleanFieldProps) { - const { checked, readOnly, onCheckedChange } = props; - - return ( - onCheckedChange(event.target.checked)} - /> - } - label="" - /> - ); -}); - -export default BooleanField; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/BooleanItem/BooleanItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/BooleanItem/BooleanItem.tsx deleted file mode 100644 index c772a0bb6..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/BooleanItem/BooleanItem.tsx +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import FieldGrid from '../FieldGrid.tsx'; -import BooleanField from './BooleanField.tsx'; -import { Box } from '@mui/material'; - -interface BooleanItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function BooleanItem(props: BooleanItemProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Get additional rendering extensions - const { displayInstructions, readOnly } = useRenderingExtensions(qItem); - - // Init input value - let checked = false; - if (qrItem?.answer && qrItem.answer[0].valueBoolean) { - checked = qrItem.answer[0].valueBoolean; - } - - // Event handlers - function handleCheckedChange(newChecked: boolean) { - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: [{ valueBoolean: newChecked }] - }); - } - - if (isTabled) { - return ( - - - - ); - } - - if (isRepeated) { - return ( - - ); - } - return ( - - - - - - ); -} - -export default BooleanItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateItem/DateField.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateItem/DateField.tsx deleted file mode 100644 index 73b98672c..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateItem/DateField.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { PropsWithIsTabledAttribute } from '../../../../types/renderProps.interface.ts'; -import type { Dayjs } from 'dayjs'; -import { DatePicker as MuiDatePicker, LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; - -interface DateFieldProps extends PropsWithIsTabledAttribute { - value: Dayjs | null; - displayPrompt: string; - entryFormat: string; - readOnly: boolean; - onDateChange: (newValue: Dayjs | null) => unknown; -} - -function DateField(props: DateFieldProps) { - const { value, displayPrompt, entryFormat, readOnly, isTabled, onDateChange } = props; - - return ( - - - - ); -} - -export default DateField; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateItem/DateItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateItem/DateItem.tsx deleted file mode 100644 index c172b1691..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateItem/DateItem.tsx +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import FieldGrid from '../FieldGrid.tsx'; -import DateField from './DateField.tsx'; -import type { Dayjs } from 'dayjs'; -import dayjs from 'dayjs'; - -interface DateItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function DateItem(props: DateItemProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Get additional rendering extensions - const { displayPrompt, displayInstructions, readOnly, entryFormat } = - useRenderingExtensions(qItem); - - // Init input value - let dateString: string | null = null; - - if (qrItem?.answer && qrItem?.answer[0].valueDate) { - dateString = qrItem.answer[0].valueDate; - } - const dateDayJs = dateString ? dayjs(dateString) : null; - - // Event handlers - function handleDateChange(newValue: Dayjs | null) { - const emptyQrItem = createEmptyQrItem(qItem); - if (newValue) { - onQrItemChange({ ...emptyQrItem, answer: [{ valueDate: newValue.format('YYYY-MM-DD') }] }); - } else { - onQrItemChange(emptyQrItem); - } - } - - if (isRepeated) { - return ( - - ); - } - - return ( - - - - - - ); -} - -export default DateItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateTimeItem/DateTimeField.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateTimeItem/DateTimeField.tsx deleted file mode 100644 index 3f04995cc..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateTimeItem/DateTimeField.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { PropsWithIsTabledAttribute } from '../../../../types/renderProps.interface.ts'; -import type { Dayjs } from 'dayjs'; -import { DateTimePicker as MuiDateTimePicker, LocalizationProvider } from '@mui/x-date-pickers'; -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; -import { Box } from '@mui/material'; - -interface DateTimeFieldProps extends PropsWithIsTabledAttribute { - value: Dayjs | null; - displayPrompt: string; - entryFormat: string; - readOnly: boolean; - onDateTimeChange: (newValue: Dayjs | null) => unknown; -} - -function DateTimeField(props: DateTimeFieldProps) { - const { value, displayPrompt, entryFormat, readOnly, isTabled, onDateTimeChange } = props; - - return ( - - - - - - ); -} - -export default DateTimeField; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateTimeItem/DateTimeItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateTimeItem/DateTimeItem.tsx deleted file mode 100644 index 46659faec..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DateTimeItem/DateTimeItem.tsx +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import FieldGrid from '../FieldGrid.tsx'; -import DateTimeField from './DateTimeField.tsx'; -import type { Dayjs } from 'dayjs'; -import dayjs from 'dayjs'; - -interface DateTimeItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function DateTimeItem(props: DateTimeItemProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Get additional rendering extensions - const { displayPrompt, displayInstructions, readOnly, entryFormat } = - useRenderingExtensions(qItem); - - // Init input value - let dateTimeString: string | null = null; - if (qrItem?.answer && qrItem?.answer[0].valueDateTime) { - dateTimeString = qrItem.answer[0].valueDateTime; - } - const dateTimeDayJs = dateTimeString ? dayjs(dateTimeString) : null; - - // Event handlers - function handleDateTimeChange(newValue: Dayjs | null) { - const emptyQrItem = createEmptyQrItem(qItem); - if (newValue) { - onQrItemChange({ ...emptyQrItem, answer: [{ valueDateTime: newValue.format() }] }); - } else { - onQrItemChange(emptyQrItem); - } - } - - if (isRepeated) { - return ( - - ); - } - - return ( - - - - - - ); -} - -export default DateTimeItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DecimalItem/DecimalField.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DecimalItem/DecimalField.tsx deleted file mode 100644 index 6191645f6..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DecimalItem/DecimalField.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { InputAdornment } from '@mui/material'; -import FadingCheckIcon from '../../../../../calculatedExpression/components/FadingCheckIcon.tsx'; -import { StandardTextField } from '../Textfield.styles.tsx'; -import type { PropsWithIsTabledAttribute } from '../../../../types/renderProps.interface.ts'; - -interface DecimalFieldProps extends PropsWithIsTabledAttribute { - linkId: string; - input: string; - feedback: string; - displayPrompt: string; - displayUnit: string; - entryFormat: string; - readOnly: boolean; - calcExpUpdated: boolean; - onInputChange: (value: string) => void; -} - -function DecimalField(props: DecimalFieldProps) { - const { - linkId, - input, - feedback, - displayPrompt, - displayUnit, - entryFormat, - readOnly, - calcExpUpdated, - isTabled, - onInputChange - } = props; - - return ( - onInputChange(event.target.value)} - disabled={readOnly} - label={displayPrompt} - placeholder={entryFormat} - fullWidth - isTabled={isTabled} - size="small" - inputProps={{ inputMode: 'numeric', pattern: '[0-9]*' }} - InputProps={{ - endAdornment: ( - - - {displayUnit} - - ) - }} - data-test="q-item-decimal-field" - /> - ); -} - -export default DecimalField; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DecimalItem/DecimalItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DecimalItem/DecimalItem.tsx deleted file mode 100644 index 6075bc369..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DecimalItem/DecimalItem.tsx +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useCallback, useState } from 'react'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import useValidationError from '../../../../hooks/useValidationError.ts'; -import debounce from 'lodash.debounce'; -import { createEmptyQrItemWithUnit } from '../../../../utils/qrItem.ts'; -import { DEBOUNCE_DURATION } from '../../../../utils/debounce.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import FieldGrid from '../FieldGrid.tsx'; -import DecimalField from './DecimalField.tsx'; -import { - parseDecimalStringToFloat, - parseDecimalStringWithPrecision -} from '../../../../utils/parseInputs.ts'; -import { getDecimalPrecision } from '../../../../utils/itemControl.ts'; -import useDecimalCalculatedExpression from '../../../../../calculatedExpression/hooks/useDecimalCalculatedExpression.ts'; - -interface DecimalItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function DecimalItem(props: DecimalItemProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Get additional rendering extensions - const precision = getDecimalPrecision(qItem); - const { - displayUnit, - displayPrompt, - displayInstructions, - readOnly, - entryFormat, - regexValidation, - maxLength - } = useRenderingExtensions(qItem); - - // Init input value - let valueDecimal = 0.0; - let initialInput = '0'; - if (qrItem?.answer) { - if (qrItem?.answer[0].valueDecimal) { - valueDecimal = qrItem.answer[0].valueDecimal; - } - - if (qrItem?.answer[0].valueInteger) { - valueDecimal = qrItem.answer[0].valueInteger; - } - - initialInput = precision ? valueDecimal.toFixed(precision) : valueDecimal.toString(); - } - const [input, setInput] = useState(initialInput); - - // Perform validation checks - const feedback = useValidationError(input, regexValidation, maxLength); - - // Process calculated expressions - const { calcExpUpdated } = useDecimalCalculatedExpression({ - qItem: qItem, - inputValue: input, - displayUnit: displayUnit, - precision: precision, - setInputValue: (newInput) => { - setInput(newInput); - }, - onQrItemChange: onQrItemChange - }); - - // Event handlers - function handleInputChange(newInput: string) { - const parsedNewInput: string = parseDecimalStringWithPrecision(newInput, precision); - - setInput(parsedNewInput); - updateQrItemWithDebounce(parsedNewInput); - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - const updateQrItemWithDebounce = useCallback( - debounce((parsedNewInput: string) => { - onQrItemChange({ - ...createEmptyQrItemWithUnit(qItem, displayUnit), - answer: precision - ? [{ valueDecimal: parseDecimalStringToFloat(parsedNewInput, precision) }] - : [{ valueDecimal: parseFloat(parsedNewInput) }] - }); - }, DEBOUNCE_DURATION), - [onQrItemChange, qItem, displayUnit, precision] - ); // Dependencies are tested, debounce is causing eslint to not recognise dependencies - - if (isRepeated) { - return ( - - ); - } - - return ( - - - - - - ); -} - -export default DecimalItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayInstructions.styles.ts b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayInstructions.styles.ts deleted file mode 100644 index 703060147..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayInstructions.styles.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Box, styled } from '@mui/material'; - -export const DisplayInstructionsWrapper = styled(Box)(({ theme }) => ({ - color: theme.palette.text.secondary, - textTransform: 'capitalize', - marginBottom: '8px' -})); diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayInstructions.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayInstructions.tsx deleted file mode 100644 index a736aa960..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayInstructions.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Typography } from '@mui/material'; -import { memo } from 'react'; -import { DisplayInstructionsWrapper } from './DisplayInstructions.styles.ts'; - -interface DisplayInstructionsProps { - displayInstructions: string; -} - -const DisplayInstructions = memo(function DisplayInstructions(props: DisplayInstructionsProps) { - const { displayInstructions } = props; - - return displayInstructions ? ( - - - {displayInstructions} - - - ) : null; -}); - -export default DisplayInstructions; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayItem.tsx deleted file mode 100644 index 688ba02c3..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/DisplayItem/DisplayItem.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { memo } from 'react'; -import type { QuestionnaireItem } from 'fhir/r4'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import { isSpecificItemControl } from '../../../../utils/itemControl.ts'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface DisplayItemProps { - qItem: QuestionnaireItem; -} - -const DisplayItem = memo(function DisplayItem(props: DisplayItemProps) { - const { qItem } = props; - - const isContextDisplay = isSpecificItemControl(qItem, 'context-display'); - if (isContextDisplay) { - return null; - } - - return ( - - - - ); -}); - -export default DisplayItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/FieldGrid.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/FieldGrid.tsx deleted file mode 100644 index f83caa73a..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/FieldGrid.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ReactNode } from 'react'; -import { Grid } from '@mui/material'; -import type { QuestionnaireItem } from 'fhir/r4'; -import DisplayInstructions from './DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from './QItemParts/LabelWrapper.tsx'; - -interface FieldGridProps { - children: ReactNode; - qItem: QuestionnaireItem; - displayInstructions: string; -} - -function FieldGrid(props: FieldGridProps) { - const { children, qItem, displayInstructions } = props; - - return ( - - - - - - {children} - - - - ); -} - -export default FieldGrid; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridGroup.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridGroup.tsx deleted file mode 100644 index df1c9606f..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridGroup.tsx +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import type { PropsWithQrItemChangeHandler } from '../../../../types/renderProps.interface.ts'; -import { createQrGroup, updateQrGroup } from '../../../../utils/qrItem.ts'; -import useHidden from '../../../../hooks/useHidden.ts'; -import { QGroupContainerBox } from '../../../../../../components/Box/Box.styles.tsx'; -import { Divider, Paper, TableContainer, Typography } from '@mui/material'; -import { useMemo } from 'react'; -import { mapQItemsIndex } from '../../../../utils'; -import GridTable from './GridTable.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface GridGroupProps extends PropsWithQrItemChangeHandler { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - groupCardElevation: number; -} - -function GridGroup(props: GridGroupProps) { - const { qItem, qrItem, groupCardElevation, onQrItemChange } = props; - - const qRowItems = qItem.item; - const qrGroup = qrItem && qrItem.item ? qrItem : createQrGroup(qItem); - const qrRowItems = qrGroup.item; - - const qItemsIndexMap = useMemo(() => mapQItemsIndex(qItem), [qItem]); - - const columnLabels: string[] = useMemo( - () => qRowItems?.[0].item?.map((firstItem) => firstItem.text ?? ' ') ?? [], - [qRowItems] - ); - - const itemIsHidden = useHidden(qItem); - if (itemIsHidden) { - return null; - } - - if (!qRowItems || !qrRowItems) { - return <>Unable to load group, something has gone terribly wrong.; - } - - // Check if there are row within the grid - if (qRowItems.length === 0) { - return null; - } - - // Event Handlers - function handleRowChange(newQrItem: QuestionnaireResponseItem) { - const updatedQrGroup: QuestionnaireResponseItem = { ...qrGroup }; - updateQrGroup(newQrItem, null, updatedQrGroup, qItemsIndexMap); - onQrItemChange(updatedQrGroup); - } - - return ( - <> - - - - - - - - - - - - ); -} - -export default GridGroup; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridRow.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridRow.tsx deleted file mode 100644 index e2f05bbfc..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridRow.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import type { PropsWithQrItemChangeHandler } from '../../../../types/renderProps.interface.ts'; -import { createQrGroup, updateQrGroup } from '../../../../utils/qrItem.ts'; -import { GridAnswerTableCell, GridTextTableCell } from '../Tables/Table.styles.tsx'; -import SingleItem from '../SingleItem/SingleItem.tsx'; -import { getQrItemsIndex, mapQItemsIndex } from '../../../../utils'; -import { Typography } from '@mui/material'; -import { useMemo } from 'react'; - -interface GridRowProps extends PropsWithQrItemChangeHandler { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - columnLabels: string[]; - numOfColumns: number; -} - -function GridRow(props: GridRowProps) { - const { qItem, qrItem, columnLabels, numOfColumns, onQrItemChange } = props; - - const rowQItems = qItem.item; - const row = qrItem && qrItem.item ? qrItem : createQrGroup(qItem); - const rowQrItems = row.item; - - const qItemsIndexMap = useMemo(() => mapQItemsIndex(qItem), [qItem]); - - if (!rowQItems || !rowQrItems) { - return null; - } - - function handleQrRowItemChange(newQrRowItem: QuestionnaireResponseItem) { - const qrRow: QuestionnaireResponseItem = { ...row }; - updateQrGroup(newQrRowItem, null, qrRow, qItemsIndexMap); - onQrItemChange(qrRow); - } - - const qrItemsByIndex = getQrItemsIndex(rowQItems, rowQrItems, qItemsIndexMap); - - return ( - <> - - {qItem.text} - - {rowQItems.map((cellQItem, index) => { - const cellQrItem = qrItemsByIndex[index]; - - // Don't render cell if column label does not match - "sparse-ness" of grid - if (columnLabels[index] !== cellQItem.text) { - return null; - } - - if (Array.isArray(cellQrItem)) { - return null; - } - - return ( - - - - ); - })} - - ); -} - -export default GridRow; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridTable.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridTable.tsx deleted file mode 100644 index 8469ca8e9..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GridGroup/GridTable.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Table, TableBody, TableCell, TableHead, TableRow } from '@mui/material'; -import { HeaderTableCell } from '../Tables/Table.styles.tsx'; -import GridRow from './GridRow.tsx'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { getQrItemsIndex } from '../../../../utils'; -import type { PropsWithQrItemChangeHandler } from '../../../../types/renderProps.interface.ts'; - -interface GridTableProps extends PropsWithQrItemChangeHandler { - qItems: QuestionnaireItem[]; - qrItems: QuestionnaireResponseItem[]; - qItemsIndexMap: Record; - columnLabels: string[]; -} - -function GridTable(props: GridTableProps) { - const { qItems, qrItems, qItemsIndexMap, columnLabels, onQrItemChange } = props; - - const qrItemsByIndex: (QuestionnaireResponseItem | QuestionnaireResponseItem[])[] = - getQrItemsIndex(qItems, qrItems, qItemsIndexMap); - - const numOfColumns = columnLabels.length; - - return ( - - - - - {columnLabels.map((label) => ( - {label} - ))} - - - - - {qItems.map((qItem, index) => { - const qrItem = qrItemsByIndex[index]; - - if (Array.isArray(qrItem)) { - return null; - } - - return ( - - - - ); - })} - -
- ); -} - -export default GridTable; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupHeading.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupHeading.tsx deleted file mode 100644 index e977f7ad1..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupHeading.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { memo } from 'react'; -import { Box, Divider } from '@mui/material'; -import { QGroupHeadingTypography } from '../Typography.styles.ts'; -import type { PropsWithIsRepeatedAttribute } from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem } from 'fhir/r4'; -import { getContextDisplays } from '../../../../utils/tabs.ts'; -import ContextDisplayItem from '../QItemParts/ContextDisplayItem.tsx'; -import LabelText from '../QItemParts/LabelText.tsx'; - -interface GroupHeadingProps extends PropsWithIsRepeatedAttribute { - qItem: QuestionnaireItem; - tabIsMarkedAsComplete?: boolean; -} - -const GroupHeading = memo(function GroupHeading(props: GroupHeadingProps) { - const { qItem, tabIsMarkedAsComplete, isRepeated } = props; - - const contextDisplayItems = getContextDisplays(qItem); - - if (isRepeated) { - return null; - } - - return ( - <> - - - - - - - {contextDisplayItems.map((item) => { - return ; - })} - - - {qItem.text ? : null} - - ); -}); - -export default GroupHeading; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItem.styles.ts b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItem.styles.ts deleted file mode 100644 index af1855852..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItem.styles.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Card, styled } from '@mui/material'; - -export const GroupCard = styled(Card, { - shouldForwardProp: (prop) => prop !== 'elevation' && prop !== 'isRepeated' -})<{ elevation: number; isRepeated: boolean }>(({ elevation, isRepeated }) => ({ - paddingTop: '20px', - paddingBottom: '20px', - paddingLeft: elevation === 1 ? '26px' : '24px', - paddingRight: elevation === 1 ? '26px' : '24px', - marginBottom: isRepeated ? 0 : '28px' -})); diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItem.tsx deleted file mode 100644 index 016756f9e..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItem.tsx +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useMemo } from 'react'; -import { getQrItemsIndex, mapQItemsIndex } from '../../../../utils'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { createQrGroup, updateQrGroup } from '../../../../utils/qrItem.ts'; -import { QGroupContainerBox } from '../../../../../../components/Box/Box.styles.tsx'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QrRepeatGroup } from '../../../../types/repeatGroup.interface.ts'; -import useHidden from '../../../../hooks/useHidden.ts'; -import type { Tabs } from '../../../../types/tab.interface.ts'; -import GroupHeading from './GroupHeading.tsx'; -import { GroupCard } from './GroupItem.styles.ts'; -import NextTabButtonWrapper from './NextTabButtonWrapper.tsx'; -import GroupItemSwitcher from './GroupItemSwitcher.tsx'; - -interface GroupItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - groupCardElevation: number; - tabIsMarkedAsComplete?: boolean; - tabs?: Tabs; - currentTabIndex?: number; - goToNextTab?: (nextTabIndex: number) => unknown; -} - -function GroupItem(props: GroupItemProps) { - const { - qItem, - qrItem, - isRepeated, - groupCardElevation, - tabIsMarkedAsComplete, - tabs, - currentTabIndex, - onQrItemChange - } = props; - - const qItemsIndexMap = useMemo(() => mapQItemsIndex(qItem), [qItem]); - - const itemIsHidden = useHidden(qItem); - if (itemIsHidden) { - return null; - } - - const qItems = qItem.item; - const qrGroup = qrItem && qrItem.item ? qrItem : createQrGroup(qItem); - const qrItems = qrGroup.item; - - // Event Handlers - function handleQrItemChange(newQrItem: QuestionnaireResponseItem) { - const updatedQrGroup: QuestionnaireResponseItem = { ...qrGroup }; - updateQrGroup(newQrItem, null, updatedQrGroup, qItemsIndexMap); - onQrItemChange(updatedQrGroup); - } - - function handleQrRepeatGroupChange(qrRepeatGroup: QrRepeatGroup) { - const updatedQrGroup: QuestionnaireResponseItem = { ...qrGroup }; - updateQrGroup(null, qrRepeatGroup, updatedQrGroup, qItemsIndexMap); - onQrItemChange(updatedQrGroup); - } - - if (!qItems || !qrItems) { - return <>Unable to load group, something has gone terribly wrong.; - } - - // If an item has multiple answers, it is a repeat group - const qrItemsByIndex: (QuestionnaireResponseItem | QuestionnaireResponseItem[])[] = - getQrItemsIndex(qItems, qrItems, qItemsIndexMap); - - return ( - - - - {qItems.map((qItem: QuestionnaireItem, i) => { - const qrItemOrItems = qrItemsByIndex[i]; - - return ( - - ); - })} - - {/* Next tab button at the end of each tab group */} - - - - ); -} - -export default GroupItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItemSwitcher.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItemSwitcher.tsx deleted file mode 100644 index 380bd6add..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/GroupItemSwitcher.tsx +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { - PropsWithQrItemChangeHandler, - PropsWithQrRepeatGroupChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { isSpecificItemControl } from '../../../../utils/itemControl.ts'; -import QItemGroupTable from '../Tables/QItemGroupTable.tsx'; -import RepeatGroup from '../RepeatGroup/RepeatGroup.tsx'; -import { isRepeatItemAndNotCheckbox } from '../../../../utils/qItem.ts'; -import RepeatItem from '../RepeatItem/RepeatItem.tsx'; -import SingleItem from '../SingleItem/SingleItem.tsx'; -import useHidden from '../../../../hooks/useHidden.ts'; -import GroupItem from './GroupItem.tsx'; -import GridGroup from '../GridGroup/GridGroup.tsx'; - -interface GroupItemSwitcherProps - extends PropsWithQrItemChangeHandler, - PropsWithQrRepeatGroupChangeHandler { - qItem: QuestionnaireItem; - qrItemOrItems: QuestionnaireResponseItem | QuestionnaireResponseItem[]; - groupCardElevation: number; -} - -function GroupItemSwitcher(props: GroupItemSwitcherProps) { - const { qItem, qrItemOrItems, groupCardElevation, onQrItemChange, onQrRepeatGroupChange } = props; - - const itemIsHidden = useHidden(qItem); - if (itemIsHidden) { - return null; - } - - // If there are multiple answers - const hasMultipleAnswers = Array.isArray(qrItemOrItems); - if (hasMultipleAnswers) { - const qrItems = qrItemOrItems; - - // qItem should always be either a repeatGroup or a groupTable item - // groupTables item have qItem.repeats = true and qItem.type = 'group' as well - if (!qItem.repeats || qItem.type !== 'group') { - return <>Something went wrong here; - } - - if (isSpecificItemControl(qItem, 'gtable')) { - return ( - - ); - } - - return ( - - ); - } - - // If there is only one answer - const qrItem = qrItemOrItems; - const itemIsGrid = isSpecificItemControl(qItem, 'grid'); - if (itemIsGrid) { - return ( - - ); - } - - const itemRepeatsAndIsNotCheckbox = isRepeatItemAndNotCheckbox(qItem); - if (itemRepeatsAndIsNotCheckbox) { - if (qItem.type === 'group') { - // If qItem is RepeatGroup or a groupTable item in this decision branch, - // their qrItem array should always be empty - if (isSpecificItemControl(qItem, 'gtable')) { - return ( - - ); - } - - return ( - - ); - } - - return ; - } - - // if qItem is not a repeating question or is a checkbox - if (qItem.type === 'group') { - return ( - - ); - } - - // Defaults to a normal QItemSwitcher - return ( - - ); -} - -export default GroupItemSwitcher; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/NextTabButton.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/NextTabButton.tsx deleted file mode 100644 index 618b176da..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/NextTabButton.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Button } from '@mui/material'; -import Iconify from '../../../../../../components/Iconify/Iconify.tsx'; - -interface NextTabButtonProps { - isDisabled: boolean; - onNextTabClick: () => void; -} - -function NextTabButton(props: NextTabButtonProps) { - const { isDisabled, onNextTabClick } = props; - - return ( - - ); -} - -export default NextTabButton; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/NextTabButtonWrapper.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/NextTabButtonWrapper.tsx deleted file mode 100644 index cb788806e..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/GroupItem/NextTabButtonWrapper.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { memo } from 'react'; -import { Box } from '@mui/material'; -import { findNumOfVisibleTabs, getNextVisibleTabIndex } from '../../../../utils/tabs.ts'; -import type { Tabs } from '../../../../types/tab.interface.ts'; -import useQuestionnaireStore from '../../../../../../stores/useQuestionnaireStore.ts'; -import NextTabButton from './NextTabButton.tsx'; - -interface NextTabButtonWrapperProps { - currentTabIndex?: number; - tabs?: Tabs; -} - -const NextTabButtonWrapper = memo(function NextTabWrapper(props: NextTabButtonWrapperProps) { - const { currentTabIndex, tabs } = props; - - const enableWhenIsActivated = useQuestionnaireStore((state) => state.enableWhenIsActivated); - const enableWhenItems = useQuestionnaireStore((state) => state.enableWhenItems); - const enableWhenExpressions = useQuestionnaireStore((state) => state.enableWhenExpressions); - const switchTab = useQuestionnaireStore((state) => state.switchTab); - - const tabsNotDefined = currentTabIndex === undefined || tabs === undefined; - - function handleNextTabClick() { - if (tabsNotDefined) { - return; - } - - const nextVisibleTabIndex = getNextVisibleTabIndex({ - tabs, - currentTabIndex, - enableWhenIsActivated, - enableWhenItems, - enableWhenExpressions - }); - switchTab(nextVisibleTabIndex); - - // Scroll to top of page - window.scrollTo(0, 0); - } - - if (tabsNotDefined) { - return null; - } - - if (currentTabIndex === Object.keys(tabs).length - 1) { - return null; - } - - const buttonIsDisabled = - findNumOfVisibleTabs(tabs, enableWhenIsActivated, enableWhenItems, enableWhenExpressions) <= 1; - - return ( - - - - ); -}); - -export default NextTabButtonWrapper; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/IntegerItem/IntegerField.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/IntegerItem/IntegerField.tsx deleted file mode 100644 index 66e28a0f4..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/IntegerItem/IntegerField.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { InputAdornment } from '@mui/material'; -import FadingCheckIcon from '../../../../../calculatedExpression/components/FadingCheckIcon.tsx'; -import { StandardTextField } from '../Textfield.styles.tsx'; -import type { PropsWithIsTabledAttribute } from '../../../../types/renderProps.interface.ts'; - -interface IntegerFieldProps extends PropsWithIsTabledAttribute { - linkId: string; - value: number; - feedback: string; - displayPrompt: string; - displayUnit: string; - entryFormat: string; - readOnly: boolean; - calcExpUpdated: boolean; - onInputChange: (value: string) => void; -} - -function IntegerField(props: IntegerFieldProps) { - const { - linkId, - value, - feedback, - displayPrompt, - displayUnit, - entryFormat, - readOnly, - calcExpUpdated, - isTabled, - onInputChange - } = props; - - return ( - onInputChange(event.target.value)} - disabled={readOnly} - label={displayPrompt} - placeholder={entryFormat} - fullWidth - isTabled={isTabled} - size="small" - inputProps={{ inputMode: 'numeric', pattern: '[0-9]*' }} - InputProps={{ - endAdornment: ( - - - {displayUnit} - - ) - }} - data-test="q-item-integer-field" - /> - ); -} - -export default IntegerField; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/IntegerItem/IntegerItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/IntegerItem/IntegerItem.tsx deleted file mode 100644 index f068df436..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/IntegerItem/IntegerItem.tsx +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useCallback, useState } from 'react'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import useValidationError from '../../../../hooks/useValidationError.ts'; -import debounce from 'lodash.debounce'; -import { createEmptyQrItemWithUnit } from '../../../../utils/qrItem.ts'; -import { DEBOUNCE_DURATION } from '../../../../utils/debounce.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import FieldGrid from '../FieldGrid.tsx'; -import IntegerField from './IntegerField.tsx'; -import useIntegerCalculatedExpression from '../../../../../calculatedExpression/hooks/useIntegerCalculatedExpression.ts'; -import { parseValidInteger } from '../../../../utils/parseInputs.ts'; - -interface IntegerItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function IntegerItem(props: IntegerItemProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Get additional rendering extensions - const { - displayUnit, - displayPrompt, - displayInstructions, - readOnly, - entryFormat, - regexValidation, - maxLength - } = useRenderingExtensions(qItem); - - // Init input value - let valueInteger = 0; - if (qrItem?.answer) { - if (qrItem?.answer[0].valueInteger) { - valueInteger = qrItem.answer[0].valueInteger; - } - if (qrItem?.answer[0].valueDecimal) { - valueInteger = Math.round(qrItem.answer[0].valueDecimal); - } - } - const [value, setValue] = useState(valueInteger); - - // Perform validation checks - const feedback = useValidationError(value.toString(), regexValidation, maxLength); - - // Process calculated expressions - const { calcExpUpdated } = useIntegerCalculatedExpression({ - qItem: qItem, - inputValue: value, - displayUnit: displayUnit, - setInputValue: (newValue) => { - setValue(newValue); - }, - onQrItemChange: onQrItemChange - }); - - // Event handlers - function handleInputChange(newInput: string) { - const newValue = parseValidInteger(newInput); - - setValue(newValue); - updateQrItemWithDebounce(newValue); - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - const updateQrItemWithDebounce = useCallback( - debounce((newValue: number) => { - onQrItemChange({ - ...createEmptyQrItemWithUnit(qItem, displayUnit), - answer: [{ valueInteger: newValue }] - }); - }, DEBOUNCE_DURATION), - [onQrItemChange, qItem, displayUnit] - ); // Dependencies are tested, debounce is causing eslint to not recognise dependencies - - if (isRepeated) { - return ( - - ); - } - - return ( - - - - - - ); -} - -export default IntegerItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Item.styles.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Item.styles.tsx deleted file mode 100644 index 1895b954a..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Item.styles.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { FormGroup, RadioGroup, styled, Typography } from '@mui/material'; - -export const QFormGroup = styled(FormGroup)(() => ({ - marginBottom: 4 -})); - -export const QRadioGroup = styled(RadioGroup)(() => ({ - marginBottom: 4 -})); - -export const QItemTypography = styled(Typography)(() => ({ - marginTop: 4 -})); diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoice.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoice.tsx deleted file mode 100644 index c0ab89eca..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoice.tsx +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { QItemChoiceControl } from '../../../../types/choice.enum.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import QItemChoiceRadioAnswerOption from './QItemChoiceRadioAnswerOption.tsx'; -import QItemChoiceSelectAnswerOption from './QItemChoiceSelectAnswerOption.tsx'; -import QItemChoiceCheckboxAnswerOption from './QItemChoiceCheckboxAnswerOption.tsx'; -import QItemChoiceAutocomplete from './QItemChoiceAutocomplete.tsx'; -import QItemChoiceSelectAnswerValueSet from './QItemChoiceSelectAnswerValueSet.tsx'; -import { getChoiceControlType, getChoiceOrientation } from '../../../../utils/choice.ts'; -import QItemChoiceRadioAnswerValueSet from './QItemChoiceRadioAnswerValueSet.tsx'; -import QItemChoiceCheckboxAnswerValueSet from './QItemChoiceCheckboxAnswerValueSet.tsx'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; - -interface Props - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function QItemChoice(props: Props) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - const orientation = getChoiceOrientation(qItem); - const choiceControlType = getChoiceControlType(qItem); - - switch (choiceControlType) { - case QItemChoiceControl.Radio: - if (qItem.answerOption) { - return ( - - ); - } else { - return ( - - ); - } - case QItemChoiceControl.Checkbox: - if (qItem.answerOption) { - return ( - - ); - } else { - return ( - - ); - } - case QItemChoiceControl.Autocomplete: - return ( - - ); - case QItemChoiceControl.Select: - if (qItem.answerOption) { - return ( - - ); - } else { - return ( - - ); - } - default: - return null; - } -} - -export default QItemChoice; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceAutocomplete.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceAutocomplete.tsx deleted file mode 100644 index 97e94f211..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceAutocomplete.tsx +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ChangeEvent, SyntheticEvent } from 'react'; -import { useState } from 'react'; -import { Autocomplete, CircularProgress, Fade, Grid, Tooltip } from '@mui/material'; -import type { Coding, QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; - -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { StandardTextField } from '../Textfield.styles.tsx'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import SearchIcon from '@mui/icons-material/Search'; -import useDebounce from '../../../../hooks/useDebounce.ts'; -import useTerminologyServerQuery from '../../../../hooks/useTerminologyServerQuery.ts'; -import InfoIcon from '@mui/icons-material/Info'; -import WarningAmberIcon from '@mui/icons-material/WarningAmber'; -import DoneIcon from '@mui/icons-material/Done'; -import ErrorIcon from '@mui/icons-material/Error'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import { getTerminologyServerUrl } from '../../../../../../utils/valueSet.ts'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import { AUTOCOMPLETE_DEBOUNCE_DURATION } from '../../../../utils/debounce.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface QItemChoiceAutocompleteProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function QItemChoiceAutocomplete(props: QItemChoiceAutocompleteProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - const qrChoice = qrItem ?? createEmptyQrItem(qItem); - - // Init input value - let valueCoding: Coding | undefined; - if (qrChoice.answer) { - valueCoding = qrChoice.answer[0].valueCoding; - } - - // Get additional rendering extensions - const { displayUnit, displayPrompt, displayInstructions, readOnly, entryFormat } = - useRenderingExtensions(qItem); - - // Query ontoserver for options - const maxList = 10; - - const [input, setInput] = useState(''); - const debouncedInput = useDebounce(input, AUTOCOMPLETE_DEBOUNCE_DURATION); - - const answerValueSetUrl = qItem.answerValueSet; - const terminologyServerUrl = getTerminologyServerUrl(qItem); - const { options, loading, feedback } = useTerminologyServerQuery( - answerValueSetUrl, - maxList, - input, - debouncedInput, - terminologyServerUrl - ); - - if (!answerValueSetUrl) return null; - - // Event handlers - function handleValueChange(_: SyntheticEvent, newValue: Coding | null) { - if (newValue === null) { - setInput(''); - onQrItemChange(createEmptyQrItem(qItem)); - return; - } - - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: [{ valueCoding: newValue }] - }); - } - - const choiceAutocomplete = ( - <> - `${option.display}`} - isOptionEqualToValue={(option, value) => option.id === value.id} - loading={loading} - loadingText={'Fetching results...'} - clearOnEscape - autoHighlight - onChange={handleValueChange} - sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160, flexGrow: 1 }} - filterOptions={(x) => x} - renderInput={(params) => ( - ) => setInput(e.target.value)} - isTabled={isTabled} - disabled={readOnly} - label={displayPrompt} - size="small" - InputProps={{ - ...params.InputProps, - - startAdornment: ( - <> - {!valueCoding ? : null} - {params.InputProps.startAdornment} - - ), - endAdornment: ( - <> - {loading ? ( - - ) : feedback ? ( - - - { - { - info: , - warning: , - success: , - error: - }[feedback.color] - } - - - ) : null} - {params.InputProps.endAdornment} - {displayUnit} - - ) - }} - /> - )} - /> - - ); - - const renderQItemChoiceAutocomplete = isRepeated ? ( - <>{choiceAutocomplete} - ) : ( - - - - - - - {choiceAutocomplete} - - - - - ); - return <>{renderQItemChoiceAutocomplete}; -} - -export default QItemChoiceAutocomplete; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceCheckboxAnswerOption.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceCheckboxAnswerOption.tsx deleted file mode 100644 index b6f133a40..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceCheckboxAnswerOption.tsx +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Grid } from '@mui/material'; -import { QItemChoiceOrientation } from '../../../../types/choice.enum.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import QItemChoiceCheckboxSingle from '../QItemParts/QItemCheckboxSingle.tsx'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { QFormGroup } from '../Item.styles.tsx'; -import { updateQrCheckboxAnswers } from '../../../../utils/choice.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface QItemChoiceCheckboxProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - orientation: QItemChoiceOrientation; -} - -function QItemChoiceCheckboxAnswerOption(props: QItemChoiceCheckboxProps) { - const { qItem, qrItem, isRepeated, onQrItemChange, orientation } = props; - - // Init input value - const qrChoiceCheckbox = qrItem ?? createEmptyQrItem(qItem); - const answers = qrChoiceCheckbox.answer ? qrChoiceCheckbox.answer : []; - - // Get additional rendering extensions - const { displayInstructions, readOnly } = useRenderingExtensions(qItem); - - // Event handlers - function handleCheckedChange(changedValue: string) { - const answerOptions = qItem.answerOption; - if (!answerOptions) return null; - - const updatedQrChoiceCheckbox = updateQrCheckboxAnswers( - changedValue, - answers, - answerOptions, - qrChoiceCheckbox, - isRepeated - ); - - if (updatedQrChoiceCheckbox) { - onQrItemChange(updatedQrChoiceCheckbox); - } - } - - const choiceCheckbox = ( - - {qItem.answerOption?.map((option) => { - if (option['valueCoding']) { - return ( - JSON.stringify(answer) === JSON.stringify(option) - )} - onCheckedChange={handleCheckedChange} - /> - ); - } else if (option['valueString']) { - return ( - answer.valueString === option.valueString)} - onCheckedChange={handleCheckedChange} - /> - ); - } else if (option['valueInteger']) { - return ( - answer.valueInteger === option.valueInteger)} - onCheckedChange={handleCheckedChange} - /> - ); - } else { - return null; - } - })} - - ); - - return ( - - - - - - - {choiceCheckbox} - - - - - ); -} - -export default QItemChoiceCheckboxAnswerOption; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceCheckboxAnswerValueSet.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceCheckboxAnswerValueSet.tsx deleted file mode 100644 index 588c63317..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceCheckboxAnswerValueSet.tsx +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Grid, Typography } from '@mui/material'; - -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import useValueSetCodings from '../../../../hooks/useValueSetCodings.ts'; -import { QItemChoiceOrientation } from '../../../../types/choice.enum.ts'; -import { mapCodingsToOptions, updateQrCheckboxAnswers } from '../../../../utils/choice.ts'; -import QItemCheckboxSingle from '../QItemParts/QItemCheckboxSingle.tsx'; -import { QFormGroup } from '../Item.styles.tsx'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import { StyledAlert } from '../../../../../../components/Nav/Nav.styles.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface Props - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - orientation: QItemChoiceOrientation; -} - -function QItemChoiceCheckboxAnswerValueSet(props: Props) { - const { qItem, qrItem, isRepeated, onQrItemChange, orientation } = props; - - // Init input value - const qrChoiceCheckbox = qrItem ?? createEmptyQrItem(qItem); - const answers = qrChoiceCheckbox.answer ? qrChoiceCheckbox.answer : []; - - // Get additional rendering extensions - const { displayInstructions, readOnly } = useRenderingExtensions(qItem); - - // Get codings/options from valueSet - const { codings, serverError } = useValueSetCodings(qItem); - - // Event handlers - function handleCheckedChange(changedValue: string) { - if (codings.length < 1) return null; - - const updatedQrChoiceCheckbox = updateQrCheckboxAnswers( - changedValue, - answers, - mapCodingsToOptions(codings), - qrChoiceCheckbox, - isRepeated - ); - - if (updatedQrChoiceCheckbox) { - onQrItemChange(updatedQrChoiceCheckbox); - } - } - - const choiceCheckbox = - codings.length > 0 ? ( - - {codings.map((coding) => { - return ( - JSON.stringify(answer.valueCoding) === JSON.stringify(coding) - )} - onCheckedChange={handleCheckedChange} - /> - ); - })} - - ) : serverError ? ( - - - - There was an error fetching options from the terminology server - - - ) : ( - - - - Unable to fetch options from the questionnaire or launch context - - - ); - - return ( - - - - - - - {choiceCheckbox} - - - - - ); -} - -export default QItemChoiceCheckboxAnswerValueSet; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioAnswerOption.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioAnswerOption.tsx deleted file mode 100644 index ec74f6b69..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioAnswerOption.tsx +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ChangeEvent } from 'react'; -import { Grid } from '@mui/material'; -import { QItemChoiceOrientation } from '../../../../types/choice.enum.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { findInAnswerOptions, getQrChoiceValue } from '../../../../utils/choice.ts'; -import QItemChoiceRadioSingle from './QItemChoiceRadioSingle.tsx'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { QRadioGroup } from '../Item.styles.tsx'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface Props - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - orientation: QItemChoiceOrientation; -} - -function QItemChoiceRadioAnswerOption(props: Props) { - const { qItem, qrItem, isRepeated, onQrItemChange, orientation } = props; - - // Init input value - const qrChoiceRadio = qrItem ?? createEmptyQrItem(qItem); - const valueRadio = getQrChoiceValue(qrChoiceRadio); - - // Get additional rendering extensions - const { displayInstructions, readOnly } = useRenderingExtensions(qItem); - - // Event handlers - function handleChange(e: ChangeEvent) { - if (qItem.answerOption) { - const qrAnswer = findInAnswerOptions(qItem.answerOption, e.target.value); - if (qrAnswer) { - onQrItemChange({ ...createEmptyQrItem(qItem), answer: [qrAnswer] }); - } - } - } - - const choiceRadio = ( - - {qItem.answerOption?.map((option) => { - if (option['valueCoding']) { - return ( - - ); - } else if (option['valueString']) { - return ( - - ); - } else if (option['valueInteger']) { - return ( - - ); - } else { - return null; - } - })} - - ); - - const renderQItemChoiceRadio = isRepeated ? ( - <>{choiceRadio} - ) : ( - - - - - - - {choiceRadio} - - - - - ); - return <>{renderQItemChoiceRadio}; -} - -export default QItemChoiceRadioAnswerOption; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioAnswerValueSet.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioAnswerValueSet.tsx deleted file mode 100644 index 792a0a7bf..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioAnswerValueSet.tsx +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ChangeEvent } from 'react'; -import { Grid, Typography } from '@mui/material'; -import { QItemChoiceOrientation } from '../../../../types/choice.enum.ts'; -import type { Coding, QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { findInAnswerValueSetCodings } from '../../../../utils/choice.ts'; -import QItemChoiceRadioSingle from './QItemChoiceRadioSingle.tsx'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { QRadioGroup } from '../Item.styles.tsx'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import useValueSetCodings from '../../../../hooks/useValueSetCodings.ts'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import { StyledAlert } from '../../../../../../components/Nav/Nav.styles.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface Props - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - orientation: QItemChoiceOrientation; -} - -function QItemChoiceRadioAnswerValueSet(props: Props) { - const { qItem, qrItem, isRepeated, onQrItemChange, orientation } = props; - - // Init input value - const qrChoiceRadio = qrItem ?? createEmptyQrItem(qItem); - - let valueRadio: string | undefined; - if (qrChoiceRadio.answer) { - valueRadio = qrChoiceRadio.answer[0].valueCoding?.code; - } - - // Get additional rendering extensions - const { displayInstructions, readOnly } = useRenderingExtensions(qItem); - - // Get codings/options from valueSet - const { codings, serverError } = useValueSetCodings(qItem); - - function handleChange(event: ChangeEvent) { - if (codings.length > 0) { - const qrAnswer = findInAnswerValueSetCodings(codings, event.target.value); - if (qrAnswer) { - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: [{ valueCoding: qrAnswer }] - }); - } - } - } - - const choiceRadio = - codings.length > 0 ? ( - - {codings.map((coding: Coding) => { - return ( - - ); - })} - - ) : serverError ? ( - - - - There was an error fetching options from the terminology server - - - ) : ( - - - - Unable to fetch options from the questionnaire or launch context - - - ); - - const renderQItemChoiceRadio = isRepeated ? ( - <>{choiceRadio} - ) : ( - - - - - - - {choiceRadio} - - - - - ); - return <>{renderQItemChoiceRadio}; -} - -export default QItemChoiceRadioAnswerValueSet; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioSingle.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioSingle.tsx deleted file mode 100644 index f95f44fca..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceRadioSingle.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { FormControlLabel, Radio } from '@mui/material'; - -interface Props { - value: string; - label: string; - readOnly: boolean; -} - -function QItemChoiceRadioSingle(props: Props) { - const { value, label, readOnly } = props; - - return ( - } - label={label} - sx={{ mr: 3 }} - /> - ); -} - -export default QItemChoiceRadioSingle; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceSelectAnswerOption.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceSelectAnswerOption.tsx deleted file mode 100644 index 1a886fec0..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceSelectAnswerOption.tsx +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { SelectChangeEvent } from '@mui/material'; -import { Grid, InputAdornment, MenuItem, Select } from '@mui/material'; - -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { findInAnswerOptions, getQrChoiceValue } from '../../../../utils/choice.ts'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import { Fragment } from 'react'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface Props - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function QItemChoiceSelectAnswerOption(props: Props) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Init input value - const qrChoiceSelect = qrItem ?? createEmptyQrItem(qItem); - let valueSelect = getQrChoiceValue(qrChoiceSelect); - if (valueSelect === null) { - valueSelect = ''; - } - - // Get additional rendering extensions - const { displayUnit, displayPrompt, displayInstructions, readOnly, entryFormat } = - useRenderingExtensions(qItem); - - // Event handlers - function handleChange(e: SelectChangeEvent) { - if (qItem.answerOption) { - const qrAnswer = findInAnswerOptions(qItem.answerOption, e.target.value); - if (qrAnswer) { - onQrItemChange({ ...createEmptyQrItem(qItem), answer: [qrAnswer] }); - return; - } - } - onQrItemChange(createEmptyQrItem(qItem)); - } - - const choiceSelectAnswerOption = ( - - ); - - const renderQItemChoiceSelectAnswerOption = isRepeated ? ( - <>{choiceSelectAnswerOption} - ) : ( - - - - - - - {choiceSelectAnswerOption} - - - - - ); - return <>{renderQItemChoiceSelectAnswerOption}; -} - -export default QItemChoiceSelectAnswerOption; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceSelectAnswerValueSet.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceSelectAnswerValueSet.tsx deleted file mode 100644 index 590529eba..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemChoice/QItemChoiceSelectAnswerValueSet.tsx +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { SyntheticEvent } from 'react'; -import { useEffect, useMemo } from 'react'; -import { Autocomplete, Grid, Typography } from '@mui/material'; - -import type { Coding, QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { StandardTextField } from '../Textfield.styles.tsx'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import useValueSetCodings from '../../../../hooks/useValueSetCodings.ts'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import { StyledAlert } from '../../../../../../components/Nav/Nav.styles.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface Props - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function QItemChoiceSelectAnswerValueSet(props: Props) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Init input value - const qrChoiceSelect = qrItem ?? createEmptyQrItem(qItem); - let valueCoding: Coding | undefined; - if (qrChoiceSelect.answer) { - valueCoding = qrChoiceSelect.answer[0].valueCoding; - } - - // Get additional rendering extensions - const { displayUnit, displayPrompt, displayInstructions, readOnly, entryFormat } = - useRenderingExtensions(qItem); - - // Get codings/options from valueSet - const { codings, serverError } = useValueSetCodings(qItem); - - valueCoding = useMemo(() => { - const updatedValueCoding = codings.find( - (queriedCoding) => queriedCoding.code === valueCoding?.code - ); - return updatedValueCoding ?? valueCoding; - }, [codings, valueCoding]); - - // Check and remove populated answer if it is a string - // NOTE: $populate will try to populate answer as valueCoding, - // but will fail if answer provided is not within options - useEffect( - () => { - if (qrChoiceSelect.answer && qrChoiceSelect.answer[0].valueString) { - onQrItemChange(createEmptyQrItem(qItem)); - } - }, - // Only run effect once - on populate - // eslint-disable-next-line react-hooks/exhaustive-deps - [] - ); - - // Event handlers - function handleChange(_: SyntheticEvent, newValue: Coding | null) { - if (newValue) { - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: [{ valueCoding: newValue }] - }); - return; - } - onQrItemChange(createEmptyQrItem(qItem)); - } - - const choiceSelectAnswerValueSet = - codings.length > 0 ? ( - `${option.display}`} - value={valueCoding ?? null} - onChange={handleChange} - openOnFocus - autoHighlight - sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160, flexGrow: 1 }} - size="small" - disabled={readOnly} - placeholder={entryFormat} - renderInput={(params) => ( - - {params.InputProps.endAdornment} - {displayUnit} - - ) - }} - data-test="q-item-choice-dropdown-answer-value-set-field" - /> - )} - /> - ) : serverError ? ( - - - - There was an error fetching options from the terminology server - - - ) : ( - - - - Unable to fetch options from the questionnaire or launch context - - - ); - - const renderQItemChoiceSelectAnswerValueSet = isRepeated ? ( - <>{choiceSelectAnswerValueSet} - ) : ( - - - - - - - {choiceSelectAnswerValueSet} - - - - - ); - return <>{renderQItemChoiceSelectAnswerValueSet}; -} - -export default QItemChoiceSelectAnswerValueSet; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoice.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoice.tsx deleted file mode 100644 index ac3798144..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoice.tsx +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { QItemOpenChoiceControl } from '../../../../types/choice.enum.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import QItemOpenChoiceSelectAnswerOption from './QItemOpenChoiceSelectAnswerOption.tsx'; -import QItemOpenChoiceSelectAnswerValueSet from './QItemOpenChoiceSelectAnswerValueSet.tsx'; -import QItemOpenChoiceAutocomplete from './QItemOpenChoiceAutocomplete.tsx'; -import { getOpenChoiceControlType } from '../../../../utils/openChoice.ts'; -import { getChoiceOrientation } from '../../../../utils/choice.ts'; -import QItemOpenChoiceCheckboxAnswerOption from './QItemOpenChoiceCheckboxAnswerOption.tsx'; -import QItemOpenChoiceRadioAnswerOption from './QItemOpenChoiceRadioAnswerOption.tsx'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; - -interface Props - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function QItemOpenChoice(props: Props) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - const orientation = getChoiceOrientation(qItem); - - switch (getOpenChoiceControlType(qItem)) { - case QItemOpenChoiceControl.Checkbox: - return ( - - ); - case QItemOpenChoiceControl.Radio: - return ( - - ); - case QItemOpenChoiceControl.Autocomplete: - return ( - - ); - case QItemOpenChoiceControl.Select: - if (qItem.answerValueSet) { - return ( - - ); - } else { - return ( - - ); - } - default: - return null; - } -} - -export default QItemOpenChoice; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceAutocomplete.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceAutocomplete.tsx deleted file mode 100644 index fe8d0c8ce..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceAutocomplete.tsx +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ChangeEvent, SyntheticEvent } from 'react'; -import { useState } from 'react'; -import { Autocomplete, Box, CircularProgress, Fade, Grid, Tooltip } from '@mui/material'; -import type { Coding, QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; - -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { StandardTextField } from '../Textfield.styles.tsx'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import SearchIcon from '@mui/icons-material/Search'; -import useDebounce from '../../../../hooks/useDebounce.ts'; -import useTerminologyServerQuery from '../../../../hooks/useTerminologyServerQuery.ts'; -import WarningAmberIcon from '@mui/icons-material/WarningAmber'; -import InfoIcon from '@mui/icons-material/Info'; -import DoneIcon from '@mui/icons-material/Done'; -import ErrorIcon from '@mui/icons-material/Error'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import { getTerminologyServerUrl } from '../../../../../../utils/valueSet.ts'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import { AUTOCOMPLETE_DEBOUNCE_DURATION } from '../../../../utils/debounce.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface QItemOpenChoiceAutocompleteProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function QItemOpenChoiceAutocomplete(props: QItemOpenChoiceAutocompleteProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - const qrOpenChoice = qrItem ?? createEmptyQrItem(qItem); - - // Init input value - let valueAutocomplete: Coding | string | undefined; - if (qrOpenChoice.answer) { - const answer = qrOpenChoice.answer[0]; - valueAutocomplete = answer.valueCoding ? answer.valueCoding : answer.valueString; - } - - if (!valueAutocomplete) { - valueAutocomplete = ''; - } - - // Get additional rendering extensions - const { displayUnit, displayPrompt, displayInstructions, readOnly, entryFormat } = - useRenderingExtensions(qItem); - - // Query ontoserver for options - const maxList = 10; - - const [input, setInput] = useState(''); - const debouncedInput = useDebounce(input, AUTOCOMPLETE_DEBOUNCE_DURATION); - - const answerValueSetUrl = qItem.answerValueSet; - const terminologyServerUrl = getTerminologyServerUrl(qItem); - const { options, loading, feedback } = useTerminologyServerQuery( - answerValueSetUrl, - maxList, - input, - debouncedInput, - terminologyServerUrl - ); - - if (!answerValueSetUrl) return null; - - // Event handlers - function handleValueChange(_: SyntheticEvent, newValue: Coding | string | null) { - if (newValue === null) { - setInput(''); - newValue = ''; - } - - if (typeof newValue === 'string') { - if (newValue !== '') { - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: [{ valueString: newValue }] - }); - } else { - onQrItemChange(createEmptyQrItem(qItem)); - } - } else { - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: [{ valueCoding: newValue }] - }); - } - } - - const openChoiceAutocomplete = ( - <> - - (typeof option === 'string' ? option : `${option.display}`)} - loading={loading} - loadingText={'Fetching results...'} - clearOnEscape - freeSolo - autoHighlight - sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 220, flexGrow: 1 }} - placeholder={entryFormat} - onChange={handleValueChange} - filterOptions={(x) => x} - renderInput={(params) => ( - { - // set answer to current input when text field is unfocused - if (!valueAutocomplete && input !== '') { - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: [{ valueString: input }] - }); - } - }} - onChange={(e: ChangeEvent) => setInput(e.target.value)} - isTabled={isTabled} - disabled={readOnly} - label={displayPrompt} - size="small" - InputProps={{ - ...params.InputProps, - startAdornment: ( - <> - {!valueAutocomplete || valueAutocomplete === '' ? ( - - ) : null} - {params.InputProps.startAdornment} - - ), - endAdornment: ( - <> - {loading ? ( - - ) : feedback ? ( - - - { - { - info: , - warning: , - success: , - error: - }[feedback.color] - } - - - ) : null} - {params.InputProps.endAdornment} - {displayUnit} - - ) - }} - data-test="q-item-open-choice-autocomplete-field" - /> - )} - /> - - - ); - - const renderQItemOpenChoiceAutocomplete = isRepeated ? ( - <>{openChoiceAutocomplete} - ) : ( - - - - - - - {openChoiceAutocomplete} - - - - - ); - return <>{renderQItemOpenChoiceAutocomplete}; -} - -export default QItemOpenChoiceAutocomplete; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceCheckboxAnswerOption.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceCheckboxAnswerOption.tsx deleted file mode 100644 index 3a9a8b848..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceCheckboxAnswerOption.tsx +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useCallback, useMemo, useState } from 'react'; -import { Grid } from '@mui/material'; -import { CheckBoxOptionType, QItemChoiceOrientation } from '../../../../types/choice.enum.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import QItemCheckboxSingle from '../QItemParts/QItemCheckboxSingle.tsx'; -import { getOpenLabelText } from '../../../../utils/itemControl.ts'; -import QItemCheckboxSingleWithOpenLabel from '../QItemParts/QItemCheckboxSingleWithOpenLabel.tsx'; -import { QFormGroup } from '../Item.styles.tsx'; -import { - getOldOpenLabelAnswer, - updateQrOpenChoiceCheckboxAnswers -} from '../../../../utils/openChoice.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import debounce from 'lodash.debounce'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import { DEBOUNCE_DURATION } from '../../../../utils/debounce.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface QItemOpenChoiceCheckboxProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - orientation: QItemChoiceOrientation; -} - -function QItemOpenChoiceCheckboxAnswerOption(props: QItemOpenChoiceCheckboxProps) { - const { qItem, qrItem, isRepeated, onQrItemChange, orientation } = props; - - // Init answers - const qrOpenChoiceCheckbox = qrItem ?? createEmptyQrItem(qItem); - const answers = useMemo(() => qrOpenChoiceCheckbox.answer ?? [], [qrOpenChoiceCheckbox.answer]); - - // Init options and open label value - const answerOptions = qItem.answerOption; - let initialOpenLabelValue = ''; - let initialOpenLabelChecked = false; - if (answerOptions) { - const oldLabelAnswer = getOldOpenLabelAnswer(answers, answerOptions); - if (oldLabelAnswer && oldLabelAnswer.valueString) { - initialOpenLabelValue = oldLabelAnswer.valueString; - initialOpenLabelChecked = true; - } - } - const [openLabelValue, setOpenLabelValue] = useState(initialOpenLabelValue); - const [openLabelChecked, setOpenLabelChecked] = useState(initialOpenLabelChecked); - - // Get additional rendering extensions - const openLabelText = getOpenLabelText(qItem); - const { displayInstructions, readOnly } = useRenderingExtensions(qItem); - - // Event handlers - const handleValueChange = useCallback( - (changedOptionValue: string | null, changedOpenLabelValue: string | null) => { - if (!answerOptions) return null; - - let updatedQrChoiceCheckbox: QuestionnaireResponseItem | null = null; - if (changedOptionValue) { - updatedQrChoiceCheckbox = updateQrOpenChoiceCheckboxAnswers( - changedOptionValue, - null, - answers, - answerOptions, - qrOpenChoiceCheckbox, - CheckBoxOptionType.AnswerOption, - isRepeated - ); - } else if (changedOpenLabelValue !== null) { - updatedQrChoiceCheckbox = updateQrOpenChoiceCheckboxAnswers( - null, - changedOpenLabelValue, - answers, - answerOptions, - qrOpenChoiceCheckbox, - CheckBoxOptionType.AnswerOption, - isRepeated - ); - } - - if (updatedQrChoiceCheckbox) { - onQrItemChange(updatedQrChoiceCheckbox); - } - }, - [answerOptions, answers, isRepeated, onQrItemChange, qrOpenChoiceCheckbox] - ); - - // eslint-disable-next-line react-hooks/exhaustive-deps - const updateOpenLabelValueWithDebounce = useCallback( - debounce((input: string) => { - handleValueChange(null, input); - }, DEBOUNCE_DURATION), - [handleValueChange] - ); // Dependencies are tested, debounce is causing eslint to not recognise dependencies - - const openChoiceCheckbox = ( - - {qItem.answerOption?.map((option) => { - if (option['valueCoding']) { - return ( - JSON.stringify(answer) === JSON.stringify(option) - )} - onCheckedChange={(changedValue) => handleValueChange(changedValue, null)} - /> - ); - } else if (option['valueString']) { - return ( - answer.valueString === option.valueString)} - onCheckedChange={(changedValue) => handleValueChange(changedValue, null)} - /> - ); - } else if (option['valueInteger']) { - return ( - answer.valueInteger === option.valueInteger)} - onCheckedChange={(changedValue) => handleValueChange(changedValue, null)} - /> - ); - } else { - return null; - } - })} - - {openLabelText ? ( - { - handleValueChange(null, openLabelValue); - setOpenLabelChecked(checked); - }} - onInputChange={(input) => { - setOpenLabelValue(input); - updateOpenLabelValueWithDebounce(input); - }} - /> - ) : null} - - ); - - return ( - - - - - - - {openChoiceCheckbox} - - - - - ); -} - -export default QItemOpenChoiceCheckboxAnswerOption; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceRadioAnswerOption.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceRadioAnswerOption.tsx deleted file mode 100644 index 3791c09ab..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceRadioAnswerOption.tsx +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ChangeEvent } from 'react'; -import { useState } from 'react'; -import { Grid } from '@mui/material'; -import { QItemChoiceOrientation } from '../../../../types/choice.enum.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { getOpenLabelText } from '../../../../utils/itemControl.ts'; -import { QRadioGroup } from '../Item.styles.tsx'; -import { getOldOpenLabelAnswer } from '../../../../utils/openChoice.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import QItemChoiceRadioSingle from '../QItemChoice/QItemChoiceRadioSingle.tsx'; -import { findInAnswerOptions, getQrChoiceValue } from '../../../../utils/choice.ts'; -import QItemRadioButtonWithOpenLabel from '../QItemParts/QItemRadioButtonWithOpenLabel.tsx'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface QItemOpenChoiceRadioProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - orientation: QItemChoiceOrientation; -} - -function QItemOpenChoiceRadioAnswerOption(props: QItemOpenChoiceRadioProps) { - const { qItem, qrItem, onQrItemChange, orientation } = props; - - // Init answers - const qrOpenChoiceRadio = qrItem ?? createEmptyQrItem(qItem); - let valueRadio: string | null = getQrChoiceValue(qrOpenChoiceRadio, true); - const answers = qrOpenChoiceRadio.answer ?? []; - - // Init empty open label - const answerOptions = qItem.answerOption; - let initialOpenLabelValue = ''; - let initialOpenLabelSelected = false; - if (answerOptions) { - const oldLabelAnswer = getOldOpenLabelAnswer(answers, answerOptions); - if (oldLabelAnswer && oldLabelAnswer.valueString) { - initialOpenLabelValue = oldLabelAnswer.valueString; - initialOpenLabelSelected = true; - valueRadio = initialOpenLabelValue; - } - } - - const [openLabelValue, setOpenLabelValue] = useState(initialOpenLabelValue); - const [openLabelSelected, setOpenLabelSelected] = useState(initialOpenLabelSelected); - - // Allow open label to remain selected even if its input was cleared - if (openLabelSelected && valueRadio === null) { - valueRadio = ''; - } - - // Get additional rendering extensions - const openLabelText = getOpenLabelText(qItem); - const { displayInstructions, readOnly } = useRenderingExtensions(qItem); - - // Event handlers - function handleValueChange( - changedOptionValue: string | null, - changedOpenLabelValue: string | null - ) { - if (!answerOptions) return null; - - if (changedOptionValue !== null) { - if (qItem.answerOption) { - const qrAnswer = findInAnswerOptions(qItem.answerOption, changedOptionValue); - - // If selected answer can be found in options, it is a non-open label selection - if (qrAnswer) { - onQrItemChange({ ...createEmptyQrItem(qItem), answer: [qrAnswer] }); - setOpenLabelSelected(false); - } else { - // Otherwise, it is an open-label selection - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: [{ valueString: changedOptionValue }] - }); - setOpenLabelValue(changedOptionValue); - setOpenLabelSelected(true); - } - } - } - - if (changedOpenLabelValue !== null) { - setOpenLabelValue(changedOpenLabelValue); - - if (changedOpenLabelValue === '') { - onQrItemChange(createEmptyQrItem(qItem)); - } else { - setOpenLabelValue(changedOpenLabelValue); - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: [{ valueString: changedOpenLabelValue }] - }); - } - } - } - - const openChoiceRadio = ( - ) => handleValueChange(e.target.value, null)} - value={valueRadio} - data-test="q-item-radio-group"> - {qItem.answerOption?.map((option) => { - if (option['valueCoding']) { - return ( - - ); - } else if (option['valueString']) { - return ( - - ); - } else if (option['valueInteger']) { - return ( - - ); - } else { - return null; - } - })} - - {openLabelText ? ( - handleValueChange(null, input)} - /> - ) : null} - - ); - - return ( - - - - - - - {openChoiceRadio} - - - - - ); -} - -export default QItemOpenChoiceRadioAnswerOption; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceSelectAnswerOption.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceSelectAnswerOption.tsx deleted file mode 100644 index 2651f54cd..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceSelectAnswerOption.tsx +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { SyntheticEvent } from 'react'; -import { Autocomplete, Grid } from '@mui/material'; - -import type { - QuestionnaireItem, - QuestionnaireItemAnswerOption, - QuestionnaireResponseItem -} from 'fhir/r4'; -import { getAnswerOptionLabel } from '../../../../utils/openChoice.ts'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { StandardTextField } from '../Textfield.styles.tsx'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface Props - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function QItemOpenChoiceSelectAnswerOption(props: Props) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Get additional rendering extensions - const { displayUnit, displayPrompt, displayInstructions, readOnly, entryFormat } = - useRenderingExtensions(qItem); - - // Init input value - const answerOptions = qItem.answerOption; - if (!answerOptions) return null; - - const qrOpenChoice = qrItem ?? createEmptyQrItem(qItem); - let valueSelect: QuestionnaireItemAnswerOption | undefined = undefined; - if (qrOpenChoice.answer) { - valueSelect = qrOpenChoice.answer[0]; - } - - // Event handlers - function handleChange( - _: SyntheticEvent, - newValue: QuestionnaireItemAnswerOption | string | null - ) { - if (newValue) { - if (typeof newValue === 'string') { - onQrItemChange({ - ...qrOpenChoice, - answer: [{ valueString: newValue }] - }); - } else { - const option = newValue; - if (option['valueCoding']) { - onQrItemChange({ - ...qrOpenChoice, - answer: [{ valueCoding: option.valueCoding }] - }); - } else if (option['valueString']) { - onQrItemChange({ - ...qrOpenChoice, - answer: [{ valueString: option.valueString }] - }); - } else if (option['valueInteger']) { - onQrItemChange({ - ...qrOpenChoice, - answer: [{ valueInteger: option.valueInteger }] - }); - } - } - return; - } - onQrItemChange(createEmptyQrItem(qItem)); - } - - const openOpenChoiceSelectAnswerOption = ( - getAnswerOptionLabel(option)} - onChange={handleChange} - freeSolo - autoHighlight - sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160, flexGrow: 1 }} - disabled={readOnly} - size="small" - placeholder={entryFormat} - renderInput={(params) => ( - - {params.InputProps.endAdornment} - {displayUnit} - - ) - }} - /> - )} - /> - ); - const renderQItemOpenChoiceAutocomplete = isRepeated ? ( - <>{openOpenChoiceSelectAnswerOption} - ) : ( - - - - - - - {openOpenChoiceSelectAnswerOption} - - - - - ); - return <>{renderQItemOpenChoiceAutocomplete}; -} - -export default QItemOpenChoiceSelectAnswerOption; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceSelectAnswerValueSet.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceSelectAnswerValueSet.tsx deleted file mode 100644 index d5a0da42c..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemOpenChoice/QItemOpenChoiceSelectAnswerValueSet.tsx +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { SyntheticEvent } from 'react'; -import { Autocomplete, Grid, Typography } from '@mui/material'; - -import type { Coding, QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { StandardTextField } from '../Textfield.styles.tsx'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import useValueSetCodings from '../../../../hooks/useValueSetCodings.ts'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import DisplayInstructions from '../DisplayItem/DisplayInstructions.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface Props - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function QItemOpenChoiceSelectAnswerValueSet(props: Props) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Init input value - const qrOpenChoice = qrItem ?? createEmptyQrItem(qItem); - let valueSelect: Coding | undefined = undefined; - if (qrOpenChoice['answer']) { - valueSelect = qrOpenChoice['answer'][0].valueCoding; - } - - // Get codings/options from valueSet - const { codings, serverError } = useValueSetCodings(qItem); - - // Get additional rendering extensions - const { displayUnit, displayPrompt, displayInstructions, readOnly, entryFormat } = - useRenderingExtensions(qItem); - - // Event handlers - function handleValueChange(_: SyntheticEvent, newValue: Coding | string | null) { - if (newValue) { - if (typeof newValue === 'string') { - onQrItemChange({ - ...qrOpenChoice, - answer: [{ valueString: newValue }] - }); - } else { - onQrItemChange({ - ...qrOpenChoice, - answer: [{ valueCoding: newValue }] - }); - } - return; - } - onQrItemChange(createEmptyQrItem(qItem)); - } - - const openChoiceSelectAnswerValueSet = ( - <> - (typeof option === 'string' ? option : `${option.display}`)} - onChange={handleValueChange} - onInputChange={(event, newValue) => handleValueChange(event, newValue)} - freeSolo - autoHighlight - sx={{ maxWidth: !isTabled ? 280 : 3000, minWidth: 160, flexGrow: 1 }} - disabled={readOnly} - size="small" - placeholder={entryFormat} - renderInput={(params) => ( - - {params.InputProps.endAdornment} - {displayUnit} - - ) - }} - /> - )} - /> - {serverError ? ( - - There was an error fetching options from the terminology server. - - ) : null} - - ); - - const renderQItemOpenChoiceSelectAnswerValueSet = isRepeated ? ( - <>{openChoiceSelectAnswerValueSet} - ) : ( - - - - - - - {openChoiceSelectAnswerValueSet} - - - - - ); - return <>{renderQItemOpenChoiceSelectAnswerValueSet}; -} - -export default QItemOpenChoiceSelectAnswerValueSet; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/ContextDisplayItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/ContextDisplayItem.tsx deleted file mode 100644 index 2d906a5ee..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/ContextDisplayItem.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { memo } from 'react'; -import type { QuestionnaireItem } from 'fhir/r4'; -import useHidden from '../../../../hooks/useHidden.ts'; -import LabelText from './LabelText.tsx'; - -interface GroupHeadingIconProps { - displayItem: QuestionnaireItem; -} - -const ContextDisplayItem = memo(function GroupHeadingIcon(props: GroupHeadingIconProps) { - const { displayItem } = props; - - const itemIsHidden = useHidden(displayItem); - if (itemIsHidden) { - return null; - } - - return ; -}); - -export default ContextDisplayItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/LabelText.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/LabelText.tsx deleted file mode 100644 index 22e2bb63a..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/LabelText.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { memo } from 'react'; -import type { QuestionnaireItem } from 'fhir/r4'; -import { getMarkdownString, getXHtmlString } from '../../../../utils/itemControl.ts'; -import { QItemTypography } from '../Item.styles.tsx'; -import parse from 'html-react-parser'; -import { Box } from '@mui/material'; -import ReactMarkdown from 'react-markdown'; - -interface LabelTextProps { - qItem: QuestionnaireItem; -} - -const LabelText = memo(function LabelText(props: LabelTextProps) { - const { qItem } = props; - - // parse xHTML if found - const xHtmlString = getXHtmlString(qItem); - - if (xHtmlString) { - return {parse(xHtmlString)}; - } - - // parse xHTML if found - const markdownString = getMarkdownString(qItem); - if (markdownString) { - return ( - - {markdownString} - - ); - } - - // parse regular text - if (qItem.type === 'group') { - return <>{qItem.text}; - } else { - return {qItem.text}; - } -}); - -export default LabelText; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/LabelWrapper.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/LabelWrapper.tsx deleted file mode 100644 index 601ff69ac..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/LabelWrapper.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Box } from '@mui/material'; -import ContextDisplayItem from './ContextDisplayItem.tsx'; -import type { QuestionnaireItem } from 'fhir/r4'; -import { getContextDisplays } from '../../../../utils/tabs.ts'; -import LabelText from './LabelText.tsx'; - -interface LabelWrapperProps { - qItem: QuestionnaireItem; -} - -function LabelWrapper(props: LabelWrapperProps) { - const { qItem } = props; - - const contextDisplayItems = getContextDisplays(qItem); - - return ( - - - - - {contextDisplayItems.map((item) => { - return ; - })} - - - ); -} - -export default LabelWrapper; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemCheckboxSingle.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemCheckboxSingle.tsx deleted file mode 100644 index 6fd1a3daf..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemCheckboxSingle.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Checkbox, FormControlLabel } from '@mui/material'; - -interface Props { - value: string; - label: string; - readOnly: boolean; - isChecked: boolean; - onCheckedChange: (value: string) => unknown; -} - -function QItemCheckboxSingle(props: Props) { - const { value, label, readOnly, isChecked, onCheckedChange } = props; - - return ( - onCheckedChange(value)} /> - } - label={label} - sx={{ mr: 3 }} - /> - ); -} - -export default QItemCheckboxSingle; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemCheckboxSingleWithOpenLabel.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemCheckboxSingleWithOpenLabel.tsx deleted file mode 100644 index 35daf8136..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemCheckboxSingleWithOpenLabel.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ChangeEvent } from 'react'; -import { Box, Checkbox, FormControlLabel } from '@mui/material'; -import { StandardTextField } from '../Textfield.styles.tsx'; - -interface Props { - value: string | null; - label: string; - isChecked: boolean; - onCheckedChange: (checked: boolean) => unknown; - onInputChange: (input: string) => unknown; -} - -function QItemCheckboxSingleWithOpenLabel(props: Props) { - const { value, label, isChecked, onCheckedChange, onInputChange } = props; - - function handleCheckedChange(event: ChangeEvent) { - onCheckedChange(event.target.checked); - } - - function handleInputChange(event: ChangeEvent) { - onInputChange(event.target.value); - } - - return ( - - } - label={label + ':'} - sx={{ mr: 3 }} - /> - - - ); -} - -export default QItemCheckboxSingleWithOpenLabel; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemRadioButtonWithOpenLabel.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemRadioButtonWithOpenLabel.tsx deleted file mode 100644 index cb5b45153..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/QItemParts/QItemRadioButtonWithOpenLabel.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ChangeEvent } from 'react'; -import { Box } from '@mui/material'; -import { StandardTextField } from '../Textfield.styles.tsx'; -import QItemChoiceRadioSingle from '../QItemChoice/QItemChoiceRadioSingle.tsx'; - -interface Props { - value: string | null; - label: string; - readOnly: boolean; - isSelected: boolean; - onInputChange: (input: string) => unknown; -} - -function QItemRadioButtonWithOpenLabel(props: Props) { - const { value, label, readOnly, isSelected, onInputChange } = props; - function handleInputChange(event: ChangeEvent) { - onInputChange(event.target.value); - } - - return ( - - - - - ); -} - -export default QItemRadioButtonWithOpenLabel; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/AddItemButton.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/AddItemButton.tsx deleted file mode 100644 index 381de598e..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/AddItemButton.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Box, Button } from '@mui/material'; -import AddIcon from '@mui/icons-material/Add'; -import type { RepeatGroupSingle } from '../../../../types/repeatGroup.interface.ts'; - -interface AddItemButtonProps { - repeatGroups: RepeatGroupSingle[]; - onAddItem: () => void; -} - -function AddItemButton(props: AddItemButtonProps) { - const { repeatGroups, onAddItem } = props; - - const isDisabled = repeatGroups[repeatGroups.length - 1].qrItem === null; - - return ( - - - - ); -} - -export default AddItemButton; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/DeleteItemButton.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/DeleteItemButton.tsx deleted file mode 100644 index 9cee7d93c..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/DeleteItemButton.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { RepeatDeleteTooltip } from '../RepeatItem/RepeatItem.styles.tsx'; -import { IconButton } from '@mui/material'; -import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline'; -import type { QuestionnaireResponseItem } from 'fhir/r4'; - -interface DeleteItemButtonProps { - nullableQrItem: QuestionnaireResponseItem | null; - numOfRepeatGroups: number; - onDeleteItem: () => void; -} - -function DeleteItemButton(props: DeleteItemButtonProps) { - const { nullableQrItem, numOfRepeatGroups, onDeleteItem } = props; - - const isDisabled = nullableQrItem === null || numOfRepeatGroups === 1; - - return ( - - - - - - - - ); -} - -export default DeleteItemButton; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/RepeatGroup.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/RepeatGroup.tsx deleted file mode 100644 index 39ac3fb51..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/RepeatGroup.tsx +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useState } from 'react'; -import type { PropsWithQrRepeatGroupChangeHandler } from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useInitialiseRepeatGroups from '../../../../hooks/useInitialiseRepeatGroups.ts'; -import { QGroupContainerBox } from '../../../../../../components/Box/Box.styles.tsx'; -import { Card, Collapse, Divider } from '@mui/material'; -import { QGroupHeadingTypography } from '../Typography.styles.ts'; -import { TransitionGroup } from 'react-transition-group'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { nanoid } from 'nanoid'; -import RepeatGroupItem from './RepeatGroupItem.tsx'; -import AddItemButton from './AddItemButton.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface RepeatGroupProps extends PropsWithQrRepeatGroupChangeHandler { - qItem: QuestionnaireItem; - qrItems: QuestionnaireResponseItem[]; - groupCardElevation: number; -} - -function RepeatGroup(props: RepeatGroupProps) { - const { qItem, qrItems, groupCardElevation, onQrRepeatGroupChange } = props; - - const initialRepeatGroups = useInitialiseRepeatGroups(qrItems); - - const [repeatGroups, setRepeatGroups] = useState(initialRepeatGroups); - - function handleAnswerChange(newQrItem: QuestionnaireResponseItem, index: number) { - const updatedRepeatGroups = [...repeatGroups]; - - if (newQrItem.item) { - updatedRepeatGroups[index].qrItem = { - linkId: newQrItem.linkId, - text: newQrItem.text, - item: newQrItem.item - }; - } - - setRepeatGroups(updatedRepeatGroups); - onQrRepeatGroupChange({ - linkId: qItem.linkId, - qrItems: updatedRepeatGroups.flatMap((singleGroup) => - singleGroup.qrItem ? [singleGroup.qrItem] : [] - ) - }); - } - - function handleDeleteItem(index: number) { - const updatedRepeatGroups = [...repeatGroups]; - - updatedRepeatGroups.splice(index, 1); - - setRepeatGroups(updatedRepeatGroups); - onQrRepeatGroupChange({ - linkId: qItem.linkId, - qrItems: updatedRepeatGroups.flatMap((singleGroup) => - singleGroup.qrItem ? [singleGroup.qrItem] : [] - ) - }); - } - - function handleAddItem() { - setRepeatGroups([ - ...repeatGroups, - { - nanoId: nanoid(), - qrItem: null - } - ]); - } - - return ( - - - - - - - - {repeatGroups.map(({ nanoId, qrItem: nullableQrItem }, index) => { - const answeredQrItem = createEmptyQrItem(qItem); - if (nullableQrItem) { - answeredQrItem.item = nullableQrItem.item; - } - - return ( - - handleDeleteItem(index)} - onQrItemChange={(newQrItem) => handleAnswerChange(newQrItem, index)} - /> - - ); - })} - - - - - - ); -} - -export default RepeatGroup; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/RepeatGroupItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/RepeatGroupItem.tsx deleted file mode 100644 index 86c394b7e..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatGroup/RepeatGroupItem.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { RepeatGroupContainerStack } from '../RepeatItem/RepeatItem.styles.tsx'; -import { Box } from '@mui/material'; -import GroupItem from '../GroupItem/GroupItem.tsx'; -import type { PropsWithQrItemChangeHandler } from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import DeleteItemButton from './DeleteItemButton.tsx'; - -interface RepeatGroupItemProps extends PropsWithQrItemChangeHandler { - qItem: QuestionnaireItem; - answeredQrItem: QuestionnaireResponseItem; - nullableQrItem: QuestionnaireResponseItem | null; - numOfRepeatGroups: number; - groupCardElevation: number; - onDeleteItem: () => void; -} - -function RepeatGroupItem(props: RepeatGroupItemProps) { - const { - qItem, - answeredQrItem, - nullableQrItem, - numOfRepeatGroups, - groupCardElevation, - onDeleteItem, - onQrItemChange - } = props; - - return ( - - - - - - - ); -} - -export default RepeatGroupItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/AddItemButton.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/AddItemButton.tsx deleted file mode 100644 index cf0ce0dc4..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/AddItemButton.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Box, Button } from '@mui/material'; -import AddIcon from '@mui/icons-material/Add'; -import type { RepeatAnswer } from '../../../../types/repeatItem.interface.ts'; - -interface AddItemButtonProps { - repeatAnswers: RepeatAnswer[]; - onAddItem: () => void; -} - -function AddItemButton(props: AddItemButtonProps) { - const { repeatAnswers, onAddItem } = props; - - const isDisabled = repeatAnswers[repeatAnswers.length - 1].answer === null; - - return ( - - - - ); -} - -export default AddItemButton; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/DeleteItemButton.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/DeleteItemButton.tsx deleted file mode 100644 index 8365dac8e..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/DeleteItemButton.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { RepeatDeleteTooltip } from './RepeatItem.styles.tsx'; -import { IconButton } from '@mui/material'; -import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline'; -import type { QuestionnaireResponseItemAnswer } from 'fhir/r4'; - -interface DeleteItemButtonProps { - answer: QuestionnaireResponseItemAnswer | null; - numOfRepeatAnswers: number; - onDeleteAnswer: () => void; -} - -function DeleteItemButton(props: DeleteItemButtonProps) { - const { answer, numOfRepeatAnswers, onDeleteAnswer } = props; - - const isDisabled = answer === null || numOfRepeatAnswers === 1; - - return ( - - - - - - - - ); -} - -export default DeleteItemButton; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatField.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatField.tsx deleted file mode 100644 index 5d43460bc..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatField.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Box } from '@mui/material'; -import { RepeatItemContainerStack } from './RepeatItem.styles.tsx'; -import SingleItem from '../SingleItem/SingleItem.tsx'; -import type { - QuestionnaireItem, - QuestionnaireResponseItem, - QuestionnaireResponseItemAnswer -} from 'fhir/r4'; -import type { PropsWithQrItemChangeHandler } from '../../../../types/renderProps.interface.ts'; -import DeleteItemButton from './DeleteItemButton.tsx'; - -interface RepeatFieldProps extends PropsWithQrItemChangeHandler { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - answer: QuestionnaireResponseItemAnswer | null; - numOfRepeatAnswers: number; - onDeleteAnswer: () => void; -} - -function RepeatField(props: RepeatFieldProps) { - const { qItem, qrItem, answer, numOfRepeatAnswers, onDeleteAnswer, onQrItemChange } = props; - - return ( - - - - - - - ); -} - -export default RepeatField; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatItem.styles.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatItem.styles.tsx deleted file mode 100644 index a3cc4471f..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatItem.styles.tsx +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Stack, styled, Tooltip } from '@mui/material'; - -export const RepeatDeleteTooltip = styled(Tooltip)(() => ({ - marginLeft: 8 -})); - -export const RepeatItemContainerStack = styled(Stack)(() => ({ - alignItems: 'center', - paddingBottom: 8 -})); - -export const RepeatGroupContainerStack = styled(Stack)(() => ({ - alignItems: 'center', - paddingBottom: 16 -})); diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatItem.tsx deleted file mode 100644 index 755f21354..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/RepeatItem/RepeatItem.tsx +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useState } from 'react'; -import type { PropsWithQrItemChangeHandler } from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { nanoid } from 'nanoid'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import FieldGrid from '../FieldGrid.tsx'; -import AddItemButton from './AddItemButton.tsx'; -import { TransitionGroup } from 'react-transition-group'; -import RepeatField from './RepeatField.tsx'; -import { Collapse } from '@mui/material'; -import useInitialiseRepeatAnswers from '../../../../hooks/useInitialiseRepeatAnswers.ts'; - -interface RepeatItemProps extends PropsWithQrItemChangeHandler { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function RepeatItem(props: RepeatItemProps) { - const { qItem, qrItem, onQrItemChange } = props; - - // Get additional rendering extensions - const { displayInstructions } = useRenderingExtensions(qItem); - - const initialRepeatAnswers = useInitialiseRepeatAnswers(qrItem); - - const [repeatAnswers, setRepeatAnswers] = useState(initialRepeatAnswers); - - // Event Handlers - function handleAnswerChange(newQrItem: QuestionnaireResponseItem, index: number) { - const updatedRepeatAnswers = [...repeatAnswers]; - updatedRepeatAnswers[index].answer = newQrItem.answer ? newQrItem.answer[0] : null; - - setRepeatAnswers(updatedRepeatAnswers); - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: updatedRepeatAnswers.flatMap((repeatAnswer) => - repeatAnswer.answer ? [repeatAnswer.answer] : [] - ) - }); - } - - function handleDeleteItem(index: number) { - const updatedRepeatAnswers = [...repeatAnswers]; - - updatedRepeatAnswers.splice(index, 1); - - setRepeatAnswers(updatedRepeatAnswers); - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: updatedRepeatAnswers.flatMap((repeatAnswer) => - repeatAnswer.answer ? [repeatAnswer.answer] : [] - ) - }); - } - - function handleAddItem() { - setRepeatAnswers([ - ...repeatAnswers, - { - nanoId: nanoid(), - answer: null - } - ]); - } - - return ( - - - - {repeatAnswers.map(({ nanoId, answer }, index) => { - const repeatAnswerQrItem = createEmptyQrItem(qItem); - if (answer) { - repeatAnswerQrItem.answer = [answer]; - } - - return ( - - handleDeleteItem(index)} - onQrItemChange={(newQrItem) => handleAnswerChange(newQrItem, index)} - /> - - ); - })} - - - - - - ); -} - -export default RepeatItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/SingleItem/SingleItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/SingleItem/SingleItem.tsx deleted file mode 100644 index 9e2c7048b..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/SingleItem/SingleItem.tsx +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useCallback } from 'react'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import useQuestionnaireStore from '../../../../../../stores/useQuestionnaireStore.ts'; -import SingleItemSwitcher from './SingleItemSwitcher.tsx'; - -interface SingleItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function SingleItem(props: SingleItemProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - const updateEnableWhenItem = useQuestionnaireStore((state) => state.updateEnableWhenItem); - - const handleQrItemChange = useCallback( - (newQrItem: QuestionnaireResponseItem) => { - if (newQrItem.answer) { - updateEnableWhenItem(qItem.linkId, newQrItem.answer); - } - onQrItemChange(newQrItem); - }, - [updateEnableWhenItem, onQrItemChange, qItem.linkId] - ); - - return ( - - ); -} - -export default SingleItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/SingleItem/SingleItemSwitcher.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/SingleItem/SingleItemSwitcher.tsx deleted file mode 100644 index c28b9e448..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/SingleItem/SingleItemSwitcher.tsx +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import QItemChoice from '../QItemChoice/QItemChoice.tsx'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import QItemOpenChoice from '../QItemOpenChoice/QItemOpenChoice.tsx'; -import { Typography } from '@mui/material'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import StringItem from '../StringItem/StringItem.tsx'; -import BooleanItem from '../BooleanItem/BooleanItem.tsx'; -import TimeItem from '../TimeItem/TimeItem.tsx'; -import DateTimeItem from '../DateTimeItem/DateTimeItem.tsx'; -import DateItem from '../DateItem/DateItem.tsx'; -import TextItem from '../TextItem/TextItem.tsx'; -import DisplayItem from '../DisplayItem/DisplayItem.tsx'; -import IntegerItem from '../IntegerItem/IntegerItem.tsx'; -import DecimalItem from '../DecimalItem/DecimalItem.tsx'; -import UrlItem from '../UrlItem/UrlItem.tsx'; - -interface SingleItemSwitcherProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function SingleItemSwitcher(props: SingleItemSwitcherProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - switch (qItem.type) { - case 'string': - return ( - - ); - case 'boolean': - return ( - - ); - case 'time': - return ( - - ); - case 'date': - return ( - - ); - case 'dateTime': - return ( - - ); - case 'text': - return ( - - ); - case 'display': - return ; - case 'integer': - return ( - - ); - case 'decimal': - return ( - - ); - case 'choice': - return ( - - ); - case 'open-choice': - return ( - - ); - case 'url': - return ( - - ); - default: - return ( - - Item type not supported yet. Only R4 datatypes are supported at the moment. - - ); - } -} - -export default SingleItemSwitcher; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/StringItem/StringField.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/StringItem/StringField.tsx deleted file mode 100644 index 86a7f21c7..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/StringItem/StringField.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { PropsWithIsTabledAttribute } from '../../../../types/renderProps.interface.ts'; -import { InputAdornment } from '@mui/material'; -import { StandardTextField } from '../Textfield.styles.tsx'; - -interface StringFieldProps extends PropsWithIsTabledAttribute { - linkId: string; - input: string; - feedback: string; - displayPrompt: string; - displayUnit: string; - entryFormat: string; - readOnly: boolean; - onInputChange: (value: string) => void; -} - -function StringField(props: StringFieldProps) { - const { - linkId, - input, - feedback, - displayPrompt, - displayUnit, - entryFormat, - readOnly, - isTabled, - onInputChange - } = props; - - return ( - onInputChange(event.target.value)} - label={displayPrompt} - placeholder={entryFormat} - disabled={readOnly} - size="small" - InputProps={{ endAdornment: {displayUnit} }} - helperText={feedback} - data-test="q-item-string-field" - /> - ); -} - -export default StringField; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/StringItem/StringItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/StringItem/StringItem.tsx deleted file mode 100644 index 634f2ae6c..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/StringItem/StringItem.tsx +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useCallback, useState } from 'react'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import useValidationError from '../../../../hooks/useValidationError.ts'; -import debounce from 'lodash.debounce'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { DEBOUNCE_DURATION } from '../../../../utils/debounce.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import FieldGrid from '../FieldGrid.tsx'; -import StringField from './StringField.tsx'; - -interface StringItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} -function StringItem(props: StringItemProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Get additional rendering extensions - const { - displayUnit, - displayPrompt, - displayInstructions, - readOnly, - entryFormat, - regexValidation, - maxLength - } = useRenderingExtensions(qItem); - - // Init input value - let valueString = ''; - if (qrItem?.answer && qrItem?.answer[0].valueString) { - valueString = qrItem.answer[0].valueString; - } - const [input, setInput] = useState(valueString); - - // Perform validation checks - const feedback = useValidationError(input, regexValidation, maxLength); - - // Event handlers - function handleChange(newInput: string) { - setInput(newInput); - updateQrItemWithDebounce(newInput); - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - const updateQrItemWithDebounce = useCallback( - debounce((input: string) => { - const emptyQrItem = createEmptyQrItem(qItem); - if (input !== '') { - onQrItemChange({ ...emptyQrItem, answer: [{ valueString: input.trim() }] }); - } else { - onQrItemChange(emptyQrItem); - } - }, DEBOUNCE_DURATION), - [onQrItemChange, qItem] - ); // Dependencies are tested, debounce is causing eslint to not recognise dependencies - - if (isRepeated) { - return ( - - ); - } - return ( - - - - - - ); -} - -export default StringItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/DeleteRowButton.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/DeleteRowButton.tsx deleted file mode 100644 index c83a4f029..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/DeleteRowButton.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { DeleteButtonTableCell } from './Table.styles.tsx'; -import { IconButton, Tooltip } from '@mui/material'; -import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline'; -import type { QuestionnaireResponseItem } from 'fhir/r4'; - -interface DeleteRowButtonProps { - nullableQrItem: QuestionnaireResponseItem | null; - numOfRows: number; - onDeleteItem: () => void; -} - -function DeleteRowButton(props: DeleteRowButtonProps) { - const { nullableQrItem, numOfRows, onDeleteItem } = props; - - const isDisabled = nullableQrItem === null || numOfRows === 1; - return ( - - - - - - - - - - ); -} - -export default DeleteRowButton; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/QItemGroupTable.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/QItemGroupTable.tsx deleted file mode 100644 index 6a147de97..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/QItemGroupTable.tsx +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useMemo, useState } from 'react'; - -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { - Button, - Divider, - Paper, - Stack, - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - Typography -} from '@mui/material'; -import AddIcon from '@mui/icons-material/Add'; -import QItemGroupTableRow from './QItemGroupTableRow.tsx'; -import { HeaderTableCell } from './Table.styles.tsx'; -import { QGroupContainerBox } from '../../../../../../components/Box/Box.styles.tsx'; -import { mapQItemsIndex } from '../../../../utils'; -import type { PropsWithQrRepeatGroupChangeHandler } from '../../../../types/renderProps.interface.ts'; -import useInitialiseGroupTable from '../../../../hooks/useInitialiseGroupTable.ts'; -import { nanoid } from 'nanoid'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import DeleteRowButton from './DeleteRowButton.tsx'; -import LabelWrapper from '../QItemParts/LabelWrapper.tsx'; - -interface Props extends PropsWithQrRepeatGroupChangeHandler { - qItem: QuestionnaireItem; - qrItems: QuestionnaireResponseItem[]; - groupCardElevation: number; -} - -function QItemGroupTable(props: Props) { - const { qItem, qrItems, groupCardElevation, onQrRepeatGroupChange } = props; - - const initialisedGroupTables = useInitialiseGroupTable(qrItems); - - const [tableRows, setTableRows] = useState(initialisedGroupTables); - - // Generate item labels as table headers - const qItems = qItem.item; - const itemLabels: string[] = useMemo( - () => qItems?.map((item) => item.text ?? '') ?? [], - [qItems] - ); - - const qItemsIndexMap = useMemo(() => mapQItemsIndex(qItem), [qItem]); - - // Check if there are columns within the group table - if (!qItems || qItems.length === 0) { - return null; - } - - // Event Handlers - function handleRowChange(newQrRow: QuestionnaireResponseItem, index: number) { - const updatedTableRows = [...tableRows]; - - if (newQrRow.item) { - updatedTableRows[index].qrItem = { - linkId: newQrRow.linkId, - text: newQrRow.text, - item: newQrRow.item - }; - } - - setTableRows(updatedTableRows); - onQrRepeatGroupChange({ - linkId: qItem.linkId, - qrItems: updatedTableRows.flatMap((singleRow) => (singleRow.qrItem ? [singleRow.qrItem] : [])) - }); - } - - function handleDeleteRow(index: number) { - const updatedTableRows = [...tableRows]; - - updatedTableRows.splice(index, 1); - - setTableRows(updatedTableRows); - onQrRepeatGroupChange({ - linkId: qItem.linkId, - qrItems: updatedTableRows.flatMap((singleRow) => (singleRow.qrItem ? [singleRow.qrItem] : [])) - }); - } - - function handleAddRow() { - setTableRows([ - ...tableRows, - { - nanoId: nanoid(), - qrItem: null - } - ]); - } - - return ( - - - - - - - - - - - {itemLabels.map((itemLabel) => ( - {itemLabel} - ))} - - - - - {tableRows.map(({ nanoId, qrItem: nullableQrItem }, index) => { - const answeredQrItem = createEmptyQrItem(qItem); - if (nullableQrItem) { - answeredQrItem.item = nullableQrItem.item; - } - - return ( - - handleRowChange(newQrGroup, index)} - /> - handleDeleteRow(index)} - /> - - ); - })} - -
- - - -
-
-
- ); -} - -export default QItemGroupTable; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/QItemGroupTableRow.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/QItemGroupTableRow.tsx deleted file mode 100644 index 1d7132dab..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/QItemGroupTableRow.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { createQrGroup, updateQrGroup } from '../../../../utils/qrItem.ts'; -import SingleItem from '../SingleItem/SingleItem.tsx'; -import { getQrItemsIndex } from '../../../../utils'; -import { StandardTableCell } from './Table.styles.tsx'; -import type { PropsWithQrItemChangeHandler } from '../../../../types/renderProps.interface.ts'; - -interface Props extends PropsWithQrItemChangeHandler { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; - qItemsIndexMap: Record; -} - -function QItemGroupTableRow(props: Props) { - const { qItem, qrItem, qItemsIndexMap, onQrItemChange } = props; - - const rowItems = qItem.item; - const row = qrItem && qrItem.item ? qrItem : createQrGroup(qItem); - const rowQrItems = row.item; - - if (!rowItems || !rowQrItems) { - return null; - } - - function handleQrRowItemChange(newQrRowItem: QuestionnaireResponseItem) { - const qrRow: QuestionnaireResponseItem = { ...row }; - updateQrGroup(newQrRowItem, null, qrRow, qItemsIndexMap); - onQrItemChange(qrRow); - } - - const qrItemsByIndex = getQrItemsIndex(rowItems, rowQrItems, qItemsIndexMap); - - return ( - <> - {rowItems.map((rowItem, index) => { - const qrItem = qrItemsByIndex[index]; - - if (Array.isArray(qrItem)) { - return null; - } - - return ( - - - - ); - })} - - ); -} - -export default QItemGroupTableRow; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/Table.styles.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/Table.styles.tsx deleted file mode 100644 index dd4b3fdd0..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Tables/Table.styles.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { styled, TableCell } from '@mui/material'; - -export const HeaderTableCell = styled(TableCell)(() => ({ - fontSize: 13, - lineHeight: 'normal' -})); - -export const StandardTableCell = styled(TableCell, { - shouldForwardProp: (prop) => prop !== 'numOfColumns' && prop !== 'isFirst' -})<{ numOfColumns: number; isFirst: boolean }>(({ numOfColumns, isFirst }) => ({ - width: `${100 / numOfColumns}%`, - paddingLeft: isFirst ? 8 : 4, - paddingRight: 4 -})); - -export const DeleteButtonTableCell = styled(TableCell)(() => ({ - paddingLeft: 0, - paddingRight: 4 -})); - -export const GridTextTableCell = styled(TableCell)(({ theme }) => ({ - width: '20%', - paddingLeft: '18px', - paddingRight: '18px', - color: theme.palette.text.secondary -})); - -export const GridAnswerTableCell = styled(TableCell, { - shouldForwardProp: (prop) => prop !== 'numOfColumns' -})<{ numOfColumns: number }>(({ numOfColumns }) => ({ - width: `${80 / numOfColumns}%`, - paddingLeft: 5, - paddingRight: 5 -})); diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TextItem/TextField.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TextItem/TextField.tsx deleted file mode 100644 index a3c2053f9..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TextItem/TextField.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { InputAdornment, TextField as MuiTextField } from '@mui/material'; -import FadingCheckIcon from '../../../../../calculatedExpression/components/FadingCheckIcon.tsx'; - -interface TextFieldProps { - linkId: string; - input: string; - feedback: string; - displayPrompt: string; - displayUnit: string; - entryFormat: string; - readOnly: boolean; - calcExpUpdated: boolean; - onInputChange: (value: string) => void; -} - -function TextField(props: TextFieldProps) { - const { - linkId, - input, - feedback, - displayPrompt, - displayUnit, - entryFormat, - readOnly, - calcExpUpdated, - onInputChange - } = props; - - return ( - onInputChange(event.target.value)} - disabled={readOnly} - label={displayPrompt} - placeholder={entryFormat} - fullWidth - multiline - size="small" - minRows={3} - InputProps={{ - endAdornment: ( - - - {displayUnit} - - ) - }} - helperText={feedback} - data-test="q-item-text-field" - /> - ); -} - -export default TextField; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TextItem/TextItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TextItem/TextItem.tsx deleted file mode 100644 index 5c5f4ab12..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TextItem/TextItem.tsx +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useCallback, useState } from 'react'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import useValidationError from '../../../../hooks/useValidationError.ts'; -import debounce from 'lodash.debounce'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { DEBOUNCE_DURATION } from '../../../../utils/debounce.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import FieldGrid from '../FieldGrid.tsx'; -import TextField from './TextField.tsx'; -import useStringCalculatedExpression from '../../../../../calculatedExpression/hooks/useStringCalculatedExpression.ts'; - -interface TextItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function TextItem(props: TextItemProps) { - const { qItem, qrItem, isRepeated, onQrItemChange } = props; - - // Get additional rendering extensions - const { - displayUnit, - displayPrompt, - displayInstructions, - readOnly, - entryFormat, - regexValidation, - maxLength - } = useRenderingExtensions(qItem); - - // Init input value - let valueText = ''; - if (qrItem?.answer && qrItem?.answer[0].valueString) { - valueText = qrItem.answer[0].valueString; - } - const [input, setInput] = useState(valueText); - - // Perform validation checks - const feedback = useValidationError(input, regexValidation, maxLength); - - // Process calculated expressions - const { calcExpUpdated } = useStringCalculatedExpression({ - qItem: qItem, - inputValue: input, - setInputValue: (value) => { - setInput(value); - }, - onQrItemChange: onQrItemChange - }); - - // Event handlers - function handleInputChange(newInput: string) { - setInput(newInput); - updateQrItemWithDebounce(newInput); - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - const updateQrItemWithDebounce = useCallback( - debounce((input: string) => { - const emptyQrItem = createEmptyQrItem(qItem); - if (input !== '') { - onQrItemChange({ ...emptyQrItem, answer: [{ valueString: input.trim() }] }); - } else { - onQrItemChange(emptyQrItem); - } - }, DEBOUNCE_DURATION), - [onQrItemChange, qItem] - ); // Dependencies are tested, debounce is causing eslint to not recognise dependencies - - if (isRepeated) { - return ( - - ); - } - return ( - - - - - - ); -} - -export default TextItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Textfield.styles.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Textfield.styles.tsx deleted file mode 100644 index debf2c4ef..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Textfield.styles.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { styled, TextField } from '@mui/material'; - -// Always use this accompanied by the TextField prop fullWidth -export const StandardTextField = styled(TextField, { - shouldForwardProp: (prop) => prop !== 'isTabled' -})<{ isTabled: boolean }>(({ isTabled }) => ({ - // Set 280 as the standard width for a field - // Set a theoretical infinite maxWidth if field is within a table to fill the table row - maxWidth: !isTabled ? 280 : 3000, - minWidth: 160 -})); diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TimeItem/TimeField.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TimeItem/TimeField.tsx deleted file mode 100644 index a8300ddb6..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TimeItem/TimeField.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { PropsWithIsTabledAttribute } from '../../../../types/renderProps.interface.ts'; -import type { Dayjs } from 'dayjs'; -import { LocalizationProvider, TimePicker as MuiTimePicker } from '@mui/x-date-pickers'; -import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; - -interface TimeFieldProps extends PropsWithIsTabledAttribute { - value: Dayjs | null; - displayPrompt: string; - entryFormat: string; - readOnly: boolean; - onTimeChange: (newValue: Dayjs | null) => unknown; -} - -function TimeField(props: TimeFieldProps) { - const { value, displayPrompt, entryFormat, readOnly, isTabled, onTimeChange } = props; - - return ( - - - - ); -} - -export default TimeField; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TimeItem/TimeItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TimeItem/TimeItem.tsx deleted file mode 100644 index 083f96673..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/TimeItem/TimeItem.tsx +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import FieldGrid from '../FieldGrid.tsx'; -import TimeField from './TimeField.tsx'; -import type { Dayjs } from 'dayjs'; -import dayjs from 'dayjs'; - -interface TimeItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} - -function TimeItem(props: TimeItemProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Get additional rendering extensions - const { displayPrompt, displayInstructions, readOnly, entryFormat } = - useRenderingExtensions(qItem); - - // Init input value - let timeString: string | null = null; - if (qrItem?.answer && qrItem?.answer[0].valueTime) { - timeString = qrItem.answer[0].valueTime; - } - const timeDayJs = timeString ? dayjs(timeString) : null; - - // Event handlers - function handleTimeChange(newValue: Dayjs | null) { - const emptyQrItem = createEmptyQrItem(qItem); - if (newValue) { - onQrItemChange({ ...emptyQrItem, answer: [{ valueTime: newValue.format() }] }); - } else { - onQrItemChange(emptyQrItem); - } - } - - if (isRepeated) { - return ( - - ); - } - - return ( - - - - - - ); -} - -export default TimeItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Typography.styles.ts b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Typography.styles.ts deleted file mode 100644 index 8c3afc6f3..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/Typography.styles.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { styled, Typography } from '@mui/material'; - -export const QGroupHeadingTypography = styled(Typography, { - shouldForwardProp: (prop) => prop !== 'isTabHeading' -})<{ isTabHeading?: boolean }>(({ isTabHeading }) => ({ - fontSize: isTabHeading ? 16 : 15 -})); diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/UrlItem/UrlField.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/UrlItem/UrlField.tsx deleted file mode 100644 index 05ac749c8..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/UrlItem/UrlField.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { PropsWithIsTabledAttribute } from '../../../../types/renderProps.interface.ts'; -import { InputAdornment } from '@mui/material'; -import { StandardTextField } from '../Textfield.styles.tsx'; - -interface UrlFieldProps extends PropsWithIsTabledAttribute { - linkId: string; - input: string; - feedback: string; - displayPrompt: string; - displayUnit: string; - entryFormat: string; - readOnly: boolean; - onInputChange: (value: string) => void; -} - -function UrlField(props: UrlFieldProps) { - const { - linkId, - input, - feedback, - displayPrompt, - displayUnit, - entryFormat, - readOnly, - isTabled, - onInputChange - } = props; - - return ( - onInputChange(event.target.value)} - label={displayPrompt} - placeholder={entryFormat} - disabled={readOnly} - size="small" - InputProps={{ endAdornment: {displayUnit} }} - helperText={feedback} - data-test="q-item-url-field" - /> - ); -} - -export default UrlField; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/UrlItem/UrlItem.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/UrlItem/UrlItem.tsx deleted file mode 100644 index a03afc940..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QFormComponents/UrlItem/UrlItem.tsx +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useCallback, useState } from 'react'; -import type { - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute, - PropsWithQrItemChangeHandler -} from '../../../../types/renderProps.interface.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useRenderingExtensions from '../../../../hooks/useRenderingExtensions.ts'; -import useValidationError from '../../../../hooks/useValidationError.ts'; -import debounce from 'lodash.debounce'; -import { createEmptyQrItem } from '../../../../utils/qrItem.ts'; -import { DEBOUNCE_DURATION } from '../../../../utils/debounce.ts'; -import { FullWidthFormComponentBox } from '../../../../../../components/Box/Box.styles.tsx'; -import FieldGrid from '../FieldGrid.tsx'; -import UrlField from './UrlField.tsx'; - -interface UrlItemProps - extends PropsWithQrItemChangeHandler, - PropsWithIsRepeatedAttribute, - PropsWithIsTabledAttribute { - qItem: QuestionnaireItem; - qrItem: QuestionnaireResponseItem; -} -function UrlItem(props: UrlItemProps) { - const { qItem, qrItem, isRepeated, isTabled, onQrItemChange } = props; - - // Get additional rendering extensions - const { - displayUnit, - displayPrompt, - displayInstructions, - readOnly, - entryFormat, - regexValidation, - maxLength - } = useRenderingExtensions(qItem); - - // Init input value - let valueUri = ''; - if (qrItem?.answer && qrItem?.answer[0].valueUri) { - valueUri = qrItem.answer[0].valueUri; - } - const [input, setInput] = useState(valueUri); - - // Perform validation checks - const feedback = useValidationError(input, regexValidation, maxLength); - - // Event handlers - function handleChange(newInput: string) { - setInput(newInput); - updateQrItemWithDebounce(newInput); - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - const updateQrItemWithDebounce = useCallback( - debounce((input: string) => { - const emptyQrItem = createEmptyQrItem(qItem); - if (input !== '') { - onQrItemChange({ ...emptyQrItem, answer: [{ valueUri: input }] }); - } else { - onQrItemChange(emptyQrItem); - } - }, DEBOUNCE_DURATION), - [onQrItemChange, qItem] - ); // Dependencies are tested, debounce is causing eslint to not recognise dependencies - - if (isRepeated) { - return ( - - ); - } - return ( - - - - - - ); -} - -export default UrlItem; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/QRSavedSnackbar.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/QRSavedSnackbar.tsx deleted file mode 100644 index f2c8c5531..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/QRSavedSnackbar.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { SyntheticEvent } from 'react'; -import { useEffect, useState } from 'react'; -import { Alert, Snackbar } from '@mui/material'; - -interface Props { - isDisplayed: boolean; -} -function QRSavedSnackbar(props: Props) { - const { isDisplayed } = props; - const [open, setOpen] = useState(isDisplayed); - - useEffect(() => { - if (isDisplayed) { - setOpen(isDisplayed); - } - }, [isDisplayed]); - - // do not display snackbar at first render - useEffect(() => { - setOpen(false); - }, []); - - const handleClose = (_: SyntheticEvent | Event, reason?: string) => { - if (reason === 'clickaway') { - return; - } - - setOpen(false); - }; - - return ( - - - Response saved! - - - ); -} - -export default QRSavedSnackbar; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/CompleteTabButton.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/CompleteTabButton.tsx deleted file mode 100644 index 5c67bf089..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/CompleteTabButton.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { memo } from 'react'; -import { IconButton, Tooltip } from '@mui/material'; -import CheckCircleIcon from '@mui/icons-material/CheckCircle'; -import useQuestionnaireStore from '../../../../../stores/useQuestionnaireStore.ts'; - -interface CompleteTabButtonProps { - tabLinkId: string; - tabIsMarkedAsComplete: boolean; -} - -const CompleteTabButton = memo(function CompleteTabButton(props: CompleteTabButtonProps) { - const { tabLinkId, tabIsMarkedAsComplete } = props; - - const markTabAsComplete = useQuestionnaireStore((state) => state.markTabAsComplete); - - return ( - - markTabAsComplete(tabLinkId)}> - - - - ); -}); - -export default CompleteTabButton; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/FormBodySingleTab.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/FormBodySingleTab.tsx deleted file mode 100644 index fa0af0b30..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/FormBodySingleTab.tsx +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { memo } from 'react'; -import { Box, ListItemButton, ListItemText, Typography } from '@mui/material'; -import useQuestionnaireStore from '../../../../../stores/useQuestionnaireStore.ts'; -import type { QuestionnaireItem } from 'fhir/r4'; -import { getContextDisplays } from '../../../utils/tabs.ts'; -import ContextDisplayItem from '../QFormComponents/QItemParts/ContextDisplayItem.tsx'; - -interface FormBodySingleTabProps { - qItem: QuestionnaireItem; - selected: boolean; - tabLabel: string; - listIndex: number; -} - -const FormBodySingleTab = memo(function FormBodySingleTab(props: FormBodySingleTabProps) { - const { qItem, selected, tabLabel, listIndex } = props; - - const switchTab = useQuestionnaireStore((state) => state.switchTab); - - const contextDisplayItems = getContextDisplays(qItem); - - function handleTabClick() { - switchTab(listIndex); - window.scrollTo(0, 0); - } - - return ( - <> - - - {tabLabel} - - {contextDisplayItems.map((item) => { - return ; - })} - - - } - /> - - - ); -}); - -export default FormBodySingleTab; diff --git a/apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/FormBodyTabList.tsx b/apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/FormBodyTabList.tsx deleted file mode 100644 index 962062cf5..000000000 --- a/apps/smart-forms-app/src/features/renderer/components/FormPage/Tabs/FormBodyTabList.tsx +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { memo } from 'react'; -import { Box, Card, Collapse } from '@mui/material'; -import { PrimarySelectableList } from '../../../../../components/List/Lists.styles.tsx'; -import { TransitionGroup } from 'react-transition-group'; -import { isHidden } from '../../../utils/qItem.ts'; -import { getShortText } from '../../../utils/itemControl.ts'; -import type { QuestionnaireItem } from 'fhir/r4'; -import FormBodySingleTab from './FormBodySingleTab.tsx'; -import type { Tabs } from '../../../types/tab.interface.ts'; -import useQuestionnaireStore from '../../../../../stores/useQuestionnaireStore.ts'; - -interface FormBodyTabListProps { - qFormItems: QuestionnaireItem[]; - currentTabIndex: number; - tabs: Tabs; -} - -const FormBodyTabList = memo(function FormBodyTabList(props: FormBodyTabListProps) { - const { qFormItems, currentTabIndex, tabs } = props; - - const enableWhenIsActivated = useQuestionnaireStore((state) => state.enableWhenIsActivated); - const enableWhenItems = useQuestionnaireStore((state) => state.enableWhenItems); - const enableWhenExpressions = useQuestionnaireStore((state) => state.enableWhenExpressions); - - return ( - - - - - {qFormItems.map((qItem, i) => { - const isTab = !!tabs[qItem.linkId]; - - if ( - !isTab || - isHidden({ - questionnaireItem: qItem, - enableWhenIsActivated, - enableWhenItems, - enableWhenExpressions - }) - ) { - return null; - } - - const tabIsSelected = currentTabIndex.toString() === i.toString(); - const tabLabel = getShortText(qItem) ?? qItem.text ?? ''; - - return ( - - - - ); - })} - - - - - ); -}); - -export default FormBodyTabList; diff --git a/apps/smart-forms-app/src/stories/Component/DateItem.stories.ts b/apps/smart-forms-app/src/stories/Component/DateItem.stories.ts deleted file mode 100644 index 5d7d30b15..000000000 --- a/apps/smart-forms-app/src/stories/Component/DateItem.stories.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Meta, StoryObj } from '@storybook/react'; - -import DateItem from '../../features/renderer/components/FormPage/QFormComponents/DateItem/DateItem.tsx'; - -// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export -const meta = { - title: 'Component/DateItem', - component: DateItem, - argTypes: { - onQrItemChange: { action: 'change' } - }, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs - tags: ['autodocs'] -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args -export const ItemWithoutAnswer: Story = { - args: { - qItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Name', - type: 'string', - repeats: false - }, - qrItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Name' - }, - isRepeated: false, - isTabled: false - } -}; - -export const ItemWithAnswer: Story = { - args: { - qItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Name', - type: 'string', - repeats: false - }, - qrItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Date', - answer: [ - { - valueDate: '2023-08-01' - } - ] - }, - isRepeated: false, - isTabled: false - } -}; diff --git a/apps/smart-forms-app/src/stories/Component/SingleItemSwitcher.stories.ts b/apps/smart-forms-app/src/stories/Component/SingleItemSwitcher.stories.ts deleted file mode 100644 index 1c12a23f6..000000000 --- a/apps/smart-forms-app/src/stories/Component/SingleItemSwitcher.stories.ts +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Meta, StoryObj } from '@storybook/react'; -import SingleItemSwitcher from '../../features/renderer/components/FormPage/QFormComponents/SingleItem/SingleItemSwitcher.tsx'; - -// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export -const meta = { - title: 'Component/SingleItemSwitcher', - component: SingleItemSwitcher, - argTypes: { - onQrItemChange: { action: 'change' } - }, - - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs - tags: ['autodocs'] -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args -export const TextItemWithAnswer: Story = { - args: { - qItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Name', - type: 'string', - repeats: false - }, - qrItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Name', - answer: [ - { - valueString: 'John' - } - ] - }, - isRepeated: false, - isTabled: false - } -}; - -export const IntegerItemWithAnswer: Story = { - args: { - qItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Age', - type: 'integer', - repeats: false - }, - qrItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Age', - answer: [ - { - valueInteger: 1 - } - ] - }, - isRepeated: false, - isTabled: false - } -}; - -export const ChoiceRadioItemWithAnswer: Story = { - args: { - qItem: { - linkId: 'c1cf9c00-15ef-4b98-bab0-20a5f01b4932', - text: 'Cervical screening status', - type: 'choice', - repeats: false, - answerOption: [ - { - valueString: 'Up to date' - }, - { - valueString: 'Discussed today' - }, - { - valueString: 'Not required' - }, - { - valueString: 'Declined' - }, - { - valueString: 'Next due' - } - ] - }, - qrItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Name', - answer: [ - { - valueString: 'Up to date' - } - ] - }, - isRepeated: false, - isTabled: false - } -}; diff --git a/apps/smart-forms-app/src/stories/Component/TextItem.stories.ts b/apps/smart-forms-app/src/stories/Component/TextItem.stories.ts deleted file mode 100644 index 80853d84a..000000000 --- a/apps/smart-forms-app/src/stories/Component/TextItem.stories.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Meta, StoryObj } from '@storybook/react'; - -import TextItem from '../../features/renderer/components/FormPage/QFormComponents/TextItem/TextItem.tsx'; - -// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export -const meta = { - title: 'Component/TextItem', - component: TextItem, - argTypes: { - onQrItemChange: { action: 'change' } - }, - // This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs - tags: ['autodocs'] -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args -export const ItemWithoutAnswer: Story = { - args: { - qItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Name', - type: 'string', - repeats: false - }, - qrItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Name' - }, - isRepeated: false - } -}; - -export const ItemWithAnswer: Story = { - args: { - qItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Name', - type: 'string', - repeats: false - }, - qrItem: { - linkId: '17596726-34cf-4133-9960-7081e1d63558', - text: 'Name', - answer: [ - { - valueString: 'John' - } - ] - }, - isRepeated: false - } -}; From 08afbbc595b41f03e7a0ed073baff5b26b885653 Mon Sep 17 00:00:00 2001 From: Sean Fong Date: Fri, 1 Sep 2023 12:31:13 +0930 Subject: [PATCH 3/4] More clean up --- .../components/FadingCheckIcon.tsx | 35 --- .../hooks/useDecimalCalculatedExpression.ts | 80 ----- .../hooks/useIntegerCalculatedExpression.ts | 72 ----- .../hooks/useStringCalculatedExpression.ts | 71 ----- .../prepopulate/types/populate.interface.ts | 12 +- .../prepopulate/utils/getExtensions.ts | 57 +++- .../preprocess/types/questionnaireModel.ts | 3 +- .../extractLaunchContext.ts | 2 +- .../extractOtherExtensions.ts | 2 +- .../extractVariables.ts | 2 +- .../preprocessQuestionnaire.ts | 3 +- .../resolveValueSets.ts | 2 +- .../renderer/contexts/FormTabsContext.tsx | 34 --- .../renderer/contexts/RendererContext.ts | 38 --- .../src/features/renderer/hooks/useHidden.ts | 40 --- .../renderer/hooks/useInitialiseGroupTable.ts | 42 --- .../hooks/useInitialiseRepeatAnswers.ts | 42 --- .../hooks/useInitialiseRepeatGroups.ts | 42 --- .../renderer/hooks/useIntersectionObserver.ts | 55 ---- .../renderer/hooks/useRenderingExtensions.ts | 52 ---- .../hooks/useTerminologyServerQuery.ts | 98 ------- .../renderer/hooks/useValidationError.ts | 48 --- .../renderer/hooks/useValueSetCodings.ts | 148 ---------- .../questionnaireProvider.interfaces.ts | 28 -- .../src/providers/questionnaireProvider.ts | 277 ------------------ ...uestionnaireResponseProvider.interfaces.ts | 0 .../questionnaireResponseProvider.ts | 35 --- .../typePredicates/isLaunchContext.ts | 53 ---- .../providers/typePredicates/isSourceQuery.ts | 27 -- .../typePredicates/isXFhirQueryVariable.ts | 30 -- .../src/stores/useConfigStore.ts | 36 --- .../stores/useQuestionnaireResponseStore.ts | 61 ---- .../src/stores/useQuestionnaireStore.ts | 218 -------------- .../src/utils/calculatedExpressions.ts | 2 +- .../src/utils/enableWhenExpression.ts | 2 +- .../typePredicates.ts => utils/qrItem.ts} | 6 + apps/smart-forms-app/src/utils/valueSet.ts | 6 +- 37 files changed, 83 insertions(+), 1678 deletions(-) delete mode 100644 apps/smart-forms-app/src/features/calculatedExpression/components/FadingCheckIcon.tsx delete mode 100644 apps/smart-forms-app/src/features/calculatedExpression/hooks/useDecimalCalculatedExpression.ts delete mode 100644 apps/smart-forms-app/src/features/calculatedExpression/hooks/useIntegerCalculatedExpression.ts delete mode 100644 apps/smart-forms-app/src/features/calculatedExpression/hooks/useStringCalculatedExpression.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/contexts/FormTabsContext.tsx delete mode 100644 apps/smart-forms-app/src/features/renderer/contexts/RendererContext.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/hooks/useHidden.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/hooks/useInitialiseGroupTable.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/hooks/useInitialiseRepeatAnswers.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/hooks/useInitialiseRepeatGroups.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/hooks/useIntersectionObserver.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/hooks/useRenderingExtensions.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/hooks/useTerminologyServerQuery.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/hooks/useValidationError.ts delete mode 100644 apps/smart-forms-app/src/features/renderer/hooks/useValueSetCodings.ts delete mode 100644 apps/smart-forms-app/src/providers/questionnaireProvider.interfaces.ts delete mode 100644 apps/smart-forms-app/src/providers/questionnaireProvider.ts delete mode 100644 apps/smart-forms-app/src/providers/questionnaireResponseProvider.interfaces.ts delete mode 100644 apps/smart-forms-app/src/providers/questionnaireResponseProvider.ts delete mode 100644 apps/smart-forms-app/src/providers/typePredicates/isLaunchContext.ts delete mode 100644 apps/smart-forms-app/src/providers/typePredicates/isSourceQuery.ts delete mode 100644 apps/smart-forms-app/src/providers/typePredicates/isXFhirQueryVariable.ts delete mode 100644 apps/smart-forms-app/src/stores/useConfigStore.ts delete mode 100644 apps/smart-forms-app/src/stores/useQuestionnaireResponseStore.ts delete mode 100644 apps/smart-forms-app/src/stores/useQuestionnaireStore.ts rename apps/smart-forms-app/src/{features/prepopulate/typePredicates/typePredicates.ts => utils/qrItem.ts} (79%) diff --git a/apps/smart-forms-app/src/features/calculatedExpression/components/FadingCheckIcon.tsx b/apps/smart-forms-app/src/features/calculatedExpression/components/FadingCheckIcon.tsx deleted file mode 100644 index 8f03d5849..000000000 --- a/apps/smart-forms-app/src/features/calculatedExpression/components/FadingCheckIcon.tsx +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Fade } from '@mui/material'; -import CheckIcon from '@mui/icons-material/Check'; - -interface FadingCheckIconProps { - fadeIn: boolean; -} - -function FadingCheckIcon(props: FadingCheckIconProps) { - const { fadeIn } = props; - - return ( - - - - ); -} - -export default FadingCheckIcon; diff --git a/apps/smart-forms-app/src/features/calculatedExpression/hooks/useDecimalCalculatedExpression.ts b/apps/smart-forms-app/src/features/calculatedExpression/hooks/useDecimalCalculatedExpression.ts deleted file mode 100644 index e0d145778..000000000 --- a/apps/smart-forms-app/src/features/calculatedExpression/hooks/useDecimalCalculatedExpression.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useEffect, useState } from 'react'; -import { createEmptyQrItemWithUnit } from '../../renderer/utils/qrItem.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useQuestionnaireStore from '../../../stores/useQuestionnaireStore.ts'; - -interface UseDecimalCalculatedExpression { - calcExpUpdated: boolean; -} - -interface useDecimalCalculatedExpressionProps { - qItem: QuestionnaireItem; - inputValue: string; - displayUnit: string; - precision: number | null; - setInputValue: (value: string) => void; - onQrItemChange: (qrItem: QuestionnaireResponseItem) => void; -} - -function useDecimalCalculatedExpression( - props: useDecimalCalculatedExpressionProps -): UseDecimalCalculatedExpression { - const { qItem, inputValue, displayUnit, precision, setInputValue, onQrItemChange } = props; - - const calculatedExpressions = useQuestionnaireStore((state) => state.calculatedExpressions); - - const [calcExpUpdated, setCalcExpUpdated] = useState(false); - - useEffect( - () => { - const calcExpression = calculatedExpressions[qItem.linkId]; - - // only update if calculated value is different from current value - if (calcExpression?.value !== inputValue && typeof calcExpression?.value === 'number') { - const value = precision - ? parseFloat(calcExpression.value.toFixed(precision)) - : calcExpression.value; - - // only update if calculated value is different from current value - if (value !== parseFloat(inputValue)) { - // update ui to show calculated value changes - setCalcExpUpdated(true); - setTimeout(() => { - setCalcExpUpdated(false); - }, 500); - - // update questionnaireResponse - setInputValue(precision ? value.toFixed(precision) : value.toString()); - onQrItemChange({ - ...createEmptyQrItemWithUnit(qItem, displayUnit), - answer: [{ valueDecimal: value }] - }); - } - } - }, - // Only trigger this effect if calculatedExpression of item changes - // eslint-disable-next-line react-hooks/exhaustive-deps - [calculatedExpressions] - ); - - return { calcExpUpdated: calcExpUpdated }; -} - -export default useDecimalCalculatedExpression; diff --git a/apps/smart-forms-app/src/features/calculatedExpression/hooks/useIntegerCalculatedExpression.ts b/apps/smart-forms-app/src/features/calculatedExpression/hooks/useIntegerCalculatedExpression.ts deleted file mode 100644 index 8cab16c28..000000000 --- a/apps/smart-forms-app/src/features/calculatedExpression/hooks/useIntegerCalculatedExpression.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useEffect, useState } from 'react'; -import { createEmptyQrItemWithUnit } from '../../renderer/utils/qrItem.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useQuestionnaireStore from '../../../stores/useQuestionnaireStore.ts'; - -interface UseIntegerCalculatedExpression { - calcExpUpdated: boolean; -} - -interface useIntegerCalculatedExpressionProps { - qItem: QuestionnaireItem; - inputValue: number; - displayUnit: string; - setInputValue: (value: number) => void; - onQrItemChange: (qrItem: QuestionnaireResponseItem) => void; -} - -function useIntegerCalculatedExpression( - props: useIntegerCalculatedExpressionProps -): UseIntegerCalculatedExpression { - const { qItem, inputValue, displayUnit, setInputValue, onQrItemChange } = props; - - const calculatedExpressions = useQuestionnaireStore((state) => state.calculatedExpressions); - - const [calcExpUpdated, setCalcExpUpdated] = useState(false); - - useEffect( - () => { - const calcExpression = calculatedExpressions[qItem.linkId]; - - // only update if calculated value is different from current value - if (calcExpression?.value !== inputValue && typeof calcExpression?.value === 'number') { - // update ui to show calculated value changes - setCalcExpUpdated(true); - setTimeout(() => { - setCalcExpUpdated(false); - }, 500); - - // update questionnaireResponse - setInputValue(calcExpression.value); - onQrItemChange({ - ...createEmptyQrItemWithUnit(qItem, displayUnit), - answer: [{ valueInteger: calcExpression.value }] - }); - } - }, - // Only trigger this effect if calculatedExpression of item changes - // eslint-disable-next-line react-hooks/exhaustive-deps - [calculatedExpressions] - ); - - return { calcExpUpdated: calcExpUpdated }; -} - -export default useIntegerCalculatedExpression; diff --git a/apps/smart-forms-app/src/features/calculatedExpression/hooks/useStringCalculatedExpression.ts b/apps/smart-forms-app/src/features/calculatedExpression/hooks/useStringCalculatedExpression.ts deleted file mode 100644 index 2d8c8eb4d..000000000 --- a/apps/smart-forms-app/src/features/calculatedExpression/hooks/useStringCalculatedExpression.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useEffect, useState } from 'react'; -import { createEmptyQrItem } from '../../renderer/utils/qrItem.ts'; -import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import useQuestionnaireStore from '../../../stores/useQuestionnaireStore.ts'; - -interface UseStringCalculatedExpression { - calcExpUpdated: boolean; -} - -interface useStringCalculatedExpressionProps { - qItem: QuestionnaireItem; - inputValue: string; - setInputValue: (value: string) => void; - onQrItemChange: (qrItem: QuestionnaireResponseItem) => void; -} - -function useStringCalculatedExpression( - props: useStringCalculatedExpressionProps -): UseStringCalculatedExpression { - const { qItem, inputValue, setInputValue, onQrItemChange } = props; - - const calculatedExpressions = useQuestionnaireStore((state) => state.calculatedExpressions); - - const [calcExpUpdated, setCalcExpUpdated] = useState(false); - - useEffect( - () => { - const calcExpression = calculatedExpressions[qItem.linkId]; - - // only update if calculated value is different from current value - if (calcExpression?.value !== inputValue && typeof calcExpression?.value === 'string') { - // update ui to show calculated value changes - setCalcExpUpdated(true); - setTimeout(() => { - setCalcExpUpdated(false); - }, 500); - - // update questionnaireResponse - setInputValue(calcExpression.value); - onQrItemChange({ - ...createEmptyQrItem(qItem), - answer: [{ valueString: calcExpression.value }] - }); - } - }, - // Only trigger this effect if calculatedExpression of item changes - // eslint-disable-next-line react-hooks/exhaustive-deps - [calculatedExpressions] - ); - - return { calcExpUpdated: calcExpUpdated }; -} - -export default useStringCalculatedExpression; diff --git a/apps/smart-forms-app/src/features/prepopulate/types/populate.interface.ts b/apps/smart-forms-app/src/features/prepopulate/types/populate.interface.ts index 892762ccd..c1563f2b0 100644 --- a/apps/smart-forms-app/src/features/prepopulate/types/populate.interface.ts +++ b/apps/smart-forms-app/src/features/prepopulate/types/populate.interface.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import type { Coding, Expression, Extension, Reference } from 'fhir/r4'; +import type { Coding, Expression, Extension, FhirResource, Reference } from 'fhir/r4'; export interface LaunchContext extends Extension { url: 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-launchContext'; @@ -216,3 +216,13 @@ interface XFhirQueryVariableExpression extends Expression { language: 'application/x-fhir-query'; expression: string; } + +export interface VariableXFhirQuery { + valueExpression: Expression; + result?: FhirResource; +} + +export interface Variables { + fhirPathVariables: Record; + xFhirQueryVariables: Record; +} diff --git a/apps/smart-forms-app/src/features/prepopulate/utils/getExtensions.ts b/apps/smart-forms-app/src/features/prepopulate/utils/getExtensions.ts index 54d5943be..ed0b01bcb 100644 --- a/apps/smart-forms-app/src/features/prepopulate/utils/getExtensions.ts +++ b/apps/smart-forms-app/src/features/prepopulate/utils/getExtensions.ts @@ -16,14 +16,46 @@ */ import type { Questionnaire } from 'fhir/r4'; +import type { Extension } from 'fhir/r4'; import type { LaunchContext, QuestionnaireLevelXFhirQueryVariable, SourceQuery } from '../types/populate.interface.ts'; -import { isLaunchContext } from '../../../providers/typePredicates/isLaunchContext.ts'; -import { isSourceQuery } from '../../../providers/typePredicates/isSourceQuery.ts'; -import { isXFhirQueryVariable } from '../../../providers/typePredicates/isXFhirQueryVariable.ts'; + +export function isLaunchContext(extension: Extension): extension is LaunchContext { + const hasLaunchContextName = + extension.url === + 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-launchContext' && + !!extension.extension?.find( + (ext) => + ext.url === 'name' && + (ext.valueId || + (ext.valueCoding && + (ext.valueCoding.code === 'patient' || + ext.valueCoding.code === 'encounter' || + ext.valueCoding.code === 'location' || + ext.valueCoding.code === 'user' || + ext.valueCoding.code === 'study' || + ext.valueCoding.code === 'sourceQueries'))) + ); + + const hasLaunchContextType = !!extension.extension?.find( + (ext) => + ext.url === 'type' && + ext.valueCode && + (ext.valueCode === 'Patient' || + ext.valueCode === 'Practitioner' || + ext.valueCode === 'Encounter') + ); + + return ( + extension.url === + 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-launchContext' && + hasLaunchContextName && + hasLaunchContextType + ); +} export function getLaunchContexts(questionnaire: Questionnaire): LaunchContext[] { if (questionnaire.extension && questionnaire.extension.length > 0) { @@ -35,6 +67,14 @@ export function getLaunchContexts(questionnaire: Questionnaire): LaunchContext[] return []; } +export function isSourceQuery(extension: Extension): extension is SourceQuery { + return ( + extension.url === + 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-sourceQueries' && + !!extension.valueReference + ); +} + // get source query references export function getSourceQueries(questionnaire: Questionnaire): SourceQuery[] { if (questionnaire.extension && questionnaire.extension.length > 0) { @@ -44,6 +84,17 @@ export function getSourceQueries(questionnaire: Questionnaire): SourceQuery[] { return []; } +export function isXFhirQueryVariable( + extension: Extension +): extension is QuestionnaireLevelXFhirQueryVariable { + return ( + extension.url === 'http://hl7.org/fhir/StructureDefinition/variable' && + !!extension.valueExpression?.name && + extension.valueExpression?.language === 'application/x-fhir-query' && + !!extension.valueExpression?.expression + ); +} + /** * Filter x-fhir-query variables from questionnaire's extensions needed for population * diff --git a/apps/smart-forms-app/src/features/preprocess/types/questionnaireModel.ts b/apps/smart-forms-app/src/features/preprocess/types/questionnaireModel.ts index 004bcf02e..d41cb91c7 100644 --- a/apps/smart-forms-app/src/features/preprocess/types/questionnaireModel.ts +++ b/apps/smart-forms-app/src/features/preprocess/types/questionnaireModel.ts @@ -1,7 +1,6 @@ import type { Coding } from 'fhir/r4'; import type { Tabs } from '../../renderer/types/tab.interface.ts'; -import type { Variables } from '../../../providers/questionnaireProvider.interfaces.ts'; -import type { LaunchContext } from '../../prepopulate/types/populate.interface.ts'; +import type { LaunchContext, Variables } from '../../prepopulate/types/populate.interface.ts'; import type { CalculatedExpression } from '../../calculatedExpression/types/calculatedExpression.interface.ts'; import type { EnableWhenExpression, diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractLaunchContext.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractLaunchContext.ts index fd29cff1e..ba54a1255 100644 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractLaunchContext.ts +++ b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractLaunchContext.ts @@ -1,6 +1,6 @@ import type { Questionnaire } from 'fhir/r4'; import type { LaunchContext } from '../../../prepopulate/types/populate.interface.ts'; -import { isLaunchContext } from '../../../../providers/typePredicates/isLaunchContext.ts'; +import { isLaunchContext } from '../../../prepopulate/utils/getExtensions.ts'; export function extractLaunchContexts(questionnaire: Questionnaire): Record { if (!questionnaire.extension || questionnaire.extension.length === 0) { diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractOtherExtensions.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractOtherExtensions.ts index b8c0bb313..0d7b4e6cc 100644 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractOtherExtensions.ts +++ b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractOtherExtensions.ts @@ -26,8 +26,8 @@ import type { AnswerExpression } from '../../../../types/answerExpression.interf import type { ValueSetPromise } from '../../../../types/valueSet.interface.ts'; import { getAnswerExpression } from '../../../renderer/utils/itemControl.ts'; import { getTerminologyServerUrl, getValueSetPromise } from '../../../../utils/valueSet.ts'; -import type { Variables } from '../../../../providers/questionnaireProvider.interfaces.ts'; import { getFhirPathVariables, getXFhirQueryVariables } from './extractVariables.ts'; +import type { Variables } from '../../../prepopulate/types/populate.interface.ts'; interface ReturnParamsRecursive { variables: Variables; diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractVariables.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractVariables.ts index b65a69ac3..cf34a015f 100644 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractVariables.ts +++ b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractVariables.ts @@ -16,7 +16,7 @@ */ import type { Expression, Extension, Questionnaire } from 'fhir/r4'; -import type { Variables } from '../../../../providers/questionnaireProvider.interfaces.ts'; +import type { Variables } from '../../../prepopulate/types/populate.interface.ts'; export function extractQuestionnaireLevelVariables(questionnaire: Questionnaire): Variables { const variables: Variables = { fhirPathVariables: {}, xFhirQueryVariables: {} }; diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/preprocessQuestionnaire.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/preprocessQuestionnaire.ts index 410e9e152..eed182f4c 100644 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/preprocessQuestionnaire.ts +++ b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/preprocessQuestionnaire.ts @@ -17,13 +17,12 @@ import type { Questionnaire } from 'fhir/r4'; import type { Tabs } from '../../../renderer/types/tab.interface.ts'; -import type { LaunchContext } from '../../../prepopulate/types/populate.interface.ts'; +import type { LaunchContext, Variables } from '../../../prepopulate/types/populate.interface.ts'; import type { QuestionnaireModel } from '../../types/questionnaireModel.ts'; import { extractLaunchContexts } from './extractLaunchContext.ts'; import { extractQuestionnaireLevelVariables } from './extractVariables.ts'; import { extractTabs } from './extractTabs.ts'; import { extractContainedValueSets } from './extractContainedValueSets.ts'; -import type { Variables } from '../../../../providers/questionnaireProvider.interfaces.ts'; import { extractOtherExtensions } from './extractOtherExtensions.ts'; import { resolveValueSets } from './resolveValueSets.ts'; diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/resolveValueSets.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/resolveValueSets.ts index a2b2210e1..e806aa7a0 100644 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/resolveValueSets.ts +++ b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/resolveValueSets.ts @@ -22,8 +22,8 @@ import { getValueSetPromise, resolvePromises } from '../../../../utils/valueSet.ts'; -import type { Variables } from '../../../../providers/questionnaireProvider.interfaces.ts'; import type { ValueSetPromise } from '../../../../types/valueSet.interface.ts'; +import type { Variables } from '../../../prepopulate/types/populate.interface.ts'; export async function resolveValueSets( variables: Variables, diff --git a/apps/smart-forms-app/src/features/renderer/contexts/FormTabsContext.tsx b/apps/smart-forms-app/src/features/renderer/contexts/FormTabsContext.tsx deleted file mode 100644 index df614052f..000000000 --- a/apps/smart-forms-app/src/features/renderer/contexts/FormTabsContext.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { createContext } from 'react'; -import type { Tabs } from '../types/tab.interface.ts'; - -export type FormTabContextType = { - tabs: Tabs; - currentTab: number; - formHasTabs: () => boolean; - switchTab: (updatedIndex: number) => unknown; - markTabAsComplete: (linkId: string) => unknown; -}; - -export const FormTabsContext = createContext({ - tabs: {}, - currentTab: 0, - formHasTabs: () => false, - switchTab: () => void 0, - markTabAsComplete: () => void 0 -}); diff --git a/apps/smart-forms-app/src/features/renderer/contexts/RendererContext.ts b/apps/smart-forms-app/src/features/renderer/contexts/RendererContext.ts deleted file mode 100644 index 5079ca1e3..000000000 --- a/apps/smart-forms-app/src/features/renderer/contexts/RendererContext.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Renderer } from '../types/renderer.interface.ts'; -import { createContext } from 'react'; -import type { QuestionnaireResponse } from 'fhir/r4'; - -type RendererContextType = { - renderer: Renderer; - setRenderer: (updatedRenderer: Renderer) => unknown; -}; - -const emptyResponse: QuestionnaireResponse = { - resourceType: 'QuestionnaireResponse', - status: 'in-progress' -}; - -export const RendererContext = createContext({ - renderer: { - response: emptyResponse, - hasChanges: false - }, - setRenderer: () => void 0 -}); diff --git a/apps/smart-forms-app/src/features/renderer/hooks/useHidden.ts b/apps/smart-forms-app/src/features/renderer/hooks/useHidden.ts deleted file mode 100644 index fd6f9ae78..000000000 --- a/apps/smart-forms-app/src/features/renderer/hooks/useHidden.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { QuestionnaireItem } from 'fhir/r4'; -import { hasHiddenExtension } from '../utils/itemControl.ts'; -import useQuestionnaireStore from '../../../stores/useQuestionnaireStore.ts'; -import { isHiddenByEnableWhens } from '../utils/qItem.ts'; - -function useHidden(qItem: QuestionnaireItem): boolean { - const enableWhenIsActivated = useQuestionnaireStore((state) => state.enableWhenIsActivated); - const enableWhenItems = useQuestionnaireStore((state) => state.enableWhenItems); - const enableWhenExpressions = useQuestionnaireStore((state) => state.enableWhenExpressions); - - if (hasHiddenExtension(qItem)) { - return true; - } - - return isHiddenByEnableWhens({ - linkId: qItem.linkId, - enableWhenIsActivated, - enableWhenItems, - enableWhenExpressions - }); -} - -export default useHidden; diff --git a/apps/smart-forms-app/src/features/renderer/hooks/useInitialiseGroupTable.ts b/apps/smart-forms-app/src/features/renderer/hooks/useInitialiseGroupTable.ts deleted file mode 100644 index f2ff914bf..000000000 --- a/apps/smart-forms-app/src/features/renderer/hooks/useInitialiseGroupTable.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { QuestionnaireResponseItem } from 'fhir/r4'; -import { nanoid } from 'nanoid'; -import type { GroupTableRow } from '../types/groupTable.interface.ts'; - -function useInitialiseGroupTable(qrItems: QuestionnaireResponseItem[]): GroupTableRow[] { - let initialGroupTableRows: GroupTableRow[] = [ - { - nanoId: nanoid(), - qrItem: null - } - ]; - - if (qrItems.length > 0) { - initialGroupTableRows = qrItems.map((qrItem) => { - return { - nanoId: nanoid(), - qrItem - }; - }); - } - - return initialGroupTableRows; -} - -export default useInitialiseGroupTable; diff --git a/apps/smart-forms-app/src/features/renderer/hooks/useInitialiseRepeatAnswers.ts b/apps/smart-forms-app/src/features/renderer/hooks/useInitialiseRepeatAnswers.ts deleted file mode 100644 index 6cb05f16e..000000000 --- a/apps/smart-forms-app/src/features/renderer/hooks/useInitialiseRepeatAnswers.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { QuestionnaireResponseItem } from 'fhir/r4'; -import type { RepeatAnswer } from '../types/repeatItem.interface.ts'; -import { nanoid } from 'nanoid'; - -function useInitialiseRepeatAnswers(qrItem: QuestionnaireResponseItem): RepeatAnswer[] { - let initialRepeatAnswers: RepeatAnswer[] = [ - { - nanoId: nanoid(), - answer: null - } - ]; - - if (qrItem?.answer) { - initialRepeatAnswers = qrItem.answer.map((answer) => { - return { - nanoId: nanoid(), - answer - }; - }); - } - - return initialRepeatAnswers; -} - -export default useInitialiseRepeatAnswers; diff --git a/apps/smart-forms-app/src/features/renderer/hooks/useInitialiseRepeatGroups.ts b/apps/smart-forms-app/src/features/renderer/hooks/useInitialiseRepeatGroups.ts deleted file mode 100644 index 4f1018a00..000000000 --- a/apps/smart-forms-app/src/features/renderer/hooks/useInitialiseRepeatGroups.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { QuestionnaireResponseItem } from 'fhir/r4'; -import { nanoid } from 'nanoid'; -import type { RepeatGroupSingle } from '../types/repeatGroup.interface.ts'; - -function useInitialiseRepeatGroups(qrItems: QuestionnaireResponseItem[]): RepeatGroupSingle[] { - let initialRepeatGroupAnswers: RepeatGroupSingle[] = [ - { - nanoId: nanoid(), - qrItem: null - } - ]; - - if (qrItems.length > 0) { - initialRepeatGroupAnswers = qrItems.map((qrItem) => { - return { - nanoId: nanoid(), - qrItem - }; - }); - } - - return initialRepeatGroupAnswers; -} - -export default useInitialiseRepeatGroups; diff --git a/apps/smart-forms-app/src/features/renderer/hooks/useIntersectionObserver.ts b/apps/smart-forms-app/src/features/renderer/hooks/useIntersectionObserver.ts deleted file mode 100644 index e48f526e1..000000000 --- a/apps/smart-forms-app/src/features/renderer/hooks/useIntersectionObserver.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { RefObject } from 'react'; -import { useEffect, useState } from 'react'; - -interface Args extends IntersectionObserverInit { - freezeOnceVisible?: boolean; -} - -// Lifted from https://usehooks-ts.com/react-hook/use-intersection-observer -export function useIntersectionObserver( - elementRef: RefObject, - { threshold = 0, root = null, rootMargin = '0%', freezeOnceVisible = false }: Args -): IntersectionObserverEntry | undefined { - const [entry, setEntry] = useState(); - - const frozen = entry?.isIntersecting && freezeOnceVisible; - - const updateEntry = ([entry]: IntersectionObserverEntry[]): void => { - setEntry(entry); - }; - - useEffect(() => { - const node = elementRef?.current; // DOM Ref - const hasIOSupport = !!window.IntersectionObserver; - - if (!hasIOSupport || frozen || !node) return; - - const observerParams = { threshold, root, rootMargin }; - const observer = new IntersectionObserver(updateEntry, observerParams); - - observer.observe(node); - - return () => observer.disconnect(); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [elementRef?.current, JSON.stringify(threshold), root, rootMargin, frozen]); - - return entry; -} diff --git a/apps/smart-forms-app/src/features/renderer/hooks/useRenderingExtensions.ts b/apps/smart-forms-app/src/features/renderer/hooks/useRenderingExtensions.ts deleted file mode 100644 index 51c427a8a..000000000 --- a/apps/smart-forms-app/src/features/renderer/hooks/useRenderingExtensions.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - getEntryFormat, - getMaxLength, - getReadOnly, - getRegexValidation, - getTextDisplayInstructions, - getTextDisplayPrompt, - getTextDisplayUnit -} from '../utils/itemControl.ts'; -import type { QuestionnaireItem } from 'fhir/r4'; -import type { RegexValidation } from '../types/regex.ts'; - -interface RenderingExtensions { - displayUnit: string; - displayPrompt: string; - displayInstructions: string; - readOnly: boolean; - entryFormat: string; - regexValidation: RegexValidation | null; - maxLength: number | null; -} - -function useRenderingExtensions(qItem: QuestionnaireItem): RenderingExtensions { - return { - displayUnit: getTextDisplayUnit(qItem), - displayPrompt: getTextDisplayPrompt(qItem), - displayInstructions: getTextDisplayInstructions(qItem), - readOnly: getReadOnly(qItem), - entryFormat: getEntryFormat(qItem), - regexValidation: getRegexValidation(qItem), - maxLength: getMaxLength(qItem) - }; -} - -export default useRenderingExtensions; diff --git a/apps/smart-forms-app/src/features/renderer/hooks/useTerminologyServerQuery.ts b/apps/smart-forms-app/src/features/renderer/hooks/useTerminologyServerQuery.ts deleted file mode 100644 index 40a954201..000000000 --- a/apps/smart-forms-app/src/features/renderer/hooks/useTerminologyServerQuery.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useQuery } from '@tanstack/react-query'; -import type { Coding, ValueSet } from 'fhir/r4'; -import { getValueSetCodings, getValueSetPromise } from '../../../utils/valueSet.ts'; - -import type { AlertColor } from '@mui/material'; -import useQuestionnaireStore from '../../../stores/useQuestionnaireStore.ts'; - -function useTerminologyServerQuery( - answerValueSetUrl: string | undefined, - maxList: number, - input: string, - searchTerm: string, - terminologyServerUrl?: string -): { options: Coding[]; loading: boolean; feedback?: { message: string; color: AlertColor } } { - const processedValueSetUrls = useQuestionnaireStore((state) => state.processedValueSetUrls); - - let fullUrl = ''; - - let options: Coding[] = []; - let loading = false; - let feedback: { message: string; color: AlertColor } | undefined; - - if (input.length === 0) { - feedback = undefined; - } - - if (searchTerm.length < 2 && searchTerm.length > 0) { - feedback = { message: 'Enter at least 2 characters to search for results.', color: 'info' }; - } - - // Restructure url to include filter and count parameters - if (answerValueSetUrl) { - if (answerValueSetUrl.startsWith('#')) { - answerValueSetUrl = answerValueSetUrl.slice(1); - } - - // attempt to get url from contained value sets when loading questionnaire - if (processedValueSetUrls[answerValueSetUrl]) { - answerValueSetUrl = processedValueSetUrls[answerValueSetUrl]; - } - - const urlWithTrailingAmpersand = - answerValueSetUrl + (answerValueSetUrl[answerValueSetUrl.length - 1] !== '&' ? '&' : ''); - fullUrl = urlWithTrailingAmpersand + 'filter=' + searchTerm + '&count=' + maxList; - } - - // Perform query - const { isInitialLoading, error, data } = useQuery( - ['expandValueSet', fullUrl], - () => getValueSetPromise(fullUrl, terminologyServerUrl), - { - enabled: searchTerm.length >= 2 && answerValueSetUrl !== undefined - } - ); - - if (isInitialLoading) { - loading = true; - } - - if (error) { - console.warn('Ontoserver query failed. Details below: \n' + error); - feedback = { - message: 'An error occurred. Try again later or try searching for a different term.', - color: 'error' - }; - } - - if (data) { - if (data.expansion?.total !== 0) { - options = getValueSetCodings(data); - } else { - feedback = { - message: "We couldn't seem to find anything. Try searching for a different term.", - color: 'warning' - }; - } - } - - return { options, loading, feedback }; -} -export default useTerminologyServerQuery; diff --git a/apps/smart-forms-app/src/features/renderer/hooks/useValidationError.ts b/apps/smart-forms-app/src/features/renderer/hooks/useValidationError.ts deleted file mode 100644 index eb8b41e4f..000000000 --- a/apps/smart-forms-app/src/features/renderer/hooks/useValidationError.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { RegexValidation } from '../types/regex.ts'; - -function useValidationError( - input: string, - regexValidation: RegexValidation | null, - maxLength: number | null -): string { - let feedback = ''; - - if (input) { - // Test regex - if (regexValidation) { - if (!regexValidation.expression.test(input)) { - feedback = - regexValidation.feedback ?? - `Input should match the specified regex ${regexValidation.expression}`; - } - } - - // Test max character limit - if (maxLength) { - if (input.length > maxLength) { - feedback = 'Input exceeds maximum character limit.'; - } - } - } - - return feedback; -} - -export default useValidationError; diff --git a/apps/smart-forms-app/src/features/renderer/hooks/useValueSetCodings.ts b/apps/smart-forms-app/src/features/renderer/hooks/useValueSetCodings.ts deleted file mode 100644 index 19c20131f..000000000 --- a/apps/smart-forms-app/src/features/renderer/hooks/useValueSetCodings.ts +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { useEffect, useMemo, useState } from 'react'; -import type { Coding, FhirResource, QuestionnaireItem, ValueSet } from 'fhir/r4'; -import { - getResourceFromLaunchContext, - getTerminologyServerUrl, - getValueSetCodings, - getValueSetPromise -} from '../../../utils/valueSet.ts'; -import { getAnswerExpression } from '../utils/itemControl.ts'; -import fhirpath from 'fhirpath'; -import fhirpath_r4_model from 'fhirpath/fhir-context/r4'; -import useQuestionnaireStore from '../../../stores/useQuestionnaireStore.ts'; -import useSmartClient from '../../../hooks/useSmartClient.ts'; - -function useValueSetCodings(qItem: QuestionnaireItem) { - const { patient, user, encounter } = useSmartClient(); - - const launchContexts = useQuestionnaireStore((state) => state.launchContexts); - const processedValueSetCodings = useQuestionnaireStore((state) => state.processedValueSetCodings); - const cachedValueSetCodings = useQuestionnaireStore((state) => state.cachedValueSetCodings); - const addCodingToCache = useQuestionnaireStore((state) => state.addCodingToCache); - const { xFhirQueryVariables } = useQuestionnaireStore((state) => state.variables); - - const valueSetUrl = qItem.answerValueSet; - let initialCodings = useMemo(() => { - // set options from cached answer options if present - if (valueSetUrl) { - let cleanValueSetUrl = valueSetUrl; - if (valueSetUrl.startsWith('#')) { - cleanValueSetUrl = valueSetUrl.slice(1); - } - - // attempt to get codings from value sets preprocessed when loading questionnaire - if (processedValueSetCodings[cleanValueSetUrl]) { - return processedValueSetCodings[cleanValueSetUrl]; - } - - // attempt to get codings from cached queried value sets - if (cachedValueSetCodings[cleanValueSetUrl]) { - return cachedValueSetCodings[cleanValueSetUrl]; - } - } - - return []; - }, [cachedValueSetCodings, processedValueSetCodings, valueSetUrl]); - - const answerExpression = getAnswerExpression(qItem)?.expression; - initialCodings = useMemo(() => { - if (initialCodings.length === 0 && answerExpression) { - const variable = answerExpression.substring( - answerExpression.indexOf('%') + 1, - answerExpression.indexOf('.') - ); - const contextMap: Record = {}; - - // get answer expression resource from launch contexts - if (launchContexts[variable]) { - const resourceType = launchContexts[variable].extension[1].valueCode; - const resource = getResourceFromLaunchContext(resourceType, patient, user, encounter); - if (resource) { - contextMap[variable] = resource; - } - } else if (xFhirQueryVariables[variable]) { - const resource = xFhirQueryVariables[variable].result; - if (resource) { - contextMap[variable] = resource; - } - } - - if (contextMap[variable]) { - try { - const evaluated: any[] = fhirpath.evaluate( - {}, - answerExpression, - contextMap, - fhirpath_r4_model - ); - - if (evaluated[0].system || evaluated[0].code) { - // determine if the evaluated array is a coding array - return evaluated; - } else if (evaluated[0].coding) { - // determine and return if the evaluated array is a codeable concept - return evaluated[0].coding; - } - } catch (e) { - console.warn(e); - } - } - } - - return initialCodings; - }, [ - answerExpression, - encounter, - initialCodings, - launchContexts, - patient, - user, - xFhirQueryVariables - ]); - - const [codings, setCodings] = useState(initialCodings); - const [serverError, setServerError] = useState(null); - - // get options from answerValueSet on render - useEffect(() => { - const valueSetUrl = qItem.answerValueSet; - if (!valueSetUrl || codings.length > 0) return; - - const terminologyServer = getTerminologyServerUrl(qItem); - const promise = getValueSetPromise(valueSetUrl, terminologyServer); - if (promise) { - promise - .then((valueSet: ValueSet) => { - const codings = getValueSetCodings(valueSet); - if (codings.length > 0) { - addCodingToCache(valueSetUrl, codings); - setCodings(codings); - } - }) - .catch((error: Error) => { - setServerError(error); - }); - } - }, [qItem]); - - return { codings, serverError }; -} - -export default useValueSetCodings; diff --git a/apps/smart-forms-app/src/providers/questionnaireProvider.interfaces.ts b/apps/smart-forms-app/src/providers/questionnaireProvider.interfaces.ts deleted file mode 100644 index 48851739f..000000000 --- a/apps/smart-forms-app/src/providers/questionnaireProvider.interfaces.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Expression, FhirResource } from 'fhir/r4'; - -export interface Variables { - fhirPathVariables: Record; - xFhirQueryVariables: Record; -} - -export interface VariableXFhirQuery { - valueExpression: Expression; - result?: FhirResource; -} diff --git a/apps/smart-forms-app/src/providers/questionnaireProvider.ts b/apps/smart-forms-app/src/providers/questionnaireProvider.ts deleted file mode 100644 index 41b1f887b..000000000 --- a/apps/smart-forms-app/src/providers/questionnaireProvider.ts +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Coding, Questionnaire, QuestionnaireItem } from 'fhir/r4'; -import { getAnswerExpression } from '../features/renderer/utils/itemControl.ts'; -import { - createValueSetToXFhirQueryVariableNameMap, - getTerminologyServerUrl, - getValueSetCodings, - getValueSetPromise, - resolvePromises -} from '../utils/valueSet.ts'; -import type { LaunchContext } from '../features/prepopulate/types/populate.interface.ts'; -import { isLaunchContext } from './typePredicates/isLaunchContext.ts'; -import type { CalculatedExpression } from '../features/calculatedExpression/types/calculatedExpression.interface.ts'; -import type { AnswerExpression } from '../types/answerExpression.interface.ts'; -import type { - EnableWhenExpression, - EnableWhenItemProperties -} from '../types/enableWhen.interface.ts'; -import type { ValueSetPromise } from '../types/valueSet.interface.ts'; -import type { Variables } from './questionnaireProvider.interfaces.ts'; -import type { Tabs } from '../features/renderer/types/tab.interface.ts'; -import { constructTabsWithProperties, isTabContainer } from '../features/renderer/utils/tabs.ts'; -import { - getFhirPathVariables, - getXFhirQueryVariables -} from '../features/preprocess/utils/preprocessQuestionnaire/extractVariables.ts'; -import { getValueSetUrlFromContained } from '../features/preprocess/utils/preprocessQuestionnaire/extractContainedValueSets.ts'; -import { - getCalculatedExpression, - getEnableWhenExpression, - getEnableWhenItemProperties -} from '../features/preprocess/utils/preprocessQuestionnaire/extractOtherExtensions.ts'; - -export class QuestionnaireProvider { - questionnaire: Questionnaire; - tabs: Tabs; - variables: Variables; - launchContexts: Record; - calculatedExpressions: Record; - enableWhenExpressions: Record; - answerExpressions: Record; - enableWhenItems: Record; - preprocessedValueSetCodings: Record; - - constructor() { - this.questionnaire = { - resourceType: 'Questionnaire', - status: 'draft' - }; - this.tabs = {}; - this.variables = { fhirPathVariables: {}, xFhirQueryVariables: {} }; - this.launchContexts = {}; - this.calculatedExpressions = {}; - this.enableWhenExpressions = {}; - this.answerExpressions = {}; - this.enableWhenItems = {}; - this.preprocessedValueSetCodings = {}; - } - - destroyQuestionnaire(): void { - this.questionnaire = { - resourceType: 'Questionnaire', - status: 'draft' - }; - this.tabs = {}; - this.variables = { fhirPathVariables: {}, xFhirQueryVariables: {} }; - this.launchContexts = {}; - this.calculatedExpressions = {}; - this.enableWhenExpressions = {}; - this.answerExpressions = {}; - this.enableWhenItems = {}; - this.preprocessedValueSetCodings = {}; - } - - async setQuestionnaire(questionnaire: Questionnaire): Promise { - this.tabs = {}; - this.variables = { fhirPathVariables: {}, xFhirQueryVariables: {} }; - this.launchContexts = {}; - this.calculatedExpressions = {}; - this.enableWhenExpressions = {}; - this.answerExpressions = {}; - this.enableWhenItems = {}; - this.preprocessedValueSetCodings = {}; - - this.questionnaire = questionnaire; - await this.preprocessQuestionnaire(); - } - - /** - * Read all enableWhen items and calculated expressions in questionnaireResponse - * - * @author Sean Fong - */ - async preprocessQuestionnaire() { - if (!this.questionnaire.item) return; - - // Store launch contexts - if (this.questionnaire.extension && this.questionnaire.extension.length > 0) { - for (const ext of this.questionnaire.extension) { - if (isLaunchContext(ext)) { - const launchContextName = ext.extension[0].valueId ?? ext.extension[0].valueCoding?.code; - if (launchContextName) { - this.launchContexts[launchContextName] = ext; - } - } - } - } - - // Process contained ValueSets - const valueSetPromiseMap: Record = {}; - if (this.questionnaire.contained && this.questionnaire.contained.length > 0) { - this.questionnaire.contained.forEach((entry) => { - if (entry.resourceType === 'ValueSet' && entry.id) { - if (entry.expansion) { - // Store contained valueSet codings - this.preprocessedValueSetCodings[entry.id] = getValueSetCodings(entry); - } else { - // Add unexpanded contained ValueSets to valueSetPromiseMap - const valueSetUrl = getValueSetUrlFromContained(entry); - if (valueSetUrl) { - valueSetPromiseMap[entry.id] = { - promise: getValueSetPromise(valueSetUrl) - }; - } - } - } - }); - } - - // Store questionnaire-level variables - if (this.questionnaire.extension && this.questionnaire.extension.length > 0) { - this.variables.fhirPathVariables['QuestionnaireLevel'] = getFhirPathVariables( - this.questionnaire.extension - ); - - for (const expression of getXFhirQueryVariables(this.questionnaire.extension)) { - if (expression.name) { - this.variables.xFhirQueryVariables[expression.name] = { - valueExpression: expression - }; - } - } - } - - // Check if the questionnaire's top-level items are tab containers or have any tabs - this.questionnaire.item.forEach((topLevelItem) => { - const items = topLevelItem.item; - const topLevelItemIsTabContainer = isTabContainer(topLevelItem); - - const tabs = constructTabsWithProperties(items, topLevelItemIsTabContainer); - - this.tabs = { ...this.tabs, ...tabs }; - }); - - // Recursively read enableWhen items, calculated expressions, enableWhen expressions and valueSets to be expanded - this.questionnaire.item.forEach((item) => { - this.readQuestionnaireItem(item, valueSetPromiseMap); - }); - - // Create a map - const valueSetToXFhirQueryVariableNameMap: Record = - createValueSetToXFhirQueryVariableNameMap(this.variables.xFhirQueryVariables); - - if (Object.keys(valueSetToXFhirQueryVariableNameMap).length > 0) { - for (const valueSetUrl in valueSetToXFhirQueryVariableNameMap) { - valueSetPromiseMap[valueSetUrl] = { - promise: getValueSetPromise(valueSetUrl) - }; - } - } - - // Resolve promises and store valueSet codings in preprocessedValueSetCodings AND XFhirQueryVariables - const valueSetPromises = await resolvePromises(valueSetPromiseMap); - - for (const valueSetUrl in valueSetPromises) { - const valueSet = valueSetPromises[valueSetUrl].valueSet; - - if (valueSet) { - if (valueSetToXFhirQueryVariableNameMap[valueSetUrl]) { - // valueSetUrl is in x-fhir-query variables, save to variable - const variableName = valueSetToXFhirQueryVariableNameMap[valueSetUrl]; - const variable = this.variables.xFhirQueryVariables[variableName]; - this.variables.xFhirQueryVariables[variableName] = { - ...variable, - result: valueSetPromises[valueSetUrl].valueSet - }; - } else { - // valueSetUrl is in x-fhir-query variables, save to preprocessedValueSetCodings - this.preprocessedValueSetCodings[valueSetUrl] = getValueSetCodings(valueSet); - } - } - } - } - - /** - * Read enableWhen items and calculated expressions of each qItem recursively - * - * @author Sean Fong - */ - readQuestionnaireItem( - item: QuestionnaireItem, - valueSetPromiseMap: Record - ) { - const items = item.item; - if (items && items.length > 0) { - // iterate through items of item recursively - items.forEach((item) => { - this.readQuestionnaireItem(item, valueSetPromiseMap); - }); - } - - // Read calculated/answer expressions, enable when expressions, enable when items, valueSets and variables from qItem - const calculatedExpression = getCalculatedExpression(item); - if (calculatedExpression) { - this.calculatedExpressions[item.linkId] = { - expression: `${calculatedExpression.expression}` - }; - } - - const enableWhenExpression = getEnableWhenExpression(item); - if (enableWhenExpression) { - this.enableWhenExpressions[item.linkId] = { - expression: `${enableWhenExpression.expression}` - }; - } - - const answerExpression = getAnswerExpression(item); - if (answerExpression) { - this.answerExpressions[item.linkId] = { - expression: `${answerExpression.expression}` - }; - } - - const enableWhenItemProperties = getEnableWhenItemProperties(item); - if (enableWhenItemProperties) { - this.enableWhenItems[item.linkId] = enableWhenItemProperties; - } - - const valueSetUrl = item.answerValueSet; - if (valueSetUrl) { - if (!valueSetPromiseMap[valueSetUrl] && !valueSetUrl.startsWith('#')) { - const terminologyServerUrl = getTerminologyServerUrl(item); - valueSetPromiseMap[valueSetUrl] = { - promise: getValueSetPromise(valueSetUrl, terminologyServerUrl) - }; - } - } - - if (item.extension) { - this.variables.fhirPathVariables[item.linkId] = getFhirPathVariables(item.extension); - - for (const expression of getXFhirQueryVariables(item.extension)) { - if (expression.name) { - this.variables.xFhirQueryVariables[expression.name] = { - valueExpression: expression - }; - } - } - } - } -} diff --git a/apps/smart-forms-app/src/providers/questionnaireResponseProvider.interfaces.ts b/apps/smart-forms-app/src/providers/questionnaireResponseProvider.interfaces.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/apps/smart-forms-app/src/providers/questionnaireResponseProvider.ts b/apps/smart-forms-app/src/providers/questionnaireResponseProvider.ts deleted file mode 100644 index f76e902ac..000000000 --- a/apps/smart-forms-app/src/providers/questionnaireResponseProvider.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { QuestionnaireResponse } from 'fhir/r4'; - -const emptyQResponse: QuestionnaireResponse = { - resourceType: 'QuestionnaireResponse', - status: 'in-progress' -}; - -export class QuestionnaireResponseProvider { - response: QuestionnaireResponse; - - constructor() { - this.response = emptyQResponse; - } - - setQuestionnaireResponse(questionnaireResponse: QuestionnaireResponse) { - this.response = questionnaireResponse; - } -} diff --git a/apps/smart-forms-app/src/providers/typePredicates/isLaunchContext.ts b/apps/smart-forms-app/src/providers/typePredicates/isLaunchContext.ts deleted file mode 100644 index 3e7dd866d..000000000 --- a/apps/smart-forms-app/src/providers/typePredicates/isLaunchContext.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Extension } from 'fhir/r4'; -import type { LaunchContext } from '../../features/prepopulate/types/populate.interface.ts'; - -export function isLaunchContext(extension: Extension): extension is LaunchContext { - const hasLaunchContextName = - extension.url === - 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-launchContext' && - !!extension.extension?.find( - (ext) => - ext.url === 'name' && - (ext.valueId || - (ext.valueCoding && - (ext.valueCoding.code === 'patient' || - ext.valueCoding.code === 'encounter' || - ext.valueCoding.code === 'location' || - ext.valueCoding.code === 'user' || - ext.valueCoding.code === 'study' || - ext.valueCoding.code === 'sourceQueries'))) - ); - - const hasLaunchContextType = !!extension.extension?.find( - (ext) => - ext.url === 'type' && - ext.valueCode && - (ext.valueCode === 'Patient' || - ext.valueCode === 'Practitioner' || - ext.valueCode === 'Encounter') - ); - - return ( - extension.url === - 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-launchContext' && - hasLaunchContextName && - hasLaunchContextType - ); -} diff --git a/apps/smart-forms-app/src/providers/typePredicates/isSourceQuery.ts b/apps/smart-forms-app/src/providers/typePredicates/isSourceQuery.ts deleted file mode 100644 index 7a98532ab..000000000 --- a/apps/smart-forms-app/src/providers/typePredicates/isSourceQuery.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Extension } from 'fhir/r4'; -import type { SourceQuery } from '../../features/prepopulate/types/populate.interface.ts'; - -export function isSourceQuery(extension: Extension): extension is SourceQuery { - return ( - extension.url === - 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-sourceQueries' && - !!extension.valueReference - ); -} diff --git a/apps/smart-forms-app/src/providers/typePredicates/isXFhirQueryVariable.ts b/apps/smart-forms-app/src/providers/typePredicates/isXFhirQueryVariable.ts deleted file mode 100644 index 8e262b91c..000000000 --- a/apps/smart-forms-app/src/providers/typePredicates/isXFhirQueryVariable.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Extension } from 'fhir/r4'; -import type { QuestionnaireLevelXFhirQueryVariable } from '../../features/prepopulate/types/populate.interface.ts'; - -export function isXFhirQueryVariable( - extension: Extension -): extension is QuestionnaireLevelXFhirQueryVariable { - return ( - extension.url === 'http://hl7.org/fhir/StructureDefinition/variable' && - !!extension.valueExpression?.name && - extension.valueExpression?.language === 'application/x-fhir-query' && - !!extension.valueExpression?.expression - ); -} diff --git a/apps/smart-forms-app/src/stores/useConfigStore.ts b/apps/smart-forms-app/src/stores/useConfigStore.ts deleted file mode 100644 index e80350557..000000000 --- a/apps/smart-forms-app/src/stores/useConfigStore.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { create } from 'zustand'; -import type { Encounter, Patient, Practitioner, Questionnaire } from 'fhir/r4'; -import type Client from 'fhirclient/lib/Client'; - -export interface ConfigState { - smartClient: Client | null; - patient: Patient | null; - user: Practitioner | null; - encounter: Encounter | null; - launchQuestionnaire: Questionnaire | null; - debugMode: boolean; - setSmartClient: (client: Client) => void; - setPatient: (patient: Patient) => void; - setUser: (user: Practitioner) => void; - setEncounter: (encounter: Encounter) => void; - setLaunchQuestionnaire: (launchQuestionnaire: Questionnaire | null) => void; - activateDebugMode: () => void; -} - -const useConfigStore = create()((set) => ({ - smartClient: null, - patient: null, - user: null, - encounter: null, - launchQuestionnaire: null, - debugMode: false, - setSmartClient: (client: Client) => set(() => ({ smartClient: client })), - setPatient: (patient: Patient) => set(() => ({ patient: patient })), - setUser: (user: Practitioner) => set(() => ({ user: user })), - setEncounter: (encounter: Encounter) => set(() => ({ encounter: encounter })), - setLaunchQuestionnaire: (launchQuestionnaire: Questionnaire | null) => - set(() => ({ launchQuestionnaire: launchQuestionnaire })), - activateDebugMode: () => set(() => ({ debugMode: true })) -})); - -export default useConfigStore; diff --git a/apps/smart-forms-app/src/stores/useQuestionnaireResponseStore.ts b/apps/smart-forms-app/src/stores/useQuestionnaireResponseStore.ts deleted file mode 100644 index f5db790b4..000000000 --- a/apps/smart-forms-app/src/stores/useQuestionnaireResponseStore.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { create } from 'zustand'; -import type { QuestionnaireResponse } from 'fhir/r4'; - -const emptyResponse: QuestionnaireResponse = { - resourceType: 'QuestionnaireResponse', - status: 'in-progress' -}; - -export interface QuestionnaireResponseState { - sourceResponse: QuestionnaireResponse; - updatableResponse: QuestionnaireResponse; - hasChanges: boolean; - buildSourceResponse: (response: QuestionnaireResponse) => void; - populateResponse: (response: QuestionnaireResponse) => void; - updateResponse: (updatedResponse: QuestionnaireResponse) => void; - saveResponse: (savedResponse: QuestionnaireResponse) => void; - clearResponse: (clearedResponse: QuestionnaireResponse) => void; - destroySourceResponse: () => void; -} - -const useQuestionnaireResponseStore = create()((set) => ({ - sourceResponse: emptyResponse, - updatableResponse: emptyResponse, - hasChanges: false, - - buildSourceResponse: (questionnaireResponse: QuestionnaireResponse) => { - set(() => ({ - sourceResponse: questionnaireResponse, - updatableResponse: questionnaireResponse - })); - }, - populateResponse: (populatedResponse: QuestionnaireResponse) => { - set(() => ({ - updatableResponse: populatedResponse - })); - }, - updateResponse: (updatedResponse: QuestionnaireResponse) => - set(() => ({ - updatableResponse: updatedResponse, - hasChanges: true - })), - saveResponse: (savedResponse: QuestionnaireResponse) => - set(() => ({ - sourceResponse: savedResponse, - updatableResponse: savedResponse, - hasChanges: false - })), - clearResponse: (clearedResponse: QuestionnaireResponse) => - set(() => ({ - updatableResponse: clearedResponse, - hasChanges: false - })), - destroySourceResponse: () => - set(() => ({ - sourceResponse: emptyResponse, - updatableResponse: emptyResponse, - hasChanges: false - })) -})); - -export default useQuestionnaireResponseStore; diff --git a/apps/smart-forms-app/src/stores/useQuestionnaireStore.ts b/apps/smart-forms-app/src/stores/useQuestionnaireStore.ts deleted file mode 100644 index d607e9ca6..000000000 --- a/apps/smart-forms-app/src/stores/useQuestionnaireStore.ts +++ /dev/null @@ -1,218 +0,0 @@ -import { create } from 'zustand'; -import type { - Coding, - Questionnaire, - QuestionnaireResponse, - QuestionnaireResponseItemAnswer -} from 'fhir/r4'; -import type { Variables } from '../providers/questionnaireProvider.interfaces.ts'; -import type { LaunchContext } from '../features/prepopulate/types/populate.interface.ts'; -import type { CalculatedExpression } from '../features/calculatedExpression/types/calculatedExpression.interface.ts'; -import type { EnableWhenExpression, EnableWhenItems } from '../types/enableWhen.interface.ts'; -import type { AnswerExpression } from '../types/answerExpression.interface.ts'; -import { createQuestionnaireModel } from '../features/preprocess/utils/preprocessQuestionnaire/preprocessQuestionnaire.ts'; -import type { Tabs } from '../features/renderer/types/tab.interface.ts'; -import { updateItemAnswer } from '../utils/enableWhen.ts'; -import { initialiseFormFromResponse } from '../utils/initaliseForm.ts'; -import { evaluateUpdatedExpressions } from '../utils/fhirpath.ts'; -import { - evaluateInitialCalculatedExpressions, - initialiseCalculatedExpressionValues -} from '../utils/calculatedExpressions.ts'; - -const emptyQuestionnaire: Questionnaire = { - resourceType: 'Questionnaire', - status: 'draft' -}; - -export const emptyResponse: QuestionnaireResponse = { - resourceType: 'QuestionnaireResponse', - status: 'in-progress' -}; - -export interface QuestionnaireState { - sourceQuestionnaire: Questionnaire; - tabs: Tabs; - currentTabIndex: number; - variables: Variables; - launchContexts: Record; - enableWhenItems: EnableWhenItems; - enableWhenLinkedQuestions: Record; - enableWhenIsActivated: boolean; - enableWhenExpressions: Record; - calculatedExpressions: Record; - answerExpressions: Record; - processedValueSetCodings: Record; - processedValueSetUrls: Record; - cachedValueSetCodings: Record; - buildSourceQuestionnaire: ( - questionnaire: Questionnaire, - questionnaireResponse?: QuestionnaireResponse - ) => Promise; - destroySourceQuestionnaire: () => void; - switchTab: (newTabIndex: number) => void; - markTabAsComplete: (tabLinkId: string) => void; - updateEnableWhenItem: (linkId: string, newAnswer: QuestionnaireResponseItemAnswer[]) => void; - toggleEnableWhenActivation: (isActivated: boolean) => void; - updateExpressions: (updatedResponse: QuestionnaireResponse) => void; - addCodingToCache: (valueSetUrl: string, codings: Coding[]) => void; - updatePopulatedProperties: (populatedResponse: QuestionnaireResponse) => QuestionnaireResponse; -} - -const useQuestionnaireStore = create()((set, get) => ({ - sourceQuestionnaire: emptyQuestionnaire, - tabs: {}, - currentTabIndex: 0, - variables: { fhirPathVariables: {}, xFhirQueryVariables: {} }, - launchContexts: {}, - calculatedExpressions: {}, - enableWhenExpressions: {}, - answerExpressions: {}, - enableWhenItems: {}, - enableWhenLinkedQuestions: {}, - enableWhenIsActivated: true, - processedValueSetCodings: {}, - processedValueSetUrls: {}, - cachedValueSetCodings: {}, - buildSourceQuestionnaire: async (questionnaire, questionnaireResponse = emptyResponse) => { - const questionnaireModel = await createQuestionnaireModel(questionnaire); - - const { - initialEnableWhenItems, - initialEnableWhenLinkedQuestions, - initialEnableWhenExpressions, - initialCalculatedExpressions, - firstVisibleTab - } = initialiseFormFromResponse({ - questionnaireResponse, - enableWhenItems: questionnaireModel.enableWhenItems, - enableWhenExpressions: questionnaireModel.enableWhenExpressions, - calculatedExpressions: questionnaireModel.calculatedExpressions, - variablesFhirPath: questionnaireModel.variables.fhirPathVariables, - tabs: questionnaireModel.tabs - }); - - set({ - sourceQuestionnaire: questionnaire, - tabs: questionnaireModel.tabs, - currentTabIndex: firstVisibleTab, - variables: questionnaireModel.variables, - launchContexts: questionnaireModel.launchContexts, - enableWhenItems: initialEnableWhenItems, - enableWhenLinkedQuestions: initialEnableWhenLinkedQuestions, - enableWhenExpressions: initialEnableWhenExpressions, - calculatedExpressions: initialCalculatedExpressions, - answerExpressions: questionnaireModel.answerExpressions, - processedValueSetCodings: questionnaireModel.processedValueSetCodings, - processedValueSetUrls: questionnaireModel.processedValueSetUrls - }); - }, - destroySourceQuestionnaire: () => - set({ - sourceQuestionnaire: emptyQuestionnaire, - tabs: {}, - currentTabIndex: 0, - variables: { fhirPathVariables: {}, xFhirQueryVariables: {} }, - launchContexts: {}, - enableWhenItems: {}, - enableWhenLinkedQuestions: {}, - enableWhenExpressions: {}, - calculatedExpressions: {}, - answerExpressions: {}, - processedValueSetCodings: {}, - processedValueSetUrls: {} - }), - switchTab: (newTabIndex: number) => set(() => ({ currentTabIndex: newTabIndex })), - markTabAsComplete: (tabLinkId: string) => { - const tabs = get().tabs; - set(() => ({ - tabs: { - ...tabs, - [tabLinkId]: { ...tabs[tabLinkId], isComplete: !tabs[tabLinkId].isComplete } - } - })); - }, - updateEnableWhenItem: (linkId: string, newAnswer: QuestionnaireResponseItemAnswer[]) => { - const enableWhenLinkedQuestions = get().enableWhenLinkedQuestions; - const enableWhenItems = get().enableWhenItems; - if (!enableWhenLinkedQuestions[linkId]) { - return; - } - - const itemLinkedQuestions = enableWhenLinkedQuestions[linkId]; - const updatedEnableWhenItems = updateItemAnswer( - { ...enableWhenItems }, - itemLinkedQuestions, - linkId, - newAnswer - ); - - set(() => ({ - enableWhenItems: updatedEnableWhenItems - })); - }, - toggleEnableWhenActivation: (isActivated: boolean) => - set(() => ({ enableWhenIsActivated: isActivated })), - updateExpressions: (updatedResponse: QuestionnaireResponse) => { - const { isUpdated, updatedCalculatedExpressions, updatedEnableWhenExpressions } = - evaluateUpdatedExpressions({ - updatedResponse: updatedResponse, - enableWhenExpressions: get().enableWhenExpressions, - calculatedExpressions: get().calculatedExpressions, - variablesFhirPath: get().variables.fhirPathVariables - }); - - if (isUpdated) { - set(() => ({ - enableWhenExpressions: updatedEnableWhenExpressions, - calculatedExpressions: updatedCalculatedExpressions - })); - } - }, - addCodingToCache: (valueSetUrl: string, codings: Coding[]) => - set(() => ({ - cachedValueSetCodings: { - ...get().cachedValueSetCodings, - [valueSetUrl]: codings - } - })), - updatePopulatedProperties: (populatedResponse: QuestionnaireResponse) => { - const initialCalculatedExpressions = evaluateInitialCalculatedExpressions({ - initialResponse: populatedResponse, - calculatedExpressions: get().calculatedExpressions, - variablesFhirPath: get().variables.fhirPathVariables - }); - - const updatedResponse = initialiseCalculatedExpressionValues( - get().sourceQuestionnaire, - populatedResponse, - initialCalculatedExpressions - ); - - const { - initialEnableWhenItems, - initialEnableWhenLinkedQuestions, - initialEnableWhenExpressions, - firstVisibleTab - } = initialiseFormFromResponse({ - questionnaireResponse: updatedResponse, - enableWhenItems: get().enableWhenItems, - enableWhenExpressions: get().enableWhenExpressions, - calculatedExpressions: initialCalculatedExpressions, - variablesFhirPath: get().variables.fhirPathVariables, - tabs: get().tabs - }); - - set(() => ({ - enableWhenItems: initialEnableWhenItems, - enableWhenLinkedQuestions: initialEnableWhenLinkedQuestions, - enableWhenExpressions: initialEnableWhenExpressions, - calculatedExpressions: initialCalculatedExpressions, - currentTabIndex: firstVisibleTab - })); - - return updatedResponse; - } -})); - -export default useQuestionnaireStore; diff --git a/apps/smart-forms-app/src/utils/calculatedExpressions.ts b/apps/smart-forms-app/src/utils/calculatedExpressions.ts index 4a1176fd6..0a158c30f 100644 --- a/apps/smart-forms-app/src/utils/calculatedExpressions.ts +++ b/apps/smart-forms-app/src/utils/calculatedExpressions.ts @@ -27,10 +27,10 @@ import type { QuestionnaireResponseItemAnswer } from 'fhir/r4'; import _isEqual from 'lodash/isEqual'; -import { emptyResponse } from '../stores/useQuestionnaireStore.ts'; import { createFhirPathContext } from './fhirpath.ts'; import { getQrItemsIndex, mapQItemsIndex } from '../features/renderer/utils'; import { updateQrGroup } from '../features/renderer/utils/qrItem.ts'; +import { emptyResponse } from './qrItem.ts'; interface EvaluateInitialCalculatedExpressionsParams { initialResponse: QuestionnaireResponse; diff --git a/apps/smart-forms-app/src/utils/enableWhenExpression.ts b/apps/smart-forms-app/src/utils/enableWhenExpression.ts index ab6b8607b..e49671a2e 100644 --- a/apps/smart-forms-app/src/utils/enableWhenExpression.ts +++ b/apps/smart-forms-app/src/utils/enableWhenExpression.ts @@ -21,7 +21,7 @@ import { createFhirPathContext } from './fhirpath.ts'; import fhirpath from 'fhirpath'; import fhirpath_r4_model from 'fhirpath/fhir-context/r4'; import _isEqual from 'lodash/isEqual'; -import { emptyResponse } from '../stores/useQuestionnaireStore.ts'; +import { emptyResponse } from './qrItem.ts'; interface EvaluateInitialEnableWhenExpressionsParams { initialResponse: QuestionnaireResponse; diff --git a/apps/smart-forms-app/src/features/prepopulate/typePredicates/typePredicates.ts b/apps/smart-forms-app/src/utils/qrItem.ts similarity index 79% rename from apps/smart-forms-app/src/features/prepopulate/typePredicates/typePredicates.ts rename to apps/smart-forms-app/src/utils/qrItem.ts index e4a8aefb2..5f40cd26e 100644 --- a/apps/smart-forms-app/src/features/prepopulate/typePredicates/typePredicates.ts +++ b/apps/smart-forms-app/src/utils/qrItem.ts @@ -14,3 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import type { QuestionnaireResponse } from 'fhir/r4'; + +export const emptyResponse: QuestionnaireResponse = { + resourceType: 'QuestionnaireResponse', + status: 'in-progress' +}; diff --git a/apps/smart-forms-app/src/utils/valueSet.ts b/apps/smart-forms-app/src/utils/valueSet.ts index e742c1e62..ebd51cd17 100644 --- a/apps/smart-forms-app/src/utils/valueSet.ts +++ b/apps/smart-forms-app/src/utils/valueSet.ts @@ -27,9 +27,11 @@ import type { ValueSet } from 'fhir/r4'; import * as FHIR from 'fhirclient'; -import type { FhirResourceString } from '../features/prepopulate/types/populate.interface.ts'; +import type { + FhirResourceString, + VariableXFhirQuery +} from '../features/prepopulate/types/populate.interface.ts'; import type { ValueSetPromise } from '../types/valueSet.interface.ts'; -import type { VariableXFhirQuery } from '../providers/questionnaireProvider.interfaces.ts'; import { ONTOSERVER_ENDPOINT } from './env.ts'; const VALID_VALUE_SET_URL_REGEX = From e2c3c0a46ba129555ee7bcca3cca77d6d390c40c Mon Sep 17 00:00:00 2001 From: Sean Fong Date: Fri, 1 Sep 2023 12:35:38 +0930 Subject: [PATCH 4/4] Yet more clean up --- .../src/{features/save => }/api/saveQr.ts | 8 +- .../Buttons/CreateNewResponseButton.tsx | 2 +- .../Buttons/OpenResponseButton.tsx | 4 +- .../preprocess/types/questionnaireModel.ts | 21 -- .../extractContainedValueSets.ts | 74 ------ .../extractLaunchContext.ts | 21 -- .../extractOtherExtensions.ts | 239 ------------------ .../preprocessQuestionnaire/extractTabs.ts | 37 --- .../extractVariables.ts | 75 ------ .../preprocessQuestionnaire.ts | 92 ------- .../resolveValueSets.ts | 68 ----- .../components/RendererEmbeddedSpeedDial.tsx | 2 +- .../RendererNav/BlockerUnsavedFormDialog.tsx | 2 +- .../SaveAsDraft/RendererSaveAsDraft.tsx | 2 +- .../SaveAsFinal/RendererSaveAsFinalDialog.tsx | 2 +- .../components/Authorisation.tsx | 4 +- .../src/features/viewer/ViewerLayout.tsx | 2 +- .../SaveAsFinal/ViewerSaveAsFinalDialog.tsx | 2 +- .../types/calculatedExpression.interface.ts | 0 .../types/printComponentRefContext.type.ts | 4 - .../{features/assemble => }/utils/assemble.ts | 4 +- .../src/utils/calculatedExpressions.ts | 2 +- apps/smart-forms-app/src/utils/fhirpath.ts | 2 +- .../src/utils/initaliseForm.ts | 2 +- 24 files changed, 20 insertions(+), 651 deletions(-) rename apps/smart-forms-app/src/{features/save => }/api/saveQr.ts (94%) delete mode 100644 apps/smart-forms-app/src/features/preprocess/types/questionnaireModel.ts delete mode 100644 apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractContainedValueSets.ts delete mode 100644 apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractLaunchContext.ts delete mode 100644 apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractOtherExtensions.ts delete mode 100644 apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractTabs.ts delete mode 100644 apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractVariables.ts delete mode 100644 apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/preprocessQuestionnaire.ts delete mode 100644 apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/resolveValueSets.ts rename apps/smart-forms-app/src/{features/calculatedExpression => }/types/calculatedExpression.interface.ts (100%) rename apps/smart-forms-app/src/{features/print => }/types/printComponentRefContext.type.ts (87%) rename apps/smart-forms-app/src/{features/assemble => }/utils/assemble.ts (96%) diff --git a/apps/smart-forms-app/src/features/save/api/saveQr.ts b/apps/smart-forms-app/src/api/saveQr.ts similarity index 94% rename from apps/smart-forms-app/src/features/save/api/saveQr.ts rename to apps/smart-forms-app/src/api/saveQr.ts index 13ab8fa9c..9913ac2b1 100644 --- a/apps/smart-forms-app/src/features/save/api/saveQr.ts +++ b/apps/smart-forms-app/src/api/saveQr.ts @@ -17,12 +17,12 @@ import type { Patient, Practitioner, Questionnaire, QuestionnaireResponse } from 'fhir/r4'; import type Client from 'fhirclient/lib/Client'; -import { constructName } from '../../smartAppLaunch/utils/launchContext.ts'; +import { constructName } from '../features/smartAppLaunch/utils/launchContext.ts'; import dayjs from 'dayjs'; -import { qrToHTML } from '../../preview/utils/preview.ts'; -import { fetchQuestionnaireById } from '../../../api/client.ts'; +import { qrToHTML } from '../features/preview/utils/preview.ts'; +import { fetchQuestionnaireById } from './client.ts'; import cloneDeep from 'lodash.clonedeep'; -import { HEADERS } from '../../../api/headers.ts'; +import { HEADERS } from './headers.ts'; /** * POST questionnaire to SMART Health IT when opening it to ensure response-saving can be performed diff --git a/apps/smart-forms-app/src/features/dashboard/components/DashboardPages/QuestionnairePage/Buttons/CreateNewResponseButton.tsx b/apps/smart-forms-app/src/features/dashboard/components/DashboardPages/QuestionnairePage/Buttons/CreateNewResponseButton.tsx index 8e77e90ee..fd852eaf4 100644 --- a/apps/smart-forms-app/src/features/dashboard/components/DashboardPages/QuestionnairePage/Buttons/CreateNewResponseButton.tsx +++ b/apps/smart-forms-app/src/features/dashboard/components/DashboardPages/QuestionnairePage/Buttons/CreateNewResponseButton.tsx @@ -17,7 +17,7 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { postQuestionnaireToSMARTHealthIT } from '../../../../../save/api/saveQr.ts'; +import { postQuestionnaireToSMARTHealthIT } from '../../../../../../api/saveQr.ts'; import { CircularProgress, IconButton, Stack, Typography } from '@mui/material'; import EditNoteIcon from '@mui/icons-material/EditNote'; import { buildForm } from '@aehrc/smart-forms-renderer'; diff --git a/apps/smart-forms-app/src/features/dashboard/components/DashboardPages/ResponsesPage/Buttons/OpenResponseButton.tsx b/apps/smart-forms-app/src/features/dashboard/components/DashboardPages/ResponsesPage/Buttons/OpenResponseButton.tsx index eb7a37c14..9d32d4e24 100644 --- a/apps/smart-forms-app/src/features/dashboard/components/DashboardPages/ResponsesPage/Buttons/OpenResponseButton.tsx +++ b/apps/smart-forms-app/src/features/dashboard/components/DashboardPages/ResponsesPage/Buttons/OpenResponseButton.tsx @@ -24,8 +24,8 @@ import { } from '../../../../utils/dashboard.ts'; import { useNavigate } from 'react-router-dom'; import { useSnackbar } from 'notistack'; -import { postQuestionnaireToSMARTHealthIT } from '../../../../../save/api/saveQr.ts'; -import { assembleIfRequired } from '../../../../../assemble/utils/assemble.ts'; +import { postQuestionnaireToSMARTHealthIT } from '../../../../../../api/saveQr.ts'; +import { assembleIfRequired } from '../../../../../../utils/assemble.ts'; import { CircularProgress, IconButton, Stack, Typography } from '@mui/material'; import OpenInNewIcon from '@mui/icons-material/OpenInNew'; import { buildForm } from '@aehrc/smart-forms-renderer'; diff --git a/apps/smart-forms-app/src/features/preprocess/types/questionnaireModel.ts b/apps/smart-forms-app/src/features/preprocess/types/questionnaireModel.ts deleted file mode 100644 index d41cb91c7..000000000 --- a/apps/smart-forms-app/src/features/preprocess/types/questionnaireModel.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Coding } from 'fhir/r4'; -import type { Tabs } from '../../renderer/types/tab.interface.ts'; -import type { LaunchContext, Variables } from '../../prepopulate/types/populate.interface.ts'; -import type { CalculatedExpression } from '../../calculatedExpression/types/calculatedExpression.interface.ts'; -import type { - EnableWhenExpression, - EnableWhenItemProperties -} from '../../../types/enableWhen.interface.ts'; -import type { AnswerExpression } from '../../../types/answerExpression.interface.ts'; - -export interface QuestionnaireModel { - tabs: Tabs; - variables: Variables; - launchContexts: Record; - enableWhenItems: Record; - enableWhenExpressions: Record; - calculatedExpressions: Record; - answerExpressions: Record; - processedValueSetCodings: Record; - processedValueSetUrls: Record; -} diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractContainedValueSets.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractContainedValueSets.ts deleted file mode 100644 index bd1d9e4fc..000000000 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractContainedValueSets.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { ValueSetPromise } from '../../../../types/valueSet.interface.ts'; -import { getValueSetCodings, getValueSetPromise } from '../../../../utils/valueSet.ts'; -import type { Coding, Questionnaire, ValueSet } from 'fhir/r4'; - -export function extractContainedValueSets(questionnaire: Questionnaire): { - processedValueSetCodings: Record; - processedValueSetUrls: Record; - valueSetPromises: Record; -} { - if (!questionnaire.contained || questionnaire.contained.length === 0) { - return { processedValueSetCodings: {}, processedValueSetUrls: {}, valueSetPromises: {} }; - } - - // Process contained ValueSets - const processedValueSetCodings: Record = {}; - const processedValueSetUrls: Record = {}; - const valueSetPromises: Record = {}; - for (const entry of questionnaire.contained) { - if (entry.resourceType !== 'ValueSet' || !entry.id) { - continue; - } - - if (entry.expansion) { - // Store contained valueSet codings - processedValueSetCodings[entry.id] = getValueSetCodings(entry); - continue; - } - - // Add unexpanded contained ValueSets to valueSetPromiseMap - const valueSetUrl = getValueSetUrlFromContained(entry); - if (valueSetUrl) { - valueSetPromises[entry.id] = { - promise: getValueSetPromise(valueSetUrl) - }; - continue; - } - - if (entry.url) { - processedValueSetUrls[entry.id] = entry.url; - } - } - - return { processedValueSetCodings, processedValueSetUrls, valueSetPromises }; -} - -/** - * Sets an array of codings with the values from a valueSet - * - * @author Sean Fong - */ -export function getValueSetUrlFromContained(valueSet: ValueSet): string { - const urls = valueSet.compose?.include?.map((include) => - include.valueSet?.[0] ? include.valueSet[0] : '' - ); - - return urls && urls.length > 0 ? urls[0] : ''; -} diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractLaunchContext.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractLaunchContext.ts deleted file mode 100644 index ba54a1255..000000000 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractLaunchContext.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { Questionnaire } from 'fhir/r4'; -import type { LaunchContext } from '../../../prepopulate/types/populate.interface.ts'; -import { isLaunchContext } from '../../../prepopulate/utils/getExtensions.ts'; - -export function extractLaunchContexts(questionnaire: Questionnaire): Record { - if (!questionnaire.extension || questionnaire.extension.length === 0) { - return {}; - } - - const launchContexts: Record = {}; - for (const ext of questionnaire.extension) { - if (isLaunchContext(ext)) { - const launchContextName = ext.extension[0].valueId ?? ext.extension[0].valueCoding?.code; - if (launchContextName) { - launchContexts[launchContextName] = ext; - } - } - } - - return launchContexts; -} diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractOtherExtensions.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractOtherExtensions.ts deleted file mode 100644 index 0d7b4e6cc..000000000 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractOtherExtensions.ts +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Expression, Extension, Questionnaire, QuestionnaireItem } from 'fhir/r4'; -import type { CalculatedExpression } from '../../../calculatedExpression/types/calculatedExpression.interface.ts'; -import type { - EnableWhenExpression, - EnableWhenItemProperties, - EnableWhenLinkedItem -} from '../../../../types/enableWhen.interface.ts'; -import type { AnswerExpression } from '../../../../types/answerExpression.interface.ts'; -import type { ValueSetPromise } from '../../../../types/valueSet.interface.ts'; -import { getAnswerExpression } from '../../../renderer/utils/itemControl.ts'; -import { getTerminologyServerUrl, getValueSetPromise } from '../../../../utils/valueSet.ts'; -import { getFhirPathVariables, getXFhirQueryVariables } from './extractVariables.ts'; -import type { Variables } from '../../../prepopulate/types/populate.interface.ts'; - -interface ReturnParamsRecursive { - variables: Variables; - enableWhenItems: Record; - enableWhenExpressions: Record; - calculatedExpressions: Record; - answerExpressions: Record; - valueSetPromises: Record; -} - -export function extractOtherExtensions( - questionnaire: Questionnaire, - variables: Variables, - valueSetPromises: Record -): ReturnParamsRecursive { - const enableWhenItems: Record = {}; - const enableWhenExpressions: Record = {}; - const calculatedExpressions: Record = {}; - const answerExpressions: Record = {}; - - if (!questionnaire.item || questionnaire.item.length === 0) { - return { - variables: variables, - enableWhenItems: {}, - enableWhenExpressions: {}, - calculatedExpressions: {}, - answerExpressions: {}, - valueSetPromises: valueSetPromises - }; - } - - for (const topLevelItem of questionnaire.item) { - extractExtensionsFromItemRecursive({ - item: topLevelItem, - variables, - enableWhenItems, - enableWhenExpressions, - calculatedExpressions, - answerExpressions, - valueSetPromises - }); - } - - return { - variables, - enableWhenItems, - enableWhenExpressions, - calculatedExpressions, - answerExpressions, - valueSetPromises - }; -} - -interface extractExtensionsFromItemRecursiveParams { - item: QuestionnaireItem; - variables: Variables; - enableWhenItems: Record; - enableWhenExpressions: Record; - calculatedExpressions: Record; - answerExpressions: Record; - valueSetPromises: Record; -} - -function extractExtensionsFromItemRecursive( - params: extractExtensionsFromItemRecursiveParams -): ReturnParamsRecursive { - const { - item, - variables, - enableWhenItems, - enableWhenExpressions, - calculatedExpressions, - answerExpressions, - valueSetPromises - } = params; - - const items = item.item; - if (items && items.length > 0) { - // iterate through items of item recursively - for (const childItem of items) { - extractExtensionsFromItemRecursive({ - ...params, - item: childItem - }); - } - } - - // Read enable when items, enablehen/calculated/answer expressions, valueSets and variables from qItem - const enableWhenItemProperties = getEnableWhenItemProperties(item); - if (enableWhenItemProperties) { - enableWhenItems[item.linkId] = enableWhenItemProperties; - } - - const enableWhenExpression = getEnableWhenExpression(item); - if (enableWhenExpression) { - enableWhenExpressions[item.linkId] = { - expression: `${enableWhenExpression.expression}` - }; - } - - const calculatedExpression = getCalculatedExpression(item); - if (calculatedExpression) { - calculatedExpressions[item.linkId] = { - expression: `${calculatedExpression.expression}` - }; - } - - const answerExpression = getAnswerExpression(item); - if (answerExpression) { - answerExpressions[item.linkId] = { - expression: `${answerExpression.expression}` - }; - } - - const valueSetUrl = item.answerValueSet; - if (valueSetUrl) { - if (!valueSetPromises[valueSetUrl] && !valueSetUrl.startsWith('#')) { - const terminologyServerUrl = getTerminologyServerUrl(item); - valueSetPromises[valueSetUrl] = { - promise: getValueSetPromise(valueSetUrl, terminologyServerUrl) - }; - } - } - - if (item.extension) { - variables.fhirPathVariables[item.linkId] = getFhirPathVariables(item.extension); - - for (const expression of getXFhirQueryVariables(item.extension)) { - if (expression.name) { - variables.xFhirQueryVariables[expression.name] = { - valueExpression: expression - }; - } - } - } - - return { - variables, - enableWhenItems, - enableWhenExpressions, - calculatedExpressions, - answerExpressions, - valueSetPromises - }; -} - -/** - * Get enableWhen items' linked items and enableBehaviour attribute and save them in an EnableWhenItemProperties object - * - * @author Sean Fong - */ -export function getEnableWhenItemProperties( - qItem: QuestionnaireItem -): EnableWhenItemProperties | null { - const enableWhen = qItem.enableWhen; - if (enableWhen) { - const enableWhenItemProperties: EnableWhenItemProperties = { linked: [], isEnabled: false }; - enableWhenItemProperties.linked = enableWhen.map((linkedItem): EnableWhenLinkedItem => { - return { enableWhen: linkedItem }; - }); - - if (qItem.enableBehavior) { - enableWhenItemProperties.enableBehavior = qItem.enableBehavior; - } - - return enableWhenItemProperties; - } - return null; -} - -/** - * Check if an enableWhenExpression extension is present - * - * @author Sean Fong - */ -export function getEnableWhenExpression(qItem: QuestionnaireItem): Expression | null { - const itemControl = qItem.extension?.find( - (extension: Extension) => - extension.url === - 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression' && - extension.valueExpression?.language === 'text/fhirpath' - ); - if (itemControl) { - if (itemControl.valueExpression) { - return itemControl.valueExpression; - } - } - return null; -} - -/** - * Check if an calculatedExpression extension is present - * - * @author Sean Fong - */ -export function getCalculatedExpression(qItem: QuestionnaireItem): Expression | null { - const itemControl = qItem.extension?.find( - (extension: Extension) => - extension.url === - 'http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression' && - extension.valueExpression?.language === 'text/fhirpath' - ); - if (itemControl) { - if (itemControl.valueExpression) { - return itemControl.valueExpression; - } - } - return null; -} diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractTabs.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractTabs.ts deleted file mode 100644 index d0d5dc455..000000000 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractTabs.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { constructTabsWithProperties, isTabContainer } from '../../../renderer/utils/tabs.ts'; -import type { Questionnaire } from 'fhir/r4'; -import type { Tabs } from '../../../renderer/types/tab.interface.ts'; - -export function extractTabs(questionnaire: Questionnaire): Tabs { - if (!questionnaire.item || questionnaire.item.length === 0) { - return {}; - } - - let totalTabs = {}; - for (const topLevelItem of questionnaire.item) { - const items = topLevelItem.item; - const topLevelItemIsTabContainer = isTabContainer(topLevelItem); - - const tabs = constructTabsWithProperties(items, topLevelItemIsTabContainer); - totalTabs = { ...totalTabs, ...tabs }; - } - - return totalTabs; -} diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractVariables.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractVariables.ts deleted file mode 100644 index cf34a015f..000000000 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/extractVariables.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Expression, Extension, Questionnaire } from 'fhir/r4'; -import type { Variables } from '../../../prepopulate/types/populate.interface.ts'; - -export function extractQuestionnaireLevelVariables(questionnaire: Questionnaire): Variables { - const variables: Variables = { fhirPathVariables: {}, xFhirQueryVariables: {} }; - - if (!questionnaire.extension || questionnaire.extension.length === 0) { - return variables; - } - - variables.fhirPathVariables['QuestionnaireLevel'] = getFhirPathVariables(questionnaire.extension); - - for (const exp of getXFhirQueryVariables(questionnaire.extension)) { - if (exp.name) { - variables.xFhirQueryVariables[exp.name] = { - valueExpression: exp - }; - } - } - - return variables; -} - -/** - * Get fhirpath variables from an array of extensions - * - * @author Sean Fong - */ -export function getFhirPathVariables(extensions: Extension[]): Expression[] { - return ( - extensions - .filter( - (extension) => - extension.url === 'http://hl7.org/fhir/StructureDefinition/variable' && - extension.valueExpression?.language === 'text/fhirpath' - ) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - .map((extension) => extension.valueExpression!) - ); -} - -/** - * Get x-fhir-query variables from an array of extensions - * - * @author Sean Fong - */ -export function getXFhirQueryVariables(extensions: Extension[]): Expression[] { - return ( - extensions - .filter( - (extension) => - extension.url === 'http://hl7.org/fhir/StructureDefinition/variable' && - extension.valueExpression?.language === 'application/x-fhir-query' - ) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - .map((extension) => extension.valueExpression!) - ); -} diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/preprocessQuestionnaire.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/preprocessQuestionnaire.ts deleted file mode 100644 index eed182f4c..000000000 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/preprocessQuestionnaire.ts +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Questionnaire } from 'fhir/r4'; -import type { Tabs } from '../../../renderer/types/tab.interface.ts'; -import type { LaunchContext, Variables } from '../../../prepopulate/types/populate.interface.ts'; -import type { QuestionnaireModel } from '../../types/questionnaireModel.ts'; -import { extractLaunchContexts } from './extractLaunchContext.ts'; -import { extractQuestionnaireLevelVariables } from './extractVariables.ts'; -import { extractTabs } from './extractTabs.ts'; -import { extractContainedValueSets } from './extractContainedValueSets.ts'; -import { extractOtherExtensions } from './extractOtherExtensions.ts'; -import { resolveValueSets } from './resolveValueSets.ts'; - -export async function createQuestionnaireModel( - questionnaire: Questionnaire -): Promise { - if (!questionnaire.item) { - return createEmptyModel(); - } - - const tabs: Tabs = extractTabs(questionnaire); - - const launchContexts: Record = extractLaunchContexts(questionnaire); - - let variables: Variables = extractQuestionnaireLevelVariables(questionnaire); - - const extractContainedValueSetsResult = extractContainedValueSets(questionnaire); - let valueSetPromises = extractContainedValueSetsResult.valueSetPromises; - let processedValueSetCodings = extractContainedValueSetsResult.processedValueSetCodings; - const processedValueSetUrls = extractContainedValueSetsResult.processedValueSetUrls; - - const extractOtherExtensionsResult = extractOtherExtensions( - questionnaire, - variables, - valueSetPromises - ); - - const { enableWhenItems, enableWhenExpressions, calculatedExpressions, answerExpressions } = - extractOtherExtensionsResult; - variables = extractOtherExtensionsResult.variables; - valueSetPromises = extractOtherExtensionsResult.valueSetPromises; - - const resolveValueSetsResult = await resolveValueSets( - variables, - valueSetPromises, - processedValueSetCodings - ); - - variables = resolveValueSetsResult.variables; - processedValueSetCodings = resolveValueSetsResult.processedValueSetCodings; - - return { - tabs, - variables, - launchContexts, - enableWhenItems, - enableWhenExpressions, - calculatedExpressions, - answerExpressions, - processedValueSetCodings, - processedValueSetUrls - }; -} - -function createEmptyModel(): QuestionnaireModel { - return { - tabs: {}, - variables: { fhirPathVariables: {}, xFhirQueryVariables: {} }, - launchContexts: {}, - calculatedExpressions: {}, - enableWhenExpressions: {}, - answerExpressions: {}, - enableWhenItems: {}, - processedValueSetCodings: {}, - processedValueSetUrls: {} - }; -} diff --git a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/resolveValueSets.ts b/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/resolveValueSets.ts deleted file mode 100644 index e806aa7a0..000000000 --- a/apps/smart-forms-app/src/features/preprocess/utils/preprocessQuestionnaire/resolveValueSets.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2023 Commonwealth Scientific and Industrial Research - * Organisation (CSIRO) ABN 41 687 119 230. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Coding } from 'fhir/r4'; -import { - createValueSetToXFhirQueryVariableNameMap, - getValueSetCodings, - getValueSetPromise, - resolvePromises -} from '../../../../utils/valueSet.ts'; -import type { ValueSetPromise } from '../../../../types/valueSet.interface.ts'; -import type { Variables } from '../../../prepopulate/types/populate.interface.ts'; - -export async function resolveValueSets( - variables: Variables, - valueSetPromises: Record, - processedValueSetCodings: Record -): Promise<{ variables: Variables; processedValueSetCodings: Record }> { - // Create a map - const valueSetToXFhirQueryVariableNameMap: Record = - createValueSetToXFhirQueryVariableNameMap(variables.xFhirQueryVariables); - - if (Object.keys(valueSetToXFhirQueryVariableNameMap).length > 0) { - for (const valueSetUrl in valueSetToXFhirQueryVariableNameMap) { - valueSetPromises[valueSetUrl] = { - promise: getValueSetPromise(valueSetUrl) - }; - } - } - - // Resolve promises and store valueSet codings in preprocessedValueSetCodings AND XFhirQueryVariables - const resolvedPromises = await resolvePromises(valueSetPromises); - - for (const valueSetUrl in resolvedPromises) { - const valueSet = resolvedPromises[valueSetUrl].valueSet; - - if (valueSet) { - if (valueSetToXFhirQueryVariableNameMap[valueSetUrl]) { - // valueSetUrl is in x-fhir-query variables, save to variable - const variableName = valueSetToXFhirQueryVariableNameMap[valueSetUrl]; - const variable = variables.xFhirQueryVariables[variableName]; - variables.xFhirQueryVariables[variableName] = { - ...variable, - result: resolvedPromises[valueSetUrl].valueSet - }; - } else { - // valueSetUrl is in x-fhir-query variables, save to preprocessedValueSetCodings - processedValueSetCodings[valueSetUrl] = getValueSetCodings(valueSet); - } - } - } - - return { variables, processedValueSetCodings }; -} diff --git a/apps/smart-forms-app/src/features/renderer/components/RendererEmbeddedSpeedDial.tsx b/apps/smart-forms-app/src/features/renderer/components/RendererEmbeddedSpeedDial.tsx index 93bf0d797..07e1cc39e 100644 --- a/apps/smart-forms-app/src/features/renderer/components/RendererEmbeddedSpeedDial.tsx +++ b/apps/smart-forms-app/src/features/renderer/components/RendererEmbeddedSpeedDial.tsx @@ -22,7 +22,7 @@ import { useSnackbar } from 'notistack'; import EditIcon from '@mui/icons-material/Edit'; import VisibilityIcon from '@mui/icons-material/Visibility'; import cloneDeep from 'lodash.clonedeep'; -import { saveQuestionnaireResponse } from '../../save/api/saveQr.ts'; +import { saveQuestionnaireResponse } from '../../../api/saveQr.ts'; import SaveIcon from '@mui/icons-material/Save'; import TaskAltIcon from '@mui/icons-material/TaskAlt'; import { useState } from 'react'; diff --git a/apps/smart-forms-app/src/features/renderer/components/RendererNav/BlockerUnsavedFormDialog.tsx b/apps/smart-forms-app/src/features/renderer/components/RendererNav/BlockerUnsavedFormDialog.tsx index 1d2c97d37..c11d95608 100644 --- a/apps/smart-forms-app/src/features/renderer/components/RendererNav/BlockerUnsavedFormDialog.tsx +++ b/apps/smart-forms-app/src/features/renderer/components/RendererNav/BlockerUnsavedFormDialog.tsx @@ -26,7 +26,7 @@ import { DialogContentText, DialogTitle } from '@mui/material'; -import { saveQuestionnaireResponse } from '../../../save/api/saveQr.ts'; +import { saveQuestionnaireResponse } from '../../../../api/saveQr.ts'; import cloneDeep from 'lodash.clonedeep'; import { LoadingButton } from '@mui/lab'; import { diff --git a/apps/smart-forms-app/src/features/renderer/components/RendererNav/SaveAsDraft/RendererSaveAsDraft.tsx b/apps/smart-forms-app/src/features/renderer/components/RendererNav/SaveAsDraft/RendererSaveAsDraft.tsx index 0655f73ae..c13e35209 100644 --- a/apps/smart-forms-app/src/features/renderer/components/RendererNav/SaveAsDraft/RendererSaveAsDraft.tsx +++ b/apps/smart-forms-app/src/features/renderer/components/RendererNav/SaveAsDraft/RendererSaveAsDraft.tsx @@ -17,7 +17,7 @@ import SaveIcon from '@mui/icons-material/Save'; import { useEffect, useState } from 'react'; -import { saveQuestionnaireResponse } from '../../../../save/api/saveQr.ts'; +import { saveQuestionnaireResponse } from '../../../../../api/saveQr.ts'; import { RendererOperationItem } from '../RendererOperationSection.tsx'; import { useSnackbar } from 'notistack'; import cloneDeep from 'lodash.clonedeep'; diff --git a/apps/smart-forms-app/src/features/renderer/components/RendererNav/SaveAsFinal/RendererSaveAsFinalDialog.tsx b/apps/smart-forms-app/src/features/renderer/components/RendererNav/SaveAsFinal/RendererSaveAsFinalDialog.tsx index 62e6764e4..bad2d29df 100644 --- a/apps/smart-forms-app/src/features/renderer/components/RendererNav/SaveAsFinal/RendererSaveAsFinalDialog.tsx +++ b/apps/smart-forms-app/src/features/renderer/components/RendererNav/SaveAsFinal/RendererSaveAsFinalDialog.tsx @@ -19,7 +19,7 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useSnackbar } from 'notistack'; import cloneDeep from 'lodash.clonedeep'; -import { saveQuestionnaireResponse } from '../../../../save/api/saveQr.ts'; +import { saveQuestionnaireResponse } from '../../../../../api/saveQr.ts'; import { Button, Dialog, diff --git a/apps/smart-forms-app/src/features/smartAppLaunch/components/Authorisation.tsx b/apps/smart-forms-app/src/features/smartAppLaunch/components/Authorisation.tsx index c946d6881..6b5eabd51 100644 --- a/apps/smart-forms-app/src/features/smartAppLaunch/components/Authorisation.tsx +++ b/apps/smart-forms-app/src/features/smartAppLaunch/components/Authorisation.tsx @@ -23,14 +23,14 @@ import { readQuestionnaireContext, responseToQuestionnaireResource } from '../utils/launch.ts'; -import { postQuestionnaireToSMARTHealthIT } from '../../save/api/saveQr.ts'; +import { postQuestionnaireToSMARTHealthIT } from '../../../api/saveQr.ts'; import GoToTestLauncher from '../../../components/Snackbar/GoToTestLauncher.tsx'; import { useSnackbar } from 'notistack'; import { useNavigate } from 'react-router-dom'; import { StyledRoot } from './Authorisation.styles.tsx'; import type { AuthActions, AuthState } from '../types/authorisation.interface.ts'; import RenderAuthStatus from './RenderAuthStatus.tsx'; -import { assembleIfRequired } from '../../assemble/utils/assemble.ts'; +import { assembleIfRequired } from '../../../utils/assemble.ts'; import { useQuestionnaireStore } from '@aehrc/smart-forms-renderer'; import useAuthRedirectHook from '../hooks/useAuthRedirectHook.ts'; import useSmartClient from '../../../hooks/useSmartClient.ts'; diff --git a/apps/smart-forms-app/src/features/viewer/ViewerLayout.tsx b/apps/smart-forms-app/src/features/viewer/ViewerLayout.tsx index 69f48eff5..16c0b737a 100644 --- a/apps/smart-forms-app/src/features/viewer/ViewerLayout.tsx +++ b/apps/smart-forms-app/src/features/viewer/ViewerLayout.tsx @@ -24,7 +24,7 @@ import { Fab } from '@mui/material'; import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; import ViewerNav from './ViewerNav/ViewerNav.tsx'; -import type { PrintComponentRefContextType } from '../print/types/printComponentRefContext.type.ts'; +import type { PrintComponentRefContextType } from '../../types/printComponentRefContext.type.ts'; import GenericHeader from '../../components/Header/GenericHeader.tsx'; export const PrintComponentRefContext = createContext({ diff --git a/apps/smart-forms-app/src/features/viewer/ViewerNav/SaveAsFinal/ViewerSaveAsFinalDialog.tsx b/apps/smart-forms-app/src/features/viewer/ViewerNav/SaveAsFinal/ViewerSaveAsFinalDialog.tsx index 2a15f13e9..623bc1975 100644 --- a/apps/smart-forms-app/src/features/viewer/ViewerNav/SaveAsFinal/ViewerSaveAsFinalDialog.tsx +++ b/apps/smart-forms-app/src/features/viewer/ViewerNav/SaveAsFinal/ViewerSaveAsFinalDialog.tsx @@ -19,7 +19,7 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { useSnackbar } from 'notistack'; import cloneDeep from 'lodash.clonedeep'; -import { saveQuestionnaireResponse } from '../../../save/api/saveQr.ts'; +import { saveQuestionnaireResponse } from '../../../../api/saveQr.ts'; import { Button, Dialog, diff --git a/apps/smart-forms-app/src/features/calculatedExpression/types/calculatedExpression.interface.ts b/apps/smart-forms-app/src/types/calculatedExpression.interface.ts similarity index 100% rename from apps/smart-forms-app/src/features/calculatedExpression/types/calculatedExpression.interface.ts rename to apps/smart-forms-app/src/types/calculatedExpression.interface.ts diff --git a/apps/smart-forms-app/src/features/print/types/printComponentRefContext.type.ts b/apps/smart-forms-app/src/types/printComponentRefContext.type.ts similarity index 87% rename from apps/smart-forms-app/src/features/print/types/printComponentRefContext.type.ts rename to apps/smart-forms-app/src/types/printComponentRefContext.type.ts index 9dea920d3..766976d65 100644 --- a/apps/smart-forms-app/src/features/print/types/printComponentRefContext.type.ts +++ b/apps/smart-forms-app/src/types/printComponentRefContext.type.ts @@ -17,10 +17,6 @@ import type { MutableRefObject } from 'react'; -export type CurrentTabIndexContextType = { - currentTabIndex: number; - setCurrentTabIndex: (updatedIndex: number) => unknown; -}; export type PrintComponentRefContextType = { componentRef: MutableRefObject | null; setComponentRef: (componentRef: MutableRefObject) => unknown; diff --git a/apps/smart-forms-app/src/features/assemble/utils/assemble.ts b/apps/smart-forms-app/src/utils/assemble.ts similarity index 96% rename from apps/smart-forms-app/src/features/assemble/utils/assemble.ts rename to apps/smart-forms-app/src/utils/assemble.ts index 07f1145c2..42451c91c 100644 --- a/apps/smart-forms-app/src/features/assemble/utils/assemble.ts +++ b/apps/smart-forms-app/src/utils/assemble.ts @@ -18,8 +18,8 @@ import type { Extension, OperationOutcome, Parameters, Questionnaire } from 'fhir/r4'; import { isInputParameters } from 'sdc-assemble'; import * as FHIR from 'fhirclient'; -import { HEADERS } from '../../../api/headers.ts'; -import { getFormsServerAssembledBundlePromise } from '../../dashboard/utils/dashboard.ts'; +import { HEADERS } from '../api/headers.ts'; +import { getFormsServerAssembledBundlePromise } from '../features/dashboard/utils/dashboard.ts'; const endpointUrl = import.meta.env.VITE_FORMS_SERVER_URL ?? 'https://api.smartforms.io/fhir'; diff --git a/apps/smart-forms-app/src/utils/calculatedExpressions.ts b/apps/smart-forms-app/src/utils/calculatedExpressions.ts index 0a158c30f..d23c20fc4 100644 --- a/apps/smart-forms-app/src/utils/calculatedExpressions.ts +++ b/apps/smart-forms-app/src/utils/calculatedExpressions.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import type { CalculatedExpression } from '../features/calculatedExpression/types/calculatedExpression.interface.ts'; +import type { CalculatedExpression } from '../types/calculatedExpression.interface.ts'; import fhirpath from 'fhirpath'; import fhirpath_r4_model from 'fhirpath/fhir-context/r4'; import type { diff --git a/apps/smart-forms-app/src/utils/fhirpath.ts b/apps/smart-forms-app/src/utils/fhirpath.ts index 8407393ed..b44d6ade9 100644 --- a/apps/smart-forms-app/src/utils/fhirpath.ts +++ b/apps/smart-forms-app/src/utils/fhirpath.ts @@ -18,7 +18,7 @@ import fhirpath from 'fhirpath'; import fhirpath_r4_model from 'fhirpath/fhir-context/r4'; import type { Expression, QuestionnaireResponse, QuestionnaireResponseItem } from 'fhir/r4'; -import type { CalculatedExpression } from '../features/calculatedExpression/types/calculatedExpression.interface.ts'; +import type { CalculatedExpression } from '../types/calculatedExpression.interface.ts'; import type { EnableWhenExpression } from '../types/enableWhen.interface.ts'; import { evaluateEnableWhenExpressions } from './enableWhenExpression.ts'; import { evaluateCalculatedExpressions } from './calculatedExpressions.ts'; diff --git a/apps/smart-forms-app/src/utils/initaliseForm.ts b/apps/smart-forms-app/src/utils/initaliseForm.ts index f303d9434..d60a16d22 100644 --- a/apps/smart-forms-app/src/utils/initaliseForm.ts +++ b/apps/smart-forms-app/src/utils/initaliseForm.ts @@ -4,7 +4,7 @@ import type { Expression, QuestionnaireResponse } from 'fhir/r4'; import type { EnableWhenExpression, EnableWhenItems } from '../types/enableWhen.interface.ts'; import type { Tabs } from '../features/renderer/types/tab.interface.ts'; import { assignPopulatedAnswersToEnableWhen } from './enableWhen.ts'; -import type { CalculatedExpression } from '../features/calculatedExpression/types/calculatedExpression.interface.ts'; +import type { CalculatedExpression } from '../types/calculatedExpression.interface.ts'; import { evaluateInitialCalculatedExpressions } from './calculatedExpressions.ts'; interface initialFormFromResponseParams {