diff --git a/apps/smart-forms-app/package.json b/apps/smart-forms-app/package.json index 7ebeb3011..26b0e2b3a 100644 --- a/apps/smart-forms-app/package.json +++ b/apps/smart-forms-app/package.json @@ -26,8 +26,9 @@ "homepage": "https://github.com/aehrc/smart-forms#readme", "dependencies": { "@aehrc/sdc-assemble": "^1.2.0", - "@aehrc/sdc-populate": "^1.3.0", - "@aehrc/smart-forms-renderer": "^0.10.5", + "@aehrc/sdc-populate": "^1.4.1", + "@aehrc/fhir-questionnaire-helpers": "^0.1.0", + "@aehrc/smart-forms-renderer": "^0.10.6", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.10.8", "@fontsource/material-icons": "^5.0.7", diff --git a/apps/smart-forms-app/vite.config.ts b/apps/smart-forms-app/vite.config.ts index 3436febf3..175706294 100644 --- a/apps/smart-forms-app/vite.config.ts +++ b/apps/smart-forms-app/vite.config.ts @@ -6,11 +6,16 @@ import svgr from 'vite-plugin-svgr'; export default defineConfig({ plugins: [react(), svgr()], optimizeDeps: { - include: ['@aehrc/sdc-assemble', '@aehrc/sdc-populate'] + include: ['@aehrc/sdc-assemble', '@aehrc/sdc-populate', '@aehrc/fhir-questionnaire-helpers'] }, build: { commonjsOptions: { - include: [/node_modules/, '@aehrc/sdc-assemble', '@aehrc/sdc-populate'] + include: [ + /node_modules/, + '@aehrc/sdc-assemble', + '@aehrc/sdc-populate', + '@aehrc/fhir-questionnaire-helpers' + ] } }, resolve: { preserveSymlinks: true } diff --git a/package-lock.json b/package-lock.json index 39ad4fb7b..1dcaafac1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,9 +47,10 @@ "version": "0.2.0", "license": "Apache-2.0", "dependencies": { + "@aehrc/fhir-questionnaire-helpers": "^0.1.0", "@aehrc/sdc-assemble": "^1.2.0", - "@aehrc/sdc-populate": "^1.3.0", - "@aehrc/smart-forms-renderer": "^0.10.5", + "@aehrc/sdc-populate": "^1.4.1", + "@aehrc/smart-forms-renderer": "^0.10.6", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.10.8", "@fontsource/material-icons": "^5.0.7", @@ -395,6 +396,10 @@ "dev": true, "license": "MIT" }, + "node_modules/@aehrc/fhir-questionnaire-helpers": { + "resolved": "packages/fhir-questionnaire-helpers", + "link": true + }, "node_modules/@aehrc/sdc-assemble": { "resolved": "packages/sdc-assemble", "link": true @@ -21000,6 +21005,19 @@ "dev": true, "license": "MIT" }, + "node_modules/fhir-extension-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/fhir-extension-helpers/-/fhir-extension-helpers-0.3.0.tgz", + "integrity": "sha512-P08MTFuWjfTPOeXEfDGDV7dSXlCzlU5JxMo4D3dZ8ykc15uiWAOKw5nVqzcZlVyNrzB5J4AyqYLH9O35zned1g==" + }, + "node_modules/fhir-sdc-helpers": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fhir-sdc-helpers/-/fhir-sdc-helpers-0.1.0.tgz", + "integrity": "sha512-oJGB4Cvfz6vx3gvxP/ZnviKLXpxx6VwOAWoQygBWDsXtGZJEaupw4pk1SzXQeXpPBbk6cv6u5YRZ/CKVESt89A==", + "dependencies": { + "fhir-extension-helpers": "^0.3.0" + } + }, "node_modules/fhirclient": { "version": "2.5.2", "license": "Apache-2.0", @@ -34018,6 +34036,17 @@ } } }, + "packages/fhir-questionnaire-helpers": { + "name": "@aehrc/fhir-questionnaire-helpers", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "fhirpath": "^3.7.1" + }, + "devDependencies": { + "@types/fhir": "^0.0.38" + } + }, "packages/sdc-assemble": { "name": "@aehrc/sdc-assemble", "version": "1.2.0", @@ -34034,10 +34063,12 @@ }, "packages/sdc-populate": { "name": "@aehrc/sdc-populate", - "version": "1.3.0", + "version": "1.4.1", "license": "Apache-2.0", "dependencies": { + "@aehrc/fhir-questionnaire-helpers": "^0.1.0", "dayjs": "^1.11.10", + "fhir-sdc-helpers": "^0.1.0", "fhirclient": "^2.5.2", "fhirpath": "^3.7.1", "moment": "^2.29.4" @@ -34052,9 +34083,10 @@ }, "packages/smart-forms-renderer": { "name": "@aehrc/smart-forms-renderer", - "version": "0.10.5", + "version": "0.10.6", "license": "Apache-2.0", "dependencies": { + "@aehrc/fhir-questionnaire-helpers": "^0.1.0", "@iconify/react": "^4.1.1", "@types/fhir": "^0.0.38", "dayjs": "^1.11.10", diff --git a/packages/fhir-questionnaire-helpers/.gitignore b/packages/fhir-questionnaire-helpers/.gitignore new file mode 100644 index 000000000..491fc3597 --- /dev/null +++ b/packages/fhir-questionnaire-helpers/.gitignore @@ -0,0 +1,2 @@ +node_modules +lib diff --git a/packages/fhir-questionnaire-helpers/README.md b/packages/fhir-questionnaire-helpers/README.md new file mode 100644 index 000000000..c5567c716 --- /dev/null +++ b/packages/fhir-questionnaire-helpers/README.md @@ -0,0 +1,3 @@ +# FHIR Questionnaire Helpers + +A Typescript library for questionnaire helper functions used in Smart Forms, smart-forms-renderer, sdc-populate and sdc-assemble. diff --git a/packages/fhir-questionnaire-helpers/package.json b/packages/fhir-questionnaire-helpers/package.json new file mode 100644 index 000000000..76d553cb2 --- /dev/null +++ b/packages/fhir-questionnaire-helpers/package.json @@ -0,0 +1,26 @@ +{ + "name": "@aehrc/fhir-questionnaire-helpers", + "version": "0.1.0", + "main": "lib/index.js", + "scripts": { + "compile": "tsc", + "watch": "tsc -w", + "prepare": "npm run compile" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/aehrc/smart-forms.git" + }, + "author": "Sean Fong", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/aehrc/smart-forms/issues" + }, + "homepage": "https://github.com/aehrc/smart-forms#readme", + "dependencies": { + "fhirpath": "^3.7.1" + }, + "devDependencies": { + "@types/fhir": "^0.0.38" + } +} diff --git a/packages/fhir-questionnaire-helpers/src/answerOption.ts b/packages/fhir-questionnaire-helpers/src/answerOption.ts new file mode 100644 index 000000000..9b0f127a9 --- /dev/null +++ b/packages/fhir-questionnaire-helpers/src/answerOption.ts @@ -0,0 +1,56 @@ +/* + * 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 { QuestionnaireItemAnswerOption, QuestionnaireResponseItemAnswer } from 'fhir/r4'; + +/** + * Find and return corresponding answerOption based on selected answer in form + * + * @author Sean Fong + */ +export function findInAnswerOptions( + options: QuestionnaireItemAnswerOption[], + str: string +): QuestionnaireResponseItemAnswer | undefined { + for (const option of options) { + if (option.valueCoding) { + if (str === option.valueCoding.code) { + return { + valueCoding: option.valueCoding + }; + } + } + + if (option.valueString) { + if (str === option.valueString) { + return { + valueString: option.valueString + }; + } + } + + if (option.valueInteger) { + if (str === option.valueInteger.toString()) { + return { + valueInteger: option.valueInteger + }; + } + } + } + + return; +} diff --git a/packages/fhir-questionnaire-helpers/src/index.ts b/packages/fhir-questionnaire-helpers/src/index.ts new file mode 100644 index 000000000..323605c37 --- /dev/null +++ b/packages/fhir-questionnaire-helpers/src/index.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export { findInAnswerOptions } from './answerOption'; diff --git a/packages/fhir-questionnaire-helpers/tsconfig.json b/packages/fhir-questionnaire-helpers/tsconfig.json new file mode 100644 index 000000000..f1baf8d14 --- /dev/null +++ b/packages/fhir-questionnaire-helpers/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ES6", + "module": "CommonJS", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "moduleResolution": "node", + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true, + "jsx": "react", + "sourceMap": true, + "allowJs": true, + "outDir": "lib", + "declaration": true, + "checkJs": true, + "resolveJsonModule": true, + + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "exactOptionalPropertyTypes": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noUncheckedIndexedAccess": true, + "noUnusedParameters": true + }, + "include": ["src"], + "exclude": ["lib"] +} diff --git a/packages/sdc-populate/package.json b/packages/sdc-populate/package.json index 44de72866..1528e3532 100644 --- a/packages/sdc-populate/package.json +++ b/packages/sdc-populate/package.json @@ -1,6 +1,6 @@ { "name": "@aehrc/sdc-populate", - "version": "1.3.0", + "version": "1.4.1", "description": "Performs the $populate operation from the HL7 FHIR SDC (Structured Data Capture) specification: http://hl7.org/fhir/uv/sdc", "main": "lib/index.js", "scripts": { @@ -20,10 +20,12 @@ }, "homepage": "https://github.com/aehrc/smart-forms#readme", "dependencies": { + "@aehrc/fhir-questionnaire-helpers": "^0.1.0", "dayjs": "^1.11.10", - "moment": "^2.29.4", + "fhir-sdc-helpers": "^0.1.0", "fhirclient": "^2.5.2", - "fhirpath": "^3.7.1" + "fhirpath": "^3.7.1", + "moment": "^2.29.4" }, "devDependencies": { "@jest/globals": "^29.3.1", diff --git a/packages/sdc-populate/src/utils/constructResponse.ts b/packages/sdc-populate/src/utils/constructResponse.ts index 5c0f8ec6c..bbfcf8b1f 100644 --- a/packages/sdc-populate/src/utils/constructResponse.ts +++ b/packages/sdc-populate/src/utils/constructResponse.ts @@ -36,6 +36,7 @@ import moment from 'moment'; import dayjs from 'dayjs'; import fhirpath from 'fhirpath'; import fhirpath_r4_model from 'fhirpath/fhir-context/r4'; +import { findInAnswerOptions } from '@aehrc/fhir-questionnaire-helpers'; /** * Constructs a questionnaireResponse recursively from a specified questionnaire, its subject and its initialExpressions @@ -389,14 +390,10 @@ function itemIsHidden(item: QuestionnaireItem): boolean { function parseValueToAnswer(qItem: QuestionnaireItem, value: any): QuestionnaireResponseItemAnswer { if (qItem.answerOption) { - const answerOption = qItem.answerOption.find( - (option: QuestionnaireItemAnswerOption) => option.valueCoding?.code === value?.code - ); + const answerOption = findInAnswerOptions(qItem.answerOption, value); if (answerOption) { - return { - valueCoding: answerOption.valueCoding - }; + return answerOption; } } diff --git a/packages/smart-forms-renderer/package.json b/packages/smart-forms-renderer/package.json index 0e16b08c4..8aa512197 100644 --- a/packages/smart-forms-renderer/package.json +++ b/packages/smart-forms-renderer/package.json @@ -1,6 +1,6 @@ { "name": "@aehrc/smart-forms-renderer", - "version": "0.10.5", + "version": "0.10.6", "description": "FHIR Structured Data Captured (SDC) rendering engine for Smart Forms", "main": "lib/index.js", "scripts": { @@ -24,6 +24,7 @@ }, "homepage": "https://github.com/aehrc/smart-forms#readme", "dependencies": { + "@aehrc/fhir-questionnaire-helpers": "^0.1.0", "@iconify/react": "^4.1.1", "@types/fhir": "^0.0.38", "dayjs": "^1.11.10", diff --git a/packages/smart-forms-renderer/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.tsx b/packages/smart-forms-renderer/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.tsx index 060b02153..1c0bccdf1 100644 --- a/packages/smart-forms-renderer/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.tsx +++ b/packages/smart-forms-renderer/src/components/FormComponents/ChoiceItems/ChoiceRadioAnswerOptionItem.tsx @@ -19,7 +19,7 @@ import React from 'react'; import Grid from '@mui/material/Grid'; import type { ChoiceItemOrientation } from '../../../interfaces/choice.enum'; import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { findInAnswerOptions, getQrChoiceValue } from '../../../utils/choice'; +import { getQrChoiceValue } from '../../../utils/choice'; import { createEmptyQrItem } from '../../../utils/qrItem'; import { FullWidthFormComponentBox } from '../../Box.styles'; import useRenderingExtensions from '../../../hooks/useRenderingExtensions'; @@ -32,6 +32,7 @@ import DisplayInstructions from '../DisplayItem/DisplayInstructions'; import LabelWrapper from '../ItemParts/ItemLabelWrapper'; import ChoiceRadioAnswerOptionFields from './ChoiceRadioAnswerOptionFields'; import useReadOnly from '../../../hooks/useReadOnly'; +import { findInAnswerOptions } from '@aehrc/fhir-questionnaire-helpers'; interface ChoiceRadioAnswerOptionItemProps extends PropsWithQrItemChangeHandler, diff --git a/packages/smart-forms-renderer/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.tsx b/packages/smart-forms-renderer/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.tsx index 3b6e0b3a8..3ebfaa0ad 100644 --- a/packages/smart-forms-renderer/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.tsx +++ b/packages/smart-forms-renderer/src/components/FormComponents/ChoiceItems/ChoiceSelectAnswerOptionItem.tsx @@ -19,7 +19,7 @@ import React from 'react'; import Grid from '@mui/material/Grid'; import type { QuestionnaireItem, QuestionnaireResponseItem } from 'fhir/r4'; -import { findInAnswerOptions, getQrChoiceValue } from '../../../utils/choice'; +import { getQrChoiceValue } from '../../../utils/choice'; import { createEmptyQrItem } from '../../../utils/qrItem'; import { FullWidthFormComponentBox } from '../../Box.styles'; import useRenderingExtensions from '../../../hooks/useRenderingExtensions'; @@ -33,6 +33,7 @@ import DisplayInstructions from '../DisplayItem/DisplayInstructions'; import LabelWrapper from '../ItemParts/ItemLabelWrapper'; import ChoiceSelectAnswerOptionFields from './ChoiceSelectAnswerOptionFields'; import useReadOnly from '../../../hooks/useReadOnly'; +import { findInAnswerOptions } from '@aehrc/fhir-questionnaire-helpers'; interface ChoiceSelectAnswerOptionItemProps extends PropsWithQrItemChangeHandler, diff --git a/packages/smart-forms-renderer/src/components/FormComponents/OpenChoiceItems/OpenChoiceRadioAnswerOptionItem.tsx b/packages/smart-forms-renderer/src/components/FormComponents/OpenChoiceItems/OpenChoiceRadioAnswerOptionItem.tsx index ca7f1ac6c..f1051aed1 100644 --- a/packages/smart-forms-renderer/src/components/FormComponents/OpenChoiceItems/OpenChoiceRadioAnswerOptionItem.tsx +++ b/packages/smart-forms-renderer/src/components/FormComponents/OpenChoiceItems/OpenChoiceRadioAnswerOptionItem.tsx @@ -23,7 +23,7 @@ import { createEmptyQrItem } from '../../../utils/qrItem'; import { getOpenLabelText } from '../../../utils/itemControl'; import { getOldOpenLabelAnswer } from '../../../utils/openChoice'; import { FullWidthFormComponentBox } from '../../Box.styles'; -import { findInAnswerOptions, getQrChoiceValue } from '../../../utils/choice'; +import { getQrChoiceValue } from '../../../utils/choice'; import useRenderingExtensions from '../../../hooks/useRenderingExtensions'; import type { PropsWithIsRepeatedAttribute, @@ -34,6 +34,7 @@ import DisplayInstructions from '../DisplayItem/DisplayInstructions'; import LabelWrapper from '../ItemParts/ItemLabelWrapper'; import OpenChoiceRadioAnswerOptionFields from './OpenChoiceRadioAnswerOptionFields'; import useReadOnly from '../../../hooks/useReadOnly'; +import { findInAnswerOptions } from '@aehrc/fhir-questionnaire-helpers'; interface OpenChoiceRadioAnswerOptionItemProps extends PropsWithQrItemChangeHandler, diff --git a/packages/smart-forms-renderer/src/utils/choice.ts b/packages/smart-forms-renderer/src/utils/choice.ts index feb7c1601..169206b2b 100644 --- a/packages/smart-forms-renderer/src/utils/choice.ts +++ b/packages/smart-forms-renderer/src/utils/choice.ts @@ -25,6 +25,7 @@ import type { } from 'fhir/r4'; import { ChoiceItemControl, ChoiceItemOrientation } from '../interfaces/choice.enum'; import { isSpecificItemControl } from './itemControl'; +import { findInAnswerOptions } from '@aehrc/fhir-questionnaire-helpers'; /** * Get choice control type based on certain criteria in choice items @@ -58,38 +59,6 @@ export function getChoiceControlType(qItem: QuestionnaireItem) { } } -/** - * Find and return corresponding answerOption based on selected answer in form - * - * @author Sean Fong - */ -export function findInAnswerOptions( - answerOptions: QuestionnaireItemAnswerOption[], - selected: string -): QuestionnaireResponseItemAnswer | undefined { - for (const option of answerOptions) { - if (option['valueCoding']) { - if (selected === option.valueCoding.code) { - return { - valueCoding: option.valueCoding - }; - } - } else if (option['valueString']) { - if (selected === option.valueString) { - return { - valueString: option.valueString - }; - } - } else if (option['valueInteger']) { - if (selected === option.valueInteger.toString()) { - return { - valueInteger: option.valueInteger - }; - } - } - } -} - /** * Find and return corresponding coding from AnswerValyeSet based on selected answer in form * diff --git a/packages/smart-forms-renderer/src/utils/openChoice.ts b/packages/smart-forms-renderer/src/utils/openChoice.ts index 63b5e53f8..fc8dac1a8 100644 --- a/packages/smart-forms-renderer/src/utils/openChoice.ts +++ b/packages/smart-forms-renderer/src/utils/openChoice.ts @@ -24,7 +24,8 @@ import type { } from 'fhir/r4'; import { CheckBoxOption, OpenChoiceItemControl } from '../interfaces/choice.enum'; import { isSpecificItemControl } from './itemControl'; -import { findInAnswerOptions, findInAnswerValueSetCodings } from './choice'; +import { findInAnswerValueSetCodings } from './choice'; +import { findInAnswerOptions } from '@aehrc/fhir-questionnaire-helpers'; /** * Update open-choice checkbox group answers based on checkbox changes