mirror of
https://github.com/vercel/commerce.git
synced 2025-05-18 07:26:59 +00:00
Complete use-cart hook
Signed-off-by: Chloe <pinkcloudvnn@gmail.com>
This commit is contained in:
parent
1b2904ac1f
commit
7d1b542b6f
@ -1,17 +1,42 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
import useAddItem, { UseAddItem } from '@vercel/commerce/cart/use-add-item'
|
import useAddItem, { UseAddItem } from '@vercel/commerce/cart/use-add-item'
|
||||||
|
import type { AddItemHook } from '@vercel/commerce/types/cart'
|
||||||
|
import { CommerceError } from '@vercel/commerce/utils/errors'
|
||||||
import { MutationHook } from '@vercel/commerce/utils/types'
|
import { MutationHook } from '@vercel/commerce/utils/types'
|
||||||
|
import useCart from './use-cart'
|
||||||
|
|
||||||
export default useAddItem as UseAddItem<typeof handler>
|
export default useAddItem as UseAddItem<typeof handler>
|
||||||
export const handler: MutationHook<any> = {
|
|
||||||
|
export const handler: MutationHook<AddItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
query: '',
|
url: '/api/cart',
|
||||||
|
method: 'POST',
|
||||||
|
},
|
||||||
|
async fetcher({ input: item, options, fetch }) {
|
||||||
|
if (
|
||||||
|
item.quantity &&
|
||||||
|
(!Number.isInteger(item.quantity) || item.quantity! < 1)
|
||||||
|
) {
|
||||||
|
throw new CommerceError({
|
||||||
|
message: 'The item quantity has to be a valid integer greater than 0',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await fetch({ ...options, body: { item } })
|
||||||
|
return data
|
||||||
},
|
},
|
||||||
async fetcher({ input, options, fetch }) {},
|
|
||||||
useHook:
|
useHook:
|
||||||
({ fetch }) =>
|
({ fetch }) =>
|
||||||
() => {
|
() => {
|
||||||
return async function addItem() {
|
const { mutate } = useCart()
|
||||||
return {}
|
|
||||||
}
|
return useCallback(
|
||||||
|
async function addItem(input) {
|
||||||
|
const data = await fetch({ input })
|
||||||
|
await mutate(data, false)
|
||||||
|
return data
|
||||||
|
},
|
||||||
|
[fetch, mutate]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,32 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { SWRHook } from '@vercel/commerce/utils/types'
|
import { SWRHook } from '@vercel/commerce/utils/types'
|
||||||
import useCart, { UseCart } from '@vercel/commerce/cart/use-cart'
|
import useCart, { UseCart } from '@vercel/commerce/cart/use-cart'
|
||||||
|
import type { GetCartHook } from '@vercel/commerce/types/cart'
|
||||||
|
|
||||||
export default useCart as UseCart<typeof handler>
|
export default useCart as UseCart<typeof handler>
|
||||||
|
|
||||||
export const handler: SWRHook<any> = {
|
export const handler: SWRHook<GetCartHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
query: '',
|
url: '/api/cart',
|
||||||
},
|
method: 'GET',
|
||||||
async fetcher() {
|
|
||||||
return {
|
|
||||||
id: '',
|
|
||||||
createdAt: '',
|
|
||||||
currency: { code: '' },
|
|
||||||
taxesIncluded: '',
|
|
||||||
lineItems: [],
|
|
||||||
lineItemsSubtotalPrice: '',
|
|
||||||
subtotalPrice: 0,
|
|
||||||
totalPrice: 0,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
useHook:
|
useHook:
|
||||||
({ useData }) =>
|
({ useData }) =>
|
||||||
(input) => {
|
(input) => {
|
||||||
|
const response = useData({
|
||||||
|
swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
|
||||||
|
})
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() =>
|
() =>
|
||||||
Object.create(
|
Object.create(response, {
|
||||||
{},
|
isEmpty: {
|
||||||
{
|
get() {
|
||||||
isEmpty: {
|
return (response.data?.lineItems.length ?? 0) <= 0
|
||||||
get() {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
enumerable: true,
|
|
||||||
},
|
},
|
||||||
}
|
enumerable: true,
|
||||||
),
|
},
|
||||||
[]
|
}),
|
||||||
|
[response]
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,59 @@
|
|||||||
import { MutationHook } from '@vercel/commerce/utils/types'
|
import { useCallback } from 'react'
|
||||||
|
import {
|
||||||
|
HookFetcherContext,
|
||||||
|
MutationHookContext,
|
||||||
|
} from '@vercel/commerce/utils/types'
|
||||||
import useRemoveItem, {
|
import useRemoveItem, {
|
||||||
UseRemoveItem,
|
UseRemoveItem,
|
||||||
} from '@vercel/commerce/cart/use-remove-item'
|
} from '@vercel/commerce/cart/use-remove-item'
|
||||||
|
import type {
|
||||||
|
LineItem,
|
||||||
|
RemoveItemHook,
|
||||||
|
Cart,
|
||||||
|
} from '@vercel/commerce/types/cart'
|
||||||
|
import { ValidationError } from '@vercel/commerce/utils/errors'
|
||||||
|
import useCart from './use-cart'
|
||||||
|
|
||||||
|
export type RemoveItemActionInput<T = any> = T extends LineItem
|
||||||
|
? Partial<RemoveItemHook['actionInput']>
|
||||||
|
: RemoveItemHook['actionInput']
|
||||||
|
|
||||||
|
export type RemoveItemFn<T = any> = T extends LineItem
|
||||||
|
? (input?: RemoveItemActionInput<T>) => Promise<Cart | null | undefined>
|
||||||
|
: (input: RemoveItemActionInput<T>) => Promise<Cart | null>
|
||||||
|
|
||||||
export default useRemoveItem as UseRemoveItem<typeof handler>
|
export default useRemoveItem as UseRemoveItem<typeof handler>
|
||||||
|
|
||||||
export const handler: MutationHook<any> = {
|
export const handler = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
query: '',
|
url: '/api/cart',
|
||||||
|
method: 'DELETE',
|
||||||
|
},
|
||||||
|
async fetcher({
|
||||||
|
input: { itemId },
|
||||||
|
options,
|
||||||
|
fetch,
|
||||||
|
}: HookFetcherContext<RemoveItemHook>) {
|
||||||
|
return await fetch({ ...options, body: { itemId } })
|
||||||
},
|
},
|
||||||
async fetcher({ input, options, fetch }) {},
|
|
||||||
useHook:
|
useHook:
|
||||||
({ fetch }) =>
|
({ fetch }: MutationHookContext<RemoveItemHook>) =>
|
||||||
() => {
|
<T extends LineItem | undefined = undefined>(ctx: { item?: T } = {}) => {
|
||||||
return async function removeItem(input) {
|
const { item } = ctx
|
||||||
return {}
|
const { mutate } = useCart()
|
||||||
|
const removeItem: RemoveItemFn<LineItem> = async (input) => {
|
||||||
|
const itemId = input?.id ?? item?.id
|
||||||
|
if (!itemId) {
|
||||||
|
throw new ValidationError({
|
||||||
|
message: 'Invalid input used for this operation',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await fetch({ input: { itemId } })
|
||||||
|
await mutate(data, false)
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return useCallback(removeItem, [fetch, mutate])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,76 @@
|
|||||||
import { MutationHook } from '@vercel/commerce/utils/types'
|
import { useCallback } from 'react'
|
||||||
|
import debounce from 'lodash.debounce'
|
||||||
|
import { MutationHook, MutationHookContext } from '@vercel/commerce/utils/types'
|
||||||
import useUpdateItem, {
|
import useUpdateItem, {
|
||||||
UseUpdateItem,
|
UseUpdateItem,
|
||||||
} from '@vercel/commerce/cart/use-update-item'
|
} from '@vercel/commerce/cart/use-update-item'
|
||||||
|
import type { LineItem, UpdateItemHook } from '@vercel/commerce/types/cart'
|
||||||
|
import { ValidationError } from '@vercel/commerce/utils/errors'
|
||||||
|
import { handler as removeItemHandler } from './use-remove-item'
|
||||||
|
import useCart from './use-cart'
|
||||||
|
|
||||||
export default useUpdateItem as UseUpdateItem<any>
|
export type UpdateItemActionInput<T = any> = T extends LineItem
|
||||||
|
? Partial<UpdateItemHook['actionInput']>
|
||||||
|
: UpdateItemHook['actionInput']
|
||||||
|
|
||||||
export const handler: MutationHook<any> = {
|
export default useUpdateItem as UseUpdateItem<typeof handler>
|
||||||
|
|
||||||
|
export const handler: MutationHook<UpdateItemHook> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
query: '',
|
query: '/api/cart',
|
||||||
|
method: 'PUT',
|
||||||
},
|
},
|
||||||
async fetcher({ input, options, fetch }) {},
|
async fetcher({ input: { itemId, item }, options, fetch }) {
|
||||||
useHook:
|
if (Number.isInteger(item.quantity)) {
|
||||||
({ fetch }) =>
|
// Also allow the update hook to remove an item if the quantity is lower than 1
|
||||||
() => {
|
if (item.quantity! < 1) {
|
||||||
return async function addItem() {
|
return removeItemHandler.fetcher({
|
||||||
return {}
|
options: removeItemHandler.fetchOptions,
|
||||||
|
input: { itemId },
|
||||||
|
fetch,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
} else if (item.quantity) {
|
||||||
|
throw new ValidationError({
|
||||||
|
message: 'The item quantity has to be a valid integer',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return await fetch({
|
||||||
|
...options,
|
||||||
|
body: { itemId, item },
|
||||||
|
})
|
||||||
|
},
|
||||||
|
useHook:
|
||||||
|
({ fetch }: MutationHookContext<UpdateItemHook>) =>
|
||||||
|
<T extends LineItem | undefined = undefined>(
|
||||||
|
ctx: { item?: T; wait?: number } = {}
|
||||||
|
) => {
|
||||||
|
const { item, wait } = ctx
|
||||||
|
const { mutate } = useCart()
|
||||||
|
|
||||||
|
return useCallback(
|
||||||
|
debounce(async (input: UpdateItemActionInput) => {
|
||||||
|
const itemId = input.id ?? item?.id
|
||||||
|
const productId = input.productId ?? item?.productId
|
||||||
|
const variantId = input.productId ?? item?.variantId
|
||||||
|
|
||||||
|
if (!itemId || !productId || !variantId) {
|
||||||
|
throw new ValidationError({
|
||||||
|
message: 'Invalid input used for this operation',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await fetch({
|
||||||
|
input: {
|
||||||
|
itemId,
|
||||||
|
item: { productId, variantId, quantity: input.quantity },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await mutate(data, false)
|
||||||
|
return data
|
||||||
|
}, wait ?? 500),
|
||||||
|
[fetch, mutate]
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user