Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feat) lab order actions - Add order-actions-slot and switches icons for overflow menu #25

Merged
merged 4 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from "@openmrs/esm-framework";
import { configSchema } from "./config-schema";
import { createHomeDashboardLink } from "./components/create-dashboard-link.component";

import { createDashboardLink } from "@openmrs/esm-patient-common-lib";

const moduleName = "@ugandaemr/esm-laboratory-app";
Expand Down Expand Up @@ -87,6 +88,16 @@ export const rejectOrderDialog = getAsyncLifecycle(
options
);

export const pickLabRequestButton = getAsyncLifecycle(
() => import("./queue-list/pick-lab-request-menu.component"),
options
);

export const rejectOrderButton = getAsyncLifecycle(
() => import("./order-actions/reject-order.component"),
options
);

export function startupApp() {
defineConfigSchema(moduleName, configSchema);
}
35 changes: 35 additions & 0 deletions src/order-actions/reject-order.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useCallback } from "react";
import { OverflowMenuItem, OverflowMenu } from "@carbon/react";
import { useTranslation } from "react-i18next";
import { showModal } from "@openmrs/esm-framework";
import { Result } from "../work-list/work-list.resource";

interface RejectOrderOverflowMenuItemProps {
order: Result;
}

const RejectOrderOverflowMenuItem: React.FC<
gitcliff marked this conversation as resolved.
Show resolved Hide resolved
RejectOrderOverflowMenuItemProps
> = ({ order }) => {
const { t } = useTranslation();

const handleRejectOrder = useCallback(() => {
gitcliff marked this conversation as resolved.
Show resolved Hide resolved
const dispose = showModal("reject-order-dialog", {
closeModal: () => dispose(),
order,
});
}, [order]);
return (
<OverflowMenuItem
itemText={t("rejectOrder", "Reject Order")}
onClick={handleRejectOrder}
gitcliff marked this conversation as resolved.
Show resolved Hide resolved
style={{
maxWidth: "100vw",
}}
isDelete={true}
hasDivider
/>
);
};

export default RejectOrderOverflowMenuItem;
52 changes: 27 additions & 25 deletions src/queue-list/laboratory-patient-list.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
TableContainer,
TableExpandHeader,
TableExpandRow,
OverflowMenuItem,
OverflowMenu,
TableHead,
TableHeader,
TableRow,
Expand All @@ -24,10 +26,11 @@ import {
DatePicker,
DatePickerInput,
} from "@carbon/react";
import { TrashCan } from "@carbon/react/icons";
import { TrashCan, OverflowMenuVertical } from "@carbon/react/icons";

