Moved useSearch to the new hook

This commit is contained in:
Luis Alvarez 2021-02-12 12:17:36 -05:00
parent 883fbcbcb9
commit 1549368c88
5 changed files with 118 additions and 66 deletions

View File

@ -1,63 +1,4 @@
import type { HookFetcher } from '@commerce/utils/types'
import type { SwrOptions } from '@commerce/utils/use-data'
import useCommerceSearch from '@commerce/products/use-search'
import type { SearchProductsData } from '../api/catalog/products'
import useSearch, { UseSearch } from '@commerce/products/use-search'
import type { BigcommerceProvider } from '..'
const defaultOpts = {
url: '/api/bigcommerce/catalog/products',
method: 'GET',
}
export type SearchProductsInput = {
search?: string
categoryId?: number
brandId?: number
sort?: string
}
export const fetcher: HookFetcher<SearchProductsData, SearchProductsInput> = (
options,
{ search, categoryId, brandId, sort },
fetch
) => {
// Use a dummy base as we only care about the relative path
const url = new URL(options?.url ?? defaultOpts.url, 'http://a')
if (search) url.searchParams.set('search', search)
if (Number.isInteger(categoryId))
url.searchParams.set('category', String(categoryId))
if (Number.isInteger(brandId)) url.searchParams.set('brand', String(brandId))
if (sort) url.searchParams.set('sort', sort)
return fetch({
url: url.pathname + url.search,
method: options?.method ?? defaultOpts.method,
})
}
export function extendHook(
customFetcher: typeof fetcher,
swrOptions?: SwrOptions<SearchProductsData, SearchProductsInput>
) {
const useSearch = (input: SearchProductsInput = {}) => {
const response = useCommerceSearch(
defaultOpts,
[
['search', input.search],
['categoryId', input.categoryId],
['brandId', input.brandId],
['sort', input.sort],
],
customFetcher,
{ revalidateOnFocus: false, ...swrOptions }
)
return response
}
useSearch.extend = extendHook
return useSearch
}
export default extendHook(fetcher)
export default useSearch as UseSearch<BigcommerceProvider>

View File

@ -5,6 +5,7 @@ import type { FetchCartInput } from '@commerce/cart/use-cart'
import { normalizeCart } from './lib/normalize'
import type { Wishlist } from './api/wishlist'
import type { Customer, CustomerData } from './api/customers'
import type { SearchProductsData } from './api/catalog/products'
import useCustomer from './customer/use-customer'
import type { Cart } from './types'
@ -153,6 +154,56 @@ const useCustomerHandler: HookHandler<
},
}
export type SearchProductsInput = {
search?: string
categoryId?: number
brandId?: number
sort?: string
}
const useSearch: HookHandler<
SearchProductsData,
SearchProductsInput,
SearchProductsInput,
any,
any
> = {
fetchOptions: {
url: '/api/bigcommerce/catalog/products',
method: 'GET',
},
fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) {
// Use a dummy base as we only care about the relative path
const url = new URL(options.url!, 'http://a')
if (search) url.searchParams.set('search', search)
if (Number.isInteger(categoryId))
url.searchParams.set('category', String(categoryId))
if (Number.isInteger(brandId))
url.searchParams.set('brand', String(brandId))
if (sort) url.searchParams.set('sort', sort)
return fetch({
url: url.pathname + url.search,
method: options.method,
})
},
useHook({ input, useData }) {
return useData({
input: [
['search', input.search],
['categoryId', input.categoryId],
['brandId', input.brandId],
['sort', input.sort],
],
swrOptions: {
revalidateOnFocus: false,
...input.swrOptions,
},
})
},
}
export const bigcommerceProvider = {
locale: 'en-us',
cartCookie: 'bc_cartId',
@ -161,6 +212,7 @@ export const bigcommerceProvider = {
cart: { useCart },
wishlist: { useWishlist },
customer: { useCustomer: useCustomerHandler },
products: { useSearch },
}
export type BigcommerceProvider = typeof bigcommerceProvider

View File

@ -8,7 +8,7 @@ import {
} from 'react'
import { Fetcher, HookHandler } from './utils/types'
import type { FetchCartInput } from './cart/use-cart'
import type { Cart, Wishlist, Customer } from './types'
import type { Cart, Wishlist, Customer, SearchProductsData } from './types'
const Commerce = createContext<CommerceContextValue<any> | {}>({})
@ -23,6 +23,9 @@ export type Provider = CommerceConfig & {
customer: {
useCustomer?: HookHandler<Customer | null, any, any>
}
products: {
useSearch?: HookHandler<SearchProductsData, any, any>
}
}
export type CommerceProps<P extends Provider> = {

View File

@ -1,5 +1,57 @@
import useData from '../utils/use-data'
import type { SearchProductsData } from '../types'
import type {
Prop,
HookFetcherFn,
UseHookInput,
UseHookResponse,
} from '../utils/types'
import defaultFetcher from '../utils/default-fetcher'
import useData from '../utils/use-data-2'
import { Provider, useCommerce } from '..'
import { BigcommerceProvider } from '@framework'
const useSearch = useData
export type UseSearchHandler<P extends Provider> = Prop<
Prop<P, 'products'>,
'useSearch'
>
export default useSearch
export type UseSeachInput<P extends Provider> = UseHookInput<
UseSearchHandler<P>
>
export type SearchResponse<P extends Provider> = UseHookResponse<
UseSearchHandler<P>
>
export type UseSearch<P extends Provider> = Partial<
UseSeachInput<P>
> extends UseSeachInput<P>
? (input?: UseSeachInput<P>) => SearchResponse<P>
: (input: UseSeachInput<P>) => SearchResponse<P>
export const fetcher = defaultFetcher as HookFetcherFn<SearchProductsData>
export default function useSearch<P extends Provider>(
input: UseSeachInput<P> = {}
) {
const { providerRef, fetcherRef } = useCommerce<P>()
const provider = providerRef.current
const opts = provider.products?.useSearch
const fetcherFn = opts?.fetcher ?? fetcher
const useHook = opts?.useHook ?? ((ctx) => ctx.useData())
return useHook({
input,
useData(ctx) {
const response = useData(
{ ...opts!, fetcher: fetcherFn },
ctx?.input ?? [],
provider.fetcher ?? fetcherRef.current,
ctx?.swrOptions ?? input.swrOptions
)
return response
},
})
}

View File

@ -1,5 +1,6 @@
import type { Wishlist as BCWishlist } from '@framework/api/wishlist'
import type { Customer as BCCustomer } from '@framework/api/customers'
import type { SearchProductsData as BCSearchProductsData } from '@framework/api/catalog/products'
export interface Discount {
// The value of the discount, can be an amount or percentage
@ -96,6 +97,9 @@ export interface Wishlist extends BCWishlist {}
// TODO: Properly define this type
export interface Customer extends BCCustomer {}
// TODO: Properly define this type
export interface SearchProductsData extends BCSearchProductsData {}
/**
* Cart mutations
*/