diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-04-28 10:51:17 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-04-28 10:51:17 +0700 |
| commit | 22afd4cf502a4dbd7bf68308cd92443545336645 (patch) | |
| tree | 3287ec808d0610029d36c2e02c450b4dd5a7cafa /src | |
| parent | 8b42783cd838b1da78d3d192860861ada5d13514 (diff) | |
search spell when not found
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/api/searchSpellApi.js | 14 | ||||
| -rw-r--r-- | src/lib/product/components/ProductSearch.jsx | 60 | ||||
| -rw-r--r-- | src/pages/api/shop/spell.js | 19 |
3 files changed, 83 insertions, 10 deletions
diff --git a/src/core/api/searchSpellApi.js b/src/core/api/searchSpellApi.js new file mode 100644 index 00000000..4794c3e1 --- /dev/null +++ b/src/core/api/searchSpellApi.js @@ -0,0 +1,14 @@ +import axios from 'axios' + +const searchSpellApi = async ({ query }) => { + const dataSearchSpell = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/spell?q=${query.trim()}` + ) + return dataSearchSpell +} + +searchSpellApi.defaultProps = { + query: '' +} + +export default searchSpellApi diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index 81e7948b..76dba005 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import useProductSearch from '../hooks/useProductSearch' import ProductCard from './ProductCard' import Pagination from '@/core/components/elements/Pagination/Pagination' @@ -12,6 +12,8 @@ import DesktopView from '@/core/components/views/DesktopView' import NextImage from 'next/image' import ProductFilterDesktop from './ProductFilterDesktop' import { useRouter } from 'next/router' +import searchSpellApi from '@/core/api/searchSpellApi' +import Link from '@/core/components/elements/Link/Link' const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const router = useRouter() @@ -19,6 +21,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { if (defaultBrand) query.brand = defaultBrand.toLowerCase() const { productSearch } = useProductSearch({ query }) const [products, setProducts] = useState(null) + const [spellings, setSpellings] = useState(null) const popup = useActive() const pageCount = Math.ceil( @@ -28,6 +31,30 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const productRows = productSearch.data?.responseHeader.params.rows const productFound = productSearch.data?.response.numFound + useEffect(() => { + if (productFound == 0 && query.q) { + searchSpellApi({ query: query.q }).then((response) => { + const oddIndexSuggestions = response.data.spellcheck.suggestions.filter( + (_, index) => index % 2 === 1 + ) + const oddIndexCollations = response.data.spellcheck.collations.filter( + (_, index) => index % 2 === 1 + ) + const dataSpellings = oddIndexSuggestions.reduce((acc, curr) => { + oddIndexCollations.forEach((collation) => { + acc.push(collation.collationQuery) + }) + curr.suggestion.forEach((s) => { + if (!acc.includes(s.word)) acc.push(s.word) + }) + return acc + }, []) + + setSpellings(dataSpellings) + }) + } + }, [productFound, query]) + const brands = productSearch.data?.facetCounts?.facetFields?.manufactureName?.filter( (value, index) => { if (index % 2 === 0) { @@ -66,6 +93,20 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { } }, [query, products, productSearch]) + const SpellingComponent = useMemo(() => { + return ( + <> + Mungkin yang anda cari{' '} + {spellings?.map((spelling, i) => ( + <Link href={`/shop/search?q=${spelling}`} key={i} className='inline'> + {spelling} + {i + 1 < spellings.length ? ', ' : ''} + </Link> + ))} + </> + ) + }, [spellings]) + return ( <> <MobileView> @@ -96,14 +137,14 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { </> )} </> - ) : ( - 'Mungkin yang anda cari' - )} + ) : SpellingComponent} </div> - <button className='btn-light mb-6 py-2 px-5' onClick={popup.activate}> - Filter - </button> + {productFound > 0 && ( + <button className='btn-light mb-6 py-2 px-5' onClick={popup.activate}> + Filter + </button> + )} <div className='grid grid-cols-2 gap-3'> {products && @@ -127,6 +168,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { /> </div> </MobileView> + <DesktopView> <div className='container mx-auto mt-10 flex mb-3'> <div className='w-3/12'> @@ -163,9 +205,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { </> )} </> - ) : ( - 'Mungkin yang anda cari' - )} + ) : SpellingComponent} </div> <div className='justify-end flex '> <div className='ml-3'> diff --git a/src/pages/api/shop/spell.js b/src/pages/api/shop/spell.js new file mode 100644 index 00000000..634adb50 --- /dev/null +++ b/src/pages/api/shop/spell.js @@ -0,0 +1,19 @@ +import axios from 'axios' + +export default async function handler(req, res) { + const { q = '' } = req.query + + let result = await axios( + process.env.SOLR_HOST + + `/solr/product/spell?indent=true&q.op=AND&q=${q}` + ) + + try { + res.status(200).json(result.data) + } catch (error) { + res.status(400).json({ + numFound: 0, + suggestions: [] + }) + } +} |
