Switch to Cart API and utils named exports

This commit is contained in:
cond0r 2022-06-29 16:32:09 +03:00
parent 2c8d46ce90
commit 168aba7770
65 changed files with 11649 additions and 6671 deletions

View File

@ -8,7 +8,7 @@
"dev": "taskr",
"types": "tsc --emitDeclarationOnly",
"prettier-fix": "prettier --write .",
"generate": "DOTENV_CONFIG_PATH=./.env graphql-codegen -r dotenv/config"
"generate": "DOTENV_CONFIG_PATH=../../site/.env.local graphql-codegen -r dotenv/config"
},
"sideEffects": false,
"type": "module",
@ -70,6 +70,7 @@
"@types/node": "^17.0.8",
"@types/react": "^17.0.38",
"dotenv": "^12.0.3",
"graphql": "^16.5.0",
"lint-staged": "^12.1.7",
"next": "^12.0.8",
"prettier": "^2.5.1",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +1,15 @@
import {
SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CHECKOUT_URL_COOKIE,
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
} from '../../../const'
import associateCustomerWithCheckoutMutation from '../../../utils/mutations/associate-customer-with-checkout'
import { SHOPIFY_CART_URL_COOKIE } from '../../../const'
import type { CheckoutEndpoint } from '.'
const getCheckout: CheckoutEndpoint['handlers']['getCheckout'] = async ({
req,
res,
config,
}) => {
const { cookies } = req
const checkoutUrl = cookies[SHOPIFY_CHECKOUT_URL_COOKIE]
const customerCookie = cookies[SHOPIFY_CUSTOMER_TOKEN_COOKIE]
const cartUrl = cookies[SHOPIFY_CART_URL_COOKIE]
if (customerCookie) {
try {
await config.fetch(associateCustomerWithCheckoutMutation, {
variables: {
checkoutId: cookies[SHOPIFY_CHECKOUT_ID_COOKIE],
customerAccessToken: cookies[SHOPIFY_CUSTOMER_TOKEN_COOKIE],
},
})
} catch (error) {
console.error(error)
}
}
if (checkoutUrl) {
res.redirect(checkoutUrl)
if (cartUrl) {
res.redirect(cartUrl)
} else {
res.redirect('/cart')
}

View File

@ -8,12 +8,12 @@ import {
API_URL,
API_TOKEN,
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CART_ID_COOKIE,
} from '../const'
import fetchGraphqlApi from './utils/fetch-graphql-api'
import * as operations from './operations'
import operations from './operations'
if (!API_URL) {
throw new Error(
@ -34,7 +34,7 @@ const config: ShopifyConfig = {
commerceUrl: API_URL,
apiToken: API_TOKEN,
customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE,
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
cartCookie: SHOPIFY_CART_ID_COOKIE,
cartCookieMaxAge: ONE_DAY * 30,
fetch: fetchGraphqlApi,
}

View File

@ -7,10 +7,9 @@ import {
GetAllPagesQueryVariables,
PageEdge,
} from '../../../schema'
import { normalizePages } from '../../utils'
import { normalizePages, getAllPagesQuery } from '../../utils'
import type { ShopifyConfig, Provider } from '..'
import type { GetAllPagesOperation, Page } from '../../types/page'
import getAllPagesQuery from '../../utils/queries/get-all-pages-query'
export default function getAllPagesOperation({
commerce,

View File

@ -6,7 +6,6 @@ import { GetAllProductPathsOperation } from '../../types/product'
import {
GetAllProductPathsQuery,
GetAllProductPathsQueryVariables,
ProductEdge,
} from '../../../schema'
import type { ShopifyConfig, Provider } from '..'
import { getAllProductsQuery } from '../../utils'

View File

@ -9,8 +9,7 @@ import {
Product as ShopifyProduct,
} from '../../../schema'
import type { ShopifyConfig, Provider } from '..'
import getAllProductsQuery from '../../utils/queries/get-all-products-query'
import { normalizeProduct } from '../../utils'
import { normalizeProduct, getAllProductsQuery } from '../../utils'
export default function getAllProductsOperation({
commerce,

View File

@ -2,7 +2,7 @@ import type {
OperationContext,
OperationOptions,
} from '@vercel/commerce/api/operations'
import { normalizePage } from '../../utils'
import { normalizePage, getPageQuery } from '../../utils'
import type { ShopifyConfig, Provider } from '..'
import {
GetPageQuery,
@ -10,7 +10,6 @@ import {
Page as ShopifyPage,
} from '../../../schema'
import { GetPageOperation } from '../../types/page'
import getPageQuery from '../../utils/queries/get-page-query'
export default function getPageOperation({
commerce,

View File

@ -1,7 +1,17 @@
export { default as getAllPages } from './get-all-pages'
export { default as getPage } from './get-page'
export { default as getAllProducts } from './get-all-products'
export { default as getAllProductPaths } from './get-all-product-paths'
export { default as getProduct } from './get-product'
export { default as getSiteInfo } from './get-site-info'
export { default as login } from './login'
import getAllPages from './get-all-pages'
import getPage from './get-page'
import getAllProducts from './get-all-products'
import getAllProductPaths from './get-all-product-paths'
import getProduct from './get-product'
import getSiteInfo from './get-site-info'
import login from './login'
export default {
getAllPages,
getPage,
getAllProducts,
getAllProductPaths,
getProduct,
getSiteInfo,
login,
}

View File

@ -2,11 +2,13 @@ import type { ServerResponse } from 'http'
import type { OperationContext } from '@vercel/commerce/api/operations'
import type { LoginOperation } from '../../types/login'
import type { ShopifyConfig, Provider } from '..'
import {
customerAccessTokenCreateMutation,
setCustomerToken,
throwUserErrors,
setCustomerToken,
customerAccessTokenCreateMutation,
} from '../../utils'
import { CustomerAccessTokenCreateMutation } from '../../../schema'
export default function loginOperation({

View File

@ -3,8 +3,12 @@ import type { MutationHook } from '@vercel/commerce/utils/types'
import useLogout, { UseLogout } from '@vercel/commerce/auth/use-logout'
import type { LogoutHook } from '../types/logout'
import useCustomer from '../customer/use-customer'
import customerAccessTokenDeleteMutation from '../utils/mutations/customer-access-token-delete'
import { getCustomerToken, setCustomerToken } from '../utils/customer-token'
import {
getCustomerToken,
setCustomerToken,
customerAccessTokenDeleteMutation,
} from '../utils'
export default useLogout as UseLogout<typeof handler>

View File

@ -6,18 +6,23 @@ import type { AddItemHook } from '../types/cart'
import useCart from './use-cart'
import {
checkoutLineItemAddMutation,
getCheckoutId,
checkoutToCart,
checkoutCreate,
cartLinesAddMutation,
getCartId,
cartCreate,
normalizeCart,
throwUserErrors,
} from '../utils'
import { Mutation, MutationCheckoutLineItemsAddArgs } from '../../schema'
import {
CartLinesAddMutation,
CartLinesAddMutationVariables,
} from '../../schema'
export default useAddItem as UseAddItem<typeof handler>
export const handler: MutationHook<AddItemHook> = {
fetchOptions: {
query: checkoutLineItemAddMutation,
query: cartLinesAddMutation,
},
async fetcher({ input: item, options, fetch }) {
if (
@ -29,29 +34,33 @@ export const handler: MutationHook<AddItemHook> = {
})
}
const lineItems = [
const lines = [
{
variantId: item.variantId,
merchandiseId: item.variantId,
quantity: item.quantity ?? 1,
},
]
let checkoutId = getCheckoutId()
let cartId = getCartId()
if (!checkoutId) {
return checkoutToCart(await checkoutCreate(fetch, lineItems))
if (!cartId) {
const cart = await cartCreate(fetch, lines)
return normalizeCart(cart)
} else {
const { checkoutLineItemsAdd } = await fetch<
Mutation,
MutationCheckoutLineItemsAddArgs
const { cartLinesAdd } = await fetch<
CartLinesAddMutation,
CartLinesAddMutationVariables
>({
...options,
variables: {
checkoutId,
lineItems,
cartId,
lines,
},
})
return checkoutToCart(checkoutLineItemsAdd)
throwUserErrors(cartLinesAdd?.userErrors)
return normalizeCart(cartLinesAdd?.cart)
}
},
useHook:

View File

@ -2,38 +2,32 @@ import { useMemo } from 'react'
import useCommerceCart, { UseCart } from '@vercel/commerce/cart/use-cart'
import { SWRHook } from '@vercel/commerce/utils/types'
import { checkoutToCart } from '../utils'
import getCheckoutQuery from '../utils/queries/get-checkout-query'
import { getCartQuery, normalizeCart } from '../utils'
import { GetCartHook } from '../types/cart'
import Cookies from 'js-cookie'
import {
SHOPIFY_CHECKOUT_ID_COOKIE,
SHOPIFY_CHECKOUT_URL_COOKIE,
} from '../const'
import { SHOPIFY_CART_ID_COOKIE, SHOPIFY_CART_URL_COOKIE } from '../const'
export default useCommerceCart as UseCart<typeof handler>
export const handler: SWRHook<GetCartHook> = {
fetchOptions: {
query: getCheckoutQuery,
query: getCartQuery,
},
async fetcher({ input: { cartId }, options, fetch }) {
if (cartId) {
const { node: checkout } = await fetch({
const { node: cart } = await fetch({
...options,
variables: {
checkoutId: cartId,
},
})
if (checkout?.completedAt) {
Cookies.remove(SHOPIFY_CHECKOUT_ID_COOKIE)
Cookies.remove(SHOPIFY_CHECKOUT_URL_COOKIE)
if (cart?.completedAt) {
Cookies.remove(SHOPIFY_CART_ID_COOKIE)
Cookies.remove(SHOPIFY_CART_URL_COOKIE)
return null
} else {
return checkoutToCart({
checkout,
})
return normalizeCart(cart)
}
}
return null

View File

@ -21,27 +21,36 @@ export type RemoveItemActionInput<T = any> = T extends LineItem
export default useRemoveItem as UseRemoveItem<typeof handler>
import {
checkoutLineItemRemoveMutation,
getCheckoutId,
checkoutToCart,
cartLinesRemoveMutation,
getCartId,
normalizeCart,
throwUserErrors,
} from '../utils'
import { Mutation, MutationCheckoutLineItemsRemoveArgs } from '../../schema'
import {
CartLinesRemoveMutation,
CartLinesRemoveMutationVariables,
} from '../../schema'
export const handler = {
fetchOptions: {
query: checkoutLineItemRemoveMutation,
query: cartLinesRemoveMutation,
},
async fetcher({
input: { itemId },
options,
fetch,
}: HookFetcherContext<RemoveItemHook>) {
const data = await fetch<Mutation, MutationCheckoutLineItemsRemoveArgs>({
const data = await fetch<
CartLinesRemoveMutation,
CartLinesRemoveMutationVariables
>({
...options,
variables: { checkoutId: getCheckoutId(), lineItemIds: [itemId] },
variables: { cartId: getCartId(), lineIds: [itemId] },
})
return checkoutToCart(data.checkoutLineItemsRemove)
throwUserErrors(data.cartLinesRemove?.userErrors)
return normalizeCart(data.cartLinesRemove?.cart)
},
useHook:
({ fetch }: MutationHookContext<RemoveItemHook>) =>

View File

@ -12,12 +12,11 @@ import useUpdateItem, {
import useCart from './use-cart'
import { handler as removeItemHandler } from './use-remove-item'
import type { UpdateItemHook, LineItem } from '../types/cart'
import { getCartId, cartLinesUpdateMutation, normalizeCart } from '../utils'
import {
getCheckoutId,
checkoutLineItemUpdateMutation,
checkoutToCart,
} from '../utils'
import { Mutation, MutationCheckoutLineItemsUpdateArgs } from '../../schema'
CartLinesUpdateMutation,
CartLinesUpdateMutationVariables,
} from '../../schema'
export type UpdateItemActionInput<T = any> = T extends LineItem
? Partial<UpdateItemHook['actionInput']>
@ -27,7 +26,7 @@ export default useUpdateItem as UseUpdateItem<typeof handler>
export const handler = {
fetchOptions: {
query: checkoutLineItemUpdateMutation,
query: cartLinesUpdateMutation,
},
async fetcher({
input: { itemId, item },
@ -48,14 +47,14 @@ export const handler = {
message: 'The item quantity has to be a valid integer',
})
}
const { checkoutLineItemsUpdate } = await fetch<
Mutation,
MutationCheckoutLineItemsUpdateArgs
const { cartLinesUpdate } = await fetch<
CartLinesUpdateMutation,
CartLinesUpdateMutationVariables
>({
...options,
variables: {
checkoutId: getCheckoutId(),
lineItems: [
cartId: getCartId(),
lines: [
{
id: itemId,
quantity: item.quantity,
@ -64,7 +63,7 @@ export const handler = {
},
})
return checkoutToCart(checkoutLineItemsUpdate)
return normalizeCart(cartLinesUpdate?.cart)
},
useHook:
({ fetch }: MutationHookContext<UpdateItemHook>) =>

View File

@ -1,6 +1,6 @@
export const SHOPIFY_CHECKOUT_ID_COOKIE = 'shopify_checkoutId'
export const SHOPIFY_CART_ID_COOKIE = 'shopify_cartId'
export const SHOPIFY_CHECKOUT_URL_COOKIE = 'shopify_checkoutUrl'
export const SHOPIFY_CART_URL_COOKIE = 'shopify_cartUrl'
export const SHOPIFY_CUSTOMER_TOKEN_COOKIE = 'shopify_customerToken'
@ -8,6 +8,6 @@ export const STORE_DOMAIN = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN
export const SHOPIFY_COOKIE_EXPIRE = 30
export const API_URL = `https://${STORE_DOMAIN}/api/2021-07/graphql.json`
export const API_URL = `https://${STORE_DOMAIN}/api/2022-04/graphql.json`
export const API_TOKEN = process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN

View File

@ -1,4 +1,4 @@
import { SHOPIFY_CHECKOUT_ID_COOKIE } from './const'
import { SHOPIFY_CART_ID_COOKIE } from './const'
import { handler as useCart } from './cart/use-cart'
import { handler as useAddItem } from './cart/use-add-item'
@ -16,7 +16,7 @@ import fetcher from './fetcher'
export const shopifyProvider = {
locale: 'en-us',
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
cartCookie: SHOPIFY_CART_ID_COOKIE,
fetcher,
cart: { useCart, useAddItem, useUpdateItem, useRemoveItem },
customer: { useCustomer },

View File

@ -0,0 +1,48 @@
import Cookies from 'js-cookie'
import { SHOPIFY_CART_ID_COOKIE, SHOPIFY_COOKIE_EXPIRE } from '../const'
import { cartCreateMutation } from './mutations/cart-create'
import {
CartCreateMutation,
CartCreateMutationVariables,
CartDetailsFragment,
CartLineInput,
} from '../../schema'
import { throwUserErrors } from './throw-user-errors'
import { setCartUrlCookie } from './set-cart-url-cookie'
import { FetcherOptions } from '@vercel/commerce/utils/types'
export const cartCreate = async (
fetch: <T = any, B = Body>(options: FetcherOptions<B>) => Promise<T>,
lines?: Array<CartLineInput> | CartLineInput
): Promise<CartDetailsFragment | null | undefined> => {
const { cartCreate } = await fetch<
CartCreateMutation,
CartCreateMutationVariables
>({
query: cartCreateMutation,
variables: {
input: {
lines,
},
},
})
const cart = cartCreate?.cart
throwUserErrors(cartCreate?.userErrors)
if (cart?.id) {
const options = {
expires: SHOPIFY_COOKIE_EXPIRE,
}
Cookies.set(SHOPIFY_CART_ID_COOKIE, cart.id, options)
}
setCartUrlCookie(cart?.checkoutUrl)
return cart
}
export default cartCreate

View File

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

View File

@ -1,41 +0,0 @@
import type { Cart } from '../types/cart'
import { CommerceError } from '@vercel/commerce/utils/errors'
import {
CheckoutLineItemsAddPayload,
CheckoutLineItemsRemovePayload,
CheckoutLineItemsUpdatePayload,
CheckoutCreatePayload,
CheckoutUserError,
Checkout,
Maybe,
} from '../../schema'
import { normalizeCart } from './normalize'
import throwUserErrors from './throw-user-errors'
export type CheckoutQuery = {
checkout: Checkout
checkoutUserErrors?: Array<CheckoutUserError>
}
export type CheckoutPayload =
| CheckoutLineItemsAddPayload
| CheckoutLineItemsUpdatePayload
| CheckoutLineItemsRemovePayload
| CheckoutCreatePayload
| CheckoutQuery
const checkoutToCart = (checkoutPayload?: Maybe<CheckoutPayload>): Cart => {
throwUserErrors(checkoutPayload?.checkoutUserErrors)
if (!checkoutPayload?.checkout) {
throw new CommerceError({
message: 'Missing checkout object from response',
})
}
return normalizeCart(checkoutPayload?.checkout)
}
export default checkoutToCart

View File

@ -1,9 +1,11 @@
import { ShopifyConfig } from '../api'
import {
GetAllProductVendorsQuery,
GetAllProductVendorsQueryVariables,
} from '../../schema'
import { ShopifyConfig } from '../api'
import getAllProductVendors from './queries/get-all-product-vendors-query'
import { getAllProductVendors } from './queries'
export type Brand = {
entityId: string
@ -17,7 +19,9 @@ export type BrandEdge = {
export type Brands = BrandEdge[]
const getBrands = async (config: ShopifyConfig): Promise<BrandEdge[]> => {
export const getBrands = async (
config: ShopifyConfig
): Promise<BrandEdge[]> => {
const { data } = await config.fetch<
GetAllProductVendorsQuery,
GetAllProductVendorsQueryVariables
@ -40,5 +44,3 @@ const getBrands = async (config: ShopifyConfig): Promise<BrandEdge[]> => {
}
})
}
export default getBrands

View File

@ -0,0 +1,6 @@
import Cookies from 'js-cookie'
import { SHOPIFY_CART_ID_COOKIE } from '../const'
export const getCartId = (id?: string) => {
return id || Cookies.get(SHOPIFY_CART_ID_COOKIE)
}

View File

@ -2,9 +2,9 @@ import type { Category } from '../types/site'
import { ShopifyConfig } from '../api'
import { CollectionEdge } from '../../schema'
import { normalizeCategory } from './normalize'
import getSiteCollectionsQuery from './queries/get-all-collections-query'
import { getSiteCollectionsQuery } from './queries/get-all-collections-query'
const getCategories = async ({
export const getCategories = async ({
fetch,
locale,
}: ShopifyConfig): Promise<Category[]> => {
@ -30,5 +30,3 @@ const getCategories = async ({
) ?? []
)
}
export default getCategories

View File

@ -1,8 +0,0 @@
import Cookies from 'js-cookie'
import { SHOPIFY_CHECKOUT_ID_COOKIE } from '../const'
const getCheckoutId = (id?: string) => {
return id ?? Cookies.get(SHOPIFY_CHECKOUT_ID_COOKIE)
}
export default getCheckoutId

View File

@ -1,4 +1,4 @@
import getSortVariables from './get-sort-variables'
import { getSortVariables } from './get-sort-variables'
import { SearchProductsBody } from '../types/product'
export const getSearchVariables = ({
@ -27,5 +27,3 @@ export const getSearchVariables = ({
}),
}
}
export default getSearchVariables

View File

@ -1,4 +1,7 @@
const getSortVariables = (sort?: string, isCategory: boolean = false) => {
export const getSortVariables = (
sort?: string,
isCategory: boolean = false
) => {
let output = {}
switch (sort) {
case 'price-asc':
@ -28,5 +31,3 @@ const getSortVariables = (sort?: string, isCategory: boolean = false) => {
}
return output
}
export default getSortVariables

View File

@ -1,5 +1,5 @@
import { FetcherOptions } from '@vercel/commerce/utils/types'
import throwUserErrors from './throw-user-errors'
import { throwUserErrors } from './throw-user-errors'
import {
MutationCustomerActivateArgs,
@ -8,7 +8,7 @@ import {
import { Mutation } from '../../schema'
import { customerActivateByUrlMutation } from './mutations'
const handleAccountActivation = async (
export const handleAccountActivation = async (
fetch: <T = any, B = Body>(options: FetcherOptions<B>) => Promise<T>,
input: MutationCustomerActivateByUrlArgs
) => {
@ -26,5 +26,3 @@ const handleAccountActivation = async (
throwUserErrors(customerActivateByUrl?.customerUserErrors)
} catch (error) {}
}
export default handleAccountActivation

View File

@ -10,7 +10,7 @@ export async function getAsyncError(res: Response) {
return getError(data.errors, res.status)
}
const handleFetchResponse = async (res: Response) => {
export const handleFetchResponse = async (res: Response) => {
if (res.ok) {
const { data, errors } = await res.json()
@ -23,5 +23,3 @@ const handleFetchResponse = async (res: Response) => {
throw await getAsyncError(res)
}
export default handleFetchResponse

View File

@ -2,9 +2,9 @@ import { FetcherOptions } from '@vercel/commerce/utils/types'
import { CustomerAccessTokenCreateInput } from '../../schema'
import { setCustomerToken } from './customer-token'
import { customerAccessTokenCreateMutation } from './mutations'
import throwUserErrors from './throw-user-errors'
import { throwUserErrors } from './throw-user-errors'
const handleLogin = (data: any) => {
export const handleLogin = (data: any) => {
const response = data.customerAccessTokenCreate
throwUserErrors(response?.customerUserErrors)
@ -32,5 +32,3 @@ export const handleAutomaticLogin = async (
handleLogin(loginData)
} catch (error) {}
}
export default handleLogin

View File

@ -1,14 +1,14 @@
export { default as handleFetchResponse } from './handle-fetch-response'
export { default as getSearchVariables } from './get-search-variables'
export { default as getSortVariables } from './get-sort-variables'
export { default as getBrands } from './get-brands'
export { default as getCategories } from './get-categories'
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 handleAccountActivation } from './handle-account-activation'
export { default as throwUserErrors } from './throw-user-errors'
export { handleFetchResponse } from './handle-fetch-response'
export { getSearchVariables } from './get-search-variables'
export { getSortVariables } from './get-sort-variables'
export { getBrands } from './get-brands'
export { getCategories } from './get-categories'
export { getCartId } from './get-cart-id'
export { cartCreate } from './cart-create'
export { handleLogin, handleAutomaticLogin } from './handle-login'
export { handleAccountActivation } from './handle-account-activation'
export { throwUserErrors } from './throw-user-errors'
export * from './queries'
export * from './mutations'
export * from './normalize'

View File

@ -1,4 +1,4 @@
const associateCustomerWithCheckoutMutation = /* GraphQl */ `
export const associateCustomerWithCheckoutMutation = /* GraphQl */ `
mutation associateCustomerWithCheckout($checkoutId: ID!, $customerAccessToken: String!) {
checkoutCustomerAssociateV2(checkoutId: $checkoutId, customerAccessToken: $customerAccessToken) {
checkout {
@ -15,4 +15,3 @@ mutation associateCustomerWithCheckout($checkoutId: ID!, $customerAccessToken: S
}
}
`
export default associateCustomerWithCheckoutMutation

View File

@ -0,0 +1,17 @@
import { cartDetailsFragment } from '../queries/get-cart-query'
export const cartCreateMutation = /* GraphQL */ `
mutation cartCreate($input: CartInput = {}) {
cartCreate(input: $input) {
cart {
...cartDetails
}
userErrors {
code
field
message
}
}
}
${cartDetailsFragment}
`

View File

@ -0,0 +1,17 @@
import { cartDetailsFragment } from '../queries/get-cart-query'
export const cartLinesAddMutation = /* GraphQL */ `
mutation cartLinesAdd($lines: [CartLineInput!]!, $cartId: ID!) {
cartLinesAdd(lines: $lines, cartId: $cartId) {
cart {
...cartDetails
}
userErrors {
code
field
message
}
}
}
${cartDetailsFragment}
`

View File

@ -0,0 +1,17 @@
import { cartDetailsFragment } from '../queries/get-cart-query'
export const cartLinesRemoveMutation = /* GraphQL */ `
mutation cartLinesRemove($cartId: ID!, $lineIds: [ID!]!) {
cartLinesRemove(cartId: $cartId, lineIds: $lineIds) {
cart {
...cartDetails
}
userErrors {
code
field
message
}
}
}
${cartDetailsFragment}
`

View File

@ -0,0 +1,17 @@
import { cartDetailsFragment } from '../queries/get-cart-query'
export const cartLinesUpdateMutation = /* GraphQL */ `
mutation cartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!) {
cartLinesUpdate(cartId: $cartId, lines: $lines) {
cart {
...cartDetails
}
userErrors {
code
field
message
}
}
}
${cartDetailsFragment}
`

View File

@ -1,19 +0,0 @@
import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutCreateMutation = /* GraphQL */ `
mutation checkoutCreate($input: CheckoutCreateInput = {}) {
checkoutCreate(input: $input) {
checkoutUserErrors {
code
field
message
}
checkout {
...checkoutDetails
}
}
}
${checkoutDetailsFragment}
`
export default checkoutCreateMutation

View File

@ -1,22 +0,0 @@
import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutLineItemAddMutation = /* GraphQL */ `
mutation checkoutLineItemAdd(
$checkoutId: ID!
$lineItems: [CheckoutLineItemInput!]!
) {
checkoutLineItemsAdd(checkoutId: $checkoutId, lineItems: $lineItems) {
checkoutUserErrors {
code
field
message
}
checkout {
...checkoutDetails
}
}
}
${checkoutDetailsFragment}
`
export default checkoutLineItemAddMutation

View File

@ -1,21 +0,0 @@
import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutLineItemRemoveMutation = /* GraphQL */ `
mutation checkoutLineItemRemove($checkoutId: ID!, $lineItemIds: [ID!]!) {
checkoutLineItemsRemove(
checkoutId: $checkoutId
lineItemIds: $lineItemIds
) {
checkoutUserErrors {
code
field
message
}
checkout {
...checkoutDetails
}
}
}
${checkoutDetailsFragment}
`
export default checkoutLineItemRemoveMutation

View File

@ -1,22 +0,0 @@
import { checkoutDetailsFragment } from '../queries/get-checkout-query'
const checkoutLineItemUpdateMutation = /* GraphQL */ `
mutation checkoutLineItemUpdate(
$checkoutId: ID!
$lineItems: [CheckoutLineItemUpdateInput!]!
) {
checkoutLineItemsUpdate(checkoutId: $checkoutId, lineItems: $lineItems) {
checkoutUserErrors {
code
field
message
}
checkout {
...checkoutDetails
}
}
}
${checkoutDetailsFragment}
`
export default checkoutLineItemUpdateMutation

View File

@ -1,4 +1,4 @@
const customerAccessTokenCreateMutation = /* GraphQL */ `
export const customerAccessTokenCreateMutation = /* GraphQL */ `
mutation customerAccessTokenCreate($input: CustomerAccessTokenCreateInput!) {
customerAccessTokenCreate(input: $input) {
customerAccessToken {
@ -13,4 +13,3 @@ const customerAccessTokenCreateMutation = /* GraphQL */ `
}
}
`
export default customerAccessTokenCreateMutation

View File

@ -1,4 +1,4 @@
const customerAccessTokenDeleteMutation = /* GraphQL */ `
export const customerAccessTokenDeleteMutation = /* GraphQL */ `
mutation customerAccessTokenDelete($customerAccessToken: String!) {
customerAccessTokenDelete(customerAccessToken: $customerAccessToken) {
deletedAccessToken
@ -10,5 +10,3 @@ const customerAccessTokenDeleteMutation = /* GraphQL */ `
}
}
`
export default customerAccessTokenDeleteMutation

View File

@ -1,4 +1,4 @@
const customerActivateByUrlMutation = /* GraphQL */ `
export const customerActivateByUrlMutation = /* GraphQL */ `
mutation customerActivateByUrl($activationUrl: URL!, $password: String!) {
customerActivateByUrl(activationUrl: $activationUrl, password: $password) {
customer {
@ -16,4 +16,3 @@ const customerActivateByUrlMutation = /* GraphQL */ `
}
}
`
export default customerActivateByUrlMutation

View File

@ -1,4 +1,4 @@
const customerActivateMutation = /* GraphQL */ `
export const customerActivateMutation = /* GraphQL */ `
mutation customerActivate($id: ID!, $input: CustomerActivateInput!) {
customerActivate(id: $id, input: $input) {
customer {
@ -16,4 +16,3 @@ const customerActivateMutation = /* GraphQL */ `
}
}
`
export default customerActivateMutation

View File

@ -1,4 +1,4 @@
const customerCreateMutation = /* GraphQL */ `
export const customerCreateMutation = /* GraphQL */ `
mutation customerCreate($input: CustomerCreateInput!) {
customerCreate(input: $input) {
customerUserErrors {
@ -12,4 +12,3 @@ const customerCreateMutation = /* GraphQL */ `
}
}
`
export default customerCreateMutation

View File

@ -1,9 +1,9 @@
export { default as customerCreateMutation } from './customer-create'
export { default as checkoutCreateMutation } from './checkout-create'
export { default as checkoutLineItemAddMutation } from './checkout-line-item-add'
export { default as checkoutLineItemUpdateMutation } from './checkout-line-item-update'
export { default as checkoutLineItemRemoveMutation } from './checkout-line-item-remove'
export { default as customerAccessTokenCreateMutation } from './customer-access-token-create'
export { default as customerAccessTokenDeleteMutation } from './customer-access-token-delete'
export { default as customerActivateMutation } from './customer-activate'
export { default as customerActivateByUrlMutation } from './customer-activate-by-url'
export { customerCreateMutation } from './customer-create'
export { cartCreateMutation } from './cart-create'
export { cartLinesAddMutation } from './cart-lines-item-add'
export { cartLinesUpdateMutation } from './cart-lines-item-update'
export { cartLinesRemoveMutation } from './cart-lines-item-remove'
export { customerAccessTokenCreateMutation } from './customer-access-token-create'
export { customerAccessTokenDeleteMutation } from './customer-access-token-delete'
export { customerActivateMutation } from './customer-activate'
export { customerActivateByUrlMutation } from './customer-activate-by-url'

View File

@ -5,8 +5,6 @@ import type { Category } from '../types/site'
import {
Product as ShopifyProduct,
Checkout,
CheckoutLineItemEdge,
SelectedOption,
ImageConnection,
ProductVariantConnection,
@ -15,8 +13,10 @@ import {
Page as ShopifyPage,
PageEdge,
Collection,
CartDetailsFragment,
} from '../../schema'
import { colorMap } from './colors'
import { CommerceError } from '@vercel/commerce/utils/errors'
const money = ({ amount, currencyCode }: MoneyV2) => {
return {
@ -53,9 +53,10 @@ const normalizeProductOption = ({
}
const normalizeProductImages = ({ edges }: ImageConnection) =>
edges?.map(({ node: { originalSrc: url, ...rest } }) => ({
url,
edges?.map(({ node: { altText: alt, url, ...rest } }) => ({
...rest,
url,
alt,
}))
const normalizeProductVariants = ({ edges }: ProductVariantConnection) => {
@ -127,52 +128,57 @@ export function normalizeProduct({
...rest,
}
}
export function normalizeCart(checkout: Checkout): Cart {
return {
id: checkout.id,
url: checkout.webUrl,
customerId: '',
email: '',
createdAt: checkout.createdAt,
currency: {
code: checkout.totalPriceV2?.currencyCode,
},
taxesIncluded: checkout.taxesIncluded,
lineItems: checkout.lineItems?.edges.map(normalizeLineItem),
lineItemsSubtotalPrice: +checkout.subtotalPriceV2?.amount,
subtotalPrice: +checkout.subtotalPriceV2?.amount,
totalPrice: checkout.totalPriceV2?.amount,
discounts: [],
}
}
function normalizeLineItem({
node: { id, title, variant, quantity },
}: CheckoutLineItemEdge): LineItem {
node: { id, merchandise: variant, quantity },
}: {
node: any
}): LineItem {
return {
id,
variantId: String(variant?.id),
productId: String(variant?.id),
name: `${title}`,
quantity,
variantId: variant?.id,
productId: variant?.id,
name: variant?.product?.title || variant?.title,
quantity: quantity ?? 0,
variant: {
id: String(variant?.id),
id: variant?.id,
sku: variant?.sku ?? '',
name: variant?.title!,
image: {
url: variant?.image?.originalSrc || '/product-img-placeholder.svg',
url: variant?.image?.url || '/product-img-placeholder.svg',
},
requiresShipping: variant?.requiresShipping ?? false,
price: variant?.priceV2?.amount,
price: +variant?.priceV2?.amount,
listPrice: variant?.compareAtPriceV2?.amount,
},
path: String(variant?.product?.handle),
path: variant?.product?.handle,
discounts: [],
options: variant?.title == 'Default Title' ? [] : variant?.selectedOptions,
}
}
export function normalizeCart(
cart: CartDetailsFragment | undefined | null
): Cart {
if (!cart) {
throw new CommerceError({ message: 'Missing cart details' })
}
return {
id: cart.id,
customerId: cart.buyerIdentity?.customer?.id,
email: cart.buyerIdentity?.email ?? '',
createdAt: cart.createdAt,
currency: {
code: cart.estimatedCost?.totalAmount?.currencyCode,
},
taxesIncluded: !!cart.estimatedCost?.totalTaxAmount?.amount,
lineItems: cart.lines?.edges?.map(normalizeLineItem) ?? [],
lineItemsSubtotalPrice: +cart.estimatedCost?.subtotalAmount?.amount,
subtotalPrice: +cart.estimatedCost?.subtotalAmount?.amount,
totalPrice: +cart.estimatedCost?.totalAmount?.amount,
discounts: [],
}
}
export const normalizePage = (
{ title: name, handle, ...page }: ShopifyPage,
locale: string = 'en-US'

View File

@ -1,4 +1,4 @@
const getSiteCollectionsQuery = /* GraphQL */ `
export const getSiteCollectionsQuery = /* GraphQL */ `
query getSiteCollections($first: Int!) {
collections(first: $first) {
edges {
@ -11,4 +11,3 @@ const getSiteCollectionsQuery = /* GraphQL */ `
}
}
`
export default getSiteCollectionsQuery

View File

@ -11,4 +11,3 @@ export const getAllPagesQuery = /* GraphQL */ `
}
}
`
export default getAllPagesQuery

View File

@ -1,4 +1,4 @@
const getAllProductVendors = /* GraphQL */ `
export const getAllProductVendors = /* GraphQL */ `
query getAllProductVendors($first: Int = 250, $cursor: String) {
products(first: $first, after: $cursor) {
pageInfo {
@ -14,4 +14,3 @@ const getAllProductVendors = /* GraphQL */ `
}
}
`
export default getAllProductVendors

View File

@ -1,4 +1,4 @@
const getAllProductsPathsQuery = /* GraphQL */ `
export const getAllProductsPathsQuery = /* GraphQL */ `
query getAllProductPaths($first: Int = 250, $cursor: String) {
products(first: $first, after: $cursor) {
pageInfo {
@ -14,4 +14,3 @@ const getAllProductsPathsQuery = /* GraphQL */ `
}
}
`
export default getAllProductsPathsQuery

View File

@ -23,7 +23,7 @@ export const productConnectionFragment = /* GraphQL */ `
}
edges {
node {
originalSrc
url
altText
width
height
@ -35,7 +35,7 @@ export const productConnectionFragment = /* GraphQL */ `
}
`
const getAllProductsQuery = /* GraphQL */ `
export const getAllProductsQuery = /* GraphQL */ `
query getAllProducts(
$first: Int = 250
$query: String = ""
@ -54,4 +54,3 @@ const getAllProductsQuery = /* GraphQL */ `
${productConnectionFragment}
`
export default getAllProductsQuery

View File

@ -0,0 +1,83 @@
export const cartDetailsFragment = /* GraphQL */ `
fragment cartDetails on Cart {
id
checkoutUrl
createdAt
updatedAt
lines(first: 10) {
edges {
node {
id
quantity
merchandise {
... on ProductVariant {
id
id
sku
title
selectedOptions {
name
value
}
image {
url
altText
width
height
}
priceV2 {
amount
currencyCode
}
compareAtPriceV2 {
amount
currencyCode
}
product {
title
handle
}
}
}
}
}
}
attributes {
key
value
}
buyerIdentity {
email
customer {
id
}
}
estimatedCost {
totalAmount {
amount
currencyCode
}
subtotalAmount {
amount
currencyCode
}
totalTaxAmount {
amount
currencyCode
}
totalDutyAmount {
amount
currencyCode
}
}
}
`
export const getCartQuery = /* GraphQL */ `
query getCart($cartId: ID!) {
cart(id: $cartId) {
...cartDetails
}
}
${cartDetailsFragment}
`

View File

@ -35,7 +35,7 @@ export const checkoutDetailsFragment = /* GraphQL */ `
value
}
image {
originalSrc
url
altText
width
height
@ -59,7 +59,7 @@ export const checkoutDetailsFragment = /* GraphQL */ `
}
`
const getCheckoutQuery = /* GraphQL */ `
export const getCheckoutQuery = /* GraphQL */ `
query getCheckout($checkoutId: ID!) {
node(id: $checkoutId) {
...checkoutDetails
@ -67,4 +67,3 @@ const getCheckoutQuery = /* GraphQL */ `
}
${checkoutDetailsFragment}
`
export default getCheckoutQuery

View File

@ -1,6 +1,6 @@
import { productConnectionFragment } from './get-all-products-query'
const getCollectionProductsQuery = /* GraphQL */ `
export const getCollectionProductsQuery = /* GraphQL */ `
query getProductsFromCollection(
$categoryId: ID!
$first: Int = 250
@ -18,4 +18,3 @@ const getCollectionProductsQuery = /* GraphQL */ `
}
${productConnectionFragment}
`
export default getCollectionProductsQuery

View File

@ -5,4 +5,3 @@ export const getCustomerQuery = /* GraphQL */ `
}
}
`
export default getCustomerQuery

View File

@ -13,4 +13,3 @@ export const getCustomerQuery = /* GraphQL */ `
}
}
`
export default getCustomerQuery

View File

@ -11,4 +11,3 @@ export const getPageQuery = /* GraphQL */ `
}
}
`
export default getPageQuery

View File

@ -1,4 +1,4 @@
const getProductQuery = /* GraphQL */ `
export const getProductQuery = /* GraphQL */ `
query getProductBySlug($slug: String!) {
productByHandle(handle: $slug) {
id
@ -58,7 +58,7 @@ const getProductQuery = /* GraphQL */ `
}
edges {
node {
originalSrc
url
altText
width
height
@ -68,5 +68,3 @@ const getProductQuery = /* GraphQL */ `
}
}
`
export default getProductQuery

View File

@ -1,8 +1,7 @@
const getSiteInfoQuery = /* GraphQL */ `
export const getSiteInfoQuery = /* GraphQL */ `
query getSiteInfo {
shop {
name
}
}
`
export default getSiteInfoQuery

View File

@ -1,11 +1,11 @@
export { default as getSiteCollectionsQuery } from './get-all-collections-query'
export { default as getProductQuery } from './get-product-query'
export { default as getAllProductsQuery } from './get-all-products-query'
export { default as getAllProductsPathtsQuery } from './get-all-products-paths-query'
export { default as getAllProductVendors } from './get-all-product-vendors-query'
export { default as getCollectionProductsQuery } from './get-collection-products-query'
export { default as getCheckoutQuery } from './get-checkout-query'
export { default as getAllPagesQuery } from './get-all-pages-query'
export { default as getPageQuery } from './get-page-query'
export { default as getCustomerQuery } from './get-customer-query'
export { default as getSiteInfoQuery } from './get-site-info-query'
export { getSiteCollectionsQuery } from './get-all-collections-query'
export { getProductQuery } from './get-product-query'
export { getAllProductsQuery } from './get-all-products-query'
export { getAllProductsPathsQuery } from './get-all-products-paths-query'
export { getAllProductVendors } from './get-all-product-vendors-query'
export { getCollectionProductsQuery } from './get-collection-products-query'
export { getAllPagesQuery } from './get-all-pages-query'
export { getPageQuery } from './get-page-query'
export { getCustomerQuery } from './get-customer-query'
export { getSiteInfoQuery } from './get-site-info-query'
export { getCartQuery } from './get-cart-query'

View File

@ -0,0 +1,14 @@
import Cookies from 'js-cookie'
import { SHOPIFY_CART_URL_COOKIE, SHOPIFY_COOKIE_EXPIRE } from '../const'
export const setCartUrlCookie = (cartUrl: string) => {
if (cartUrl) {
const oldCookie = Cookies.get(SHOPIFY_CART_URL_COOKIE)
if (oldCookie !== cartUrl) {
Cookies.set(SHOPIFY_CART_URL_COOKIE, cartUrl, {
expires: SHOPIFY_COOKIE_EXPIRE,
})
}
}
}

View File

@ -5,13 +5,18 @@ import {
CheckoutUserError,
CustomerErrorCode,
CustomerUserError,
CartUserError,
CartErrorCode,
} from '../../schema'
export type UserErrors = Array<CheckoutUserError | CustomerUserError>
export type UserErrors = Array<
CheckoutUserError | CustomerUserError | CartUserError
>
export type UserErrorCode =
| CustomerErrorCode
| CheckoutErrorCode
| CartErrorCode
| null
| undefined
@ -34,5 +39,3 @@ export const throwUserErrors = (errors?: UserErrors) => {
})
}
}
export default throwUserErrors

View File

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

2079
yarn.lock

File diff suppressed because it is too large Load Diff