diff --git a/src/channels/components/AssignmentList/AssignmentListHeader.tsx b/src/channels/components/AssignmentList/AssignmentListHeader.tsx index 203fdf534..582940783 100644 --- a/src/channels/components/AssignmentList/AssignmentListHeader.tsx +++ b/src/channels/components/AssignmentList/AssignmentListHeader.tsx @@ -17,13 +17,13 @@ const AssignmentListHeader: React.FC = ({ itemsName, loading, }) => { - const classes = useHeaderStyles(); + const { container, skeleton, ...accordion } = useHeaderStyles(); return ( -
- } classes={classes}> +
+ } classes={accordion}> {loading ? ( - + ) : ( {`${assignCount} ${itemsName.toLowerCase()}`} diff --git a/src/channels/pages/ChannelDetailsPage/ChannelDetailsPage.tsx b/src/channels/pages/ChannelDetailsPage/ChannelDetailsPage.tsx index 9db0afefc..80177087c 100644 --- a/src/channels/pages/ChannelDetailsPage/ChannelDetailsPage.tsx +++ b/src/channels/pages/ChannelDetailsPage/ChannelDetailsPage.tsx @@ -5,6 +5,7 @@ import { channelsListUrl } from "@saleor/channels/urls"; import CardSpacer from "@saleor/components/CardSpacer"; import Form from "@saleor/components/Form"; import Grid from "@saleor/components/Grid"; +import RequirePermissions from "@saleor/components/RequirePermissions"; import Savebar from "@saleor/components/Savebar"; import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; import { @@ -13,6 +14,7 @@ import { ChannelErrorFragment, CountryCode, CountryFragment, + PermissionEnum, SearchShippingZonesQuery, SearchWarehousesQuery, StockSettingsInput, @@ -214,33 +216,45 @@ const ChannelDetailsPage = function({ )} - - - - + + + + + + + + { const navigate = useNavigator(); @@ -106,30 +103,20 @@ export const ChannelCreateView = ({}) => { }; const { - data: shippingZonesCountData, - loading: shippingZonesCountLoading, - } = useShippingZonesCountQuery(); + shippingZonesCountData, + shippingZonesCountLoading, + fetchMoreShippingZones, + searchShippingZones, + searchShippingZonesResult, + } = useShippingZones(); const { - loadMore: fetchMoreShippingZones, - search: searchShippingZones, - result: searchShippingZonesResult, - } = useShippingZonesSearch({ - variables: DEFAULT_INITIAL_SEARCH_DATA, - }); - - const { - data: warehousesCountData, - loading: warehousesCountLoading, - } = useWarehousesCountQuery(); - - const { - loadMore: fetchMoreWarehouses, - search: searchWarehouses, - result: searchWarehousesResult, - } = useWarehouseSearch({ - variables: DEFAULT_INITIAL_SEARCH_DATA, - }); + warehousesCountData, + warehousesCountLoading, + fetchMoreWarehouses, + searchWarehouses, + searchWarehousesResult, + } = useWarehouses(); const currencyCodeChoices = currencyCodes.data.map(currencyData => ({ label: intl.formatMessage( diff --git a/src/channels/views/ChannelDetails/ChannelDetails.tsx b/src/channels/views/ChannelDetails/ChannelDetails.tsx index b87096e42..a6722b0c0 100644 --- a/src/channels/views/ChannelDetails/ChannelDetails.tsx +++ b/src/channels/views/ChannelDetails/ChannelDetails.tsx @@ -5,7 +5,6 @@ import { Backlink } from "@saleor/components/Backlink"; import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; import { WindowTitle } from "@saleor/components/WindowTitle"; -import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; import { ChannelDeleteMutation, ChannelErrorFragment, @@ -15,11 +14,8 @@ import { useChannelDeleteMutation, useChannelQuery, useChannelReorderWarehousesMutation, - useChannelShippingZonesQuery, useChannelsQuery, useChannelUpdateMutation, - useShippingZonesCountQuery, - useWarehousesCountQuery, } from "@saleor/graphql"; import { getSearchFetchMoreProps } from "@saleor/hooks/makeTopLevelSearch/utils"; import useNavigator from "@saleor/hooks/useNavigator"; @@ -28,8 +24,6 @@ import { getDefaultNotifierSuccessErrorData } from "@saleor/hooks/useNotifier/ut import useShop from "@saleor/hooks/useShop"; import { sectionNames } from "@saleor/intl"; import { extractMutationErrors } from "@saleor/misc"; -import useShippingZonesSearch from "@saleor/searches/useShippingZonesSearch"; -import useWarehouseSearch from "@saleor/searches/useWarehouseSearch"; import getChannelsErrorMessage from "@saleor/utils/errors/channels"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import { mapEdgesToItems } from "@saleor/utils/maps"; @@ -44,6 +38,8 @@ import { ChannelUrlQueryParams, } from "../../urls"; import { calculateItemsOrderMoves } from "./handlers"; +import { useShippingZones } from "./useShippingZones"; +import { useWarehouses } from "./useWarehouses"; interface ChannelDetailsProps { id: string; @@ -203,41 +199,22 @@ export const ChannelDetails: React.FC = ({ }; const { - data: shippingZonesCountData, - loading: shippingZonesCountLoading, - } = useShippingZonesCountQuery(); + shippingZonesCountData, + shippingZonesCountLoading, + channelShippingZonesData, + channelsShippingZonesLoading, + fetchMoreShippingZones, + searchShippingZones, + searchShippingZonesResult, + } = useShippingZones(id); const { - data: channelShippingZonesData, - loading: channelsShippingZonesLoading, - } = useChannelShippingZonesQuery({ - variables: { - filter: { - channels: [id], - }, - }, - }); - - const { - loadMore: fetchMoreShippingZones, - search: searchShippingZones, - result: searchShippingZonesResult, - } = useShippingZonesSearch({ - variables: DEFAULT_INITIAL_SEARCH_DATA, - }); - - const { - data: warehousesCountData, - loading: warehousesCountLoading, - } = useWarehousesCountQuery(); - - const { - loadMore: fetchMoreWarehouses, - search: searchWarehouses, - result: searchWarehousesResult, - } = useWarehouseSearch({ - variables: DEFAULT_INITIAL_SEARCH_DATA, - }); + warehousesCountData, + warehousesCountLoading, + fetchMoreWarehouses, + searchWarehouses, + searchWarehousesResult, + } = useWarehouses(); const channelWarehouses = data?.channel?.warehouses || []; const channelShippingZones = mapEdgesToItems( diff --git a/src/channels/views/ChannelDetails/useShippingZones.ts b/src/channels/views/ChannelDetails/useShippingZones.ts new file mode 100644 index 000000000..ff0c1316c --- /dev/null +++ b/src/channels/views/ChannelDetails/useShippingZones.ts @@ -0,0 +1,52 @@ +import { useUserPermissions } from "@saleor/auth/hooks/useUserPermissions"; +import { hasPermissions } from "@saleor/components/RequirePermissions"; +import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; +import { + PermissionEnum, + useChannelShippingZonesQuery, + useShippingZonesCountQuery, +} from "@saleor/graphql"; +import useShippingZonesSearch from "@saleor/searches/useShippingZonesSearch"; + +export const useShippingZones = (channelId?: string) => { + const userPermissions = useUserPermissions(); + const canLoadShippingZones = hasPermissions(userPermissions, [ + PermissionEnum.MANAGE_SHIPPING, + ]); + + const { + data: shippingZonesCountData, + loading: shippingZonesCountLoading, + } = useShippingZonesCountQuery({ skip: !canLoadShippingZones }); + + const { + data: channelShippingZonesData, + loading: channelsShippingZonesLoading, + } = useChannelShippingZonesQuery({ + variables: { + filter: { + channels: [channelId], + }, + }, + skip: !channelId || !canLoadShippingZones, + }); + + const { + loadMore: fetchMoreShippingZones, + search: searchShippingZones, + result: searchShippingZonesResult, + } = useShippingZonesSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA, + skip: !canLoadShippingZones, + }); + + return { + shippingZonesCountData, + shippingZonesCountLoading, + channelShippingZonesData, + channelsShippingZonesLoading, + fetchMoreShippingZones, + searchShippingZones, + searchShippingZonesResult, + }; +}; diff --git a/src/channels/views/ChannelDetails/useWarehouses.ts b/src/channels/views/ChannelDetails/useWarehouses.ts new file mode 100644 index 000000000..162856565 --- /dev/null +++ b/src/channels/views/ChannelDetails/useWarehouses.ts @@ -0,0 +1,36 @@ +import { useUserPermissions } from "@saleor/auth/hooks/useUserPermissions"; +import { hasOneOfPermissions } from "@saleor/components/RequirePermissions"; +import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; +import { PermissionEnum, useWarehousesCountQuery } from "@saleor/graphql"; +import useWarehouseSearch from "@saleor/searches/useWarehouseSearch"; + +export const useWarehouses = () => { + const userPermissions = useUserPermissions(); + const canLoadWarehouses = hasOneOfPermissions(userPermissions, [ + PermissionEnum.MANAGE_SHIPPING, + PermissionEnum.MANAGE_ORDERS, + PermissionEnum.MANAGE_PRODUCTS, + ]); + + const { + data: warehousesCountData, + loading: warehousesCountLoading, + } = useWarehousesCountQuery({ skip: !canLoadWarehouses }); + + const { + loadMore: fetchMoreWarehouses, + search: searchWarehouses, + result: searchWarehousesResult, + } = useWarehouseSearch({ + variables: DEFAULT_INITIAL_SEARCH_DATA, + skip: !canLoadWarehouses, + }); + + return { + warehousesCountData, + warehousesCountLoading, + fetchMoreWarehouses, + searchWarehouses, + searchWarehousesResult, + }; +}; diff --git a/src/components/RequirePermissions.tsx b/src/components/RequirePermissions.tsx index 03b0e5111..f15d4e0cb 100644 --- a/src/components/RequirePermissions.tsx +++ b/src/components/RequirePermissions.tsx @@ -2,32 +2,58 @@ import { useUserPermissions } from "@saleor/auth/hooks/useUserPermissions"; import { PermissionEnum, UserPermissionFragment } from "@saleor/graphql"; import React from "react"; +const findPerm = (permList, perm) => + permList.find(userPerm => userPerm.code === perm); + export function hasPermissions( userPermissions: UserPermissionFragment[], requiredPermissions: PermissionEnum[], ): boolean { return requiredPermissions.reduce( - (acc, perm) => - acc && !!userPermissions.find(userPerm => userPerm.code === perm), + (acc, perm) => acc && !!findPerm(userPermissions, perm), true, ); } +export function hasOneOfPermissions( + userPermissions: UserPermissionFragment[], + givenPermissions: PermissionEnum[], +): boolean { + return givenPermissions.some(perm => !!findPerm(userPermissions, perm)); +} + export interface RequirePermissionsProps { children: React.ReactNode | React.ReactNodeArray; - requiredPermissions: PermissionEnum[]; + requiredPermissions?: PermissionEnum[]; + oneOfPermissions?: PermissionEnum[]; } const RequirePermissions: React.FC = ({ children, requiredPermissions, + oneOfPermissions, }) => { const userPermissions = useUserPermissions(); - return userPermissions && - hasPermissions(userPermissions, requiredPermissions) ? ( - <>{children} - ) : null; + if (!userPermissions) { + return null; + } + + if ( + requiredPermissions && + hasPermissions(userPermissions, requiredPermissions) + ) { + return <>{children}; + } + + if ( + oneOfPermissions && + hasOneOfPermissions(userPermissions, oneOfPermissions) + ) { + return <>{children}; + } + + return null; }; RequirePermissions.displayName = "RequirePermissions"; diff --git a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx index 6e025219a..ea7f2c798 100644 --- a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx +++ b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx @@ -165,7 +165,10 @@ const SingleAutocompleteSelectFieldComponent: React.FC { diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 222161e48..d5c2b9ace 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -46999,468 +46999,6 @@ exports[`Storyshots Views / Channels / Channel details default 1`] = `
-
-
-
- - Shipping Zones - -
-
-
-
- Select shipping zones that will be supplied via this channel. You can assign shipping zones to multiple channels. -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- Europe -
-
- -
-
-
-
-
- USA -
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
- - Warehouses - -
-
-
-
- Assign and sort warehouses that will be used in this channel (warehouses can be assigned in multiple channels). -
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
- Warehouse 1 -
-
- -
-
-
-
- -
- Warehouse 2 -
-
- -
-
-
-
- - Add Warehouses - - -
-
-
-
-
-
-
-
@@ -47960,224 +47498,6 @@ exports[`Storyshots Views / Channels / Channel details disabled 1`] = `
-
-
-
- - Shipping Zones - -
-
-
-
- Select shipping zones that will be supplied via this channel. You can assign shipping zones to multiple channels. -
-
-
-
- -
-
-
-
-
-
-
- - ‌ - -
-
-
-
-
-
-
-
-
-
- - Warehouses - -
-
-
-
- Assign and sort warehouses that will be used in this channel (warehouses can be assigned in multiple channels). -
-
-
-
- -
-
-
-
-
-
-
- - ‌ - -
-
-
-
-
-
-
@@ -48677,468 +47997,6 @@ exports[`Storyshots Views / Channels / Channel details loading 1`] = `
-
-
-
- - Shipping Zones - -
-
-
-
- Select shipping zones that will be supplied via this channel. You can assign shipping zones to multiple channels. -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- Europe -
-
- -
-
-
-
-
- USA -
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
- - Warehouses - -
-
-
-
- Assign and sort warehouses that will be used in this channel (warehouses can be assigned in multiple channels). -
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
- Warehouse 1 -
-
- -
-
-
-
- -
- Warehouse 2 -
-
- -
-
-
-
- - Add Warehouses - - -
-
-
-
-
-
-
-
@@ -49634,468 +48492,6 @@ exports[`Storyshots Views / Channels / Channel details with data 1`] = `
-
-
-
- - Shipping Zones - -
-
-
-
- Select shipping zones that will be supplied via this channel. You can assign shipping zones to multiple channels. -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- Europe -
-
- -
-
-
-
-
- USA -
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
- - Warehouses - -
-
-
-
- Assign and sort warehouses that will be used in this channel (warehouses can be assigned in multiple channels). -
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
- Warehouse 1 -
-
- -
-
-
-
- -
- Warehouse 2 -
-
- -
-
-
-
- - Add Warehouses - - -
-
-
-
-
-
-
-
@@ -50597,468 +48993,6 @@ exports[`Storyshots Views / Channels / Channel details with errors 1`] = `
-
-
-
- - Shipping Zones - -
-
-
-
- Select shipping zones that will be supplied via this channel. You can assign shipping zones to multiple channels. -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- Europe -
-
- -
-
-
-
-
- USA -
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
- - Warehouses - -
-
-
-
- Assign and sort warehouses that will be used in this channel (warehouses can be assigned in multiple channels). -
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
- Warehouse 1 -
-
- -
-
-
-
- -
- Warehouse 2 -
-
- -
-
-
-
- - Add Warehouses - - -
-
-
-
-
-
-
-
@@ -51497,468 +49431,6 @@ exports[`Storyshots Views / Channels / Channel details without editable currency
-
-
-
- - Shipping Zones - -
-
-
-
- Select shipping zones that will be supplied via this channel. You can assign shipping zones to multiple channels. -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- Europe -
-
- -
-
-
-
-
- USA -
-
- -
-
-
- -
-
-
-
-
-
-
-
-
-
- - Warehouses - -
-
-
-
- Assign and sort warehouses that will be used in this channel (warehouses can be assigned in multiple channels). -
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
- Warehouse 1 -
-
- -
-
-
-
- -
- Warehouse 2 -
-
- -
-
-
-
- - Add Warehouses - - -
-
-
-
-
-
-
-