Fix configuration page

This commit is contained in:
Krzysztof Bialoglowicz 2019-09-12 16:38:40 +02:00
parent 78132229af
commit ad4975bd84
6 changed files with 196 additions and 331 deletions

View file

@ -173,6 +173,13 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
}); });
const intl = useIntl(); const intl = useIntl();
const configutationMenu = createConfigurationMenu(intl).map(menu => {
menu.menuItems.map(item => {
return user.permissions
.map(perm => perm.code)
.includes(item.permission);
});
});
const handleSubMenu = itemLabel => { const handleSubMenu = itemLabel => {
setActiveSubMenu({ setActiveSubMenu({
isActive: isActive:
@ -304,35 +311,30 @@ const MenuList = withStyles(styles, { name: "MenuList" })(
</a> </a>
); );
})} })}
{renderConfigure && {renderConfigure && configutationMenu.length > 0 && (
createConfigurationMenu(intl).filter(menuItem => <a
user.permissions className={classes.menuListItem}
.map(perm => perm.code) href={createHref(configurationMenuUrl)}
.includes(menuItem.permission) onClick={event => closeSubMenu(configurationMenuUrl, event)}
).length > 0 && ( >
<a <div className={classes.menuItemHover}>
className={classes.menuListItem} <SVG
href={createHref(configurationMenuUrl)} className={classNames(classes.menuIcon, {
onClick={event => closeSubMenu(configurationMenuUrl, event)} [classes.menuIconDark]: isDark
> })}
<div className={classes.menuItemHover}> src={configureIcon}
<SVG />
className={classNames(classes.menuIcon, { <Typography
[classes.menuIconDark]: isDark aria-label="configuration"
})} className={classNames(classes.menuListItemText, {
src={configureIcon} [classes.menuListItemTextHide]: !isMenuSmall
/> })}
<Typography >
aria-label="configuration" <FormattedMessage {...sectionNames.configuration} />
className={classNames(classes.menuListItemText, { </Typography>
[classes.menuListItemTextHide]: !isMenuSmall </div>
})} </a>
> )}
<FormattedMessage {...sectionNames.configuration} />
</Typography>
</div>
</a>
)}
</div> </div>
); );
} }

View file

