diff --git a/framework/bigcommerce/cart/use-remove-item.tsx b/framework/bigcommerce/cart/use-remove-item.tsx index c8cdaeb0d..c1f1ab4c0 100644 --- a/framework/bigcommerce/cart/use-remove-item.tsx +++ b/framework/bigcommerce/cart/use-remove-item.tsx @@ -1,8 +1,9 @@ import { useCallback } from 'react' -import { HookFetcher } from '@commerce/utils/types' +import { HookContext, HookFetcherContext } from '@commerce/utils/types' import { ValidationError } from '@commerce/utils/errors' -import useCartRemoveItem, { - RemoveItemInput as UseRemoveItemInput, +import useRemoveItem, { + RemoveItemInput as RemoveItemInputBase, + UseRemoveItem, } from '@commerce/cart/use-remove-item' import { normalizeCart } from '../lib/normalize' import type { @@ -13,41 +14,39 @@ import type { } from '../types' import useCart from './use-cart' -const defaultOpts = { - url: '/api/bigcommerce/cart', - method: 'DELETE', -} - export type RemoveItemFn = T extends LineItem ? (input?: RemoveItemInput) => Promise : (input: RemoveItemInput) => Promise export type RemoveItemInput = T extends LineItem - ? Partial - : UseRemoveItemInput + ? Partial + : RemoveItemInputBase -export const fetcher: HookFetcher = async ( - options, - { itemId }, - fetch -) => { - const data = await fetch({ - ...defaultOpts, - ...options, - body: { itemId }, - }) - return normalizeCart(data) -} +export default useRemoveItem as UseRemoveItem -export function extendHook(customFetcher: typeof fetcher) { - const useRemoveItem = ( - item?: T +export const handler = { + fetchOptions: { + url: '/api/bigcommerce/cart', + method: 'DELETE', + }, + async fetcher({ + input: { itemId }, + options, + fetch, + }: HookFetcherContext) { + const data = await fetch({ + ...options, + body: { itemId }, + }) + return normalizeCart(data) + }, + useHook: ({ fetch }: HookContext) => < + T extends LineItem | undefined = undefined + >( + ctx: { item?: T } = {} ) => { - const { mutate } = useCart() - const fn = useCartRemoveItem( - defaultOpts, - customFetcher - ) + const { item } = ctx + const { mutate } = useCart() as any const removeItem: RemoveItemFn = async (input) => { const itemId = input?.id ?? item?.id @@ -57,17 +56,11 @@ export function extendHook(customFetcher: typeof fetcher) { }) } - const data = await fn({ itemId }) + const data = await fetch({ input: { itemId } }) await mutate(data, false) return data } - return useCallback(removeItem as RemoveItemFn, [fn, mutate]) - } - - useRemoveItem.extend = extendHook - - return useRemoveItem + return useCallback(removeItem as RemoveItemFn, [fetch, mutate]) + }, } - -export default extendHook(fetcher) diff --git a/framework/bigcommerce/cart/use-update-item.tsx b/framework/bigcommerce/cart/use-update-item.tsx index f5a09006a..cfd6007d1 100644 --- a/framework/bigcommerce/cart/use-update-item.tsx +++ b/framework/bigcommerce/cart/use-update-item.tsx @@ -13,7 +13,7 @@ import type { BigcommerceCart, LineItem, } from '../types' -import { fetcher as removeFetcher } from './use-remove-item' +import { handler as removeItemHandler } from './use-remove-item' import useCart from './use-cart' export type UpdateItemInput = T extends LineItem @@ -35,7 +35,11 @@ export const handler = { if (Number.isInteger(item.quantity)) { // Also allow the update hook to remove an item if the quantity is lower than 1 if (item.quantity! < 1) { - return removeFetcher(null, { itemId }, fetch) + return removeItemHandler.fetcher({ + options: removeItemHandler.fetchOptions, + input: { itemId }, + fetch, + }) } } else if (item.quantity) { throw new ValidationError({ diff --git a/framework/bigcommerce/provider.ts b/framework/bigcommerce/provider.ts index 434c1c39e..e233dad04 100644 --- a/framework/bigcommerce/provider.ts +++ b/framework/bigcommerce/provider.ts @@ -1,6 +1,7 @@ import { handler as useCart } from './cart/use-cart' import { handler as useAddItem } from './cart/use-add-item' import { handler as useUpdateItem } from './cart/use-update-item' +import { handler as useRemoveItem } from './cart/use-remove-item' import { handler as useWishlist } from './wishlist/use-wishlist' import { handler as useCustomer } from './customer/use-customer' import { handler as useSearch } from './product/use-search' @@ -10,7 +11,7 @@ export const bigcommerceProvider = { locale: 'en-us', cartCookie: 'bc_cartId', fetcher, - cart: { useCart, useAddItem, useUpdateItem }, + cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, wishlist: { useWishlist }, customer: { useCustomer }, products: { useSearch }, diff --git a/framework/commerce/cart/use-remove-item.tsx b/framework/commerce/cart/use-remove-item.tsx index 8a63b1b73..32d8cbf1c 100644 --- a/framework/commerce/cart/use-remove-item.tsx +++ b/framework/commerce/cart/use-remove-item.tsx @@ -1,10 +1,32 @@ -import useAction from '../utils/use-action' +import useHook, { useHookHandler } from '../utils/use-hook' +import { mutationFetcher } from '../utils/default-fetcher' +import type { MutationHook } from '../utils/types' +import type { Cart, LineItem, RemoveCartItemBody } from '../types' +import type { Provider } from '..' -// Input expected by the action returned by the `useRemoveItem` hook -export interface RemoveItemInput { +/** + * Input expected by the action returned by the `useRemoveItem` hook + */ +export type RemoveItemInput = { id: string } -const useRemoveItem = useAction +export type UseRemoveItem< + H extends MutationHook = MutationHook< + Cart | null, + { item?: LineItem }, + RemoveItemInput, + RemoveCartItemBody + > +> = ReturnType + +export const fetcher = mutationFetcher + +const fn = (provider: Provider) => provider.cart?.useRemoveItem! + +const useRemoveItem: UseRemoveItem = (input) => { + const handler = useHookHandler(fn, fetcher) + return handler(useHook(fn, fetcher))(input) +} export default useRemoveItem diff --git a/framework/commerce/cart/use-update-item.tsx b/framework/commerce/cart/use-update-item.tsx index cc904a14a..93afdbb1e 100644 --- a/framework/commerce/cart/use-update-item.tsx +++ b/framework/commerce/cart/use-update-item.tsx @@ -1,17 +1,19 @@ import useHook, { useHookHandler } from '../utils/use-hook' -import type { MutationHook, HookFetcherFn } from '../utils/types' +import { mutationFetcher } from '../utils/default-fetcher' +import type { MutationHook } from '../utils/types' import type { Cart, CartItemBody, LineItem, UpdateCartItemBody } from '../types' import type { Provider } from '..' -import debounce from 'lodash.debounce' -// Input expected by the action returned by the `useUpdateItem` hook +/** + * Input expected by the action returned by the `useUpdateItem` hook + */ export type UpdateItemInput = T & { id: string } export type UseUpdateItem< H extends MutationHook = MutationHook< - Cart, + Cart | null, { item?: LineItem wait?: number @@ -21,19 +23,13 @@ export type UseUpdateItem< > > = ReturnType -export const fetcher: HookFetcherFn = async ({ - options, - input, - fetch, -}) => { - return fetch({ ...options, body: input }) -} +export const fetcher = mutationFetcher const fn = (provider: Provider) => provider.cart?.useUpdateItem! -const useUpdateItem: UseUpdateItem = (input = {}) => { +const useUpdateItem: UseUpdateItem = (input) => { const handler = useHookHandler(fn, fetcher) - return debounce(handler(useHook(fn, fetcher))(input), input.wait ?? 500) + return handler(useHook(fn, fetcher))(input) } export default useUpdateItem diff --git a/framework/commerce/utils/default-fetcher.ts b/framework/commerce/utils/default-fetcher.ts index 8dc9def75..cdaf05516 100644 --- a/framework/commerce/utils/default-fetcher.ts +++ b/framework/commerce/utils/default-fetcher.ts @@ -3,4 +3,10 @@ import type { HookFetcherFn } from './types' const defaultFetcher: HookFetcherFn = ({ options, fetch }) => fetch(options) +export const mutationFetcher: HookFetcherFn = ({ + input, + options, + fetch, +}) => fetch({ ...options, body: input }) + export default defaultFetcher