import { Button } from "@material-ui/core"; import { createShippingChannelsFromRate, createSortedShippingChannels } from "@saleor/channels/utils"; import ChannelsAvailabilityDialog from "@saleor/components/ChannelsAvailabilityDialog"; import { WindowTitle } from "@saleor/components/WindowTitle"; import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; import { PAGINATE_BY } from "@saleor/config"; import useBulkActions from "@saleor/hooks/useBulkActions"; import useChannels from "@saleor/hooks/useChannels"; import useLocalPaginator, { useLocalPaginationState } from "@saleor/hooks/useLocalPaginator"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; import { sectionNames } from "@saleor/intl"; import { commonMessages } from "@saleor/intl"; import { getById, getByUnmatchingId } from "@saleor/orders/components/OrderReturnPage/utils"; import useProductSearch from "@saleor/searches/useProductSearch"; import DeleteShippingRateDialog from "@saleor/shipping/components/DeleteShippingRateDialog"; import ShippingMethodProductsAddDialog from "@saleor/shipping/components/ShippingMethodProductsAddDialog"; import ShippingZonePostalCodeRangeDialog from "@saleor/shipping/components/ShippingZonePostalCodeRangeDialog"; import ShippingZoneRatesPage from "@saleor/shipping/components/ShippingZoneRatesPage"; import { ShippingZoneRateUpdateFormData } from "@saleor/shipping/components/ShippingZoneRatesPage/types"; import UnassignDialog from "@saleor/shipping/components/UnassignDialog"; import { getShippingMethodChannelVariables, getUpdateShippingPriceRateVariables } from "@saleor/shipping/handlers"; import { useShippingMethodChannelListingUpdate, useShippingPriceExcludeProduct, useShippingPriceRemoveProductsFromExclude, useShippingRateDelete, useShippingRateUpdate } from "@saleor/shipping/mutations"; import { useShippingZone } from "@saleor/shipping/queries"; import { shippingPriceRatesEditUrl, ShippingRateUrlDialog, ShippingRateUrlQueryParams, shippingZoneUrl } from "@saleor/shipping/urls"; import postalCodesReducer from "@saleor/shipping/views/reducer"; import { filterPostalCodes, getPostalCodeRuleByMinMax, getRuleObject } from "@saleor/shipping/views/utils"; import { MinMax } from "@saleor/types"; import { PostalCodeRuleInclusionTypeEnum, ShippingMethodTypeEnum } from "@saleor/types/globalTypes"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createMetadataUpdateHandler from "@saleor/utils/handlers/metadataUpdateHandler"; import { mapEdgesToItems } from "@saleor/utils/maps"; import { useMetadataUpdate, usePrivateMetadataUpdate } from "@saleor/utils/metadata/updateMetadata"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; export interface PriceRatesUpdateProps { id: string; rateId: string; params: ShippingRateUrlQueryParams; } export const PriceRatesUpdate: React.FC = ({ id, rateId, params }) => { const navigate = useNavigator(); const notify = useNotifier(); const intl = useIntl(); const [paginationState, setPaginationState] = useLocalPaginationState( PAGINATE_BY ); const paginate = useLocalPaginator(setPaginationState); const { data, loading, refetch } = useShippingZone({ displayLoader: true, variables: { id, ...paginationState } }); const channelsData = data?.shippingZone?.channels; const rate = data?.shippingZone?.shippingMethods?.find(getById(rateId)); const { loadMore, search: productsSearch, result: productsSearchOpts } = useProductSearch({ variables: DEFAULT_INITIAL_SEARCH_DATA }); const [openModal, closeModal] = createDialogActionHandlers< ShippingRateUrlDialog, ShippingRateUrlQueryParams >(navigate, params => shippingPriceRatesEditUrl(id, rateId, params), params); const { isSelected, listElements, reset, toggle, toggleAll } = useBulkActions( [] ); const { loadNextPage, loadPreviousPage, pageInfo } = paginate( rate?.excludedProducts.pageInfo, paginationState ); const [ updateShippingMethodChannelListing, updateShippingMethodChannelListingOpts ] = useShippingMethodChannelListingUpdate({}); const [ unassignProduct, unassignProductOpts ] = useShippingPriceRemoveProductsFromExclude({ onCompleted: data => { if (data.shippingPriceRemoveProductFromExclude.errors.length === 0) { handleSuccess(); refetch(); closeModal(); } } }); const [assignProduct, assignProductOpts] = useShippingPriceExcludeProduct({ onCompleted: data => { if (data.shippingPriceExcludeProducts.errors.length === 0) { handleSuccess(); refetch(); closeModal(); } } }); const shippingChannels = createShippingChannelsFromRate( rate?.channelListings ); const allChannels = createSortedShippingChannels(channelsData); const { channelListElements, channelsToggle, currentChannels, handleChannelsConfirm, handleChannelsModalClose, handleChannelsModalOpen, isChannelSelected, isChannelsModalOpen, setCurrentChannels, toggleAllChannels } = useChannels(shippingChannels, params?.action, { closeModal, openModal }); const [updateShippingRate, updateShippingRateOpts] = useShippingRateUpdate( {} ); const handleSuccess = () => { notify({ status: "success", text: intl.formatMessage(commonMessages.savedChanges) }); }; const [deleteShippingRate, deleteShippingRateOpts] = useShippingRateDelete({ onCompleted: data => { if (data.shippingPriceDelete.errors.length === 0) { handleSuccess(); navigate(shippingZoneUrl(id)); } } }); const [updateMetadata] = useMetadataUpdate({}); const [updatePrivateMetadata] = usePrivateMetadataUpdate({}); const [state, dispatch] = React.useReducer(postalCodesReducer, { codesToDelete: [], havePostalCodesChanged: false, inclusionType: rate?.postalCodeRules[0]?.inclusionType, originalCodes: [], postalCodeRules: rate?.postalCodeRules || [] }); const postalCodeRulesLoaded = !loading && !state.postalCodeRules?.length && !state.codesToDelete?.length && rate?.postalCodeRules?.length; if (postalCodeRulesLoaded) { dispatch({ postalCodeRules: rate.postalCodeRules }); } const onPostalCodeInclusionChange = ( inclusion: PostalCodeRuleInclusionTypeEnum ) => { dispatch({ codesToDelete: rate.postalCodeRules.map(code => code.id), havePostalCodesChanged: true, inclusionType: inclusion, postalCodeRules: [] }); }; const updateData = async ( formData: ShippingZoneRateUpdateFormData ): Promise => { const response = await updateShippingRate({ variables: getUpdateShippingPriceRateVariables( formData, id, rateId, state.postalCodeRules, state.codesToDelete ) }); dispatch({ codesToDelete: [] }); const errors = response.data.shippingPriceUpdate.errors; if (errors.length === 0) { handleSuccess(); dispatch({ havePostalCodesChanged: false }); updateShippingMethodChannelListing({ variables: getShippingMethodChannelVariables( rateId, formData.orderValueRestricted, formData.channelListings, shippingChannels ) }); } return errors; }; const handleSubmit = createMetadataUpdateHandler( rate, updateData, variables => updateMetadata({ variables }), variables => updatePrivateMetadata({ variables }) ); const handleProductAssign = (ids: string[]) => assignProduct({ variables: { id: rateId, input: { products: ids } } }); const handleProductUnassign = (ids: string[]) => { unassignProduct({ variables: { id: rateId, products: ids } }); reset(); }; const onPostalCodeAssign = (rule: MinMax) => { if (!state.originalCodes.length) { dispatch({ originalCodes: rate.postalCodeRules }); } if ( state.postalCodeRules.filter(getPostalCodeRuleByMinMax(rule)).length > 0 ) { closeModal(); return; } const newCode = getRuleObject(rule, state.inclusionType); dispatch({ havePostalCodesChanged: true, postalCodeRules: [...state.postalCodeRules, newCode] }); closeModal(); }; const onPostalCodeUnassign = code => { if (code.id !== undefined) { dispatch({ codesToDelete: [...state.codesToDelete, code.id], havePostalCodesChanged: true, postalCodeRules: state.postalCodeRules.filter( getByUnmatchingId(code.id) ) }); } else { dispatch({ havePostalCodesChanged: true, postalCodeRules: filterPostalCodes(state.postalCodeRules, code) }); } }; const handleBack = () => navigate(shippingZoneUrl(id)); return ( <> {!!allChannels?.length && ( )} deleteShippingRate({ variables: { id: rateId } }) } open={params.action === "remove"} name={rate?.name} /> handleProductUnassign(listElements)} /> suggestedProduct.id )} onClose={closeModal} onFetch={productsSearch} onFetchMore={loadMore} onSubmit={handleProductAssign} /> openModal("remove")} onSubmit={handleSubmit} onBack={handleBack} rate={rate} errors={updateShippingRateOpts.data?.shippingPriceUpdate.errors || []} channelErrors={ updateShippingMethodChannelListingOpts?.data ?.shippingMethodChannelListingUpdate?.errors || [] } openChannelsModal={handleChannelsModalOpen} onChannelsChange={setCurrentChannels} onProductUnassign={handleProductUnassign} onProductAssign={() => openModal("assign-product")} variant={ShippingMethodTypeEnum.PRICE} isChecked={isSelected} selected={listElements.length} toggle={toggle} toggleAll={toggleAll} onNextPage={loadNextPage} onPreviousPage={loadPreviousPage} pageInfo={pageInfo} toolbar={ } onPostalCodeInclusionChange={onPostalCodeInclusionChange} onPostalCodeAssign={() => openModal("add-range")} onPostalCodeUnassign={onPostalCodeUnassign} postalCodeRules={state.postalCodeRules} /> onPostalCodeAssign(code)} open={params.action === "add-range"} /> ); }; export default PriceRatesUpdate;