import { useTranslation } from "react-i18next";
import {
ExtensionSlot,
age,
formatDate,
formatDatetime,
Expand All @@ -39,7 +42,7 @@ import {
import styles from "./laboratory-queue.scss";
import { getStatusColor } from "../utils/functions";
import { Result, useGetOrdersWorklist } from "../work-list/work-list.resource";
import PickLabRequestActionMenu from "./pick-lab-request-menu.component";
import OrderCustomOverflowMenuComponent from "../ui-components/overflow-menu.component";

interface LaboratoryPatientListProps {}

Expand All @@ -65,23 +68,6 @@ const LaboratoryPatientList: React.FC<LaboratoryPatientListProps> = () => {
results: paginatedWorklistQueueEntries,
currentPage,
} = usePagination(workListEntries, currentPageSize);

const RejectOrder: React.FC<RejectOrderProps> = ({ order }) => {
const launchRejectOrderModal = useCallback(() => {
const dispose = showModal("reject-order-dialog", {
closeModal: () => dispose(),
order,
});
}, [order]);
return (
<Button
kind="ghost"
onClick={launchRejectOrderModal}
renderIcon={(props) => <TrashCan size={16} {...props} />}
/>
);
};

// get picked orders
let columns = [
{ id: 0, header: t("date", "Date"), key: "date" },
Expand Down Expand Up @@ -136,11 +122,22 @@ const LaboratoryPatientList: React.FC<LaboratoryPatientListProps> = () => {
actions: {
content: (
<>
<PickLabRequestActionMenu
order={paginatedWorklistQueueEntries[index]}
closeModal={() => true}
/>
<RejectOrder order={paginatedWorklistQueueEntries[index]} />
<OrderCustomOverflowMenuComponent
menuTitle={
<>
<OverflowMenuVertical
size={16}
style={{ marginLeft: "0.3rem" }}
/>
</>
}
>
<ExtensionSlot
className={styles.menuLink}
state={{ order: paginatedWorklistQueueEntries[index] }}
name="order-actions-slot"
/>
</OrderCustomOverflowMenuComponent>
</>
),
},
Expand All @@ -155,7 +152,12 @@ const LaboratoryPatientList: React.FC<LaboratoryPatientListProps> = () => {
return (
<div>
<div className={styles.headerBtnContainer}></div>
<DataTable rows={tableRows} headers={columns} useZebraStyles>
<DataTable
rows={tableRows}
headers={columns}
useZebraStyles
overflowMenuOnHover={true}
>
{({
rows,
headers,
Expand Down
20 changes: 9 additions & 11 deletions src/queue-list/pick-lab-request-menu.component.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { Button, Tooltip } from "@carbon/react";
import { Notification } from "@carbon/react/icons";

import { OverflowMenuItem } from "@carbon/react";
import { showModal } from "@openmrs/esm-framework";
import React, { useCallback } from "react";
import { useTranslation } from "react-i18next";
import { MappedPatientQueueEntry } from "./laboratory-patient-list.resource";
import { Encounter, Order } from "../types/patient-queues";
import { Order } from "../types/patient-queues";

interface PickLabRequestActionMenuProps {
order: Order;
Expand All @@ -17,7 +14,7 @@ const PickLabRequestActionMenu: React.FC<PickLabRequestActionMenuProps> = ({
}) => {
const { t } = useTranslation();

const launchPickLabRequestQueueModal = useCallback(() => {
const launchPickLabRequestModal = useCallback(() => {
const dispose = showModal("add-to-worklist-dialog", {
closeModal: () => dispose(),

Expand All @@ -26,11 +23,12 @@ const PickLabRequestActionMenu: React.FC<PickLabRequestActionMenuProps> = ({
}, [order]);

return (
<Button
kind="ghost"
onClick={launchPickLabRequestQueueModal}
iconDescription={t("pickRequest", "Pick Lab Request ")}
renderIcon={(props) => <Notification size={16} {...props} />}
<OverflowMenuItem
itemText={t("pickLabRequest", "Pick Lab Request")}
onClick={launchPickLabRequestModal}
style={{
maxWidth: "100vw",
}}
/>
);
};
Expand Down
10 changes: 10 additions & 0 deletions src/routes.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@
{
"name" : "reject-order-dialog",
"component": "rejectOrderDialog"
},
{
"name": "pick-lab-request-button",
"component": "pickLabRequestButton",
"slot": "order-actions-slot"
},
{
"name": "reject-order-button",
"component": "rejectOrderButton",
"slot": "order-actions-slot"
}
]
}
88 changes: 88 additions & 0 deletions src/ui-components/overflow-menu.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React, { useState, useCallback, useEffect, useRef } from "react";
import classNames from "classnames";
import { useLayoutType } from "@openmrs/esm-framework";
import styles from "./overflow-menu.scss";

interface OrderCustomOverflowMenuComponentProps {
menuTitle: React.ReactNode;
children: React.ReactNode;
}

const OrderCustomOverflowMenuComponent: React.FC<
OrderCustomOverflowMenuComponentProps
> = ({ children, menuTitle }) => {
const [showMenu, setShowMenu] = useState(false);
const isTablet = useLayoutType() === "tablet";
const wrapperRef = useRef(null);

const toggleShowMenu = useCallback(() => setShowMenu((state) => !state), []);

useEffect(() => {
/**
* Toggle showMenu if clicked on outside of element
*/
function handleClickOutside(event: MouseEvent) {
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
setShowMenu(false);
}
}

// Bind the event listener
document.addEventListener("mousedown", handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener("mousedown", handleClickOutside);
};
}, [wrapperRef]);

return (
<div
data-overflow-menu
className={classNames("cds--overflow-menu", styles.container)}
ref={wrapperRef}
>
gitcliff marked this conversation as resolved.
Show resolved Hide resolved
<button
className={classNames(
"cds--btn",
"cds--btn--ghost",
"cds--overflow-menu__trigger",
{ "cds--overflow-menu--open": showMenu },
styles.overflowMenuButton
)}
aria-haspopup="true"
aria-expanded={showMenu}
id="custom-actions-overflow-menu-trigger"
aria-controls="custom-actions-overflow-menu"
onClick={toggleShowMenu}
>
{menuTitle}
</button>
<div
className={classNames(
"cds--overflow-menu-options",
"cds--overflow-menu--flip",
styles.menu,
Comment on lines +44 to +64
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we switch this to move away from specifying carbon classnames manually? Am sure we can get an equivalent from what comes out of the box.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pirupius i agree

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @pirupius @jabahum ...
I initially did that and wrapped the OverflowMenuItem items with OverflowMenu out of the box from carbon , which would be the out of the box equivalent but it does not display the extensionSlot which it houses and its children hence on clicking the icon it displays nothing .
So i used the custom overflow flow menu approach that was used in the patient banner actions . Had discussions with Samuel about this, we tested the 2 options and resolved to keep the custom overflow

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gitcliff i left a comment that you haven't addressed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gitcliff i left a comment that you haven't addressed

@pirupius do you mean the one in regards to specifying carbon classnames manually?

{
[styles.show]: showMenu,
}
)}
tabIndex={0}
data-floating-menu-direction="bottom"
role="menu"
aria-labelledby="custom-actions-overflow-menu-trigger"
id="custom-actions-overflow-menu"
>
<ul
className={classNames("cds--overflow-menu-options__content", {
"cds--overflow-menu-options--lg": isTablet,
})}
>
{children}
</ul>
<span />
</div>
</div>
);
};

export default OrderCustomOverflowMenuComponent;
39 changes: 39 additions & 0 deletions src/ui-components/overflow-menu.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@use '@carbon/colors';
@import '~@openmrs/esm-styleguide/src/vars';

.container {
position: relative;
top: 0px;
}

.menu {
display: none;
top: 3.125rem;
min-width: initial;
left: auto;
right: 0;
background-color: $ui-01;
margin-right: 0.2rem;
box-shadow: 0 6px 6px rgb(0 0 0 / 30%);
}

.show {
display: block;
}

.overflowMenuButton {
width: auto;
height: auto;
padding: 0.875rem 1rem;
color: colors.$blue-60;
display: flex;
align-items: center;

&:hover {
background-color: colors.$gray-10-hover;
}
}

.deceased {
color: colors.$blue-40;
}
4 changes: 3 additions & 1 deletion translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@
"transferred": "Transferred",
"visitId": "Visit ID",
"waitingTime": "Waiting time",
"worklist": "Worklist"
"worklist": "Worklist",
"rejectOrder": "Reject Order",
"pickLabRequest": "Pick Lab Request"
}
Loading