4
0
forked from crowetic/commerce

Shopify: create checkout on add to cart (#432)

* Create checkout on add to cart

* Checkout changes

* Revert files

* Fix checkout
This commit is contained in:
cond0r 2021-09-24 22:55:46 +03:00 committed by GitHub
parent 8e7b942240
commit f9644fecef
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 97 additions and 73 deletions

View File

@ -41,4 +41,4 @@ export const handler: MutationHook<AddItemHook> = {
[fetch, mutate] [fetch, mutate]
) )
}, },
} }

View File

@ -9,6 +9,7 @@ import {
checkoutLineItemAddMutation, checkoutLineItemAddMutation,
getCheckoutId, getCheckoutId,
checkoutToCart, checkoutToCart,
checkoutCreate,
} from '../utils' } from '../utils'
import { Mutation, MutationCheckoutLineItemsAddArgs } from '../schema' import { Mutation, MutationCheckoutLineItemsAddArgs } from '../schema'
@ -28,34 +29,42 @@ export const handler: MutationHook<AddItemHook> = {
}) })
} }
const { checkoutLineItemsAdd } = await fetch< const lineItems = [
Mutation, {
MutationCheckoutLineItemsAddArgs variantId: item.variantId,
>({ quantity: item.quantity ?? 1,
...options,
variables: {
checkoutId: getCheckoutId(),
lineItems: [
{
variantId: item.variantId,
quantity: item.quantity ?? 1,
},
],
}, },
}) ]
return checkoutToCart(checkoutLineItemsAdd) let checkoutId = getCheckoutId()
},
useHook: ({ fetch }) => () => {
const { mutate } = useCart()
return useCallback( if (!checkoutId) {
async function addItem(input) { return checkoutToCart(await checkoutCreate(fetch, lineItems))
const data = await fetch({ input }) } else {
await mutate(data, false) const { checkoutLineItemsAdd } = await fetch<
return data Mutation,
}, MutationCheckoutLineItemsAddArgs
[fetch, mutate] >({
) ...options,
variables: {
checkoutId,
lineItems,
},
})
return checkoutToCart(checkoutLineItemsAdd)
}
}, },
useHook:
({ fetch }) =>
() => {
const { mutate } = useCart()
return useCallback(
async function addItem(input) {
const data = await fetch({ input })
await mutate(data, false)
return data
},
[fetch, mutate]
)
},
} }

View File

@ -2,15 +2,15 @@ import { useMemo } from 'react'
import useCommerceCart, { UseCart } from '@commerce/cart/use-cart' import useCommerceCart, { UseCart } from '@commerce/cart/use-cart'
import { SWRHook } from '@commerce/utils/types' import { SWRHook } from '@commerce/utils/types'
import { checkoutCreate, checkoutToCart } from '../utils' import { checkoutToCart } from '../utils'
import getCheckoutQuery from '../utils/queries/get-checkout-query' import getCheckoutQuery from '../utils/queries/get-checkout-query'
import { GetCartHook } from '../types/cart' import { GetCartHook } from '../types/cart'
import Cookies from 'js-cookie'
import { import {
GetCheckoutQuery, SHOPIFY_CHECKOUT_ID_COOKIE,
GetCheckoutQueryVariables, SHOPIFY_CHECKOUT_URL_COOKIE,
CheckoutDetailsFragment, } from '../const'
} from '../schema'
export default useCommerceCart as UseCart<typeof handler> export default useCommerceCart as UseCart<typeof handler>
@ -18,40 +18,43 @@ export const handler: SWRHook<GetCartHook> = {
fetchOptions: { fetchOptions: {
query: getCheckoutQuery, query: getCheckoutQuery,
}, },
async fetcher({ input: { cartId: checkoutId }, options, fetch }) { async fetcher({ input: { cartId }, options, fetch }) {
let checkout if (cartId) {
const { node: checkout } = await fetch({
if (checkoutId) {
const data = await fetch({
...options, ...options,
variables: { variables: {
checkoutId: checkoutId, checkoutId: cartId,
}, },
}) })
checkout = data.node if (checkout?.completedAt) {
Cookies.remove(SHOPIFY_CHECKOUT_ID_COOKIE)
Cookies.remove(SHOPIFY_CHECKOUT_URL_COOKIE)
return null
} else {
return checkoutToCart({
checkout,
})
}
} }
return null
if (checkout?.completedAt || !checkoutId) {
checkout = await checkoutCreate(fetch)
}
return checkoutToCart({ checkout })
}, },
useHook: ({ useData }) => (input) => { useHook:
const response = useData({ ({ useData }) =>
swrOptions: { revalidateOnFocus: false, ...input?.swrOptions }, (input) => {
}) const response = useData({
return useMemo( swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
() => })
Object.create(response, { return useMemo(
isEmpty: { () =>
get() { Object.create(response, {
return (response.data?.lineItems.length ?? 0) <= 0 isEmpty: {
get() {
return (response.data?.lineItems.length ?? 0) <= 0
},
enumerable: true,
}, },
enumerable: true, }),
}, [response]
}), )
[response] },
)
},
} }

