From ff053db28d2777776966bfdcbaaa8ca96e82f964 Mon Sep 17 00:00:00 2001 From: Joeri de Gooijer Date: Fri, 6 Dec 2024 12:47:40 -0800 Subject: [PATCH 1/3] refactor: Migrate search example to Limitless UI React components --- examples/search/src/App.tsx | 160 +++++++++++++++------------------- examples/search/src/index.tsx | 7 +- 2 files changed, 78 insertions(+), 89 deletions(-) diff --git a/examples/search/src/App.tsx b/examples/search/src/App.tsx index 80ebfe7..4d6db64 100644 --- a/examples/search/src/App.tsx +++ b/examples/search/src/App.tsx @@ -1,19 +1,13 @@ -import { useEffect, useMemo, useState } from "react"; -import parse from "html-react-parser"; +import { useContext, useEffect, useState } from "react"; +import { ToggleField, Pagination, ExternalLinkIcon } from "@bloomreach/react-banana-ui"; +import { Configuration, ProductSearchOptions } from "@bloomreach/discovery-web-sdk"; import { - ToggleField, - InputField, - LoaderIcon, - SearchIcon, - Pagination, - ExternalLinkIcon, -} from "@bloomreach/react-banana-ui"; -import { - Configuration, - ProductSearchOptions, -} from "@bloomreach/discovery-web-sdk"; -import { ProductCard, useSearch, Theme } from '@bloomreach/limitless-ui-react'; -import _ from "lodash"; + ProductCard, + Theme, + SearchContext, + SearchBox, + Results, +} from "@bloomreach/limitless-ui-react"; import Highlighter from "react-highlight-words"; import JsonView from "@uiw/react-json-view"; @@ -24,6 +18,7 @@ import { account_id, account_name, auth_key, domain_key, product_fields } from " import BrLogo from "./assets/br-logo-primary.svg"; import "./app.css"; +import "@bloomreach/limitless-ui-react/style.css"; const config: Configuration = { account_id, @@ -36,12 +31,6 @@ const uid = encodeURIComponent(`uid=12345:v=11.8:ts=${Date.now()}:hc=3`); export default function App() { const [showJson, setShowJson] = useState(false); - // query rendered in the search input - const [query, setQuery] = useState("chair"); - - // query used to make the search API calls, set after debouncing the search input value changes - const [searchQuery, setSearchQuery] = useState("chair"); - // query used to execute the search, in case the search input was auto-corrected by the API const [searchedQuery, setSearchedQuery] = useState(""); const [sort, setSort] = useState(""); @@ -53,49 +42,40 @@ export default function App() { url: window.location.href, ref_url: window.location.href, request_id: Date.now(), - 'facet.version': '3.0', - q: query, + "facet.version": "3.0", start: page * perPage, rows: perPage, sort: sort, - 'stats.field': 'sale_price', - 'query.numeric_precision': 'standard', - br_diagnostic: 'all', - fl: product_fields - } as ProductSearchOptions) + "stats.field": "sale_price", + "query.numeric_precision": "standard", + // br_diagnostic: 'all', + fl: product_fields, + }); - const debouncedUpdateSearchQuery = useMemo(() => _.debounce(updateSearchQuery, 300), []); - const { loading, error, response: data } = useSearch('product', config, options); + const searchContext = useContext(SearchContext); + + if (!searchContext) { + throw new Error("Search Context not provided, can not retrieve results"); + } + const { inputValue, setInputValue, error, searchResponse: data } = searchContext; useEffect(() => { setOptions((opts: ProductSearchOptions) => ({ ...{}, ...opts, ...{ - q: searchQuery, start: page * perPage, rows: perPage, sort: sort, }, })); - }, [searchQuery, page, perPage, sort]); + }, [page, perPage, sort]); useEffect(() => { - setSearchedQuery(data?.autoCorrectQuery || searchQuery); + setSearchedQuery(data?.autoCorrectQuery || inputValue); }, [data]); - function updateSearchQuery(newQuery: string) { - setPage(0); - setSort(""); - setSearchQuery(newQuery); - } - - function updateQuery(newQuery: string) { - setQuery(newQuery); - debouncedUpdateSearchQuery(newQuery); - } - - function updateSort(newSort: string) { + function updateSort(newSort = "") { setPage(0); setSort(newSort); } @@ -110,13 +90,12 @@ export default function App() {
- Account: {account_name} ( - {account_id}) + Account: {account_name} ({account_id})
setShowJson(!showJson)} /> @@ -142,14 +121,21 @@ export default function App() {
- : } - clearable - fullWidth - onChange={(e) => updateQuery(e.target.value)} + updateSort()} + labels={{ + label: "Searchbox", + placeholder: + "Search for chair, bed, office furniture, chiar (for autocorrect), plant (for campaign), bloomreach (for redirect)...", + submit: "Submit", + reset: "Reset", + }} /> + {!!error && (

Error:

@@ -157,7 +143,7 @@ export default function App() {
)} - {searchQuery ? ( + {inputValue ? (
{showJson ? ( <>{data ? : null} @@ -165,11 +151,8 @@ export default function App() {
- Search results for{" "} - {searchedQuery} - {data?.autoCorrectQuery ? ( - (autocorrected) - ) : null} + Search results for {searchedQuery} + {data?.autoCorrectQuery ? (autocorrected) : null} {data?.did_you_mean?.length ? (
Did you mean:{" "} @@ -177,7 +160,7 @@ export default function App() { updateQuery(term)} + onClick={() => setInputValue(term)} > {term} @@ -195,34 +178,33 @@ export default function App() { - - + +
- {data?.keywordRedirect ? : null} - {data?.campaign?.htmlText ?
- {parse(data.campaign.htmlText)} -
: null} + {data?.keywordRedirect ? ( + + ) : null} - {data?.response?.docs?.length ? ( + {data ? (
-
- {data?.response?.docs.map((product) => ( + ( - + - + - ))} -
+ )} + /> + {data?.response?.numFound && data?.response?.numFound > 0 ? (
- updatePerPage(newPerPage) - } + onItemsPerPageChange={(newPerPage) => updatePerPage(newPerPage)} onPageChange={(newPage) => setPage(newPage)} page={page} /> diff --git a/examples/search/src/index.tsx b/examples/search/src/index.tsx index 20c19f4..26f4cee 100644 --- a/examples/search/src/index.tsx +++ b/examples/search/src/index.tsx @@ -2,12 +2,17 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import App from "./App"; +import { LimitlessUIProvider, Theme } from "@bloomreach/limitless-ui-react"; const rootElement = document.getElementById("root") as HTMLElement; const root = createRoot(rootElement); root.render( - + + + + + , ); From e55ad1e99f815a176a8abf97bf8ecb80526bab4a Mon Sep 17 00:00:00 2001 From: Joeri de Gooijer Date: Fri, 6 Dec 2024 15:12:58 -0800 Subject: [PATCH 2/3] refactor: Migrate to Limitless UI Pagination implementation --- examples/search/src/App.tsx | 223 ++++++++++++++++++------------------ 1 file changed, 112 insertions(+), 111 deletions(-) diff --git a/examples/search/src/App.tsx b/examples/search/src/App.tsx index 4d6db64..8a4726a 100644 --- a/examples/search/src/App.tsx +++ b/examples/search/src/App.tsx @@ -1,13 +1,13 @@ import { useContext, useEffect, useState } from "react"; -import { ToggleField, Pagination, ExternalLinkIcon } from "@bloomreach/react-banana-ui"; import { Configuration, ProductSearchOptions } from "@bloomreach/discovery-web-sdk"; import { ProductCard, - Theme, SearchContext, SearchBox, Results, + Pagination, } from "@bloomreach/limitless-ui-react"; + import Highlighter from "react-highlight-words"; import JsonView from "@uiw/react-json-view"; @@ -29,13 +29,11 @@ const config: Configuration = { const uid = encodeURIComponent(`uid=12345:v=11.8:ts=${Date.now()}:hc=3`); export default function App() { - const [showJson, setShowJson] = useState(false); - // query used to execute the search, in case the search input was auto-corrected by the API const [searchedQuery, setSearchedQuery] = useState(""); const [sort, setSort] = useState(""); const [page, setPage] = useState(0); - const [perPage, setPerPage] = useState(12); + const [perPage, setPerPage] = useState(10); const [options, setOptions] = useState({ _br_uid_2: uid, @@ -92,20 +90,12 @@ export default function App() {
Account: {account_name} ({account_id})
- setShowJson(!showJson)} - /> Feedback -
@@ -143,109 +133,120 @@ export default function App() {
)} - {inputValue ? ( + {!!data && (
- {showJson ? ( - <>{data ? : null} - ) : ( - -
-
- Search results for {searchedQuery} - {data?.autoCorrectQuery ? (autocorrected) : null} - {data?.did_you_mean?.length ? ( -
- Did you mean:{" "} - {data.did_you_mean.map((term) => ( - setInputValue(term)} - > - {term} - - ))} -
- ) : null} -
- -
- -
+
+
+
+ Search results for {searchedQuery} + {data?.autoCorrectQuery ? (autocorrected) : null} + {data?.did_you_mean?.length ? ( +
+ Did you mean:{" "} + {data.did_you_mean.map((term) => ( + setInputValue(term)} + > + {term} + + ))} +
+ ) : null}
- {data?.keywordRedirect ? ( - - ) : null} - - {data ? ( -
- ( - - - - - - - {product.variants?.length > 1 ? ( - {`${product.variants.length} variants`} - ) : null} - - - - - - )} - /> - - {data?.response?.numFound && data?.response?.numFound > 0 ? ( -
- updatePerPage(newPerPage)} - onPageChange={(newPage) => setPage(newPage)} - page={page} +
+ +
+
+ + {data?.keywordRedirect ? ( + + ) : null} + + {data ? ( +
+ ( + + + + + + + {product.variants?.length > 1 ? ( + {`${product.variants.length} variants`} + ) : null} + + + + + + )} + /> + + {data?.response?.numFound && data?.response?.numFound > 0 && ( +
+ + `Showing ${start} to ${end} of ${total}`} /> -
- ) : null} -
- ) : ( -
No results!
- )} - - )} + + + + + + + + + + + + +
+ )} +
+ ) : ( +
No results!
+ )} +
- ) : null} + )}