Changes, fix Shopify GraphQL deprecations

This commit is contained in:
cond0r 2021-03-04 10:37:51 +02:00
parent 639863bb35
commit 9ccb32ce21
25 changed files with 103 additions and 133 deletions

View File

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

View File

@ -1,2 +1,2 @@
SHOPIFY_STORE_DOMAIN= NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN=
SHOPIFY_STOREFRONT_ACCESS_TOKEN= NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN=

View File

@ -10,7 +10,7 @@ import {
MutationCheckoutCreateArgs, MutationCheckoutCreateArgs,
} from '../schema' } from '../schema'
import useLogin, { UseLogin } from '@commerce/auth/use-login' import useLogin, { UseLogin } from '@commerce/auth/use-login'
import { setCustomerToken } from '../utils' import { setCustomerToken, throwUserErrors } from '../utils'
export default useLogin as UseLogin<typeof handler> export default useLogin as UseLogin<typeof handler>
@ -45,13 +45,8 @@ export const handler: MutationHook<null, {}, CustomerAccessTokenCreateInput> = {
}, },
}) })
const errors = customerAccessTokenCreate?.customerUserErrors throwUserErrors(customerAccessTokenCreate?.customerUserErrors)
if (errors && errors.length) {
throw new ValidationError({
message: getErrorMessage(errors[0]),
})
}
const customerAccessToken = customerAccessTokenCreate?.customerAccessToken const customerAccessToken = customerAccessTokenCreate?.customerAccessToken
const accessToken = customerAccessToken?.accessToken const accessToken = customerAccessToken?.accessToken

View File

@ -10,7 +10,7 @@ import {
} from '../schema' } from '../schema'
import { customerCreateMutation } from '../utils/mutations' import { customerCreateMutation } from '../utils/mutations'
import { handleAutomaticLogin, handleAccountActivation } from '../utils' import { handleAutomaticLogin, throwUserErrors } from '../utils'
export default useSignup as UseSignup<typeof handler> export default useSignup as UseSignup<typeof handler>
@ -50,15 +50,7 @@ export const handler: MutationHook<
}, },
}) })
const errors = customerCreate?.customerUserErrors throwUserErrors(customerCreate?.customerUserErrors)
if (errors && errors.length) {
const [error] = errors
throw new ValidationError({
message: error.message,
})
}
await handleAutomaticLogin(fetch, { email, password }) await handleAutomaticLogin(fetch, { email, password })
return null return null

View File

@ -1,3 +1,4 @@
export { default as useCart } from './use-cart' export { default as useCart } from './use-cart'
export { default as useAddItem } from './use-add-item' export { default as useAddItem } from './use-add-item'
export { default as useUpdateItem } from './use-update-item'
export { default as useRemoveItem } from './use-remove-item' export { default as useRemoveItem } from './use-remove-item'

View File

@ -1,12 +1,15 @@
import { useCallback } from 'react'
import type { MutationHook } from '@commerce/utils/types' import type { MutationHook } from '@commerce/utils/types'
import { CommerceError } from '@commerce/utils/errors' import { CommerceError } from '@commerce/utils/errors'
import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item'
import useCart from './use-cart' import useCart from './use-cart'
import {
checkoutLineItemAddMutation,
getCheckoutId,
checkoutToCart,
} from '../utils'
import { Cart, CartItemBody } from '../types' import { Cart, CartItemBody } from '../types'
import { checkoutLineItemAddMutation, getCheckoutId } from '../utils'
import { checkoutToCart } from './utils'
import { Mutation, MutationCheckoutLineItemsAddArgs } from '../schema' import { Mutation, MutationCheckoutLineItemsAddArgs } from '../schema'
import { useCallback } from 'react'
export default useAddItem as UseAddItem<typeof handler> export default useAddItem as UseAddItem<typeof handler>

View File

