Updated cart hooks

This commit is contained in:
Luis Alvarez 2021-03-31 22:12:45 -06:00
parent 731486e07b
commit 6d06d8b705
10 changed files with 56 additions and 96 deletions

View File

@ -3,12 +3,11 @@ import type { MutationHook } from '@commerce/utils/types'
import { CommerceError } from '@commerce/utils/errors' import { CommerceError } from '@commerce/utils/errors'
import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item' import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item'
import { normalizeCart } from '../lib/normalize' import { normalizeCart } from '../lib/normalize'
import type { BigcommerceCart, AddItemHook } from '../types/cart' import type { BigcommerceCart, AddItemHook, CartTypes } from '../types/cart'
import useCart from './use-cart' import useCart from './use-cart'
export default useAddItem as UseAddItem<typeof handler> export default useAddItem as UseAddItem<typeof handler>
// export const handler: MutationHook<Cart, {}, CartItemBody> = {
export const handler: MutationHook<AddItemHook> = { export const handler: MutationHook<AddItemHook> = {
fetchOptions: { fetchOptions: {
url: '/api/bigcommerce/cart', url: '/api/bigcommerce/cart',

View File

@ -4,26 +4,23 @@ import type {
HookFetcherContext, HookFetcherContext,
} from '@commerce/utils/types' } from '@commerce/utils/types'
import { ValidationError } from '@commerce/utils/errors' import { ValidationError } from '@commerce/utils/errors'
import useRemoveItem, { import useRemoveItem, { UseRemoveItem } from '@commerce/cart/use-remove-item'
RemoveItemInput as RemoveItemInputBase,
UseRemoveItem,
} from '@commerce/cart/use-remove-item'
import { normalizeCart } from '../lib/normalize' import { normalizeCart } from '../lib/normalize'
import type { import type {
RemoveCartItemBody,
Cart, Cart,
BigcommerceCart,
LineItem, LineItem,
} from '../types' RemoveItemHook,
BigcommerceCart,
} from '../types/cart'
import useCart from './use-cart' import useCart from './use-cart'
export type RemoveItemFn<T = any> = T extends LineItem export type RemoveItemFn<T = any> = T extends LineItem
? (input?: RemoveItemInput<T>) => Promise<Cart | null> ? (input?: RemoveItemActionInput<T>) => Promise<Cart | null>
: (input: RemoveItemInput<T>) => Promise<Cart | null> : (input: RemoveItemActionInput<T>) => Promise<Cart | null>
export type RemoveItemInput<T = any> = T extends LineItem export type RemoveItemActionInput<T = any> = T extends LineItem
? Partial<RemoveItemInputBase> ? Partial<RemoveItemHook['actionInput']>
: RemoveItemInputBase : RemoveItemHook['actionInput']
export default useRemoveItem as UseRemoveItem<typeof handler> export default useRemoveItem as UseRemoveItem<typeof handler>
@ -36,16 +33,14 @@ export const handler = {
input: { itemId }, input: { itemId },
options, options,
fetch, fetch,
}: HookFetcherContext<RemoveCartItemBody>) { }: HookFetcherContext<RemoveItemHook>) {
const data = await fetch<BigcommerceCart>({ const data = await fetch<BigcommerceCart>({
...options, ...options,
body: { itemId }, body: { itemId },
}) })
return normalizeCart(data) return normalizeCart(data)
}, },
useHook: ({ useHook: ({ fetch }: MutationHookContext<RemoveItemHook>) => <
fetch,
}: MutationHookContext<Cart | null, RemoveCartItemBody>) => <
T extends LineItem | undefined = undefined T extends LineItem | undefined = undefined
>( >(
ctx: { item?: T } = {} ctx: { item?: T } = {}

View File

@ -5,23 +5,15 @@ import type {
HookFetcherContext, HookFetcherContext,
} from '@commerce/utils/types' } from '@commerce/utils/types'
import { ValidationError } from '@commerce/utils/errors' import { ValidationError } from '@commerce/utils/errors'
import useUpdateItem, { import useUpdateItem, { UseUpdateItem } from '@commerce/cart/use-update-item'
UpdateItemInput as UpdateItemInputBase,
UseUpdateItem,
} from '@commerce/cart/use-update-item'
import { normalizeCart } from '../lib/normalize' import { normalizeCart } from '../lib/normalize'
import type { import type { Cart, BigcommerceCart, LineItem, UpdateItemHook } from '../types'
UpdateCartItemBody,
Cart,
BigcommerceCart,
LineItem,
} from '../types'
import { handler as removeItemHandler } from './use-remove-item' import { handler as removeItemHandler } from './use-remove-item'
import useCart from './use-cart' import useCart from './use-cart'
export type UpdateItemInput<T = any> = T extends LineItem export type UpdateItemActionInput<T = any> = T extends LineItem
? Partial<UpdateItemInputBase<LineItem>> ? Partial<UpdateItemHook['actionInput']>
: UpdateItemInputBase<LineItem> : UpdateItemHook['actionInput']
export default useUpdateItem as UseUpdateItem<typeof handler> export default useUpdateItem as UseUpdateItem<typeof handler>
@ -34,7 +26,7 @@ export const handler = {
input: { itemId, item }, input: { itemId, item },
options, options,
fetch, fetch,
}: HookFetcherContext<UpdateCartItemBody>) { }: HookFetcherContext<UpdateItemHook>) {
if (Number.isInteger(item.quantity)) { if (Number.isInteger(item.quantity)) {
// Also allow the update hook to remove an item if the quantity is lower than 1 // Also allow the update hook to remove an item if the quantity is lower than 1
if (item.quantity! < 1) { if (item.quantity! < 1) {
@ -50,16 +42,14 @@ export const handler = {
}) })
} }
const data = await fetch<BigcommerceCart, UpdateCartItemBody>({ const data = await fetch<BigcommerceCart>({
...options, ...options,
body: { itemId, item }, body: { itemId, item },
}) })
return normalizeCart(data) return normalizeCart(data)
}, },
useHook: ({ useHook: ({ fetch }: MutationHookContext<UpdateItemHook>) => <
fetch,
}: MutationHookContext<Cart | null, UpdateCartItemBody>) => <
T extends LineItem | undefined = undefined T extends LineItem | undefined = undefined
>( >(
ctx: { ctx: {
@ -71,7 +61,7 @@ export const handler = {
const { mutate } = useCart() as any const { mutate } = useCart() as any
return useCallback( return useCallback(
debounce(async (input: UpdateItemInput<T>) => { debounce(async (input: UpdateItemActionInput<T>) => {
const itemId = input.id ?? item?.id const itemId = input.id ?? item?.id
const productId = input.productId ?? item?.productId const productId = input.productId ?? item?.productId
const variantId = input.productId ?? item?.variantId const variantId = input.productId ?? item?.variantId

View File

@ -45,7 +45,8 @@ export type CartItemBody = Core.CartItemBody & {
export type CartTypes = { export type CartTypes = {
cart: Cart cart: Cart
item: CartItemBody item: Core.LineItem
itemBody: CartItemBody
} }
export type CartHooks = Core.CartHooks<CartTypes> export type CartHooks = Core.CartHooks<CartTypes>

View File

@ -5,6 +5,10 @@ import type { AddItemHook } from '../types/cart'
import type { Provider } from '..' import type { Provider } from '..'
export type UseAddItem< export type UseAddItem<
H extends MutationHook<AddItemHook<any>> = MutationHook<AddItemHook>
> = ReturnType<H['useHook']>
export type UseAddItem2<
H extends MutationHook<any> = MutationHook<AddItemHook> H extends MutationHook<any> = MutationHook<AddItemHook>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>

View File

@ -4,9 +4,9 @@ import type { SWRHook, HookFetcherFn } from '../utils/types'
import type { GetCartHook } from '../types/cart' import type { GetCartHook } from '../types/cart'
import { Provider, useCommerce } from '..' import { Provider, useCommerce } from '..'
export type UseCart<H extends SWRHook<any> = SWRHook<GetCartHook>> = ReturnType< export type UseCart<
H['useHook'] H extends SWRHook<GetCartHook<any>> = SWRHook<GetCartHook>
> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn<GetCartHook> = async ({ export const fetcher: HookFetcherFn<GetCartHook> = async ({
options, options,

View File

@ -1,29 +1,14 @@
import { useHook, useMutationHook } from '../utils/use-hook' import { useHook, useMutationHook } from '../utils/use-hook'
import { mutationFetcher } from '../utils/default-fetcher' import { mutationFetcher } from '../utils/default-fetcher'
import type { HookFetcherFn, MutationHook } from '../utils/types' import type { HookFetcherFn, MutationHook } from '../utils/types'
import type { Cart, LineItem, RemoveCartItemBody } from '../types' import type { RemoveItemHook } from '../types/cart'
import type { Provider } from '..' import type { Provider } from '..'
/**
* Input expected by the action returned by the `useRemoveItem` hook
*/
export type RemoveItemInput = {
id: string
}
export type UseRemoveItem< export type UseRemoveItem<
H extends MutationHook<any, any, any> = MutationHook< H extends MutationHook<RemoveItemHook<any>> = MutationHook<RemoveItemHook>
Cart | null,
{ item?: LineItem },
RemoveItemInput,
RemoveCartItemBody
>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn< export const fetcher: HookFetcherFn<RemoveItemHook> = mutationFetcher
Cart | null,
RemoveCartItemBody
> = mutationFetcher
const fn = (provider: Provider) => provider.cart?.useRemoveItem! const fn = (provider: Provider) => provider.cart?.useRemoveItem!

View File

@ -1,32 +1,14 @@
import { useHook, useMutationHook } from '../utils/use-hook' import { useHook, useMutationHook } from '../utils/use-hook'
import { mutationFetcher } from '../utils/default-fetcher' import { mutationFetcher } from '../utils/default-fetcher'
import type { HookFetcherFn, MutationHook } from '../utils/types' import type { HookFetcherFn, MutationHook } from '../utils/types'
import type { Cart, CartItemBody, LineItem, UpdateCartItemBody } from '../types' import type { UpdateItemHook } from '../types/cart'
import type { Provider } from '..' import type { Provider } from '..'
/**
* Input expected by the action returned by the `useUpdateItem` hook
*/
export type UpdateItemInput<T extends CartItemBody> = T & {
id: string
}
export type UseUpdateItem< export type UseUpdateItem<
H extends MutationHook<any, any, any> = MutationHook< H extends MutationHook<UpdateItemHook<any>> = MutationHook<UpdateItemHook>
Cart | null,
{
item?: LineItem
wait?: number
},
UpdateItemInput<CartItemBody>,
UpdateCartItemBody<CartItemBody>
>
> = ReturnType<H['useHook']> > = ReturnType<H['useHook']>
export const fetcher: HookFetcherFn< export const fetcher: HookFetcherFn<UpdateItemHook> = mutationFetcher
Cart | null,
UpdateCartItemBody<CartItemBody>
> = mutationFetcher
const fn = (provider: Provider) => provider.cart?.useUpdateItem! const fn = (provider: Provider) => provider.cart?.useUpdateItem!

View File

@ -87,7 +87,8 @@ export type CartItemBody = {
export type CartTypes = { export type CartTypes = {
cart: Cart cart: Cart
item: CartItemBody item: LineItem
itemBody: CartItemBody
} }
export type CartHooks<T extends CartTypes = CartTypes> = { export type CartHooks<T extends CartTypes = CartTypes> = {
@ -106,20 +107,26 @@ export type GetCartHook<T extends CartTypes = CartTypes> = {
export type AddItemHook<T extends CartTypes = CartTypes> = { export type AddItemHook<T extends CartTypes = CartTypes> = {
data: T['cart'] data: T['cart']
body: { item: T['item'] } body: { item: T['itemBody'] }
input: T['item'] input: T['itemBody']
fetchInput: T['item'] fetchInput: T['itemBody']
actionInput: T['item'] actionInput: T['itemBody']
} }
export type UpdateItemHook<T extends CartTypes = CartTypes> = { export type UpdateItemHook<T extends CartTypes = CartTypes> = {
data: T['cart'] data: T['cart'] | null
body: { itemId: string; item: T['item'] } body: { itemId: string; item: T['itemBody'] }
input: { item?: T['item']; wait?: number }
fetchInput: { itemId: string; item: T['itemBody'] }
actionInput: T['itemBody'] & { id: string }
} }
export type RemoveItemHook<T extends CartTypes = CartTypes> = { export type RemoveItemHook<T extends CartTypes = CartTypes> = {
data: T['cart'] | null data: T['cart'] | null
body: { itemId: string } body: { itemId: string }
input: { item?: T['item'] }
fetchInput: { itemId: string }
actionInput: { id: string }
} }
/** /**
@ -155,6 +162,7 @@ export type AddItemOperation<
export type UpdateItemOperation< export type UpdateItemOperation<
T extends CartTypes = CartTypes T extends CartTypes = CartTypes
> = UpdateItemHook<T> & { > = UpdateItemHook<T> & {
data: T['cart']
body: { cartId: string } body: { cartId: string }
} }

View File

@ -36,18 +36,14 @@ export type HookFetcher<Data, Input = null, Result = any> = (
fetch: <T = Result, Body = any>(options: FetcherOptions<Body>) => Promise<T> fetch: <T = Result, Body = any>(options: FetcherOptions<Body>) => Promise<T>
) => Data | Promise<Data> ) => Data | Promise<Data>
export type HookFetcherFn< export type HookFetcherFn<H extends HookSchemaBase> = (
H extends HookSchemaBase, context: HookFetcherContext<H>
Result = any,
Body = H['body']
> = (
context: HookFetcherContext<H['fetchInput'], Result, Body>
) => H['data'] | Promise<H['data']> ) => H['data'] | Promise<H['data']>
export type HookFetcherContext<Input = undefined, Result = any, Body = any> = { export type HookFetcherContext<H extends HookSchemaBase> = {
options: HookFetcherOptions options: HookFetcherOptions
input: Input input: H['fetchInput']
fetch: <T = Result, B = Body>(options: FetcherOptions<B>) => Promise<T> fetch: <T = any, B = H['body']>(options: FetcherOptions<B>) => Promise<T>
} }
export type HookFetcherOptions = { method?: string } & ( export type HookFetcherOptions = { method?: string } & (