import { ContextModule } from "@artsy/cohesion" import InfoIcon from "@artsy/icons/InfoIcon" import { Button, Clickable, Flex, Radio, Spacer, Text, Tooltip, } from "@artsy/palette" import { RadioOptionRow } from "Apps/Order2/Routes/Checkout/Components/RadioOptionRow" import { validateAndExtractOrderResponse } from "Apps/Order/Components/ExpressCheckout/Util/mutationHandling" import { SectionHeading } from "Apps/Order2/Components/SectionHeading" import { CheckoutStepName } from "Apps/Order2/Routes/Checkout/CheckoutContext/types" import { CheckoutErrorBanner, fallbackError, } from "Apps/Order2/Routes/Checkout/Components/CheckoutErrorBanner" import { deliveryOptionLabel, deliveryOptionTimeEstimate, } from "Apps/Order2/Routes/Checkout/Components/DeliveryOptionsStep/utils" import { useCheckoutContext } from "Apps/Order2/Routes/Checkout/Hooks/useCheckoutContext" import { useScrollToErrorBanner } from "Apps/Order2/Routes/Checkout/Hooks/useScrollToErrorBanner" import { useOrder2SetOrderFulfillmentOptionMutation } from "Apps/Order2/Routes/Checkout/Mutations/useOrder2SetOrderFulfillmentOptionMutation" import { BUYER_GUARANTEE_URL } from "Apps/Order2/constants" import { RouterLink } from "System/Components/RouterLink" import type { Order2DeliveryOptionsForm_order$data, Order2DeliveryOptionsForm_order$key, } from "__generated__/Order2DeliveryOptionsForm_order.graphql" import { Form, Formik, type FormikConfig, useFormikContext } from "formik" import { useState } from "react" import { graphql, useFragment } from "react-relay" interface Order2DeliveryOptionsFormProps { order: Order2DeliveryOptionsForm_order$key } type DeliveryOption = Order2DeliveryOptionsForm_order$data["fulfillmentOptions"][number] interface FormValues { deliveryOption: DeliveryOption } export const Order2DeliveryOptionsForm: React.FC< Order2DeliveryOptionsFormProps > = ({ order }) => { const orderData = useFragment(FRAGMENT, order) const { checkoutTracking, setDeliveryOptionComplete, setSectionErrorMessage, messages, } = useCheckoutContext() const setFulfillmentOptionMutation = useOrder2SetOrderFulfillmentOptionMutation() const deliveryOptionError = messages[CheckoutStepName.DELIVERY_OPTION]?.error const errorBannerRef = useScrollToErrorBanner( CheckoutStepName.DELIVERY_OPTION, ) const { fulfillmentOptions, shippingOrigin } = orderData const deliveryOptions = fulfillmentOptions.filter( option => option.type !== "PICKUP", ) const isSingleOption = deliveryOptions.length === 1 const handleSubmit: FormikConfig["onSubmit"] = async ({ deliveryOption, }) => { try { checkoutTracking.clickedOrderProgression( ContextModule.ordersShippingMethods, ) const setFulfillmentOptionResult = await setFulfillmentOptionMutation.submitMutation({ variables: { input: { id: orderData.internalID, fulfillmentOption: { type: deliveryOption.type, }, }, }, }) validateAndExtractOrderResponse( setFulfillmentOptionResult.setOrderFulfillmentOption?.orderOrError, ).order setSectionErrorMessage({ section: CheckoutStepName.DELIVERY_OPTION, error: null, }) setDeliveryOptionComplete() } catch (error) { console.error("Error setting delivery option:", error) setSectionErrorMessage({ section: CheckoutStepName.DELIVERY_OPTION, error: fallbackError("selecting your shipping method", error?.code), }) } } return ( initialValues={{ deliveryOption: deliveryOptions[0] }} onSubmit={handleSubmit} > {({ isSubmitting }) => { return (
{deliveryOptionError && ( <> )} Shipping method Shipping methods depend on location and artwork size. If shipped internationally or part of a show, delivery may take longer. } > {shippingOrigin && ( Ships from {shippingOrigin} )} All options are protected against damage and loss with{" "} checkoutTracking.clickedBuyerProtection( ContextModule.ordersShippingMethods, ) } inline target="_blank" to={BUYER_GUARANTEE_URL} > Artsy’s Buyer Guarantee . {isSingleOption ? ( ) : ( )}
) }} ) } const FRAGMENT = graphql` fragment Order2DeliveryOptionsForm_order on Order { internalID fulfillmentOptions { amount { display } type selected } shippingOrigin } ` interface SingleShippingOptionProps { option: DeliveryOption } const SingleShippingOption = ({ option }: SingleShippingOptionProps) => { const label = deliveryOptionLabel(option.type) const timeEstimate = deliveryOptionTimeEstimate(option.type) const [prefix, timeRange] = timeEstimate || [] return ( {label} {option.amount?.display} {timeEstimate && ( {prefix} {timeRange} )} ) } interface MultipleShippingOptionsFormProps { options: DeliveryOption[] } const MultipleShippingOptionsForm = ({ options, }: MultipleShippingOptionsFormProps) => { const defaultOption = options.find(option => option.selected) || options[0] const [selectedOption, setSelectedOption] = useState(defaultOption) const { setFieldValue } = useFormikContext() const { checkoutTracking } = useCheckoutContext() return ( {options.map((option, i) => { const label = deliveryOptionLabel(option.type) const timeEstimate = deliveryOptionTimeEstimate(option.type) const [prefix, timeRange] = timeEstimate || [] const isSelected = selectedOption === option return ( { setSelectedOption(option) setFieldValue("deliveryOption", option) checkoutTracking.clickedSelectShippingOption(option.type) }} > {label} {option.amount?.display} } value={option} selected={isSelected} > {timeEstimate && ( {prefix} {timeRange} )} {option.type === "ARTSY_WHITE_GLOVE" && isSelected && ( This service includes custom packing, transportation on a fine art shuttle, and in-home delivery. )} ) })} ) }