diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cf729cbda..7fd9606baf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ All notable, unreleased changes to this project will be documented in this file. - Change register mutation to accountRegister - #549 by @tomaszszymanski129 - Add `ProductVariantPicker` component supporting multiple product variant attributes - #550 by @orzechdev - Fix not working storefront when no data in saleor database exist - #551 by @orzechdev +- Make checkout working without shipping if it is not required - #571 by @orzechdev ## 0.7.0 diff --git a/package-lock.json b/package-lock.json index 078da1fcbc..fbec30798a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16901,17 +16901,17 @@ "dev": true }, "graphql": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.2.tgz", - "integrity": "sha512-gUC4YYsaiSJT1h40krG3J+USGlwhzNTXSb4IOZljn9ag5Tj+RkoXrWp+Kh7WyE3t1NCfab5kzCuxBIvOMERMXw==", + "version": "14.5.8", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.5.8.tgz", + "integrity": "sha512-MMwmi0zlVLQKLdGiMfWkgQD7dY/TUKt4L+zgJ/aR0Howebod3aNgP5JkgvAULiR2HPVZaP2VEElqtdidHweLkg==", "requires": { "iterall": "^1.2.2" } }, "graphql-tag": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.0.tgz", - "integrity": "sha512-9FD6cw976TLLf9WYIUPCaaTpniawIjHWZSwIRZSjrfufJamcXbVVYfN2TWvJYbw0Xf2JjYbl1/f2+wDnBVw3/w==" + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.1.tgz", + "integrity": "sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg==" }, "growly": { "version": "1.3.0", @@ -18937,9 +18937,9 @@ } }, "iterall": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", - "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz", + "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==" }, "java-properties": { "version": "1.0.2", diff --git a/package.json b/package.json index ba22f9d10e..397867e1ee 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,8 @@ "dompurify": "^2.0.7", "draftjs-to-html": "^0.8.4", "formik": "^1.5.7", - "graphql": "^14.0.2", - "graphql-tag": "^2.9.2", + "graphql": "^14.5.8", + "graphql-tag": "^2.10.1", "history": "^4.7.2", "isomorphic-fetch": "^2.2.1", "js-base64": "^2.4.8", diff --git a/src/@sdk/fragments/checkout.ts b/src/@sdk/fragments/checkout.ts index 17dc52fa84..25759f4748 100644 --- a/src/@sdk/fragments/checkout.ts +++ b/src/@sdk/fragments/checkout.ts @@ -108,9 +108,6 @@ export const checkoutFragment = gql` } token id - user { - email - } totalPrice { ...Price } @@ -136,5 +133,6 @@ export const checkoutFragment = gql` lines { ...CheckoutLine } + isShippingRequired } `; diff --git a/src/@sdk/fragments/types/Checkout.ts b/src/@sdk/fragments/types/Checkout.ts index 3e41f702c4..3003e01e71 100644 --- a/src/@sdk/fragments/types/Checkout.ts +++ b/src/@sdk/fragments/types/Checkout.ts @@ -30,11 +30,6 @@ export interface Checkout_availablePaymentGateways { config: Checkout_availablePaymentGateways_config[]; } -export interface Checkout_user { - __typename: "User"; - email: string; -} - export interface Checkout_totalPrice_gross { __typename: "Money"; /** @@ -529,7 +524,6 @@ export interface Checkout { * The ID of the object. */ id: string; - user: Checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -557,4 +551,8 @@ export interface Checkout { * A list of checkout lines, each containing information about an item in the checkout. */ lines: (Checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } diff --git a/src/@sdk/index.ts b/src/@sdk/index.ts index 5610d29b97..415be9758c 100644 --- a/src/@sdk/index.ts +++ b/src/@sdk/index.ts @@ -16,13 +16,13 @@ import { MapFn, QueryShape, WatchMapFn, - WatchQueryData + WatchQueryData, } from "./types"; import { getErrorsFromData, getMappedData, isDataEmpty, - mergeEdges + mergeEdges, } from "./utils"; import { UserDetails } from "./queries/types/UserDetails"; @@ -88,6 +88,11 @@ export class SaleorAPI { data.me ? data.me.checkout : null ); + getVariantsProducts = this.watchQuery( + QUERIES.VariantsProducts, + data => data.productVariants + ); + setUserDefaultAddress = this.fireQuery( MUTATIONS.AddressTypeUpdate, data => data!.accountSetDefaultAddress diff --git a/src/@sdk/mutations/checkout.ts b/src/@sdk/mutations/checkout.ts index 9c52b810fa..7f53cd23ba 100644 --- a/src/@sdk/mutations/checkout.ts +++ b/src/@sdk/mutations/checkout.ts @@ -3,7 +3,7 @@ import gql from "graphql-tag"; import { checkoutFragment, checkoutLineFragment, - checkoutPriceFragment + checkoutPriceFragment, } from "../fragments/checkout"; export const updateCheckoutLineQuery = gql` @@ -19,6 +19,7 @@ export const updateCheckoutLineQuery = gql` subtotalPrice { ...Price } + isShippingRequired } errors { field diff --git a/src/@sdk/mutations/types/CreateCheckout.ts b/src/@sdk/mutations/types/CreateCheckout.ts index d74f885523..12c901b56a 100644 --- a/src/@sdk/mutations/types/CreateCheckout.ts +++ b/src/@sdk/mutations/types/CreateCheckout.ts @@ -45,11 +45,6 @@ export interface CreateCheckout_checkoutCreate_checkout_availablePaymentGateways config: CreateCheckout_checkoutCreate_checkout_availablePaymentGateways_config[]; } -export interface CreateCheckout_checkoutCreate_checkout_user { - __typename: "User"; - email: string; -} - export interface CreateCheckout_checkoutCreate_checkout_totalPrice_gross { __typename: "Money"; /** @@ -544,7 +539,6 @@ export interface CreateCheckout_checkoutCreate_checkout { * The ID of the object. */ id: string; - user: CreateCheckout_checkoutCreate_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -572,6 +566,10 @@ export interface CreateCheckout_checkoutCreate_checkout { * A list of checkout lines, each containing information about an item in the checkout. */ lines: (CreateCheckout_checkoutCreate_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface CreateCheckout_checkoutCreate { diff --git a/src/@sdk/mutations/types/UpdateCheckoutBillingAddress.ts b/src/@sdk/mutations/types/UpdateCheckoutBillingAddress.ts index 078637906a..18f4d9838b 100644 --- a/src/@sdk/mutations/types/UpdateCheckoutBillingAddress.ts +++ b/src/@sdk/mutations/types/UpdateCheckoutBillingAddress.ts @@ -45,11 +45,6 @@ export interface UpdateCheckoutBillingAddress_checkoutBillingAddressUpdate_check config: UpdateCheckoutBillingAddress_checkoutBillingAddressUpdate_checkout_availablePaymentGateways_config[]; } -export interface UpdateCheckoutBillingAddress_checkoutBillingAddressUpdate_checkout_user { - __typename: "User"; - email: string; -} - export interface UpdateCheckoutBillingAddress_checkoutBillingAddressUpdate_checkout_totalPrice_gross { __typename: "Money"; /** @@ -544,7 +539,6 @@ export interface UpdateCheckoutBillingAddress_checkoutBillingAddressUpdate_check * The ID of the object. */ id: string; - user: UpdateCheckoutBillingAddress_checkoutBillingAddressUpdate_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -572,6 +566,10 @@ export interface UpdateCheckoutBillingAddress_checkoutBillingAddressUpdate_check * A list of checkout lines, each containing information about an item in the checkout. */ lines: (UpdateCheckoutBillingAddress_checkoutBillingAddressUpdate_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface UpdateCheckoutBillingAddress_checkoutBillingAddressUpdate { diff --git a/src/@sdk/mutations/types/UpdateCheckoutLine.ts b/src/@sdk/mutations/types/UpdateCheckoutLine.ts index 69e83f5530..71e4fc1106 100644 --- a/src/@sdk/mutations/types/UpdateCheckoutLine.ts +++ b/src/@sdk/mutations/types/UpdateCheckoutLine.ts @@ -283,6 +283,10 @@ export interface UpdateCheckoutLine_checkoutLinesUpdate_checkout { * The price of the checkout before shipping, with taxes included. */ subtotalPrice: UpdateCheckoutLine_checkoutLinesUpdate_checkout_subtotalPrice | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface UpdateCheckoutLine_checkoutLinesUpdate_errors { diff --git a/src/@sdk/mutations/types/UpdateCheckoutShippingAddress.ts b/src/@sdk/mutations/types/UpdateCheckoutShippingAddress.ts index 59daf72680..aa5e87e2d1 100644 --- a/src/@sdk/mutations/types/UpdateCheckoutShippingAddress.ts +++ b/src/@sdk/mutations/types/UpdateCheckoutShippingAddress.ts @@ -45,11 +45,6 @@ export interface UpdateCheckoutShippingAddress_checkoutShippingAddressUpdate_che config: UpdateCheckoutShippingAddress_checkoutShippingAddressUpdate_checkout_availablePaymentGateways_config[]; } -export interface UpdateCheckoutShippingAddress_checkoutShippingAddressUpdate_checkout_user { - __typename: "User"; - email: string; -} - export interface UpdateCheckoutShippingAddress_checkoutShippingAddressUpdate_checkout_totalPrice_gross { __typename: "Money"; /** @@ -544,7 +539,6 @@ export interface UpdateCheckoutShippingAddress_checkoutShippingAddressUpdate_che * The ID of the object. */ id: string; - user: UpdateCheckoutShippingAddress_checkoutShippingAddressUpdate_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -572,6 +566,10 @@ export interface UpdateCheckoutShippingAddress_checkoutShippingAddressUpdate_che * A list of checkout lines, each containing information about an item in the checkout. */ lines: (UpdateCheckoutShippingAddress_checkoutShippingAddressUpdate_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface UpdateCheckoutShippingAddress_checkoutShippingAddressUpdate { @@ -610,11 +608,6 @@ export interface UpdateCheckoutShippingAddress_checkoutEmailUpdate_checkout_avai config: UpdateCheckoutShippingAddress_checkoutEmailUpdate_checkout_availablePaymentGateways_config[]; } -export interface UpdateCheckoutShippingAddress_checkoutEmailUpdate_checkout_user { - __typename: "User"; - email: string; -} - export interface UpdateCheckoutShippingAddress_checkoutEmailUpdate_checkout_totalPrice_gross { __typename: "Money"; /** @@ -1109,7 +1102,6 @@ export interface UpdateCheckoutShippingAddress_checkoutEmailUpdate_checkout { * The ID of the object. */ id: string; - user: UpdateCheckoutShippingAddress_checkoutEmailUpdate_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -1137,6 +1129,10 @@ export interface UpdateCheckoutShippingAddress_checkoutEmailUpdate_checkout { * A list of checkout lines, each containing information about an item in the checkout. */ lines: (UpdateCheckoutShippingAddress_checkoutEmailUpdate_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface UpdateCheckoutShippingAddress_checkoutEmailUpdate_errors { diff --git a/src/@sdk/queries/index.ts b/src/@sdk/queries/index.ts index dec5ba6fb2..22d73d843c 100644 --- a/src/@sdk/queries/index.ts +++ b/src/@sdk/queries/index.ts @@ -1,7 +1,7 @@ import { ApolloClient, ObservableQuery, - QueryOptions as ApolloQueryOptions + QueryOptions as ApolloQueryOptions, } from "apollo-client"; import gql from "graphql-tag"; @@ -14,26 +14,31 @@ import * as Product from "./products"; import { CheckoutDetails, - CheckoutDetailsVariables + CheckoutDetailsVariables, } from "./types/CheckoutDetails"; import { OrderByToken, OrderByTokenVariables } from "./types/OrderByToken"; import { Attributes, AttributesVariables } from "./types/Attributes"; import { ProductDetails, - ProductDetailsVariables + ProductDetailsVariables, } from "./types/ProductDetails"; import { ProductList, ProductListVariables } from "./types/ProductList"; import { CategoryDetails, - CategoryDetailsVariables + CategoryDetailsVariables, } from "./types/CategoryDetails"; import { OrdersByUser, OrdersByUserVariables } from "./types/OrdersByUser"; import { UserCheckoutDetails } from "./types/UserCheckoutDetails"; import { UserDetails } from "./types/UserDetails"; +import { + VariantsProducts, + VariantsProductsVariables, +} from "./types/VariantsProducts"; + import * as User from "./user"; type QueryOptions = T extends { [n: string]: never } @@ -132,6 +137,16 @@ export const QUERIES = { `, ...options, }), + VariantsProducts: ( + client: ApolloClient, + options: QueryOptions + ): ObservableQuery => + client.watchQuery({ + query: gql` + ${Product.variantsProducts} + `, + ...options, + }), }; export type QUERIES = typeof QUERIES; diff --git a/src/@sdk/queries/products.ts b/src/@sdk/queries/products.ts index bfc9f4d321..bdbe394c54 100644 --- a/src/@sdk/queries/products.ts +++ b/src/@sdk/queries/products.ts @@ -115,3 +115,21 @@ export const productDetails = gql` } } `; + +export const variantsProducts = gql` + query VariantsProducts($ids: [ID]) { + productVariants(ids: $ids, first: 100) { + edges { + node { + id + product { + id + productType { + isShippingRequired + } + } + } + } + } + } +`; diff --git a/src/@sdk/queries/types/CheckoutDetails.ts b/src/@sdk/queries/types/CheckoutDetails.ts index 90c31b518f..076754532a 100644 --- a/src/@sdk/queries/types/CheckoutDetails.ts +++ b/src/@sdk/queries/types/CheckoutDetails.ts @@ -30,11 +30,6 @@ export interface CheckoutDetails_checkout_availablePaymentGateways { config: CheckoutDetails_checkout_availablePaymentGateways_config[]; } -export interface CheckoutDetails_checkout_user { - __typename: "User"; - email: string; -} - export interface CheckoutDetails_checkout_totalPrice_gross { __typename: "Money"; /** @@ -529,7 +524,6 @@ export interface CheckoutDetails_checkout { * The ID of the object. */ id: string; - user: CheckoutDetails_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -557,6 +551,10 @@ export interface CheckoutDetails_checkout { * A list of checkout lines, each containing information about an item in the checkout. */ lines: (CheckoutDetails_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface CheckoutDetails { diff --git a/src/@sdk/queries/types/UserCheckoutDetails.ts b/src/@sdk/queries/types/UserCheckoutDetails.ts index abfed62303..0e35cddab1 100644 --- a/src/@sdk/queries/types/UserCheckoutDetails.ts +++ b/src/@sdk/queries/types/UserCheckoutDetails.ts @@ -30,11 +30,6 @@ export interface UserCheckoutDetails_me_checkout_availablePaymentGateways { config: UserCheckoutDetails_me_checkout_availablePaymentGateways_config[]; } -export interface UserCheckoutDetails_me_checkout_user { - __typename: "User"; - email: string; -} - export interface UserCheckoutDetails_me_checkout_totalPrice_gross { __typename: "Money"; /** @@ -529,7 +524,6 @@ export interface UserCheckoutDetails_me_checkout { * The ID of the object. */ id: string; - user: UserCheckoutDetails_me_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -557,6 +551,10 @@ export interface UserCheckoutDetails_me_checkout { * A list of checkout lines, each containing information about an item in the checkout. */ lines: (UserCheckoutDetails_me_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface UserCheckoutDetails_me { diff --git a/src/@sdk/queries/types/VariantsProducts.ts b/src/@sdk/queries/types/VariantsProducts.ts new file mode 100644 index 0000000000..955798f700 --- /dev/null +++ b/src/@sdk/queries/types/VariantsProducts.ts @@ -0,0 +1,54 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL query operation: VariantsProducts +// ==================================================== + +export interface VariantsProducts_productVariants_edges_node_product_productType { + __typename: "ProductType"; + isShippingRequired: boolean; +} + +export interface VariantsProducts_productVariants_edges_node_product { + __typename: "Product"; + /** + * The ID of the object. + */ + id: string; + productType: VariantsProducts_productVariants_edges_node_product_productType; +} + +export interface VariantsProducts_productVariants_edges_node { + __typename: "ProductVariant"; + /** + * The ID of the object. + */ + id: string; + product: VariantsProducts_productVariants_edges_node_product; +} + +export interface VariantsProducts_productVariants_edges { + __typename: "ProductVariantCountableEdge"; + /** + * The item at the end of the edge. + */ + node: VariantsProducts_productVariants_edges_node; +} + +export interface VariantsProducts_productVariants { + __typename: "ProductVariantCountableConnection"; + edges: VariantsProducts_productVariants_edges[]; +} + +export interface VariantsProducts { + /** + * List of product variants. + */ + productVariants: VariantsProducts_productVariants | null; +} + +export interface VariantsProductsVariables { + ids?: (string | null)[] | null; +} diff --git a/src/@sdk/react/queries.ts b/src/@sdk/react/queries.ts index 5ca2986444..3b3cfb1501 100644 --- a/src/@sdk/react/queries.ts +++ b/src/@sdk/react/queries.ts @@ -19,3 +19,7 @@ export const useCategoryDetails = queryWithVariablesFactory( ); export const useAtrributes = queryWithVariablesFactory("getAttributes"); + +export const useVariantsProducts = queryWithVariablesFactory( + "getVariantsProducts" +); diff --git a/src/@sdk/types/globalTypes.ts b/src/@sdk/types/globalTypes.ts index 2ca548d338..d2603d6203 100644 --- a/src/@sdk/types/globalTypes.ts +++ b/src/@sdk/types/globalTypes.ts @@ -329,7 +329,8 @@ export interface AddressInput { export interface AttributeInput { slug: string; - value: string; + value?: string | null; + values?: (string | null)[] | null; } export interface CheckoutCreateInput { diff --git a/src/checkout/CheckoutProvider.tsx b/src/checkout/CheckoutProvider.tsx index 0bcf9aa075..804603cf99 100644 --- a/src/checkout/CheckoutProvider.tsx +++ b/src/checkout/CheckoutProvider.tsx @@ -3,11 +3,7 @@ import * as React from "react"; import { useLocalStorage } from "@hooks"; import { useAuth, useCheckoutDetails, useUserCheckout } from "@sdk/react"; -import { - CheckoutContext, - CheckoutContextInterface, - CheckoutStep -} from "./context"; +import { CheckoutContext, CheckoutContextInterface } from "./context"; interface ProviderProps { children: React.ReactNode; @@ -54,32 +50,6 @@ export const CheckoutProvider: React.FC = ({ } }, [user.data]); - const getCurrentStep = () => { - if (!state.checkout) { - return CheckoutStep.ShippingAddress; - } - - const isShippingOptionStep = - state.checkout.availableShippingMethods.length && - !!state.checkout.shippingAddress; - const isBillingStep = - isShippingOptionStep && !!state.checkout.shippingMethod; - const isPaymentStep = isBillingStep && !!state.checkout.billingAddress; - const isReviewStep = - isPaymentStep && !!(state.cardData || state.dummyStatus); - - if (isReviewStep) { - return CheckoutStep.Review; - } else if (isPaymentStep) { - return CheckoutStep.Payment; - } else if (isBillingStep) { - return CheckoutStep.BillingAddress; - } else if (isShippingOptionStep) { - return CheckoutStep.ShippingOption; - } - return CheckoutStep.ShippingAddress; - }; - const update = (checkoutData: CheckoutContextInterface) => { setState(prevState => ({ ...prevState, @@ -104,7 +74,6 @@ export const CheckoutProvider: React.FC = ({ const getContext = () => ({ ...state, clear, - step: getCurrentStep(), update, }); diff --git a/src/checkout/components/GuestAddressForm/GuestAddressForm.tsx b/src/checkout/components/GuestAddressForm/GuestAddressForm.tsx index 040d4b56d2..4db3dd086e 100644 --- a/src/checkout/components/GuestAddressForm/GuestAddressForm.tsx +++ b/src/checkout/components/GuestAddressForm/GuestAddressForm.tsx @@ -69,6 +69,7 @@ const GuestAddressForm: React.FC = ({ shippingAsBilling, shop, type = "shipping", + noShipping, }) => ( = ({ loading={loading} shippingAsBilling={shippingAsBilling} onSubmit={proceedToNextStep} + noShipping={noShipping} /> ); diff --git a/src/checkout/components/StepCheck.tsx b/src/checkout/components/StepCheck.tsx deleted file mode 100644 index 8398f9a0c0..0000000000 --- a/src/checkout/components/StepCheck.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import * as React from "react"; -import { generatePath, Redirect } from "react-router"; - -import { CheckoutStep } from "../context"; -import { - baseUrl, - billingUrl, - paymentUrl, - reviewUrl, - shippingAddressUrl, - shippingOptionsUrl -} from "../routes"; -import { Checkout } from "../types/Checkout"; - -/** - * Gets checkout step based on the provided path. - */ -export const getCurrentStep = (path: string, token?: string): CheckoutStep => { - const generatedPath = path => generatePath(path, { token }); - - switch (generatedPath(path)) { - case generatedPath(shippingAddressUrl): - return CheckoutStep.ShippingAddress; - - case generatedPath(shippingOptionsUrl): - return CheckoutStep.ShippingOption; - - case generatedPath(billingUrl): - return CheckoutStep.BillingAddress; - - case generatedPath(paymentUrl): - return CheckoutStep.Payment; - - case generatedPath(reviewUrl): - return CheckoutStep.Review; - - default: - return CheckoutStep.ShippingAddress; - } -}; - -/** - * Redirector to prevent user from entering invalid step by manually pasting the url. - */ -const StepCheck: React.FC<{ - checkout: Checkout; - step: CheckoutStep; - path: string; - token?: string; -}> = ({ step, checkout, path, token, children }) => { - if (!checkout || step < getCurrentStep(path, token)) { - return ; - } - return children ? <>{children} : null; -}; - -export default StepCheck; diff --git a/src/checkout/components/Steps.tsx b/src/checkout/components/Steps.tsx index 16e3829a87..cc0a861c77 100644 --- a/src/checkout/components/Steps.tsx +++ b/src/checkout/components/Steps.tsx @@ -1,12 +1,62 @@ import * as React from "react"; import { generatePath, Link } from "react-router-dom"; +import { useVariantsProducts } from "@sdk/react"; + +import { VariantsProducts_productVariants } from "@sdk/queries/types/VariantsProducts"; import { ShippingOptionSummary } from "."; import { AddressSummary } from "../../components"; +import { CartContext } from "../../components/CartProvider/context"; import { CheckoutStep } from "../context"; import { billingUrl, shippingAddressUrl, shippingOptionsUrl } from "../routes"; import { Checkout } from "../types/Checkout"; +const steps = [ + { + header: "Shipping Address", + path: shippingAddressUrl, + step: CheckoutStep.ShippingAddress, + type: "shipping", + }, + { + header: "Shipping Method", + path: shippingOptionsUrl, + step: CheckoutStep.ShippingOption, + type: "shipping", + }, + { + header: "Billing Address", + path: billingUrl, + step: CheckoutStep.BillingAddress, + }, + { + header: "Payment Method", + step: CheckoutStep.Payment, + }, +]; + +const getAvailableSteps = ( + checkout: Checkout, + variantsProducts: VariantsProducts_productVariants +) => { + if (checkout && checkout.isShippingRequired) { + return steps; + } else if (checkout) { + return steps.filter(({ type }) => type !== "shipping"); + } else if (variantsProducts) { + const isShippingRequired = + variantsProducts.edges && + variantsProducts.edges.some( + ({ node }) => node.product.productType.isShippingRequired + ); + if (isShippingRequired) { + return steps; + } + return steps.filter(({ type }) => type !== "shipping"); + } + return steps; +}; + const getSummary = ( step: CheckoutStep, checkout: Checkout @@ -46,32 +96,20 @@ const Steps: React.FC<{ token?: string; checkout?: Checkout; }> = ({ checkout, step: currentStep, token, children }) => { - const steps = [ - { - header: "Shipping Address", - path: shippingAddressUrl, - step: CheckoutStep.ShippingAddress, - }, - { - header: "Shipping Method", - path: shippingOptionsUrl, - step: CheckoutStep.ShippingOption, - }, - { - header: "Billing Address", - path: billingUrl, - step: CheckoutStep.BillingAddress, - }, - { - header: "Payment Method", - step: CheckoutStep.Payment, - }, - ]; - const currentStepIndex = steps.findIndex(({ step }) => step === currentStep); + const { lines: cardLines } = React.useContext(CartContext); + const { data: variantsProducts } = useVariantsProducts({ + ids: cardLines ? cardLines.map(line => line.variantId) : [], + }); + + const availableSteps = getAvailableSteps(checkout, variantsProducts); + + const currentStepIndex = availableSteps.findIndex( + ({ step }) => step === currentStep + ); return ( <> - {steps.map(({ header, step, path }, index) => ( + {availableSteps.map(({ header, step, path }, index) => ( {currentStepIndex > index ? ( <> @@ -85,7 +123,7 @@ const Steps: React.FC<{

