forked from crowetic/commerce
Replace use-cart with the new hook
This commit is contained in:
parent
2c9b8b100d
commit
aab2e7f7cc
@ -1,7 +1,10 @@
|
|||||||
import { FC } from 'react'
|
import { FC } from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import cn from 'classnames'
|
import cn from 'classnames'
|
||||||
|
import type { BigcommerceProvider } from '@framework'
|
||||||
|
import { LineItem } from '@framework/types'
|
||||||
import useCart from '@framework/cart/use-cart'
|
import useCart from '@framework/cart/use-cart'
|
||||||
|
import useFake from '@commerce/cart/use-fake'
|
||||||
import useCustomer from '@framework/customer/use-customer'
|
import useCustomer from '@framework/customer/use-customer'
|
||||||
import { Heart, Bag } from '@components/icons'
|
import { Heart, Bag } from '@components/icons'
|
||||||
import { useUI } from '@components/ui/context'
|
import { useUI } from '@components/ui/context'
|
||||||
@ -15,12 +18,14 @@ interface Props {
|
|||||||
|
|
||||||
const countItem = (count: number, item: LineItem) => count + item.quantity
|
const countItem = (count: number, item: LineItem) => count + item.quantity
|
||||||
|
|
||||||
const UserNav: FC<Props> = ({ className, children }) => {
|
const UserNav: FC<Props> = ({ className }) => {
|
||||||
const { data } = useCart()
|
const { data } = useCart()
|
||||||
const { data: customer } = useCustomer()
|
const { data: customer } = useCustomer()
|
||||||
const { toggleSidebar, closeSidebarIfPresent, openModal } = useUI()
|
const { toggleSidebar, closeSidebarIfPresent, openModal } = useUI()
|
||||||
const itemsCount = data?.lineItems.reduce(countItem, 0) ?? 0
|
const itemsCount = data?.lineItems.reduce(countItem, 0) ?? 0
|
||||||
|
|
||||||
|
const x = useFake<BigcommerceProvider>()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className={cn(s.root, className)}>
|
<nav className={cn(s.root, className)}>
|
||||||
<div className={s.mainContainer}>
|
<div className={s.mainContainer}>
|
||||||
|
@ -1,52 +1,4 @@
|
|||||||
import type { HookFetcher } from '@commerce/utils/types'
|
import useCommerceCart, { UseCart } from '@commerce/cart/use-cart'
|
||||||
import type { SwrOptions } from '@commerce/utils/use-data'
|
import { BigcommerceProvider } from '..'
|
||||||
import useResponse from '@commerce/utils/use-response'
|
|
||||||
import useCommerceCart, { CartInput } from '@commerce/cart/use-cart'
|
|
||||||
import { normalizeCart } from '../lib/normalize'
|
|
||||||
import type { Cart, BigcommerceCart } from '../types'
|
|
||||||
|
|
||||||
const defaultOpts = {
|
export default useCommerceCart as UseCart<BigcommerceProvider>
|
||||||
url: '/api/bigcommerce/cart',
|
|
||||||
method: 'GET',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const fetcher: HookFetcher<Cart | null, CartInput> = async (
|
|
||||||
options,
|
|
||||||
{ cartId },
|
|
||||||
fetch
|
|
||||||
) => {
|
|
||||||
const data = cartId
|
|
||||||
? await fetch<BigcommerceCart>({ ...defaultOpts, ...options })
|
|
||||||
: null
|
|
||||||
return data && normalizeCart(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extendHook(
|
|
||||||
customFetcher: typeof fetcher,
|
|
||||||
swrOptions?: SwrOptions<Cart | null, CartInput>
|
|
||||||
) {
|
|
||||||
const useCart = () => {
|
|
||||||
const response = useCommerceCart(defaultOpts, [], customFetcher, {
|
|
||||||
revalidateOnFocus: false,
|
|
||||||
...swrOptions,
|
|
||||||
})
|
|
||||||
const res = useResponse(response, {
|
|
||||||
descriptors: {
|
|
||||||
isEmpty: {
|
|
||||||
get() {
|
|
||||||
return (response.data?.lineItems.length ?? 0) <= 0
|
|
||||||
},
|
|
||||||
enumerable: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
useCart.extend = extendHook
|
|
||||||
|
|
||||||
return useCart
|
|
||||||
}
|
|
||||||
|
|
||||||
export default extendHook(fetcher)
|
|
||||||
|
@ -49,14 +49,18 @@ const fetcher: Fetcher<any> = async ({
|
|||||||
throw await getError(res)
|
throw await getError(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
const useCart: HookHandler<Cart, CartInput> = {
|
const useCart: HookHandler<Cart, CartInput, any, any, { isEmpty?: boolean }> = {
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
url: '/api/bigcommerce/cart',
|
url: '/api/bigcommerce/cart',
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
},
|
},
|
||||||
fetcher(context) {
|
swrOptions: {
|
||||||
return undefined as any
|
revalidateOnFocus: false,
|
||||||
},
|
},
|
||||||
|
// fetcher(context) {
|
||||||
|
// return undefined as any
|
||||||
|
// },
|
||||||
|
normalizer: normalizeCart,
|
||||||
onResponse(response) {
|
onResponse(response) {
|
||||||
return Object.create(response, {
|
return Object.create(response, {
|
||||||
isEmpty: {
|
isEmpty: {
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import Cookies from 'js-cookie'
|
|
||||||
import type { HookInput, HookFetcher, HookFetcherOptions } from '../utils/types'
|
|
||||||
import useData, { ResponseState, SwrOptions } from '../utils/use-data'
|
|
||||||
import type { Cart } from '../types'
|
|
||||||
import { useCommerce } from '..'
|
|
||||||
|
|
||||||
export type CartResponse<Data> = ResponseState<Data> & { isEmpty?: boolean }
|
|
||||||
|
|
||||||
// Input expected by the `useCart` hook
|
|
||||||
export type CartInput = {
|
|
||||||
cartId?: Cart['id']
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function useCart<Data extends Cart | null>(
|
|
||||||
options: HookFetcherOptions,
|
|
||||||
input: HookInput,
|
|
||||||
fetcherFn: HookFetcher<Data, CartInput>,
|
|
||||||
swrOptions?: SwrOptions<Data, CartInput>
|
|
||||||
): CartResponse<Data> {
|
|
||||||
const { providerRef, 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
|
|
||||||
}
|
|
@ -1,28 +1,46 @@
|
|||||||
|
import { useMemo } from 'react'
|
||||||
import Cookies from 'js-cookie'
|
import Cookies from 'js-cookie'
|
||||||
import type { HookInput, HookFetcher, HookFetcherOptions } from '../utils/types'
|
|
||||||
import useData, { ResponseState, SwrOptions } from '../utils/use-data'
|
|
||||||
import type { Cart } from '../types'
|
import type { Cart } from '../types'
|
||||||
import { useCommerce } from '..'
|
import type { HookFetcherFn } from '../utils/types'
|
||||||
|
import useData from '../utils/use-data-2'
|
||||||
export type CartResponse<Data> = ResponseState<Data> & { isEmpty?: boolean }
|
import { Provider, useCommerce } from '..'
|
||||||
|
|
||||||
// Input expected by the `useCart` hook
|
// Input expected by the `useCart` hook
|
||||||
export type CartInput = {
|
export type CartInput = {
|
||||||
cartId?: Cart['id']
|
cartId?: Cart['id']
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function useCart<Data extends Cart | null>(
|
export type CartResponse<P extends Provider> = ReturnType<
|
||||||
options: HookFetcherOptions,
|
NonNullable<NonNullable<NonNullable<P['cart']>['useCart']>['onResponse']>
|
||||||
input: HookInput,
|
>
|
||||||
fetcherFn: HookFetcher<Data, CartInput>,
|
|
||||||
swrOptions?: SwrOptions<Data, CartInput>
|
|
||||||
): CartResponse<Data> {
|
|
||||||
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
|
export type UseCart<P extends Provider> = () => CartResponse<P>
|
||||||
|
|
||||||
|
export const fetcher: HookFetcherFn<Cart | null, CartInput> = async ({
|
||||||
|
options,
|
||||||
|
input: { cartId },
|
||||||
|
fetch,
|
||||||
|
normalize,
|
||||||
|
}) => {
|
||||||
|
const data = cartId ? await fetch({ ...options }) : null
|
||||||
|
return data && normalize ? normalize(data) : data
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useCart<P extends Provider>() {
|
||||||
|
const { providerRef, cartCookie } = useCommerce<P>()
|
||||||
|
|
||||||
|
const provider = providerRef.current
|
||||||
|
const opts = provider.cart?.useCart
|
||||||
|
const fetcherFn = opts?.fetcher ?? fetcher
|
||||||
|
const wrapper: typeof fetcher = (context) => {
|
||||||
|
context.input.cartId = Cookies.get(cartCookie)
|
||||||
|
return fetcherFn(context)
|
||||||
|
}
|
||||||
|
const response = useData(opts!, [], wrapper, opts?.swrOptions)
|
||||||
|
const memoizedResponse = useMemo(
|
||||||
|
() => (opts?.onResponse ? opts.onResponse(response) : response),
|
||||||
|
[response]
|
||||||
|
)
|
||||||
|
|
||||||
|
return memoizedResponse as CartResponse<P>
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,11 @@ export type CartInput = {
|
|||||||
cartId?: Cart['id']
|
cartId?: Cart['id']
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetcher: HookFetcherFn<Cart | null, CartInput> = async ({
|
export type CartResponse<P extends Provider> = ReturnType<
|
||||||
|
NonNullable<NonNullable<NonNullable<P['cart']>['useCart']>['onResponse']>
|
||||||
|
>
|
||||||
|
|
||||||
|
export const fetcher: HookFetcherFn<Cart | null, CartInput> = async ({
|
||||||
options,
|
options,
|
||||||
input: { cartId },
|
input: { cartId },
|
||||||
fetch,
|
fetch,
|
||||||
@ -31,12 +35,11 @@ export default function useFake<P extends Provider>() {
|
|||||||
context.input.cartId = Cookies.get(cartCookie)
|
context.input.cartId = Cookies.get(cartCookie)
|
||||||
return fetcherFn(context)
|
return fetcherFn(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = useData(options, [], wrapper, opts?.swrOptions)
|
const response = useData(options, [], wrapper, opts?.swrOptions)
|
||||||
const memoizedResponse = useMemo(
|
const memoizedResponse = useMemo(
|
||||||
() => (opts?.onResponse ? opts.onResponse(response) : response),
|
() => (opts?.onResponse ? opts.onResponse(response) : response),
|
||||||
[response]
|
[response]
|
||||||
)
|
)
|
||||||
|
|
||||||
return memoizedResponse
|
return memoizedResponse as CartResponse<P>
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,11 @@ export type Provider = CommerceConfig & {
|
|||||||
cartNormalizer(data: any): Cart
|
cartNormalizer(data: any): Cart
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HookHandler<Data, Input, Result = any, Body = any> = {
|
export type HookHandler<Data, Input, Result = any, Body = any, State = {}> = {
|
||||||
swrOptions?: SwrOptions<Data | null, Input, Result>
|
swrOptions?: SwrOptions<Data | null, Input, Result>
|
||||||
onResponse?(response: ResponseState<Data | null>): ResponseState<Data | null>
|
onResponse?(
|
||||||
|
response: ResponseState<Data | null>
|
||||||
|
): ResponseState<Data | null> & State
|
||||||
onMutation?: any
|
onMutation?: any
|
||||||
fetchOptions?: HookFetcherOptions
|
fetchOptions?: HookFetcherOptions
|
||||||
} & (
|
} & (
|
||||||
|
@ -7,7 +7,7 @@ import type {
|
|||||||
} from './types'
|
} from './types'
|
||||||
import defineProperty from './define-property'
|
import defineProperty from './define-property'
|
||||||
import { CommerceError } from './errors'
|
import { CommerceError } from './errors'
|
||||||
import { useCommerce } from '..'
|
import { HookHandler, useCommerce } from '..'
|
||||||
|
|
||||||
export type SwrOptions<Data, Input = null, Result = any> = ConfigInterface<
|
export type SwrOptions<Data, Input = null, Result = any> = ConfigInterface<
|
||||||
Data,
|
Data,
|
||||||
@ -20,7 +20,7 @@ export type ResponseState<Result> = responseInterface<Result, CommerceError> & {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type UseData = <Data = any, Input = null, Result = any>(
|
export type UseData = <Data = any, Input = null, Result = any>(
|
||||||
options: HookFetcherOptions | (() => HookFetcherOptions | null),
|
options: HookHandler<Data, Input, Result>,
|
||||||
input: HookInput,
|
input: HookInput,
|
||||||
fetcherFn: HookFetcherFn<Data, Input, Result>,
|
fetcherFn: HookFetcherFn<Data, Input, Result>,
|
||||||
swrOptions?: SwrOptions<Data, Input, Result>
|
swrOptions?: SwrOptions<Data, Input, Result>
|
||||||
@ -43,6 +43,7 @@ const useData: UseData = (options, input, fetcherFn, swrOptions) => {
|
|||||||
return obj
|
return obj
|
||||||
}, {}),
|
}, {}),
|
||||||
fetch: fetcherRef.current,
|
fetch: fetcherRef.current,
|
||||||
|
normalize: options.normalizer,
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// SWR will not log errors, but any error that's not an instance
|
// SWR will not log errors, but any error that's not an instance
|
||||||
@ -55,7 +56,7 @@ const useData: UseData = (options, input, fetcherFn, swrOptions) => {
|
|||||||
}
|
}
|
||||||
const response = useSWR(
|
const response = useSWR(
|
||||||
() => {
|
() => {
|
||||||
const opts = typeof options === 'function' ? options() : options
|
const opts = options.fetchOptions
|
||||||
return opts
|
return opts
|
||||||
? [opts.url, opts.query, opts.method, ...input.map((e) => e[1])]
|
? [opts.url, opts.query, opts.method, ...input.map((e) => e[1])]
|
||||||
: null
|
: null
|
||||||
|
Loading…
x
Reference in New Issue
Block a user