View File

@ -1,6 +1,7 @@
{ {
"provider": "shopify", "provider": "shopify",
"features": { "features": {
"wishlist": false "wishlist": false,
"customerAuth": true
} }
} }

View File

@ -7,27 +7,39 @@ import {
} from '../const' } from '../const'
import checkoutCreateMutation from './mutations/checkout-create' import checkoutCreateMutation from './mutations/checkout-create'
import { CheckoutCreatePayload } from '../schema' import {
CheckoutCreatePayload,
CheckoutLineItemInput,
Mutation,
MutationCheckoutCreateArgs,
} from '../schema'
import { FetcherOptions } from '@commerce/utils/types'
export const checkoutCreate = async ( export const checkoutCreate = async (
fetch: any fetch: <T = any, B = Body>(options: FetcherOptions<B>) => Promise<T>,
lineItems: CheckoutLineItemInput[]
): Promise<CheckoutCreatePayload> => { ): Promise<CheckoutCreatePayload> => {
const data = await fetch({ const { checkoutCreate } = await fetch<Mutation, MutationCheckoutCreateArgs>({
query: checkoutCreateMutation, query: checkoutCreateMutation,
variables: {
input: { lineItems },
},
}) })
const checkout = data.checkoutCreate?.checkout const checkout = checkoutCreate?.checkout
const checkoutId = checkout?.id
if (checkoutId) { if (checkout) {
const checkoutId = checkout?.id
const options = { const options = {
expires: SHOPIFY_COOKIE_EXPIRE, expires: SHOPIFY_COOKIE_EXPIRE,
} }
Cookies.set(SHOPIFY_CHECKOUT_ID_COOKIE, checkoutId, options) Cookies.set(SHOPIFY_CHECKOUT_ID_COOKIE, checkoutId, options)
Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout.webUrl, options) if (checkout?.webUrl) {
Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout.webUrl, options)
}
} }
return checkout return checkoutCreate!
} }
export default checkoutCreate export default checkoutCreate

View File

@ -27,16 +27,15 @@ export type CheckoutPayload =
| CheckoutQuery | CheckoutQuery
const checkoutToCart = (checkoutPayload?: Maybe<CheckoutPayload>): Cart => { const checkoutToCart = (checkoutPayload?: Maybe<CheckoutPayload>): Cart => {
const checkout = checkoutPayload?.checkout
throwUserErrors(checkoutPayload?.checkoutUserErrors) throwUserErrors(checkoutPayload?.checkoutUserErrors)
if (!checkout) { if (!checkoutPayload?.checkout) {
throw new CommerceError({ throw new CommerceError({
message: 'Missing checkout object from response', message: 'Missing checkout object from response',
}) })
} }
return normalizeCart(checkout) return normalizeCart(checkoutPayload?.checkout)
} }
export default checkoutToCart export default checkoutToCart