diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/Filter.js | 83 | ||||
| -rw-r--r-- | src/components/Header.js | 2 | ||||
| -rw-r--r-- | src/pages/api/shop/search.js | 6 | ||||
| -rw-r--r-- | src/pages/shop/brands.js | 15 | ||||
| -rw-r--r-- | src/pages/shop/search.js | 80 |
5 files changed, 119 insertions, 67 deletions
diff --git a/src/components/Filter.js b/src/components/Filter.js index cb8fd626..a07beff3 100644 --- a/src/components/Filter.js +++ b/src/components/Filter.js @@ -1,28 +1,78 @@ +import { useRouter } from "next/router"; +import { useEffect, useState } from "react"; import CloseIcon from "../icons/close.svg"; const Filter = ({ - selectedBrand, - onChangeBrand, - selectedCategory, - onChangeCategory, - brands, - categories, - isActiveFilter, + isActive, closeFilter, - onSubmit + defaultRoute, + defaultPriceFrom, + defaultPriceTo, + defaultCategory, + defaultBrand, + searchResults }) => { + const router = useRouter(); + + const [priceFrom, setPriceFrom] = useState(defaultPriceFrom); + const [priceTo, setPriceTo] = useState(defaultPriceTo); + const [selectedCategory, setSelectedCategory] = useState(defaultCategory); + const [selectedBrand, setSelectedBrand] = useState(defaultBrand); + const [categories, setCategories] = useState([]); + const [brands, setBrands] = useState([]); + + const filterRoute = () => { + let filterRoute = defaultRoute; + if (selectedBrand) filterRoute += `&brand=${selectedBrand}`; + if (selectedCategory) filterRoute += `&category=${selectedCategory}`; + if (priceFrom > 0) filterRoute += `&price_from=${priceFrom}`; + if (priceTo > 0) filterRoute += `&price_to=${priceTo}`; + return filterRoute; + } + + 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]); + + const submit = (e) => { + e.preventDefault(); + closeFilter(); + router.push(filterRoute(), undefined, { scroll: false }); + } + + const reset = () => { + setSelectedBrand(''); + setSelectedCategory(''); + setPriceFrom(0); + setPriceTo(0); + } + return ( - <div className={`fixed w-full z-[60] py-8 px-4 ring ring-gray-300 bg-white rounded-t-3xl idt-transition ${isActiveFilter ? 'bottom-0' : 'bottom-[-100%]'}`}> + <div className={`fixed w-full z-[60] py-8 px-4 ring ring-gray-300 bg-white rounded-t-3xl idt-transition ${isActive ? 'bottom-0' : 'bottom-[-100%]'}`}> <div className="flex justify-between items-center mb-5"> <h2 className="text-xl font-semibold">Filter Produk</h2> <button onClick={closeFilter}> <CloseIcon className="w-7" /> </button> </div> - <form className="flex flex-col gap-y-4" onSubmit={onSubmit}> + <form className="flex flex-col gap-y-4" onSubmit={submit}> <div> <label>Kategori</label> - <select className="form-input mt-2" value={selectedCategory} onChange={onChangeCategory}> + <select className="form-input mt-2" value={selectedCategory} onChange={(e) => setSelectedCategory(e.target.value)}> <option value="">Pilih kategori...</option> {categories?.map((category, index) => ( <option key={index} value={category}>{category}</option> @@ -31,7 +81,7 @@ const Filter = ({ </div> <div> <label>Brand</label> - <select className="form-input mt-2" value={selectedBrand} onChange={onChangeBrand}> + <select className="form-input mt-2" value={selectedBrand} onChange={(e) => setSelectedBrand(e.target.value)}> <option value="">Pilih brand...</option> {brands?.map((brand, index) => ( <option key={index} value={brand}>{brand}</option> @@ -41,14 +91,19 @@ const Filter = ({ <div> <label>Harga</label> <div className="flex gap-x-4 mt-2 items-center"> - <input className="form-input"/> + <input className="form-input" value={priceFrom} onChange={(e) => setPriceFrom(e.target.value)}/> <span>-</span> - <input className="form-input"/> + <input className="form-input" value={priceTo} onChange={(e) => setPriceTo(e.target.value)}/> </div> </div> <button type="submit" className="btn-yellow font-semibold mt-4 w-full"> Terapkan Filter </button> + {selectedBrand || selectedCategory || priceFrom > 0 || priceTo > 0 ? ( + <button type="button" className="btn-light font-semibold w-full" onClick={reset}> + Reset Filter + </button> + ) : ''} </form> </div> ) diff --git a/src/components/Header.js b/src/components/Header.js index f5eb22f4..2a33df63 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -108,7 +108,7 @@ export default function Header({ title }) { name="q" onChange={(e) => setSearchQuery(e.target.value)} value={searchQuery} - className="form-input rounded-r-none border-r-0" + className="form-input rounded-r-none border-r-0 focus:ring-0" placeholder="Ketikan nama, merek, part number" /> <button diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index 3f13f56c..9cd3d4ba 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -43,11 +43,12 @@ export default async function handler(req, res) { page = 1, brand = '', category = '', + price_from = 0, + price_to = 0 } = req.query; let limit = 30; let offset = (page - 1) * limit; - let parameter = [ `facet.query=${q}`, 'facet=true', @@ -58,7 +59,8 @@ export default async function handler(req, res) { 'facet.field=category_name_str', `start=${offset}`, `rows=${limit}`, - 'sort=product_rating desc' + 'sort=product_rating desc', + `fq=price_discount:[${price_from == 0 ? '*' : price_from} TO ${price_to == 0 ? '*' : price_to}]` ]; if (brand) parameter.push(`fq=brand:${brand}`); diff --git a/src/pages/shop/brands.js b/src/pages/shop/brands.js index 8a7b7684..5d93bf4b 100644 --- a/src/pages/shop/brands.js +++ b/src/pages/shop/brands.js @@ -5,7 +5,7 @@ import "react-lazy-load-image-component/src/effects/blur.css"; import Link from "../../components/Link"; import { createSlug } from "../../helpers/slug"; import InfiniteScroll from "react-infinite-scroll-component"; -import { useCallback, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import Spinner from "../../components/Spinner"; import Layout from "../../components/Layout"; @@ -22,12 +22,13 @@ export default function Brands({ initialManufactures }) { const alpha = Array.from(Array(26)).map((e, i) => i + 65); const alphabets = alpha.map((x) => String.fromCharCode(x)); - const getMoreManufactures = useCallback(async () => { + const getMoreManufactures = async () => { const name = manufactureStartwith != '' ? `${manufactureStartwith}%` : ''; + console.log(manufactures, manufactures.length); const result = await apiOdoo('GET', `/api/v1/manufacture?limit=30&offset=${manufactures.length}&name=${name}`); setHasMoreManufacture(manufactures.length + 30 < result.manufacture_total) setManufactures((manufactures) => [...manufactures, ...result.manufactures]); - }, [manufactureStartwith]); + }; const filterManufactureStartWith = (character) => { setManufactures([]); @@ -40,7 +41,7 @@ export default function Brands({ initialManufactures }) { useEffect(() => { getMoreManufactures(); - }, [getMoreManufactures]); + }, [manufactureStartwith]); return ( <> @@ -48,9 +49,9 @@ export default function Brands({ initialManufactures }) { <Layout> <div className="p-4"> <h1>Semua Brand di Indoteknik</h1> - <div className="flex overflow-x-auto gap-x-4 py-2"> + <div className="flex overflow-x-auto gap-x-2 py-2"> {alphabets.map((alphabet, index) => ( - <button key={index} className={"p-2 py-1 border bg-white border-gray-300 rounded" + (manufactureStartwith == alphabet ? ' bg-yellow-900 border-yellow-900 ' : '')} onClick={() => filterManufactureStartWith(alphabet)}> + <button key={index} className={"p-2 py-1 border bg-white border-gray-300 rounded w-10 flex-shrink-0" + (manufactureStartwith == alphabet ? ' bg-yellow-900 border-yellow-900 ' : '')} onClick={() => filterManufactureStartWith(alphabet)}> {alphabet} </button> ))} @@ -59,7 +60,7 @@ export default function Brands({ initialManufactures }) { dataLength={manufactures.length} next={getMoreManufactures} hasMore={hasMoreManufacture} - className="grid grid-cols-3 gap-4 mt-6 !overflow-x-hidden" + className="grid grid-cols-4 gap-4 mt-6 !overflow-x-hidden" loader={ <div className="flex justify-center items-center border border-gray-300 p-2 rounded h-14"> <Spinner className="w-6 h-6 text-gray-600 fill-gray-900"/> diff --git a/src/pages/shop/search.js b/src/pages/shop/search.js index f41adf3e..29c5b106 100644 --- a/src/pages/shop/search.js +++ b/src/pages/shop/search.js @@ -4,18 +4,33 @@ 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 { useState } from "react"; import Filter from "../../components/Filter"; import { useRouter } from "next/router"; export async function getServerSideProps(context) { - 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}`); + const { + q, + page = 1, + brand = '', + category = '', + price_from = '0', + price_to = '0' + } = context.query; + + let urlParameter = [ + `page=${page}`, + `brand=${brand}`, + `category=${category}`, + `price_from=${price_from}`, + `price_to=${price_to}`, + ].join('&'); + let searchResults = await axios(`${process.env.SELF_HOST}/api/shop/search?q=${q}&${urlParameter}`); searchResults = searchResults.data; - return { props: { searchResults, q, page, brand, category } }; + return { props: { searchResults, q, page, brand, category, price_from, price_to } }; } -export default function ShopSearch({ searchResults, q, page, brand, category }) { +export default function ShopSearch({ searchResults, q, page, brand, category, price_from, price_to }) { const router = useRouter(); const pageCount = Math.ceil(searchResults.response.numFound / searchResults.responseHeader.params.rows); @@ -23,51 +38,30 @@ export default function ShopSearch({ searchResults, q, page, brand, category }) const productRows = searchResults.responseHeader.params.rows; const productFound = searchResults.response.numFound; + // Variable for <Filter/> props state 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 }); + const route = () => { + let route = `/shop/search?q=${q}`; + if (brand) route += `&brand=${brand}`; + if (category) route += `&category=${category}`; + if (price_from > 0) route += `&price_from=${price_from}`; + if (price_to > 0) route += `&price_to=${price_to}`; + return route; } - 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 ( <> <Header title={`Jual ${q} - Indoteknik`} /> <Filter - selectedBrand={selectedBrand} - onChangeBrand={(e) => setSelectedBrand(e.target.value)} - selectedCategory={selectedCategory} - onChangeCategory={(e) => setSelectedCategory(e.target.value)} - brands={brands} - categories={categories} - isActiveFilter={activeFilter} - closeFilter={() => setActiveFilter(false)} - onSubmit={filterSubmit} + defaultRoute={`/shop/search?q=${q}`} + isActive={activeFilter} + closeFilter={() => setActiveFilter(false)} + defaultPriceFrom={price_from} + defaultPriceTo={price_to} + defaultBrand={brand} + defaultCategory={category} + searchResults={searchResults} /> <Layout> <div className="p-4"> @@ -99,7 +93,7 @@ export default function ShopSearch({ searchResults, q, page, brand, category }) </div> <div className="mt-4"> - <Pagination pageCount={pageCount} currentPage={parseInt(page)} url={`/shop/search?q=${q}`} /> + <Pagination pageCount={pageCount} currentPage={parseInt(page)} url={route()} /> </div> </div> </Layout> |
