Skip to content

Commit

Permalink
(feat) The lab order form should have a reason for ordering field (#1458
Browse files Browse the repository at this point in the history
)

* (feat): Lab form should have "reason for ordering

* Code review changes

* More fixes

* code review changes

* Code review changes and conflix fixes

* More review changes

* Remove concept label from config
  • Loading branch information
makombe authored Feb 16, 2024
1 parent 83542a7 commit 8be52b2
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 3 deletions.
1 change: 1 addition & 0 deletions packages/esm-patient-common-lib/src/orders/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export interface OrderPost {
previousOrder?: string;
asNeededCondition?: string;
orderReasonNonCoded?: string;
orderReason?: string;
instructions?: string;
}

Expand Down
30 changes: 30 additions & 0 deletions packages/esm-patient-labs-app/src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,46 @@ export const configSchema = {
_default: '52a447d3-a64a-11e3-9aeb-50e549534c5e',
},
},
labTestsWithOrderReasons: {
_type: Type.Array,
_elements: {
labTestUuid: {
_type: Type.UUID,
_description: 'UUID of the lab test that requires a reason for ordering',
_default: '',
},
orderReasons: {
_type: Type.Array,
_elements: {
_type: Type.ConceptUuid,
_description: 'Array of coded concepts that represent reasons for ordering a lab test',
},
_default: [],
_description: 'Coded Lab test order reason options',
},
},
_default: [],
_description: 'Whether to allow for provision of coded order reason',
},
};

export interface ObsTreeEntry {
conceptUuid: string;
defaultOpen: boolean;
}
export interface LabTestReason {
uuid: string;
label?: string;
}
export interface OrderReason {
labTestUuid: string;
orderReasons: Array<string>;
}
export interface ConfigObject {
concepts: Array<ObsTreeEntry>;
showPrintButton: boolean;
orders: {
labOrderTypeUuid: string;
};
labTestsWithOrderReasons: Array<OrderReason>;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useCallback, useEffect, useState } from 'react';
import classNames from 'classnames';
import { launchPatientWorkspace, promptBeforeClosing, useOrderBasket } from '@openmrs/esm-patient-common-lib';
import { translateFrom, useLayoutType, useSession } from '@openmrs/esm-framework';
import { careSettingUuid, type LabOrderBasketItem, prepLabOrderPostData } from '../api';
import { translateFrom, useLayoutType, useSession, useConfig } from '@openmrs/esm-framework';
import { careSettingUuid, type LabOrderBasketItem, prepLabOrderPostData, useOrderReasons } from '../api';
import {
Button,
ButtonSet,
Expand All @@ -22,6 +22,7 @@ import { Controller, type FieldErrors, useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { moduleName } from '@openmrs/esm-patient-chart-app/src/constants';
import { type ConfigObject } from '../../config-schema';
import styles from './lab-order-form.scss';

export interface LabOrderFormProps {
Expand All @@ -44,6 +45,7 @@ const labOrderFormSchema = z.object({
invalid_type_error: translateFrom(moduleName, 'addLabOrderLabReferenceRequired', 'Test type is required'),
},
),
orderReason: z.string().optional(),
});

// Designs:
Expand All @@ -70,6 +72,11 @@ export function LabOrderForm({ initialOrder, closeWorkspace }: LabOrderFormProps
...initialOrder,
},
});
const config = useConfig<ConfigObject>();
const orderReasonUuids =
(config.labTestsWithOrderReasons?.find((c) => c.labTestUuid === defaultValues?.testType?.conceptUuid) || {})
.orderReasons || [];
const { orderReasons } = useOrderReasons(orderReasonUuids);

