
* Replace withStyleswith useStyles (#1100) * Replace withStyleswith useStyles * Update messages * Use rem as a spacing unit (#1101) * Use rems as spacing units * Fix visual bugs * Update stories * Use macaw-ui as theme provider (#1108) * Use macaw ui as a theme provider * Add react-dom to aliases * Fix jest module resolution * Update useTheme hook usage * Fix test wrapper * Use macaw from git repo * Fix CI * Update stories * Fix aliasing * Extract savebar to macaw ui (#1146) * wip * Use savebar from macaw * Use confirm button from macaw * Improve file structure * Use sidebar context from macaw * Update macaw * Update macaw version * Remove savebar from storybook * Update stories * Use alerts and notifications from macaw (#1166) * Use alerts from macaw * Add notifications from macaw * Update stories * Pin macaw version * Encapsulate limit reached in one component * Remove unused imports * Use backlinks from macaw (#1183) * Use backlink from macaw * Update macaw version * Use macaw sidebar (#1148) * Use sidebar from macaw * Use shipped logo * Use lowercase * Update stories * Use user chip from macaw (#1191) * Use user chip from macaw * Use dedicated components for menu items * Simplify code * Bump version and fix types (#1210) * Rename onBack to onClick * Rename UserChip to UserChipMenu * Rename IMenuItem to SidebarMenuItem * Update macaw version * Fix tables after changes in macaw (#1220) * Update macaw version * Update changelog * Update stories * Fix after rebase * Update to macaw 0.2.0 * Lint files * Update macaw to 0.2.2
232 lines
8.5 KiB
TypeScript
232 lines
8.5 KiB
TypeScript
import { OutputData } from "@editorjs/editorjs";
|
|
import { ChannelShippingData } from "@saleor/channels/utils";
|
|
import CardSpacer from "@saleor/components/CardSpacer";
|
|
import ChannelsAvailabilityCard from "@saleor/components/ChannelsAvailabilityCard";
|
|
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
|
import Container from "@saleor/components/Container";
|
|
import Form from "@saleor/components/Form";
|
|
import Grid from "@saleor/components/Grid";
|
|
import Metadata from "@saleor/components/Metadata/Metadata";
|
|
import { MetadataFormData } from "@saleor/components/Metadata/types";
|
|
import PageHeader from "@saleor/components/PageHeader";
|
|
import Savebar from "@saleor/components/Savebar";
|
|
import { ShippingChannelsErrorFragment } from "@saleor/fragments/types/ShippingChannelsErrorFragment";
|
|
import { ShippingErrorFragment } from "@saleor/fragments/types/ShippingErrorFragment";
|
|
import { ShippingMethodFragment_postalCodeRules } from "@saleor/fragments/types/ShippingMethodFragment";
|
|
import { Backlink } from "@saleor/macaw-ui";
|
|
import { validatePrice } from "@saleor/products/utils/validation";
|
|
import OrderValue from "@saleor/shipping/components/OrderValue";
|
|
import OrderWeight from "@saleor/shipping/components/OrderWeight";
|
|
import PricingCard from "@saleor/shipping/components/PricingCard";
|
|
import ShippingMethodProducts from "@saleor/shipping/components/ShippingMethodProducts";
|
|
import ShippingRateInfo from "@saleor/shipping/components/ShippingRateInfo";
|
|
import { createChannelsChangeHandler } from "@saleor/shipping/handlers";
|
|
import {
|
|
ShippingZone_shippingZone_shippingMethods,
|
|
ShippingZone_shippingZone_shippingMethods_postalCodeRules
|
|
} from "@saleor/shipping/types/ShippingZone";
|
|
import { ListActions, ListProps } from "@saleor/types";
|
|
import {
|
|
PermissionEnum,
|
|
PostalCodeRuleInclusionTypeEnum,
|
|
ShippingMethodTypeEnum
|
|
} from "@saleor/types/globalTypes";
|
|
import { mapEdgesToItems, mapMetadataItemToInput } from "@saleor/utils/maps";
|
|
import useMetadataChangeTrigger from "@saleor/utils/metadata/useMetadataChangeTrigger";
|
|
import React from "react";
|
|
import { FormattedMessage } from "react-intl";
|
|
|
|
import ShippingZonePostalCodes from "../ShippingZonePostalCodes";
|
|
|
|
export interface FormData extends MetadataFormData {
|
|
channelListings: ChannelShippingData[];
|
|
name: string;
|
|
description: OutputData;
|
|
noLimits: boolean;
|
|
minValue: string;
|
|
maxValue: string;
|
|
minDays: string;
|
|
maxDays: string;
|
|
type: ShippingMethodTypeEnum;
|
|
}
|
|
|
|
export interface ShippingZoneRatesPageProps
|
|
extends Pick<ListProps, Exclude<keyof ListProps, "onRowClick">>,
|
|
ListActions {
|
|
allChannelsCount?: number;
|
|
shippingChannels: ChannelShippingData[];
|
|
disabled: boolean;
|
|
hasChannelChanged?: boolean;
|
|
havePostalCodesChanged?: boolean;
|
|
rate: ShippingZone_shippingZone_shippingMethods;
|
|
channelErrors: ShippingChannelsErrorFragment[];
|
|
errors: ShippingErrorFragment[];
|
|
saveButtonBarState: ConfirmButtonTransitionState;
|
|
postalCodeRules: ShippingZone_shippingZone_shippingMethods_postalCodeRules[];
|
|
onBack: () => void;
|
|
onDelete?: () => void;
|
|
onSubmit: (data: FormData) => void;
|
|
onPostalCodeInclusionChange: (
|
|
inclusion: PostalCodeRuleInclusionTypeEnum
|
|
) => void;
|
|
onPostalCodeAssign: () => void;
|
|
onPostalCodeUnassign: (code: ShippingMethodFragment_postalCodeRules) => void;
|
|
onChannelsChange: (data: ChannelShippingData[]) => void;
|
|
openChannelsModal: () => void;
|
|
onProductAssign: () => void;
|
|
onProductUnassign: (ids: string[]) => void;
|
|
variant: ShippingMethodTypeEnum;
|
|
}
|
|
|
|
export const ShippingZoneRatesPage: React.FC<ShippingZoneRatesPageProps> = ({
|
|
allChannelsCount,
|
|
shippingChannels,
|
|
channelErrors,
|
|
disabled,
|
|
errors,
|
|
hasChannelChanged,
|
|
havePostalCodesChanged,
|
|
onBack,
|
|
onDelete,
|
|
onSubmit,
|
|
onPostalCodeInclusionChange,
|
|
onChannelsChange,
|
|
onPostalCodeAssign,
|
|
onPostalCodeUnassign,
|
|
onProductAssign,
|
|
onProductUnassign,
|
|
openChannelsModal,
|
|
rate,
|
|
saveButtonBarState,
|
|
postalCodeRules,
|
|
variant,
|
|
...listProps
|
|
}) => {
|
|
const isPriceVariant = variant === ShippingMethodTypeEnum.PRICE;
|
|
const initialForm: FormData = {
|
|
channelListings: shippingChannels,
|
|
maxDays: rate?.maximumDeliveryDays?.toString() || "",
|
|
maxValue: rate?.maximumOrderWeight?.value.toString() || "",
|
|
metadata: rate?.metadata.map(mapMetadataItemToInput),
|
|
minDays: rate?.minimumDeliveryDays?.toString() || "",
|
|
minValue: rate?.minimumOrderWeight?.value.toString() || "",
|
|
name: rate?.name || "",
|
|
description: rate?.description && JSON.parse(rate.description),
|
|
noLimits: false,
|
|
privateMetadata: rate?.privateMetadata.map(mapMetadataItemToInput),
|
|
type: rate?.type || null
|
|
};
|
|
|
|
const {
|
|
makeChangeHandler: makeMetadataChangeHandler
|
|
} = useMetadataChangeTrigger();
|
|
|
|
return (
|
|
<Form initial={initialForm} onSubmit={onSubmit}>
|
|
{({ change, data, hasChanged, submit, set, triggerChange }) => {
|
|
const handleChannelsChange = createChannelsChangeHandler(
|
|
shippingChannels,
|
|
onChannelsChange,
|
|
triggerChange
|
|
);
|
|
const formDisabled = data.channelListings?.some(channel =>
|
|
validatePrice(channel.price)
|
|
);
|
|
const onDescriptionChange = (description: OutputData) => {
|
|
set({ description });
|
|
triggerChange();
|
|
};
|
|
|
|
const changeMetadata = makeMetadataChangeHandler(change);
|
|
const formIsUnchanged =
|
|
!hasChanged && !hasChannelChanged && !havePostalCodesChanged;
|
|
|
|
return (
|
|
<Container>
|
|
<Backlink onClick={onBack}>
|
|
<FormattedMessage defaultMessage="Shipping" />
|
|
</Backlink>
|
|
<PageHeader title={rate?.name} />
|
|
<Grid>
|
|
<div>
|
|
<ShippingRateInfo
|
|
data={data}
|
|
disabled={disabled}
|
|
errors={errors}
|
|
onChange={change}
|
|
onDescriptionChange={onDescriptionChange}
|
|
/>
|
|
<CardSpacer />
|
|
{isPriceVariant ? (
|
|
<OrderValue
|
|
channels={data.channelListings}
|
|
errors={channelErrors}
|
|
noLimits={data.noLimits}
|
|
disabled={disabled}
|
|
onChange={change}
|
|
onChannelsChange={handleChannelsChange}
|
|
/>
|
|
) : (
|
|
<OrderWeight
|
|
noLimits={data.noLimits}
|
|
disabled={disabled}
|
|
minValue={data.minValue}
|
|
maxValue={data.maxValue}
|
|
onChange={change}
|
|
errors={errors}
|
|
/>
|
|
)}
|
|
<CardSpacer />
|
|
<PricingCard
|
|
channels={data.channelListings}
|
|
onChange={handleChannelsChange}
|
|
disabled={disabled}
|
|
errors={channelErrors}
|
|
/>
|
|
<CardSpacer />
|
|
<ShippingZonePostalCodes
|
|
disabled={disabled}
|
|
onPostalCodeDelete={onPostalCodeUnassign}
|
|
onPostalCodeInclusionChange={onPostalCodeInclusionChange}
|
|
onPostalCodeRangeAdd={onPostalCodeAssign}
|
|
postalCodes={postalCodeRules}
|
|
/>
|
|
<CardSpacer />
|
|
<ShippingMethodProducts
|
|
products={mapEdgesToItems(rate?.excludedProducts)}
|
|
onProductAssign={onProductAssign}
|
|
onProductUnassign={onProductUnassign}
|
|
disabled={disabled}
|
|
{...listProps}
|
|
/>
|
|
<CardSpacer />
|
|
<Metadata data={data} onChange={changeMetadata} />
|
|
</div>
|
|
<div>
|
|
<ChannelsAvailabilityCard
|
|
managePermissions={[PermissionEnum.MANAGE_SHIPPING]}
|
|
allChannelsCount={allChannelsCount}
|
|
selectedChannelsCount={shippingChannels?.length}
|
|
channelsList={data.channelListings.map(channel => ({
|
|
id: channel.id,
|
|
name: channel.name
|
|
}))}
|
|
openModal={openChannelsModal}
|
|
/>
|
|
</div>
|
|
</Grid>
|
|
<Savebar
|
|
disabled={disabled || formDisabled || formIsUnchanged}
|
|
onCancel={onBack}
|
|
onDelete={onDelete}
|
|
onSubmit={submit}
|
|
state={saveButtonBarState}
|
|
/>
|
|
</Container>
|
|
);
|
|
}}
|
|
</Form>
|
|
);
|
|
};
|
|
|
|
export default ShippingZoneRatesPage;
|