From 155a001d7aa9d7af17bf84c0d212e56b3cc5a8b4 Mon Sep 17 00:00:00 2001 From: ojwanganto Date: Mon, 8 Jan 2024 17:03:49 +0300 Subject: [PATCH] (fix) Enhance result form to handle non-set order concepts --- src/results/result-form-field.component.tsx | 74 +++++++ src/results/result-form.component.tsx | 129 +++++------ src/results/result-form.resource.ts | 35 +-- src/results/single-result-form.component.tsx | 214 ------------------- src/work-list/work-list.component.tsx | 4 +- 5 files changed, 128 insertions(+), 328 deletions(-) create mode 100644 src/results/result-form-field.component.tsx delete mode 100644 src/results/single-result-form.component.tsx diff --git a/src/results/result-form-field.component.tsx b/src/results/result-form-field.component.tsx new file mode 100644 index 0000000..9612e47 --- /dev/null +++ b/src/results/result-form-field.component.tsx @@ -0,0 +1,74 @@ +import React, { useState } from "react"; +import styles from "./result-form.scss"; +import { TextInput, Select, SelectItem } from "@carbon/react"; +import { useTranslation } from "react-i18next"; + +import { ConceptReference } from "./result-form.resource"; + +interface ResultFormFieldProps { + concept: ConceptReference; +} +const ResultFormField: React.FC = ({ concept }) => { + const { t } = useTranslation(); + const [inputValues, setInputValues] = useState({}); + + // getInput values + const handleInputChange = (memberUuid, value) => { + setInputValues((prevValues) => ({ + ...prevValues, + [memberUuid]: value, + })); + }; + + // create input fields + if (concept === undefined) { + return null; + } + + let inputField; + if ( + concept.datatype?.display === "Text" || + concept.datatype?.display === "Numeric" + ) { + inputField = ( + handleInputChange(concept.uuid, e.target.value)} + /> + ); + } else if (concept?.datatype?.display === "Coded") { + inputField = ( + + ); + } + return <>{inputField}; +}; + +export default ResultFormField; diff --git a/src/results/result-form.component.tsx b/src/results/result-form.component.tsx index 1540049..2f96a18 100644 --- a/src/results/result-form.component.tsx +++ b/src/results/result-form.component.tsx @@ -1,15 +1,6 @@ import React, { useMemo, useState } from "react"; import styles from "./result-form.scss"; -import { - Button, - InlineLoading, - TextInput, - Select, - SelectItem, - ModalBody, - ModalFooter, - ModalHeader, -} from "@carbon/react"; +import { Button, InlineLoading, ModalBody, ModalFooter } from "@carbon/react"; import { useTranslation } from "react-i18next"; import { closeOverlay } from "../components/overlay/hook"; import { @@ -23,6 +14,7 @@ import { useGetOrderConceptByUuid, } from "./result-form.resource"; import { Result } from "../work-list/work-list.resource"; +import ResultFormField from "./result-form-field.component"; interface ResultFormProps { patientUuid: string; @@ -38,9 +30,9 @@ const ResultForm: React.FC = ({ order, patientUuid }) => { const [isSubmitting, setIsSubmitting] = useState(false); + const [selectedOption, setSelectedOption] = useState(); const [inputValues, setInputValues] = useState({}); - const [selectedOption, setSelectedOption] = useState(); const bannerState = useMemo(() => { if (patient) { @@ -52,67 +44,23 @@ const ResultForm: React.FC = ({ order, patientUuid }) => { } }, [patient, patientUuid]); - // getInput values - const handleInputChange = (memberUuid, value) => { - setInputValues((prevValues) => ({ - ...prevValues, - [memberUuid]: value, - })); - }; - // create input fields - const Questions = ({ conceptMembers }) => { + const Questions = ({ concept }) => { const inputFields = useMemo(() => { - return conceptMembers.map((member) => { - let inputField; - - if ( - member.datatype.display === "Text" || - member.datatype.display === "Numeric" - ) { - inputField = ( - handleInputChange(member.uuid, e.target.value)} - /> - ); - } else if (member.datatype.display === "Coded") { - inputField = ( - - ); - } + if (concept === undefined) { + return null; + } - return inputField; - }); - }, [conceptMembers]); // Memoize when conceptMembers changes + if (concept.set && concept.setMembers.length > 0) { + return concept.setMembers.map((member) => { + let inputField = ; + return inputField; + }); + } else if (!concept.set && concept.setMembers.length === 0) { + let inputField = ; + return <>{inputField}; + } + }, [concept]); // Memoize when conceptMembers changes return <>{inputFields}; }; @@ -128,26 +76,49 @@ const ResultForm: React.FC = ({ order, patientUuid }) => { order: { uuid: order.uuid }, groupMembers: groupMembers, }; - concept.forEach((item) => { + + if (concept.set && concept.setMembers.length > 0) { + concept.setMembers.forEach((item) => { + let value; + if ( + item.datatype.display === "Numeric" || + item.datatype.display === "Text" + ) { + value = inputValues[`${item.uuid}`]; + } else if (item.datatype.display === "Coded") { + value = { + uuid: inputValues[`${item.uuid}`], + }; + } + const groupMember = { + concept: { uuid: item.uuid }, + value: value, + status: "FINAL", + order: { uuid: order.uuid }, + }; + groupMembers.push(groupMember); + }); + } else if (!concept.set && concept.setMembers.length === 0) { let value; if ( - item.datatype.display === "Numeric" || - item.datatype.display === "Text" + concept.datatype.display === "Numeric" || + concept.datatype.display === "Text" ) { - value = inputValues[`${item.uuid}`]; - } else if (item.datatype.display === "Coded") { + value = inputValues[`${concept.uuid}`]; + } else if (concept.datatype.display === "Coded") { value = { - uuid: inputValues[`${item.uuid}`], + uuid: inputValues[`${concept.uuid}`], }; } const groupMember = { - concept: { uuid: item.uuid }, + concept: { uuid: concept.uuid }, value: value, status: "FINAL", order: { uuid: order.uuid }, }; groupMembers.push(groupMember); - }); + } + obsValue.push(ob); const payload = { @@ -198,9 +169,9 @@ const ResultForm: React.FC = ({ order, patientUuid }) => { )} - {concept?.length > 0 && ( + {concept && (
- +
)} diff --git a/src/results/result-form.resource.ts b/src/results/result-form.resource.ts index 87628ea..3cd33f5 100644 --- a/src/results/result-form.resource.ts +++ b/src/results/result-form.resource.ts @@ -14,23 +14,13 @@ export interface ConceptResponse { descriptions: Description[]; mappings: Mapping[]; answers: any[]; - setMembers: ConceptResponse[]; + setMembers: ConceptReference[]; auditInfo: AuditInfo; attributes: any[]; links: Link18[]; resourceVersion: string; } -export interface ConceptMiniResponse { - uuid: string; - display: string; - name: Name; - datatype: Datatype; - conceptClass: ConceptClass; - set: boolean; - answers: any[]; -} - export interface Name { display: string; uuid: string; @@ -152,7 +142,7 @@ export interface Link8 { resourceAlias: string; } -export interface SetMember { +export interface ConceptReference { uuid: string; display: string; name: Name3; @@ -315,11 +305,8 @@ export function useGetOrderConceptByUuid(uuid: string) { { data: ConceptResponse }, Error >(apiUrl, openmrsFetch); - console.log("Mini concept data: ", data); - const defList = new Array(); - defList.push(data?.data); return { - concept: data?.data ? data?.data.setMembers : defList, + concept: data?.data, isLoading, isError: error, isValidating, @@ -327,22 +314,6 @@ export function useGetOrderConceptByUuid(uuid: string) { }; } -export function useGetOrderConceptDetailsByUuid(uuid: string) { - const apiUrl = `/ws/rest/v1/concept/${uuid}?v=full`; - const { data, error, isLoading, isValidating, mutate } = useSWR< - { data: ConceptResponse }, - Error - >(apiUrl, openmrsFetch); - console.log("log url", data); - - return { - concept: data?.data ?? {}, - isLoading, - isError: error, - isValidating, - mutate, - }; -} // create observation export async function UpdateEncounter(uuid: string, payload: any) { const abortController = new AbortController(); diff --git a/src/results/single-result-form.component.tsx b/src/results/single-result-form.component.tsx deleted file mode 100644 index 0424455..0000000 --- a/src/results/single-result-form.component.tsx +++ /dev/null @@ -1,214 +0,0 @@ -import React, { useMemo, useState } from "react"; -import styles from "./result-form.scss"; -import { - Button, - InlineLoading, - TextInput, - Select, - SelectItem, - ModalBody, - ModalFooter, - ModalHeader, -} from "@carbon/react"; -import { useTranslation } from "react-i18next"; -import { closeOverlay } from "../components/overlay/hook"; -import { - ExtensionSlot, - showNotification, - showToast, - usePatient, -} from "@openmrs/esm-framework"; -import { - UpdateEncounter, - useGetOrderConceptByUuid, - useGetOrderConceptDetailsByUuid, - ConceptMiniResponse, -} from "./result-form.resource"; -import { Result } from "../work-list/work-list.resource"; - -interface ResultFormProps { - patientUuid: string; - order: Result; -} - -const LabResultForm: React.FC = ({ order, patientUuid }) => { - const { t } = useTranslation(); - const { patient, isLoading } = usePatient(patientUuid); - - const { concept } = useGetOrderConceptDetailsByUuid(order.concept.uuid); - - const [isSubmitting, setIsSubmitting] = useState(false); - - const [inputValues, setInputValues] = useState({}); - - const [selectedOption, setSelectedOption] = useState(); - - const bannerState = useMemo(() => { - if (patient) { - return { - patient, - patientUuid, - hideActionsOverflow: true, - }; - } - }, [patient, patientUuid]); - - // getInput values - const handleInputChange = (memberUuid, value) => { - setInputValues((prevValues) => ({ - ...prevValues, - [memberUuid]: value, - })); - }; - - // create input fields - const Questions = ({ concept }) => { - console.log(`Datatype: ${concept?.datatype?.display}`); - - let inputField; - if ( - concept?.datatype?.display === "Text" || - concept?.datatype?.display === "Numeric" - ) { - inputField = ( - handleInputChange(concept.uuid, e.target.value)} - /> - ); - } else if (concept?.datatype?.display === "Coded") { - inputField = ( - - ); - } - return <>{inputField}; - }; - - const handleSubmit = (e) => { - e.preventDefault(); - // assign value to test - let groupMembers = []; - let obsValue = []; - const ob = { - concept: { uuid: order.concept.uuid }, - status: "FINAL", - order: { uuid: order.uuid }, - groupMembers: groupMembers, - }; - // concept.forEach((item) => { - // let value; - // if ( - // item.datatype.display === "Numeric" || - // item.datatype.display === "Text" - // ) { - // value = inputValues[`${item.uuid}`]; - // } else if (item.datatype.display === "Coded") { - // value = { - // uuid: inputValues[`${item.uuid}`], - // }; - // } - // const groupMember = { - // concept: { uuid: item.uuid }, - // value: value, - // status: "FINAL", - // order: { uuid: order.uuid }, - // }; - // groupMembers.push(groupMember); - // }); - obsValue.push(ob); - - const payload = { - obs: obsValue, - }; - setIsSubmitting(true); - // update encounter - UpdateEncounter(order.encounter.uuid, payload).then( - () => { - setIsSubmitting(false); - showToast({ - critical: true, - title: t("updateEncounter", "Update Encounter"), - kind: "success", - description: t( - "generateSuccessfully", - "You have successfully encounter with test results" - ), - }); - }, - (err) => { - setIsSubmitting(false); - showNotification({ - title: t( - `errorUpdatingEncounter', 'Error occurred while updating encounter` - ), - kind: "error", - critical: true, - description: err?.message, - }); - } - ); - }; - - return ( - <> -
- - {isLoading && ( - - )} - {patient && ( - - )} - - - - - - - -
- - ); -}; - -export default LabResultForm; diff --git a/src/work-list/work-list.component.tsx b/src/work-list/work-list.component.tsx index a19c499..6487f70 100644 --- a/src/work-list/work-list.component.tsx +++ b/src/work-list/work-list.component.tsx @@ -47,7 +47,6 @@ import { import { launchOverlay } from "../components/overlay/hook"; import ResultForm from "../results/result-form.component"; import { getStatusColor } from "../utils/functions"; -import LabResultForm from "../results/single-result-form.component"; interface WorklistProps { fulfillerStatus: string; @@ -127,8 +126,7 @@ const WorkList: React.FC = ({ fulfillerStatus }) => { onClick={() => { launchOverlay( t("resultForm", "Result Tests"), - // - + ); }} renderIcon={(props) => }