const handleFormSubmission = useCallback(
(data: LabOrderBasketItem) => {
Expand Down Expand Up @@ -187,6 +194,30 @@ export function LabOrderForm({ initialOrder, closeWorkspace }: LabOrderFormProps
</InputWrapper>
</Column>
</Grid>
{orderReasons.length > 0 && (
<Grid className={styles.gridRow}>
<Column lg={16} md={8} sm={4}>
<InputWrapper>
<Controller
name="orderReason"
control={control}
render={({ field: { onChange, onBlur, value } }) => (
<ComboBox
size="lg"
id="orderReasonInput"
titleText={t('orderReason', 'Order reason')}
selectedItem={''}
itemToString={(item) => item?.display}
items={orderReasons}
onBlur={onBlur}
onChange={({ selectedItem }) => onChange(selectedItem?.uuid || '')}
/>
)}
/>
</InputWrapper>
</Column>
</Grid>
)}
<Grid className={styles.gridRow}>
<Column lg={16} md={8} sm={4}>
<InputWrapper>
Expand Down
55 changes: 54 additions & 1 deletion packages/esm-patient-labs-app/src/lab-orders/api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import useSWR, { mutate } from 'swr';
import { type FetchResponse, openmrsFetch, useConfig } from '@openmrs/esm-framework';
import { type FetchResponse, openmrsFetch, useConfig, showSnackbar } from '@openmrs/esm-framework';
import { type ConfigObject } from '../config-schema';
import { useCallback, useMemo } from 'react';
import { type OrderBasketItem, type OrderPost, type PatientOrderFetchResponse } from '@openmrs/esm-patient-common-lib';
import useSWRImmutable from 'swr/immutable';

export const careSettingUuid = '6f0c9a92-6f24-11e3-af88-005056821db0';
/**
Expand Down Expand Up @@ -42,6 +43,32 @@ export function usePatientLabOrders(patientUuid: string, status: 'ACTIVE' | 'any
};
}

export function useOrderReasons(conceptUuids: Array<string>) {
const shouldFetch = conceptUuids && conceptUuids.length > 0;
const url = shouldFetch ? getConceptReferenceUrls(conceptUuids) : null;
const { data, error, isLoading } = useSWRImmutable<FetchResponse<ConceptResponse>, Error>(
shouldFetch ? `/ws/rest/v1/${url[0]}` : null,
openmrsFetch,
);

const ob = data?.data;
const orderReasons = ob
? Object.entries(ob).map(([key, value]) => ({
uuid: value.uuid,
display: value.display,
}))
: [];

if (error) {
showSnackbar({
title: error.name,
subtitle: error.message,
kind: 'error',
});
}

return { orderReasons: orderReasons, isLoading };
}
export interface LabOrderBasketItem extends OrderBasketItem {
testType?: {
label: string;
Expand All @@ -50,6 +77,7 @@ export interface LabOrderBasketItem extends OrderBasketItem {
labReferenceNumber?: string;
urgency?: string;
instructions?: string;
orderReason?: string;
}

export function prepLabOrderPostData(order: LabOrderBasketItem, patientUuid: string, encounterUuid: string): OrderPost {
Expand All @@ -62,11 +90,36 @@ export function prepLabOrderPostData(order: LabOrderBasketItem, patientUuid: str
encounter: encounterUuid,
concept: order.testType.conceptUuid,
instructions: order.instructions,
orderReason: order.orderReason,
};
}
const chunkSize = 10;
export function getConceptReferenceUrls(conceptUuids: Array<string>) {
const accumulator = [];
for (let i = 0; i < conceptUuids.length; i += chunkSize) {
accumulator.push(conceptUuids.slice(i, i + chunkSize));
}

return accumulator.map((partition) => `conceptreferences?references=${partition.join(',')}&v=custom:(uuid,display)`);
}

export type PostDataPrepLabOrderFunction = (
order: LabOrderBasketItem,
patientUuid: string,
encounterUuid: string,
) => OrderPost;

export interface ConceptAnswers {
display: string;
uuid: string;
}
export interface ConceptResponse {
uuid: string;
display: string;
datatype: {
uuid: string;
display: string;
};
answers: Array<ConceptAnswers>;
setMembers: Array<ConceptAnswers>;
}
1 change: 1 addition & 0 deletions packages/esm-patient-labs-app/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"onDate": "on",
"orderActionNew": "New",
"ordered": "Ordered",
"orderReason": "Order reason",
"other": "Other",
"panel": "Panel",
"pleaseRequiredFields": "Please fill all required fields",
Expand Down

0 comments on commit 8be52b2

Please sign in to comment.