mirror of
https://github.com/vercel/commerce.git
synced 2025-06-18 13:11:23 +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 '..'
|
||||
|
||||
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 ({
|
||||
req,
|
||||
|
@ -9,7 +9,7 @@ const API_URL = process.env.VENDURE_SHOP_API_URL
|
||||
|
||||
if (!API_URL) {
|
||||
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 { HookFetcher } from '@commerce/utils/types'
|
||||
import fetchGraphqlApi from '@framework/api/utils/fetch-graphql-api'
|
||||
import useCartAddItem from '@commerce/cart/use-add-item'
|
||||
import type { ItemBody, AddItemBody } from '../api/cart'
|
||||
import useCart, { Cart } from './use-cart'
|
||||
import useCart from './use-cart'
|
||||
import { useCallback } from 'react'
|
||||
|
||||
const defaultOpts = {
|
||||
url: '/api/bigcommerce/cart',
|
||||
method: 'POST',
|
||||
}
|
||||
export const addItemToOrderMutation = /* GraphQL */ `
|
||||
mutation addItemToOrder($variantId: ID!, $quantity: Int!) {
|
||||
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,
|
||||
{ item },
|
||||
{ variantId, quantity },
|
||||
fetch
|
||||
) => {
|
||||
if (
|
||||
item.quantity &&
|
||||
(!Number.isInteger(item.quantity) || item.quantity! < 1)
|
||||
quantity &&
|
||||
(!Number.isInteger(quantity) || quantity! < 1)
|
||||
) {
|
||||
throw new CommerceError({
|
||||
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({
|
||||
...defaultOpts,
|
||||
...options,
|
||||
body: { item },
|
||||
query: addItemToOrderMutation,
|
||||
variables: { variantId, quantity: quantity || 1 },
|
||||
}).then(res => {
|
||||
console.log({ res });
|
||||
return res;
|
||||
})
|
||||
}
|
||||
|
||||
export function extendHook(customFetcher: typeof fetcher) {
|
||||
const useAddItem = () => {
|
||||
const { mutate } = useCart()
|
||||
const fn = useCartAddItem(defaultOpts, customFetcher)
|
||||
const fn = useCartAddItem({}, customFetcher)
|
||||
|
||||
return useCallback(
|
||||
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)
|
||||
return data
|
||||
},
|
||||
|
@ -1,46 +1,83 @@
|
||||
import { normalizeCart } from '../lib/normalize'
|
||||
import type { HookFetcher } from '@commerce/utils/types'
|
||||
import type { SwrOptions } from '@commerce/utils/use-data'
|
||||
import useResponse from '@commerce/utils/use-response'
|
||||
import fetchGraphqlApi from '@framework/api/utils/fetch-graphql-api'
|
||||
import { HookFetcher } from '@commerce/utils/types'
|
||||
import useData, { SwrOptions } from '@commerce/utils/use-data'
|
||||
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 = {
|
||||
url: '/api/bigcommerce/cart',
|
||||
method: 'GET',
|
||||
}
|
||||
export const getCartQuery = /* GraphQL */ `
|
||||
query activeOrder {
|
||||
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<UseCartResponse | null, CartInput> = (
|
||||
export const fetcher: HookFetcher<any | null> = (
|
||||
options,
|
||||
{ cartId },
|
||||
input,
|
||||
fetch
|
||||
) => {
|
||||
return cartId ? fetch({ ...defaultOpts, ...options }) : null
|
||||
return fetch({ ...options, query: getCartQuery })
|
||||
}
|
||||
|
||||
export function extendHook(
|
||||
customFetcher: typeof fetcher,
|
||||
swrOptions?: SwrOptions<UseCartResponse | null, CartInput>
|
||||
swrOptions?: SwrOptions<any | null>
|
||||
) {
|
||||
const useCart = () => {
|
||||
const response = useCommerceCart(defaultOpts, [], customFetcher, {
|
||||
revalidateOnFocus: false,
|
||||
...swrOptions,
|
||||
})
|
||||
const response = useData({}, [], customFetcher, swrOptions)
|
||||
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: {
|
||||
isEmpty: {
|
||||
get() {
|
||||
return Object.values(response.data?.line_items ?? {}).every(
|
||||
(items) => !items.length
|
||||
)
|
||||
return response.data?.activeOrder?.totalQuantity === 0
|
||||
},
|
||||
enumerable: true,
|
||||
},
|
||||
},
|
||||
enumerable: true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return res
|
||||
|
@ -15,8 +15,9 @@ export const fetcher: HookFetcher<Customer | null> = async (
|
||||
_,
|
||||
fetch
|
||||
) => {
|
||||
const data = await fetch<CustomerData | null>({ ...defaultOpts, ...options })
|
||||
return data?.customer ?? null
|
||||
// const data = await fetch<CustomerData | null>({ ...defaultOpts, ...options })
|
||||
// return data?.customer ?? null
|
||||
return null;
|
||||
}
|
||||
|
||||
export function extendHook(
|
||||
|
@ -26,13 +26,13 @@ async function getError(res: Response) {
|
||||
export const vendureConfig: CommerceConfig = {
|
||||
locale: 'en-us',
|
||||
cartCookie: 'bc_cartId',
|
||||
async fetcher({ url, method = 'GET', variables, body: bodyObj }) {
|
||||
const hasBody = Boolean(variables || bodyObj)
|
||||
async fetcher({ url, method = 'POST', variables, query, body: bodyObj }) {
|
||||
const hasBody = Boolean(variables || query)
|
||||
const body = hasBody
|
||||
? JSON.stringify(variables ? { variables } : bodyObj)
|
||||
? JSON.stringify({ query, variables })
|
||||
: 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) {
|
||||
const { data } = await res.json()
|
||||
|
Loading…
x
Reference in New Issue
Block a user