Skip to content

Commit

Permalink
feat: nested menu for mortality and sample shipment
Browse files Browse the repository at this point in the history
  • Loading branch information
9sneha-n committed May 13, 2024
1 parent 1f1ffdb commit 91fd3dd
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 98 deletions.
1 change: 1 addition & 0 deletions src/data/entities/D2Survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const PREVALENCE_SAMPLE_SHIP_TRACK_FORM_ID = "ew0mOwKdcJp";
export const PREVALENCE_CENTRAL_REF_LAB_FORM_ID = "aaAzYmn5vBG";
export const PREVALENCE_PATHOGEN_ISO_STORE_TRACK_ID = "KActa6iTwIM";
export const PREVALENCE_SUPRANATIONAL_REF_LAB_ID = "igEDINFwytu";

//Prevalence Data element Ids

export const AMR_SURVEYS_PREVALENCE_DEA_SURVEY_ID = "o6oNnIbpPDH";
Expand Down
5 changes: 4 additions & 1 deletion src/domain/entities/Survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ export type SURVEY_FORM_TYPES =
| "PrevalenceSampleShipTrackForm"
| "PrevalenceCentralRefLabForm"
| "PrevalencePathogenIsolatesLog"
| "PrevalenceSupranationalRefLabForm";
| "PrevalenceSupranationalRefLabForm"
| "PrevalenceD28FollowUp"
| "PrevalenceDischarge"
| "PrevalenceCohortEnrolment";

export type SURVEY_STATUSES = "FUTURE" | "ACTIVE" | "COMPLETED";
export type SURVEY_TYPES = "SUPRANATIONAL" | "NATIONAL" | "HOSP";
Expand Down
87 changes: 61 additions & 26 deletions src/domain/utils/optionsHelper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export type OptionType = {
label: string;
isHidden?: boolean;
isSubMenu?: boolean;
subMenu?: OptionType[];
};

