Add more options to the hook handler

This commit is contained in:
Luis Alvarez 2021-02-10 10:51:46 -05:00
parent 5aecb0f303
commit 0eeb290eb0
3 changed files with 100 additions and 26 deletions

View File

@ -1,3 +1,4 @@
import { useMemo } from 'react'
import { FetcherError } from '@commerce/utils/errors' import { FetcherError } from '@commerce/utils/errors'
import type { Fetcher, HookHandler } from '@commerce/utils/types' import type { Fetcher, HookHandler } from '@commerce/utils/types'
import type { FetchCartInput } from '@commerce/cart/use-cart' import type { FetchCartInput } from '@commerce/cart/use-cart'
@ -57,6 +58,22 @@ const useCart: HookHandler<
revalidateOnFocus: false, revalidateOnFocus: false,
}, },
normalizer: normalizeCart, normalizer: normalizeCart,
useHook({ input, useData }) {
const response = useData({ input })
return useMemo(
() =>
Object.create(response, {
isEmpty: {
get() {
return (response.data?.lineItems.length ?? 0) <= 0
},
enumerable: true,
},
}),
[response]
)
},
onResponse(response) { onResponse(response) {
return Object.create(response, { return Object.create(response, {
isEmpty: { isEmpty: {

View File

@ -1,23 +1,24 @@
import { useMemo } from 'react' import { useMemo } from 'react'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import type { HookFetcherFn } from '../utils/types'
import useData from '../utils/use-data-2'
import type { Cart } from '../types' import type { Cart } from '../types'
import type { Prop, HookFetcherFn, UseHookInput } from '../utils/types'
import useData from '../utils/use-data-2'
import { Provider, useCommerce } from '..' import { Provider, useCommerce } from '..'
export type FetchCartInput = { export type FetchCartInput = {
cartId?: Cart['id'] cartId?: Cart['id']
} }
export type CartResponse<P extends Provider> = ReturnType< export type UseCartHandler<P extends Provider> = Prop<
NonNullable<NonNullable<NonNullable<P['cart']>['useCart']>['onResponse']> Prop<P, 'cart'>,
'useCart'
> >
export type UseCartInput<P extends Provider> = Parameters< export type CartResponse<P extends Provider> = ReturnType<
NonNullable< Prop<UseCartHandler<P>, 'onResponse'>
NonNullable<NonNullable<NonNullable<P['cart']>['useCart']>>['input'] >
>
>[0] export type UseCartInput<P extends Provider> = UseHookInput<UseCartHandler<P>>
export type UseCart<P extends Provider> = Partial< export type UseCart<P extends Provider> = Partial<
UseCartInput<P> UseCartInput<P>
@ -35,25 +36,59 @@ export const fetcher: HookFetcherFn<Cart | null, FetchCartInput> = async ({
return data && normalize ? normalize(data) : data return data && normalize ? normalize(data) : data
} }
export default function useCart<P extends Provider>(input?: UseCartInput<P>) { type X = UseCartInput<Provider>
export default function useCart<P extends Provider>(
input: UseCartInput<P> = {}
) {
const { providerRef, fetcherRef, cartCookie } = useCommerce<P>() const { providerRef, fetcherRef, cartCookie } = useCommerce<P>()
const provider = providerRef.current const provider = providerRef.current
const opts = provider.cart?.useCart const opts = provider.cart?.useCart
const { swrOptions, ...hookInput } = input
return opts?.useHook!({
input: hookInput,
swrOptions,
useData(ctx) {
const fetcherFn = opts?.fetcher ?? fetcher const fetcherFn = opts?.fetcher ?? fetcher
const wrapper: typeof fetcher = (context) => { const wrapper: typeof fetcher = (context) => {
context.input.cartId = Cookies.get(cartCookie) context.input.cartId = Cookies.get(cartCookie)
return fetcherFn(context) return fetcherFn(context)
} }
const response = useData( const response = useData(
{ ...opts, fetcher: wrapper }, {
opts?.input ? opts.input(input ?? {}) : [], ...opts,
fetcher: wrapper,
swrOptions: {
...opts.swrOptions,
...(ctx?.swrOptions ?? swrOptions),
},
},
ctx?.input ?? [],
provider.fetcher ?? fetcherRef.current provider.fetcher ?? fetcherRef.current
) )
const memoizedResponse = useMemo( return response
() => (opts?.onResponse ? opts.onResponse(response) : response), },
[response] })
)
return memoizedResponse as CartResponse<P> // console.log(i)
// const fetcherFn = opts?.fetcher ?? fetcher
// const wrapper: typeof fetcher = (context) => {
// context.input.cartId = Cookies.get(cartCookie)
// return fetcherFn(context)
// }
// const response = useData(
// { ...opts, fetcher: wrapper },
// opts?.input ? opts.input(input ?? {}) : [],
// provider.fetcher ?? fetcherRef.current
// )
// const memoizedResponse = useMemo(
// () => (opts?.onResponse ? opts.onResponse(response) : response),
// [response]
// )
// return memoizedResponse as CartResponse<P>
} }

View File

@ -74,9 +74,16 @@ export type HookHandler<
input?( input?(
input: Input & { swrOptions?: SwrOptions<Data, FetchInput, Result> } input: Input & { swrOptions?: SwrOptions<Data, FetchInput, Result> }
): HookFetchInput | HookSwrInput ): HookFetchInput | HookSwrInput
useHook?(context: {
input: Input
swrOptions?: SwrOptions<Data, FetchInput, Result>
useData(context?: {
input?: HookFetchInput | HookSwrInput
swrOptions?: SwrOptions<Data, FetchInput, Result>
}): ResponseState<Data>
}): ResponseState<Data> & State
swrOptions?: SwrOptions<Data, FetchInput, Result> swrOptions?: SwrOptions<Data, FetchInput, Result>
onResponse?(response: ResponseState<Data>): ResponseState<Data> & State onResponse?(response: ResponseState<Data>): ResponseState<Data> & State
onMutation?: any
fetchOptions?: HookFetcherOptions fetchOptions?: HookFetcherOptions
fetcher?: HookFetcherFn<Data, FetchInput, Result, Body> fetcher?: HookFetcherFn<Data, FetchInput, Result, Body>
normalizer?(data: Result): Data normalizer?(data: Result): Data
@ -87,3 +94,18 @@ export type SwrOptions<Data, Input = null, Result = any> = ConfigInterface<
CommerceError, CommerceError,
HookFetcher<Data, Input, Result> HookFetcher<Data, Input, Result>
> >
/**
* Returns the property K from type T excluding nullables
*/
export type Prop<T, K extends keyof T> = NonNullable<T[K]>
export type UseHookParameters<H extends HookHandler<any>> = Parameters<
Prop<H, 'useHook'>
>
export type UseHookInput<
H extends HookHandler<any>
> = UseHookParameters<H>[0]['input'] & {
swrOptions?: UseHookParameters<H>[0]['swrOptions']
}