saleor-dashboard/src/channels/views/ChannelDetails/ChannelDetails.tsx
Dawid f1ffb5093f
Add assign warehouse section in channel page (#2127)
* Add assign warehouse section in channel page

* Update data-test-ids on channel page

* Update channel page form details

* Update shipping zones and warehouses cards in chaannel page

* Assigning warehouses by channel in product and variant pages (#2135)

* Assigning warehouses by channel in product and variant pages

* Disable warehouse assignment when no channel on variant page

* Update products stocks section messages
2022-07-11 11:43:08 +02:00

272 lines
7.9 KiB
TypeScript

import ChannelDeleteDialog from "@saleor/channels/components/ChannelDeleteDialog";
import { FormData } from "@saleor/channels/components/ChannelForm/ChannelForm";
import { getChannelsCurrencyChoices } from "@saleor/channels/utils";
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,
ChannelUpdateMutation,
useChannelActivateMutation,
useChannelDeactivateMutation,
useChannelDeleteMutation,
useChannelQuery,
useChannelShippingZonesQuery,
useChannelsQuery,
useChannelUpdateMutation,
useChannelWarehousesQuery,
} from "@saleor/graphql";
import { getSearchFetchMoreProps } from "@saleor/hooks/makeTopLevelSearch/utils";
import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier";
import { getDefaultNotifierSuccessErrorData } from "@saleor/hooks/useNotifier/utils";
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 React from "react";
import { useIntl } from "react-intl";
import ChannelDetailsPage from "../../pages/ChannelDetailsPage";
import {
channelsListUrl,
channelUrl,
ChannelUrlDialog,
ChannelUrlQueryParams,
} from "../../urls";
interface ChannelDetailsProps {
id: string;
params: ChannelUrlQueryParams;
}
export const ChannelDetails: React.FC<ChannelDetailsProps> = ({
id,
params,
}) => {
const navigate = useNavigator();
const notify = useNotifier();
const intl = useIntl();
const shop = useShop();
const channelsListData = useChannelsQuery({ displayLoader: true });
const [openModal, closeModal] = createDialogActionHandlers<
ChannelUrlDialog,
ChannelUrlQueryParams
>(navigate, params => channelUrl(id, params), params);
const [updateChannel, updateChannelOpts] = useChannelUpdateMutation({
onCompleted: ({ channelUpdate: { errors } }: ChannelUpdateMutation) =>
notify(getDefaultNotifierSuccessErrorData(errors, intl)),
});
const { data, loading } = useChannelQuery({
displayLoader: true,
variables: { id },
});
const handleError = (error: ChannelErrorFragment) => {
notify({
status: "error",
text: getChannelsErrorMessage(error, intl),
});
};
const [activateChannel, activateChannelOpts] = useChannelActivateMutation({
onCompleted: data => {
const errors = data.channelActivate.errors;
if (errors.length) {
errors.forEach(error => handleError(error));
}
},
});
const [
deactivateChannel,
deactivateChannelOpts,
] = useChannelDeactivateMutation({
onCompleted: data => {
const errors = data.channelDeactivate.errors;
if (errors.length) {
errors.forEach(error => handleError(error));
}
},
});
const handleSubmit = ({
name,
slug,
shippingZonesIdsToRemove,
shippingZonesIdsToAdd,
warehousesIdsToRemove,
warehousesIdsToAdd,
defaultCountry,
}: FormData) =>
extractMutationErrors(
updateChannel({
variables: {
id: data?.channel.id,
input: {
name,
slug,
defaultCountry,
addShippingZones: shippingZonesIdsToAdd,
removeShippingZones: shippingZonesIdsToRemove,
addWarehouses: warehousesIdsToAdd,
removeWarehouses: warehousesIdsToRemove,
},
},
}),
);
const onDeleteCompleted = (data: ChannelDeleteMutation) => {
const errors = data.channelDelete.errors;
if (errors.length === 0) {
notify({
status: "success",
text: intl.formatMessage({
id: "AkyGP2",
defaultMessage: "Channel deleted",
}),
});
closeModal();
navigate(channelsListUrl());
} else {
errors.map(error =>
notify({
status: "error",
text: getChannelsErrorMessage(error, intl),
}),
);
}
};
const [deleteChannel, deleteChannelOpts] = useChannelDeleteMutation({
onCompleted: onDeleteCompleted,
});
const channelsChoices = getChannelsCurrencyChoices(
id,
data?.channel,
channelsListData?.data?.channels,
);
const handleRemoveConfirm = (channelId?: string) => {
const data = channelId ? { id, input: { channelId } } : { id };
deleteChannel({ variables: data });
};
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: channelWarehousesData,
loading: channelsWarehousesLoading,
} = useChannelWarehousesQuery({
variables: {
filter: {
channels: [id],
},
},
});
const {
loadMore: fetchMoreWarehouses,
search: searchWarehouses,
result: searchWarehousesResult,
} = useWarehouseSearch({
variables: DEFAULT_INITIAL_SEARCH_DATA,
});
return (
<>
<WindowTitle
title={intl.formatMessage({
id: "D9Rg+F",
defaultMessage: "Channel details",
description: "window title",
})}
/>
<Container>
<Backlink href={channelsListUrl()}>
{intl.formatMessage(sectionNames.channels)}
</Backlink>
<PageHeader title={data?.channel?.name} />
<ChannelDetailsPage
channelShippingZones={channelShippingZonesData?.shippingZones?.edges?.map(
({ node }) => node,
)}
searchShippingZones={searchShippingZones}
searchShippingZonesData={searchShippingZonesResult.data}
fetchMoreShippingZones={getSearchFetchMoreProps(
searchShippingZonesResult,
fetchMoreShippingZones,
)}
channelWarehouses={channelWarehousesData?.warehouses?.edges?.map(
({ node }) => node,
)}
searchWarehouses={searchWarehouses}
searchWarehousesData={searchWarehousesResult.data}
fetchMoreWarehouses={getSearchFetchMoreProps(
searchWarehousesResult,
fetchMoreWarehouses,
)}
channel={data?.channel}
disabled={
updateChannelOpts.loading ||
loading ||
channelsShippingZonesLoading ||
channelsWarehousesLoading
}
disabledStatus={
activateChannelOpts.loading || deactivateChannelOpts.loading
}
errors={updateChannelOpts?.data?.channelUpdate?.errors || []}
onDelete={() => openModal("remove")}
onSubmit={handleSubmit}
updateChannelStatus={() =>
data?.channel?.isActive
? deactivateChannel({ variables: { id } })
: activateChannel({ variables: { id } })
}
saveButtonBarState={updateChannelOpts.status}
countries={shop?.countries || []}
/>
</Container>
<ChannelDeleteDialog
channelsChoices={channelsChoices}
hasOrders={data?.channel?.hasOrders}
open={params.action === "remove"}
confirmButtonState={deleteChannelOpts.status}
onBack={() => navigate(channelsListUrl())}
onClose={closeModal}
onConfirm={handleRemoveConfirm}
/>
</>
);
};
export default ChannelDetails;