import NextImage from 'next/image'; import { useRouter } from 'next/router'; import { useEffect, useMemo, useState, useRef } from 'react'; import { HStack, Image, Tag, TagCloseButton, TagLabel } from '@chakra-ui/react'; import axios from 'axios'; import _ from 'lodash'; import { toQuery } from 'lodash-contrib'; import { FunnelIcon, AdjustmentsHorizontalIcon, } from '@heroicons/react/24/outline'; import odooApi from '@/core/api/odooApi'; import searchSpellApi from '@/core/api/searchSpellApi'; import Link from '@/core/components/elements/Link/Link'; import Pagination from '@/core/components/elements/Pagination/Pagination'; import DesktopView from '@/core/components/views/DesktopView'; import MobileView from '@/core/components/views/MobileView'; import useActive from '@/core/hooks/useActive'; import { formatCurrency } from '@/core/utils/formatValue'; import { createSlug } from '@/core/utils/slug'; import whatsappUrl from '@/core/utils/whatsappUrl'; import useProductSearch from '../hooks/useProductSearch'; import ProductCard from './ProductCard'; import ProductFilter from './ProductFilter'; import ProductFilterDesktop from './ProductFilterDesktop'; 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 { data } from 'autoprefixer'; const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null, }) => { const router = useRouter(); 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 [dataLob, setDataLob] = useState([]); const appliedDefaultBrandOrder = useRef(false); if (defaultBrand) query.brand = defaultBrand.toLowerCase(); useEffect(() => { if (!router.isReady) return; const onBrandsPage = router.pathname.includes('brands'); const onSearchPage = prefixUrl === '/shop/search'; const hasOrder = typeof router.query?.orderBy === 'string' && router.query.orderBy !== ''; if ( (onBrandsPage || onSearchPage) && !hasOrder && !appliedDefaultBrandOrder.current ) { let params = { ...router.query, orderBy: 'popular', }; params = _.pickBy(params, _.identity); const qs = toQuery(params); // ganti URL tanpa nambah history & tanpa full reload router.replace(`${prefixUrl}?${qs}`, undefined, { shallow: true }); // sinkronkan state lokal setOrderBy('popular'); appliedDefaultBrandOrder.current = true; } }, [router.isReady, router.pathname, router.query?.orderBy, prefixUrl]); const dataIdCategories = []; useEffect(() => { if (prefixUrl.includes('category')) { const loadProduct = async () => { const getCategoriesId = await odooApi( 'GET', `/api/v1/category/numFound?parent_id=${categoryId}`, ); if (getCategoriesId) { setDataCategoriesProduct(getCategoriesId); } }; loadProduct(); } else if (prefixUrl.includes('lob')) { const loadProduct = async () => { 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} AND 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) { if (cat && cat.id) { ids.push(cat.id); } if (Array.isArray(cat.children)) { cat.children.forEach(recurse); } } recurse(category); return ids; }; useEffect(() => { 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 : '', }; setFinalQuery(newQuery); } else if (prefixUrl.includes('lob')) { const fetchCategoryData = async () => { if (dataLob[0]?.categoryIds) { for (const cate of dataLob[0].categoryIds) { 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 : '', }; setFinalQuery(newQuery); } }; fetchCategoryData(); } }, [dataCategoriesProduct, dataLob]); useEffect(() => { if ( prefixUrl.includes('category') || prefixUrl.includes('lob') || router.asPath.includes('penawaran') ) { setQueryFinal({ ...finalQuery, q, limit, orderBy }); } else { setQueryFinal({ ...query, q, limit, orderBy }); } }, [prefixUrl, dataCategoriesProduct, query, finalQuery]); const { productSearch } = useProductSearch({ query: queryFinal, operation: 'AND', }); const [products, setProducts] = useState(null); const [spellings, setSpellings] = useState(null); const [bannerPromotionHeader, setBannerPromotionHeader] = useState(null); const [bannerPromotionFooter, setBannerPromotionFooter] = useState(null); const [isBrand, setIsBrand] = useState(null); const popup = useActive(); const numRows = [30, 50, 80, 100]; const [brandValues, setBrand] = useState( !router.pathname.includes('brands') ? router.query.brand ? router.query.brand.split(',') : [] : [], ); 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); const pageCount = Math.ceil(productSearch.data?.response.numFound / limit); const productStart = productSearch.data?.responseHeader.params.start; const productRows = limit; const productFound = productSearch.data?.response.numFound; const [dataCategories, setDataCategories] = useState([]); useEffect(() => { if (productFound == 0 && query.q && !spellings) { searchSpellApi({ query: query.q }).then((response) => { const oddIndexSuggestions = response.data.spellcheck.suggestions.filter( (_, index) => index % 2 === 1, ); const oddIndexCollations = response.data.spellcheck.collations.filter( (_, index) => index % 2 === 1, ); const dataSpellings = oddIndexSuggestions.reduce((acc, curr) => { oddIndexCollations.forEach((collation) => { acc.push(collation.collationQuery); }); curr.suggestion.forEach((s) => { if (!acc.includes(s.word)) acc.push(s.word); }); return acc; }, []); if (dataSpellings.length > 0) { setQ(dataSpellings[0]); } setSpellings(dataSpellings); }); } }, [productFound, query, spellings]); let id = []; useEffect(() => { const checkIfBrand = async () => { const brand = await axios( `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?params=search&q=${search}`, ); if (brand.data.length > 0) { setIsBrand(brand?.data[0]); } else { setIsBrand(null); } }; if (router.pathname.includes('search') && q !== '*') { checkIfBrand(); } }, [q]); useEffect(() => { 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 brands = []; for ( let i = 0; i < productSearch.data?.facetCounts?.facetFields?.manufactureNameS.length; i += 2 ) { const brand = productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i]; const qty = productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i + 1]; if (qty > 0) { brands.push({ brand, qty }); } } 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 orderOptions = [ { value: '', label: 'Pilih Filter' }, { value: 'price-asc', label: 'Harga Terendah' }, { value: 'price-desc', label: 'Harga Tertinggi' }, { value: 'popular', label: 'Populer' }, { value: 'stock', label: 'Ready Stock' }, ]; const handleOrderBy = (e) => { let params = { ...router.query, orderBy: e.target.value, }; params = _.pickBy(params, _.identity); params = toQuery(params); 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}`); }; 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); }, [productSearch]); const SpellingComponent = useMemo(() => { return ( <> {spellings?.length > 0 ? ( <>Mungkin yang anda cari ) : ( <>Produk yang cari anda tidak ada )} {spellings?.map((spelling, i) => ( {spelling} {i + 1 < spellings.length ? ', ' : ''} ))} ); }, [spellings]); const handleDeleteFilter = async (source, value) => { let params = { penawaran: router.query.penawaran, q: router.query.q, orderBy: orderBy, brand: brandValues.join(','), category: categoryValues?.join(','), priceFrom, priceTo, }; let brands = brandValues; let catagories = categoryValues; switch (source) { case 'brands': brands = brandValues.filter((item) => item !== value); params.brand = brands.join(','); await setBrand(brands); break; case 'category': catagories = categoryValues.filter((item) => item !== value); params.category = catagories.join(','); await setCategory(catagories); break; case 'price': params.priceFrom = null; params.priceTo = null; break; case 'delete': params = { penawaran: router.query.penawaran, q: router.query.q, orderBy: orderBy, }; break; } handleSubmitFilter(params); }; const handleSubmitFilter = (params) => { params = _.pickBy(params, _.identity); params = toQuery(params); router.push(`${prefixUrl}?${params}`); }; const isNotReadyStockPage = router.asPath !== '/shop/search?orderBy=stock'; return ( <> {productSearch.isLoading && }
{isNotReadyStockPage && isBrand && isBrand.logo && (

Brand Pencarian {q}

)}

Produk

{/* info jumlah hasil */}
{!spellings ? ( <> Menampilkan  {pageCount > 1 ? ( <> {productStart + 1}- {parseInt(productStart) + parseInt(productRows) > productFound ? productFound : parseInt(productStart) + parseInt(productRows)}  dari  ) : ( '' )} {productFound}  produk{' '} {query.q && ( <> untuk pencarian{' '} {query.q} )} ) : ( SpellingComponent )}
{productFound > 0 && (
)} {!!dataLob?.length && } {!!dataCategories?.length && ( )}
{products && products.map((product) => ( ))}
{brand && (
Produk dari brand:
{brand?.data?.logo && ( {brand?.data?.name} )} {!brand?.data?.logo && (
{brand?.data?.name}
)}
)}
{bannerPromotionHeader && bannerPromotionHeader?.image && (
)} {isNotReadyStockPage && isBrand && isBrand.logo && (

Brand Pencarian {q}

)}

Hasil Pencarian

{spellings?.length < 1 || !spellings ? ( <> Menampilkan  {pageCount > 1 ? ( <> {productStart + 1}- {parseInt(productStart) + parseInt(productRows) > productFound ? productFound : parseInt(productStart) + parseInt(productRows)}  dari  ) : ( '' )} {productFound}  produk{' '} {query.q && ( <> untuk pencarian {query.q} )} ) : ( SpellingComponent )}
{productSearch.isLoading && }
{products && products.map((product) => ( ))}
Barang yang anda cari tidak ada?{' '} Hubungi Kami
{bannerPromotionFooter && bannerPromotionFooter?.image && (
)}
); }; export default ProductSearch; const FilterChoicesComponent = ({ brandValues, categoryValues, priceFrom, priceTo, handleDeleteFilter, }) => (
{brandValues?.map((value, index) => ( {value} handleDeleteFilter('brands', value)} /> ))} {categoryValues?.map((value, index) => ( {value} handleDeleteFilter('category', value)} /> ))} {priceFrom && priceTo && ( {formatCurrency(priceFrom) + '-' + formatCurrency(priceTo)} handleDeleteFilter('price', priceFrom)} /> )} {brandValues?.length > 0 || categoryValues?.length > 0 || priceFrom || priceTo ? ( ) : ( '' )}
);