From 4087f967e76b38886b875844e526ec1fc1c85d8d Mon Sep 17 00:00:00 2001 From: Pius Rubangakene Date: Mon, 4 Dec 2023 10:41:19 +0300 Subject: [PATCH] (feat) Order summary/history (#1463) * (feat) lab orders history and results orders print and pending orders adds translations moving orders summary to orders esm translations updates import * fixes to residue after rebase * adds pagination and filter logic * pr changes * PR changes * adds feature flag and minor tweaks * Cleanup --------- Co-authored-by: Vineet Sharma --- .../src/orders/index.ts | 1 + .../src/orders/types.ts | 33 ++ .../src/orders/useOrders.ts | 52 ++ .../lab-order-form.component.tsx | 4 +- packages/esm-patient-labs-app/src/routes.json | 2 +- .../src/routes.json | 8 +- .../esm-patient-orders-app/src/api/api.ts | 2 + .../src/components/order-details-table.scss | 55 +++ .../orders-details-table.component.tsx | 444 ++++++++++++++++++ .../src/dashboard.meta.ts | 7 + packages/esm-patient-orders-app/src/index.ts | 24 +- .../orders-summary.component.tsx | 25 + .../src/print/print.component.tsx | 63 +++ .../src/print/print.scss | 66 +++ .../esm-patient-orders-app/src/routes.json | 24 +- .../esm-patient-orders-app/src/utils/utils.ts | 30 ++ .../translations/am.json | 21 +- .../translations/ar.json | 21 +- .../translations/en.json | 21 +- .../translations/es.json | 21 +- .../translations/fr.json | 21 +- .../translations/he.json | 21 +- .../translations/km.json | 21 +- 23 files changed, 970 insertions(+), 17 deletions(-) create mode 100644 packages/esm-patient-common-lib/src/orders/useOrders.ts create mode 100644 packages/esm-patient-orders-app/src/components/order-details-table.scss create mode 100644 packages/esm-patient-orders-app/src/components/orders-details-table.component.tsx create mode 100644 packages/esm-patient-orders-app/src/dashboard.meta.ts create mode 100644 packages/esm-patient-orders-app/src/orders-summary/orders-summary.component.tsx create mode 100644 packages/esm-patient-orders-app/src/print/print.component.tsx create mode 100644 packages/esm-patient-orders-app/src/print/print.scss create mode 100644 packages/esm-patient-orders-app/src/utils/utils.ts diff --git a/packages/esm-patient-common-lib/src/orders/index.ts b/packages/esm-patient-common-lib/src/orders/index.ts index 9b17fc7884..e349281908 100644 --- a/packages/esm-patient-common-lib/src/orders/index.ts +++ b/packages/esm-patient-common-lib/src/orders/index.ts @@ -1,3 +1,4 @@ export * from './useOrderBasket'; export * from './postOrders'; +export * from './useOrders'; export * from './types'; diff --git a/packages/esm-patient-common-lib/src/orders/types.ts b/packages/esm-patient-common-lib/src/orders/types.ts index d0c5220600..6e1d603baa 100644 --- a/packages/esm-patient-common-lib/src/orders/types.ts +++ b/packages/esm-patient-common-lib/src/orders/types.ts @@ -100,6 +100,39 @@ export interface Order { route: OpenmrsResource; scheduleDate: null; urgency: string; + + // additional properties + accessionNumber: string; + scheduledDate: string; + display: string; + auditInfo: { + creator: { + uuid: string; + display: string; + }; + dateCreated: string; + changedBy: string; + dateChanged: string; + }; + fulfillerStatus: string; + fulfillerComment: string; + specimenSource: string; + laterality: string; + clinicalHistory: string; + numberOfRepeats: string; + type: string; +} + +export interface OrderTypeFetchResponse { + results: Array; +} + +export interface OrderType { + uuid: string; + display: string; + name: string; + retired: boolean; + description: string; } export interface Drug { diff --git a/packages/esm-patient-common-lib/src/orders/useOrders.ts b/packages/esm-patient-common-lib/src/orders/useOrders.ts new file mode 100644 index 0000000000..662aff8114 --- /dev/null +++ b/packages/esm-patient-common-lib/src/orders/useOrders.ts @@ -0,0 +1,52 @@ +import useSWR, { mutate } from 'swr'; +import { type FetchResponse, openmrsFetch } from '@openmrs/esm-framework'; +import { useCallback, useMemo } from 'react'; +import { type OrderTypeFetchResponse, type PatientOrderFetchResponse } from '@openmrs/esm-patient-common-lib'; + +export const careSettingUuid = '6f0c9a92-6f24-11e3-af88-005056821db0'; + +export function usePatientOrders(patientUuid: string, status: 'ACTIVE' | 'any', orderType?: string) { + const baseOrdersUrl = `/ws/rest/v1/order?v=full&patient=${patientUuid}&careSetting=${careSettingUuid}&status=${status}`; + const ordersUrl = orderType ? `${baseOrdersUrl}&orderType=${orderType}` : baseOrdersUrl; + + const { data, error, isLoading, isValidating } = useSWR, Error>( + patientUuid ? ordersUrl : null, + openmrsFetch, + ); + + const mutateOrders = useCallback( + () => mutate((key) => typeof key === 'string' && key.startsWith(`/ws/rest/v1/order?patient=${patientUuid}`)), + [patientUuid], + ); + + const orders = useMemo( + () => + data?.data?.results + ? data.data.results?.sort((order1, order2) => (order2.dateActivated > order1.dateActivated ? 1 : -1)) + : null, + [data], + ); + + return { + data: orders, + error, + isLoading, + isValidating, + mutate: mutateOrders, + }; +} + +export function useOrderTypes() { + const orderTypesUrl = `/ws/rest/v1/ordertype`; + const { data, error, isLoading, isValidating } = useSWR, Error>( + orderTypesUrl, + openmrsFetch, + ); + + return { + data: data?.data?.results, + error, + isLoading, + isValidating, + }; +} diff --git a/packages/esm-patient-labs-app/src/lab-orders/add-lab-order/lab-order-form.component.tsx b/packages/esm-patient-labs-app/src/lab-orders/add-lab-order/lab-order-form.component.tsx index bf3d1e3eb8..f8e306f80b 100644 --- a/packages/esm-patient-labs-app/src/lab-orders/add-lab-order/lab-order-form.component.tsx +++ b/packages/esm-patient-labs-app/src/lab-orders/add-lab-order/lab-order-form.component.tsx @@ -1,10 +1,10 @@ import React, { useCallback, useState } from 'react'; import classNames from 'classnames'; -import { useTranslation } from 'react-i18next'; -import { Button, ButtonSet, Column, ComboBox, Form, Layer, Grid, InlineNotification, TextInput } from '@carbon/react'; import { launchPatientWorkspace, useOrderBasket } from '@openmrs/esm-patient-common-lib'; import { useLayoutType, useSession } from '@openmrs/esm-framework'; import { type LabOrderBasketItem, careSettingUuid, prepLabOrderPostData } from '../api'; +import { Button, ButtonSet, Column, ComboBox, Form, Layer, Grid, InlineNotification, TextInput } from '@carbon/react'; +import { useTranslation } from 'react-i18next'; import { priorityOptions } from './lab-order'; import { type TestType, useTestTypes } from './useTestTypes'; import styles from './lab-order-form.scss'; diff --git a/packages/esm-patient-labs-app/src/routes.json b/packages/esm-patient-labs-app/src/routes.json index 91144cb60b..738036eb1f 100644 --- a/packages/esm-patient-labs-app/src/routes.json +++ b/packages/esm-patient-labs-app/src/routes.json @@ -45,4 +45,4 @@ } ], "pages": [] -} \ No newline at end of file +} diff --git a/packages/esm-patient-medications-app/src/routes.json b/packages/esm-patient-medications-app/src/routes.json index 4da4279bac..848ad0b9c2 100644 --- a/packages/esm-patient-medications-app/src/routes.json +++ b/packages/esm-patient-medications-app/src/routes.json @@ -7,7 +7,7 @@ { "name": "medications-details-widget", "component": "medicationsSummary", - "slot": "patient-chart-orders-dashboard-slot", + "slot": "patient-chart-medications-dashboard-slot", "meta": { "columnSpan": 1 } @@ -19,7 +19,7 @@ "meta": { "columnSpan": 4 }, - "order": 4 + "order": 4 }, { "name": "medications-summary-dashboard", @@ -27,7 +27,7 @@ "slot": "patient-chart-dashboard-slot", "order": 3, "meta": { - "slot": "patient-chart-orders-dashboard-slot", + "slot": "patient-chart-medications-dashboard-slot", "columns": 1, "path": "Medications" } @@ -39,4 +39,4 @@ "order": 1 } ] -} \ No newline at end of file +} diff --git a/packages/esm-patient-orders-app/src/api/api.ts b/packages/esm-patient-orders-app/src/api/api.ts index 1d4d6d3173..c2811a22ab 100644 --- a/packages/esm-patient-orders-app/src/api/api.ts +++ b/packages/esm-patient-orders-app/src/api/api.ts @@ -3,6 +3,8 @@ import useSWR, { useSWRConfig } from 'swr'; import { type FetchResponse, openmrsFetch, type OpenmrsResource, parseDate, type Visit } from '@openmrs/esm-framework'; import { type OrderPost, useVisitOrOfflineVisit, useSystemVisitSetting } from '@openmrs/esm-patient-common-lib'; +export const careSettingUuid = '6f0c9a92-6f24-11e3-af88-005056821db0'; + /** * Returns a function which refreshes the patient orders cache. Uses SWR's mutate function. * Refreshes patient orders for all kinds of orders. diff --git a/packages/esm-patient-orders-app/src/components/order-details-table.scss b/packages/esm-patient-orders-app/src/components/order-details-table.scss new file mode 100644 index 0000000000..72b010c1d2 --- /dev/null +++ b/packages/esm-patient-orders-app/src/components/order-details-table.scss @@ -0,0 +1,55 @@ +@use '@carbon/styles/scss/colors'; +@use '@carbon/styles/scss/spacing'; +@use '@carbon/styles/scss/type'; +@import "../root"; + +.widgetCard { + border: 1px solid colors.$gray-20; + border-bottom: none; +} + +.row { + span { + margin: auto; + } + + p { + padding: spacing.$spacing-02 0; + } +} + +.medicationRecord { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.startDateColumn { + @include type.type-style("body-compact-01"); + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: space-between; + min-height: spacing.$spacing-11; + padding-bottom: spacing.$spacing-02; + + span { + margin: 0rem; + } +} + +.dosage { + @include type.type-style("heading-compact-01"); +} + +.tooltip { + margin: 0rem -0.5rem -0.625rem; +} + +.menuItem { + max-width: none; +} + +.buttons { + justify-content: flex-end; +} diff --git a/packages/esm-patient-orders-app/src/components/orders-details-table.component.tsx b/packages/esm-patient-orders-app/src/components/orders-details-table.component.tsx new file mode 100644 index 0000000000..d226d4ec45 --- /dev/null +++ b/packages/esm-patient-orders-app/src/components/orders-details-table.component.tsx @@ -0,0 +1,444 @@ +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import dayjs from 'dayjs'; +import capitalize from 'lodash-es/capitalize'; +import { + DataTable, + Button, + IconButton, + InlineLoading, + OverflowMenu, + OverflowMenuItem, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableHeader, + TableRow, + Dropdown, + DataTableSkeleton, +} from '@carbon/react'; +import { + CardHeader, + type Order, + type OrderBasketItem, + PatientChartPagination, + useOrderBasket, + useLaunchWorkspaceRequiringVisit, + type OrderType, + EmptyState, + ErrorState, + usePatientOrders, + useOrderTypes, +} from '../../../esm-patient-common-lib'; +import { Add, User, Printer } from '@carbon/react/icons'; +import { age, formatDate, useConfig, useLayoutType, usePagination, usePatient } from '@openmrs/esm-framework'; +import { useTranslation } from 'react-i18next'; +import styles from './order-details-table.scss'; +import { useReactToPrint } from 'react-to-print'; +import { compare, orderPriorityToColor } from '../utils/utils'; +import PrintComponent from '../print/print.component'; +import { orderBy } from 'lodash-es'; +import { Tooltip } from '@carbon/react'; +interface OrderDetailsProps { + title?: string; + patientUuid: string; + showAddButton?: boolean; + showPrintButton?: boolean; +} + +interface OrderHeaderProps { + key: string; + header: string; + isSortable: boolean; + isVisible?: boolean; +} + +const OrderDetailsTable: React.FC = ({ title, patientUuid, showAddButton, showPrintButton }) => { + const { t } = useTranslation(); + const defaultPageSize = 5; + const headerTitle = t('orders', 'Orders'); + const isTablet = useLayoutType() === 'tablet'; + const launchOrderBasket = useLaunchWorkspaceRequiringVisit('order-basket'); + const contentToPrintRef = useRef(null); + const patient = usePatient(patientUuid); + const { excludePatientIdentifierCodeTypes } = useConfig(); + const [isPrinting, setIsPrinting] = useState(false); + const [sortParams, setSortParams] = useState({ key: '', order: 'none' }); + + const { orders, setOrders } = useOrderBasket('order-basket'); + const { data: orderTypes } = useOrderTypes(); + const [selectedOrderTypeUuid, setSelectedOrderTypeUuid] = useState(null); + + const { + data: allOrders, + error: isError, + isLoading, + isValidating, + } = usePatientOrders(patientUuid, 'ACTIVE', selectedOrderTypeUuid); + + const tableHeaders: Array = [ + { + key: 'orderId', + header: t('orderId', 'Order ID'), + isSortable: true, + }, + { + key: 'dateOfOrder', + header: t('dateOfOrder', 'Date of order'), + isSortable: true, + }, + { + key: 'orderType', + header: t('orderType', 'Order type'), + isSortable: true, + }, + { + key: 'order', + header: t('order', 'Order'), + isSortable: true, + }, + { + key: 'priority', + header: t('priority', 'Priority'), + isSortable: true, + }, + { + key: 'orderedBy', + header: t('orderedBy', 'Ordered by'), + isSortable: false, + }, + { + key: 'status', + header: t('status', 'Status'), + isSortable: true, + }, + ]; + + const tableRows = allOrders?.map((order, id) => ({ + id: `${id}`, + startDate: { + sortKey: dayjs(order.dateActivated).toDate(), + content: ( +
+ {formatDate(new Date(order.dateActivated))} + {!isPrinting && } +
+ ), + }, + orderId: order.orderNumber, + dateOfOrder: formatDate(new Date(order.dateActivated)), + orderType: capitalize(order.orderType?.display ?? '--'), + order: order.display, + // order: ( + //
{order.display.length > 20 ? : order.display}
+ // ), + priority: ( +
+ {capitalize(order.urgency)} +
+ ), + orderedBy: order.orderer?.display, + status: capitalize(order.fulfillerStatus ?? '--'), + })); + + const sortRow = (cellA, cellB, { sortDirection, sortStates }) => { + return sortDirection === sortStates.DESC + ? compare(cellB.sortKey, cellA.sortKey) + : compare(cellA.sortKey, cellB.sortKey); + }; + + const sortDate = (myArray, order) => + order === 'ASC' + ? orderBy(myArray, [(obj) => new Date(obj.encounterDate).getTime()], ['desc']) + : orderBy(myArray, [(obj) => new Date(obj.encounterDate).getTime()], ['asc']); + + const { key, order } = sortParams; + const sortedData = + key === 'dateOfOrder' + ? sortDate(tableRows, order) + : order === 'DESC' + ? orderBy(tableRows, [key], ['desc']) + : orderBy(tableRows, [key], ['asc']); + + const { results: paginatedOrders, goTo, currentPage } = usePagination(sortedData, defaultPageSize); + + const patientDetails = useMemo(() => { + const getGender = (gender: string): string => { + switch (gender) { + case 'male': + return t('male', 'Male'); + case 'female': + return t('female', 'Female'); + case 'other': + return t('other', 'Other'); + case 'unknown': + return t('unknown', 'Unknown'); + default: + return gender; + } + }; + + const identifiers = + patient?.patient?.identifier?.filter( + (identifier) => !excludePatientIdentifierCodeTypes?.uuids.includes(identifier.type.coding[0].code), + ) ?? []; + + return { + name: `${patient?.patient?.name?.[0]?.given?.join(' ')} ${patient?.patient?.name?.[0].family}`, + age: age(patient?.patient?.birthDate), + gender: getGender(patient?.patient?.gender), + location: patient?.patient?.address?.[0].city, + identifiers: identifiers?.length ? identifiers.map(({ value, type }) => value) : [], + }; + }, [patient, t, excludePatientIdentifierCodeTypes?.uuids]); + + const onBeforeGetContentResolve = useRef(null); + + useEffect(() => { + if (isPrinting && onBeforeGetContentResolve.current) { + onBeforeGetContentResolve.current(); + } + }, [isPrinting, onBeforeGetContentResolve]); + + const handlePrint = useReactToPrint({ + content: () => contentToPrintRef.current, + documentTitle: `OpenMRS - ${patientDetails.name} - ${title}`, + onBeforeGetContent: () => + new Promise((resolve) => { + if (patient && patient.patient && title) { + onBeforeGetContentResolve.current = resolve; + setIsPrinting(true); + } + }), + onAfterPrint: () => { + onBeforeGetContentResolve.current = null; + setIsPrinting(false); + }, + }); + + if (isLoading) { + return ; + } + + if (isError) { + return ; + } + + if (!tableRows?.length) { + return ; + } + + return ( + <> +
+ + {isValidating ? ( + + + + ) : null} +
+ {orderTypes && orderTypes?.length > 0 && ( + x.uuid === selectedOrderTypeUuid)} + itemToString={(orderType: OrderType) => (orderType ? capitalize(orderType.display) : '')} + onChange={(e) => { + if (e.selectedItem.display === 'All') { + setSelectedOrderTypeUuid(null); + return; + } + setSelectedOrderTypeUuid(e.selectedItem.uuid); + }} + /> + )} + + {showPrintButton && ( + + )} + {showAddButton ?? true ? ( + + ) : null} +
+
+
+ + + {({ rows, headers, getTableProps, getHeaderProps, getRowProps }) => ( + + + + + {headers.map((header) => ( + + {header.header} + + ))} + + + + + {rows.map((row, rowIndex) => ( + + {row.cells.map((cell) => ( + + + + ))} + {!isPrinting && ( + + + + )} + + ))} + +
+
+ )} +
+ {!isPrinting && ( + goTo(page)} + /> + )} +
+
+ + ); +}; + +function FormatCellDisplay({ rowDisplay }: { rowDisplay: string }) { + return ( + <> + {typeof rowDisplay === 'string' && rowDisplay.length > 20 ? ( + + <>{rowDisplay.substring(0, 20).concat('...')} + + ) : ( + rowDisplay + )} + + ); +} + +function InfoTooltip({ orderer }: { orderer: string }) { + return ( + } + iconDescription={orderer} + kind="ghost" + size="sm" + /> + ); +} + +function OrderBasketItemActions({ + orderItem, + items, + setItems, + openOrderBasket, + openOrderForm, +}: { + orderItem: Order; + items: Array; + setItems: (items: Array) => void; + openOrderBasket: () => void; + openOrderForm: (additionalProps?: { order: OrderBasketItem }) => void; +}) { + const { t } = useTranslation(); + const isTablet = useLayoutType() === 'tablet'; + const alreadyInBasket = items.some((x) => x.uuid === orderItem.uuid); + + const handleViewEditClick = useCallback(() => { + // openOrderForm({ order: orderItem }); + }, [orderItem, openOrderForm]); + + const handleAddResultsClick = useCallback(() => { + // openOrderForm({ order: orderItem, addResults: true }); + }, [orderItem, openOrderForm]); + + const handleCancelClick = useCallback(() => { + // setItems(items.filter((x) => x.uuid !== orderItem.uuid)); + }, [items, orderItem, setItems]); + + return ( + + + {!orderItem.fulfillerStatus && ( + + )} + + + ); +} + +export default OrderDetailsTable; diff --git a/packages/esm-patient-orders-app/src/dashboard.meta.ts b/packages/esm-patient-orders-app/src/dashboard.meta.ts new file mode 100644 index 0000000000..5c9ad40f4a --- /dev/null +++ b/packages/esm-patient-orders-app/src/dashboard.meta.ts @@ -0,0 +1,7 @@ +export const ordersDashboardMeta = { + slot: 'patient-chart-lab-orders-dashboard-slot', + columns: 1, + path: 'Orders', + title: 'Orders', + hideDashboardTitle: true, +}; diff --git a/packages/esm-patient-orders-app/src/index.ts b/packages/esm-patient-orders-app/src/index.ts index 700a27561b..ed67c723da 100644 --- a/packages/esm-patient-orders-app/src/index.ts +++ b/packages/esm-patient-orders-app/src/index.ts @@ -1,7 +1,9 @@ -import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle } from '@openmrs/esm-framework'; -import { registerWorkspace } from '@openmrs/esm-patient-common-lib'; +import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle, registerFeatureFlag } from '@openmrs/esm-framework'; +import { createDashboardLink, registerWorkspace } from '@openmrs/esm-patient-common-lib'; import { configSchema } from './config-schema'; import orderBasketActionMenuComponent from './order-basket-action-button/order-basket-action-button.extension'; +import { ordersDashboardMeta } from './dashboard.meta'; +import OrdersSummary from './orders-summary/orders-summary.component'; export const importTranslation = require.context('../translations', false, /.json$/, 'lazy'); @@ -24,4 +26,22 @@ registerWorkspace({ canHide: true, }); +registerFeatureFlag( + 'ordersSummary', + 'Orders Summary', + 'This feature introduces a navigation on the patient chart left nav called Orders and shows a history of patient orders within patient chart', +); + export const orderBasketActionMenu = getSyncLifecycle(orderBasketActionMenuComponent, options); + +export const ordersDashboardLink = + // t('Orders', 'Orders') + getSyncLifecycle( + createDashboardLink({ + ...ordersDashboardMeta, + moduleName, + }), + options, + ); + +export const ordersDashboard = getSyncLifecycle(OrdersSummary, options); diff --git a/packages/esm-patient-orders-app/src/orders-summary/orders-summary.component.tsx b/packages/esm-patient-orders-app/src/orders-summary/orders-summary.component.tsx new file mode 100644 index 0000000000..c928e4ed5a --- /dev/null +++ b/packages/esm-patient-orders-app/src/orders-summary/orders-summary.component.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import OrderDetailsTable from '../components/orders-details-table.component'; + +export interface OrdersSummaryProps { + patientUuid: string; +} + +const OrdersSummary: React.FC = ({ patientUuid }) => { + const { t } = useTranslation(); + const ordersDisplayText = t('orders', 'Orders'); + + return ( +
+ +
+ ); +}; + +export default OrdersSummary; diff --git a/packages/esm-patient-orders-app/src/print/print.component.tsx b/packages/esm-patient-orders-app/src/print/print.component.tsx new file mode 100644 index 0000000000..fb2db6fccf --- /dev/null +++ b/packages/esm-patient-orders-app/src/print/print.component.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { formatDate, useConfig, useSession } from '@openmrs/esm-framework'; +import styles from './print.scss'; + +interface PrintComponentProps { + subheader: string; + patientDetails: { + name: string; + age: string; + gender: string; + location: string; + identifiers: Array; + }; +} + +export function PrintComponent({ subheader, patientDetails }: PrintComponentProps) { + const { t } = useTranslation(); + const { logo } = useConfig(); + + const session = useSession(); + + return ( +
+
+ {logo?.src ? ( + {logo.alt} + ) : logo?.name ? ( + logo.name + ) : ( + // OpenMRS Logo + + + + )} + +
+ {patientDetails?.name} + + {patientDetails?.gender}, {patientDetails?.age}, {patientDetails?.identifiers}{' '} + +
+ +
+ {t('printedBy', 'Printed by')} + + {session.user.display} {t('onDate', 'on')} {formatDate(new Date(), { noToday: true })} + +
+
+ +
+

{subheader}

+
+
+ ); +} + +export default PrintComponent; diff --git a/packages/esm-patient-orders-app/src/print/print.scss b/packages/esm-patient-orders-app/src/print/print.scss new file mode 100644 index 0000000000..32c0b57784 --- /dev/null +++ b/packages/esm-patient-orders-app/src/print/print.scss @@ -0,0 +1,66 @@ +@use '@carbon/styles/scss/colors'; +@use "@carbon/styles/scss/spacing"; +@use '@carbon/styles/scss/type'; + +@media screen { + .printPage { + background-color: colors.$white; + display: none; + } +} + +@media print { + @page { + size: auto; + margin: spacing.$spacing-08; + font-size: smaller; + } + + .header { + display: flex; + align-items: center; + justify-content: space-between; + background-color: colors.$white; + } + + .patientDetails { + @include type.type-style('body-compact-02'); + margin: 0 spacing.$spacing-03; + } + + .patientInfo { + color: colors.$gray-80; + @include type.type-style('body-compact-02'); + } + + .name { + @include type.type-style('heading-compact-02'); + margin-right: spacing.$spacing-03; + } + + .footer { + font-size: spacing.$spacing-04; + display: flex; + } + + .date { + margin-left: spacing.$spacing-06; + } + + .gender { + text-transform: capitalize; + } + + .printedBy { + @include type.type-style('body-compact-01'); + margin: 0 spacing.$spacing-02; + font-size: smaller; + } + + .subheader { + @include type.type-style('heading-03'); + color: colors.$gray-70; + padding: spacing.$spacing-03; + text-align: center; + } +} diff --git a/packages/esm-patient-orders-app/src/routes.json b/packages/esm-patient-orders-app/src/routes.json index fb0f7394a7..a4cd896623 100644 --- a/packages/esm-patient-orders-app/src/routes.json +++ b/packages/esm-patient-orders-app/src/routes.json @@ -9,6 +9,28 @@ "component": "orderBasketActionMenu", "slot": "action-menu-chart-items-slot", "order": 0 + }, + { + "name": "patient-orders-summary-dashboard", + "component": "ordersDashboardLink", + "slot": "patient-chart-dashboard-slot", + "meta": { + "slot": "patient-chart-orders-dashboard-slot", + "columns": 1, + "path": "Orders", + "hideDashboardTitle": true + }, + "order": 4, + "featureFlag": "ordersSummary" + }, + { + "name": "patient-orders-dashboard", + "component": "ordersDashboard", + "slot": "patient-chart-orders-dashboard-slot", + "meta": { + "columnSpan": 4 + }, + "featureFlag": "ordersSummary" } ] -} \ No newline at end of file +} diff --git a/packages/esm-patient-orders-app/src/utils/utils.ts b/packages/esm-patient-orders-app/src/utils/utils.ts new file mode 100644 index 0000000000..566facd649 --- /dev/null +++ b/packages/esm-patient-orders-app/src/utils/utils.ts @@ -0,0 +1,30 @@ +export function orderPriorityToColor(priority) { + switch (priority) { + case 'URGENT': + return '#FCD6D9'; + case 'ROUTINE': + return '#A7EFBB'; + default: + return 'grey'; + } +} + +/** + * Enables a comparison of arbitrary values with support for undefined/null. + * Requires the `<` and `>` operators to return something reasonable for the provided values. + */ +export function compare(x?: T, y?: T) { + if (x == undefined && y == undefined) { + return 0; + } else if (x == undefined) { + return -1; + } else if (y == undefined) { + return 1; + } else if (x < y) { + return -1; + } else if (x > y) { + return 1; + } else { + return 0; + } +} diff --git a/packages/esm-patient-orders-app/translations/am.json b/packages/esm-patient-orders-app/translations/am.json index 209dc0813d..d5114a2f88 100644 --- a/packages/esm-patient-orders-app/translations/am.json +++ b/packages/esm-patient-orders-app/translations/am.json @@ -1,3 +1,22 @@ { - "Medications": "Medications" + "add": "Add", + "addResults": "Add Results", + "cancelOrder": "Cancel Order", + "dateOfOrder": "Date of Order", + "female": "Female", + "male": "Male", + "onDate": "on", + "order": "Order", + "orderedBy": "Ordered By", + "orderId": "Order ID", + "orders": "Orders", + "Orders": "Orders", + "orderType": "Order Type", + "other": "Other", + "print": "Print", + "printedBy": "Printed by", + "priority": "Priority", + "status": "Status", + "unknown": "Unknown", + "viewEdit": "View/Edit Order" } diff --git a/packages/esm-patient-orders-app/translations/ar.json b/packages/esm-patient-orders-app/translations/ar.json index 48190c7987..d5114a2f88 100644 --- a/packages/esm-patient-orders-app/translations/ar.json +++ b/packages/esm-patient-orders-app/translations/ar.json @@ -1,3 +1,22 @@ { - "Medications": "الأدوية" + "add": "Add", + "addResults": "Add Results", + "cancelOrder": "Cancel Order", + "dateOfOrder": "Date of Order", + "female": "Female", + "male": "Male", + "onDate": "on", + "order": "Order", + "orderedBy": "Ordered By", + "orderId": "Order ID", + "orders": "Orders", + "Orders": "Orders", + "orderType": "Order Type", + "other": "Other", + "print": "Print", + "printedBy": "Printed by", + "priority": "Priority", + "status": "Status", + "unknown": "Unknown", + "viewEdit": "View/Edit Order" } diff --git a/packages/esm-patient-orders-app/translations/en.json b/packages/esm-patient-orders-app/translations/en.json index 209dc0813d..d5114a2f88 100644 --- a/packages/esm-patient-orders-app/translations/en.json +++ b/packages/esm-patient-orders-app/translations/en.json @@ -1,3 +1,22 @@ { - "Medications": "Medications" + "add": "Add", + "addResults": "Add Results", + "cancelOrder": "Cancel Order", + "dateOfOrder": "Date of Order", + "female": "Female", + "male": "Male", + "onDate": "on", + "order": "Order", + "orderedBy": "Ordered By", + "orderId": "Order ID", + "orders": "Orders", + "Orders": "Orders", + "orderType": "Order Type", + "other": "Other", + "print": "Print", + "printedBy": "Printed by", + "priority": "Priority", + "status": "Status", + "unknown": "Unknown", + "viewEdit": "View/Edit Order" } diff --git a/packages/esm-patient-orders-app/translations/es.json b/packages/esm-patient-orders-app/translations/es.json index 3473c79c77..d5114a2f88 100644 --- a/packages/esm-patient-orders-app/translations/es.json +++ b/packages/esm-patient-orders-app/translations/es.json @@ -1,3 +1,22 @@ { - "Medications": "Medicamentos" + "add": "Add", + "addResults": "Add Results", + "cancelOrder": "Cancel Order", + "dateOfOrder": "Date of Order", + "female": "Female", + "male": "Male", + "onDate": "on", + "order": "Order", + "orderedBy": "Ordered By", + "orderId": "Order ID", + "orders": "Orders", + "Orders": "Orders", + "orderType": "Order Type", + "other": "Other", + "print": "Print", + "printedBy": "Printed by", + "priority": "Priority", + "status": "Status", + "unknown": "Unknown", + "viewEdit": "View/Edit Order" } diff --git a/packages/esm-patient-orders-app/translations/fr.json b/packages/esm-patient-orders-app/translations/fr.json index 209dc0813d..d5114a2f88 100644 --- a/packages/esm-patient-orders-app/translations/fr.json +++ b/packages/esm-patient-orders-app/translations/fr.json @@ -1,3 +1,22 @@ { - "Medications": "Medications" + "add": "Add", + "addResults": "Add Results", + "cancelOrder": "Cancel Order", + "dateOfOrder": "Date of Order", + "female": "Female", + "male": "Male", + "onDate": "on", + "order": "Order", + "orderedBy": "Ordered By", + "orderId": "Order ID", + "orders": "Orders", + "Orders": "Orders", + "orderType": "Order Type", + "other": "Other", + "print": "Print", + "printedBy": "Printed by", + "priority": "Priority", + "status": "Status", + "unknown": "Unknown", + "viewEdit": "View/Edit Order" } diff --git a/packages/esm-patient-orders-app/translations/he.json b/packages/esm-patient-orders-app/translations/he.json index b20e68ff20..d5114a2f88 100644 --- a/packages/esm-patient-orders-app/translations/he.json +++ b/packages/esm-patient-orders-app/translations/he.json @@ -1,3 +1,22 @@ { - "Medications": "תרופות" + "add": "Add", + "addResults": "Add Results", + "cancelOrder": "Cancel Order", + "dateOfOrder": "Date of Order", + "female": "Female", + "male": "Male", + "onDate": "on", + "order": "Order", + "orderedBy": "Ordered By", + "orderId": "Order ID", + "orders": "Orders", + "Orders": "Orders", + "orderType": "Order Type", + "other": "Other", + "print": "Print", + "printedBy": "Printed by", + "priority": "Priority", + "status": "Status", + "unknown": "Unknown", + "viewEdit": "View/Edit Order" } diff --git a/packages/esm-patient-orders-app/translations/km.json b/packages/esm-patient-orders-app/translations/km.json index b6883be647..d5114a2f88 100644 --- a/packages/esm-patient-orders-app/translations/km.json +++ b/packages/esm-patient-orders-app/translations/km.json @@ -1,3 +1,22 @@ { - "Medications": "ឱសថ" + "add": "Add", + "addResults": "Add Results", + "cancelOrder": "Cancel Order", + "dateOfOrder": "Date of Order", + "female": "Female", + "male": "Male", + "onDate": "on", + "order": "Order", + "orderedBy": "Ordered By", + "orderId": "Order ID", + "orders": "Orders", + "Orders": "Orders", + "orderType": "Order Type", + "other": "Other", + "print": "Print", + "printedBy": "Printed by", + "priority": "Priority", + "status": "Status", + "unknown": "Unknown", + "viewEdit": "View/Edit Order" }