Basic sidebar version (#3039)
This commit is contained in:
parent
112747a51c
commit
1e6b53e249
4 changed files with 343 additions and 12 deletions
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -27,7 +27,7 @@
|
|||
"@material-ui/lab": "^4.0.0-alpha.61",
|
||||
"@material-ui/styles": "^4.11.4",
|
||||
"@reach/auto-id": "^0.16.0",
|
||||
"@saleor/macaw-ui": "^0.8.0-pre.1",
|
||||
"@saleor/macaw-ui": "^0.8.0-pre.4",
|
||||
"@saleor/sdk": "^0.4.4",
|
||||
"@sentry/react": "^6.0.0",
|
||||
"@types/faker": "^5.1.6",
|
||||
|
@ -7235,9 +7235,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@saleor/macaw-ui": {
|
||||
"version": "0.8.0-pre.1",
|
||||
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.1.tgz",
|
||||
"integrity": "sha512-zNnLJcm13HMqGJjHmjyoLL/lQ5dIefUbOq/Ws7wxPn1Bh0wwhY/3T+Qc6iG5W9gvIcpTXJojwL7tT31DHQ2KRw==",
|
||||
"version": "0.8.0-pre.4",
|
||||
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.4.tgz",
|
||||
"integrity": "sha512-9x97IhjCxZ5FD0b3pJfNs2U3YEvsnlJWZHXvGZKPztr0XbtkGbMy5EdHazSH/lNeI3g2T9CE9uKONyatiXAvmw==",
|
||||
"engines": {
|
||||
"node": ">=16 <19"
|
||||
},
|
||||
|
@ -44660,9 +44660,9 @@
|
|||
}
|
||||
},
|
||||
"@saleor/macaw-ui": {
|
||||
"version": "0.8.0-pre.1",
|
||||
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.1.tgz",
|
||||
"integrity": "sha512-zNnLJcm13HMqGJjHmjyoLL/lQ5dIefUbOq/Ws7wxPn1Bh0wwhY/3T+Qc6iG5W9gvIcpTXJojwL7tT31DHQ2KRw=="
|
||||
"version": "0.8.0-pre.4",
|
||||
"resolved": "https://registry.npmjs.org/@saleor/macaw-ui/-/macaw-ui-0.8.0-pre.4.tgz",
|
||||
"integrity": "sha512-9x97IhjCxZ5FD0b3pJfNs2U3YEvsnlJWZHXvGZKPztr0XbtkGbMy5EdHazSH/lNeI3g2T9CE9uKONyatiXAvmw=="
|
||||
},
|
||||
"@saleor/sdk": {
|
||||
"version": "0.4.4",
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
"@editorjs/list": "^1.7.0",
|
||||
"@editorjs/paragraph": "^2.8.0",
|
||||
"@editorjs/quote": "^2.4.0",
|
||||
"@floating-ui/react-dom-interactions": "^0.5.0",
|
||||
"@glideapps/glide-data-grid": "^5.0.0",
|
||||
"@graphiql/plugin-explorer": "^0.1.12",
|
||||
"@graphiql/react": "^0.15.0",
|
||||
|
@ -33,9 +34,8 @@
|
|||
"@material-ui/lab": "^4.0.0-alpha.61",
|
||||
"@material-ui/styles": "^4.11.4",
|
||||
"@reach/auto-id": "^0.16.0",
|
||||
"@saleor/macaw-ui": "^0.8.0-pre.1",
|
||||
"@saleor/macaw-ui": "^0.8.0-pre.4",
|
||||
"@saleor/sdk": "^0.4.4",
|
||||
"@floating-ui/react-dom-interactions": "^0.5.0",
|
||||
"@sentry/react": "^6.0.0",
|
||||
"@types/faker": "^5.1.6",
|
||||
"@uiw/react-color-hue": "0.0.34",
|
||||
|
@ -204,6 +204,7 @@
|
|||
"husky": "^8.0.0",
|
||||
"jest": "^27.5.1",
|
||||
"jest-canvas-mock": "^2.4.0",
|
||||
"jest-environment-jsdom": "^27.5.1",
|
||||
"jest-file": "^1.0.0",
|
||||
"jest-localstorage-mock": "^2.4.3",
|
||||
"lint-staged": "^10.5.1",
|
||||
|
@ -213,8 +214,7 @@
|
|||
"mochawesome-report-generator": "^6.0.1",
|
||||
"prettier": "^2.8.3",
|
||||
"setup-polly-jest": "^0.9.1",
|
||||
"ts-jest": "^27.1.5",
|
||||
"jest-environment-jsdom": "^27.5.1"
|
||||
"ts-jest": "^27.1.5"
|
||||
},
|
||||
"jest": {
|
||||
"resetMocks": false,
|
||||
|
|
|
@ -1,3 +1,42 @@
|
|||
import { useUser } from "@dashboard/auth";
|
||||
import { Box, List, sprinkles, Text } from "@saleor/macaw-ui/next";
|
||||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export const NewSidebar = () => <div>Work in progress</div>;
|
||||
import useMenuStructure from "./useMenuStructure";
|
||||
|
||||
export const NewSidebar = () => {
|
||||
const intl = useIntl();
|
||||
const { user } = useUser();
|
||||
const [menuStructure] = useMenuStructure(intl, user);
|
||||
|
||||
return (
|
||||
<Box
|
||||
backgroundColor="subdued"
|
||||
as="aside"
|
||||
padding={5}
|
||||
borderColor="neutralPlain"
|
||||
borderRightWidth={1}
|
||||
borderRightStyle="solid"
|
||||
>
|
||||
<List as="ol">
|
||||
{menuStructure.map(menuItem => (
|
||||
<List.Item borderRadius={3} key={menuItem.id}>
|
||||
<Link
|
||||
to={menuItem.url}
|
||||
className={sprinkles({
|
||||
padding: 4,
|
||||
})}
|
||||
>
|
||||
<Box display="flex" alignItems="center" gap={5}>
|
||||
{menuItem.icon}
|
||||
<Text>{menuItem.label}</Text>
|
||||
</Box>
|
||||
</Link>
|
||||
</List.Item>
|
||||
))}
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
|
292
src/components/Sidebar/useMenuStructure.tsx
Normal file
292
src/components/Sidebar/useMenuStructure.tsx
Normal file
|
@ -0,0 +1,292 @@
|
|||
import { appsListPath } from "@dashboard/apps/urls";
|
||||
import {
|
||||
extensionMountPoints,
|
||||
useExtensions,
|
||||
} from "@dashboard/apps/useExtensions";
|
||||
import { categoryListUrl } from "@dashboard/categories/urls";
|
||||
import { collectionListUrl } from "@dashboard/collections/urls";
|
||||
import { MARKETPLACE_URL } from "@dashboard/config";
|
||||
import { configurationMenuUrl } from "@dashboard/configuration";
|
||||
import { getConfigMenuItemsPermissions } from "@dashboard/configuration/utils";
|
||||
import { customerListUrl } from "@dashboard/customers/urls";
|
||||
import { saleListUrl, voucherListUrl } from "@dashboard/discounts/urls";
|
||||
import { giftCardListUrl } from "@dashboard/giftCards/urls";
|
||||
import { PermissionEnum, UserFragment } from "@dashboard/graphql";
|
||||
import { commonMessages, sectionNames } from "@dashboard/intl";
|
||||
import { marketplaceUrlResolver } from "@dashboard/marketplace/marketplace-url-resolver";
|
||||
import { orderDraftListUrl, orderListUrl } from "@dashboard/orders/urls";
|
||||
import { pageListPath } from "@dashboard/pages/urls";
|
||||
import { productListUrl } from "@dashboard/products/urls";
|
||||
import { languageListUrl } from "@dashboard/translations/urls";
|
||||
import { SidebarMenuItem } from "@saleor/macaw-ui";
|
||||
import {
|
||||
ConfigurationIcon,
|
||||
CustomersIcon,
|
||||
HomeIcon,
|
||||
MarketplaceIcon,
|
||||
OrdersIcon,
|
||||
ProductsIcons,
|
||||
TableEditIcon,
|
||||
TranslationsIcon,
|
||||
VouchersIcon,
|
||||
} from "@saleor/macaw-ui/next";
|
||||
import React from "react";
|
||||
import { IntlShape } from "react-intl";
|
||||
|
||||
import { getMenuItemExtension, mapToExtensionsItems } from "./legacy/utils";
|
||||
|
||||
export interface FilterableMenuItem extends Omit<any, "children"> {
|
||||
children?: FilterableMenuItem[];
|
||||
permissions?: PermissionEnum[];
|
||||
}
|
||||
|
||||
function useMenuStructure(intl: IntlShape, user: UserFragment) {
|
||||
const extensions = useExtensions(extensionMountPoints.NAVIGATION_SIDEBAR);
|
||||
|
||||
const handleMenuItemClick = (menuItem: SidebarMenuItem) => {
|
||||
const extension = getMenuItemExtension(extensions, menuItem);
|
||||
if (extension) {
|
||||
extension.open();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const appExtensionsHeaderItem = {
|
||||
id: "extensions",
|
||||
label: intl.formatMessage(sectionNames.appExtensions),
|
||||
};
|
||||
|
||||
// This will be deleted when Marketplace is released
|
||||
// Consider this solution as temporary
|
||||
const getAppSection = () => {
|
||||
if (MARKETPLACE_URL) {
|
||||
return {
|
||||
icon: <MarketplaceIcon color="iconNeutralSubdued" />,
|
||||
label: intl.formatMessage(sectionNames.apps),
|
||||
permissions: [PermissionEnum.MANAGE_APPS],
|
||||
id: "apps_section",
|
||||
children: [
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.apps),
|
||||
id: "apps",
|
||||
url: appsListPath,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.marketplace),
|
||||
id: "marketplace-saleor-apps",
|
||||
url: marketplaceUrlResolver.getSaleorAppsDashboardPath(),
|
||||
},
|
||||
{
|
||||
ariaLabel: "marketplace",
|
||||
label: intl.formatMessage(sectionNames.appTemplateGallery),
|
||||
id: "marketplace-template-gallery",
|
||||
url: marketplaceUrlResolver.getTemplateGalleryDashboardPath(),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
icon: <MarketplaceIcon color="iconNeutralSubdued" />,
|
||||
label: intl.formatMessage(sectionNames.apps),
|
||||
permissions: [PermissionEnum.MANAGE_APPS],
|
||||
id: "apps",
|
||||
url: appsListPath,
|
||||
};
|
||||
};
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
icon: <HomeIcon color="iconNeutralSubdued" />,
|
||||
label: intl.formatMessage(sectionNames.home),
|
||||
id: "home",
|
||||
url: "/",
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.products),
|
||||
id: "products",
|
||||
url: productListUrl(),
|
||||
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.categories),
|
||||
id: "categories",
|
||||
url: categoryListUrl(),
|
||||
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.collections),
|
||||
id: "collections",
|
||||
url: collectionListUrl(),
|
||||
permissions: [PermissionEnum.MANAGE_PRODUCTS],
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.giftCards),
|
||||
id: "giftCards",
|
||||
url: giftCardListUrl(),
|
||||
permissions: [PermissionEnum.MANAGE_GIFT_CARD],
|
||||
},
|
||||
...mapToExtensionsItems(
|
||||
extensions.NAVIGATION_CATALOG,
|
||||
appExtensionsHeaderItem,
|
||||
),
|
||||
],
|
||||
icon: <ProductsIcons color="iconNeutralSubdued" />,
|
||||
label: intl.formatMessage(commonMessages.catalog),
|
||||
permissions: [
|
||||
PermissionEnum.MANAGE_GIFT_CARD,
|
||||
PermissionEnum.MANAGE_PRODUCTS,
|
||||
],
|
||||
id: "catalogue",
|
||||
},
|
||||
{
|
||||
children: [
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.orders),
|
||||
permissions: [PermissionEnum.MANAGE_ORDERS],
|
||||
id: "orders",
|
||||
url: orderListUrl(),
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage(commonMessages.drafts),
|
||||
permissions: [PermissionEnum.MANAGE_ORDERS],
|
||||
id: "order-drafts",
|
||||
url: orderDraftListUrl(),
|
||||
},
|
||||
...mapToExtensionsItems(
|
||||
extensions.NAVIGATION_ORDERS,
|
||||
appExtensionsHeaderItem,
|
||||
),
|
||||
],
|
||||
icon: <OrdersIcon color="iconNeutralSubdued" />,
|
||||
label: intl.formatMessage(sectionNames.orders),
|
||||
permissions: [PermissionEnum.MANAGE_ORDERS],
|
||||
id: "orders",
|
||||
},
|
||||
{
|
||||
children: extensions.NAVIGATION_CUSTOMERS.length > 0 && [
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.customers),
|
||||
permissions: [PermissionEnum.MANAGE_USERS],
|
||||
id: "customers",
|
||||
url: customerListUrl(),
|
||||
},
|
||||
...mapToExtensionsItems(
|
||||
extensions.NAVIGATION_CUSTOMERS,
|
||||
appExtensionsHeaderItem,
|
||||
),
|
||||
],
|
||||
icon: <CustomersIcon color="iconNeutralSubdued" />,
|
||||
label: intl.formatMessage(sectionNames.customers),
|
||||
permissions: [PermissionEnum.MANAGE_USERS],
|
||||
id: "customers",
|
||||
url: customerListUrl(),
|
||||
},
|
||||
|
||||
{
|
||||
children: [
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.sales),
|
||||
id: "sales",
|
||||
url: saleListUrl(),
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.vouchers),
|
||||
id: "vouchers",
|
||||
url: voucherListUrl(),
|
||||
},
|
||||
...mapToExtensionsItems(
|
||||
extensions.NAVIGATION_DISCOUNTS,
|
||||
appExtensionsHeaderItem,
|
||||
),
|
||||
],
|
||||
icon: <VouchersIcon color="iconNeutralSubdued" />,
|
||||
label: intl.formatMessage(commonMessages.discounts),
|
||||
permissions: [PermissionEnum.MANAGE_DISCOUNTS],
|
||||
id: "discounts",
|
||||
},
|
||||
{
|
||||
children: extensions.NAVIGATION_PAGES.length > 0 && [
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.pages),
|
||||
permissions: [PermissionEnum.MANAGE_PAGES],
|
||||
id: "pages",
|
||||
url: pageListPath,
|
||||
},
|
||||
...mapToExtensionsItems(
|
||||
extensions.NAVIGATION_PAGES,
|
||||
appExtensionsHeaderItem,
|
||||
),
|
||||
],
|
||||
icon: <TableEditIcon color="iconNeutralSubdued" />,
|
||||
label: intl.formatMessage(sectionNames.pages),
|
||||
permissions: [PermissionEnum.MANAGE_PAGES],
|
||||
id: "pages",
|
||||
url: pageListPath,
|
||||
},
|
||||
getAppSection(),
|
||||
{
|
||||
children: extensions.NAVIGATION_TRANSLATIONS.length > 0 && [
|
||||
{
|
||||
label: intl.formatMessage(sectionNames.translations),
|
||||
permissions: [PermissionEnum.MANAGE_TRANSLATIONS],
|
||||
id: "translations",
|
||||
url: languageListUrl,
|
||||
},
|
||||
...mapToExtensionsItems(
|
||||
extensions.NAVIGATION_TRANSLATIONS,
|
||||
appExtensionsHeaderItem,
|
||||
),
|
||||
],
|
||||
icon: <TranslationsIcon color="iconNeutralSubdued" />,
|
||||
label: intl.formatMessage(sectionNames.translations),
|
||||
permissions: [PermissionEnum.MANAGE_TRANSLATIONS],
|
||||
id: "translations",
|
||||
url: languageListUrl,
|
||||
},
|
||||
{
|
||||
icon: <ConfigurationIcon color="iconNeutralSubdued" />,
|
||||
label: intl.formatMessage(sectionNames.configuration),
|
||||
permissions: getConfigMenuItemsPermissions(intl),
|
||||
id: "configure",
|
||||
url: configurationMenuUrl,
|
||||
},
|
||||
];
|
||||
|
||||
const isMenuItemPermitted = (menuItem: FilterableMenuItem) => {
|
||||
const userPermissions = (user?.userPermissions || []).map(
|
||||
permission => permission.code,
|
||||
);
|
||||
if (!menuItem?.permissions || menuItem?.permissions?.length < 1) {
|
||||
return true;
|
||||
}
|
||||
return menuItem.permissions.some(permission =>
|
||||
userPermissions.includes(permission),
|
||||
);
|
||||
};
|
||||
|
||||
const getFilteredMenuItems = (menuItems: FilterableMenuItem[]) =>
|
||||
menuItems.filter(isMenuItemPermitted);
|
||||
|
||||
return [
|
||||
menuItems.reduce(
|
||||
(resultItems: FilterableMenuItem[], menuItem: FilterableMenuItem) => {
|
||||
if (!isMenuItemPermitted(menuItem)) {
|
||||
return resultItems;
|
||||
}
|
||||
const { children } = menuItem;
|
||||
const filteredChildren = children
|
||||
? getFilteredMenuItems(children)
|
||||
: undefined;
|
||||
|
||||
return [...resultItems, { ...menuItem, children: filteredChildren }];
|
||||
},
|
||||
[],
|
||||
),
|
||||
handleMenuItemClick,
|
||||
] as const;
|
||||
}
|
||||
|
||||
export default useMenuStructure;
|
Loading…
Reference in a new issue