export const PPSSurveyNationalOptions = (hasReadAccess: boolean, hasCaptureAccess: boolean) => {
Expand Down Expand Up @@ -117,32 +119,65 @@ export const PrevalenceCaseReportFormOptions = (
return [
...DefaultFormOptions(hasReadAccess, hasCaptureAccess),
{
label: "Add New Sample Shipment",
isHidden: hasReadAccess,
},
{
label: "List Sample Shipments",
},
{
label: "Add New Central Ref Lab Results",
isHidden: hasReadAccess,
},
{
label: "List Central Ref Labs Results",
},
{
label: "Add New Pathogen Isolates Log",
isHidden: hasReadAccess,
},
{
label: "List Pathogen Isolates Logs",
},
{
label: "Add New Supranational Ref Results",
isHidden: hasReadAccess,
},
{
label: "List Supranational Refs Results",
label: "Shipments and Lab results",
isSubMenu: true,
subMenu: [
{
label: "Add New Sample Shipment",
isHidden: hasReadAccess,
},
{
label: "List Sample Shipments",
},
{
label: "Add New Central Ref Lab Results",
isHidden: hasReadAccess,
},
{
label: "List Central Ref Labs Results",
},
{
label: "Add New Pathogen Isolates Log",
isHidden: hasReadAccess,
},
{
label: "List Pathogen Isolates Logs",
},
{
label: "Add New Supranational Ref Results",
isHidden: hasReadAccess,
},
{
label: "List Supranational Refs Results",
},
],
},
{
label: "Mortality",
isSubMenu: true,
subMenu: [
{
label: "Add D28 Follow-up",
isHidden: hasReadAccess,
},
{
label: "List D28 Follow-up",
},
{
label: "Add Discharge",
isHidden: hasReadAccess,
},
{
label: "List Discharge",
},
{
label: "Add Cohort enrolment",
isHidden: hasReadAccess,
},
{
label: "List Cohort enrolment",
},
],
},
];
};
Expand Down
168 changes: 145 additions & 23 deletions src/webapp/components/action-menu-button/ActionMenuButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,104 @@ import MoreVert from "@material-ui/icons/MoreVert";
import * as React from "react";
import styled from "styled-components";
import { OptionType } from "../../../domain/utils/optionsHelper";
import _c from "../../../domain/entities/generic/Collection";
import { makeStyles } from "@material-ui/styles";
import { ArrowForwardIosOutlined } from "@material-ui/icons";

interface ActionMenuProps {
options: OptionType[];
optionClickHandler: { option: string; handler: (option?: string) => void }[];
onClickHandler: () => void;
}

const useStyles = makeStyles({
popOverRoot: {
pointerEvents: "none",
},
});

export const ActionMenuButton: React.FC<ActionMenuProps> = ({
options,
optionClickHandler,
onClickHandler,
}) => {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const [mainAnchorEl, setMainAnchorEl] = React.useState<null | HTMLElement>(null);
const [subMenuAnchorEl, setSubMenuAnchorEl] =
React.useState<{ option: string; element: HTMLElement | null }[]>();
const styles = useStyles();

React.useEffect(() => {
const subMenus = _c(
options.map(option => {
if (option.isSubMenu) {
return { option: option.label, element: null };
}
})
)
.compact()
.value();
if (subMenus) setSubMenuAnchorEl(subMenus);
}, [options, setSubMenuAnchorEl]);

const handleMainClick = React.useCallback(
(event: React.MouseEvent<HTMLElement>) => {
setMainAnchorEl(event.currentTarget);
},
[setMainAnchorEl]
);

const handleMainClose = React.useCallback(() => {
setMainAnchorEl(null);
}, [setMainAnchorEl]);

const menuItemClick = (option: string) => {
optionClickHandler.find(optionClick => optionClick.option === option)?.handler(option);
handleClose();
};
const handleSubMenuClick = React.useCallback(
(event: React.MouseEvent<HTMLElement>, option: string) => {
setSubMenuAnchorEl(prevSubMenu => {
return prevSubMenu?.map(subMenu => {
if (subMenu.option === option) {
return { option: subMenu.option, element: event.currentTarget };
} else {
return { option: subMenu.option, element: null };
}
});
});
},
[setSubMenuAnchorEl]
);

const handleSubMenuClose = React.useCallback(
(option: string) => {
setSubMenuAnchorEl(prevSubMenu => {
return prevSubMenu?.map(subMenu => {
if (subMenu.option === option) {
return { option: subMenu.option, element: null };
} else {
return { option: subMenu.option, element: null };
}
});
});
},
[setSubMenuAnchorEl]
);

const mainMenuItemClick = React.useCallback(
(option: string) => {
optionClickHandler.find(optionClick => optionClick.option === option)?.handler(option);
handleMainClose();
handleSubMenuClose(option);
},
[handleMainClose, handleSubMenuClose, optionClickHandler]
);

return (
<div onClick={onClickHandler}>
<StyledIconButton
aria-label="more"
id="long-button"
aria-controls={open ? "long-menu" : undefined}
aria-expanded={open ? "true" : undefined}
aria-controls={mainAnchorEl ? "long-menu" : undefined}
aria-expanded={mainAnchorEl ? "true" : undefined}
aria-haspopup="true"
onClick={handleClick}
onClick={handleMainClick}
>
<MoreVert />
</StyledIconButton>
Expand All @@ -46,17 +109,76 @@ export const ActionMenuButton: React.FC<ActionMenuProps> = ({
MenuListProps={{
"aria-labelledby": "long-button",
}}
anchorEl={anchorEl}
open={open}
onClose={handleClose}
anchorEl={mainAnchorEl}
open={Boolean(mainAnchorEl)}
onClose={handleMainClose}
>
{options
.filter(option => !option.isHidden)
.map(option => (
<MenuItem key={option.label} onClick={() => menuItemClick(option.label)}>
{option.label}
</MenuItem>
))}
.map((option, index) =>
option.isSubMenu === true ? (
<div key={index}>
<MenuItem onMouseOver={e => handleSubMenuClick(e, option.label)}>
<span
style={{
display: "flex",
justifyContent: "space-between",
width: "100%",
}}
>
{option.label}
<ArrowForwardIosOutlined fontSize="small" />
</span>
</MenuItem>

<Menu
id="long-menu"
MenuListProps={{
"aria-labelledby": "long-button",
onMouseEnter: e => handleSubMenuClick(e, option.label),
onMouseLeave: _e => handleSubMenuClose(option.label),
style: { pointerEvents: "auto" },
}}
anchorEl={
subMenuAnchorEl?.find(
subMenu => subMenu.option === option.label
)?.element
}
open={Boolean(
subMenuAnchorEl?.find(
subMenu => subMenu.option === option.label
)?.element
)}
onClose={() => handleSubMenuClose(option.label)}
getContentAnchorEl={null}
anchorOrigin={{ vertical: "top", horizontal: "right" }}
PopoverClasses={{
root: styles.popOverRoot,
}}
>
{option.subMenu
?.filter(subMenu => !subMenu.isHidden)
.map(subMenuOption => (
<MenuItem
key={subMenuOption.label}
onClick={() =>
mainMenuItemClick(subMenuOption.label)
}
>
{subMenuOption.label}
</MenuItem>
))}
</Menu>
</div>
) : (
<MenuItem
key={option.label}
onClick={() => mainMenuItemClick(option.label)}
>
{option.label}
</MenuItem>
)
)}
</Menu>
</div>
);
Expand Down
Loading

0 comments on commit 91fd3dd

Please sign in to comment.