summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrisusilo <tri.susilo@altama.co.id>2023-10-16 02:12:57 +0000
committertrisusilo <tri.susilo@altama.co.id>2023-10-16 02:12:57 +0000
commitd9526998613669289c5b37912e15d8e93edcb4e3 (patch)
tree8e2c8238d0641afa2ab5717a3994b283004073a1
parentdd2662fc4c88fe660671aba06fd0be788f820ce5 (diff)
parent43e59b8c7f8b742e5781a8a8b991afcf9aabb90e (diff)
Merged in CR/UI (pull request #99)
CR/UI
-rw-r--r--.env.example17
-rw-r--r--src/core/components/elements/Navbar/Search.jsx42
-rw-r--r--src/lib/cart/components/Cartheader.jsx30
-rw-r--r--src/lib/product/components/ProductFilter.jsx64
-rw-r--r--src/lib/product/components/ProductFilterDesktop.jsx70
-rw-r--r--src/lib/product/components/ProductSearch.jsx54
-rw-r--r--src/pages/api/shop/search.js2
-rw-r--r--src/pages/shop/category/[slug].jsx6
8 files changed, 200 insertions, 85 deletions
diff --git a/.env.example b/.env.example
index 71977847..397c01f0 100644
--- a/.env.example
+++ b/.env.example
@@ -13,14 +13,23 @@ MIDTRANS_ENV=
MIDTRANS_SERVER_KEY=
MIDTRANS_CLIENT_KEY=
+GOOGLE_CLIENT_ID=
+GOOGLE_CLIENT_SECRET=
-GOOGLE_CLIENT_ID="396438712998-308hckshgeekr34phr5jskj1f6qltfvk.apps.googleusercontent.com"
-GOOGLE_CLIENT_SECRET=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
+JWT_SECRET=
-JWT_SECRET=NTNv7j0TuYARvmNMmWXo6fKvM4o6nvaUi9ryX38ZHL1bkrnD1ObOQ8JAUmHCBq7Iy7otZcyAagBLHVKvvYaIpmMuxmARQ97jUVG16Jkpkp1wXOPsrF9zwew6TpczyHkHgX5EuLg2MeBuiTqJACs1J0apruOOJCggOtkjB4c
+RECAPTCHA_GOOGLE=
+RAJA_ONGKIR_HOST=
+RAJA_ONGKIR_KEY=
+
+PPN=
NEXT_PUBLIC_SELF_HOST=$SELF_HOST
NEXT_PUBLIC_ODOO_API_HOST=$ODOO_API_HOST
NEXT_PUBLIC_ODOO_HOST=$ODOO_HOST
-NEXT_PUBLIC_MIDTRANS_CLIENT_KEY=$MIDTRANS_CLIENT_KEY \ No newline at end of file
+NEXT_PUBLIC_MIDTRANS_CLIENT_KEY=$MIDTRANS_CLIENT_KEY
+NEXT_PUBLIC_RECAPTCHA_GOOGLE=$RECAPTCHA_GOOGLE
+NEXT_PUBLIC_RAJA_ONGKIR_HOST=$RAJA_ONGKIR_HOST
+NEXT_PUBLIC_RAJA_ONGKIR_KEY=$RAJA_ONGKIR_KEY
+NEXT_PUBLIC_PPN=$PPN \ No newline at end of file
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 (