mirror of
https://github.com/vercel/commerce.git
synced 2025-06-18 21:21:21 +00:00
Implement useCart/useAddItem
This commit is contained in:
parent
2d2861b944
commit
0f7c151805
@ -1,4 +1,3 @@
|
|||||||
import type { GetLoggedInCustomerQuery } from '../../../schema'
|
|
||||||
import type { CustomersHandlers } from '..'
|
import type { CustomersHandlers } from '..'
|
||||||
|
|
||||||
export const getLoggedInCustomerQuery = /* GraphQL */ `
|
export const getLoggedInCustomerQuery = /* GraphQL */ `
|
||||||
@ -22,7 +21,7 @@ export const getLoggedInCustomerQuery = /* GraphQL */ `
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export type Customer = NonNullable<GetLoggedInCustomerQuery['customer']>
|
export type Customer = NonNullable<any>
|
||||||
|
|
||||||
const getLoggedInCustomer: CustomersHandlers['getLoggedInCustomer'] = async ({
|
const getLoggedInCustomer: CustomersHandlers['getLoggedInCustomer'] = async ({
|
||||||
req,
|
req,
|
||||||
|
@ -9,7 +9,7 @@ const API_URL = process.env.VENDURE_SHOP_API_URL
|
|||||||
|
|
||||||
if (!API_URL) {
|
if (!API_URL) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`The environment variable BIGCOMMERCE_STOREFRONT_API_URL is missing and it's required to access your store`
|
`The environment variable VENDURE_SHOP_API_URL is missing and it's required to access your store`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,25 +1,43 @@
|
|||||||
import { useCallback } from 'react'
|
|
||||||
import type { HookFetcher } from '@commerce/utils/types'
|
|
||||||
import { CommerceError } from '@commerce/utils/errors'
|
import { CommerceError } from '@commerce/utils/errors'
|
||||||
|
import { HookFetcher } from '@commerce/utils/types'
|
||||||
|
import fetchGraphqlApi from '@framework/api/utils/fetch-graphql-api'
|
||||||
import useCartAddItem from '@commerce/cart/use-add-item'
|
import useCartAddItem from '@commerce/cart/use-add-item'
|
||||||
import type { ItemBody, AddItemBody } from '../api/cart'
|
import useCart from './use-cart'
|
||||||
import useCart, { Cart } from './use-cart'
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
const defaultOpts = {
|
export const addItemToOrderMutation = /* GraphQL */ `
|
||||||
url: '/api/bigcommerce/cart',
|
mutation addItemToOrder($variantId: ID!, $quantity: Int!) {
|
||||||
method: 'POST',
|
addItemToOrder(productVariantId: $variantId, quantity: $quantity) {
|
||||||
}
|
... on Order {
|
||||||
|
id
|
||||||
|
code
|
||||||
|
totalQuantity
|
||||||
|
total
|
||||||
|
totalWithTax
|
||||||
|
lines {
|
||||||
|
id
|
||||||
|
productVariant {
|
||||||
|
featuredAsset {
|
||||||
|
id
|
||||||
|
preview
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
export type AddItemInput = ItemBody
|
export type AddItemInput = { productId?: number; variantId: number; quantity?: number; };
|
||||||
|
|
||||||
export const fetcher: HookFetcher<Cart, AddItemBody> = (
|
export const fetcher: HookFetcher<Cart, AddItemInput> = (
|
||||||
options,
|
options,
|
||||||
{ item },
|
{ variantId, quantity },
|
||||||
fetch
|
fetch
|
||||||
) => {
|
) => {
|
||||||
if (
|
if (
|
||||||
item.quantity &&
|
quantity &&
|
||||||
(!Number.isInteger(item.quantity) || item.quantity! < 1)
|
(!Number.isInteger(quantity) || quantity! < 1)
|
||||||
) {
|
) {
|
||||||
throw new CommerceError({
|
throw new CommerceError({
|
||||||
message: 'The item quantity has to be a valid integer greater than 0',
|
message: 'The item quantity has to be a valid integer greater than 0',
|
||||||
@ -27,20 +45,23 @@ export const fetcher: HookFetcher<Cart, AddItemBody> = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
return fetch({
|
return fetch({
|
||||||
...defaultOpts,
|
|
||||||
...options,
|
...options,
|
||||||
body: { item },
|
query: addItemToOrderMutation,
|
||||||
|
variables: { variantId, quantity: quantity || 1 },
|
||||||
|
}).then(res => {
|
||||||
|
console.log({ res });
|
||||||
|
return res;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extendHook(customFetcher: typeof fetcher) {
|
export function extendHook(customFetcher: typeof fetcher) {
|
||||||
const useAddItem = () => {
|
const useAddItem = () => {
|
||||||
const { mutate } = useCart()
|
const { mutate } = useCart()
|
||||||
const fn = useCartAddItem(defaultOpts, customFetcher)
|
const fn = useCartAddItem({}, customFetcher)
|
||||||
|
|
||||||
return useCallback(
|
return useCallback(
|
||||||
async function addItem(input: AddItemInput) {
|
async function addItem(input: AddItemInput) {
|
||||||
const data = await fn({ item: input })
|
const data = await fn({ quantity: input.quantity, variantId: input.variantId })
|
||||||
await mutate(data, false)
|
await mutate(data, false)
|
||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
|
@ -1,46 +1,83 @@
|
|||||||
import { normalizeCart } from '../lib/normalize'
|
import fetchGraphqlApi from '@framework/api/utils/fetch-graphql-api'
|
||||||
import type { HookFetcher } from '@commerce/utils/types'
|
import { HookFetcher } from '@commerce/utils/types'
|
||||||
import type { SwrOptions } from '@commerce/utils/use-data'
|
import useData, { SwrOptions } from '@commerce/utils/use-data'
|
||||||
import useResponse from '@commerce/utils/use-response'
|
|
||||||
import useCommerceCart, { CartInput } from '@commerce/cart/use-cart'
|
import useCommerceCart, { CartInput } from '@commerce/cart/use-cart'
|
||||||
import type { Cart as BigCommerceCart } from '../api/cart'
|
import useResponse from '@commerce/utils/use-response'
|
||||||
|
import useAction from '@commerce/utils/use-action'
|
||||||
|
import { useCallback } from 'react'
|
||||||
|
import { normalizeCart } from '../../bigcommerce/lib/normalize'
|
||||||
|
|
||||||
const defaultOpts = {
|
export const getCartQuery = /* GraphQL */ `
|
||||||
url: '/api/bigcommerce/cart',
|
query activeOrder {
|
||||||
method: 'GET',
|
activeOrder {
|
||||||
}
|
id
|
||||||
|
code
|
||||||
|
totalQuantity
|
||||||
|
subTotal
|
||||||
|
subTotalWithTax
|
||||||
|
total
|
||||||
|
totalWithTax
|
||||||
|
currencyCode
|
||||||
|
lines {
|
||||||
|
id
|
||||||
|
quantity
|
||||||
|
featuredAsset {
|
||||||
|
id
|
||||||
|
preview
|
||||||
|
}
|
||||||
|
productVariant {
|
||||||
|
name
|
||||||
|
product {
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
productId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
type UseCartResponse = BigCommerceCart & Cart
|
export const fetcher: HookFetcher<any | null> = (
|
||||||
|
|
||||||
export const fetcher: HookFetcher<UseCartResponse | null, CartInput> = (
|
|
||||||
options,
|
options,
|
||||||
{ cartId },
|
input,
|
||||||
fetch
|
fetch
|
||||||
) => {
|
) => {
|
||||||
return cartId ? fetch({ ...defaultOpts, ...options }) : null
|
return fetch({ ...options, query: getCartQuery })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extendHook(
|
export function extendHook(
|
||||||
customFetcher: typeof fetcher,
|
customFetcher: typeof fetcher,
|
||||||
swrOptions?: SwrOptions<UseCartResponse | null, CartInput>
|
swrOptions?: SwrOptions<any | null>
|
||||||
) {
|
) {
|
||||||
const useCart = () => {
|
const useCart = () => {
|
||||||
const response = useCommerceCart(defaultOpts, [], customFetcher, {
|
const response = useData({}, [], customFetcher, swrOptions)
|
||||||
revalidateOnFocus: false,
|
|
||||||
...swrOptions,
|
|
||||||
})
|
|
||||||
const res = useResponse(response, {
|
const res = useResponse(response, {
|
||||||
normalizer: normalizeCart,
|
normalizer: (data => {
|
||||||
|
const order = data?.activeOrder;
|
||||||
|
console.log({ order });
|
||||||
|
return (order ? {
|
||||||
|
id: order.id,
|
||||||
|
currency: { code: order.currencyCode },
|
||||||
|
subTotal: order.subTotalWithTax / 100,
|
||||||
|
total: order.totalWithTax / 100,
|
||||||
|
items: order.lines?.map(l => ({
|
||||||
|
name: l.productVariant.name,
|
||||||
|
quantity: l.quantity,
|
||||||
|
url: l.productVariant.product.slug,
|
||||||
|
variantId: l.productVariant.id,
|
||||||
|
productId: l.productVariant.productId,
|
||||||
|
images: [{ url: l.featuredAsset?.preview }]
|
||||||
|
}))
|
||||||
|
} : null)
|
||||||
|
}),
|
||||||
descriptors: {
|
descriptors: {
|
||||||
isEmpty: {
|
isEmpty: {
|
||||||
get() {
|
get() {
|
||||||
return Object.values(response.data?.line_items ?? {}).every(
|
return response.data?.activeOrder?.totalQuantity === 0
|
||||||
(items) => !items.length
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
enumerable: true,
|
enumerable: true
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
@ -15,8 +15,9 @@ export const fetcher: HookFetcher<Customer | null> = async (
|
|||||||
_,
|
_,
|
||||||
fetch
|
fetch
|
||||||
) => {
|
) => {
|
||||||
const data = await fetch<CustomerData | null>({ ...defaultOpts, ...options })
|
// const data = await fetch<CustomerData | null>({ ...defaultOpts, ...options })
|
||||||
return data?.customer ?? null
|
// return data?.customer ?? null
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extendHook(
|
export function extendHook(
|
||||||
|
@ -26,13 +26,13 @@ async function getError(res: Response) {
|
|||||||
export const vendureConfig: CommerceConfig = {
|
export const vendureConfig: CommerceConfig = {
|
||||||
locale: 'en-us',
|
locale: 'en-us',
|
||||||
cartCookie: 'bc_cartId',
|
cartCookie: 'bc_cartId',
|
||||||
async fetcher({ url, method = 'GET', variables, body: bodyObj }) {
|
async fetcher({ url, method = 'POST', variables, query, body: bodyObj }) {
|
||||||
const hasBody = Boolean(variables || bodyObj)
|
const hasBody = Boolean(variables || query)
|
||||||
const body = hasBody
|
const body = hasBody
|
||||||
? JSON.stringify(variables ? { variables } : bodyObj)
|
? JSON.stringify({ query, variables })
|
||||||
: undefined
|
: undefined
|
||||||
const headers = hasBody ? { 'Content-Type': 'application/json' } : undefined
|
const headers = hasBody ? { 'Content-Type': 'application/json' } : undefined
|
||||||
const res = await fetch(url!, { method, body, headers })
|
const res = await fetch('http://localhost:3001/shop-api'!, { method, body, headers, credentials: 'include' })
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const { data } = await res.json()
|
const { data } = await res.json()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user