diff --git a/src/search/hooks/productSearch.hook.ts b/src/search/hooks/productSearch.hook.ts deleted file mode 100644 index fbc32d8..0000000 --- a/src/search/hooks/productSearch.hook.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { - Configuration, - ProductSearchOptions, - SearchResponse, - productSearch, -} from '@bloomreach/discovery-web-sdk'; -import { useEffect, useMemo, useState } from 'react'; - -type UseProductSearchResult = { - response: SearchResponse | null; - loading: boolean; - error: unknown; -}; - -/** - * Custom hook to perform a product search using Bloomreach Discovery Web SDK. - * - * @param query - The search query string. - * @param configuration - The configuration object for the Bloomreach SDK. - * @param searchOptions - Additional search options excluding the query. - * @returns An object containing the search response, loading state, and any error encountered. - */ -export function useProductSearch( - query: string, - configuration: Configuration, - searchOptions: Omit, -): UseProductSearchResult { - const [response, setResponse] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - // Memoize the search options to avoid unnecessary re-renders - const memoizedSearchOptions = useMemo( - () => ({ ...searchOptions, q: query }), - [query, searchOptions], - ); - - useEffect(() => { - setLoading(true); - - productSearch(configuration, memoizedSearchOptions) - .then((response: SearchResponse) => { - setResponse(response); - }) - .catch((e: unknown) => { - setError(e); - }) - .finally(() => { - setLoading(false); - }); - }, [configuration, memoizedSearchOptions]); - - return { response, loading, error }; -} diff --git a/src/search/hooks/search.hook.ts b/src/search/hooks/search.hook.ts new file mode 100644 index 0000000..af59f24 --- /dev/null +++ b/src/search/hooks/search.hook.ts @@ -0,0 +1,80 @@ +import { + BestsellerOptions, + CategorySearchOptions, + Configuration, + ContentSearchOptions, + ProductSearchOptions, + SearchResponse, + bestseller, + categorySearch, + contentSearch, + productSearch, +} from '@bloomreach/discovery-web-sdk'; +import { useEffect, useState } from 'react'; +import { SearchType } from '../search-box/search-box.types'; + +type SearchOptions = + | ProductSearchOptions + | CategorySearchOptions + | ContentSearchOptions + | BestsellerOptions; + +type UseSearch = { + response: SearchResponse | null; + loading: boolean; + error: unknown; +}; + +/** + * Custom hook to perform a product search using Bloomreach Discovery Web SDK. + * + * @param query - The search query string. + * @param configuration - The configuration object for the Bloomreach SDK. + * @param searchOptions - Additional search options excluding the query. + * @returns An object containing the search response, loading state, and any error encountered. + */ +export function useSearch( + searchType: SearchType, + configuration: Configuration, + searchOptions: SearchOptions, +): UseSearch { + const [response, setResponse] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchData = async () => { + setLoading(true); + + if (searchType === 'product') { + const apiResponse = await productSearch(configuration, searchOptions as ProductSearchOptions); + setResponse(apiResponse); + } + + if (searchType === 'category') { + const apiResponse = await categorySearch(configuration, searchOptions as CategorySearchOptions); + setResponse(apiResponse); + } + + if (searchType === 'content') { + const apiResponse = await contentSearch(configuration, searchOptions as ContentSearchOptions); + setResponse(apiResponse); + } + + if (searchType === 'bestseller') { + const apiResponse = await bestseller(configuration, searchOptions as BestsellerOptions); + setResponse(apiResponse); + } + }; + + fetchData() + .catch((e: unknown) => { + setError(e); + }) + .finally(() => { + setLoading(false); + }); + }, [searchType, configuration, searchOptions]); + + return { response, loading, error }; +} diff --git a/src/search/search-box/search-box.hook.ts b/src/search/search-box/search-box.hook.ts index 79bfa24..e90a2c3 100644 --- a/src/search/search-box/search-box.hook.ts +++ b/src/search/search-box/search-box.hook.ts @@ -4,27 +4,42 @@ import { useCallback, useContext, useEffect, + useMemo, useState, } from 'react'; import { debounce } from '../../utils/debounce'; import { SearchContext } from '../context/search.context'; -import { useProductSearch } from '../hooks/productSearch.hook'; +import { useSearch } from '../hooks/search.hook'; import { SearchBoxProps } from './search-box.types'; +import { SearchResponse } from '@bloomreach/discovery-web-sdk'; type UseSearchBox = { + response: SearchResponse | null; + loading: boolean; + error: unknown; changeHandler: ChangeEventHandler; }; export function useSearchBox(props: SearchBoxProps): UseSearchBox { - const { configuration, searchOptions, debounceDelay } = props; + const { configuration, searchOptions, debounceDelay, searchType } = props; const [query, setQuery] = useState(''); const debouncedSetQuery = debounce((event: ChangeEvent) => { setQuery(event.target.value); }, debounceDelay ?? 500); - const { response } = useProductSearch(query, configuration, searchOptions); + + const memoizedSearchOptions = useMemo( + () => ({ + ...searchOptions, + q: query, + }), + [query, searchOptions], + ); + + const { response, error, loading } = useSearch(searchType, configuration, memoizedSearchOptions); const searchContext = useContext(SearchContext); + useEffect(() => { if (response) { searchContext.setSearchResponse(response); @@ -34,6 +49,9 @@ export function useSearchBox(props: SearchBoxProps): UseSearchBox { const changeHandler = useCallback(debouncedSetQuery, [debouncedSetQuery]); return { + response, + error, + loading, changeHandler, }; } diff --git a/src/search/search-box/search-box.stories.tsx b/src/search/search-box/search-box.stories.tsx index bb30802..feb6e62 100644 --- a/src/search/search-box/search-box.stories.tsx +++ b/src/search/search-box/search-box.stories.tsx @@ -32,7 +32,7 @@ export const Basic: Story = { {({ searchResponse }) => searchResponse?.response?.docs?.map((result) => { return ( -
+

{result.title}

{result.description}

@@ -58,5 +58,6 @@ export const Basic: Story = { start: 0, url: 'https://example.com', }, + searchType: 'product' }, }; diff --git a/src/search/search-box/search-box.tsx b/src/search/search-box/search-box.tsx index cbc77db..74b8edc 100644 --- a/src/search/search-box/search-box.tsx +++ b/src/search/search-box/search-box.tsx @@ -32,6 +32,7 @@ import type { SearchBoxProps } from './search-box.types'; * * @@ -56,7 +57,15 @@ import type { SearchBoxProps } from './search-box.types'; */ export const SearchBox = forwardRef( (props: SearchBoxProps, forwardedRef: ForwardedRef | null): ReactElement => { - const { children, className, configuration, searchOptions, debounceDelay, ...rest } = props; + const { + children, + className, + configuration, + searchOptions, + debounceDelay, + searchType, + ...rest + } = props; const { changeHandler } = useSearchBox(props); return ( diff --git a/src/search/search-box/search-box.types.ts b/src/search/search-box/search-box.types.ts index e6ad288..a88ddb8 100644 --- a/src/search/search-box/search-box.types.ts +++ b/src/search/search-box/search-box.types.ts @@ -22,4 +22,14 @@ export interface SearchBoxProps extends PropsWithChildren { * The options specific to a Bloormeach search e.g. `q` and `fl` */ searchOptions: Omit; + + /** + * The type of search. + */ + searchType: SearchType; } + +/** + * The type of search. + */ +export type SearchType = 'product' | 'category' | 'content' | 'bestseller';