4
0
forked from crowetic/commerce

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 useSearch, { UseSearch } from '@commerce/products/use-search'
import type { SwrOptions } from '@commerce/utils/use-data' import type { BigcommerceProvider } from '..'
import useCommerceSearch from '@commerce/products/use-search'
import type { SearchProductsData } from '../api/catalog/products'
const defaultOpts = { export default useSearch as UseSearch<BigcommerceProvider>
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)

View File

@ -5,6 +5,7 @@ import type { FetchCartInput } from '@commerce/cart/use-cart'
import { normalizeCart } from './lib/normalize' import { normalizeCart } from './lib/normalize'
import type { Wishlist } from './api/wishlist' import type { Wishlist } from './api/wishlist'
import type { Customer, CustomerData } from './api/customers' import type { Customer, CustomerData } from './api/customers'
import type { SearchProductsData } from './api/catalog/products'
import useCustomer from './customer/use-customer' import useCustomer from './customer/use-customer'
import type { Cart } from './types' 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 = { export const bigcommerceProvider = {
locale: 'en-us', locale: 'en-us',
cartCookie: 'bc_cartId', cartCookie: 'bc_cartId',
@ -161,6 +212,7 @@ export const bigcommerceProvider = {
cart: { useCart }, cart: { useCart },
wishlist: { useWishlist }, wishlist: { useWishlist },
customer: { useCustomer: useCustomerHandler }, customer: { useCustomer: useCustomerHandler },
products: { useSearch },
} }
export type BigcommerceProvider = typeof bigcommerceProvider export type BigcommerceProvider = typeof bigcommerceProvider

View File

@ -8,7 +8,7 @@ import {
} from 'react' } from 'react'
import { Fetcher, HookHandler } from './utils/types' import { Fetcher, HookHandler } from './utils/types'
import type { FetchCartInput } from './cart/use-cart' 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> | {}>({}) const Commerce = createContext<CommerceContextValue<any> | {}>({})
@ -23,6 +23,9 @@ export type Provider = CommerceConfig & {
customer: { customer: {
useCustomer?: HookHandler<Customer | null, any, any> useCustomer?: HookHandler<Customer | null, any, any>
} }
products: {
useSearch?: HookHandler<SearchProductsData, any, any>
}
} }
export type CommerceProps<P extends Provider> = { 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 { Wishlist as BCWishlist } from '@framework/api/wishlist'
import type { Customer as BCCustomer } from '@framework/api/customers' import type { Customer as BCCustomer } from '@framework/api/customers'
import type { SearchProductsData as BCSearchProductsData } from '@framework/api/catalog/products'
export interface Discount { export interface Discount {
// The value of the discount, can be an amount or percentage // 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 // TODO: Properly define this type
export interface Customer extends BCCustomer {} export interface Customer extends BCCustomer {}
// TODO: Properly define this type
export interface SearchProductsData extends BCSearchProductsData {}
/** /**
* Cart mutations * Cart mutations
*/ */