Make use-add-item hook extendable

This commit is contained in:
Luis Alvarez 2020-10-09 10:36:23 -05:00
parent 6dca1eadd2
commit c2096a8ab4
4 changed files with 68 additions and 27 deletions

View File

@ -1,12 +1,21 @@
import { useCallback } from 'react'
import type { Fetcher } from '@lib/commerce'
import { HookFetcher } from '@lib/commerce/utils/types'
import { default as useCartAddItem } from '@lib/commerce/cart/use-add-item'
import type { ItemBody, AddItemBody } from '../api/cart'
import { Cart, useCart } from '.'
export type UpdateItemInput = ItemBody
function fetcher(fetch: Fetcher<Cart>, { item }: AddItemBody) {
const defaultOpts = {
url: '/api/bigcommerce/cart',
method: 'POST',
}
export const fetcher: HookFetcher<Cart, AddItemBody> = (
options,
{ item },
fetch
) => {
if (
item.quantity &&
(!Number.isInteger(item.quantity) || item.quantity! < 1)
@ -16,19 +25,31 @@ function fetcher(fetch: Fetcher<Cart>, { item }: AddItemBody) {
)
}
return fetch({ url: '/api/bigcommerce/cart', method: 'POST', body: { item } })
return fetch({
url: options.url!,
method: options.method!,
body: { item },
})
}
export default function useAddItem() {
const { mutate } = useCart()
const fn = useCartAddItem<Cart, AddItemBody>(fetcher)
function extend(customFetcher: typeof fetcher) {
const useAddItem = () => {
const { mutate } = useCart()
const fn = useCartAddItem<Cart, AddItemBody>(defaultOpts, customFetcher)
return useCallback(
async function addItem(input: UpdateItemInput) {
const data = await fn({ item: input })
await mutate(data, false)
return data
},
[fn, mutate]
)
return useCallback(
async function addItem(input: UpdateItemInput) {
const data = await fn({ item: input })
await mutate(data, false)
return data
},
[fn, mutate]
)
}
useAddItem.extend = extend
return useAddItem
}
export default extend(fetcher)

View File

@ -1,14 +1,16 @@
import { useCallback } from 'react'
import { Fetcher, useCommerce } from '..'
import { HookFetcher, HookFetcherOptions } from '../utils/types'
import { useCommerce } from '..'
export default function useAddItem<T, Input>(
fetcher: (fetch: Fetcher<T>, input: Input) => T | Promise<T>
options: HookFetcherOptions,
fetcher: HookFetcher<T, Input>
) {
const { fetcherRef } = useCommerce()
return useCallback(
function addItem(input: Input) {
return fetcher(fetcherRef.current, input)
return fetcher(options, input, fetcherRef.current)
},
[fetcher]
)

View File

@ -6,6 +6,7 @@ import {
useMemo,
useRef,
} from 'react'
import { Fetcher } from './utils/types'
const Commerce = createContext<CommerceConfig | null>(null)
@ -20,16 +21,6 @@ export type CommerceConfig = {
cartCookie: string
}
export type Fetcher<T> = (options: FetcherOptions) => T | Promise<T>
export type FetcherOptions = {
url?: string
query?: string
method?: string
variables?: any
body?: any
}
export function CommerceProvider({ children, config }: CommerceProps) {
if (!config) {
throw new Error('CommerceProvider requires a valid config object')

View File

@ -0,0 +1,27 @@
// Core fetcher added by CommerceProvider
export type Fetcher<T> = (options: FetcherOptions) => T | Promise<T>
export type FetcherOptions = {
url?: string
query?: string
method?: string
variables?: any
body?: any
}
export type HookFetcher<T, Input> = (
options: HookFetcherOptions,
input: Input,
fetch: Fetcher<T>
) => T | Promise<T>
// export type HookFetcher<T> = (
// options: FetcherOptions,
// fetch: Fetcher<T>
// ) => T | Promise<T>
export type HookFetcherOptions = {
query?: string
url?: string
method?: string
}