@ -61,8 +61,7 @@ const styles = (theme: Theme) =>
paddingRight: theme.spacing.unit paddingRight: theme.spacing.unit
}, },
chipLabel: { chipLabel: {
color: theme.palette.common.white, color: theme.palette.primary.contrastText
fontSize: "16px"
}, },
container: { container: {
flexGrow: 1, flexGrow: 1,
@ -276,7 +275,7 @@ export const MultiAutocompleteSelectFieldComponent = withStyles(styles, {
{displayValues.map(value => ( {displayValues.map(value => (
<div className={classes.chip} key={value.value}> <div className={classes.chip} key={value.value}>
<div className={classes.chipInner}> <div className={classes.chipInner}>
<Typography className={classes.chipLabel} variant="caption"> <Typography className={classes.chipLabel}>
{value.label} {value.label}
</Typography> </Typography>
<IconButton <IconButton

View file

@ -12,19 +12,23 @@ import { useIntl } from "react-intl";
import { IconProps } from "@material-ui/core/Icon"; import { IconProps } from "@material-ui/core/Icon";
import { sectionNames } from "@saleor/intl"; import { sectionNames } from "@saleor/intl";
import { ConfigurationCategoryEnum } from "@saleor/types"; import { hasPermission } from "../auth/misc";
import { User } from "../auth/types/User"; import { User } from "../auth/types/User";
import Container from "../components/Container"; import Container from "../components/Container";
import PageHeader from "../components/PageHeader"; import PageHeader from "../components/PageHeader";
import { PermissionEnum } from "../types/globalTypes"; import { PermissionEnum } from "../types/globalTypes";
export interface MenuItem { export interface MenuItem {
category: ConfigurationCategoryEnum; label: string;
description: string; menuItems: [
icon: React.ReactElement<IconProps>; {
permission: PermissionEnum; description: string;
title: string; icon: React.ReactElement<IconProps>;
url?: string; permission: PermissionEnum;
title: string;
url?: string;
}
];
} }
const styles = (theme: Theme) => const styles = (theme: Theme) =>
@ -70,6 +74,9 @@ const styles = (theme: Theme) =>
configurationLabel: { configurationLabel: {
paddingBottom: 20 paddingBottom: 20
}, },
header: {
margin: 0
},
icon: { icon: {
color: theme.palette.primary.main, color: theme.palette.primary.main,
fontSize: 48 fontSize: 48
@ -99,191 +106,45 @@ export const ConfigurationPage = withStyles(styles, {
const intl = useIntl(); const intl = useIntl();
return ( return (
<Container> <Container>
<PageHeader title={intl.formatMessage(sectionNames.configuration)} /> <PageHeader
<div className={classes.configurationCategory}> className={classes.header}
<div className={classes.configurationLabel}> title={intl.formatMessage(sectionNames.configuration)}
<Typography> />
{intl.formatMessage({ {menu
defaultMessage: "Attributes and Product Types", .filter(menu =>
description: "configuration category" menu.menuItems.map(item => hasPermission(item.permission, user))
})} )
</Typography> .map((menu, menuIndex) => (
</div> <div className={classes.configurationCategory}>
<div className={classes.configurationItem}> <div className={classes.configurationLabel}>
{menu <Typography>{menu.label}</Typography>
.filter(menuItem => </div>
user.permissions <div className={classes.configurationItem}>
.map(perm => perm.code) {menu.menuItems.map(item => (
.includes(menuItem.permission) <Card
) className={item.url ? classes.card : classes.cardDisabled}
.map( onClick={() => onSectionClick(item.url)}
(menuItem, menuItemIndex) => key={menuIndex}
menuItem.category === >
ConfigurationCategoryEnum.ATTRUBUTES_PRODUCT_TYPES && ( <CardContent className={classes.cardContent}>
<Card <div className={classes.icon}>{item.icon}</div>
className={ <div>
menuItem.url ? classes.card : classes.cardDisabled <Typography
} className={classes.sectionTitle}
onClick={() => onSectionClick(menuItem.url)} color="primary"
key={menuItemIndex} >
> {item.title}
<CardContent className={classes.cardContent}> </Typography>
<div className={classes.icon}>{menuItem.icon}</div> <Typography className={classes.sectionDescription}>
<div> {item.description}
<Typography </Typography>
className={classes.sectionTitle} </div>
color="primary" </CardContent>
> </Card>
{menuItem.title} ))}
</Typography> </div>
<Typography className={classes.sectionDescription}> </div>
{menuItem.description} ))}
</Typography>
</div>
</CardContent>
</Card>
)
)}
</div>
</div>
<div className={classes.configurationCategory}>
<div className={classes.configurationLabel}>
<Typography>
{intl.formatMessage({
defaultMessage: "Product Settings",
description: "configuration category"
})}
</Typography>
</div>
<div className={classes.configurationItem}>
{menu
.filter(menuItem =>
user.permissions
.map(perm => perm.code)
.includes(menuItem.permission)
)
.map(
(menuItem, menuItemIndex) =>
menuItem.category ===
ConfigurationCategoryEnum.PRODUCT_SETTINGS && (
<Card
className={
menuItem.url ? classes.card : classes.cardDisabled
}
onClick={() => onSectionClick(menuItem.url)}
key={menuItemIndex}
>
<CardContent className={classes.cardContent}>
<div className={classes.icon}>{menuItem.icon}</div>
<div>
<Typography
className={classes.sectionTitle}
color="primary"
>
{menuItem.title}
</Typography>
<Typography className={classes.sectionDescription}>
{menuItem.description}
</Typography>
</div>
</CardContent>
</Card>
)
)}
</div>
</div>
<div className={classes.configurationCategory}>
<div className={classes.configurationLabel}>
<Typography>
{intl.formatMessage({
defaultMessage: "Staff Settings",
description: "configuration category"
})}
</Typography>
</div>
<div className={classes.configurationItem}>
{menu
.filter(menuItem =>
user.permissions
.map(perm => perm.code)
.includes(menuItem.permission)
)
.map(
(menuItem, menuItemIndex) =>
menuItem.category ===
ConfigurationCategoryEnum.STAFF_SETTINGS && (
<Card
className={
menuItem.url ? classes.card : classes.cardDisabled
}
onClick={() => onSectionClick(menuItem.url)}
key={menuItemIndex}
>
<CardContent className={classes.cardContent}>
<div className={classes.icon}>{menuItem.icon}</div>
<div>
<Typography
className={classes.sectionTitle}
color="primary"
>
{menuItem.title}
</Typography>
<Typography className={classes.sectionDescription}>
{menuItem.description}
</Typography>
</div>
</CardContent>
</Card>
)
)}
</div>
</div>
<div className={classes.configurationCategory}>
<div className={classes.configurationLabel}>
<Typography>
{intl.formatMessage({
defaultMessage: "Miscellaneous",
description: "configuration category"
})}
</Typography>
</div>
<div className={classes.configurationItem}>
{menu
.filter(menuItem =>
user.permissions
.map(perm => perm.code)
.includes(menuItem.permission)
)
.map(
(menuItem, menuItemIndex) =>
menuItem.category ===
ConfigurationCategoryEnum.MISCELLANEOUS && (
<Card
className={
menuItem.url ? classes.card : classes.cardDisabled
}
onClick={() => onSectionClick(menuItem.url)}
key={menuItemIndex}
>
<CardContent className={classes.cardContent}>
<div className={classes.icon}>{menuItem.icon}</div>
<div>
<Typography
className={classes.sectionTitle}
color="primary"
>
{menuItem.title}
</Typography>
<Typography className={classes.sectionDescription}>
{menuItem.description}
</Typography>
</div>
</CardContent>
</Card>
)
)}
</div>
</div>
</Container> </Container>
); );
} }

View file

@ -24,116 +24,126 @@ import { shippingZonesListUrl } from "@saleor/shipping/urls";
import { siteSettingsUrl } from "@saleor/siteSettings/urls"; import { siteSettingsUrl } from "@saleor/siteSettings/urls";
import { staffListUrl } from "@saleor/staff/urls"; import { staffListUrl } from "@saleor/staff/urls";
import { taxSection } from "@saleor/taxes/urls"; import { taxSection } from "@saleor/taxes/urls";
import { ConfigurationCategoryEnum } from "@saleor/types";
import { PermissionEnum } from "@saleor/types/globalTypes"; import { PermissionEnum } from "@saleor/types/globalTypes";
import ConfigurationPage, { MenuItem } from "./ConfigurationPage"; import ConfigurationPage, { MenuItem } from "./ConfigurationPage";
export function createConfigurationMenu(intl: IntlShape): MenuItem[] { export function createConfigurationMenu(intl: IntlShape): MenuItem[] {
return [ return [
{ {
category: ConfigurationCategoryEnum.ATTRUBUTES_PRODUCT_TYPES, label: "Attributes and Product Types",
description: intl.formatMessage({ menuItems: [
defaultMessage: "Determine attributes used to create product types", {
id: "configurationMenuAttributes" description: intl.formatMessage({
}), defaultMessage: "Determine attributes used to create product types",
icon: <Attributes fontSize="inherit" viewBox="0 0 44 44" />, id: "configurationMenuAttributes"
permission: PermissionEnum.MANAGE_PRODUCTS, }),
title: intl.formatMessage(sectionNames.attributes), icon: <Attributes fontSize="inherit" viewBox="0 0 44 44" />,
url: attributeListUrl() permission: PermissionEnum.MANAGE_PRODUCTS,
title: intl.formatMessage(sectionNames.attributes),
url: attributeListUrl()
},
{
description: intl.formatMessage({
defaultMessage: "Define types of products you sell",
id: "configurationMenuProductTypes"
}),
icon: <ProductTypes fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_PRODUCTS,
title: intl.formatMessage(sectionNames.productTypes),
url: productTypeListUrl()
}
]
}, },
{ {
category: ConfigurationCategoryEnum.ATTRUBUTES_PRODUCT_TYPES, label: "Product Settings",
description: intl.formatMessage({ menuItems: [
defaultMessage: "Define types of products you sell", {
id: "configurationMenuProductTypes" description: intl.formatMessage({
}), defaultMessage: "Manage how you ship out orders",
icon: <ProductTypes fontSize="inherit" viewBox="0 0 44 44" />, id: "configurationMenuShipping"
permission: PermissionEnum.MANAGE_PRODUCTS, }),
title: intl.formatMessage(sectionNames.productTypes), icon: <ShippingMethods fontSize="inherit" viewBox="0 0 44 44" />,
url: productTypeListUrl() permission: PermissionEnum.MANAGE_SHIPPING,
title: intl.formatMessage(sectionNames.shipping),
url: shippingZonesListUrl()
},
{
description: intl.formatMessage({
defaultMessage: "Manage how your store charges tax",
id: "configurationMenuTaxes"
}),
icon: <Taxes fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_PRODUCTS,
title: intl.formatMessage(sectionNames.taxes),
url: taxSection
}
]
}, },
{ {
category: ConfigurationCategoryEnum.STAFF_SETTINGS, label: "Staff Settings",
description: intl.formatMessage({ menuItems: [
defaultMessage: "Manage your employees and their permissions", {
id: "configurationMenuStaff" description: intl.formatMessage({
}), defaultMessage: "Manage your employees and their permissions",
icon: <StaffMembers fontSize="inherit" viewBox="0 0 44 44" />, id: "configurationMenuStaff"
permission: PermissionEnum.MANAGE_STAFF, }),
title: intl.formatMessage(sectionNames.staff), icon: <StaffMembers fontSize="inherit" viewBox="0 0 44 44" />,
url: staffListUrl() permission: PermissionEnum.MANAGE_STAFF,
title: intl.formatMessage(sectionNames.staff),
url: staffListUrl()
}
]
}, },
{ {
category: ConfigurationCategoryEnum.PRODUCT_SETTINGS, label: "Miscellaneous",
description: intl.formatMessage({ menuItems: [
defaultMessage: "Manage how you ship out orders", {
id: "configurationMenuShipping" description: intl.formatMessage({
}), defaultMessage: "Define how users can navigate through your store",
icon: <ShippingMethods fontSize="inherit" viewBox="0 0 44 44" />, id: "configurationMenuNavigation"
permission: PermissionEnum.MANAGE_SHIPPING, }),
title: intl.formatMessage(sectionNames.shipping), icon: <Navigation fontSize="inherit" viewBox="0 0 44 44" />,
url: shippingZonesListUrl() permission: PermissionEnum.MANAGE_MENUS,
}, title: intl.formatMessage(sectionNames.navigation),
{ url: menuListUrl()
category: ConfigurationCategoryEnum.PRODUCT_SETTINGS, },
description: intl.formatMessage({ {
defaultMessage: "Manage how your store charges tax", description: intl.formatMessage({
id: "configurationMenuTaxes" defaultMessage: "View and update your site settings",
}), id: "configurationMenuSiteSettings"
icon: <Taxes fontSize="inherit" viewBox="0 0 44 44" />, }),
permission: PermissionEnum.MANAGE_PRODUCTS, icon: <SiteSettings fontSize="inherit" viewBox="0 0 44 44" />,
title: intl.formatMessage(sectionNames.taxes), permission: PermissionEnum.MANAGE_SETTINGS,
url: taxSection title: intl.formatMessage(sectionNames.siteSettings),
}, url: siteSettingsUrl()
{ },
category: ConfigurationCategoryEnum.MISCELLANEOUS, {
description: intl.formatMessage({ description: intl.formatMessage({
defaultMessage: "Define how users can navigate through your store", defaultMessage: "Manage and add additional pages",
id: "configurationMenuNavigation" id: "configurationMenuPages"
}), }),
icon: <Navigation fontSize="inherit" viewBox="0 0 44 44" />, icon: <Pages fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_MENUS, permission: PermissionEnum.MANAGE_PAGES,
title: intl.formatMessage(sectionNames.navigation), title: intl.formatMessage(sectionNames.pages),
url: menuListUrl() url: pageListUrl()
}, },
{ {
category: ConfigurationCategoryEnum.MISCELLANEOUS, description: intl.formatMessage({
description: intl.formatMessage({ defaultMessage: "View and update your plugins and their settings.",
defaultMessage: "View and update your site settings", id: "configurationPluginsPages"
id: "configurationMenuSiteSettings" }),
}), icon: (
icon: <SiteSettings fontSize="inherit" viewBox="0 0 44 44" />, <Plugins
permission: PermissionEnum.MANAGE_SETTINGS, fontSize="inherit"
title: intl.formatMessage(sectionNames.siteSettings), viewBox="-8 -5 44 44"
url: siteSettingsUrl() preserveAspectRatio="xMinYMin meet"
}, />
{ ),
category: ConfigurationCategoryEnum.MISCELLANEOUS, permission: PermissionEnum.MANAGE_SETTINGS,
description: intl.formatMessage({ title: intl.formatMessage(sectionNames.plugins),
defaultMessage: "Manage and add additional pages", url: pluginsListUrl()
id: "configurationMenuPages" }
}), ]
icon: <Pages fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_PAGES,
title: intl.formatMessage(sectionNames.pages),
url: pageListUrl()
},
{
category: ConfigurationCategoryEnum.MISCELLANEOUS,
description: intl.formatMessage({
defaultMessage: "View and update your plugins and their settings.",
id: "configurationPluginsPages"
}),
icon: (
<Plugins
fontSize="inherit"
viewBox="-8 -5 44 44"
preserveAspectRatio="xMinYMin meet"
/>
),
permission: PermissionEnum.MANAGE_SETTINGS,
title: intl.formatMessage(sectionNames.plugins),
url: pluginsListUrl()
} }
]; ];
} }

View file

@ -227,8 +227,8 @@ const Routes: React.FC = () => {
path={attributeSection} path={attributeSection}
component={AttributeSection} component={AttributeSection}
/> />
{createConfigurationMenu(intl).filter(menuItem => {createConfigurationMenu(intl).filter(menu =>
hasPermission(menuItem.permission, user) menu.menuItems.map(item => hasPermission(item.permission, user))
).length > 0 && ( ).length > 0 && (
<SectionRoute <SectionRoute
exact exact

View file

@ -134,10 +134,3 @@ export interface FetchMoreProps {
hasMore: boolean; hasMore: boolean;
onFetchMore: () => void; onFetchMore: () => void;
} }
export enum ConfigurationCategoryEnum {
ATTRUBUTES_PRODUCT_TYPES = "ATTRUBUTES_PRODUCT_TYPES",
PRODUCT_SETTINGS = "PRODUCT_SETTINGS",
STAFF_SETTINGS = "STAFF_SETTINGS",
MISCELLANEOUS = "MISCELLANEOUS"
}