diff options
| author | trisusilo <tri.susilo@altama.co.id> | 2023-10-16 02:12:57 +0000 |
|---|---|---|
| committer | trisusilo <tri.susilo@altama.co.id> | 2023-10-16 02:12:57 +0000 |
| commit | d9526998613669289c5b37912e15d8e93edcb4e3 (patch) | |
| tree | 8e2c8238d0641afa2ab5717a3994b283004073a1 /src | |
| parent | dd2662fc4c88fe660671aba06fd0be788f820ce5 (diff) | |
| parent | 43e59b8c7f8b742e5781a8a8b991afcf9aabb90e (diff) | |
Merged in CR/UI (pull request #99)
CR/UI
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/components/elements/Navbar/Search.jsx | 42 | ||||
| -rw-r--r-- | src/lib/cart/components/Cartheader.jsx | 30 | ||||
| -rw-r--r-- | src/lib/product/components/ProductFilter.jsx | 64 | ||||
| -rw-r--r-- | src/lib/product/components/ProductFilterDesktop.jsx | 70 | ||||
| -rw-r--r-- | src/lib/product/components/ProductSearch.jsx | 54 | ||||
| -rw-r--r-- | src/pages/api/shop/search.js | 2 | ||||
| -rw-r--r-- | src/pages/shop/category/[slug].jsx | 6 |
7 files changed, 187 insertions, 81 deletions
diff --git a/src/core/components/elements/Navbar/Search.jsx b/src/core/components/elements/Navbar/Search.jsx index f4a8ab3a..e4f89103 100644 --- a/src/core/components/elements/Navbar/Search.jsx +++ b/src/core/components/elements/Navbar/Search.jsx @@ -3,12 +3,18 @@ import { MagnifyingGlassIcon } from '@heroicons/react/24/outline' import { useCallback, useEffect, useRef, useState } from 'react' import Link from '../Link/Link' import { useRouter } from 'next/router' +import { getIdFromSlug, getNameFromSlug } from '@/core/utils/slug' const Search = () => { const router = useRouter() const queryRef = useRef() + const { slug = '' } = router.query const [query, setQuery] = useState(router.query.q || '') const [suggestions, setSuggestions] = useState([]) + const [segment, setSegment] = useState(null) + const [optionSegment, setOptionSegment] = useState(null) + const [optoinSelected, setOptionSelected] = useState(getNameFromSlug(slug) || 'default') + const [pathSegments, setPathSegments] = useState(router?.asPath.split('/') || []) const loadSuggestion = useCallback(() => { if (query && document.activeElement == queryRef.current) { @@ -26,14 +32,29 @@ const Search = () => { } else { setSuggestions([]) } + setFilterSearch() }, [loadSuggestion, query]) const handleSubmit = (e) => { e.preventDefault() - if (query) { - router.push(`/shop/search?q=${query}`) + if (optionSegment && optoinSelected !== 'default' && optoinSelected) { + router.push(`/shop/${segment}/${slug}?q=${query}`) } else { - queryRef.current.focus() + if (query) { + router.push(`/shop/search?q=${query}`) + } else { + queryRef.current.focus() + } + } + } + + const handleSelectChange = async (e) => { + await setOptionSelected(e.target.value) + } + const setFilterSearch = async () => { + if (router.pathname.includes('brands') && pathSegments[3]) { + await setSegment(pathSegments[2]) + await setOptionSegment(getNameFromSlug(slug)) } } @@ -46,10 +67,23 @@ const Search = () => { return ( <> <form onSubmit={handleSubmit} className='flex-1 flex relative'> + {segment && ( + <select + value={optoinSelected} + onChange={handleSelectChange} + className='form-select p-3 rounded-l-sm bg-white border border-gray_r-6 border-r-0 capitalize' + > + <option value='default'>Di Indoteknik</option> + <option value={optionSegment}>Di {optionSegment}</option> + </select> + )} + <input type='text' ref={queryRef} - className='form-input p-3 rounded-r-none border-r-0 focus:border-gray_r-6' + className={`form-input p-3 ${ + segment ? 'rounded-l-none border-l-0' : '' + } rounded-r-none border-r-0 focus:border-gray_r-6`} placeholder='Ketik nama, part number, merk' value={query} onChange={(e) => setQuery(e.target.value)} diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx index 901b1501..aa6980ac 100644 --- a/src/lib/cart/components/Cartheader.jsx +++ b/src/lib/cart/components/Cartheader.jsx @@ -125,7 +125,7 @@ const Cardheader = (cartCount) => { > <div className='w-full max-w-md p-2 bg-white border border-gray-200 rounded-lg shadow'> <div className='p-2 flex justify-between items-center'> - <h5 class='text-base font-semibold leading-none'>Keranjang Belanja</h5> + <h5 className='text-base font-semibold leading-none'>Keranjang Belanja</h5> <Link href='/shop/cart' class='text-sm font-medium text-red-600 underline'> Lihat Semua </Link> @@ -145,15 +145,15 @@ const Cardheader = (cartCount) => { )} {isLoading && itemLoading.map((item) => ( - <div key={item} role='status' class='max-w-sm animate-pulse'> - <div class='flex items-center space-x-4 mb- 2'> - <div class='flex-shrink-0'> - <PhotoIcon class='h-16 w-16 text-gray-500' /> + <div key={item} role='status' className='max-w-sm animate-pulse'> + <div className='flex items-center space-x-4 mb- 2'> + <div className='flex-shrink-0'> + <PhotoIcon className='h-16 w-16 text-gray-500' /> </div> - <div class='flex-1 min-w-0'> - <div class='h-2.5 bg-gray-200 rounded-full dark:bg-gray-700 w-48 mb-4'></div> - <div class='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px] mb-2.5'></div> - <div class='h-2 bg-gray-200 rounded-full dark:bg-gray-700 mb-2.5'></div> + <div className='flex-1 min-w-0'> + <div className='h-2.5 bg-gray-200 rounded-full dark:bg-gray-700 w-48 mb-4'></div> + <div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px] mb-2.5'></div> + <div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 mb-2.5'></div> </div> </div> </div> @@ -167,13 +167,13 @@ const Cardheader = (cartCount) => { )} {auth && products.length > 0 && !isLoading && ( <> - <ul role='list' class='divide-y divide-gray-200 dark:divide-gray-700'> + <ul role='list' className='divide-y divide-gray-200 dark:divide-gray-700'> {products && products?.map((product, index) => ( <> - <li class='py-1 sm:py-2'> - <div class='flex items-center space-x-4'> - <div class='flex-shrink-0'> + <li className='py-1 sm:py-2'> + <div className='flex items-center space-x-4'> + <div className='flex-shrink-0'> <Link href={createSlug( '/shop/product/', @@ -189,7 +189,7 @@ const Cardheader = (cartCount) => { /> </Link> </div> - <div class='flex-1 min-w-0'> + <div className='flex-1 min-w-0'> <Link href={createSlug( '/shop/product/', @@ -199,7 +199,7 @@ const Cardheader = (cartCount) => { className='line-clamp-2 leading-6 !text-gray_r-12 font-normal' > {' '} - <p class='text-caption-2 font-medium text-gray-900 truncate dark:text-white'> + <p className='text-caption-2 font-medium text-gray-900 truncate dark:text-white'> {product.parent.name} </p> </Link> diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx index 40bfc824..14eef0ba 100644 --- a/src/lib/product/components/ProductFilter.jsx +++ b/src/lib/product/components/ProductFilter.jsx @@ -87,27 +87,31 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr return ( <BottomPopup active={active} close={close} title='Filter Produk'> <div className='flex flex-col gap-y-4'> - {!router.pathname.includes('brands') && - !defaultBrand && ( - <div> - <label>Brand</label> - <select - name='brand' - className='form-input mt-2' - value={brand} - onChange={(e) => setBrand(e.target.value)} - > - <option value=''>Pilih Brand...</option> - {brands.map((brand, index) => ( - <option value={brand.brand} key={index}> - {brand.brand} <span className='text-sm text-gray-200'>({brand.qty})</span> - </option> - ))} - </select> - </div> - ) - } - + {!router.pathname.includes('brands') && !defaultBrand && ( + <div> + <label>Brand</label> + <select + name='brand' + className='form-input mt-2' + value={brand} + onChange={(e) => setBrand(e.target.value)} + > + {brands.length > 0 ? ( + <> + <option value=''>Pilih Brand...</option> + {brands.map((brand, index) => ( + <option value={brand.brand} key={index}> + {brand.brand} <span className='text-sm text-gray-200'>({brand.qty})</span> + </option> + ))} + </> + ) : ( + <option value=''>Brands tidak tersedia</option> + )} + </select> + </div> + )} + <div> <label>Kategori</label> <select @@ -116,12 +120,18 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr value={category} onChange={(e) => setCategory(e.target.value)} > - <option value=''>Pilih Kategori...</option> - {categories.map((category, index) => ( - <option value={category} key={index}> - {category} - </option> - ))} + {categories.length > 0 ? ( + <> + <option value=''>Pilih Kategori...</option> + {categories.map((category, index) => ( + <option value={category.name} key={index}> + {category.name} <span className='text-sm text-gray-200'>({category.qty})</span> + </option> + ))} + </> + ) : ( + <option value=''>Kategori tidak tersedia</option> + )} </select> </div> <div> diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index cdfd85e8..e84d6526 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -111,7 +111,6 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu return ( <> <Accordion defaultIndex={[0]} allowMultiple> - {!router.pathname.includes('brands') && ( <AccordionItem> <AccordionButton padding={[2, 4]}> @@ -123,21 +122,25 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu <AccordionPanel> <Stack gap={3} direction='column' maxH={'240px'} overflow='auto'> - {brands.map((brand, index) => ( - <div className='flex items-center gap-2 ' key={index}> - <Checkbox - isChecked={brandValues.includes(brand.brand)} - onChange={handleBrandsChange} - value={brand.brand} - size='md' - > - <div className='flex items-center gap-2'> - <span>{brand.brand} </span> - <span className='text-sm text-gray-600'>({brand.qty})</span> - </div> - </Checkbox> - </div> - ))} + {brands && brands.length > 0 ? ( + brands.map((brand, index) => ( + <div className='flex items-center gap-2 ' key={index}> + <Checkbox + isChecked={brandValues.includes(brand.brand)} + onChange={handleBrandsChange} + value={brand.brand} + size='md' + > + <div className='flex items-center gap-2'> + <span>{brand.brand} </span> + <span className='text-sm text-gray-600'>({brand.qty})</span> + </div> + </Checkbox> + </div> + )) + ) : ( + <div className='flex items-center gap-2'>Brands tidak tersedia</div> + )} </Stack> </AccordionPanel> </AccordionItem> @@ -153,18 +156,25 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu <AccordionPanel> <Stack gap={3} direction='column' maxH={'240px'} overflow='auto'> - {categories.map((category, index) => ( - <div className='flex items-center gap-2' key={index}> - <Checkbox - isChecked={categoryValues.includes(category)} - onChange={handleCategoriesChange} - value={category} - size='md' - > - {category} - </Checkbox> - </div> - ))} + {categories && categories.length > 0 ? ( + categories.map((category, index) => ( + <div className='flex items-center gap-2' key={index}> + <Checkbox + isChecked={categoryValues.includes(category.name)} + onChange={handleCategoriesChange} + value={category.name} + size='md' + > + <div className='flex items-center gap-2'> + <span>{category.name} </span> + <span className='text-sm text-gray-600'>({category.qty})</span> + </div> + </Checkbox> + </div> + )) + ) : ( + <div className='flex items-center gap-2'>Kategori tidak tersedia</div> + )} </Stack> </AccordionPanel> </AccordionItem> @@ -215,7 +225,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu </AccordionPanel> </AccordionItem> - <AccordionItem> + {/* <AccordionItem> <AccordionButton padding={[2, 4]}> <Box as='span' flex='1' textAlign='left' fontWeight='semibold'> Ketersedian Stok @@ -233,7 +243,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu Ketersedian Stock </Checkbox> </AccordionPanel> - </AccordionItem> + </AccordionItem> */} </Accordion> <Button className='w-full mt-6' colorScheme='red' onClick={handleSubmit}> diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index edc98197..fd75d587 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -15,6 +15,8 @@ import { useRouter } from 'next/router' import searchSpellApi from '@/core/api/searchSpellApi' import Link from '@/core/components/elements/Link/Link' import whatsappUrl from '@/core/utils/whatsappUrl' +import { Image } from '@chakra-ui/react' +import odooApi from '@/core/api/odooApi' const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const router = useRouter() @@ -25,6 +27,8 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { const { productSearch } = useProductSearch({ query: { ...query, q, limit } }) const [products, setProducts] = useState(null) const [spellings, setSpellings] = useState(null) + const [bannerPromotionHeader, setBannerPromotionHeader] = useState(null) + const [bannerPromotionFooter, setBannerPromotionFooter] = useState(null) const popup = useActive() const numRows = [30, 50, 80, 100] @@ -71,7 +75,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { ) { const brand = productSearch.data?.facetCounts?.facetFields?.manufactureName[i] const qty = productSearch.data?.facetCounts?.facetFields?.manufactureName[i + 1] - brands.push({ brand, qty }) + if (qty > 0) { + brands.push({ brand, qty }) + } } /*const brandsList = productSearch.data?.facetCounts?.facetFields?.manufactureName?.filter( (value, index) => { @@ -83,13 +89,22 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { } )*/ - const categories = productSearch.data?.facetCounts?.facetFields?.categoryName?.filter( + const categories = [] + for (let i = 0; i < productSearch.data?.facetCounts?.facetFields?.categoryName.length; i += 2) { + const name = productSearch.data?.facetCounts?.facetFields?.categoryName[i] + const qty = productSearch.data?.facetCounts?.facetFields?.categoryName[i + 1] + if (qty > 0) { + categories.push({ name, qty }) + } + } + + /*const categories = productSearch.data?.facetCounts?.facetFields?.categoryName?.filter( (value, index) => { if (index % 2 === 0) { return true } } - ) + )*/ const orderOptions = [ { value: 'price-asc', label: 'Harga Terendah' }, @@ -117,6 +132,20 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { params = toQuery(params) router.push(`${prefixUrl}?${params}`) } + const getBanner = async () => { + if (router.pathname.includes('search')) { + const getBannerHeader = await odooApi('GET', '/api/v1/banner?type=promotion-header') + const getBannerFooter = await odooApi('GET', '/api/v1/banner?type=promotion-footer') + var randomIndex = Math.floor(Math.random() * getBannerHeader.length) + var randomIndexFooter = Math.floor(Math.random() * getBannerFooter.length) + setBannerPromotionHeader(getBannerHeader[randomIndex]) + setBannerPromotionFooter(getBannerFooter[randomIndexFooter]) + } + } + + useEffect(() => { + getBanner() + }, []) useEffect(() => { setProducts(productSearch.data?.response?.products) @@ -230,6 +259,16 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { /> </div> <div className='w-9/12 pl-6'> + {bannerPromotionHeader && bannerPromotionHeader?.image && ( + <div className='mb-3'> + <Image + src={bannerPromotionHeader?.image} + alt='' + className='object-cover object-center h-full mx-auto' + /> + </div> + )} + <h1 className='text-2xl mb-2 font-semibold'>Hasil Pencarian</h1> <div className='flex justify-between items-center mb-2'> <div className='mb-2 leading-6 text-gray_r-11'> @@ -332,6 +371,15 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => { className='!justify-end' /> </div> + {bannerPromotionFooter && bannerPromotionFooter?.image && ( + <div className='mb-3'> + <Image + src={bannerPromotionFooter?.image} + alt='' + className='object-cover object-center h-full mx-auto' + /> + </div> + )} </div> </div> </DesktopView> diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index 874431e0..fd7a215a 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -13,7 +13,7 @@ export default async function handler(req, res) { orderBy = '', operation = 'AND', fq = '', - limit = '', + limit = 0, stock = '' } = req.query diff --git a/src/pages/shop/category/[slug].jsx b/src/pages/shop/category/[slug].jsx index e3650235..6d3985a8 100644 --- a/src/pages/shop/category/[slug].jsx +++ b/src/pages/shop/category/[slug].jsx @@ -14,8 +14,12 @@ export default function CategoryDetail() { const categoryName = getNameFromSlug(slug) const categoryId = getIdFromSlug(slug) + const q = router?.query.q || null const query = { - fq: `manufacture_id_i:${categoryId}` + fq: `category_id_i:${categoryId}` + } + if (q) { + query.q = q } return ( |
