import { ChannelShippingData } from "@dashboard/channels/utils"; import { CountryFragment, CreateShippingRateMutationVariables, PostalCodeRuleInclusionTypeEnum, ShippingMethodChannelListingUpdateMutationVariables, ShippingMethodTypeEnum, ShippingMethodTypeFragment, ShippingPostalCodeRulesCreateInputRange, UpdateShippingRateMutationVariables, useCreateShippingRateMutation, useDeleteShippingRateMutation, useShippingMethodChannelListingUpdateMutation, } from "@dashboard/graphql"; import useNavigator from "@dashboard/hooks/useNavigator"; import useNotifier from "@dashboard/hooks/useNotifier"; import { commonMessages } from "@dashboard/intl"; import { extractMutationErrors, getMutationState } from "@dashboard/misc"; import { getParsedDataForJsonStringField } from "@dashboard/utils/richText/misc"; import differenceBy from "lodash/differenceBy"; import { useIntl } from "react-intl"; import { ShippingZoneRateCommonFormData } from "./components/ShippingZoneRatesPage/types"; import { shippingRateEditUrl } from "./urls"; export const createChannelsChangeHandler = ( selectedChannels: ChannelShippingData[], setSelectedChannels: (channels: ChannelShippingData[]) => void, triggerChange: () => void, ) => ( channelId: string, value: { maxValue: string; minValue: string; price: string }, ) => { const itemIndex = selectedChannels.findIndex(item => item.id === channelId); const channel = selectedChannels[itemIndex]; setSelectedChannels([ ...selectedChannels.slice(0, itemIndex), { ...channel, maxValue: value.maxValue, minValue: value.minValue, price: value.price, }, ...selectedChannels.slice(itemIndex + 1), ]); triggerChange(); }; const getPostalCodeRulesToAdd = ( rules: ShippingMethodTypeFragment["postalCodeRules"], ) => rules .filter(code => !code.id || code.id === "0") .map( code => ({ end: code.end, start: code.start, } as ShippingPostalCodeRulesCreateInputRange), ); export function getCreateShippingPriceRateVariables( data: ShippingZoneRateCommonFormData, id: string, addPostalCodeRules: ShippingMethodTypeFragment["postalCodeRules"], inclusionType: PostalCodeRuleInclusionTypeEnum, ): CreateShippingRateMutationVariables { const parsedMinDays = parseInt(data.minDays, 10); const parsedMaxDays = parseInt(data.maxDays, 10); const postalCodeRules = getPostalCodeRulesToAdd(addPostalCodeRules); return { input: { addPostalCodeRules: postalCodeRules, inclusionType, maximumDeliveryDays: parsedMaxDays, minimumDeliveryDays: parsedMinDays, name: data.name, shippingZone: id, type: ShippingMethodTypeEnum.PRICE, description: getParsedDataForJsonStringField(data.description), }, }; } export function getCreateShippingWeightRateVariables( data: ShippingZoneRateCommonFormData, id: string, addPostalCodeRules: ShippingMethodTypeFragment["postalCodeRules"], inclusionType: PostalCodeRuleInclusionTypeEnum, ): CreateShippingRateMutationVariables { const parsedMinValue = parseFloat(data.minValue); const parsedMaxValue = parseFloat(data.maxValue); const parsedMinDays = parseInt(data.minDays, 10); const parsedMaxDays = parseInt(data.maxDays, 10); const isWeightSet = data.orderValueRestricted; const postalCodeRules = getPostalCodeRulesToAdd(addPostalCodeRules); return { input: { addPostalCodeRules: postalCodeRules, inclusionType, maximumDeliveryDays: parsedMaxDays, maximumOrderWeight: isWeightSet ? parsedMaxValue : null, minimumDeliveryDays: parsedMinDays, minimumOrderWeight: isWeightSet ? parsedMinValue : null, name: data.name, shippingZone: id, type: ShippingMethodTypeEnum.WEIGHT, description: getParsedDataForJsonStringField(data.description), }, }; } export function getUpdateShippingPriceRateVariables( data: ShippingZoneRateCommonFormData, id: string, rateId: string, addPostalCodeRules: ShippingMethodTypeFragment["postalCodeRules"], deletePostalCodeRules: string[], ): UpdateShippingRateMutationVariables { const parsedMinDays = parseInt(data.minDays, 10); const parsedMaxDays = parseInt(data.maxDays, 10); const postalCodeRules = getPostalCodeRulesToAdd(addPostalCodeRules); return { id: rateId, input: { addPostalCodeRules: postalCodeRules, deletePostalCodeRules, inclusionType: addPostalCodeRules[0]?.inclusionType || PostalCodeRuleInclusionTypeEnum.EXCLUDE, maximumDeliveryDays: parsedMaxDays, minimumDeliveryDays: parsedMinDays, name: data.name, shippingZone: id, type: ShippingMethodTypeEnum.PRICE, description: getParsedDataForJsonStringField(data.description), taxClass: data.taxClassId, }, }; } export function getUpdateShippingWeightRateVariables( data: ShippingZoneRateCommonFormData, id: string, rateId: string, addPostalCodeRules: ShippingMethodTypeFragment["postalCodeRules"], deletePostalCodeRules: string[], ): UpdateShippingRateMutationVariables { const parsedMinValue = parseFloat(data.minValue); const parsedMaxValue = parseFloat(data.maxValue); const parsedMinDays = parseInt(data.minDays, 10); const parsedMaxDays = parseInt(data.maxDays, 10); const isWeightSet = data.orderValueRestricted; const postalCodeRules = getPostalCodeRulesToAdd(addPostalCodeRules); return { id: rateId, input: { addPostalCodeRules: postalCodeRules, deletePostalCodeRules, inclusionType: addPostalCodeRules[0]?.inclusionType || PostalCodeRuleInclusionTypeEnum.EXCLUDE, maximumDeliveryDays: parsedMaxDays, maximumOrderWeight: isWeightSet ? parsedMaxValue : null, minimumDeliveryDays: parsedMinDays, minimumOrderWeight: isWeightSet ? parsedMinValue : null, name: data.name, shippingZone: id, type: ShippingMethodTypeEnum.WEIGHT, description: getParsedDataForJsonStringField(data.description), taxClass: data.taxClassId, }, }; } export function getShippingMethodChannelVariables( id: string, orderValueRestricted: boolean, formChannels: ChannelShippingData[], prevChannels?: ChannelShippingData[], ): ShippingMethodChannelListingUpdateMutationVariables { const removeChannels = prevChannels ? differenceBy(prevChannels, formChannels, "id").map(({ id }) => id) : []; return { id, input: { addChannels: formChannels?.map(channel => ({ channelId: channel.id, maximumOrderPrice: channel.maxValue && orderValueRestricted ? channel.maxValue : null, minimumOrderPrice: channel.minValue && orderValueRestricted ? channel.minValue : null, price: channel.price, })) || [], removeChannels, }, }; } export function useShippingRateCreator( shippingZoneId: string, type: ShippingMethodTypeEnum, postalCodes: ShippingMethodTypeFragment["postalCodeRules"], inclusionType: PostalCodeRuleInclusionTypeEnum, ) { const intl = useIntl(); const notify = useNotifier(); const navigate = useNavigator(); const [ createBaseShippingRate, createBaseShippingRateOpts, ] = useCreateShippingRateMutation({}); const [ updateShippingMethodChannelListing, updateShippingMethodChannelListingOpts, ] = useShippingMethodChannelListingUpdateMutation({}); const [deleteShippingRate] = useDeleteShippingRateMutation({}); const getVariables = type === ShippingMethodTypeEnum.PRICE ? getCreateShippingPriceRateVariables : getCreateShippingWeightRateVariables; const createShippingRate = async (data: ShippingZoneRateCommonFormData) => { const response = await createBaseShippingRate({ variables: getVariables(data, shippingZoneId, postalCodes, inclusionType), }); const createErrors = response.data.shippingPriceCreate.errors; if (createErrors.length > 0) { return createErrors; } const rateId = response.data.shippingPriceCreate.shippingMethod.id; const errors = await extractMutationErrors( updateShippingMethodChannelListing({ variables: getShippingMethodChannelVariables( rateId, data.orderValueRestricted, data.channelListings, ), }), ); if (errors.length > 0) { deleteShippingRate({ variables: { id: rateId, }, }); notify({ status: "error", text: intl.formatMessage(commonMessages.somethingWentWrong), }); return errors; } else { notify({ status: "success", text: intl.formatMessage(commonMessages.savedChanges), }); navigate(shippingRateEditUrl(shippingZoneId, rateId)); return []; } }; const called = createBaseShippingRateOpts.called || updateShippingMethodChannelListingOpts.called; const loading = createBaseShippingRateOpts.loading || updateShippingMethodChannelListingOpts.loading; const errors = [ ...(createBaseShippingRateOpts.data?.shippingPriceCreate.errors || []), ]; const channelErrors = updateShippingMethodChannelListingOpts.data ?.shippingMethodChannelListingUpdate.errors || []; return { channelErrors, createShippingRate, errors, status: getMutationState(called, loading, [...errors, ...channelErrors]), }; } export function getCountrySelectionMap( countries?: CountryFragment[], countriesSelected?: string[], ) { return ( countriesSelected && countries?.reduce((acc, country) => { acc[country.code] = !!countriesSelected.find( selectedCountries => selectedCountries === country.code, ); return acc; }, {} as Map) ); } export function isRestWorldCountriesSelected( restWorldCountries?: string[], countrySelectionMap?: Map, ) { return ( countrySelectionMap && restWorldCountries?.every(countryCode => countrySelectionMap[countryCode]) ); }