@ -6,7 +6,7 @@ import useCommerceCart, {
import { Cart } from '../types' import { Cart } from '../types'
import { SWRHook } from '@commerce/utils/types' import { SWRHook } from '@commerce/utils/types'
import { checkoutCreate, checkoutToCart } from './utils' import { checkoutCreate, checkoutToCart } from '../utils'
import getCheckoutQuery from '../utils/queries/get-checkout-query' import getCheckoutQuery from '../utils/queries/get-checkout-query'
export default useCommerceCart as UseCart<typeof handler> export default useCommerceCart as UseCart<typeof handler>

View File

@ -1,23 +1,22 @@
import { useCallback } from 'react' import { useCallback } from 'react'
import type { import type {
MutationHookContext, MutationHookContext,
HookFetcherContext, HookFetcherContext,
} from '@commerce/utils/types' } from '@commerce/utils/types'
import { RemoveCartItemBody } from '@commerce/types'
import { ValidationError } from '@commerce/utils/errors' import { ValidationError } from '@commerce/utils/errors'
import useRemoveItem, { import useRemoveItem, {
RemoveItemInput as RemoveItemInputBase, RemoveItemInput as RemoveItemInputBase,
UseRemoveItem, UseRemoveItem,
} from '@commerce/cart/use-remove-item' } from '@commerce/cart/use-remove-item'
import useCart from './use-cart' import useCart from './use-cart'
import { checkoutLineItemRemoveMutation, getCheckoutId } from '../utils' import {
import { checkoutToCart } from './utils' checkoutLineItemRemoveMutation,
getCheckoutId,
checkoutToCart,
} from '../utils'
import { Cart, LineItem } from '../types' import { Cart, LineItem } from '../types'
import { Mutation, MutationCheckoutLineItemsRemoveArgs } from '../schema' import { Mutation, MutationCheckoutLineItemsRemoveArgs } from '../schema'
import { RemoveCartItemBody } from '@commerce/types'
export type RemoveItemFn<T = any> = T extends LineItem export type RemoveItemFn<T = any> = T extends LineItem
? (input?: RemoveItemInput<T>) => Promise<Cart | null> ? (input?: RemoveItemInput<T>) => Promise<Cart | null>

View File

@ -13,7 +13,7 @@ import useUpdateItem, {
import useCart from './use-cart' import useCart from './use-cart'
import { handler as removeItemHandler } from './use-remove-item' import { handler as removeItemHandler } from './use-remove-item'
import type { Cart, LineItem, UpdateCartItemBody } from '../types' import type { Cart, LineItem, UpdateCartItemBody } from '../types'
import { checkoutToCart } from './utils' import { checkoutToCart } from '../utils'
import { getCheckoutId, checkoutLineItemUpdateMutation } from '../utils' import { getCheckoutId, checkoutLineItemUpdateMutation } from '../utils'
import { Mutation, MutationCheckoutLineItemsUpdateArgs } from '../schema' import { Mutation, MutationCheckoutLineItemsUpdateArgs } from '../schema'

View File

@ -1,31 +0,0 @@
import { HookFetcherFn } from '@commerce/utils/types'
import { Cart } from '@commerce/types'
import { checkoutCreate, checkoutToCart } from '.'
import { FetchCartInput } from '@commerce/cart/use-cart'
const fetcher: HookFetcherFn<Cart | null, FetchCartInput> = async ({
options,
input: { cartId: checkoutId },
fetch,
}) => {
let checkout
if (checkoutId) {
const data = await fetch({
...options,
variables: {
checkoutId,
},
})
checkout = data.node
}
if (checkout?.completedAt || !checkoutId) {
checkout = await checkoutCreate(fetch)
}
// TODO: Fix this type
return checkoutToCart({ checkout } as any)
}
export default fetcher

View File

@ -1,2 +0,0 @@
export { default as checkoutToCart } from './checkout-to-cart'
export { default as checkoutCreate } from './checkout-create'

View File

@ -23,9 +23,6 @@ export const shopifyProvider = {
customer: { useCustomer }, customer: { useCustomer },
products: { useSearch }, products: { useSearch },
auth: { useLogin, useLogout, useSignup }, auth: { useLogin, useLogout, useSignup },
features: {
wishlist: false,
},
} }
export type ShopifyProvider = typeof shopifyProvider export type ShopifyProvider = typeof shopifyProvider

View File

@ -1,12 +1,13 @@
import Cookies from 'js-cookie'
import { import {
SHOPIFY_CHECKOUT_ID_COOKIE, SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CHECKOUT_URL_COOKIE, SHOPIFY_CHECKOUT_URL_COOKIE,
SHOPIFY_COOKIE_EXPIRE, SHOPIFY_COOKIE_EXPIRE,
} from '../../const' } from '../const'
import checkoutCreateMutation from '../../utils/mutations/checkout-create' import checkoutCreateMutation from './mutations/checkout-create'
import Cookies from 'js-cookie' import { CheckoutCreatePayload } from '../schema'
import { CheckoutCreatePayload } from '../../schema'
export const checkoutCreate = async ( export const checkoutCreate = async (
fetch: any fetch: any
@ -23,7 +24,7 @@ export const checkoutCreate = async (
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) Cookies.set(SHOPIFY_CHECKOUT_URL_COOKIE, checkout.webUrl, options)
} }
return checkout return checkout

View File

@ -1,20 +1,22 @@
import { Cart } from '../../types' import { Cart } from '../types'
import { CommerceError, ValidationError } from '@commerce/utils/errors' import { CommerceError } from '@commerce/utils/errors'
import { import {
CheckoutLineItemsAddPayload, CheckoutLineItemsAddPayload,
CheckoutLineItemsRemovePayload, CheckoutLineItemsRemovePayload,
CheckoutLineItemsUpdatePayload, CheckoutLineItemsUpdatePayload,
CheckoutCreatePayload, CheckoutCreatePayload,
CheckoutUserError,
Checkout, Checkout,
UserError, Maybe,
} from '../../schema' } from '../schema'
import { normalizeCart } from '../../utils'
import { Maybe } from 'framework/bigcommerce/schema' import { normalizeCart } from './normalize'
import throwUserErrors from './throw-user-errors'
export type CheckoutQuery = { export type CheckoutQuery = {
checkout: Checkout checkout: Checkout
userErrors?: Array<UserError> checkoutUserErrors: Array<CheckoutUserError>
} }
export type CheckoutPayload = export type CheckoutPayload =
@ -27,22 +29,16 @@ export type CheckoutPayload =
const checkoutToCart = (checkoutPayload?: Maybe<CheckoutPayload>): Cart => { const checkoutToCart = (checkoutPayload?: Maybe<CheckoutPayload>): Cart => {
if (!checkoutPayload) { if (!checkoutPayload) {
throw new CommerceError({ throw new CommerceError({
message: 'Invalid response from Shopify', message: 'Missing checkout payload from response',
}) })
} }
const checkout = checkoutPayload?.checkout const checkout = checkoutPayload?.checkout
const userErrors = checkoutPayload?.userErrors throwUserErrors(checkoutPayload?.checkoutUserErrors)
if (userErrors && userErrors.length) {
throw new ValidationError({
message: userErrors[0].message,
})
}
if (!checkout) { if (!checkout) {
throw new CommerceError({ throw new CommerceError({
message: 'Invalid response from Shopify', message: 'Missing checkout object from response',
}) })
} }

View File

@ -1,4 +1,4 @@
const getSortVariables = (sort?: string, isCategory = false) => { const getSortVariables = (sort?: string, isCategory: boolean = false) => {
let output = {} let output = {}
switch (sort) { switch (sort) {
case 'price-asc': case 'price-asc':

View File

@ -1,5 +1,6 @@
import { ValidationError } from '@commerce/utils/errors'
import { FetcherOptions } from '@commerce/utils/types' import { FetcherOptions } from '@commerce/utils/types'
import throwUserErrors from './throw-user-errors'
import { import {
MutationCustomerActivateArgs, MutationCustomerActivateArgs,
MutationCustomerActivateByUrlArgs, MutationCustomerActivateByUrlArgs,
@ -22,13 +23,7 @@ const handleAccountActivation = async (
}, },
}) })
const errors = customerActivateByUrl?.customerUserErrors throwUserErrors(customerActivateByUrl?.customerUserErrors)
if (errors && errors.length) {
const [error] = errors
throw new ValidationError({
message: error.message,
})
}
} catch (error) {} } catch (error) {}
} }

