diff --git a/framework/bigcommerce/index.tsx b/framework/bigcommerce/index.tsx index 83fbdbcbc..b35785ed2 100644 --- a/framework/bigcommerce/index.tsx +++ b/framework/bigcommerce/index.tsx @@ -1,4 +1,4 @@ -import { ReactNode } from 'react' +import type { ReactNode } from 'react' import { CommerceConfig, CommerceProvider as CoreCommerceProvider, diff --git a/framework/bigcommerce/provider.ts b/framework/bigcommerce/provider.ts index b6385546c..e4ab5c757 100644 --- a/framework/bigcommerce/provider.ts +++ b/framework/bigcommerce/provider.ts @@ -43,7 +43,7 @@ const fetcher: Fetcher = async ({ const useCart: HookHandler< Cart | null, - [], + {}, FetchCartInput, any, any, @@ -71,7 +71,7 @@ const useCart: HookHandler< const useWishlist: HookHandler< Cart | null, - [], + {}, FetchCartInput, any, any, diff --git a/framework/commerce/cart/use-cart.tsx b/framework/commerce/cart/use-cart.tsx index b19e609da..8f40fd055 100644 --- a/framework/commerce/cart/use-cart.tsx +++ b/framework/commerce/cart/use-cart.tsx @@ -1,8 +1,8 @@ import { useMemo } from 'react' import Cookies from 'js-cookie' -import type { Cart } from '../types' import type { HookFetcherFn } from '../utils/types' import useData from '../utils/use-data-2' +import type { Cart } from '../types' import { Provider, useCommerce } from '..' export type FetchCartInput = { @@ -13,13 +13,17 @@ export type CartResponse

= ReturnType< NonNullable['useCart']>['onResponse']> > -export type UseCart

= ( - ...input: UseCartInput

-) => CartResponse

+export type UseCartInput

= Parameters< + NonNullable< + NonNullable['useCart']>>['input'] + > +>[0] -export type UseCartInput

= NonNullable< - NonNullable['useCart']>>['input'] -> +export type UseCart

= Partial< + UseCartInput

+> extends UseCartInput

+ ? (input?: UseCartInput

) => CartResponse

+ : (input: UseCartInput

) => CartResponse

export const fetcher: HookFetcherFn = async ({ options, @@ -31,7 +35,7 @@ export const fetcher: HookFetcherFn = async ({ return data && normalize ? normalize(data) : data } -export default function useCart

(...input: UseCartInput

) { +export default function useCart

(input?: UseCartInput

) { const { providerRef, fetcherRef, cartCookie } = useCommerce

() const provider = providerRef.current @@ -43,7 +47,7 @@ export default function useCart

(...input: UseCartInput

) { } const response = useData( { ...opts, fetcher: wrapper }, - input, + opts?.input ? opts.input(input ?? {}) : [], provider.fetcher ?? fetcherRef.current ) const memoizedResponse = useMemo( diff --git a/framework/commerce/index.tsx b/framework/commerce/index.tsx index 82e86947d..fa7e3e7e8 100644 --- a/framework/commerce/index.tsx +++ b/framework/commerce/index.tsx @@ -16,10 +16,10 @@ const Commerce = createContext | {}>({}) export type Provider = CommerceConfig & { fetcher: Fetcher cart?: { - useCart?: HookHandler + useCart?: HookHandler } wishlist?: { - useWishlist?: HookHandler + useWishlist?: HookHandler } } diff --git a/framework/commerce/utils/types.ts b/framework/commerce/utils/types.ts index d84ec07f0..6b4f1ddbe 100644 --- a/framework/commerce/utils/types.ts +++ b/framework/commerce/utils/types.ts @@ -4,11 +4,15 @@ import type { ResponseState } from './use-data' export type Override = Omit & K -// Returns the properties in T with the properties in type K changed from optional to required +/** + * Returns the properties in T with the properties in type K changed from optional to required + */ export type PickRequired = Omit & Required> -// Core fetcher added by CommerceProvider +/** + * Core fetcher added by CommerceProvider + */ export type Fetcher = ( options: FetcherOptions ) => T | Promise @@ -47,15 +51,17 @@ export type HookFetcherOptions = { export type HookInputValue = string | number | boolean | undefined -export type HookInput = [string, HookInputValue][] +export type HookSwrInput = [string, HookInputValue][] export type HookFetchInput = { [k: string]: HookInputValue } +export type HookInput = {} + export type HookHandler< // Data obj returned by the hook and fetch operation Data, // Input expected by the hook - Input = [...any], + Input extends { [k: string]: unknown } = {}, // Input expected before doing a fetch operation FetchInput extends HookFetchInput = never, // Data returned by the API after a fetch operation @@ -65,7 +71,9 @@ export type HookHandler< // Custom state added to the response object of SWR State = {} > = { - input?: Input + input?( + input: Input & { swrOptions?: SwrOptions } + ): HookFetchInput | HookSwrInput swrOptions?: SwrOptions onResponse?(response: ResponseState): ResponseState & State onMutation?: any diff --git a/framework/commerce/utils/use-data-2.ts b/framework/commerce/utils/use-data-2.ts index 5536bb02c..d9a9e9a39 100644 --- a/framework/commerce/utils/use-data-2.ts +++ b/framework/commerce/utils/use-data-2.ts @@ -1,7 +1,7 @@ import useSWR, { responseInterface } from 'swr' import type { HookHandler, - HookInput, + HookSwrInput, HookFetchInput, PickRequired, Fetcher, @@ -15,7 +15,7 @@ export type ResponseState = responseInterface & { export type UseData = < Data = any, - Input = [...any], + Input extends { [k: string]: unknown } = {}, FetchInput extends HookFetchInput = never, Result = any, Body = any @@ -24,11 +24,12 @@ export type UseData = < HookHandler, 'fetcher' >, - input: HookInput, + input: HookFetchInput | HookSwrInput, fetcherFn: Fetcher ) => ResponseState const useData: UseData = (options, input, fetcherFn) => { + const hookInput = Array.isArray(input) ? input : Object.entries(input) const fetcher = async ( url?: string, query?: string, @@ -40,7 +41,7 @@ const useData: UseData = (options, input, fetcherFn) => { options: { url, query, method }, // Transform the input array into an object input: args.reduce((obj, val, i) => { - obj[input[i][0]!] = val + obj[hookInput[i][0]!] = val return obj }, {}), fetch: fetcherFn, @@ -59,7 +60,7 @@ const useData: UseData = (options, input, fetcherFn) => { () => { const opts = options.fetchOptions return opts - ? [opts.url, opts.query, opts.method, ...input.map((e) => e[1])] + ? [opts.url, opts.query, opts.method, ...hookInput.map((e) => e[1])] : null }, fetcher, diff --git a/framework/commerce/utils/use-data.tsx b/framework/commerce/utils/use-data.tsx index 38af46a44..58a1a0a47 100644 --- a/framework/commerce/utils/use-data.tsx +++ b/framework/commerce/utils/use-data.tsx @@ -1,5 +1,5 @@ import useSWR, { ConfigInterface, responseInterface } from 'swr' -import type { HookInput, HookFetcher, HookFetcherOptions } from './types' +import type { HookSwrInput, HookFetcher, HookFetcherOptions } from './types' import defineProperty from './define-property' import { CommerceError } from './errors' import { useCommerce } from '..' @@ -16,7 +16,7 @@ export type ResponseState = responseInterface & { export type UseData = ( options: HookFetcherOptions | (() => HookFetcherOptions | null), - input: HookInput, + input: HookSwrInput, fetcherFn: HookFetcher, swrOptions?: SwrOptions ) => ResponseState diff --git a/framework/commerce/wishlist/use-wishlist.tsx b/framework/commerce/wishlist/use-wishlist.tsx index df8bebe5c..5272766c6 100644 --- a/framework/commerce/wishlist/use-wishlist.tsx +++ b/framework/commerce/wishlist/use-wishlist.tsx @@ -1,4 +1,8 @@ -import type { HookInput, HookFetcher, HookFetcherOptions } from '../utils/types' +import type { + HookSwrInput, + HookFetcher, + HookFetcherOptions, +} from '../utils/types' import useData, { ResponseState, SwrOptions } from '../utils/use-data' export type WishlistResponse = ResponseState & { @@ -7,7 +11,7 @@ export type WishlistResponse = ResponseState & { export default function useWishlist( options: HookFetcherOptions, - input: HookInput, + input: HookSwrInput, fetcherFn: HookFetcher, swrOptions?: SwrOptions ): WishlistResponse {