From 930ed6680100e9732157ed1861af3572e36219a0 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 22 Nov 2022 17:09:05 +0700 Subject: Filter search by brand, category, price --- src/components/Filter.js | 57 +++++++++++++++++++++++++++++++++++++ src/icons/close.svg | 1 + src/pages/api/shop/search.js | 11 ++++++-- src/pages/login.js | 4 +-- src/pages/register.js | 6 ++-- src/pages/shop/search.js | 67 +++++++++++++++++++++++++++++++++++++------- src/styles/globals.css | 10 +++++++ 7 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 src/components/Filter.js create mode 100644 src/icons/close.svg (limited to 'src') diff --git a/src/components/Filter.js b/src/components/Filter.js new file mode 100644 index 00000000..cb8fd626 --- /dev/null +++ b/src/components/Filter.js @@ -0,0 +1,57 @@ +import CloseIcon from "../icons/close.svg"; + +const Filter = ({ + selectedBrand, + onChangeBrand, + selectedCategory, + onChangeCategory, + brands, + categories, + isActiveFilter, + closeFilter, + onSubmit +}) => { + return ( +
+
+

Filter Produk

+ +
+
+
+ + +
+
+ + +
+
+ +
+ + - + +
+
+ +
+
+ ) +}; + +export default Filter; \ No newline at end of file diff --git a/src/icons/close.svg b/src/icons/close.svg new file mode 100644 index 00000000..50e0589d --- /dev/null +++ b/src/icons/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index 72db04fd..3f13f56c 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -40,7 +40,9 @@ const productResponseMap = (products) => { export default async function handler(req, res) { const { q, - page = 1 + page = 1, + brand = '', + category = '', } = req.query; let limit = 30; @@ -57,9 +59,12 @@ export default async function handler(req, res) { `start=${offset}`, `rows=${limit}`, 'sort=product_rating desc' - ].join('&'); + ]; + + if (brand) parameter.push(`fq=brand:${brand}`); + if (category) parameter.push(`fq=category_name:${category}`); - let result = await axios(process.env.SOLR_HOST + '/solr/products/select?' + parameter); + let result = await axios(process.env.SOLR_HOST + '/solr/products/select?' + parameter.join('&')); try { result.data.response.products = productResponseMap(result.data.response.docs); result.data.responseHeader.params.start = parseInt(result.data.responseHeader.params.start); diff --git a/src/pages/login.js b/src/pages/login.js index cff2e0cd..cb299afa 100644 --- a/src/pages/login.js +++ b/src/pages/login.js @@ -65,14 +65,14 @@ export default function Login() {
setEmail(e.target.value)} /> setPassword(e.target.value)} diff --git a/src/pages/register.js b/src/pages/register.js index ff6aa1d8..41bd7c75 100644 --- a/src/pages/register.js +++ b/src/pages/register.js @@ -63,21 +63,21 @@ export default function Login() { setEmail(e.target.value)} /> setName(e.target.value)} /> setPassword(e.target.value)} diff --git a/src/pages/shop/search.js b/src/pages/shop/search.js index 21a4ccd9..f41adf3e 100644 --- a/src/pages/shop/search.js +++ b/src/pages/shop/search.js @@ -4,30 +4,77 @@ import Layout from "../../components/Layout"; import Pagination from "../../components/Pagination"; import ProductCard from "../../components/ProductCard"; import FilterIcon from "../../icons/filter.svg"; +import { useEffect, useState } from "react"; +import Filter from "../../components/Filter"; +import { useRouter } from "next/router"; export async function getServerSideProps(context) { - const { q, page = 1 } = context.query; - let searchResults = await axios(`${process.env.SELF_HOST}/api/shop/search?q=${q}&page=${page}`); + const { q, page = 1, brand = '', category = '' } = context.query; + let searchResults = await axios(`${process.env.SELF_HOST}/api/shop/search?q=${q}&page=${page}&brand=${brand}&category=${category}`); searchResults = searchResults.data; - return { props: { searchResults, q, page } }; + return { props: { searchResults, q, page, brand, category } }; } -export default function ShopSearch({ searchResults, q, page }) { +export default function ShopSearch({ searchResults, q, page, brand, category }) { + const router = useRouter(); + const pageCount = Math.ceil(searchResults.response.numFound / searchResults.responseHeader.params.rows); const productStart = searchResults.responseHeader.params.start; const productRows = searchResults.responseHeader.params.rows; const productFound = searchResults.response.numFound; + + const [activeFilter, setActiveFilter] = useState(false); + const [selectedCategory, setSelectedCategory] = useState(category); + const [selectedBrand, setSelectedBrand] = useState(brand); + const [categories, setCategories] = useState([]); + const [brands, setBrands] = useState([]); + + const filterSubmit = (e) => { + e.preventDefault(); + setActiveFilter(false); + let filterRoute = `/shop/search?q=${q}`; + if (selectedBrand) filterRoute += `&brand=${selectedBrand}`; + if (selectedCategory) filterRoute += `&category=${selectedCategory}`; + router.push(filterRoute, undefined, { scroll: false }); + } + + useEffect(() => { + const filterCategory = searchResults.facet_counts.facet_fields.category_name_str.filter((category, index) => { + if (index % 2 == 0) { + const productCountInCategory = searchResults.facet_counts.facet_fields.category_name_str[index + 1]; + if (productCountInCategory > 0) return category; + } + }); + setCategories(filterCategory); + + const filterBrand = searchResults.facet_counts.facet_fields.brand_str.filter((brand, index) => { + if (index % 2 == 0) { + const productCountInBrand = searchResults.facet_counts.facet_fields.brand_str[index + 1]; + if (productCountInBrand > 0) return brand; + } + }); + setBrands(filterBrand); + }, [searchResults]); return ( <>
+ setSelectedBrand(e.target.value)} + selectedCategory={selectedCategory} + onChangeCategory={(e) => setSelectedCategory(e.target.value)} + brands={brands} + categories={categories} + isActiveFilter={activeFilter} + closeFilter={() => setActiveFilter(false)} + onSubmit={filterSubmit} + />
-
-

Produk

- -
+ +

Produk

{productFound > 0 ? ( <> diff --git a/src/styles/globals.css b/src/styles/globals.css index 8e81f7e8..5033a220 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -91,6 +91,8 @@ html, body { w-full leading-none focus:outline-none + focus:ring-1 + focus:ring-yellow-900 ; } @@ -339,4 +341,12 @@ html, body { bg-gray-100 text-sm ; +} + +.idt-transition { + @apply + transition-all + ease-linear + duration-300 + ; } \ No newline at end of file -- cgit v1.2.3