4
0
forked from crowetic/commerce

Added useResponse hook

This commit is contained in:
Luis Alvarez 2021-01-21 21:19:53 -05:00
parent 2613a5cec7
commit bafb8a4479
6 changed files with 57 additions and 24 deletions

View File

@ -1,10 +1,9 @@
import { normalizeCart } from '../lib/normalize'
import type { HookFetcher } from '@commerce/utils/types'
import type { SwrOptions } from '@commerce/utils/use-data'
import defineProperty from '@commerce/utils/define-property'
import useResponse from '@commerce/utils/use-response'
import useCommerceCart, { CartInput } from '@commerce/cart/use-cart'
import type { Cart as BigCommerceCart } from '../api/cart'
import update from '@framework/lib/immutability'
const defaultOpts = {
url: '/api/bigcommerce/cart',
@ -30,25 +29,21 @@ export function extendHook(
revalidateOnFocus: false,
...swrOptions,
})
// Uses a getter to only calculate the prop when required
// response.data is also a getter and it's better to not trigger it early
if (!('isEmpty' in response)) {
defineProperty(response, 'isEmpty', {
get() {
return Object.values(response.data?.line_items ?? {}).every(
(items) => !items.length
)
const res = useResponse(response, {
normalizer: normalizeCart,
descriptors: {
isEmpty: {
get() {
return Object.values(response.data?.line_items ?? {}).every(
(items) => !items.length
)
},
enumerable: true,
},
set: (x) => x,
})
}
},
})
return response.data
? update(response, {
data: { $set: normalizeCart(response.data) },
})
: response
return res
}
useCart.extend = extendHook

View File

@ -1,4 +1,3 @@
import type { responseInterface } from 'swr'
import Cookies from 'js-cookie'
import type { HookInput, HookFetcher, HookFetcherOptions } from '../utils/types'
import useData, { ResponseState, SwrOptions } from '../utils/use-data'
@ -17,12 +16,10 @@ export default function useCart<Result>(
swrOptions?: SwrOptions<Result, CartInput>
): CartResponse<Result> {
const { cartCookie } = useCommerce()
const fetcher: typeof fetcherFn = (options, input, fetch) => {
input.cartId = Cookies.get(cartCookie)
return fetcherFn(options, input, fetch)
}
const response = useData(options, input, fetcher, swrOptions)
return response

View File

@ -22,3 +22,5 @@ export type HookFetcherOptions = {
}
export type HookInput = [string, string | number | boolean | undefined][]
export type Override<T, K> = Omit<T, keyof K> & K

View File

@ -64,7 +64,7 @@ const useData: UseData = (options, input, fetcherFn, swrOptions) => {
get() {
return response.data === undefined
},
set: (x) => x,
enumerable: true,
})
}

View File

@ -0,0 +1,40 @@
import { useMemo } from 'react'
import { responseInterface } from 'swr'
import { CommerceError } from './errors'
import { Override } from './types'
export type UseResponseOptions<
D,
R extends responseInterface<any, CommerceError>
> = {
descriptors?: PropertyDescriptorMap
normalizer?: (data: R['data']) => D
}
export type UseResponse = <D, R extends responseInterface<any, CommerceError>>(
response: R,
options: UseResponseOptions<D, R>
) => D extends object ? Override<R, { data?: D }> : R
const useResponse: UseResponse = (response, { descriptors, normalizer }) => {
const memoizedResponse = useMemo(
() =>
Object.create(response, {
...descriptors,
...(normalizer
? {
data: {
get() {
return normalizer(response.data)
},
enumerable: true,
},
}
: {}),
}),
[response]
)
return memoizedResponse
}
export default useResponse

View File

@ -1,4 +1,3 @@
import type { responseInterface } from 'swr'
import type { HookInput, HookFetcher, HookFetcherOptions } from '../utils/types'
import useData, { ResponseState, SwrOptions } from '../utils/use-data'