4
0
forked from crowetic/commerce

Updated the useAddItem and useRemoveItem hooks

This commit is contained in:
Luis Alvarez 2021-02-02 20:16:47 -05:00
parent 023058dc0c
commit 5cfa8241f6
7 changed files with 98 additions and 51 deletions

View File

@ -11,42 +11,22 @@ import removeItem from './handlers/remove-item'
import type {
BigcommerceCart,
GetCartHandlerBody,
AddCartItemHandlerBody,
UpdateCartItemHandlerBody,
RemoveCartItemHandlerBody,
} from '../../types'
type OptionSelections = {
option_id: Number
option_value: Number | String
}
export type ItemBody = {
productId: number
variantId: number
quantity?: number
optionSelections?: OptionSelections
}
export type AddItemBody = { item: ItemBody }
export type RemoveItemBody = { itemId: string }
export type CartHandlers = {
getCart: BigcommerceHandler<BigcommerceCart, GetCartHandlerBody>
addItem: BigcommerceHandler<
BigcommerceCart,
{ cartId?: string } & Partial<AddItemBody>
>
addItem: BigcommerceHandler<BigcommerceCart, AddCartItemHandlerBody>
updateItem: BigcommerceHandler<BigcommerceCart, UpdateCartItemHandlerBody>
removeItem: BigcommerceHandler<
BigcommerceCart,
{ cartId?: string } & Partial<RemoveItemBody>
>
removeItem: BigcommerceHandler<BigcommerceCart, RemoveCartItemHandlerBody>
}
const METHODS = ['GET', 'POST', 'PUT', 'DELETE']
// TODO: a complete implementation should have schema validation for `req.body`
const cartApi: BigcommerceApiHandler<Cart, CartHandlers> = async (
const cartApi: BigcommerceApiHandler<BigcommerceCart, CartHandlers> = async (
req,
res,
config,

View File

@ -1,13 +1,16 @@
import { useCallback } from 'react'
import type { HookFetcher } from '@commerce/utils/types'
import { CommerceError } from '@commerce/utils/errors'
import useCartAddItem from '@commerce/cart/use-add-item'
import useCartAddItem, {
AddItemInput as UseAddItemInput,
} from '@commerce/cart/use-add-item'
import { normalizeCart } from '../lib/normalize'
import type {
ItemBody,
AddItemBody,
Cart as BigcommerceCart,
} from '../api/cart'
AddCartItemBody,
Cart,
BigcommerceCart,
CartItemBody,
} from '../types'
import useCart from './use-cart'
const defaultOpts = {
@ -15,9 +18,9 @@ const defaultOpts = {
method: 'POST',
}
export type AddItemInput = ItemBody
export type AddItemInput = UseAddItemInput<CartItemBody>
export const fetcher: HookFetcher<Cart, AddItemBody> = async (
export const fetcher: HookFetcher<Cart, AddCartItemBody> = async (
options,
{ item },
fetch
@ -31,7 +34,7 @@ export const fetcher: HookFetcher<Cart, AddItemBody> = async (
})
}
const data = await fetch<BigcommerceCart>({
const data = await fetch<BigcommerceCart, AddCartItemBody>({
...defaultOpts,
...options,
body: { item },

View File

@ -1,8 +1,16 @@
import { useCallback } from 'react'
import { HookFetcher } from '@commerce/utils/types'
import useCartRemoveItem from '@commerce/cart/use-remove-item'
import { ValidationError } from '@commerce/utils/errors'
import useCartRemoveItem, {
RemoveItemInput as UseRemoveItemInput,
} from '@commerce/cart/use-remove-item'
import { normalizeCart } from '../lib/normalize'
import type { RemoveItemBody, Cart as BigcommerceCart } from '../api/cart'
import type {
RemoveCartItemBody,
Cart,
BigcommerceCart,
LineItem,
} from '../types'
import useCart from './use-cart'
const defaultOpts = {
@ -10,11 +18,15 @@ const defaultOpts = {
method: 'DELETE',
}
export type RemoveItemInput = {
id: string
}
export type RemoveItemFn<T = any> = T extends LineItem
? (input?: RemoveItemInput<T>) => Promise<Cart | null>
: (input: RemoveItemInput<T>) => Promise<Cart | null>
export const fetcher: HookFetcher<Cart | null, RemoveItemBody> = async (
export type RemoveItemInput<T = any> = T extends LineItem
? Partial<UseRemoveItemInput>
: UseRemoveItemInput
export const fetcher: HookFetcher<Cart | null, RemoveCartItemBody> = async (
options,
{ itemId },
fetch
@ -28,21 +40,29 @@ export const fetcher: HookFetcher<Cart | null, RemoveItemBody> = async (
}
export function extendHook(customFetcher: typeof fetcher) {
const useRemoveItem = (item?: any) => {
const useRemoveItem = <T extends LineItem | undefined = undefined>(
item?: T
) => {
const { mutate } = useCart()
const fn = useCartRemoveItem<Cart | null, RemoveItemBody>(
const fn = useCartRemoveItem<Cart | null, RemoveCartItemBody>(
defaultOpts,
customFetcher
)
const removeItem: RemoveItemFn<LineItem> = async (input) => {
const itemId = input?.id ?? item?.id
return useCallback(
async function removeItem(input: RemoveItemInput) {
const data = await fn({ itemId: input.id ?? item?.id })
await mutate(data, false)
return data
},
[fn, mutate]
)
if (!itemId) {
throw new ValidationError({
message: 'Invalid input used for this operation',
})
}
const data = await fn({ itemId })
await mutate(data, false)
return data
}
return useCallback(removeItem as RemoveItemFn<T>, [fn, mutate])
}
useRemoveItem.extend = extendHook

View File

@ -45,8 +45,18 @@ export interface CartItemBody extends Core.CartItemBody {
export interface GetCartHandlerBody extends Core.GetCartHandlerBody {}
export interface AddCartItemBody extends Core.AddCartItemBody<CartItemBody> {}
export interface AddCartItemHandlerBody
extends Core.AddCartItemHandlerBody<CartItemBody> {}
export interface UpdateCartItemBody
extends Core.UpdateCartItemBody<CartItemBody> {}
export interface UpdateCartItemHandlerBody
extends Core.UpdateCartItemHandlerBody<CartItemBody> {}
export interface RemoveCartItemBody extends Core.RemoveCartItemBody {}
export interface RemoveCartItemHandlerBody
extends Core.RemoveCartItemHandlerBody {}

View File

@ -1,4 +1,8 @@
import useAction from '../utils/use-action'
import type { CartItemBody } from '../types'
// Input expected by the action returned by the `useAddItem` hook
export type AddItemInput<T extends CartItemBody> = T
const useAddItem = useAction

View File

@ -1,5 +1,10 @@
import useAction from '../utils/use-action'
// Input expected by the action returned by the `useRemoveItem` hook
export interface RemoveItemInput {
id: string
}
const useRemoveItem = useAction
export default useRemoveItem

View File

@ -87,6 +87,10 @@ export interface Cart {
discounts?: Discount[]
}
/**
* Cart mutations
*/
// Base cart item body used for cart mutations
export interface CartItemBody {
variantId: string
@ -99,14 +103,35 @@ export interface GetCartHandlerBody {
cartId?: string
}
// Body used by the update operation
// Body used by the add item to cart operation
export interface AddCartItemBody<T extends CartItemBody> {
item: T
}
// Body expected by the add item to cart operation handler
export interface AddCartItemHandlerBody<T extends CartItemBody>
extends Partial<AddCartItemBody<T>> {
cartId?: string
}
// Body used by the update cart item operation
export interface UpdateCartItemBody<T extends CartItemBody> {
itemId: string
item: T
}
// Body expected by the update operation handler
// Body expected by the update cart item operation handler
export interface UpdateCartItemHandlerBody<T extends CartItemBody>
extends Partial<UpdateCartItemBody<T>> {
cartId?: string
}
// Body used by the remove cart item operation
export interface RemoveCartItemBody {
itemId: string
}
// Body expected by the remove cart item operation handler
export interface RemoveCartItemHandlerBody extends Partial<RemoveCartItemBody> {
cartId?: string
}