forked from crowetic/commerce
Login, Sign Up, Log Out, and checkout & customer association
This commit is contained in:
parent
612392aaba
commit
dde09c5105
@ -3,16 +3,35 @@ import createApiHandler, {
|
|||||||
ShopifyApiHandler,
|
ShopifyApiHandler,
|
||||||
} from '../utils/create-api-handler'
|
} from '../utils/create-api-handler'
|
||||||
|
|
||||||
import { SHOPIFY_CHECKOUT_URL_COOKIE } from '@framework/const'
|
import {
|
||||||
|
SHOPIFY_CHECKOUT_ID_COOKIE,
|
||||||
|
SHOPIFY_CHECKOUT_URL_COOKIE,
|
||||||
|
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
|
||||||
|
} from '@framework/const'
|
||||||
|
import { getConfig } from '..'
|
||||||
|
import associateCustomerWithCheckoutMutation from '@framework/utils/mutations/associate-customer-with-checkout'
|
||||||
|
|
||||||
const METHODS = ['GET']
|
const METHODS = ['GET']
|
||||||
|
|
||||||
const checkoutApi: ShopifyApiHandler<any> = async (req, res) => {
|
const checkoutApi: ShopifyApiHandler<any> = async (req, res, config) => {
|
||||||
if (!isAllowedMethod(req, res, METHODS)) return
|
if (!isAllowedMethod(req, res, METHODS)) return
|
||||||
|
|
||||||
|
config = getConfig()
|
||||||
|
|
||||||
const { cookies } = req
|
const { cookies } = req
|
||||||
const checkoutUrl = cookies[SHOPIFY_CHECKOUT_URL_COOKIE]
|
const checkoutUrl = cookies[SHOPIFY_CHECKOUT_URL_COOKIE]
|
||||||
|
|
||||||
|
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) {
|
if (checkoutUrl) {
|
||||||
res.redirect(checkoutUrl)
|
res.redirect(checkoutUrl)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import type { CommerceAPIConfig } from '@commerce/api'
|
import type { CommerceAPIConfig } from '@commerce/api'
|
||||||
import { SHOPIFY_CHECKOUT_ID_COOKIE } from '@framework/const'
|
import {
|
||||||
|
SHOPIFY_CHECKOUT_ID_COOKIE,
|
||||||
|
SHOPIFY_CUSTOMER_TOKEN_COOKIE,
|
||||||
|
} from '@framework/const'
|
||||||
import fetchGraphqlApi from '../utils/fetch-graphql-api'
|
import fetchGraphqlApi from '../utils/fetch-graphql-api'
|
||||||
|
|
||||||
export interface ShopifyConfig extends CommerceAPIConfig {}
|
export interface ShopifyConfig extends CommerceAPIConfig {}
|
||||||
@ -46,7 +49,7 @@ const config = new Config({
|
|||||||
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
|
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
|
||||||
cartCookieMaxAge: ONE_DAY * 30,
|
cartCookieMaxAge: ONE_DAY * 30,
|
||||||
fetch: fetchGraphqlApi,
|
fetch: fetchGraphqlApi,
|
||||||
customerCookie: 'SHOP_TOKEN',
|
customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE,
|
||||||
})
|
})
|
||||||
|
|
||||||
export function getConfig(userConfig?: Partial<ShopifyConfig>) {
|
export function getConfig(userConfig?: Partial<ShopifyConfig>) {
|
||||||
|
@ -1,21 +1,37 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import type { HookFetcher } from '@commerce/utils/types'
|
import type { HookFetcher } from '@commerce/utils/types'
|
||||||
import { CommerceError } from '@commerce/utils/errors'
|
import { CommerceError, ValidationError } from '@commerce/utils/errors'
|
||||||
import useCommerceLogin from '@commerce/use-login'
|
import useCommerceLogin from '@commerce/use-login'
|
||||||
import useCustomer from '../customer/use-customer'
|
import useCustomer from '../customer/use-customer'
|
||||||
import createCustomerAccessTokenMutation from '../utils/mutations/customer-acces-token-create'
|
import createCustomerAccessTokenMutation from '../utils/mutations/customer-access-token-create'
|
||||||
import { CustomerAccessTokenCreateInput } from '@framework/schema'
|
import { CustomerAccessTokenCreateInput } from '@framework/schema'
|
||||||
|
import { setCustomerToken } from '@framework/utils/customer-token'
|
||||||
|
|
||||||
const defaultOpts = {
|
const defaultOpts = {
|
||||||
query: createCustomerAccessTokenMutation,
|
query: createCustomerAccessTokenMutation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
export const fetcher: HookFetcher<null, CustomerAccessTokenCreateInput> = (
|
export const fetcher: HookFetcher<null, CustomerAccessTokenCreateInput> = (
|
||||||
options,
|
options,
|
||||||
{ email, password },
|
input,
|
||||||
fetch
|
fetch
|
||||||
) => {
|
) => {
|
||||||
if (!(email && password)) {
|
if (!(input.email && input.password)) {
|
||||||
throw new CommerceError({
|
throw new CommerceError({
|
||||||
message:
|
message:
|
||||||
'A first name, last name, email and password are required to login',
|
'A first name, last name, email and password are required to login',
|
||||||
@ -25,7 +41,25 @@ export const fetcher: HookFetcher<null, CustomerAccessTokenCreateInput> = (
|
|||||||
return fetch({
|
return fetch({
|
||||||
...defaultOpts,
|
...defaultOpts,
|
||||||
...options,
|
...options,
|
||||||
body: { email, password },
|
variables: { input },
|
||||||
|
}).then((data) => {
|
||||||
|
const response = data?.customerAccessTokenCreate
|
||||||
|
const errors = response?.customerUserErrors
|
||||||
|
|
||||||
|
if (errors && errors.length) {
|
||||||
|
throw new ValidationError({
|
||||||
|
message: getErrorMessage(errors[0]),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const customerAccessToken = response?.customerAccessToken
|
||||||
|
const accessToken = customerAccessToken?.accessToken
|
||||||
|
|
||||||
|
if (accessToken) {
|
||||||
|
setCustomerToken(accessToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
return customerAccessToken
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,45 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
|
import type { HookFetcher } from '@commerce/utils/types'
|
||||||
|
import useCommerceLogout from '@commerce/use-logout'
|
||||||
|
import useCustomer from '../customer/use-customer'
|
||||||
|
import customerAccessTokenDeleteMutation from '@framework/utils/mutations/customer-access-token-delete'
|
||||||
|
import {
|
||||||
|
getCustomerToken,
|
||||||
|
setCustomerToken,
|
||||||
|
} from '@framework/utils/customer-token'
|
||||||
|
|
||||||
export function emptyHook() {
|
const defaultOpts = {
|
||||||
const useEmptyHook = async (options = {}) => {
|
query: customerAccessTokenDeleteMutation,
|
||||||
return useCallback(async function () {
|
|
||||||
return Promise.resolve()
|
|
||||||
}, [])
|
|
||||||
}
|
|
||||||
|
|
||||||
return useEmptyHook
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default emptyHook
|
export const fetcher: HookFetcher<null> = (options, _, fetch) => {
|
||||||
|
return fetch({
|
||||||
|
...defaultOpts,
|
||||||
|
...options,
|
||||||
|
variables: {
|
||||||
|
customerAccessToken: getCustomerToken(),
|
||||||
|
},
|
||||||
|
}).then((d) => setCustomerToken(null))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extendHook(customFetcher: typeof fetcher) {
|
||||||
|
const useLogout = () => {
|
||||||
|
const { mutate } = useCustomer()
|
||||||
|
const fn = useCommerceLogout<null>(defaultOpts, customFetcher)
|
||||||
|
|
||||||
|
return useCallback(
|
||||||
|
async function login() {
|
||||||
|
const data = await fn(null)
|
||||||
|
await mutate(null, false)
|
||||||
|
return data
|
||||||
|
},
|
||||||
|
[fn]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
useLogout.extend = extendHook
|
||||||
|
|
||||||
|
return useLogout
|
||||||
|
}
|
||||||
|
|
||||||
|
export default extendHook(fetcher)
|
||||||
|
@ -1,13 +1,57 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
|
import type { HookFetcher } from '@commerce/utils/types'
|
||||||
|
import { CommerceError } from '@commerce/utils/errors'
|
||||||
|
import useCommerceSignup from '@commerce/use-signup'
|
||||||
|
import useCustomer from '../customer/use-customer'
|
||||||
|
import customerCreateMutation from '@framework/utils/mutations/customer-create'
|
||||||
|
import { CustomerCreateInput } from '@framework/schema'
|
||||||
|
|
||||||
export function emptyHook() {
|
const defaultOpts = {
|
||||||
const useEmptyHook = async (options = {}) => {
|
query: customerCreateMutation,
|
||||||
return useCallback(async function () {
|
|
||||||
return Promise.resolve()
|
|
||||||
}, [])
|
|
||||||
}
|
|
||||||
|
|
||||||
return useEmptyHook
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default emptyHook
|
export const fetcher: HookFetcher<null, CustomerCreateInput> = (
|
||||||
|
options,
|
||||||
|
input,
|
||||||
|
fetch
|
||||||
|
) => {
|
||||||
|
if (!(input.firstName && input.lastName && input.email && input.password)) {
|
||||||
|
throw new CommerceError({
|
||||||
|
message:
|
||||||
|
'A first name, last name, email and password are required to signup',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch({
|
||||||
|
...defaultOpts,
|
||||||
|
...options,
|
||||||
|
variables: { input },
|
||||||
|
}).then((data) => {
|
||||||
|
return data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extendHook(customFetcher: typeof fetcher) {
|
||||||
|
const useSignup = () => {
|
||||||
|
const { revalidate } = useCustomer()
|
||||||
|
const fn = useCommerceSignup<null, CustomerCreateInput>(
|
||||||
|
defaultOpts,
|
||||||
|
customFetcher
|
||||||
|
)
|
||||||
|
|
||||||
|
return useCallback(
|
||||||
|
async function signup(input: CustomerCreateInput) {
|
||||||
|
const data = await fn(input)
|
||||||
|
await revalidate()
|
||||||
|
return data
|
||||||
|
},
|
||||||
|
[fn]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
useSignup.extend = extendHook
|
||||||
|
|
||||||
|
return useSignup
|
||||||
|
}
|
||||||
|
|
||||||
|
export default extendHook(fetcher)
|
||||||
|
@ -32,7 +32,7 @@ const shopifyConfig: ShopifyConfig = {
|
|||||||
locale: 'en-us',
|
locale: 'en-us',
|
||||||
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
|
cartCookie: SHOPIFY_CHECKOUT_ID_COOKIE,
|
||||||
storeDomain: STORE_DOMAIN,
|
storeDomain: STORE_DOMAIN,
|
||||||
async fetcher({ method = 'POST', variables, query }) {
|
async fetcher({ method = 'POST', query, variables }) {
|
||||||
const res = await fetch(API_URL, {
|
const res = await fetch(API_URL, {
|
||||||
method,
|
method,
|
||||||
body: JSON.stringify({ query, variables }),
|
body: JSON.stringify({ query, variables }),
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
export const SHOPIFY_CHECKOUT_ID_COOKIE = 'shopify_checkoutId'
|
export const SHOPIFY_CHECKOUT_ID_COOKIE = 'shopify_checkoutId'
|
||||||
export const SHOPIFY_CHECKOUT_URL_COOKIE = 'shopify_checkoutUrl'
|
export const SHOPIFY_CHECKOUT_URL_COOKIE = 'shopify_checkoutUrl'
|
||||||
|
export const SHOPIFY_CUSTOMER_TOKEN_COOKIE = 'shopify_customerToken'
|
||||||
|
24
framework/shopify/customer/get-customer-id.ts
Normal file
24
framework/shopify/customer/get-customer-id.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { getConfig, ShopifyConfig } from '@framework/api'
|
||||||
|
import getCustomerIdQuery from '@framework/utils/queries/get-customer-id-query'
|
||||||
|
import Cookies from 'js-cookie'
|
||||||
|
|
||||||
|
async function getCustomerId({
|
||||||
|
customerToken: customerAccesToken,
|
||||||
|
config,
|
||||||
|
}: {
|
||||||
|
customerToken: string
|
||||||
|
config?: ShopifyConfig
|
||||||
|
}): Promise<number | undefined> {
|
||||||
|
config = getConfig(config)
|
||||||
|
|
||||||
|
const { data } = await config.fetch(getCustomerIdQuery, {
|
||||||
|
variables: {
|
||||||
|
customerAccesToken:
|
||||||
|
customerAccesToken || Cookies.get(config.customerCookie),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return data?.customer?.id
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getCustomerId
|
@ -1,23 +1,29 @@
|
|||||||
import type { HookFetcher } from '@commerce/utils/types'
|
import type { HookFetcher } from '@commerce/utils/types'
|
||||||
import type { SwrOptions } from '@commerce/utils/use-data'
|
import type { SwrOptions } from '@commerce/utils/use-data'
|
||||||
import useCommerceCustomer from '@commerce/use-customer'
|
import useCommerceCustomer from '@commerce/use-customer'
|
||||||
|
import getCustomerQuery from '@framework/utils/queries/get-customer-query'
|
||||||
|
import { getCustomerToken } from '@framework/utils/customer-token'
|
||||||
|
|
||||||
const defaultOpts = {
|
const defaultOpts = {
|
||||||
query: '/api/bigcommerce/customers',
|
query: getCustomerQuery,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetcher: HookFetcher<Customer | null> = async (
|
export const fetcher: HookFetcher<any | null> = async (options, _, fetch) => {
|
||||||
options,
|
const customerAccessToken = getCustomerToken()
|
||||||
_,
|
if (customerAccessToken) {
|
||||||
fetch
|
const data = await fetch<any | null>({
|
||||||
) => {
|
...defaultOpts,
|
||||||
const data = await fetch<CustomerData | null>({ ...defaultOpts, ...options })
|
...options,
|
||||||
return data?.customer ?? null
|
variables: { customerAccessToken },
|
||||||
|
})
|
||||||
|
return data?.customer ?? null
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extendHook(
|
export function extendHook(
|
||||||
customFetcher: typeof fetcher,
|
customFetcher: typeof fetcher,
|
||||||
swrOptions?: SwrOptions<Customer | null>
|
swrOptions?: SwrOptions<any | null>
|
||||||
) {
|
) {
|
||||||
const useCustomer = () => {
|
const useCustomer = () => {
|
||||||
return useCommerceCustomer(defaultOpts, [], customFetcher, {
|
return useCommerceCustomer(defaultOpts, [], customFetcher, {
|
||||||
|
@ -111,7 +111,7 @@ function normalizeLineItem({
|
|||||||
variant: {
|
variant: {
|
||||||
id: String(variant?.id),
|
id: String(variant?.id),
|
||||||
sku: variant?.sku ?? '',
|
sku: variant?.sku ?? '',
|
||||||
name: variant?.title,
|
name: variant?.title!,
|
||||||
image: {
|
image: {
|
||||||
url: variant?.image?.originalSrc,
|
url: variant?.image?.originalSrc,
|
||||||
},
|
},
|
||||||
|
@ -11,7 +11,7 @@ const getAllCollections = async (options?: {
|
|||||||
config = getConfig(config)
|
config = getConfig(config)
|
||||||
|
|
||||||
const { data } = await config.fetch(getAllCollectionsQuery, { variables })
|
const { data } = await config.fetch(getAllCollectionsQuery, { variables })
|
||||||
const edges = data.collections?.edges ?? []
|
const edges = data?.collections?.edges ?? []
|
||||||
|
|
||||||
const categories = edges.map(
|
const categories = edges.map(
|
||||||
({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({
|
({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({
|
||||||
|
@ -18,12 +18,12 @@ const getAllProductPaths = async (options?: {
|
|||||||
variables,
|
variables,
|
||||||
})
|
})
|
||||||
|
|
||||||
const edges = data.products?.edges
|
const edges = data?.products?.edges
|
||||||
const productInfo = data.products?.productInfo
|
const productInfo = data?.products?.productInfo
|
||||||
const hasNextPage = productInfo?.hasNextPage
|
const hasNextPage = productInfo?.hasNextPage
|
||||||
|
|
||||||
return {
|
return {
|
||||||
products: edges.map(({ node: { handle } }: ProductEdge) => ({
|
products: edges?.map(({ node: { handle } }: ProductEdge) => ({
|
||||||
node: {
|
node: {
|
||||||
path: `/${handle}`,
|
path: `/${handle}`,
|
||||||
},
|
},
|
||||||
|
@ -61,7 +61,6 @@ export function extendHook(
|
|||||||
const response = useCommerceSearch(
|
const response = useCommerceSearch(
|
||||||
{
|
{
|
||||||
query: getAllProductsQuery,
|
query: getAllProductsQuery,
|
||||||
method: 'POST',
|
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
['search', input.search],
|
['search', input.search],
|
||||||
|
12
framework/shopify/utils/customer-token.ts
Normal file
12
framework/shopify/utils/customer-token.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import Cookies from 'js-cookie'
|
||||||
|
import { SHOPIFY_CUSTOMER_TOKEN_COOKIE } from '@framework/const'
|
||||||
|
|
||||||
|
export const getCustomerToken = () => Cookies.get(SHOPIFY_CUSTOMER_TOKEN_COOKIE)
|
||||||
|
|
||||||
|
export const setCustomerToken = (token: string | null, options?: any) => {
|
||||||
|
if (!token) {
|
||||||
|
Cookies.remove(SHOPIFY_CUSTOMER_TOKEN_COOKIE)
|
||||||
|
} else {
|
||||||
|
Cookies.set(SHOPIFY_CUSTOMER_TOKEN_COOKIE, token, options)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
const associateCustomerWithCheckoutMutation = /* GraphQl */ `
|
||||||
|
mutation associateCustomerWithCheckout($checkoutId: ID!, $customerAccessToken: String!) {
|
||||||
|
checkoutCustomerAssociateV2(checkoutId: $checkoutId, customerAccessToken: $customerAccessToken) {
|
||||||
|
checkout {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
checkoutUserErrors {
|
||||||
|
code
|
||||||
|
field
|
||||||
|
message
|
||||||
|
}
|
||||||
|
customer {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
export default associateCustomerWithCheckoutMutation
|
@ -0,0 +1,14 @@
|
|||||||
|
const customerAccessTokenDeleteMutation = /* GraphQL */ `
|
||||||
|
mutation customerAccessTokenDelete($customerAccessToken: String!) {
|
||||||
|
customerAccessTokenDelete(customerAccessToken: $customerAccessToken) {
|
||||||
|
deletedAccessToken
|
||||||
|
deletedCustomerAccessTokenId
|
||||||
|
userErrors {
|
||||||
|
field
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default customerAccessTokenDeleteMutation
|
@ -3,3 +3,5 @@ export { default as checkoutCreateMutation } from './checkout-create'
|
|||||||
export { default as checkoutLineItemAddMutation } from './checkout-line-item-add'
|
export { default as checkoutLineItemAddMutation } from './checkout-line-item-add'
|
||||||
export { default as checkoutLineItemUpdateMutation } from './checkout-create'
|
export { default as checkoutLineItemUpdateMutation } from './checkout-create'
|
||||||
export { default as checkoutLineItemRemoveMutation } from './checkout-line-item-remove'
|
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'
|
||||||
|
8
framework/shopify/utils/queries/get-customer-id-query.ts
Normal file
8
framework/shopify/utils/queries/get-customer-id-query.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export const getCustomerQuery = /* GraphQL */ `
|
||||||
|
query getCustomerId($customerAccessToken: String!) {
|
||||||
|
customer(customerAccessToken: $customerAccessToken) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
export default getCustomerQuery
|
16
framework/shopify/utils/queries/get-customer-query.ts
Normal file
16
framework/shopify/utils/queries/get-customer-query.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export const getCustomerQuery = /* GraphQL */ `
|
||||||
|
query getCustomer($customerAccessToken: String!) {
|
||||||
|
customer(customerAccessToken: $customerAccessToken) {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
displayName
|
||||||
|
email
|
||||||
|
phone
|
||||||
|
tags
|
||||||
|
acceptsMarketing
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
export default getCustomerQuery
|
@ -4,3 +4,4 @@ export { default as getAllProductsQuery } from './get-all-products-query'
|
|||||||
export { default as getAllProductsPathtsQuery } from './get-all-products-paths-query'
|
export { default as getAllProductsPathtsQuery } from './get-all-products-paths-query'
|
||||||
export { default as getCheckoutQuery } from './get-checkout-query'
|
export { default as getCheckoutQuery } from './get-checkout-query'
|
||||||
export { default as getAllPagesQuery } from './get-all-pages-query'
|
export { default as getAllPagesQuery } from './get-all-pages-query'
|
||||||
|
export { default as getCustomerQuery } from './get-checkout-query'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user