Hide shipping zones when you do not have access (#2333)

* hide shipping zones when you do not have access

* use single style hook

* cover warehouses

* snapshot
This commit is contained in:
Patryk Andrzejewski 2022-09-29 10:40:19 +02:00 committed by GitHub
parent 02c4e8d6e2
commit 2d2151abc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 200 additions and 2633 deletions

View file

@ -17,13 +17,13 @@ const AssignmentListHeader: React.FC<AssignmentListHeaderProps> = ({
itemsName,
loading,
}) => {
const classes = useHeaderStyles();
const { container, skeleton, ...accordion } = useHeaderStyles();
return (
<div className={classes.container}>
<AccordionSummary expandIcon={<IconChevronDown />} classes={classes}>
<div className={container}>
<AccordionSummary expandIcon={<IconChevronDown />} classes={accordion}>
{loading ? (
<Skeleton className={classes.skeleton} />
<Skeleton className={skeleton} />
) : (
<Typography variant="subtitle2" color="textSecondary">
{`${assignCount} ${itemsName.toLowerCase()}`}

View file

@ -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<TErrors>({
<CardSpacer />
</>
)}
<ShippingZones
shippingZonesChoices={getFilteredShippingZonesChoices(
data.shippingZonesToDisplay,
)}
shippingZones={data.shippingZonesToDisplay}
addShippingZone={addShippingZone}
removeShippingZone={removeShippingZone}
searchShippingZones={searchShippingZones}
fetchMoreShippingZones={fetchMoreShippingZones}
totalCount={allShippingZonesCount}
loading={disabled}
/>
<CardSpacer />
<Warehouses
warehousesChoices={getFilteredWarehousesChoices(
data.warehousesToDisplay,
)}
warehouses={data.warehousesToDisplay}
addWarehouse={addWarehouse}
removeWarehouse={removeWarehouse}
searchWarehouses={searchWarehouses}
fetchMoreWarehouses={fetchMoreWarehouses}
totalCount={allWarehousesCount}
reorderWarehouses={reorderWarehouse}
loading={disabled}
/>
<CardSpacer />
<RequirePermissions
requiredPermissions={[PermissionEnum.MANAGE_SHIPPING]}
>
<ShippingZones
shippingZonesChoices={getFilteredShippingZonesChoices(
data.shippingZonesToDisplay,
)}
shippingZones={data.shippingZonesToDisplay}
addShippingZone={addShippingZone}
removeShippingZone={removeShippingZone}
searchShippingZones={searchShippingZones}
fetchMoreShippingZones={fetchMoreShippingZones}
totalCount={allShippingZonesCount}
loading={disabled}
/>
<CardSpacer />
</RequirePermissions>
<RequirePermissions
oneOfPermissions={[
PermissionEnum.MANAGE_SHIPPING,
PermissionEnum.MANAGE_ORDERS,
PermissionEnum.MANAGE_PRODUCTS,
]}
>
<Warehouses
warehousesChoices={getFilteredWarehousesChoices(
data.warehousesToDisplay,
)}
warehouses={data.warehousesToDisplay}
addWarehouse={addWarehouse}
removeWarehouse={removeWarehouse}
searchWarehouses={searchWarehouses}
fetchMoreWarehouses={fetchMoreWarehouses}
totalCount={allWarehousesCount}
reorderWarehouses={reorderWarehouse}
loading={disabled}
/>
<CardSpacer />
</RequirePermissions>
<ChannelAllocationStrategy
data={data}
disabled={disabled}

View file

@ -3,14 +3,11 @@ 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 {
ChannelCreateMutation,
ChannelErrorFragment,
useChannelCreateMutation,
useChannelReorderWarehousesMutation,
useShippingZonesCountQuery,
useWarehousesCountQuery,
} from "@saleor/graphql";
import { getSearchFetchMoreProps } from "@saleor/hooks/makeTopLevelSearch/utils";
import useNavigator from "@saleor/hooks/useNavigator";
@ -19,8 +16,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 currencyCodes from "currency-codes";
import React from "react";
@ -29,6 +24,8 @@ import { useIntl } from "react-intl";
import ChannelDetailsPage from "../../pages/ChannelDetailsPage";
import { channelPath, channelsListUrl } from "../../urls";
import { calculateItemsOrderMoves } from "../ChannelDetails/handlers";
import { useShippingZones } from "../ChannelDetails/useShippingZones";
import { useWarehouses } from "../ChannelDetails/useWarehouses";
export const ChannelCreateView = ({}) => {
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(

View file

@ -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<ChannelDetailsProps> = ({
};
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(

View file

@ -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,
};
};

View file

@ -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,
};
};

View file

@ -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<RequirePermissionsProps> = ({
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";

View file

@ -165,7 +165,10 @@ const SingleAutocompleteSelectFieldComponent: React.FC<SingleAutocompleteSelectF
if (fetchOnFocus) {
fetchChoices(inputValue);
}
input.current.select();
if (input.current) {
input.current.select();
}
};
const handleToggleMenu = () => {

File diff suppressed because it is too large Load diff