diff --git a/framework/bigcommerce/auth/use-login.tsx b/framework/bigcommerce/auth/use-login.tsx index fa2294666..b66fca493 100644 --- a/framework/bigcommerce/auth/use-login.tsx +++ b/framework/bigcommerce/auth/use-login.tsx @@ -1,54 +1,40 @@ import { useCallback } from 'react' -import type { HookFetcher } from '@commerce/utils/types' +import type { MutationHook } from '@commerce/utils/types' import { CommerceError } from '@commerce/utils/errors' -import useCommerceLogin from '@commerce/use-login' +import useLogin, { UseLogin } from '@commerce/use-login' import type { LoginBody } from '../api/customers/login' import useCustomer from '../customer/use-customer' -const defaultOpts = { - url: '/api/bigcommerce/customers/login', - method: 'POST', -} +export default useLogin as UseLogin -export type LoginInput = LoginBody +export const handler: MutationHook = { + fetchOptions: { + url: '/api/bigcommerce/customers/login', + method: 'POST', + }, + async fetcher({ input: { email, password }, options, fetch }) { + if (!(email && password)) { + throw new CommerceError({ + message: + 'A first name, last name, email and password are required to login', + }) + } -export const fetcher: HookFetcher = ( - options, - { email, password }, - fetch -) => { - if (!(email && password)) { - throw new CommerceError({ - message: - 'A first name, last name, email and password are required to login', + return fetch({ + ...options, + body: { email, password }, }) - } - - return fetch({ - ...defaultOpts, - ...options, - body: { email, password }, - }) -} - -export function extendHook(customFetcher: typeof fetcher) { - const useLogin = () => { + }, + useHook: ({ fetch }) => () => { const { revalidate } = useCustomer() - const fn = useCommerceLogin(defaultOpts, customFetcher) return useCallback( - async function login(input: LoginInput) { - const data = await fn(input) + async function login(input) { + const data = await fetch({ input }) await revalidate() return data }, - [fn] + [fetch, revalidate] ) - } - - useLogin.extend = extendHook - - return useLogin + }, } - -export default extendHook(fetcher) diff --git a/framework/bigcommerce/auth/use-logout.tsx b/framework/bigcommerce/auth/use-logout.tsx index 6aaee29f9..6278a4dd1 100644 --- a/framework/bigcommerce/auth/use-logout.tsx +++ b/framework/bigcommerce/auth/use-logout.tsx @@ -1,38 +1,25 @@ import { useCallback } from 'react' -import type { HookFetcher } from '@commerce/utils/types' -import useCommerceLogout from '@commerce/use-logout' +import type { MutationHook } from '@commerce/utils/types' +import useLogout, { UseLogout } from '@commerce/use-logout' import useCustomer from '../customer/use-customer' -const defaultOpts = { - url: '/api/bigcommerce/customers/logout', - method: 'GET', -} +export default useLogout as UseLogout -export const fetcher: HookFetcher = (options, _, fetch) => { - return fetch({ - ...defaultOpts, - ...options, - }) -} - -export function extendHook(customFetcher: typeof fetcher) { - const useLogout = () => { +export const handler: MutationHook = { + fetchOptions: { + url: '/api/bigcommerce/customers/logout', + method: 'GET', + }, + useHook: ({ fetch }) => () => { const { mutate } = useCustomer() - const fn = useCommerceLogout(defaultOpts, customFetcher) return useCallback( - async function login() { - const data = await fn(null) + async function logout() { + const data = await fetch() await mutate(null, false) return data }, - [fn] + [fetch, mutate] ) - } - - useLogout.extend = extendHook - - return useLogout + }, } - -export default extendHook(fetcher) diff --git a/framework/bigcommerce/provider.ts b/framework/bigcommerce/provider.ts index bd2fbe34f..40bdc2c06 100644 --- a/framework/bigcommerce/provider.ts +++ b/framework/bigcommerce/provider.ts @@ -9,6 +9,9 @@ import { handler as useWishlistRemoveItem } from './wishlist/use-remove-item' import { handler as useCustomer } from './customer/use-customer' import { handler as useSearch } from './product/use-search' + +import { handler as useLogin } from './auth/use-login' + import fetcher from './fetcher' export const bigcommerceProvider = { @@ -23,6 +26,7 @@ export const bigcommerceProvider = { }, customer: { useCustomer }, products: { useSearch }, + auth: { useLogin }, } export type BigcommerceProvider = typeof bigcommerceProvider diff --git a/framework/commerce/cart/use-add-item.tsx b/framework/commerce/cart/use-add-item.tsx index 13da6b416..324464656 100644 --- a/framework/commerce/cart/use-add-item.tsx +++ b/framework/commerce/cart/use-add-item.tsx @@ -1,18 +1,18 @@ import { useHook, useMutationHook } from '../utils/use-hook' import { mutationFetcher } from '../utils/default-fetcher' -import type { MutationHook, HookFetcherFn } from '../utils/types' +import type { HookFetcherFn, MutationHook } from '../utils/types' import type { Cart, CartItemBody, AddCartItemBody } from '../types' import type { Provider } from '..' +export type UseAddItem< + H extends MutationHook = MutationHook +> = ReturnType + export const fetcher: HookFetcherFn< Cart, AddCartItemBody > = mutationFetcher -export type UseAddItem< - H extends MutationHook = MutationHook -> = ReturnType - const fn = (provider: Provider) => provider.cart?.useAddItem! const useAddItem: UseAddItem = (...args) => { diff --git a/framework/commerce/index.tsx b/framework/commerce/index.tsx index bcaecc1a3..07bf74a22 100644 --- a/framework/commerce/index.tsx +++ b/framework/commerce/index.tsx @@ -25,12 +25,17 @@ export type Provider = CommerceConfig & { useAddItem?: MutationHook useRemoveItem?: MutationHook } - customer: { + customer?: { useCustomer?: SWRHook } - products: { + products?: { useSearch?: SWRHook } + auth?: { + useSignup?: MutationHook + useLogin?: MutationHook + useLogout?: MutationHook + } } export type CommerceProps

= { diff --git a/framework/commerce/use-login.tsx b/framework/commerce/use-login.tsx index 2a251fea3..755e10fd9 100644 --- a/framework/commerce/use-login.tsx +++ b/framework/commerce/use-login.tsx @@ -1,5 +1,19 @@ -import useAction from './utils/use-action' +import { useHook, useMutationHook } from './utils/use-hook' +import { mutationFetcher } from './utils/default-fetcher' +import type { MutationHook, HookFetcherFn } from './utils/types' +import type { Provider } from '.' -const useLogin = useAction +export type UseLogin< + H extends MutationHook = MutationHook +> = ReturnType + +export const fetcher: HookFetcherFn = mutationFetcher + +const fn = (provider: Provider) => provider.auth?.useLogin! + +const useLogin: UseLogin = (...args) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(...args) +} export default useLogin diff --git a/framework/commerce/use-logout.tsx b/framework/commerce/use-logout.tsx index ef3fc4135..0a80c318b 100644 --- a/framework/commerce/use-logout.tsx +++ b/framework/commerce/use-logout.tsx @@ -1,5 +1,19 @@ -import useAction from './utils/use-action' +import { useHook, useMutationHook } from './utils/use-hook' +import { mutationFetcher } from './utils/default-fetcher' +import type { HookFetcherFn, MutationHook } from './utils/types' +import type { Provider } from '.' -const useLogout = useAction +export type UseLogout< + H extends MutationHook = MutationHook +> = ReturnType + +export const fetcher: HookFetcherFn = mutationFetcher + +const fn = (provider: Provider) => provider.auth?.useLogout! + +const useLogout: UseLogout = (...args) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(...args) +} export default useLogout diff --git a/framework/commerce/utils/types.ts b/framework/commerce/utils/types.ts index 2bab3f800..852afb208 100644 --- a/framework/commerce/utils/types.ts +++ b/framework/commerce/utils/types.ts @@ -36,11 +36,11 @@ export type HookFetcher = ( fetch: (options: FetcherOptions) => Promise ) => Data | Promise -export type HookFetcherFn = ( +export type HookFetcherFn = ( context: HookFetcherContext ) => Data | Promise -export type HookFetcherContext = { +export type HookFetcherContext = { options: HookFetcherOptions input: Input fetch: (options: FetcherOptions) => Promise @@ -58,7 +58,7 @@ export type HookSWRInput = [string, HookInputValue][] export type HookFetchInput = { [k: string]: HookInputValue } export type HookFunction< - Input extends { [k: string]: unknown } | {}, + Input extends { [k: string]: unknown } | null, T > = keyof Input extends never ? () => T @@ -115,9 +115,13 @@ export type MutationHook< export type MutationHookContext< Data, - FetchInput extends { [k: string]: unknown } = {} + FetchInput extends { [k: string]: unknown } | null = {} > = { - fetch: (context: { input: FetchInput }) => Data | Promise + fetch: keyof FetchInput extends never + ? () => Data | Promise + : Partial extends FetchInput + ? (context?: { input?: FetchInput }) => Data | Promise + : (context: { input: FetchInput }) => Data | Promise } export type SwrOptions = ConfigInterface< diff --git a/framework/commerce/utils/use-hook.ts b/framework/commerce/utils/use-hook.ts index 79c0808be..da3431e3c 100644 --- a/framework/commerce/utils/use-hook.ts +++ b/framework/commerce/utils/use-hook.ts @@ -37,7 +37,7 @@ export function useMutationHook>( return hook.useHook({ fetch: useCallback( - ({ input }) => { + ({ input } = {}) => { return hook.fetcher({ input, options: hook.fetchOptions,