summaryrefslogtreecommitdiff
path: root/src/lib/product/components/ProductSearch.jsx
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2024-01-04 10:05:25 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2024-01-04 10:05:25 +0700
commit67398e6f10d6f7729d8f1ace7005ef13d32c5ddd (patch)
tree7d47ad6c1a7093e595e22bcecb40016a626162f6 /src/lib/product/components/ProductSearch.jsx
parent89f32128f37d99b490de7590e2116a9cfd853f89 (diff)
Update promotion program feature
Diffstat (limited to 'src/lib/product/components/ProductSearch.jsx')
-rw-r--r--src/lib/product/components/ProductSearch.jsx379
1 files changed, 225 insertions, 154 deletions
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx
index 29bb987e..e2b961f1 100644
--- a/src/lib/product/components/ProductSearch.jsx
+++ b/src/lib/product/components/ProductSearch.jsx
@@ -1,124 +1,141 @@
-import { useEffect, useMemo, useState } from 'react'
-import useProductSearch from '../hooks/useProductSearch'
-import ProductCard from './ProductCard'
-import Pagination from '@/core/components/elements/Pagination/Pagination'
-import { toQuery } from 'lodash-contrib'
-import _ from 'lodash'
-import ProductSearchSkeleton from './Skeleton/ProductSearchSkeleton'
-import ProductFilter from './ProductFilter'
-import useActive from '@/core/hooks/useActive'
-import MobileView from '@/core/components/views/MobileView'
-import DesktopView from '@/core/components/views/DesktopView'
-import NextImage from 'next/image'
-import ProductFilterDesktop from './ProductFilterDesktop'
-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 { HStack, Image, Tag, TagCloseButton, TagLabel } from '@chakra-ui/react'
-import odooApi from '@/core/api/odooApi'
-import { formatCurrency } from '@/core/utils/formatValue'
-import axios from 'axios'
-import Skeleton from 'react-loading-skeleton'
-import { createSlug } from '@/core/utils/slug'
-
-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(query?.limit || 30)
- const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular')
- if (defaultBrand) query.brand = defaultBrand.toLowerCase()
+import { useEffect, useMemo, useState } from 'react';
+import useProductSearch from '../hooks/useProductSearch';
+import ProductCard from './ProductCard';
+import Pagination from '@/core/components/elements/Pagination/Pagination';
+import { toQuery } from 'lodash-contrib';
+import _ from 'lodash';
+import ProductSearchSkeleton from './Skeleton/ProductSearchSkeleton';
+import ProductFilter from './ProductFilter';
+import useActive from '@/core/hooks/useActive';
+import MobileView from '@/core/components/views/MobileView';
+import DesktopView from '@/core/components/views/DesktopView';
+import NextImage from 'next/image';
+import ProductFilterDesktop from './ProductFilterDesktop';
+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 { HStack, Image, Tag, TagCloseButton, TagLabel } from '@chakra-ui/react';
+import odooApi from '@/core/api/odooApi';
+import { formatCurrency } from '@/core/utils/formatValue';
+import axios from 'axios';
+import { createSlug } from '@/core/utils/slug';
+
+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(query?.limit || 30);
+ const [orderBy, setOrderBy] = useState(router.query?.orderBy || 'popular');
+ if (defaultBrand) query.brand = defaultBrand.toLowerCase();
const { productSearch } = useProductSearch({
query: { ...query, q, limit, orderBy },
- 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]
+ 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') ? (query.brand ? query.brand.split(',') : []) : []
- )
- const [categoryValues, setCategory] = useState(query?.category?.split(',') || [])
- const [priceFrom, setPriceFrom] = useState(query?.priceFrom || null)
- const [priceTo, setPriceTo] = useState(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
+ !router.pathname.includes('brands')
+ ? query.brand
+ ? query.brand.split(',')
+ : []
+ : []
+ );
+ const [categoryValues, setCategory] = useState(
+ query?.category?.split(',') || []
+ );
+ const [priceFrom, setPriceFrom] = useState(query?.priceFrom || null);
+ const [priceTo, setPriceTo] = useState(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;
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)
- })
+ acc.push(collation.collationQuery);
+ });
curr.suggestion.forEach((s) => {
- if (!acc.includes(s.word)) acc.push(s.word)
- })
- return acc
- }, [])
+ if (!acc.includes(s.word)) acc.push(s.word);
+ });
+ return acc;
+ }, []);
if (dataSpellings.length > 0) {
- setQ(dataSpellings[0])
+ setQ(dataSpellings[0]);
}
- setSpellings(dataSpellings)
- })
+ setSpellings(dataSpellings);
+ });
}
- }, [productFound, query, spellings])
+ }, [productFound, query, spellings]);
useEffect(() => {
const checkIfBrand = async () => {
const brand = await axios(
`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?params=search&q=${search}`
- )
- console.log('ini brand', brand)
+ );
+
if (brand.data.length > 0) {
- setIsBrand(brand?.data[0])
+ setIsBrand(brand?.data[0]);
} else {
- setIsBrand(null)
+ setIsBrand(null);
}
- }
+ };
if (router.pathname.includes('search')) {
- checkIfBrand()
+ checkIfBrand();
}
- }, [q])
+ }, [q]);
- const brands = []
+ 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]
+ const brand =
+ productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i];
+ const qty =
+ productSearch.data?.facetCounts?.facetFields?.manufactureNameS[i + 1];
if (qty > 0) {
- brands.push({ brand, qty })
+ 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]
+ 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 })
+ categories.push({ name, qty });
}
}
@@ -126,46 +143,54 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
{ 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 handleOrderBy = (e) => {
let params = {
...router.query,
- orderBy: e.target.value
- }
- params = _.pickBy(params, _.identity)
- params = toQuery(params)
- router.push(`${prefixUrl}?${params}`)
- }
+ 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}`)
- }
+ 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])
+ 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()
- }, [])
+ getBanner();
+ }, []);
useEffect(() => {
- setProducts(productSearch.data?.response?.products)
- }, [productSearch])
+ setProducts(productSearch.data?.response?.products);
+ }, [productSearch]);
const SpellingComponent = useMemo(() => {
return (
@@ -182,8 +207,8 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
</Link>
))}
</>
- )
- }, [spellings])
+ );
+ }, [spellings]);
const handleDeleteFilter = async (source, value) => {
let params = {
@@ -192,41 +217,41 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
brand: brandValues.join(','),
category: categoryValues.join(','),
priceFrom,
- priceTo
- }
+ priceTo,
+ };
- let brands = brandValues
- let catagories = categoryValues
+ let brands = brandValues;
+ let catagories = categoryValues;
switch (source) {
case 'brands':
- brands = brandValues.filter((item) => item !== value)
- params.brand = brands.join(',')
- await setBrand(brands)
- break
+ 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
+ catagories = categoryValues.filter((item) => item !== value);
+ params.category = catagories.join(',');
+ await setCategory(catagories);
+ break;
case 'price':
- params.priceFrom = null
- params.priceTo = null
- break
+ params.priceFrom = null;
+ params.priceTo = null;
+ break;
case 'delete':
params = {
q: router.query.q,
- orderBy: orderBy
- }
- break
+ orderBy: orderBy,
+ };
+ break;
}
- handleSubmitFilter(params)
- }
+ handleSubmitFilter(params);
+ };
const handleSubmitFilter = (params) => {
- params = _.pickBy(params, _.identity)
- params = toQuery(params)
- router.push(`${prefixUrl}?${params}`)
- }
+ params = _.pickBy(params, _.identity);
+ params = toQuery(params);
+ router.push(`${prefixUrl}?${params}`);
+ };
return (
<>
@@ -235,8 +260,14 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
<div className='p-4 pt-0'>
{isBrand && isBrand.logo && (
<div className='mb-3'>
- <h1 className='mb-2 font-semibold text-h-sm'>Brand Pencarian {q}</h1>
- <Image src={isBrand?.logo} alt='' className='object-cover object-center h-[60px]' />
+ <h1 className='mb-2 font-semibold text-h-sm'>
+ Brand Pencarian {q}
+ </h1>
+ <Image
+ src={isBrand?.logo}
+ alt=''
+ className='object-cover object-center h-[60px]'
+ />
</div>
)}
<h1 className='mb-2 font-semibold text-h-sm'>Produk</h1>
@@ -255,7 +286,8 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
{pageCount > 1 ? (
<>
{productStart + 1}-
- {parseInt(productStart) + parseInt(productRows) > productFound
+ {parseInt(productStart) + parseInt(productRows) >
+ productFound
? productFound
: parseInt(productStart) + parseInt(productRows)}
&nbsp;dari&nbsp;
@@ -267,7 +299,8 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
&nbsp;produk{' '}
{query.q && (
<>
- untuk pencarian <span className='font-semibold'>{query.q}</span>
+ untuk pencarian{' '}
+ <span className='font-semibold'>{query.q}</span>
</>
)}
</>
@@ -279,7 +312,10 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
{productFound > 0 && (
<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}>
+ <button
+ className='btn-light py-2 px-5 h-[40px]'
+ onClick={popup.activate}
+ >
Filter
</button>
</div>
@@ -303,7 +339,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
<div className='grid grid-cols-2 gap-3'>
{products &&
- products.map((product) => <ProductCard product={product} key={product.id} />)}
+ products.map((product) => (
+ <ProductCard product={product} key={product.id} />
+ ))}
</div>
<Pagination
@@ -329,7 +367,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
<div className='w-3/12'>
{brand && (
<div className='p-4'>
- <div className='text-caption-1 text-gray_r-11 mb-2'>Produk dari brand:</div>
+ <div className='text-caption-1 text-gray_r-11 mb-2'>
+ Produk dari brand:
+ </div>
{brand?.data?.logo && (
<Image
src={brand?.data?.logo}
@@ -365,12 +405,18 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
{isBrand && isBrand.logo && (
<div className='mb-3'>
- <h1 className='text-2xl mb-2 font-semibold'>Brand Pencarian {q}</h1>
+ <h1 className='text-2xl mb-2 font-semibold'>
+ Brand Pencarian {q}
+ </h1>
<Link
href={createSlug('/shop/brands/', isBrand.name, isBrand.id)}
className='inline'
>
- <Image src={isBrand?.logo} alt='' className='object-cover object-center h-24' />
+ <Image
+ src={isBrand?.logo}
+ alt=''
+ className='object-cover object-center h-24'
+ />
</Link>
</div>
)}
@@ -391,7 +437,8 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
{pageCount > 1 ? (
<>
{productStart + 1}-
- {parseInt(productStart) + parseInt(productRows) > productFound
+ {parseInt(productStart) + parseInt(productRows) >
+ productFound
? productFound
: parseInt(productStart) + parseInt(productRows)}
&nbsp;dari&nbsp;
@@ -403,7 +450,8 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
&nbsp;produk{' '}
{query.q && (
<>
- untuk pencarian <span className='font-semibold'>{query.q}</span>
+ untuk pencarian{' '}
+ <span className='font-semibold'>{query.q}</span>
</>
)}
</>
@@ -447,7 +495,9 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
{productSearch.isLoading && <ProductSearchSkeleton />}
<div className='grid grid-cols-5 gap-x-3 gap-y-6'>
{products &&
- products.map((product) => <ProductCard product={product} key={product.id} />)}
+ products.map((product) => (
+ <ProductCard product={product} key={product.id} />
+ ))}
</div>
<div className='flex justify-between items-center mt-6 mb-2'>
<div className='pt-2 pb-6 flex items-center gap-x-3'>
@@ -464,7 +514,7 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
href={
query?.q
? whatsappUrl('productSearch', {
- name: query.q
+ name: query.q,
})
: whatsappUrl()
}
@@ -496,40 +546,61 @@ const ProductSearch = ({ query, prefixUrl, defaultBrand = null, brand = null })
</div>
</DesktopView>
</>
- )
-}
+ );
+};
-export default ProductSearch
+export default ProductSearch;
const FilterChoicesComponent = ({
brandValues,
categoryValues,
priceFrom,
priceTo,
- handleDeleteFilter
+ handleDeleteFilter,
}) => (
<div className='flex items-center'>
<HStack spacing={2} className='flex-wrap'>
{brandValues?.map((value, index) => (
- <Tag size='lg' key={index} borderRadius='lg' variant='outline' colorScheme='gray'>
+ <Tag
+ size='lg'
+ key={index}
+ borderRadius='lg'
+ variant='outline'
+ colorScheme='gray'
+ >
<TagLabel>{value}</TagLabel>
<TagCloseButton onClick={() => handleDeleteFilter('brands', value)} />
</Tag>
))}
{categoryValues?.map((value, index) => (
- <Tag size='lg' key={index} borderRadius='lg' variant='outline' colorScheme='gray'>
+ <Tag
+ size='lg'
+ key={index}
+ borderRadius='lg'
+ variant='outline'
+ colorScheme='gray'
+ >
<TagLabel>{value}</TagLabel>
- <TagCloseButton onClick={() => handleDeleteFilter('category', value)} />
+ <TagCloseButton
+ onClick={() => handleDeleteFilter('category', value)}
+ />
</Tag>
))}
{priceFrom && priceTo && (
<Tag size='lg' borderRadius='lg' variant='outline' colorScheme='gray'>
- <TagLabel>{formatCurrency(priceFrom) + '-' + formatCurrency(priceTo)}</TagLabel>
- <TagCloseButton onClick={() => handleDeleteFilter('price', priceFrom)} />
+ <TagLabel>
+ {formatCurrency(priceFrom) + '-' + formatCurrency(priceTo)}
+ </TagLabel>
+ <TagCloseButton
+ onClick={() => handleDeleteFilter('price', priceFrom)}
+ />
</Tag>
)}
- {brandValues?.length > 0 || categoryValues?.length > 0 || priceFrom || priceTo ? (
+ {brandValues?.length > 0 ||
+ categoryValues?.length > 0 ||
+ priceFrom ||
+ priceTo ? (
<span>
<button
className='btn-transparent py-2 px-5 h-[40px] text-red-700'
@@ -543,4 +614,4 @@ const FilterChoicesComponent = ({
)}
</HStack>
</div>
-)
+);