diff --git a/app/search/page.tsx b/app/search/page.tsx index 2f7a53bd4..99e9e7f73 100644 --- a/app/search/page.tsx +++ b/app/search/page.tsx @@ -1,7 +1,7 @@ import Grid from 'components/grid'; import ProductGridItems from 'components/layout/product-grid-items'; -import { defaultSort, sorting } from 'lib/constants'; -import { getProducts } from 'lib/shopify'; +import { orama } from 'lib/orama'; +import { Product } from 'lib/shopify/types'; export const runtime = 'edge'; @@ -16,24 +16,31 @@ export default async function SearchPage({ searchParams?: { [key: string]: string | string[] | undefined }; }) { const { sort, q: searchValue } = searchParams as { [key: string]: string }; - const { sortKey, reverse } = sorting.find((item) => item.slug === sort) || defaultSort; + // const { sortKey, reverse } = sorting.find((item) => item.slug === sort) || defaultSort; + const products = await orama.search({ + term: searchValue, + boost: { + title: 2 + }, + limit: 50, + }) - const products = await getProducts({ sortKey, reverse, query: searchValue }); - const resultsText = products.length > 1 ? 'results' : 'result'; + const resultsText = products.count > 1 ? 'results' : 'result'; + const docs = products.hits.map((hit) => hit.document) as Product[]; return ( <> {searchValue ? ( <p className="mb-4"> - {products.length === 0 + {products.count === 0 ? 'There are no products that match ' - : `Showing ${products.length} ${resultsText} for `} + : `Showing ${products.count} ${resultsText} for `} <span className="font-bold">"{searchValue}"</span> </p> ) : null} - {products.length > 0 ? ( + {products.count > 0 ? ( <Grid className="grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"> - <ProductGridItems products={products} /> + <ProductGridItems products={docs} /> </Grid> ) : null} </> diff --git a/components/layout/navbar/search.tsx b/components/layout/navbar/search.tsx index 962794256..71445bc4a 100644 --- a/components/layout/navbar/search.tsx +++ b/components/layout/navbar/search.tsx @@ -1,7 +1,7 @@ 'use client'; import Link from 'next/link'; -import { useRouter, useSearchParams } from 'next/navigation'; +import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import { useEffect, useRef, useState } from 'react'; import { MagnifyingGlassIcon } from '@heroicons/react/24/outline'; @@ -15,21 +15,30 @@ export default function Search() { const searchParams = useSearchParams(); const [searchValue, setSearchValue] = useState(''); const [searchResults, setSearchResults] = useState<Results>(); + const isSearchPage = usePathname() === '/search' + useEffect(() => { setSearchValue(searchParams?.get('q') || ''); }, [searchParams, setSearchValue]); useEffect(() => { - orama.search({ - term: searchValue, - limit: 5, - boost: { - title: 2, - } - }) - .then(setSearchResults) - .catch(console.log); + + if (isSearchPage) { + router.push(createUrl('/search', new URLSearchParams({ q: searchValue }))) + } else { + orama.search({ + term: searchValue, + limit: 5, + threshold: 0, + boost: { + title: 2, + } + }) + .then(setSearchResults) + .catch(console.log); + } + }, [searchValue]); @@ -55,7 +64,7 @@ export default function Search() { setSearchValue(''); }); - const showSearchResults = searchValue.length > 0 && !!searchResults + const showSearchResults = searchValue.length > 0 && !!searchResults && !isSearchPage; return ( <form onSubmit={onSubmit} className="w-max-[550px] relative w-full lg:w-80 xl:w-full"> @@ -74,18 +83,31 @@ export default function Search() { { showSearchResults && ( <ul ref={searchResultsRef} className='nextra-scrollbar border border-gray-200 bg-white text-gray-100 dark:border-neutral-800 dark:bg-neutral-900 absolute top-full z-20 mt-2 overflow-auto overscroll-contain rounded-xl py-2.5 shadow-xl max-h-[min(calc(50vh-11rem-env(safe-area-inset-bottom)),400px)] md:max-h-[min(calc(100vh-5rem-env(safe-area-inset-bottom)),400px)] inset-x-0 ltr:md:left-auto rtl:md:right-auto contrast-more:border contrast-more:border-gray-900 contrast-more:dark:border-gray-50 w-full min-h-[100px]'> - {searchResults?.hits?.map((product) => ( - <li key={product.id} className='mx-2.5 break-words rounded-md contrast-more:border text-gray-800 contrast-more:border-transparent dark:text-gray-300'> - <Link href={`/product/${product.document.handle}`} className='block scroll-m-12 px-2.5 py-2 rounded-md hover:bg-blue-600 hover:bg-opacity-10 hover:text-blue-500'> - <div className='text-base font-semibold leading-5'> - {product.document.title as string} - </div> - <div className='excerpt mt-1 text-sm leading-[1.35rem] text-gray-600 dark:text-gray-400 contrast-more:dark:text-gray-50'> - {trimDescription((product.document.description || product.document.title) as string)} - </div> - </Link> - </li> - ))} + { + searchResults.count + ? ( + searchResults?.hits?.map((product) => ( + <li key={product.id} className='mx-2.5 break-words rounded-md contrast-more:border text-gray-800 contrast-more:border-transparent dark:text-gray-300'> + <Link href={`/product/${product.document.handle}`} className='block scroll-m-12 px-2.5 py-2 rounded-md hover:bg-blue-600 hover:bg-opacity-10 hover:text-blue-500'> + <div className='text-base font-semibold leading-5'> + {product.document.title as string} + </div> + <div className='excerpt mt-1 text-sm leading-[1.35rem] text-gray-600 dark:text-gray-400 contrast-more:dark:text-gray-50'> + {trimDescription((product.document.description || product.document.title) as string)} + </div> + </Link> + </li> + )) + ) : ( + <li className='mx-2.5 break-words rounded-md contrast-more:border text-gray-800 contrast-more:border-transparent dark:text-gray-300'> + <div className='block scroll-m-12 px-2.5 py-2 rounded-md'> + <div className='text-base font-semibold leading-5'> + No results found for "{searchValue}" + </div> + </div> + </li> + ) + } </ul> ) } diff --git a/components/layout/product-grid-items.tsx b/components/layout/product-grid-items.tsx index ea8a5ebf7..0e8da5564 100644 --- a/components/layout/product-grid-items.tsx +++ b/components/layout/product-grid-items.tsx @@ -13,8 +13,8 @@ export default function ProductGridItems({ products }: { products: Product[] }) alt={product.title} label={{ title: product.title, - amount: product.priceRange.maxVariantPrice.amount, - currencyCode: product.priceRange.maxVariantPrice.currencyCode + amount: product.priceRange?.maxVariantPrice?.amount, + currencyCode: product.priceRange?.maxVariantPrice?.currencyCode }} src={product.featuredImage?.url} fill