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:
parent
02c4e8d6e2
commit
2d2151abc0
9 changed files with 200 additions and 2633 deletions
|
@ -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()}`}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
52
src/channels/views/ChannelDetails/useShippingZones.ts
Normal file
52
src/channels/views/ChannelDetails/useShippingZones.ts
Normal 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,
|
||||
};
|
||||
};
|
36
src/channels/views/ChannelDetails/useWarehouses.ts
Normal file
36
src/channels/views/ChannelDetails/useWarehouses.ts
Normal 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,
|
||||
};
|
||||
};
|
|
@ -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";
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue