diff options
Diffstat (limited to 'src/lib/product/components')
| -rw-r--r-- | src/lib/product/components/CategorySection.jsx | 105 | ||||
| -rw-r--r-- | src/lib/product/components/LobSectionCategory.jsx | 80 | ||||
| -rw-r--r-- | src/lib/product/components/ProductCard.jsx | 67 | ||||
| -rw-r--r-- | src/lib/product/components/ProductFilter.jsx | 126 | ||||
| -rw-r--r-- | src/lib/product/components/ProductFilterDesktop.jsx | 161 | ||||
| -rw-r--r-- | src/lib/product/components/ProductSearch.jsx | 172 |
6 files changed, 476 insertions, 235 deletions
diff --git a/src/lib/product/components/CategorySection.jsx b/src/lib/product/components/CategorySection.jsx new file mode 100644 index 00000000..a287fa78 --- /dev/null +++ b/src/lib/product/components/CategorySection.jsx @@ -0,0 +1,105 @@ +import Image from "next/image"; +import Link from 'next/link'; +import { createSlug } from '@/core/utils/slug'; +import useDevice from '@/core/hooks/useDevice'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/css'; +import { useQuery } from 'react-query'; +import { useRouter } from 'next/router'; +import { + ChevronDownIcon, + ChevronUpIcon, // Import ChevronUpIcon for toggling + DocumentCheckIcon, + HeartIcon, +} from '@heroicons/react/24/outline'; +import { useState } from 'react'; // Import useState +import { getIdFromSlug } from '@/core/utils/slug' + +const CategorySection = ({ categories }) => { + const { isDesktop, isMobile } = useDevice(); + const [isOpenCategory, setIsOpenCategory] = useState(false); // State to manage category visibility + + const handleToggleCategories = () => { + setIsOpenCategory(!isOpenCategory); + }; + + + const displayedCategories = isOpenCategory ? categories : categories.slice(0, 10); + + return ( + <section> + {isDesktop && ( + <div className="group/item grid grid-cols-5 gap-y-2 gap-x-2 w-full h-full col-span-2 "> + {displayedCategories.map((category) => ( + <Link href={createSlug('/shop/category/', category?.name, category?.id)} key={category?.id} passHref> + <div className="group transition-colors duration-300 "> + <div className="KartuInti h-12 w-26 max-w-sm lg:max-w-full flex flex-col border-[2px] border-gray-200 group-hover:border-red-400 rounded relative "> + <div className="flex items-center justify-start h-full px-1 flex-row "> + <Image className="h-full p-1" src={category?.image1920 ? category?.image1920 : '/images/noimage.jpeg'} width={56} height={48} alt={category?.name} /> + <h2 className="text-gray-700 group-hover:text-[#E20613] line-clamp-2 content-center h-fit w-60 px-1 font-semibold text-sm text-start">{category?.name}</h2> + </div> + </div> + </div> + </Link> + ))} + </div> + )} + {isDesktop && categories.length > 10 && ( + <div className="w-full flex justify-center mt-4"> + <button + onClick={handleToggleCategories} + className="flex justify-end mt-4 text-red-500 font-bold px-4 py-2 rounded" + > + {isOpenCategory ? 'Sembunyikan' : 'Lihat semua'} + {isOpenCategory ? ( + <ChevronUpIcon className="ml-auto w-5 font-bold" /> + ) : ( + <ChevronDownIcon className="ml-auto w-5 font-bold" /> + )} + </button> + </div> + )} + + {isMobile && ( + <div className="py-4"> + <Swiper slidesPerView={2.3} spaceBetween={10}> + {categories.map((category) => ( + <SwiperSlide key={category?.id}> + <Link href={createSlug('/shop/category/', category?.name, category?.id)} passHref> + <div className="group transition-colors duration-300"> + <div className="KartuInti min-h-16 max-h-16 w-26 max-w-sm lg:max-w-full flex flex-col border-[2px] border-gray-200 group-hover:bg-red-200 group-hover:border-red-400 rounded relative"> + <div className="flex items-center justify-center h-full px-1 flex-row"> + <Image + src={category?.image1920 ? category?.image1920 : '/images/noimage.jpeg'} + width={56} + height={48} + alt={category?.name} + className="p-3" + /> + <h2 className="text-gray-700 group-hover:text-[#E20613] line-clamp-2 content-center h-fit w-60 px-1 font-semibold text-sm text-start"> + {category?.name} + </h2> + </div> + </div> + </div> + </Link> + </SwiperSlide> + ))} + </Swiper> + {/* {categories.length > 10 && ( + <div className="w-full flex justify-end mt-4"> + <button + onClick={handleToggleCategories} + className="flex justify-end mt-4 bg-red-500 text-white text-sm px-4 py-2 rounded" + > + {isOpenCategory ? 'Sembunyikan Semua' : 'Lihat Semua'} + </button> + </div> + )} */} + </div> + )} + </section> + ) +} + +export default CategorySection diff --git a/src/lib/product/components/LobSectionCategory.jsx b/src/lib/product/components/LobSectionCategory.jsx new file mode 100644 index 00000000..5cd467e9 --- /dev/null +++ b/src/lib/product/components/LobSectionCategory.jsx @@ -0,0 +1,80 @@ +import Image from "next/image"; +import Link from 'next/link'; +import { createSlug } from '@/core/utils/slug'; +import useDevice from '@/core/hooks/useDevice'; +import { Swiper, SwiperSlide } from 'swiper/react'; +import 'swiper/css'; +import { useQuery } from 'react-query'; +import { useRouter } from 'next/router'; +import { + ChevronDownIcon, + ChevronUpIcon, // Import ChevronUpIcon for toggling + DocumentCheckIcon, + HeartIcon, +} from '@heroicons/react/24/outline'; +import { useState } from 'react'; // Import useState +import { getIdFromSlug } from '@/core/utils/slug' + +const LobSectionCategory = ({ categories }) => { + const { isDesktop, isMobile } = useDevice(); + const [isOpenCategory, setIsOpenCategory] = useState(false); // State to manage category visibility + + const handleToggleCategories = () => { + setIsOpenCategory(!isOpenCategory); + }; + + const displayedCategories = categories[0]?.categoryIds; + return ( + <section> + {isDesktop && ( + <div className="group/item grid grid-flow-col gap-y-2 gap-x-4 w-full h-full"> + {displayedCategories?.map((category) => ( + <Link + href={createSlug('/shop/category/', category?.name, category?.id)} + key={category?.id} + passHref + className="block hover:scale-105 transition-transform duration-300 bg-cover bg-center h-[144px]" + style={{ + backgroundImage: `url('${category?.image ? category?.image : 'https://erp.indoteknik.com/web/image?model=x_banner.banner&id=5&field=x_banner_image&unique=09202023100557'}')`, + }} + > + </Link> + ))} + </div> + )} + + {isMobile && ( + <div className="py-4"> + <Swiper slidesPerView={1.2} spaceBetween={10}> + {displayedCategories?.map((category) => ( + <SwiperSlide key={category?.id}> + <Link + href={createSlug('/shop/category/', category?.name, category?.id)} + key={category?.id} + passHref + className="block bg-cover bg-center h-[144px]" + style={{ + backgroundImage: `url('${category?.image ? category?.image : 'https://erp.indoteknik.com/web/image?model=x_banner.banner&id=5&field=x_banner_image&unique=09202023100557'}')`, + }} + > + </Link> + </SwiperSlide> + ))} + </Swiper> + {categories.length > 10 && ( + <div className="w-full flex justify-end mt-4"> + <button + onClick={handleToggleCategories} + className="flex justify-end mt-4 bg-red-500 text-white text-sm px-4 py-2 rounded" + > + {isOpenCategory ? 'Sembunyikan Semua' : 'Lihat Semua'} + </button> + </div> + )} + </div> + )} + </section> + ) +} + +export default LobSectionCategory diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index c5e82c82..d3b50302 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -17,12 +17,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { const [discount, setDiscount] = useState(0); let voucherPastiHemat = 0; - - if (product?.voucherPastiHemat ? product?.voucherPastiHemat.length : voucherPastiHemat > 0) { - const stringVoucher = product?.voucherPastiHemat[0]; - const validJsonString = stringVoucher.replace(/'/g, '"'); - voucherPastiHemat = JSON.parse(validJsonString); - } + voucherPastiHemat = product?.newVoucherPastiHemat[0]; const callForPriceWhatsapp = whatsappUrl('product', { name: product.name, @@ -48,18 +43,18 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { const hitungDiscountVoucher = () => { let countDiscount = 0; - if (voucherPastiHemat.discount_type === 'percentage') { + if (voucherPastiHemat.discountType === 'percentage') { countDiscount = product?.lowestPrice.priceDiscount * - (voucherPastiHemat.discount_amount / 100); + (voucherPastiHemat.discountAmount / 100); if ( - voucherPastiHemat.max_discount > 0 && - countDiscount > voucherPastiHemat.max_discount + voucherPastiHemat.maxDiscount > 0 && + countDiscount > voucherPastiHemat.maxDiscount ) { - countDiscount = voucherPastiHemat.max_discount; + countDiscount = voucherPastiHemat.maxDiscount; } } else { - countDiscount = voucherPastiHemat.discount_amount; + countDiscount = voucherPastiHemat.discountAmount; } setDiscount(countDiscount); @@ -128,7 +123,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { width={13} height={5} /> - <span className='text-white text-[9px] md:text-[10px] text-nowrap font-semibold'> + <span className='text-white text-[9px] md:text-[10px] font-semibold'> {product?.flashSale?.tag != 'false' || product?.flashSale?.tag ? product?.flashSale?.tag @@ -146,13 +141,26 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { )} </Link> <div className='p-2 sm:p-3 pb-3 text-caption-2 sm:text-body-2 leading-5'> - {product?.manufacture?.name ? ( - <Link href={URL.manufacture} className='mb-1'> - {product.manufacture.name} - </Link> - ) : ( - <div>-</div> - )} + <div className='flex justify-between '> + {product?.manufacture?.name ? ( + <Link href={URL.manufacture} className='mb-1 mt-1'> + {product.manufacture.name} + </Link> + ) : ( + <div>-</div> + )} + {product?.isInBu && ( + <Link href='/panduan-pick-up-service' className='group'> + <Image + src='/images/PICKUP-NOW.png' + className='group-hover:scale-105 transition-transform duration-200' + alt='pickup now' + width={90} + height={12} + /> + </Link> + )} + </div> <Link href={URL.product} className={`mb-2 !text-gray_r-12 leading-6 block line-clamp-3 h-[64px]`} @@ -218,11 +226,11 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { <div className='flex w-full items-center gap-x-1 '> {product?.stockTotal > 0 && ( - <div className='badge-solid-red text-nowrap'>Ready Stock</div> + <div className='badge-solid-red'>Ready Stock</div> )} {/* <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div> */} {product?.qtySold > 0 && ( - <div className='text-gray_r-9 text-[11px] text-nowrap truncate'> + <div className='text-gray_r-9 text-[11px]'> {sellingProductFormat(product?.qtySold) + ' Terjual'} </div> )} @@ -292,9 +300,18 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { </div> )} {product?.manufacture?.name ? ( - <Link href={URL.manufacture} className='mb-1'> - {product.manufacture.name} - </Link> + <div className='flex justify-between'> + <Link href={URL.manufacture} className='mb-1'> + {product.manufacture.name} + </Link> + {/* {product?.is_in_bu && ( + <div className='bg-red-500 rounded'> + <span className='p-[6px] text-xs text-white'> + Click & Pickup + </span> + </div> + )} */} + </div> ) : ( <div>-</div> )} diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx index dd9ec8f4..947550b7 100644 --- a/src/lib/product/components/ProductFilter.jsx +++ b/src/lib/product/components/ProductFilter.jsx @@ -1,64 +1,71 @@ -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import { useRouter } from 'next/router' -import { useState } from 'react' -import _ from 'lodash' -import { toQuery } from 'lodash-contrib' -import { Checkbox } from '@chakra-ui/react' +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +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' }, { value: 'price-desc', label: 'Harga Tertinggi' }, { value: 'popular', label: 'Populer' }, - { value: 'stock', label: 'Ready Stock' } -] + { value: 'stock', label: 'Ready Stock' }, +]; -const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBrand = null }) => { - const router = useRouter() - const { query } = router - const [order, setOrder] = useState(query?.orderBy || 'popular') - const [brand, setBrand] = useState(query?.brand) - const [category, setCategory] = useState(query?.category) - const [priceFrom, setPriceFrom] = useState(query?.priceFrom) - const [priceTo, setPriceTo] = useState(query?.priceTo) +const ProductFilter = ({ + active, + close, + brands, + categories, + prefixUrl, + defaultBrand = null, +}) => { + const router = useRouter(); + const { query } = router; + const [order, setOrder] = useState(query?.orderBy || 'popular'); + const [brand, setBrand] = useState(query?.brand); + const [category, setCategory] = useState(query?.category); + const [priceFrom, setPriceFrom] = useState(query?.priceFrom); + const [priceTo, setPriceTo] = useState(query?.priceTo); - const [stock, setStock] = useState(query?.stock) + const [stock, setStock] = useState(query?.stock); - const [activeRange, setActiveRange] = useState(null) + const [activeRange, setActiveRange] = useState(null); const priceRange = [ { priceFrom: 100000, - priceTo: 200000 + priceTo: 200000, }, { priceFrom: 200000, - priceTo: 300000 + priceTo: 300000, }, { priceFrom: 300000, - priceTo: 400000 + priceTo: 400000, }, { priceFrom: 400000, - priceTo: 500000 - } - ] + priceTo: 500000, + }, + ]; const handlePriceFromChange = async (priceFromr, priceTor, index) => { - await setPriceFrom(priceFromr) - await setPriceTo(priceTor) - setActiveRange(index) - } + await setPriceFrom(priceFromr); + await setPriceTo(priceTor); + setActiveRange(index); + }; const handleReadyStockChange = (event) => { - const value = event.target.value - const isChecked = event.target.checked + const value = event.target.value; + const isChecked = event.target.checked; if (isChecked) { - setStock(value) + setStock(value); } else { - setStock(null) + setStock(null); } - } + }; const handleSubmit = () => { let params = { @@ -69,21 +76,21 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr category, priceFrom, priceTo, - stock: stock - } - params = _.pickBy(params, _.identity) - params = toQuery(params) - router.push(`${prefixUrl}?${params}`) - } + 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` + const thousands = Math.floor(value / 1000); // Menghitung ribuan + return `Rp${thousands}k`; } else { - return `Rp${value}` + return `Rp${value}`; } - } + }; return ( <BottomPopup active={active} close={close} title='Filter Produk'> @@ -102,7 +109,10 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr <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> + {brand.brand}{' '} + <span className='text-sm text-gray-200'> + ({brand.qty}) + </span> </option> ))} </> @@ -126,7 +136,10 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr <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> + {category.name}{' '} + <span className='text-sm text-gray-200'> + ({category.qty}) + </span> </option> ))} </> @@ -142,7 +155,9 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr <button key={orderOption.value} className={`btn-light px-3 font-normal flex-shrink-0 ${ - order == orderOption.value ? 'bg-warning-500' : 'bg-transparent' + order == orderOption.value + ? 'bg-warning-500' + : 'bg-transparent' }`} onClick={() => setOrder(orderOption.value)} > @@ -174,13 +189,16 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr {priceRange.map((price, i) => ( <button key={i} - onClick={() => handlePriceFromChange(price.priceFrom, price.priceTo, 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)} + {formatCurrency(price.priceFrom)} -{' '} + {formatCurrency(price.priceTo)} </button> ))} </div> @@ -198,12 +216,16 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr </Checkbox> </div> </div> */} - <button type='button' className='btn-solid-red w-full mt-2' onClick={handleSubmit}> + <button + type='button' + className='btn-solid-red w-full mt-2' + onClick={handleSubmit} + > Terapkan Filter </button> </div> </BottomPopup> - ) -} + ); +}; -export default ProductFilter +export default ProductFilter; diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index 2bdf962a..d2ecb4d9 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -1,7 +1,7 @@ -import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' -import _ from 'lodash' -import { toQuery } from 'lodash-contrib' +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; +import _ from 'lodash'; +import { toQuery } from 'lodash-contrib'; import { Accordion, AccordionButton, @@ -15,81 +15,90 @@ import { InputGroup, InputLeftAddon, Stack, - VStack -} from '@chakra-ui/react' -import Image from '@/core/components/elements/Image/Image' -import { formatCurrency } from '@/core/utils/formatValue' + VStack, +} from '@chakra-ui/react'; +import Image from '@/core/components/elements/Image/Image'; +import { formatCurrency } from '@/core/utils/formatValue'; -const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = null }) => { - - const router = useRouter() - const { query } = router - const [order, setOrder] = useState(query?.orderBy) - const [brandValues, setBrand] = useState(query?.brand?.split(',') || []) - 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 [activeIndeces, setActiveIndeces] = useState([]) +const ProductFilterDesktop = ({ + brands, + categories, + prefixUrl, + defaultBrand = null, +}) => { + const router = useRouter(); + const { query } = router; + const [order, setOrder] = useState(query?.orderBy); + const [brandValues, setBrand] = useState(query?.brand?.split(',') || []); + 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 [activeIndeces, setActiveIndeces] = useState([]); const priceRange = [ { priceFrom: 100000, - priceTo: 200000 + priceTo: 200000, }, { priceFrom: 200000, - priceTo: 300000 + priceTo: 300000, }, { priceFrom: 300000, - priceTo: 400000 + priceTo: 400000, }, { priceFrom: 400000, - priceTo: 500000 - } - ] + priceTo: 500000, + }, + ]; const indexRange = priceRange.findIndex((range) => { - return range.priceFrom === parseInt(priceFrom) && range.priceTo == parseInt(priceTo) - }) + return ( + range.priceFrom === parseInt(priceFrom) && + range.priceTo == parseInt(priceTo) + ); + }); const handleCategoriesChange = (event) => { - const value = event.target.value - const isChecked = event.target.checked + const value = event.target.value; + const isChecked = event.target.checked; if (isChecked) { - setCategory([...categoryValues, value]) + setCategory([...categoryValues, value]); } else { - setCategory(categoryValues.filter((val) => val !== value)) + setCategory(categoryValues.filter((val) => val !== value)); } - } + }; const handleBrandsChange = (event) => { - const value = event.target.value - const isChecked = event.target.checked + const value = event.target.value; + const isChecked = event.target.checked; if (isChecked) { - setBrand([...brandValues, value]) + setBrand([...brandValues, value]); } else { - setBrand(brandValues.filter((val) => val !== value)) + setBrand(brandValues.filter((val) => val !== value)); } - } + }; const handleReadyStockChange = (event) => { - const value = event.target.value - const isChecked = event.target.checked + const value = event.target.value; + const isChecked = event.target.checked; if (isChecked) { - setStock(value) + setStock(value); } else { - setStock(null) + setStock(null); } - } + }; const handlePriceFromChange = async (priceFromr, priceTor, index) => { - await setPriceFrom(priceFromr) - await setPriceTo(priceTor) - setActiveRange(index) - } + await setPriceFrom(priceFromr); + await setPriceTo(priceTor); + setActiveRange(index); + }; const handleSubmit = () => { let params = { @@ -100,21 +109,25 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu category: categoryValues.join(','), priceFrom, priceTo, - stock: stock - } - params = _.pickBy(params, _.identity) - params = toQuery(params) + stock: stock, + }; + params = _.pickBy(params, _.identity); + params = toQuery(params); - const slug = Array.isArray(router.query.slug) ? router.query.slug[0] : router.query.slug; + const slug = Array.isArray(router.query.slug) + ? router.query.slug[0] + : router.query.slug; if (slug) { - router.push(`${prefixUrl}/${slug}?${params}`) + if (prefixUrl.includes('category') || prefixUrl.includes('lob')) { + router.push(`${prefixUrl}?${params}`); + } else { + router.push(`${prefixUrl}/${slug}?${params}`); + } } else { - router.push(`${prefixUrl}?${params}`) + router.push(`${prefixUrl}?${params}`); } - } - - + }; /*const handleIndexAccordion = async () => { if (brandValues) { @@ -132,9 +145,8 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu }*/ useEffect(() => { - setActiveRange(indexRange) - }, []) - + setActiveRange(indexRange); + }, []); return ( <> @@ -161,13 +173,17 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu > <div className='flex items-center gap-2'> <span>{brand.brand} </span> - <span className='text-sm text-gray-600'>({brand.qty})</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> + <div className='flex items-center gap-2'> + Brands tidak tersedia + </div> )} </Stack> </AccordionPanel> @@ -195,13 +211,17 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu > <div className='flex items-center gap-2'> <span>{category.name} </span> - <span className='text-sm text-gray-600'>({category.qty})</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> + <div className='flex items-center gap-2'> + Kategori tidak tersedia + </div> )} </Stack> </AccordionPanel> @@ -239,13 +259,16 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu {priceRange.map((price, i) => ( <button key={i} - onClick={() => handlePriceFromChange(price.priceFrom, price.priceTo, 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)} + {formatCurrency(price.priceFrom)} -{' '} + {formatCurrency(price.priceTo)} </button> ))} </div> @@ -278,7 +301,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu Terapkan </Button> </> - ) -} + ); +}; -export default ProductFilterDesktop +export default ProductFilterDesktop; diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index 7c1b0a40..f7b044aa 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -26,9 +26,9 @@ import ProductSearchSkeleton from './Skeleton/ProductSearchSkeleton'; import SideBanner from '~/modules/side-banner'; import FooterBanner from '~/modules/footer-banner'; -// import CategorySection from './CategorySection'; -// import LobSectionCategory from './LobSectionCategory'; -import { getIdFromSlug } from '@/core/utils/slug' +import CategorySection from './CategorySection'; +import LobSectionCategory from './LobSectionCategory'; +import { getIdFromSlug } from '@/core/utils/slug'; import { data } from 'autoprefixer'; const ProductSearch = ({ @@ -41,59 +41,62 @@ const ProductSearch = ({ const { page = 1 } = query; const [q, setQ] = useState(query?.q || '*'); const [search, setSearch] = useState(query?.q || '*'); + const [limit, setLimit] = useState(router.query?.limit || 30); + const [orderBy, setOrderBy] = useState(router.query?.orderBy); const [finalQuery, setFinalQuery] = useState({}); const [queryFinal, setQueryFinal] = useState({}); - const [dataCategoriesProduct, setDataCategoriesProduct] = useState([]) - const [dataCategoriesLob, setDataCategoriesLob] = useState([]) - const categoryId = getIdFromSlug(prefixUrl) - const [data, setData] = useState([]) + const [dataCategoriesProduct, setDataCategoriesProduct] = useState([]); + const [dataCategoriesLob, setDataCategoriesLob] = useState([]); + const categoryId = getIdFromSlug(prefixUrl); + const [data, setData] = useState([]); const [dataLob, setDataLob] = useState([]); - const [limit, setLimit] = useState(query?.limit || 30); - const [orderBy, setOrderBy] = useState(router.query?.orderBy); if (defaultBrand) query.brand = defaultBrand.toLowerCase(); - const dataIdCategories = [] - - useEffect(() => { - const checkIfPenawaran = async () => { - if (router.asPath.includes('penawaran')) { - query = { - ...query, - fq: [ - `-flashsale_id_i:${router.query.penawaran}`, - `flashsale_price_f:[1 TO *]` - ], - orderBy: 'flashsale-discount-desc' - }; - console.log('setOrder') - setOrderBy('flashsale-discount-desc') - console.log('orderBy',orderBy) - } - }; - checkIfPenawaran(); - }, [router.query, prefixUrl, q, finalQuery, queryFinal]); - + const dataIdCategories = []; useEffect(() => { - if(prefixUrl.includes('category')){ + if (prefixUrl.includes('category')) { const loadProduct = async () => { - const getCategoriesId = await odooApi('GET', `/api/v1/category/numFound?parent_id=${categoryId}`); + const getCategoriesId = await odooApi( + 'GET', + `/api/v1/category/numFound?parent_id=${categoryId}` + ); if (getCategoriesId) { setDataCategoriesProduct(getCategoriesId); } }; loadProduct(); - }else if(prefixUrl.includes('lob')){ + } else if (prefixUrl.includes('lob')) { const loadProduct = async () => { - const lobData = await odooApi('GET', `/api/v1/lob_homepage/${categoryId}/category_id`); - + const lobData = await odooApi( + 'GET', + `/api/v1/lob_homepage/${categoryId}/category_id` + ); + if (lobData) { setDataLob(lobData); } }; loadProduct(); - } }, [categoryId]); - + + useEffect(() => { + const checkIfPenawaran = async () => { + if (router.asPath.includes('penawaran')) { + query = { + ...query, + fq: [ + `-flashsale_id_i:${router.query.penawaran}`, + `flashsale_price_f:[1 TO *]`, + ], + orderBy: 'flashsale-discount-desc', + }; + setFinalQuery(query); + setOrderBy('flashsale-discount-desc'); + } + }; + checkIfPenawaran(); + }, [router.query]); + const collectIds = (category) => { const ids = []; function recurse(cat) { @@ -107,47 +110,41 @@ const ProductSearch = ({ recurse(category); return ids; }; - useEffect(() => { - if(prefixUrl.includes('category')){ + if (prefixUrl.includes('category')) { const ids = collectIds(dataCategoriesProduct); const newQuery = { fq: `category_id_ids:(${ids.join(' OR ')})`, - page : router.query.page? router.query.page : 1, - brand : router.query.brand? router.query.brand : '', - category : router.query.category? router.query.category : '', - priceFrom : router.query.priceFrom? router.query.priceFrom : '', - priceTo : router.query.priceTo? router.query.priceTo : '', - limit : router.query.limit? router.query.limit : '', - orderBy : router.query.orderBy? router.query.orderBy : '' + page: router.query.page ? router.query.page : 1, + brand: router.query.brand ? router.query.brand : '', + category: router.query.category ? router.query.category : '', + priceFrom: router.query.priceFrom ? router.query.priceFrom : '', + priceTo: router.query.priceTo ? router.query.priceTo : '', + limit: router.query.limit ? router.query.limit : '', + orderBy: router.query.orderBy ? router.query.orderBy : '', }; setFinalQuery(newQuery); - } else if (prefixUrl.includes('lob')){ - + } else if (prefixUrl.includes('lob')) { const fetchCategoryData = async () => { if (dataLob[0]?.categoryIds) { - for (const cate of dataLob[0].categoryIds) { - - dataIdCategories.push(cate.childId) + dataIdCategories.push(cate.childId); } - - + const mergedArray = dataIdCategories.flat(); - + const newQuery = { fq: `category_id_ids:(${mergedArray.join(' OR ')})`, - category : router.query.category? router.query.category : '', - page : router.query.page? router.query.page : 1, - brand : router.query.brand? router.query.brand : '', - priceFrom : router.query.priceFrom? router.query.priceFrom : '', - priceTo : router.query.priceTo? router.query.priceTo : '', - limit : router.query.limit? router.query.limit : '', - orderBy : router.query.orderBy? router.query.orderBy : '' + category: router.query.category ? router.query.category : '', + page: router.query.page ? router.query.page : 1, + brand: router.query.brand ? router.query.brand : '', + priceFrom: router.query.priceFrom ? router.query.priceFrom : '', + priceTo: router.query.priceTo ? router.query.priceTo : '', + limit: router.query.limit ? router.query.limit : '', + orderBy: router.query.orderBy ? router.query.orderBy : '', }; - + setFinalQuery(newQuery); - } }; fetchCategoryData(); @@ -158,11 +155,9 @@ const ProductSearch = ({ if (prefixUrl.includes('category') || prefixUrl.includes('lob')) { setQueryFinal({ ...finalQuery, q, limit, orderBy }); } else { - console.log("data query",orderBy) setQueryFinal({ ...query, q, limit, orderBy }); } - }, [prefixUrl,dataCategoriesProduct, query, finalQuery, orderBy]); - + }, [prefixUrl, dataCategoriesProduct, query, finalQuery]); const { productSearch } = useProductSearch({ query: queryFinal, @@ -185,7 +180,7 @@ const ProductSearch = ({ const [categoryValues, setCategory] = useState( router.query?.category?.split(',') || router.query?.category?.split(',') ); - + const [priceFrom, setPriceFrom] = useState(router.query?.priceFrom || null); const [priceTo, setPriceTo] = useState(router.query?.priceTo || null); @@ -193,8 +188,8 @@ const ProductSearch = ({ const productStart = productSearch.data?.responseHeader.params.start; const productRows = limit; const productFound = productSearch.data?.response.numFound; - const [dataCategories, setDataCategories] = useState([]) - + const [dataCategories, setDataCategories] = useState([]); + useEffect(() => { if (productFound == 0 && query.q && !spellings) { searchSpellApi({ query: query.q }).then((response) => { @@ -224,7 +219,7 @@ const ProductSearch = ({ }); } }, [productFound, query, spellings]); - let id = [] + let id = []; useEffect(() => { const checkIfBrand = async () => { const brand = await axios( @@ -241,21 +236,21 @@ const ProductSearch = ({ checkIfBrand(); } }, [q]); - + useEffect(() => { - if(prefixUrl.includes('category')){ + if (prefixUrl.includes('category')) { const loadCategories = async () => { - const getCategories = await odooApi('GET', `/api/v1/category/child?parent_id=${categoryId}`) - if(getCategories){ - setDataCategories(getCategories) - } - } - loadCategories() + const getCategories = await odooApi( + 'GET', + `/api/v1/category/child?parent_id=${categoryId}` + ); + if (getCategories) { + setDataCategories(getCategories); + } + }; + loadCategories(); } - }, []) - - - + }, []); const brands = []; for ( @@ -271,7 +266,6 @@ const ProductSearch = ({ brands.push({ brand, qty }); } } - const categories = []; for ( @@ -286,7 +280,6 @@ const ProductSearch = ({ categories.push({ name, qty }); } } - const orderOptions = [ { value: '', label: 'Pilih Filter' }, @@ -406,6 +399,7 @@ const ProductSearch = ({ }; const isNotReadyStockPage = router.asPath !== '/shop/search?orderBy=stock'; + return ( <> <MobileView> @@ -466,8 +460,8 @@ const ProductSearch = ({ SpellingComponent )} </div> - {/* <LobSectionCategory categories={dataLob}/> - <CategorySection categories={dataCategories}/> */} + <LobSectionCategory categories={dataLob} /> + <CategorySection categories={dataCategories} /> {productFound > 0 && ( <div className='flex items-center gap-x-2 mb-5 justify-between'> @@ -559,8 +553,8 @@ const ProductSearch = ({ </div> <div className='w-9/12 pl-6'> - {/* <LobSectionCategory categories={dataLob}/> - <CategorySection categories={dataCategories}/> */} + <LobSectionCategory categories={dataLob} /> + <CategorySection categories={dataCategories} /> {bannerPromotionHeader && bannerPromotionHeader?.image && ( <div className='mb-3'> <Image @@ -599,7 +593,7 @@ const ProductSearch = ({ /> <div className='flex justify-between items-center mb-5'> <div className='leading-6 text-gray_r-11'> - {!spellings ? ( + {spellings?.length < 1 || !spellings ? ( <> Menampilkan {pageCount > 1 ? ( |