{header}

- {getSummary(step, checkout)} + {checkout && getSummary(step, checkout)} ) : (
diff --git a/src/checkout/components/index.ts b/src/checkout/components/index.ts index 01884e1565..4b81931be4 100644 --- a/src/checkout/components/index.ts +++ b/src/checkout/components/index.ts @@ -1,11 +1,8 @@ export { default as Option } from "./Option"; export { default as ShippingOptionSummary } from "./ShippingOptionSummary"; -export { default as StepCheck } from "./StepCheck"; export { default as Steps } from "./Steps"; export { CartSummary } from "./CartSummary"; export { AddressPicker } from "./AddressPicker"; export { default as GuestAddressForm } from "./GuestAddressForm"; export { default as UserAddressSelector } from "./UserAddressSelector"; -export { - default as ShippingUnavailableModal -} from "./ShippingUnavailableModal"; +export { default as ShippingUnavailableModal } from "./ShippingUnavailableModal"; diff --git a/src/checkout/context.tsx b/src/checkout/context.tsx index bae05b3619..e3ed1a4a52 100644 --- a/src/checkout/context.tsx +++ b/src/checkout/context.tsx @@ -1,5 +1,6 @@ import { createContext } from "react"; +import { CardData } from "./types/CardData"; import { Checkout } from "./types/Checkout"; export enum CheckoutStep { @@ -10,12 +11,6 @@ export enum CheckoutStep { Review, } -export interface CardData { - lastDigits: string; - ccType: string; - token: string; -} - export interface CheckoutContextInterface { syncWithCart?: boolean; syncUserCheckout?: boolean; @@ -24,6 +19,9 @@ export interface CheckoutContextInterface { checkout?: Checkout; loading?: boolean; shippingAsBilling?: boolean; + /* + * @deprecated Use useCheckoutStepState hook to determine step instead. + */ step?: CheckoutStep; update?(checkoutData: CheckoutContextInterface): void; clear?(): void; diff --git a/src/checkout/hooks/index.ts b/src/checkout/hooks/index.ts new file mode 100644 index 0000000000..8883869da7 --- /dev/null +++ b/src/checkout/hooks/index.ts @@ -0,0 +1,2 @@ +export * from "./useCheckoutStepState"; +export * from "./useCheckoutStepFromPath"; diff --git a/src/checkout/hooks/useCheckoutStepFromPath.ts b/src/checkout/hooks/useCheckoutStepFromPath.ts new file mode 100644 index 0000000000..d051f7a2dc --- /dev/null +++ b/src/checkout/hooks/useCheckoutStepFromPath.ts @@ -0,0 +1,55 @@ +import { useEffect, useState } from "react"; + +import { CheckoutStep } from "../context"; +import { + baseUrl, + billingBaseUrl, + paymentBaseUrl, + reviewBaseUrl, + shippingAddressBaseUrl, + shippingOptionsBaseUrl, +} from "../routes"; + +/** + * Gets checkout step based on the provided path. + */ +export const useCheckoutStepFromPath = ( + path: string, + token?: string +): CheckoutStep => { + const getStep = () => { + const pathList = [ + { + basePath: `${baseUrl}${shippingAddressBaseUrl}`, + step: CheckoutStep.ShippingAddress, + }, + { + basePath: `${baseUrl}${shippingOptionsBaseUrl}`, + step: CheckoutStep.ShippingOption, + }, + { + basePath: `${baseUrl}${billingBaseUrl}`, + step: CheckoutStep.BillingAddress, + }, + { basePath: `${baseUrl}${paymentBaseUrl}`, step: CheckoutStep.Payment }, + { basePath: `${baseUrl}${reviewBaseUrl}`, step: CheckoutStep.Review }, + ]; + + const pathItem = pathList.find(({ basePath }) => + path.replace(/\//g, "").includes(basePath.replace(/\//g, "")) + ); + + return pathItem ? pathItem.step : null; + }; + + const [step, setStep] = useState(getStep()); + + useEffect(() => { + const newStep = getStep(); + if (step !== newStep) { + setStep(newStep); + } + }, [path, token]); + + return step; +}; diff --git a/src/checkout/hooks/useCheckoutStepState.ts b/src/checkout/hooks/useCheckoutStepState.ts new file mode 100644 index 0000000000..2f84d257a7 --- /dev/null +++ b/src/checkout/hooks/useCheckoutStepState.ts @@ -0,0 +1,71 @@ +import { useEffect, useState } from "react"; + +import { VariantsProducts_productVariants } from "@sdk/queries/types/VariantsProducts"; + +import { CardData } from "../types/CardData"; +import { Checkout } from "../types/Checkout"; + +export enum CheckoutStep { + ShippingAddress = 1, + ShippingOption, + BillingAddress, + Payment, + Review, +} + +export const useCheckoutStepState = ( + checkout: Checkout, + variantsProducts: VariantsProducts_productVariants, + cardData: CardData, + dummyStatus: string +): CheckoutStep => { + const isShippingRequiredForProducts = () => { + return ( + variantsProducts.edges && + variantsProducts.edges.some( + ({ node }) => node.product.productType.isShippingRequired + ) + ); + }; + + const getStep = () => { + if (!checkout && variantsProducts && isShippingRequiredForProducts()) { + return CheckoutStep.ShippingAddress; + } else if (!checkout && variantsProducts) { + return CheckoutStep.BillingAddress; + } else if (!checkout) { + return null; + } + + const isShippingOptionStep = + checkout.availableShippingMethods.length && !!checkout.shippingAddress; + const isBillingStep = + (isShippingOptionStep && !!checkout.shippingMethod) || + !checkout.isShippingRequired; + const isPaymentStep = isBillingStep && !!checkout.billingAddress; + const isReviewStep = isPaymentStep && !!(cardData || dummyStatus); + + if (isReviewStep) { + return CheckoutStep.Review; + } else if (isPaymentStep) { + return CheckoutStep.Payment; + } else if (isBillingStep) { + return CheckoutStep.BillingAddress; + } else if (isShippingOptionStep) { + return CheckoutStep.ShippingOption; + } else { + return CheckoutStep.ShippingAddress; + } + }; + + const [step, setStep] = useState(getStep()); + + useEffect(() => { + const newStep = getStep(); + if (step !== newStep) { + setStep(newStep); + } + }, [checkout, variantsProducts, cardData, dummyStatus]); + + return step; +}; diff --git a/src/checkout/index.tsx b/src/checkout/index.tsx index 95b46beed7..b779c2f8fb 100644 --- a/src/checkout/index.tsx +++ b/src/checkout/index.tsx @@ -1,58 +1,95 @@ import "./scss/index.scss"; import * as React from "react"; -import { Redirect } from "react-router"; +import { Redirect, RouteComponentProps } from "react-router"; import { Link } from "react-router-dom"; import ReactSVG from "react-svg"; +import { useVariantsProducts } from "@sdk/react"; + import { Loader, Offline, OfflinePlaceholder, Online, - OverlayManager + OverlayManager, } from "../components"; import { CartContext } from "../components/CartProvider/context"; import { BASE_URL } from "../core/config"; +import logoImg from "../images/logo.svg"; import { CheckoutContext } from "./context"; -import { Routes } from "./routes"; +import { useCheckoutStepFromPath, useCheckoutStepState } from "./hooks"; +import { baseUrl, Routes } from "./routes"; -import logoImg from "../images/logo.svg"; +const CheckoutApp: React.FC = ({ + history: { + location: { pathname }, + }, +}) => { + const { + loading: checkoutLoading, + checkout, + cardData, + dummyStatus, + } = React.useContext(CheckoutContext); + const { lines: cartLines, loading: cartLoading } = React.useContext( + CartContext + ); + + const { + data: variantsProducts, + loading: variantsProductsLoading, + } = useVariantsProducts({ + ids: cartLines ? cartLines.map(line => line.variantId) : [], + }); + + const step = useCheckoutStepState( + checkout, + variantsProducts, + cardData, + dummyStatus + ); + const stepFromPath = useCheckoutStepFromPath(pathname); -const CheckoutApp: React.FC = () => ( -
-
-
- + return ( +
+
+
+ +
+ Return to shopping
- Return to shopping -
-
- - - {cart => ( - - {({ loading }) => { - if (!cart.lines.length) { - return ; - } - - if (loading) { - return ; - } - - return ; - }} - - )} - - - - - +
+ + {(() => { + if ( + cartLoading || + checkoutLoading || + variantsProductsLoading || + !step || + (!stepFromPath && baseUrl !== pathname) + ) { + return ; + } + + if (!cartLines.length) { + return ; + } + + if ((!checkout && !variantsProducts) || step < stepFromPath) { + return ; + } + + return ; + })()} + + + + +
+
- -
-); + ); +}; export default CheckoutApp; diff --git a/src/checkout/queries.ts b/src/checkout/queries.ts index ffefbf3e82..1419f53232 100644 --- a/src/checkout/queries.ts +++ b/src/checkout/queries.ts @@ -4,10 +4,14 @@ import { TypedMutation } from "../core/mutations"; import { TypedQuery } from "../core/queries"; import { createCheckout, - createCheckoutVariables + createCheckoutVariables, } from "./types/createCheckout"; import { getCheckout, getCheckoutVariables } from "./types/getCheckout"; import { getUserCheckout } from "./types/getUserCheckout"; +import { + getVariantsProducts, + getVariantsProductsVariables, +} from "./types/getVariantsProducts"; export const checkoutAddressFragment = gql` fragment Address on Address { @@ -114,9 +118,6 @@ export const checkoutFragment = gql` } token id - user { - email - } totalPrice { ...Price } @@ -142,6 +143,7 @@ export const checkoutFragment = gql` lines { ...CheckoutLine } + isShippingRequired } `; @@ -172,6 +174,7 @@ export const updateCheckoutLineQuery = gql` subtotalPrice { ...Price } + isShippingRequired } errors { field @@ -215,3 +218,26 @@ const getUserCheckoutQuery = gql` export const TypedGetUserCheckoutQuery = TypedQuery( getUserCheckoutQuery ); + +export const getVariantsProductsQuery = gql` + query getVariantsProducts($ids: [ID]) { + productVariants(ids: $ids, first: 100) { + edges { + node { + id + product { + id + productType { + isShippingRequired + } + } + } + } + } + } +`; + +export const TypedGetVariantsProductsQuery = TypedQuery< + getVariantsProducts, + getVariantsProductsVariables +>(getUserCheckoutQuery); diff --git a/src/checkout/routes.tsx b/src/checkout/routes.tsx deleted file mode 100644 index e97f2a02f4..0000000000 --- a/src/checkout/routes.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import * as React from "react"; -import { Route, Switch } from "react-router-dom"; - -import { NotFound } from "../components"; -import { - Billing, - CheckoutDispatcher, - Payment, - Review, - Shipping, - ShippingOptions -} from "./views"; - -export const baseUrl = "/checkout/"; -export const shippingAddressUrl = `${baseUrl}shipping-address/:token?/`; -export const shippingOptionsUrl = `${baseUrl}shipping-options/:token?/`; -export const billingUrl = `${baseUrl}billing-address/:token?/`; -export const paymentUrl = `${baseUrl}payment/:token?/`; -export const reviewUrl = `${baseUrl}review/:token?/`; - -export const Routes: React.FC = () => ( - - - - - - - - - -); diff --git a/src/checkout/routes/CheckoutRouteDispatcher.tsx b/src/checkout/routes/CheckoutRouteDispatcher.tsx new file mode 100644 index 0000000000..c392d26016 --- /dev/null +++ b/src/checkout/routes/CheckoutRouteDispatcher.tsx @@ -0,0 +1,63 @@ +import * as React from "react"; +import { generatePath, Redirect, RouteComponentProps } from "react-router"; + +import { useVariantsProducts } from "@sdk/react"; + +import { + billingUrl, + paymentUrl, + reviewUrl, + shippingAddressUrl, + shippingOptionsUrl, +} from "."; +import { Loader } from "../../components"; +import { CartContext } from "../../components/CartProvider/context"; +import { CheckoutContext } from "../context"; +import { CheckoutStep, useCheckoutStepState } from "../hooks"; + +export const CheckoutRouteDispatcher: React.FC> = ({ + match: { + params: { token }, + }, +}) => { + const { + loading: checkoutLoading, + checkout, + cardData, + dummyStatus, + } = React.useContext(CheckoutContext); + const { lines: cartLines } = React.useContext(CartContext); + + const { + data: variantsProducts, + loading: variantsProductsLoading, + } = useVariantsProducts({ + ids: cartLines ? cartLines.map(line => line.variantId) : [], + }); + + const step = useCheckoutStepState( + checkout, + variantsProducts, + cardData, + dummyStatus + ); + + if (checkoutLoading || variantsProductsLoading || !step) { + return ; + } + + switch (step) { + case CheckoutStep.BillingAddress: + return ; + case CheckoutStep.ShippingAddress: + return ; + case CheckoutStep.Review: + return ; + case CheckoutStep.Payment: + return ; + case CheckoutStep.ShippingOption: + return ; + } +}; diff --git a/src/checkout/routes/index.tsx b/src/checkout/routes/index.tsx new file mode 100644 index 0000000000..034e4d5280 --- /dev/null +++ b/src/checkout/routes/index.tsx @@ -0,0 +1,30 @@ +import * as React from "react"; +import { Route, Switch } from "react-router-dom"; + +import { NotFound } from "../../components"; +import { Billing, Payment, Review, Shipping, ShippingOptions } from "../views"; +import { CheckoutRouteDispatcher } from "./CheckoutRouteDispatcher"; + +export const baseUrl = "/checkout/"; +export const shippingAddressBaseUrl = `shipping-address/`; +export const shippingOptionsBaseUrl = `shipping-options/`; +export const billingBaseUrl = `billing-address/`; +export const paymentBaseUrl = `payment/`; +export const reviewBaseUrl = `review/`; +export const shippingAddressUrl = `${baseUrl}${shippingAddressBaseUrl}:token?/`; +export const shippingOptionsUrl = `${baseUrl}${shippingOptionsBaseUrl}:token?/`; +export const billingUrl = `${baseUrl}${billingBaseUrl}:token?/`; +export const paymentUrl = `${baseUrl}${paymentBaseUrl}:token?/`; +export const reviewUrl = `${baseUrl}${reviewBaseUrl}:token?/`; + +export const Routes: React.FC = () => ( + + + + + + + + + +); diff --git a/src/checkout/types.ts b/src/checkout/types.ts index 0d22c9a0ef..ec438269a4 100644 --- a/src/checkout/types.ts +++ b/src/checkout/types.ts @@ -36,6 +36,7 @@ export interface IGuestAddressProps { proceedToNextStep: (formData: FormAddressType) => void; shippingAsBilling?: boolean; type?: CheckoutFormType; + noShipping?: boolean; } export interface UserAddressSelectorProps { diff --git a/src/checkout/types/CardData.ts b/src/checkout/types/CardData.ts new file mode 100644 index 0000000000..9726c1cd06 --- /dev/null +++ b/src/checkout/types/CardData.ts @@ -0,0 +1,5 @@ +export interface CardData { + lastDigits: string; + ccType: string; + token: string; +} diff --git a/src/checkout/types/Checkout.ts b/src/checkout/types/Checkout.ts index 6ea1180f15..33e7ccb3da 100644 --- a/src/checkout/types/Checkout.ts +++ b/src/checkout/types/Checkout.ts @@ -30,11 +30,6 @@ export interface Checkout_availablePaymentGateways { config: Checkout_availablePaymentGateways_config[]; } -export interface Checkout_user { - __typename: "User"; - email: string; -} - export interface Checkout_totalPrice_gross { __typename: "Money"; /** @@ -513,7 +508,6 @@ export interface Checkout { * The ID of the object. */ id: string; - user: Checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -541,4 +535,8 @@ export interface Checkout { * A list of checkout lines, each containing information about an item in the checkout. */ lines: (Checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } diff --git a/src/checkout/types/createCheckout.ts b/src/checkout/types/createCheckout.ts index 8237183515..959e250324 100644 --- a/src/checkout/types/createCheckout.ts +++ b/src/checkout/types/createCheckout.ts @@ -45,11 +45,6 @@ export interface createCheckout_checkoutCreate_checkout_availablePaymentGateways config: createCheckout_checkoutCreate_checkout_availablePaymentGateways_config[]; } -export interface createCheckout_checkoutCreate_checkout_user { - __typename: "User"; - email: string; -} - export interface createCheckout_checkoutCreate_checkout_totalPrice_gross { __typename: "Money"; /** @@ -528,7 +523,6 @@ export interface createCheckout_checkoutCreate_checkout { * The ID of the object. */ id: string; - user: createCheckout_checkoutCreate_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -556,6 +550,10 @@ export interface createCheckout_checkoutCreate_checkout { * A list of checkout lines, each containing information about an item in the checkout. */ lines: (createCheckout_checkoutCreate_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface createCheckout_checkoutCreate { diff --git a/src/checkout/types/getCheckout.ts b/src/checkout/types/getCheckout.ts index e787ce18c3..3798d87b2d 100644 --- a/src/checkout/types/getCheckout.ts +++ b/src/checkout/types/getCheckout.ts @@ -30,11 +30,6 @@ export interface getCheckout_checkout_availablePaymentGateways { config: getCheckout_checkout_availablePaymentGateways_config[]; } -export interface getCheckout_checkout_user { - __typename: "User"; - email: string; -} - export interface getCheckout_checkout_totalPrice_gross { __typename: "Money"; /** @@ -513,7 +508,6 @@ export interface getCheckout_checkout { * The ID of the object. */ id: string; - user: getCheckout_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -541,6 +535,10 @@ export interface getCheckout_checkout { * A list of checkout lines, each containing information about an item in the checkout. */ lines: (getCheckout_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface getCheckout { diff --git a/src/checkout/types/getUserCheckout.ts b/src/checkout/types/getUserCheckout.ts index a6bc9bb545..b0670e35db 100644 --- a/src/checkout/types/getUserCheckout.ts +++ b/src/checkout/types/getUserCheckout.ts @@ -30,11 +30,6 @@ export interface getUserCheckout_me_checkout_availablePaymentGateways { config: getUserCheckout_me_checkout_availablePaymentGateways_config[]; } -export interface getUserCheckout_me_checkout_user { - __typename: "User"; - email: string; -} - export interface getUserCheckout_me_checkout_totalPrice_gross { __typename: "Money"; /** @@ -513,7 +508,6 @@ export interface getUserCheckout_me_checkout { * The ID of the object. */ id: string; - user: getUserCheckout_me_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -541,6 +535,10 @@ export interface getUserCheckout_me_checkout { * A list of checkout lines, each containing information about an item in the checkout. */ lines: (getUserCheckout_me_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface getUserCheckout_me { diff --git a/src/checkout/types/getVariantsProducts.ts b/src/checkout/types/getVariantsProducts.ts new file mode 100644 index 0000000000..360814016e --- /dev/null +++ b/src/checkout/types/getVariantsProducts.ts @@ -0,0 +1,54 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +// ==================================================== +// GraphQL query operation: getVariantsProducts +// ==================================================== + +export interface getVariantsProducts_productVariants_edges_node_product_productType { + __typename: "ProductType"; + isShippingRequired: boolean; +} + +export interface getVariantsProducts_productVariants_edges_node_product { + __typename: "Product"; + /** + * The ID of the object. + */ + id: string; + productType: getVariantsProducts_productVariants_edges_node_product_productType; +} + +export interface getVariantsProducts_productVariants_edges_node { + __typename: "ProductVariant"; + /** + * The ID of the object. + */ + id: string; + product: getVariantsProducts_productVariants_edges_node_product; +} + +export interface getVariantsProducts_productVariants_edges { + __typename: "ProductVariantCountableEdge"; + /** + * The item at the end of the edge. + */ + node: getVariantsProducts_productVariants_edges_node; +} + +export interface getVariantsProducts_productVariants { + __typename: "ProductVariantCountableConnection"; + edges: getVariantsProducts_productVariants_edges[]; +} + +export interface getVariantsProducts { + /** + * List of product variants. + */ + productVariants: getVariantsProducts_productVariants | null; +} + +export interface getVariantsProductsVariables { + ids?: (string | null)[] | null; +} diff --git a/src/checkout/types/updateCheckoutLine.ts b/src/checkout/types/updateCheckoutLine.ts index 9c0e6a3752..49737d93af 100644 --- a/src/checkout/types/updateCheckoutLine.ts +++ b/src/checkout/types/updateCheckoutLine.ts @@ -283,6 +283,10 @@ export interface updateCheckoutLine_checkoutLinesUpdate_checkout { * The price of the checkout before shipping, with taxes included. */ subtotalPrice: updateCheckoutLine_checkoutLinesUpdate_checkout_subtotalPrice | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface updateCheckoutLine_checkoutLinesUpdate_errors { diff --git a/src/checkout/views/Billing/Page.tsx b/src/checkout/views/Billing/Page.tsx index b6248553b3..c32ca88f77 100644 --- a/src/checkout/views/Billing/Page.tsx +++ b/src/checkout/views/Billing/Page.tsx @@ -8,9 +8,8 @@ import { maybe } from "../../../core/utils"; import { CartSummary, GuestAddressForm, - StepCheck, Steps, - UserAddressSelector + UserAddressSelector, } from "../../components"; import { CheckoutStep } from "../../context"; import { paymentUrl } from "../../routes"; @@ -19,13 +18,14 @@ import { Checkout } from "../../types/Checkout"; import { IBillingPageProps } from "./types"; import { CountryCode } from "types/globalTypes"; +import { CartLineInterface } from "../../../components/CartProvider/context"; const computeMutationVariables = ( formData: FormAddressType, checkout: Checkout, shippingAsBilling: boolean ) => { - const { shippingAddress } = checkout; + const shippingAddress = checkout ? checkout.shippingAddress : {}; const data = shippingAsBilling ? (shippingAddress as FormAddressType) : formData; @@ -33,7 +33,10 @@ const computeMutationVariables = ( return { billingAddress: { city: data.city, - country: maybe(() => data.country.value, data.country.code) as CountryCode, + country: maybe( + () => data.country.value, + data.country.code + ) as CountryCode, countryArea: data.countryArea, firstName: data.firstName, lastName: data.lastName, @@ -41,28 +44,67 @@ const computeMutationVariables = ( streetAddress1: data.streetAddress1, streetAddress2: data.streetAddress2, }, - checkoutId: checkout.id, + checkoutId: checkout ? checkout.id : null, + email: data.email, }; }; +const computeCheckoutData = ( + data: FormAddressType, + lines: CartLineInterface[], + email?: string +) => ({ + billingAddress: { + city: data.city, + country: maybe(() => data.country.value, data.country.code) as CountryCode, + countryArea: data.countryArea, + firstName: data.firstName, + lastName: data.lastName, + postalCode: data.postalCode, + streetAddress1: data.streetAddress1, + streetAddress2: data.streetAddress2, + }, + email: data.email || email, + ...(lines && { + lines: lines.map(({ quantity, variantId }) => ({ + quantity, + variantId, + })), + }), +}); + const View: React.FC = ({ + checkoutId, checkout, - validateStep, + createCheckout: [ + create, + { loading: createCheckoutLoading, error: createCheckoutError }, + ], proceedToNextStepData, - path, shippingAsBilling, shop, - step, update, + lines, updateCheckoutBillingAddress, + isShippingRequired, }) => { const [saveBillingAddress, { loading, error }] = updateCheckoutBillingAddress; const errors = maybe(() => error.extraInfo.userInputErrors, []); const onSaveBillingAddressHandler = (formData: FormAddressType) => { - return saveBillingAddress( - computeMutationVariables(formData, checkout, shippingAsBilling) - ); + if (checkoutId) { + return saveBillingAddress( + computeMutationVariables(formData, checkout, shippingAsBilling) + ); + } + const data = computeCheckoutData(formData, lines); + return create({ + checkoutInput: { + billingAddress: data.billingAddress, + email: data.email, + lines: data.lines, + }, + }); }; const onSubmitHandler = (formData: FormAddressType) => { @@ -98,14 +140,7 @@ const View: React.FC = ({ const { data: user } = useUserDetails(); - return validateStep ? ( - - ) : ( + return ( = ({ checkout={checkout} > <> -
- -
+ {isShippingRequired && ( +
+ +
+ )} {user ? ( = ({ )} diff --git a/src/checkout/views/Billing/View.tsx b/src/checkout/views/Billing/View.tsx index 777b375cda..df39fdeeab 100644 --- a/src/checkout/views/Billing/View.tsx +++ b/src/checkout/views/Billing/View.tsx @@ -1,8 +1,14 @@ import * as React from "react"; import { RouteComponentProps } from "react-router"; -import { useUpdateCheckoutBillingAddress, useUserDetails } from "@sdk/react"; +import { + useCreateCheckout, + useUpdateCheckoutBillingAddress, + useUserDetails, + useVariantsProducts, +} from "@sdk/react"; +import { CartContext } from "../../../components/CartProvider/context"; import { ShopContext } from "../../../components/ShopProvider/context"; import { maybe } from "../../../core/utils"; import { CheckoutContext } from "../../context"; @@ -11,45 +17,63 @@ import Page from "./Page"; const View: React.FC> = ({ history, match: { - path, params: { token }, }, }) => { - const [validateStep, setValidateStep] = React.useState(true); const updateCheckoutBillingAddress = useUpdateCheckoutBillingAddress(); - React.useEffect(() => { - setValidateStep(false); - }, []); - const { data: user } = useUserDetails(); + const { update, checkout, shippingAsBilling } = React.useContext( + CheckoutContext + ); + const { lines: cardLines } = React.useContext(CartContext); + const { data: variantsProducts } = useVariantsProducts({ + ids: cardLines ? cardLines.map(line => line.variantId) : [], + }); + const isShippingRequired = () => { + if (checkout && checkout.isShippingRequired) { + return true; + } else if (checkout) { + return false; + } else if (variantsProducts) { + const isShippingRequired = + variantsProducts.edges && + variantsProducts.edges.some( + ({ node }) => node.product.productType.isShippingRequired + ); + if (isShippingRequired) { + return true; + } + return false; + } + return false; + }; + + const createCheckout = useCreateCheckout(); + return ( - - {({ update, checkout, shippingAsBilling, step }) => ( - - {shop => ( - checkout.id, null)} - checkout={checkout} - shop={shop} - path={path} - update={update} - step={step} - user={user} - updateCheckoutBillingAddress={updateCheckoutBillingAddress} - proceedToNextStepData={{ - history, - token, - update, - }} - validateStep={validateStep} - /> - )} - + + {shop => ( + checkout.id, null)} + checkout={checkout} + shop={shop} + createCheckout={createCheckout} + update={update} + user={user} + updateCheckoutBillingAddress={updateCheckoutBillingAddress} + proceedToNextStepData={{ + history, + token, + update, + }} + lines={cardLines} + /> )} - + ); }; diff --git a/src/checkout/views/Billing/types.ts b/src/checkout/views/Billing/types.ts index d657f1e724..d557a14466 100644 --- a/src/checkout/views/Billing/types.ts +++ b/src/checkout/views/Billing/types.ts @@ -2,20 +2,36 @@ import { History } from "history"; import { MutationFn, MutationResult } from "@sdk/react/useMutation"; +import { + CreateCheckout_checkoutCreate, + CreateCheckoutVariables, +} from "@sdk/mutations/types/CreateCheckout"; +import { CartLineInterface } from "../../../components/CartProvider/context"; import { getShop_shop } from "../../../components/ShopProvider/types/getShop"; import { User } from "../../../components/User/types/User"; import { FormError } from "../../../core/types"; -import { CheckoutContextInterface, CheckoutStep } from "../../context"; +import { CheckoutContextInterface } from "../../context"; import { Checkout } from "../../types/Checkout"; import { updateCheckoutBillingAddress_checkoutBillingAddressUpdate, - updateCheckoutBillingAddressVariables + updateCheckoutBillingAddressVariables, } from "./types/updateCheckoutBillingAddress"; export interface IBillingPageProps { checkoutId?: string; checkout?: Checkout; update: (checkoutData: CheckoutContextInterface) => void; + createCheckout: [ + MutationFn< + { + data: CreateCheckout_checkoutCreate; + }, + CreateCheckoutVariables + >, + MutationResult<{ + data: CreateCheckout_checkoutCreate; + }> + ]; updateCheckoutBillingAddress: [ MutationFn< { @@ -27,17 +43,16 @@ export interface IBillingPageProps { data: updateCheckoutBillingAddress_checkoutBillingAddressUpdate; }> ]; + lines?: CartLineInterface[]; shippingAsBilling: boolean; user: User; - path: string; shop: getShop_shop; - step: CheckoutStep; proceedToNextStepData: { update: (checkoutData: CheckoutContextInterface) => void; history: History; token?: string; }; - validateStep: boolean; + isShippingRequired: boolean; } export interface IBillingPageState { diff --git a/src/checkout/views/Billing/types/updateCheckoutBillingAddress.ts b/src/checkout/views/Billing/types/updateCheckoutBillingAddress.ts index d1dc5a05f7..2cdb105455 100644 --- a/src/checkout/views/Billing/types/updateCheckoutBillingAddress.ts +++ b/src/checkout/views/Billing/types/updateCheckoutBillingAddress.ts @@ -45,11 +45,6 @@ export interface updateCheckoutBillingAddress_checkoutBillingAddressUpdate_check config: updateCheckoutBillingAddress_checkoutBillingAddressUpdate_checkout_availablePaymentGateways_config[]; } -export interface updateCheckoutBillingAddress_checkoutBillingAddressUpdate_checkout_user { - __typename: "User"; - email: string; -} - export interface updateCheckoutBillingAddress_checkoutBillingAddressUpdate_checkout_totalPrice_gross { __typename: "Money"; /** @@ -528,7 +523,6 @@ export interface updateCheckoutBillingAddress_checkoutBillingAddressUpdate_check * The ID of the object. */ id: string; - user: updateCheckoutBillingAddress_checkoutBillingAddressUpdate_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -556,6 +550,10 @@ export interface updateCheckoutBillingAddress_checkoutBillingAddressUpdate_check * A list of checkout lines, each containing information about an item in the checkout. */ lines: (updateCheckoutBillingAddress_checkoutBillingAddressUpdate_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface updateCheckoutBillingAddress_checkoutBillingAddressUpdate { diff --git a/src/checkout/views/CheckoutDispatcher.tsx b/src/checkout/views/CheckoutDispatcher.tsx deleted file mode 100644 index d054ade11c..0000000000 --- a/src/checkout/views/CheckoutDispatcher.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import * as React from "react"; -import { generatePath, Redirect, RouteComponentProps } from "react-router"; - -import { BASE_URL } from "../../core/config"; -import { CheckoutContext, CheckoutStep } from "../context"; -import { - billingUrl, - paymentUrl, - reviewUrl, - shippingAddressUrl, - shippingOptionsUrl -} from "../routes"; - -const getRedirectUrl = (token: string, step: CheckoutStep): string => { - const generatedPath = (path: string) => generatePath(path, { token }); - - switch (step) { - case CheckoutStep.ShippingAddress: - return generatedPath(shippingAddressUrl); - - case CheckoutStep.ShippingOption: - return generatedPath(shippingOptionsUrl); - - case CheckoutStep.BillingAddress: - return generatedPath(billingUrl); - - case CheckoutStep.Payment: - return generatedPath(paymentUrl); - - case CheckoutStep.Review: - return generatedPath(reviewUrl); - - default: - return BASE_URL; - } -}; - -const CheckoutDispatcher: React.FC> = ({ - match: { - params: { token }, - }, -}) => ( - - {({ step }) => } - -); - -export default CheckoutDispatcher; diff --git a/src/checkout/views/Payment/View.tsx b/src/checkout/views/Payment/View.tsx index 532c1665af..b6516b38b9 100644 --- a/src/checkout/views/Payment/View.tsx +++ b/src/checkout/views/Payment/View.tsx @@ -7,11 +7,11 @@ import { generatePath, RouteComponentProps } from "react-router"; import { Checkout_availablePaymentGateways_config } from "../../../checkout/types/Checkout"; import { Button } from "../../../components"; import { PROVIDERS } from "../../../core/config"; -import { CartSummary, Option, StepCheck, Steps } from "../../components"; +import { CartSummary, Option, Steps } from "../../components"; import { CheckoutContext, CheckoutContextInterface, - CheckoutStep + CheckoutStep, } from "../../context"; import { reviewUrl } from "../../routes"; import CreditCard from "./Gateways/Braintree/CreditCard"; @@ -102,119 +102,106 @@ class View extends React.Component< render() { const { params: { token }, - path, } = this.props.match; const { selectedGeteway, loading: stateLoding } = this.state; return ( - {checkout => - this.state.validateStep ? ( - - ) : ( - -
- ( + +
+ + - - {( + {(createPaymentMethod, { loading: paymentCreateLoading }) => { + const { availablePaymentGateways } = checkout.checkout; + const processPayment = this.processPayment( createPaymentMethod, - { loading: paymentCreateLoading } - ) => { - const { availablePaymentGateways } = checkout.checkout; - const processPayment = this.processPayment( - createPaymentMethod, - checkout - ); - const loading = stateLoding || paymentCreateLoading; - const optionProps = providerName => ({ - key: providerName, - onSelect: () => - this.setState({ selectedGeteway: providerName }), - selected: selectedGeteway === providerName, - value: providerName, - }); - const providerProps = { - checkout, - formRef: this.formRef, - loading, - processPayment, - setLoadingState: this.setLoadingState, - }; - - return ( -
- {availablePaymentGateways.map(provider => { - const providerName = provider.name; - const paymentGatewayProps = { - ...providerProps, - paymentGatewayConfig: provider.config, - }; - switch (providerName) { - case PROVIDERS.BRAINTREE: - return ( - - ); - - case PROVIDERS.DUMMY: - return ( - - ); - - case PROVIDERS.STRIPE: - return ( - - ); - } - })} - -
- -
+ checkout + ); + const loading = stateLoding || paymentCreateLoading; + const optionProps = providerName => ({ + key: providerName, + onSelect: () => + this.setState({ selectedGeteway: providerName }), + selected: selectedGeteway === providerName, + value: providerName, + }); + const providerProps = { + checkout, + formRef: this.formRef, + loading, + processPayment, + setLoadingState: this.setLoadingState, + }; + + return ( +
+ {availablePaymentGateways.map(provider => { + const providerName = provider.name; + const paymentGatewayProps = { + ...providerProps, + paymentGatewayConfig: provider.config, + }; + switch (providerName) { + case PROVIDERS.BRAINTREE: + return ( + + ); + + case PROVIDERS.DUMMY: + return ( + + ); + + case PROVIDERS.STRIPE: + return ( + + ); + } + })} + +
+
- ); - }} - - -
- - ) - } +
+ ); + }} +
+
+
+
+ )} ); } diff --git a/src/checkout/views/Review/Summary.tsx b/src/checkout/views/Review/Summary.tsx index 19cdbdac1a..a75f11191f 100644 --- a/src/checkout/views/Review/Summary.tsx +++ b/src/checkout/views/Review/Summary.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import ReactSVG from "react-svg"; import { AddressSummary } from "../../../components"; -import { CardData } from "../../context"; +import { CardData } from "../../types/CardData"; import { Checkout } from "../../types/Checkout"; import copyImg from "../../../images/copy.svg"; @@ -43,7 +43,7 @@ class Summary extends React.PureComponent<{ /> @@ -62,17 +62,19 @@ class Summary extends React.PureComponent<{ paragraphRef={this.billingAddressRef} />
-
-

- Shipping method - -

-

{checkout.shippingMethod.name}

-
+ {checkout.isShippingRequired && ( +
+

+ Shipping method + +

+

{checkout.shippingMethod.name}

+
+ )}

Payment method diff --git a/src/checkout/views/Review/View.tsx b/src/checkout/views/Review/View.tsx index 60e188ecea..0a84ab1bcd 100644 --- a/src/checkout/views/Review/View.tsx +++ b/src/checkout/views/Review/View.tsx @@ -11,7 +11,6 @@ import { Button, CartTable } from "../../../components"; import { CartContext } from "../../../components/CartProvider/context"; import { extractCheckoutLines } from "../../../components/CartProvider/utils"; import { orderConfirmationUrl } from "../../../routes"; -import { StepCheck } from "../../components"; import { CheckoutContext } from "../../context"; import { paymentUrl } from "../../routes"; import { TypedCompleteCheckoutMutation } from "./queries"; @@ -50,7 +49,6 @@ const completeCheckout = ( const View: React.FC> = ({ history, match: { - path, params: { token }, }, }) => { @@ -60,21 +58,11 @@ const View: React.FC> = ({ dummyStatus, checkout, clear: clearCheckout, - step, } = React.useContext(CheckoutContext); const { clear: clearCart } = React.useContext(CartContext); - const stepCheck = ( - - ); - - if (!checkout) { - return stepCheck; - } - return ( <> - {stepCheck}
> = ({
- 5 + {checkout.isShippingRequired ? "5" : "3"}

Review your order

@@ -92,7 +80,9 @@ const View: React.FC> = ({
diff --git a/src/checkout/views/Shipping/Page.tsx b/src/checkout/views/Shipping/Page.tsx index 66cc8d49ee..f19d734045 100644 --- a/src/checkout/views/Shipping/Page.tsx +++ b/src/checkout/views/Shipping/Page.tsx @@ -8,7 +8,7 @@ import { CartSummary, GuestAddressForm, Steps, - UserAddressSelector + UserAddressSelector, } from "../../components"; import { CheckoutStep } from "../../context"; import { shippingOptionsUrl } from "../../routes"; diff --git a/src/checkout/views/Shipping/View.tsx b/src/checkout/views/Shipping/View.tsx index a43321f9a4..fa36f46adc 100644 --- a/src/checkout/views/Shipping/View.tsx +++ b/src/checkout/views/Shipping/View.tsx @@ -4,7 +4,7 @@ import { RouteComponentProps } from "react-router"; import { useCreateCheckout, useUpdateCheckoutShippingAddress, - useUserDetails + useUserDetails, } from "@sdk/react"; import { CartContext } from "../../../components/CartProvider/context"; diff --git a/src/checkout/views/Shipping/types.ts b/src/checkout/views/Shipping/types.ts index 35dbc1ce40..1107c9dcfb 100644 --- a/src/checkout/views/Shipping/types.ts +++ b/src/checkout/views/Shipping/types.ts @@ -2,11 +2,11 @@ import { History } from "history"; import { CreateCheckout_checkoutCreate, - CreateCheckoutVariables + CreateCheckoutVariables, } from "@sdk/mutations/types/CreateCheckout"; import { UpdateCheckoutShippingAddress_checkoutShippingAddressUpdate, - UpdateCheckoutShippingAddressVariables + UpdateCheckoutShippingAddressVariables, } from "@sdk/mutations/types/UpdateCheckoutShippingAddress"; import { MutationFn, MutationResult } from "@sdk/react/useMutation"; diff --git a/src/checkout/views/Shipping/types/updateCheckoutShippingAddress.ts b/src/checkout/views/Shipping/types/updateCheckoutShippingAddress.ts index 41ec2621d2..8864661171 100644 --- a/src/checkout/views/Shipping/types/updateCheckoutShippingAddress.ts +++ b/src/checkout/views/Shipping/types/updateCheckoutShippingAddress.ts @@ -45,11 +45,6 @@ export interface updateCheckoutShippingAddress_checkoutShippingAddressUpdate_che config: updateCheckoutShippingAddress_checkoutShippingAddressUpdate_checkout_availablePaymentGateways_config[]; } -export interface updateCheckoutShippingAddress_checkoutShippingAddressUpdate_checkout_user { - __typename: "User"; - email: string; -} - export interface updateCheckoutShippingAddress_checkoutShippingAddressUpdate_checkout_totalPrice_gross { __typename: "Money"; /** @@ -528,7 +523,6 @@ export interface updateCheckoutShippingAddress_checkoutShippingAddressUpdate_che * The ID of the object. */ id: string; - user: updateCheckoutShippingAddress_checkoutShippingAddressUpdate_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -556,6 +550,10 @@ export interface updateCheckoutShippingAddress_checkoutShippingAddressUpdate_che * A list of checkout lines, each containing information about an item in the checkout. */ lines: (updateCheckoutShippingAddress_checkoutShippingAddressUpdate_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface updateCheckoutShippingAddress_checkoutShippingAddressUpdate { @@ -594,11 +592,6 @@ export interface updateCheckoutShippingAddress_checkoutEmailUpdate_checkout_avai config: updateCheckoutShippingAddress_checkoutEmailUpdate_checkout_availablePaymentGateways_config[]; } -export interface updateCheckoutShippingAddress_checkoutEmailUpdate_checkout_user { - __typename: "User"; - email: string; -} - export interface updateCheckoutShippingAddress_checkoutEmailUpdate_checkout_totalPrice_gross { __typename: "Money"; /** @@ -1077,7 +1070,6 @@ export interface updateCheckoutShippingAddress_checkoutEmailUpdate_checkout { * The ID of the object. */ id: string; - user: updateCheckoutShippingAddress_checkoutEmailUpdate_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -1105,6 +1097,10 @@ export interface updateCheckoutShippingAddress_checkoutEmailUpdate_checkout { * A list of checkout lines, each containing information about an item in the checkout. */ lines: (updateCheckoutShippingAddress_checkoutEmailUpdate_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface updateCheckoutShippingAddress_checkoutEmailUpdate_errors { diff --git a/src/checkout/views/ShippingOptions/View.tsx b/src/checkout/views/ShippingOptions/View.tsx index 7f6ce383e7..9eb237b352 100644 --- a/src/checkout/views/ShippingOptions/View.tsx +++ b/src/checkout/views/ShippingOptions/View.tsx @@ -4,11 +4,11 @@ import * as React from "react"; import { generatePath, RouteComponentProps } from "react-router"; import { Button } from "../../../components"; -import { CartSummary, Option, StepCheck, Steps } from "../../components"; +import { CartSummary, Option, Steps } from "../../components"; import { CheckoutContext, CheckoutContextInterface, - CheckoutStep + CheckoutStep, } from "../../context"; import { billingUrl } from "../../routes"; import { TypedUpdateCheckoutShippingOptionsMutation } from "./queries"; @@ -41,76 +41,66 @@ class View extends React.Component< const { selectedShipping } = this.state; const { params: { token }, - path, } = this.props.match; return ( {({ checkout, update, step }) => (
- - - + + + this.proceedToBilling(data, update, token) + } > - - this.proceedToBilling(data, update, token) - } - > - {(updateCheckoutShippingOptions, { loading }) => { - const shippingMethods = - checkout.availableShippingMethods || []; - return ( - <> -
- {shippingMethods.map(method => ( -
- - - ); - }} -
-
-
-
+ {(updateCheckoutShippingOptions, { loading }) => { + const shippingMethods = + checkout.availableShippingMethods || []; + return ( + <> +
+ {shippingMethods.map(method => ( +
+ + + ); + }} + + +
)}
diff --git a/src/checkout/views/ShippingOptions/types/updateCheckoutShippingOptions.ts b/src/checkout/views/ShippingOptions/types/updateCheckoutShippingOptions.ts index a837b20c7d..23cbc26291 100644 --- a/src/checkout/views/ShippingOptions/types/updateCheckoutShippingOptions.ts +++ b/src/checkout/views/ShippingOptions/types/updateCheckoutShippingOptions.ts @@ -43,11 +43,6 @@ export interface updateCheckoutShippingOptions_checkoutShippingMethodUpdate_chec config: updateCheckoutShippingOptions_checkoutShippingMethodUpdate_checkout_availablePaymentGateways_config[]; } -export interface updateCheckoutShippingOptions_checkoutShippingMethodUpdate_checkout_user { - __typename: "User"; - email: string; -} - export interface updateCheckoutShippingOptions_checkoutShippingMethodUpdate_checkout_totalPrice_gross { __typename: "Money"; /** @@ -526,7 +521,6 @@ export interface updateCheckoutShippingOptions_checkoutShippingMethodUpdate_chec * The ID of the object. */ id: string; - user: updateCheckoutShippingOptions_checkoutShippingMethodUpdate_checkout_user | null; /** * The sum of the the checkout line prices, with all the taxes,shipping costs, and discounts included. */ @@ -554,6 +548,10 @@ export interface updateCheckoutShippingOptions_checkoutShippingMethodUpdate_chec * A list of checkout lines, each containing information about an item in the checkout. */ lines: (updateCheckoutShippingOptions_checkoutShippingMethodUpdate_checkout_lines | null)[] | null; + /** + * Returns True, if checkout requires shipping. + */ + isShippingRequired: boolean; } export interface updateCheckoutShippingOptions_checkoutShippingMethodUpdate { diff --git a/src/checkout/views/index.ts b/src/checkout/views/index.ts index c8aac1bbbe..69a6d49770 100644 --- a/src/checkout/views/index.ts +++ b/src/checkout/views/index.ts @@ -3,5 +3,4 @@ export { default as Payment } from "./Payment/View"; export { default as Review } from "./Review/View"; export { default as Shipping } from "./Shipping/View"; export { default as ShippingOptions } from "./ShippingOptions/View"; -export { default as CheckoutDispatcher } from "./CheckoutDispatcher"; export { default as OrderConfirmation } from "./OrderConfirmation/View"; diff --git a/src/components/AddressSummary/index.tsx b/src/components/AddressSummary/index.tsx index e17f368aee..11238fbeed 100644 --- a/src/components/AddressSummary/index.tsx +++ b/src/components/AddressSummary/index.tsx @@ -5,46 +5,56 @@ import * as React from "react"; import { FormAddressType } from "../ShippingAddressForm/types"; const AddressSummary: React.FC<{ - address: FormAddressType; + address?: FormAddressType; email?: string; paragraphRef?: React.RefObject; -}> = ({ address, email, paragraphRef }) => - address ? ( -

- {`${address.firstName} ${address.lastName}`} -
- {address.companyName && ( - <> - {address.companyName}
- - )} - {address.streetAddress1} -
- {address.streetAddress2 && ( - <> - {address.streetAddress2}
- - )} - {address.city}, {address.postalCode} -
- {address.countryArea && ( - <> - {address.countryArea}
- - )} - {address.country.country} -
- {address.phone && ( - <> - Phone number: {address.phone}
- - )} - {email && ( - <> - {email}
- - )} -

- ) : null; +}> = ({ address, email, paragraphRef }) => { + if (address) { + return ( +

+ {`${address.firstName} ${address.lastName}`} +
+ {address.companyName && ( + <> + {address.companyName}
+ + )} + {address.streetAddress1} +
+ {address.streetAddress2 && ( + <> + {address.streetAddress2}
+ + )} + {address.city}, {address.postalCode} +
+ {address.countryArea && ( + <> + {address.countryArea}
+ + )} + {address.country.country} +
+ {address.phone && ( + <> + Phone number: {address.phone}
+ + )} + {email && ( + <> + {email}
+ + )} +

+ ); + } else if (email) { + return ( +

+ {email} +

+ ); + } + return null; +}; export default AddressSummary; diff --git a/src/components/CartProvider/index.tsx b/src/components/CartProvider/index.tsx index af1961a9dc..bd24d51d51 100644 --- a/src/components/CartProvider/index.tsx +++ b/src/components/CartProvider/index.tsx @@ -6,14 +6,14 @@ import { CheckoutContextInterface } from "../../checkout/context"; import { updateCheckoutLineQuery } from "../../checkout/queries"; import { updateCheckoutLine, - updateCheckoutLineVariables + updateCheckoutLineVariables, } from "../../checkout/types/updateCheckoutLine"; import { maybe } from "../../core/utils"; import { CartContext, CartInterface, CartLine, - CartLineInterface + CartLineInterface, } from "./context"; enum LocalStorageKeys { @@ -123,6 +123,7 @@ export default class CartProvider extends React.Component< checkout.update({ checkout: { ...checkout.checkout, + isShippingRequired: updatedCheckout.isShippingRequired, lines: updatedCheckout.lines, subtotalPrice: updatedCheckout.subtotalPrice, }, diff --git a/src/components/ShippingAddressForm/AddNewShippingAddressForm.tsx b/src/components/ShippingAddressForm/AddNewShippingAddressForm.tsx index 8dea5f332e..060698b994 100644 --- a/src/components/ShippingAddressForm/AddNewShippingAddressForm.tsx +++ b/src/components/ShippingAddressForm/AddNewShippingAddressForm.tsx @@ -9,9 +9,14 @@ import { ShopContext } from "../ShopProvider/context"; import { FormAddressType, IShippingNewAddressFormProps } from "./types"; import { getFormData } from "./utils"; -export const AddNewShippingAddressForm: React.FC< - IShippingNewAddressFormProps -> = ({ data, errors, onSubmit, children, type }) => ( +export const AddNewShippingAddressForm: React.FC = ({ + data, + errors, + onSubmit, + children, + type, + noShipping = false, +}) => (
{({ countries, geolocalization, defaultCountry }) => ( diff --git a/src/components/ShippingAddressForm/ShippingAddressForm.tsx b/src/components/ShippingAddressForm/ShippingAddressForm.tsx index 0be2854358..f5cac6e1bb 100644 --- a/src/components/ShippingAddressForm/ShippingAddressForm.tsx +++ b/src/components/ShippingAddressForm/ShippingAddressForm.tsx @@ -16,6 +16,7 @@ const ShippingAddressForm: React.FC = ({ onSubmit, children, shippingAsBilling = false, + noShipping = false, type = "shipping", }) => (
@@ -100,7 +101,7 @@ const ShippingAddressForm: React.FC = ({ "address-form__grid--full": type === "billing", })} > - {type === "shipping" && ( + {(type === "shipping" || noShipping) && ( { export interface FormAddressType extends Omit { asBilling?: boolean; asNew?: boolean; + email?: string; country: { country?: string; code?: string; value?: string }; } @@ -23,9 +24,11 @@ export interface IShippingAddressFormProps buttonText: string; onSubmit: (data: FormAddressType) => void; shippingAsBilling?: boolean; + noShipping?: boolean; } export interface IShippingNewAddressFormProps extends IBaseShippingAddressFormProps { onSubmit: (data: FormAddressType) => void; + noShipping?: boolean; } diff --git a/src/index.tsx b/src/index.tsx index d757e9f997..610ead4895 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -5,7 +5,7 @@ import { NotificationTemplate } from "@components/atoms"; import { I18nLoader, ServiceWorkerContext, - ServiceWorkerProvider + ServiceWorkerProvider, } from "@components/containers"; import { SaleorProvider, useAuth, useUserDetails } from "@sdk/react"; import { defaultTheme, GlobalStyle } from "@styles"; @@ -38,7 +38,7 @@ import ShopProvider from "./components/ShopProvider"; import { authLink, - invalidTokenLinkWithTokenHandlerComponent + invalidTokenLinkWithTokenHandlerComponent, } from "./core/auth"; import { languages } from "./languages"; diff --git a/types/globalTypes.ts b/types/globalTypes.ts index 56f5b017ff..b29f687047 100644 --- a/types/globalTypes.ts +++ b/types/globalTypes.ts @@ -329,7 +329,8 @@ export interface AddressInput { export interface AttributeInput { slug: string; - value: string; + value?: string | null; + values?: (string | null)[] | null; } export interface CheckoutCreateInput {