diff --git a/package-lock.json b/package-lock.json
index 1f1edaa86..b0633b9c8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 8cf576c99..700c886dc 100644
--- a/package.json
+++ b/package.json
@@ -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,
diff --git a/src/components/Sidebar/NewSidebar.tsx b/src/components/Sidebar/NewSidebar.tsx
index 5bcf81efa..4c1ffb77f 100644
--- a/src/components/Sidebar/NewSidebar.tsx
+++ b/src/components/Sidebar/NewSidebar.tsx
@@ -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 = () =>
Work in progress
;
+import useMenuStructure from "./useMenuStructure";
+
+export const NewSidebar = () => {
+ const intl = useIntl();
+ const { user } = useUser();
+ const [menuStructure] = useMenuStructure(intl, user);
+
+ return (
+
+
+ {menuStructure.map(menuItem => (
+
+
+
+ {menuItem.icon}
+ {menuItem.label}
+
+
+
+ ))}
+
+
+ );
+};
diff --git a/src/components/Sidebar/useMenuStructure.tsx b/src/components/Sidebar/useMenuStructure.tsx
new file mode 100644
index 000000000..d4da676fb
--- /dev/null
+++ b/src/components/Sidebar/useMenuStructure.tsx
@@ -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 {
+ 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: ,
+ 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: ,
+ label: intl.formatMessage(sectionNames.apps),
+ permissions: [PermissionEnum.MANAGE_APPS],
+ id: "apps",
+ url: appsListPath,
+ };
+ };
+
+ const menuItems = [
+ {
+ icon: ,
+ 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: ,
+ 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: ,
+ 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: ,
+ 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: ,
+ 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: ,
+ 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: ,
+ label: intl.formatMessage(sectionNames.translations),
+ permissions: [PermissionEnum.MANAGE_TRANSLATIONS],
+ id: "translations",
+ url: languageListUrl,
+ },
+ {
+ icon: ,
+ 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;