saleor-dashboard/src/components/AppLayout/MenuList.tsx
2019-06-19 16:40:52 +02:00

176 lines
4.8 KiB
TypeScript

import {
createStyles,
Theme,
withStyles,
WithStyles
} from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import classNames from "classnames";
import * as React from "react";
import { matchPath } from "react-router";
import { User } from "../../auth/types/User";
import { configurationMenu, configurationMenuUrl } from "../../configuration";
import i18n from "../../i18n";
import { createHref } from "../../misc";
import { orderDraftListUrl, orderListUrl } from "../../orders/urls";
import MenuNested from "./MenuNested";
import { IMenuItem } from "./menuStructure";
const styles = (theme: Theme) =>
createStyles({
menuList: {
display: "flex",
flexDirection: "column",
height: "100%",
marginLeft: theme.spacing.unit * 4,
marginTop: theme.spacing.unit * 2,
paddingBottom: theme.spacing.unit * 3
},
menuListItem: {
"&:hover": {
color: theme.palette.primary.main
},
alignItems: "center",
display: "block",
marginTop: theme.spacing.unit * 2,
paddingLeft: 0,
textDecoration: "none",
transition: theme.transitions.duration.standard + "ms"
},
menuListItemActive: {
"&:before": {
background: theme.palette.primary.main,
content: "''",
height: "100%",
left: -32,
position: "absolute",
width: 5
},
position: "relative"
},
menuListItemText: {
"&:hover": {
color: theme.palette.primary.main
},
cursor: "pointer",
fontSize: "1rem",
fontWeight: 500,
textTransform: "uppercase",
transition: theme.transitions.duration.standard + "ms"
},
menuListNested: {
"& $menuListItemActive": {
"& $menuListItemText": {
color: theme.palette.primary.main
},
"&:before": {
borderRadius: "100%",
height: 8,
marginLeft: 9,
marginTop: 7,
width: 8
}
},
"& $menuListItemText": {
textTransform: "none"
},
marginLeft: theme.spacing.unit * 3
}
});
interface MenuListProps {
className?: string;
menuItems: IMenuItem[];
location: string;
user: User;
renderConfigure: boolean;
onMenuItemClick: (url: string, event: React.MouseEvent<any>) => void;
}
const MenuList = withStyles(styles, { name: "MenuList" })(
({
classes,
className,
menuItems,
location,
user,
renderConfigure,
onMenuItemClick
}: MenuListProps & WithStyles<typeof styles>) => (
<div className={className}>
{/* FIXME: this .split("?")[0] looks gross */}
{menuItems.map(menuItem => {
const isActive = (menuItem: IMenuItem) =>
location.split("?")[0] === orderDraftListUrl().split("?")[0] &&
menuItem.url.split("?")[0] === orderListUrl().split("?")[0]
? false
: !!matchPath(location.split("?")[0], {
exact: menuItem.url.split("?")[0] === "/",
path: menuItem.url.split("?")[0]
});
if (
menuItem.permission &&
!user.permissions.map(perm => perm.code).includes(menuItem.permission)
) {
return null;
}
if (!menuItem.url) {
const isAnyChildActive = menuItem.children.reduce(
(acc, child) => acc || isActive(child),
false
);
return (
<MenuNested
classes={classes}
isAnyChildActive={isAnyChildActive}
location={location}
menuItem={menuItem}
onMenuItemClick={onMenuItemClick}
user={user}
key={menuItem.label}
/>
);
}
return (
<a
className={classNames(classes.menuListItem, {
[classes.menuListItemActive]: isActive(menuItem)
})}
href={createHref(menuItem.url)}
onClick={event => onMenuItemClick(menuItem.url, event)}
key={menuItem.label}
>
<Typography
aria-label={menuItem.ariaLabel}
className={classes.menuListItemText}
>
{menuItem.label}
</Typography>
</a>
);
})}
{renderConfigure &&
configurationMenu.filter(menuItem =>
user.permissions.map(perm => perm.code).includes(menuItem.permission)
).length > 0 && (
<a
className={classes.menuListItem}
href={createHref(configurationMenuUrl)}
onClick={event => onMenuItemClick(configurationMenuUrl, event)}
>
<Typography
aria-label="configure"
className={classes.menuListItemText}
>
{i18n.t("Configure")}
</Typography>
</a>
)}
</div>
)
);
export default MenuList;