View File

@ -1,33 +1,12 @@
import { ValidationError } from '@commerce/utils/errors'
import { FetcherOptions } from '@commerce/utils/types' import { FetcherOptions } from '@commerce/utils/types'
import { CustomerAccessTokenCreateInput } from '../schema' import { CustomerAccessTokenCreateInput } from '../schema'
import { setCustomerToken } from './customer-token' import { setCustomerToken } from './customer-token'
import { customerAccessTokenCreateMutation } from './mutations' import { customerAccessTokenCreateMutation } from './mutations'
import throwUserErrors from './throw-user-errors'
const getErrorMessage = ({
code,
message,
}: {
code: string
message: string
}) => {
switch (code) {
case 'UNIDENTIFIED_CUSTOMER':
message = 'Cannot find an account that matches the provided credentials'
break
}
return message
}
const handleLogin = (data: any) => { const handleLogin = (data: any) => {
const response = data.customerAccessTokenCreate const response = data.customerAccessTokenCreate
const errors = response?.customerUserErrors throwUserErrors(response?.customerUserErrors)
if (errors && errors.length) {
throw new ValidationError({
message: getErrorMessage(errors[0]),
})
}
const customerAccessToken = response?.customerAccessToken const customerAccessToken = response?.customerAccessToken
const accessToken = customerAccessToken?.accessToken const accessToken = customerAccessToken?.accessToken

View File

@ -4,8 +4,11 @@ export { default as getSortVariables } from './get-sort-variables'
export { default as getVendors } from './get-vendors' export { default as getVendors } from './get-vendors'
export { default as getCategories } from './get-categories' export { default as getCategories } from './get-categories'
export { default as getCheckoutId } from './get-checkout-id' export { default as getCheckoutId } from './get-checkout-id'
export { default as checkoutCreate } from './checkout-create'
export { default as checkoutToCart } from './checkout-to-cart'
export { default as handleLogin, handleAutomaticLogin } from './handle-login' export { default as handleLogin, handleAutomaticLogin } from './handle-login'
export { default as handleAccountActivation } from './handle-account-activation' export { default as handleAccountActivation } from './handle-account-activation'
export { default as throwUserErrors } from './throw-user-errors'
export * from './queries' export * from './queries'
export * from './mutations' export * from './mutations'
export * from './normalize' export * from './normalize'

View File

@ -3,9 +3,10 @@ import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutCreateMutation = /* GraphQL */ ` const checkoutCreateMutation = /* GraphQL */ `
mutation { mutation {
checkoutCreate(input: {}) { checkoutCreate(input: {}) {
userErrors { checkoutUserErrors {
message code
field field
message
} }
checkout { checkout {
${checkoutDetailsFragment} ${checkoutDetailsFragment}

View File

@ -3,9 +3,10 @@ import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutLineItemAddMutation = /* GraphQL */ ` const checkoutLineItemAddMutation = /* GraphQL */ `
mutation($checkoutId: ID!, $lineItems: [CheckoutLineItemInput!]!) { mutation($checkoutId: ID!, $lineItems: [CheckoutLineItemInput!]!) {
checkoutLineItemsAdd(checkoutId: $checkoutId, lineItems: $lineItems) { checkoutLineItemsAdd(checkoutId: $checkoutId, lineItems: $lineItems) {
userErrors { checkoutUserErrors {
message code
field field
message
} }
checkout { checkout {
${checkoutDetailsFragment} ${checkoutDetailsFragment}

View File

@ -6,9 +6,10 @@ const checkoutLineItemRemoveMutation = /* GraphQL */ `
checkoutId: $checkoutId checkoutId: $checkoutId
lineItemIds: $lineItemIds lineItemIds: $lineItemIds
) { ) {
userErrors { checkoutUserErrors {
message code
field field
message
} }
checkout { checkout {
${checkoutDetailsFragment} ${checkoutDetailsFragment}

View File

@ -3,9 +3,10 @@ import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutLineItemUpdateMutation = /* GraphQL */ ` const checkoutLineItemUpdateMutation = /* GraphQL */ `
mutation($checkoutId: ID!, $lineItems: [CheckoutLineItemUpdateInput!]!) { mutation($checkoutId: ID!, $lineItems: [CheckoutLineItemUpdateInput!]!) {
checkoutLineItemsUpdate(checkoutId: $checkoutId, lineItems: $lineItems) { checkoutLineItemsUpdate(checkoutId: $checkoutId, lineItems: $lineItems) {
userErrors { checkoutUserErrors {
message code
field field
message
} }
checkout { checkout {
${checkoutDetailsFragment} ${checkoutDetailsFragment}

View File

@ -3,7 +3,7 @@ const customerAccessTokenDeleteMutation = /* GraphQL */ `
customerAccessTokenDelete(customerAccessToken: $customerAccessToken) { customerAccessTokenDelete(customerAccessToken: $customerAccessToken) {
deletedAccessToken deletedAccessToken
deletedCustomerAccessTokenId deletedCustomerAccessTokenId
userErrors { customerUserErrors {
field field
message message
} }

View File

@ -0,0 +1,38 @@
import { ValidationError } from '@commerce/utils/errors'
import {
CheckoutErrorCode,
CheckoutUserError,
CustomerErrorCode,
CustomerUserError,
} from '../schema'
export type UserErrors = Array<CheckoutUserError | CustomerUserError>
export type UserErrorCode =
| CustomerErrorCode
| CheckoutErrorCode
| null
| undefined
const getCustomMessage = (code: UserErrorCode, message: string) => {
switch (code) {
case 'UNIDENTIFIED_CUSTOMER':
message = 'Cannot find an account that matches the provided credentials'
break
}
return message
}
export const throwUserErrors = (errors?: UserErrors) => {
if (errors && errors.length) {
throw new ValidationError({
errors: errors.map(({ code, message }) => ({
code: code ?? 'validation_error',
message: getCustomMessage(code, message),
})),
})
}
}
export default throwUserErrors

View File

@ -22,8 +22,8 @@
"@components/*": ["components/*"], "@components/*": ["components/*"],
"@commerce": ["framework/commerce"], "@commerce": ["framework/commerce"],
"@commerce/*": ["framework/commerce/*"], "@commerce/*": ["framework/commerce/*"],
"@framework": ["framework/bigcommerce"], "@framework": ["framework/shopify"],
"@framework/*": ["framework/bigcommerce/*"] "@framework/*": ["framework/shopify/*"]
} }
}, },
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"], "include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],