summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-10-11 16:51:56 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-10-11 16:51:56 +0700
commitdd2662fc4c88fe660671aba06fd0be788f820ce5 (patch)
tree0ccc252bc43b5a09b6cc7ef67ff97c172062bc1b /src/lib
parent46efc6f8113b3e3deb3a011806ce92b6475c7673 (diff)
parente4bce35fe6ec891bb8841bbfad981e97f5bb2aa8 (diff)
Merge branch 'CR/UI' into development
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/product/components/ProductFilter.jsx118
-rw-r--r--src/lib/product/components/ProductFilterDesktop.jsx140
-rw-r--r--src/lib/product/components/ProductSearch.jsx87
3 files changed, 285 insertions, 60 deletions
diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx
index 34357526..40bfc824 100644
--- a/src/lib/product/components/ProductFilter.jsx
+++ b/src/lib/product/components/ProductFilter.jsx
@@ -3,6 +3,7 @@ import { useRouter } from 'next/router'
import { useState } from 'react'
import _ from 'lodash'
import { toQuery } from 'lodash-contrib'
+import { Checkbox } from '@chakra-ui/react'
const orderOptions = [
{ value: 'price-asc', label: 'Harga Terendah' },
@@ -20,6 +21,45 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr
const [priceFrom, setPriceFrom] = useState(query?.priceFrom)
const [priceTo, setPriceTo] = useState(query?.priceTo)
+ const [stock, setStock] = useState(query?.stock)
+
+ const [activeRange, setActiveRange] = useState(null)
+
+ const priceRange = [
+ {
+ priceFrom: 100000,
+ priceTo: 200000
+ },
+ {
+ priceFrom: 200000,
+ priceTo: 300000
+ },
+ {
+ priceFrom: 300000,
+ priceTo: 400000
+ },
+ {
+ priceFrom: 400000,
+ priceTo: 500000
+ }
+ ]
+
+ const handlePriceFromChange = async (priceFromr, priceTor, index) => {
+ await setPriceFrom(priceFromr)
+ await setPriceTo(priceTor)
+ setActiveRange(index)
+ }
+
+ const handleReadyStockChange = (event) => {
+ const value = event.target.value
+ const isChecked = event.target.checked
+ if (isChecked) {
+ setStock(value)
+ } else {
+ setStock(null)
+ }
+ }
+
const handleSubmit = () => {
let params = {
q: router.query.q,
@@ -27,34 +67,47 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr
brand,
category,
priceFrom,
- priceTo
+ priceTo,
+ stock: stock
}
params = _.pickBy(params, _.identity)
params = toQuery(params)
router.push(`${prefixUrl}?${params}`)
}
+ const formatCurrency = (value) => {
+ if (value >= 1000) {
+ const thousands = Math.floor(value / 1000) // Menghitung ribuan
+ return `Rp${thousands}k`
+ } else {
+ return `Rp${value}`
+ }
+ }
+
return (
<BottomPopup active={active} close={close} title='Filter Produk'>
<div className='flex flex-col gap-y-4'>
- {!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} key={index}>
- {brand}
- </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)}
+ >
+ <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>
+ )
+ }
+
<div>
<label>Kategori</label>
<select
@@ -106,6 +159,33 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr
onChange={(e) => setPriceTo(e.target.value)}
/>
</div>
+ <div className='grid grid-cols-2 gap-x-3 gap-y-2 mt-2'>
+ {priceRange.map((price, i) => (
+ <button
+ key={i}
+ onClick={() => handlePriceFromChange(price.priceFrom, price.priceTo, i)}
+ className={`w-full border ${
+ i === activeRange ? 'border-red-600' : 'border-gray-400'
+ }
+ py-2 p-3 rounded-full text-sm whitespace-nowrap`}
+ >
+ {formatCurrency(price.priceFrom)} - {formatCurrency(price.priceTo)}
+ </button>
+ ))}
+ </div>
+ </div>
+ <div>
+ <label>Ketersedian Stok</label>
+ <div className='mt-2'>
+ <Checkbox
+ isChecked={stock === 'ready stock'}
+ onChange={handleReadyStockChange}
+ value={'ready stock'}
+ size='md'
+ >
+ Ketersedian Stok
+ </Checkbox>
+ </div>
</div>
<button type='button' className='btn-solid-red w-full mt-2' onClick={handleSubmit}>
Terapkan Filter
diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx
index b64349c7..cdfd85e8 100644
--- a/src/lib/product/components/ProductFilterDesktop.jsx
+++ b/src/lib/product/components/ProductFilterDesktop.jsx
@@ -1,5 +1,5 @@
import { useRouter } from 'next/router'
-import { useState } from 'react'
+import { useEffect, useState } from 'react'
import _ from 'lodash'
import { toQuery } from 'lodash-contrib'
import {
@@ -17,6 +17,7 @@ import {
Stack,
VStack
} from '@chakra-ui/react'
+import Image from '@/core/components/elements/Image/Image'
const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = null }) => {
const router = useRouter()
@@ -26,6 +27,27 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu
const [categoryValues, setCategory] = useState(query?.category?.split(',') || [])
const [priceFrom, setPriceFrom] = useState(query?.priceFrom)
const [priceTo, setPriceTo] = useState(query?.priceTo)
+ const [stock, setStock] = useState(query?.stock)
+ const [activeRange, setActiveRange] = useState(null)
+
+ const priceRange = [
+ {
+ priceFrom: 100000,
+ priceTo: 200000
+ },
+ {
+ priceFrom: 200000,
+ priceTo: 300000
+ },
+ {
+ priceFrom: 300000,
+ priceTo: 400000
+ },
+ {
+ priceFrom: 400000,
+ priceTo: 500000
+ }
+ ]
const handleCategoriesChange = (event) => {
const value = event.target.value
@@ -46,6 +68,22 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu
}
}
+ const handleReadyStockChange = (event) => {
+ const value = event.target.value
+ const isChecked = event.target.checked
+ if (isChecked) {
+ setStock(value)
+ } else {
+ setStock(null)
+ }
+ }
+
+ const handlePriceFromChange = async (priceFromr, priceTor, index) => {
+ await setPriceFrom(priceFromr)
+ await setPriceTo(priceTor)
+ setActiveRange(index)
+ }
+
const handleSubmit = () => {
let params = {
q: router.query.q,
@@ -53,41 +91,57 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu
brand: brandValues.join(','),
category: categoryValues.join(','),
priceFrom,
- priceTo
+ priceTo,
+ stock: stock
}
params = _.pickBy(params, _.identity)
params = toQuery(params)
router.push(`${prefixUrl}?${params}`)
}
+ const formatCurrency = (value) => {
+ if (value >= 1000) {
+ const thousands = Math.floor(value / 1000) // Menghitung ribuan
+ return `Rp${thousands}k`
+ } else {
+ return `Rp${value}`
+ }
+ }
+
return (
<>
<Accordion defaultIndex={[0]} allowMultiple>
- <AccordionItem>
- <AccordionButton padding={[2, 4]}>
- <Box as='span' flex='1' textAlign='left' fontWeight='semibold'>
- Brand
- </Box>
- <AccordionIcon />
- </AccordionButton>
+
+ {!router.pathname.includes('brands') && (
+ <AccordionItem>
+ <AccordionButton padding={[2, 4]}>
+ <Box as='span' flex='1' textAlign='left' fontWeight='semibold'>
+ Brand
+ </Box>
+ <AccordionIcon />
+ </AccordionButton>
- <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)}
- onChange={handleBrandsChange}
- value={brand}
- size='md'
- >
- {brand}
- </Checkbox>
- </div>
- ))}
- </Stack>
- </AccordionPanel>
- </AccordionItem>
+ <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>
+ ))}
+ </Stack>
+ </AccordionPanel>
+ </AccordionItem>
+ )}
<AccordionItem>
<AccordionButton padding={[2, 4]}>
@@ -143,9 +197,43 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu
onChange={(e) => setPriceTo(e.target.value)}
/>
</InputGroup>
+ <div className='grid grid-cols-2 gap-x-3 gap-y-2'>
+ {priceRange.map((price, i) => (
+ <button
+ key={i}
+ onClick={() => handlePriceFromChange(price.priceFrom, price.priceTo, i)}
+ className={`w-full border ${
+ i === activeRange ? 'border-red-600' : 'border-gray-400'
+ }
+ py-2 p-3 rounded-full text-sm whitespace-nowrap`}
+ >
+ {formatCurrency(price.priceFrom)} - {formatCurrency(price.priceTo)}
+ </button>
+ ))}
+ </div>
</VStack>
</AccordionPanel>
</AccordionItem>
+
+ <AccordionItem>
+ <AccordionButton padding={[2, 4]}>
+ <Box as='span' flex='1' textAlign='left' fontWeight='semibold'>
+ Ketersedian Stok
+ </Box>
+ <AccordionIcon />
+ </AccordionButton>
+
+ <AccordionPanel paddingY={4}>
+ <Checkbox
+ isChecked={stock === 'ready stock'}
+ onChange={handleReadyStockChange}
+ value={'ready stock'}
+ size='md'
+ >
+ Ketersedian Stock
+ </Checkbox>
+ </AccordionPanel>
+ </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 f6987051..edc98197 100644
--- a/src/lib/product/components/ProductSearch.jsx
+++ b/src/lib/product/components/ProductSearch.jsx
@@ -20,17 +20,17 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
const router = useRouter()
const { page = 1 } = query
const [q, setQ] = useState(query?.q || '*')
+ const [limit, setLimit] = useState(query?.limit || 30)
if (defaultBrand) query.brand = defaultBrand.toLowerCase()
- const { productSearch } = useProductSearch({ query: { ...query, q } })
+ const { productSearch } = useProductSearch({ query: { ...query, q, limit } })
const [products, setProducts] = useState(null)
const [spellings, setSpellings] = useState(null)
const popup = useActive()
+ const numRows = [30, 50, 80, 100]
- const pageCount = Math.ceil(
- productSearch.data?.response.numFound / productSearch.data?.responseHeader.params.rows
- )
+ const pageCount = Math.ceil(productSearch.data?.response.numFound / limit)
const productStart = productSearch.data?.responseHeader.params.start
- const productRows = productSearch.data?.responseHeader.params.rows
+ const productRows = limit
const productFound = productSearch.data?.response.numFound
useEffect(() => {
@@ -63,13 +63,26 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
}
}, [productFound, query, spellings])
- const brands = productSearch.data?.facetCounts?.facetFields?.manufactureName?.filter(
+ const brands = []
+ for (
+ let i = 0;
+ i < productSearch.data?.facetCounts?.facetFields?.manufactureName.length;
+ i += 2
+ ) {
+ const brand = productSearch.data?.facetCounts?.facetFields?.manufactureName[i]
+ const qty = productSearch.data?.facetCounts?.facetFields?.manufactureName[i + 1]
+ brands.push({ brand, qty })
+ }
+ /*const brandsList = productSearch.data?.facetCounts?.facetFields?.manufactureName?.filter(
(value, index) => {
if (index % 2 === 0) {
- return true
+ const brand = value
+ const qty = index + 1
+ brands.push({ brand, qty })
}
}
- )
+ )*/
+
const categories = productSearch.data?.facetCounts?.facetFields?.categoryName?.filter(
(value, index) => {
if (index % 2 === 0) {
@@ -95,6 +108,16 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
router.push(`${prefixUrl}?${params}`)
}
+ const handleLimit = (e) => {
+ let params = {
+ ...router.query,
+ limit: e.target.value
+ }
+ params = _.pickBy(params, _.identity)
+ params = toQuery(params)
+ router.push(`${prefixUrl}?${params}`)
+ }
+
useEffect(() => {
setProducts(productSearch.data?.response?.products)
}, [productSearch])
@@ -127,9 +150,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
{pageCount > 1 ? (
<>
{productStart + 1}-
- {productStart + productRows > productFound
+ {parseInt(productStart) + parseInt(productRows) > productFound
? productFound
- : productStart + productRows}
+ : parseInt(productStart) + parseInt(productRows)}
&nbsp;dari&nbsp;
</>
) : (
@@ -149,9 +172,28 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
</div>
{productFound > 0 && (
- <button className='btn-light mb-6 py-2 px-5' onClick={popup.activate}>
- Filter
- </button>
+ <div className='flex items-center gap-x-2 mb-5 justify-between'>
+ <div>
+ <button className='btn-light py-2 px-5 h-[40px]' onClick={popup.activate}>
+ Filter
+ </button>
+ </div>
+ <div className=''>
+ <select
+ name='limit'
+ className='form-input w-24'
+ value={router.query?.limit || ''}
+ onChange={(e) => handleLimit(e)}
+ >
+ {numRows.map((option, index) => (
+ <option key={index} value={option}>
+ {' '}
+ {option}{' '}
+ </option>
+ ))}
+ </select>
+ </div>
+ </div>
)}
<div className='grid grid-cols-2 gap-3'>
@@ -197,9 +239,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
{pageCount > 1 ? (
<>
{productStart + 1}-
- {productStart + productRows > productFound
+ {parseInt(productStart) + parseInt(productRows) > productFound
? productFound
- : productStart + productRows}
+ : parseInt(productStart) + parseInt(productRows)}
&nbsp;dari&nbsp;
</>
) : (
@@ -234,6 +276,21 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null }) => {
))}
</select>
</div>
+ <div className='ml-3'>
+ <select
+ name='limit'
+ className='form-input mt-2'
+ value={router.query?.limit || ''}
+ onChange={(e) => handleLimit(e)}
+ >
+ {numRows.map((option, index) => (
+ <option key={index} value={option}>
+ {' '}
+ {option}{' '}
+ </option>
+ ))}
+ </select>
+ </div>
</div>
</div>
{productSearch.isLoading && <ProductSearchSkeleton />}