summaryrefslogtreecommitdiff
path: root/src/lib/product/components
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
parent89f32128f37d99b490de7590e2116a9cfd853f89 (diff)
Update promotion program feature
Diffstat (limited to 'src/lib/product/components')
-rw-r--r--src/lib/product/components/Product/ProductDesktop.jsx763
-rw-r--r--src/lib/product/components/Product/ProductMobile.jsx411
-rw-r--r--src/lib/product/components/ProductSearch.jsx379
3 files changed, 906 insertions, 647 deletions
diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx
index 5f034c09..4074f243 100644
--- a/src/lib/product/components/Product/ProductDesktop.jsx
+++ b/src/lib/product/components/Product/ProductDesktop.jsx
@@ -1,416 +1,441 @@
-import Image from '@/core/components/elements/Image/Image'
-import Link from '@/core/components/elements/Link/Link'
-import DesktopView from '@/core/components/views/DesktopView'
-import currencyFormat from '@/core/utils/currencyFormat'
-import { HeartIcon } from '@heroicons/react/24/outline'
-import { useCallback, useEffect, useRef, useState } from 'react'
-import LazyLoad from 'react-lazy-load'
-import ProductSimilar from '../ProductSimilar'
-import { toast } from 'react-hot-toast'
-import { updateItemCart } from '@/core/utils/cart'
-import { useRouter } from 'next/router'
-import { createSlug } from '@/core/utils/slug'
-import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
-import ProductCard from '../ProductCard'
-import productSimilarApi from '../../api/productSimilarApi'
-import whatsappUrl from '@/core/utils/whatsappUrl'
-import odooApi from '@/core/api/odooApi'
-import PromotionType from '@/lib/promotinProgram/components/PromotionType'
-import useAuth from '@/core/hooks/useAuth'
-import ImageNext from 'next/image'
-import CountDown2 from '@/core/components/elements/CountDown/CountDown2'
-import { LazyLoadComponent } from 'react-lazy-load-image-component'
-import ColumnsSLA from './ColumnsSLA'
-import { useProductCartContext } from '@/contexts/ProductCartContext'
-import { Box, Skeleton, Tooltip } from '@chakra-ui/react'
-import { Info } from 'lucide-react'
-import Breadcrumb from './Breadcrumb'
-import { sellingProductFormat } from '@/core/utils/formatValue'
+import { useEffect, useRef, useState } from 'react';
+import ImageNext from 'next/image';
+import { LazyLoadComponent } from 'react-lazy-load-image-component';
+import { Box, Skeleton, Tooltip } from '@chakra-ui/react';
+import { HeartIcon } from '@heroicons/react/24/outline';
+import { Info } from 'lucide-react';
+import LazyLoad from 'react-lazy-load';
+import { toast } from 'react-hot-toast';
+import { useRouter } from 'next/router';
+
+import Image from '@/core/components/elements/Image/Image';
+import Link from '@/core/components/elements/Link/Link';
+import DesktopView from '@/core/components/views/DesktopView';
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup';
+import CountDown2 from '@/core/components/elements/CountDown/CountDown2';
+
+import currencyFormat from '@/core/utils/currencyFormat';
+import { updateItemCart } from '@/core/utils/cart';
+import { createSlug } from '@/core/utils/slug';
+import whatsappUrl from '@/core/utils/whatsappUrl';
+import { sellingProductFormat } from '@/core/utils/formatValue';
+
+import odooApi from '@/core/api/odooApi';
+import useAuth from '@/core/hooks/useAuth';
+
+import { useProductCartContext } from '@/contexts/ProductCartContext';
+
+import PromotionType from '@/lib/promotinProgram/components/PromotionType';
+
+import ProductSimilar from '../ProductSimilar';
+import ProductCard from '../ProductCard';
+import productSimilarApi from '../../api/productSimilarApi';
+import ColumnsSLA from './ColumnsSLA';
+import Breadcrumb from './Breadcrumb';
+
+import ProductPromoSection from '~/modules/product-promo/components/Section';
const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
- const router = useRouter()
- const auth = useAuth()
- const { slug } = router.query
+ const router = useRouter();
+ const auth = useAuth();
+ const { slug } = router.query;
- const [quantityActive, setQuantity] = useState(null)
- const [lowestPrice, setLowestPrice] = useState(null)
- const [product, setProducts] = useState(products)
+ const [quantityActive, setQuantity] = useState(null);
+ const [lowestPrice, setLowestPrice] = useState(null);
+ const [product, setProducts] = useState(products);
- const [addCartAlert, setAddCartAlert] = useState(false)
- const [isLoadingSLA, setIsLoadingSLA] = useState(true)
- const [promotionType, setPromotionType] = useState(false)
- const [promotionActiveId, setPromotionActiveId] = useState(null)
- const [selectVariantPromoActive, setSelectVariantPromoActive] = useState(null)
- const [backgorundFlashSale, setBackgorundFlashSale] = useState(null)
+ const [addCartAlert, setAddCartAlert] = useState(false);
+ const [isLoadingSLA, setIsLoadingSLA] = useState(true);
+ const [promotionType, setPromotionType] = useState(false);
+ const [promotionActiveId, setPromotionActiveId] = useState(null);
+ const [selectVariantPromoActive, setSelectVariantPromoActive] =
+ useState(null);
+ const [backgorundFlashSale, setBackgorundFlashSale] = useState(null);
- const { setRefreshCart, refreshCart } = useProductCartContext()
+ const { setRefreshCart, refreshCart } = useProductCartContext();
useEffect(() => {
- setLowestPrice({ price: product?.lowestPrice })
- }, [product])
+ setLowestPrice({ price: product?.lowestPrice });
+ }, [product]);
useEffect(() => {
const getBackgound = async () => {
- const get = await odooApi('GET', '/api/v1/banner?type=flash-sale-background-banner')
- setBackgorundFlashSale(get[0].image)
- }
- getBackgound()
- }, [])
+ const get = await odooApi(
+ 'GET',
+ '/api/v1/banner?type=flash-sale-background-banner'
+ );
+ setBackgorundFlashSale(get[0].image);
+ };
+ getBackgound();
+ }, []);
- const [informationTab, setInformationTab] = useState(informationTabOptions[0].value)
+ const [informationTab, setInformationTab] = useState(
+ informationTabOptions[0].value
+ );
- const variantQuantityRefs = useRef([])
+ const variantQuantityRefs = useRef([]);
const setVariantQuantityRef = (variantId) => (element) => {
if (element) {
- let variantIndex = product.variants.findIndex((varian) => varian.id == variantId)
- product.variants[variantIndex].quantity = element?.value
+ let variantIndex = product.variants.findIndex(
+ (varian) => varian.id == variantId
+ );
+ product.variants[variantIndex].quantity = element?.value;
}
- variantQuantityRefs.current[variantId] = element
- }
+ variantQuantityRefs.current[variantId] = element;
+ };
const validQuantity = (quantity) => {
- let isValid = true
+ let isValid = true;
if (!quantity || quantity < 1 || isNaN(parseInt(quantity))) {
- toast.error('Jumlah barang minimal 1')
- isValid = false
+ toast.error('Jumlah barang minimal 1');
+ isValid = false;
}
- return isValid
- }
+ return isValid;
+ };
const updateCart = (variantId, quantity, source) => {
let dataUpdate = {
productId: variantId,
quantity,
selected: true,
- source: source === 'buy' ? 'buy' : null
- }
+ source: source === 'buy' ? 'buy' : null,
+ };
if (product.variants.length > 1) {
- let variantIndex = product.variants.findIndex((varian) => varian.id == variantId)
- dataUpdate['programLineId'] = product.variants[variantIndex].programActive
+ let variantIndex = product.variants.findIndex(
+ (varian) => varian.id == variantId
+ );
+ dataUpdate['programLineId'] =
+ product.variants[variantIndex].programActive;
} else {
- dataUpdate['programLineId'] = promotionActiveId
+ dataUpdate['programLineId'] = promotionActiveId;
}
- updateItemCart(dataUpdate)
- }
+ updateItemCart(dataUpdate);
+ };
const redirectToLogin = (action, variantId, quantity) => {
- const nextURL = `/shop/product/${slug}?action=${action}&variantId=${variantId}&qty=${quantity}`
- router.push(`/login?next=${encodeURIComponent(nextURL)}`)
- return true
- }
+ const nextURL = `/shop/product/${slug}?action=${action}&variantId=${variantId}&qty=${quantity}`;
+ router.push(`/login?next=${encodeURIComponent(nextURL)}`);
+ return true;
+ };
const handleAddToCart = (variantId) => {
- const quantity = variantQuantityRefs.current[variantId].value
+ const quantity = variantQuantityRefs.current[variantId].value;
- if (!validQuantity(quantity)) return
+ if (!validQuantity(quantity)) return;
if (!auth) {
- return redirectToLogin('add_to_cart', variantId, quantity)
+ return redirectToLogin('add_to_cart', variantId, quantity);
}
- let source = 'cart'
- updateCart(variantId, quantity, source)
- setRefreshCart(true)
- setAddCartAlert(true)
- }
+ let source = 'cart';
+ updateCart(variantId, quantity, source);
+ setRefreshCart(true);
+ setAddCartAlert(true);
+ };
const handleQuantityChange = (variantId) => (event) => {
- const { value } = event.target
- const variantIndex = product.variants.findIndex((variant) => variant.id === variantId)
+ const { value } = event.target;
+ const variantIndex = product.variants.findIndex(
+ (variant) => variant.id === variantId
+ );
if (variantIndex !== -1) {
- product.variants[variantIndex].quantity = parseInt(value, 10) // Pastikan untuk mengubah ke tipe number jika diperlukan
+ product.variants[variantIndex].quantity = parseInt(value, 10); // Pastikan untuk mengubah ke tipe number jika diperlukan
// Lakukan sesuatu jika nilai quantity diubah
}
- }
+ };
const handleBuy = (variant) => {
- const quantity = variantQuantityRefs.current[variant].value
- if (!validQuantity(quantity)) return
+ const quantity = variantQuantityRefs.current[variant].value;
+ if (!validQuantity(quantity)) return;
if (!auth) {
- return redirectToLogin('buy', variant, quantity)
+ return redirectToLogin('buy', variant, quantity);
}
- let source = 'buy'
- updateCart(variant, quantity, source)
- router.push(`/shop/checkout?source=buy`)
- }
+ let source = 'buy';
+ updateCart(variant, quantity, source);
+ router.push(`/shop/checkout?source=buy`);
+ };
- const variantSectionRef = useRef(null)
+ const variantSectionRef = useRef(null);
const goToVariantSection = () => {
if (variantSectionRef.current) {
- const position = variantSectionRef.current.getBoundingClientRect()
+ const position = variantSectionRef.current.getBoundingClientRect();
window.scrollTo({
top: position.top - 120 + window.pageYOffset,
- behavior: 'smooth'
- })
+ behavior: 'smooth',
+ });
}
- }
+ };
const handlePromoClick = (variantId) => {
- setSelectVariantPromoActive(variantId)
- setPromotionType(true)
- }
+ setSelectVariantPromoActive(variantId);
+ setPromotionType(true);
+ };
const productSimilarQuery = [
product?.name,
`fq=-product_id_i:${product.id}`,
- `fq=-manufacture_id_i:${product.manufacture?.id || 0}`
- ].join('&')
+ `fq=-manufacture_id_i:${product.manufacture?.id || 0}`,
+ ].join('&');
- const [productSimilarInBrand, setProductSimilarInBrand] = useState(null)
+ const [productSimilarInBrand, setProductSimilarInBrand] = useState(null);
useEffect(() => {
const loadProductSimilarInBrand = async () => {
- const productSimilarQuery = [product?.name, `fq=-product_id_i:${product.id}`].join('&')
- const source = 'right'
- const dataProductSimilar = await productSimilarApi({ query: productSimilarQuery, source })
- setProductSimilarInBrand(dataProductSimilar.products)
- }
- if (!productSimilarInBrand) loadProductSimilarInBrand()
- }, [product, productSimilarInBrand])
+ const productSimilarQuery = [
+ product?.name,
+ `fq=-product_id_i:${product.id}`,
+ ].join('&');
+ const source = 'right';
+ const dataProductSimilar = await productSimilarApi({
+ query: productSimilarQuery,
+ source,
+ });
+ setProductSimilarInBrand(dataProductSimilar.products);
+ };
+ if (!productSimilarInBrand) loadProductSimilarInBrand();
+ }, [product, productSimilarInBrand]);
useEffect(() => {
const fetchData = async () => {
const promises = product.variants.map(async (variant) => {
- const dataSLA = await odooApi('GET', `/api/v1/product_variant/${variant.id}/stock`)
+ const dataSLA = await odooApi(
+ 'GET',
+ `/api/v1/product_variant/${variant.id}/stock`
+ );
return {
...variant,
- sla: dataSLA
- }
- })
- const variantData = await Promise.all(promises)
- product.variants = variantData
+ sla: dataSLA,
+ };
+ });
+ const variantData = await Promise.all(promises);
+ product.variants = variantData;
- setIsLoadingSLA(false)
- }
- if (product.variantTotal == 1) fetchData()
- }, [product])
+ setIsLoadingSLA(false);
+ };
+ if (product.variantTotal == 1) fetchData();
+ }, [product]);
return (
<DesktopView>
<div className='container mx-auto pt-10'>
<Breadcrumb productId={product.id} productName={product.name} />
- <div className='flex'>
- <div className='w-full flex flex-wrap'>
- <div className='w-5/12'>
- <div className='relative mb-2'>
- {product?.flashSale?.remainingTime > 0 &&
- lowestPrice?.price.discountPercentage > 0 && (
- <div className={`absolute bottom-0 w-full`}>
- <div className='absolute bottom-0 w-full h-full'>
- <ImageNext
- src={backgorundFlashSale || '/images/GAMBAR-BG-FLASH-SALE.jpg'}
- width={1000}
- height={100}
- />
- </div>
- <div className='relative'>
- <div className='flex gap-x-2 items-center p-2'>
- <div className='bg-yellow-400 rounded-full p-1 h-9 w-20 flex items-center justify-center '>
- <span className='text-lg font-bold'>
- {Math.floor(product.lowestPrice.discountPercentage)}%
- </span>
- </div>
- <div
- className={`bg-red-600 border border-solid border-yellow-400 rounded-full h-9 p-2 flex w-[50%] items-center justify-center gap-x-4`}
- >
- <ImageNext
- src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg'
- width={17}
- height={10}
- />
- <span className='text-white text-lg font-semibold'>
- {product?.flashSale?.tag != 'false' || product?.flashSale?.tag
- ? product?.flashSale?.tag
- : 'FLASH SALE'}
- </span>
- </div>
- <div>
- <CountDown2 initialTime={product.flashSale.remainingTime} />
- </div>
+
+ <div className='w-full flex flex-wrap'>
+ <div className='w-3/12'>
+ <div className='relative mb-2'>
+ {product?.flashSale?.remainingTime > 0 &&
+ lowestPrice?.price.discountPercentage > 0 && (
+ <div className={`absolute bottom-0 w-full`}>
+ <div className='absolute bottom-0 w-full h-full'>
+ <ImageNext
+ src={
+ backgorundFlashSale ||
+ '/images/GAMBAR-BG-FLASH-SALE.jpg'
+ }
+ width={1000}
+ height={100}
+ />
+ </div>
+ <div className='relative'>
+ <div className='flex gap-x-2 items-center p-2'>
+ <div className='bg-yellow-400 rounded-full p-1 h-9 w-20 flex items-center justify-center '>
+ <span className='text-lg font-bold'>
+ {Math.floor(product.lowestPrice.discountPercentage)}
+ %
+ </span>
+ </div>
+ <div
+ className={`bg-red-600 border border-solid border-yellow-400 rounded-full h-9 p-2 flex w-[50%] items-center justify-center gap-x-4`}
+ >
+ <ImageNext
+ src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg'
+ width={17}
+ height={10}
+ />
+ <span className='text-white text-lg font-semibold'>
+ {product?.flashSale?.tag != 'false' ||
+ product?.flashSale?.tag
+ ? product?.flashSale?.tag
+ : 'FLASH SALE'}
+ </span>
+ </div>
+ <div>
+ <CountDown2
+ initialTime={product.flashSale.remainingTime}
+ />
</div>
</div>
</div>
- )}
- <Image
- src={product.image}
- alt={product.name}
- className='h-[430px] object-contain object-center w-full border border-gray_r-4'
- />
- </div>
- <div>
- <p className='text-justify text-xs leading-5'>
- <span className='font-semibold '>Keterangan : </span>Gambar atau foto berperan
- sebagai ilustrasi produk. Kadang tidak sesuai dengan kondisi terbaru dengan
- berbagai perubahan dan perbaikan. Hubungi tim sales kami untuk informasi yang
- lebih baik perihal gambar di 021-2933 8828.
- </p>
- </div>
- </div>
-
- <div className='w-7/12 px-4'>
- <h1 className='text-title-md leading-10 font-medium'>{product?.name}</h1>
- <div className='mt-10'>
- <div className='flex p-3'>
- <div className='w-4/12 text-gray_r-12/70'>Nomor SKU</div>
- <div className='w-8/12'>SKU-{product.id}</div>
- </div>
- <div className='flex p-3 bg-gray_r-4'>
- <div className='w-4/12 text-gray_r-12/70'>Part Number</div>
- <div className='w-8/12'>{product.code || '-'}</div>
- </div>
- <div className='flex p-3'>
- <div className='w-4/12 text-gray_r-12/70'>Manufacture</div>
- <div className='w-8/12'>
- {product.manufacture?.name ? (
- <Link
- href={createSlug(
- '/shop/brands/',
- product.manufacture?.name,
- product.manufacture?.id
- )}
- >
- {product.manufacture?.name}
- </Link>
- ) : (
- <div>-</div>
- )}
</div>
- </div>
- <div className='flex p-3 items-center bg-gray_r-4'>
- <div className='w-4/12 text-gray_r-12/70'>Persiapan Barang</div>
- <div className='w-8/12'>
- {product.variants.length > 1 && (
- <button
- type='button'
- onClick={goToVariantSection}
- className={`flex gap-x-1 items-center p-2 rounded-lg w-auto btn-light`}
- >
- <span className='text-red-600 text-sm'>Lihat Selengkapnya</span>
- </button>
- )}
+ )}
+ <Image
+ src={product.image}
+ alt={product.name}
+ className='h-[430px] object-contain object-center w-full border border-gray_r-4'
+ />
+ </div>
+ <div>
+ <p className='text-justify text-xs leading-5'>
+ <span className='font-semibold '>Keterangan : </span>Gambar atau
+ foto berperan sebagai ilustrasi produk. Kadang tidak sesuai
+ dengan kondisi terbaru dengan berbagai perubahan dan perbaikan.
+ Hubungi tim sales kami untuk informasi yang lebih baik perihal
+ gambar di 021-2933 8828.
+ </p>
+ </div>
+ </div>
- {product.variants.length === 1 && (
- <>
- {!product.variants[0]?.sla && <Skeleton width='20%' height='16px' />}
- {product.variants[0]?.sla && (
- <Tooltip
- placement='top'
- label={`Masa Persiapan Barang ${product.variants[0]?.sla?.slaDate}`}
- >
- <Box className='w-fit flex items-center gap-x-2'>
- {product.variants[0]?.sla?.slaDate}
- <Info size={16} />
- </Box>
- </Tooltip>
- )}
- </>
- )}
- </div>
+ <div className='w-6/12 px-6'>
+ <h1 className='text-title-md leading-10 font-medium'>
+ {product?.name}
+ </h1>
+ <div className='mt-10'>
+ <div className='flex p-3'>
+ <div className='w-4/12 text-gray_r-12/70'>Nomor SKU</div>
+ <div className='w-8/12'>SKU-{product.id}</div>
+ </div>
+ <div className='flex p-3 bg-gray_r-4'>
+ <div className='w-4/12 text-gray_r-12/70'>Part Number</div>
+ <div className='w-8/12'>{product.code || '-'}</div>
+ </div>
+ <div className='flex p-3'>
+ <div className='w-4/12 text-gray_r-12/70'>Manufacture</div>
+ <div className='w-8/12'>
+ {product.manufacture?.name ? (
+ <Link
+ href={createSlug(
+ '/shop/brands/',
+ product.manufacture?.name,
+ product.manufacture?.id
+ )}
+ >
+ {product.manufacture?.name}
+ </Link>
+ ) : (
+ <div>-</div>
+ )}
</div>
+ </div>
+ <div className='flex p-3 items-center bg-gray_r-4'>
+ <div className='w-4/12 text-gray_r-12/70'>Persiapan Barang</div>
+ <div className='w-8/12'>
+ {product.variants.length > 1 && (
+ <button
+ type='button'
+ onClick={goToVariantSection}
+ className={`flex gap-x-1 items-center p-2 rounded-lg w-auto btn-light`}
+ >
+ <span className='text-red-600 text-sm'>
+ Lihat Selengkapnya
+ </span>
+ </button>
+ )}
- {product.variants.length === 1 && (
- <div className='flex p-3 '>
- <div className='w-4/12 text-gray_r-12/70'>Stock</div>
- <div className='w-8/12'>
- {!product.variants[0]?.sla && <Skeleton width='10%' height='16px' />}
- {product?.variants[0].sla?.qty > 0 && (
- <span>{product?.variants[0].sla?.qty}</span>
+ {product.variants.length === 1 && (
+ <>
+ {!product.variants[0]?.sla && (
+ <Skeleton width='20%' height='16px' />
)}
- {product?.variants[0].sla?.qty == 0 && (
- <a
- href={whatsappUrl('product', {
- name: product.name,
- manufacture: product?.manufacture?.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
- })}
- className='text-danger-500 font-medium'
+ {product.variants[0]?.sla && (
+ <Tooltip
+ placement='top'
+ label={`Masa Persiapan Barang ${product.variants[0]?.sla?.slaDate}`}
>
- Tanya Admin
- </a>
+ <Box className='w-fit flex items-center gap-x-2'>
+ {product.variants[0]?.sla?.slaDate}
+ <Info size={16} />
+ </Box>
+ </Tooltip>
)}
- </div>
- </div>
- )}
+ </>
+ )}
+ </div>
+ </div>
- <div className={`flex p-3 ${product.variants.length > 1 ? '' : 'bg-gray_r-4'} `}>
- <div className='w-4/12 text-gray_r-12/70'>Berat Barang</div>
+ {product.variants.length === 1 && (
+ <div className='flex p-3 '>
+ <div className='w-4/12 text-gray_r-12/70'>Stock</div>
<div className='w-8/12'>
- {product?.weight > 0 && <span>{product?.weight} KG</span>}
- {product?.weight == 0 && (
+ {!product.variants[0]?.sla && (
+ <Skeleton width='10%' height='16px' />
+ )}
+ {product?.variants[0].sla?.qty > 0 && (
+ <span>{product?.variants[0].sla?.qty}</span>
+ )}
+ {product?.variants[0].sla?.qty == 0 && (
<a
- href={whatsappUrl('productWeight', {
+ href={whatsappUrl('product', {
name: product.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
+ manufacture: product?.manufacture?.name,
+ url: createSlug(
+ '/shop/product/',
+ product.name,
+ product.id,
+ true
+ ),
})}
className='text-danger-500 font-medium'
>
- Tanya Berat
+ Tanya Admin
</a>
)}
</div>
</div>
- {product.variants.length <= 1 && (
- <div className='pt-3'>
- <div className='flex mt-1'>
- <PromotionType
- variantId={product.variants[0].id}
- setPromotionActiveId={setPromotionActiveId}
- promotionActiveId={promotionActiveId}
- quantity={quantityActive}
- product={product}
- ></PromotionType>
- </div>
- </div>
- )}
- </div>
- </div>
+ )}
- <div className='w-full'>
- <div className='mt-12'>
- <div className='text-h-lg font-semibold'>Informasi Produk</div>
- <div className='flex gap-x-4 mt-6 mb-4'>
- {informationTabOptions.map((option) => (
- <TabButton
- value={option.value}
- key={option.value}
- active={informationTab == option.value}
- onClick={() => setInformationTab(option.value)}
+ <div
+ className={`flex p-3 ${
+ product.variants.length > 1 ? '' : 'bg-gray_r-4'
+ } `}
+ >
+ <div className='w-4/12 text-gray_r-12/70'>Berat Barang</div>
+ <div className='w-8/12'>
+ {product?.weight > 0 && <span>{product?.weight} KG</span>}
+ {product?.weight == 0 && (
+ <a
+ href={whatsappUrl('productWeight', {
+ name: product.name,
+ url: createSlug(
+ '/shop/product/',
+ product.name,
+ product.id,
+ true
+ ),
+ })}
+ className='text-danger-500 font-medium'
>
- {option.label}
- </TabButton>
- ))}
+ Tanya Berat
+ </a>
+ )}
</div>
- <div className='flex'>
- <div className='w-3/4 leading-8 product__description'>
- <TabContent active={informationTab == 'description'}>
- <span
- dangerouslySetInnerHTML={{
- __html:
- product.description != ''
- ? product.description
- : 'Belum ada deskripsi produk.'
- }}
- />
- </TabContent>
-
- <TabContent active={informationTab == 'information'}>
- Belum ada informasi.
- </TabContent>
+ </div>
+ {product.variants.length <= 1 && (
+ <div className='pt-3'>
+ <div className='flex mt-1'>
+ <PromotionType
+ variantId={product.variants[0].id}
+ setPromotionActiveId={setPromotionActiveId}
+ promotionActiveId={promotionActiveId}
+ quantity={quantityActive}
+ product={product}
+ ></PromotionType>
+ <ProductPromoSection productId={product.variants[0].id} />
</div>
</div>
- </div>
+ )}
</div>
</div>
- <div className='w-[30%]'>
- {product.variants.length > 1 && product.lowestPrice.priceDiscount > 0 && (
- <div className='text-gray_r-12/80'>Harga mulai dari: </div>
- )}
+ <div className='w-3/12'>
+ {product.variants.length > 1 &&
+ product.lowestPrice.priceDiscount > 0 && (
+ <div className='text-gray_r-12/80'>Harga mulai dari: </div>
+ )}
{/* {lowestPrice?.discountPercentage > 0 && (
<div className='flex gap-x-1 items-center mt-2'>
@@ -441,7 +466,8 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
{sellingProductFormat(product?.qtySold) + ' Terjual'}
</div>
)}
- {product?.flashSale?.id && lowestPrice?.price.discountPercentage > 0 ? (
+ {product?.flashSale?.id &&
+ lowestPrice?.price.discountPercentage > 0 ? (
<>
<div className='flex gap-x-1 items-center mt-2'>
<div className='badge-solid-red text-caption-1'>
@@ -456,7 +482,10 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
</div>
<div className='text-gray_r-9 text-base font-normal mt-1'>
Termasuk PPN:{' '}
- {currencyFormat(lowestPrice?.price.priceDiscount * process.env.NEXT_PUBLIC_PPN)}
+ {currencyFormat(
+ lowestPrice?.price.priceDiscount *
+ process.env.NEXT_PUBLIC_PPN
+ )}
</div>
</>
) : (
@@ -466,7 +495,9 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
{currencyFormat(lowestPrice?.price.price)}
<div className='text-gray_r-9 text-base font-normal mt-1'>
Termasuk PPN:{' '}
- {currencyFormat(lowestPrice?.price.price * process.env.NEXT_PUBLIC_PPN)}
+ {currencyFormat(
+ lowestPrice?.price.price * process.env.NEXT_PUBLIC_PPN
+ )}
</div>
</>
) : (
@@ -476,7 +507,12 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
href={whatsappUrl('product', {
name: product.name,
manufacture: product.manufacture?.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
+ url: createSlug(
+ '/shop/product/',
+ product.name,
+ product.id,
+ true
+ ),
})}
className='text-danger-500 underline'
rel='noopener noreferrer'
@@ -524,7 +560,10 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
)}
<div className='flex mt-4'>
- <button className='flex items-center gap-x-1' onClick={toggleWishlist}>
+ <button
+ className='flex items-center gap-x-1'
+ onClick={toggleWishlist}
+ >
{wishlist.data?.productTotal > 0 ? (
<HeartIcon className='w-6 fill-danger-500 text-danger-500' />
) : (
@@ -538,7 +577,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
<div className='font-medium text-center p-4 bg-gray_r-1 border-b border-gray_r-6 sticky top-0 z-10'>
Produk Serupa
</div>
- <div className='h-full divide-y divide-gray_r-6 max-h-96'>
+ <div className='h-full divide-y divide-gray_r-6 max-h-[550px]'>
{productSimilarInBrand &&
productSimilarInBrand?.map((product) => (
<div className='py-2' key={product.id}>
@@ -550,6 +589,42 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
</div>
</div>
+ <div className='w-full'>
+ <div className='mt-12'>
+ <div className='text-h-lg font-semibold'>Informasi Produk</div>
+ <div className='flex gap-x-4 mt-6 mb-4'>
+ {informationTabOptions.map((option) => (
+ <TabButton
+ value={option.value}
+ key={option.value}
+ active={informationTab == option.value}
+ onClick={() => setInformationTab(option.value)}
+ >
+ {option.label}
+ </TabButton>
+ ))}
+ </div>
+ <div className='flex'>
+ <div className='w-3/4 leading-8 product__description'>
+ <TabContent active={informationTab == 'description'}>
+ <span
+ dangerouslySetInnerHTML={{
+ __html:
+ product.description != ''
+ ? product.description
+ : 'Belum ada deskripsi produk.',
+ }}
+ />
+ </TabContent>
+
+ <TabContent active={informationTab == 'information'}>
+ Belum ada informasi.
+ </TabContent>
+ </div>
+ </div>
+ </div>
+ </div>
+
{product.variants.length > 1 && (
<div className='mt-12' ref={variantSectionRef}>
<div className='text-h-lg font-semibold mb-6'>Varian Produk</div>
@@ -571,7 +646,9 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
<tr key={variant.id}>
<td className='flex items-center justify-center gap-x-1'>
{variant.isFlashsale && (
- <span className='blink-color-flash-sale'>&#128498;</span>
+ <span className='blink-color-flash-sale'>
+ &#128498;
+ </span>
)}
{variant.code}
</td>
@@ -580,11 +657,13 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
<ColumnsSLA variant={variant} product={product} />
</LazyLoadComponent>
<td>
- {variant.isFlashsale && variant?.price?.discountPercentage > 0 ? (
+ {variant.isFlashsale &&
+ variant?.price?.discountPercentage > 0 ? (
<>
<div className='flex items-center gap-x-1 justify-center'>
<div className='badge-solid-red text-caption-1'>
- {Math.floor(variant?.price?.discountPercentage)}%
+ {Math.floor(variant?.price?.discountPercentage)}
+ %
</div>
<div className='line-through text-caption-1 text-gray_r-11'>
{currencyFormat(variant?.price?.price)}
@@ -596,7 +675,8 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
<div className=' text-caption-1 text-gray_r-11 mb-1'>
Inc. PPN:{' '}
{currencyFormat(
- variant.price.priceDiscount * process.env.NEXT_PUBLIC_PPN
+ variant.price.priceDiscount *
+ process.env.NEXT_PUBLIC_PPN
)}
</div>
</>
@@ -610,7 +690,8 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
<div className=' text-caption-1 text-gray_r-11 mb-1'>
Inc. PPN:{' '}
{currencyFormat(
- variant?.price?.price * process.env.NEXT_PUBLIC_PPN
+ variant?.price?.price *
+ process.env.NEXT_PUBLIC_PPN
)}
</div>
</>
@@ -619,7 +700,12 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
href={whatsappUrl('product', {
name: variant.name,
manufacture: product.manufacture?.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
+ url: createSlug(
+ '/shop/product/',
+ product.name,
+ product.id,
+ true
+ ),
})}
className='text-red_r-11'
rel='noopener noreferrer'
@@ -705,11 +791,14 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
)}
<div className='my-12'>
- <div className='text-h-lg font-semibold mb-6'>Kamu Mungkin Juga Suka</div>
+ <div className='text-h-lg font-semibold mb-6'>
+ Kamu Mungkin Juga Suka
+ </div>
<LazyLoad>
<ProductSimilar query={productSimilarQuery} />
</LazyLoad>
</div>
+
<BottomPopup
className=' !h-[75%]'
title='Pakai Promo'
@@ -728,6 +817,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
></PromotionType>
</div>
</BottomPopup>
+
<BottomPopup
className='!container'
title='Berhasil Ditambahkan'
@@ -742,16 +832,23 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
className='h-32 object-contain object-center w-full border border-gray_r-4'
/>
</div>
- <div className='ml-3 flex flex-1 items-center font-normal'>{product.name}</div>
+ <div className='ml-3 flex flex-1 items-center font-normal'>
+ {product.name}
+ </div>
<div className='ml-3 flex items-center font-normal'>
- <Link href='/shop/cart' className='flex-1 py-2 text-gray_r-12 btn-yellow'>
+ <Link
+ href='/shop/cart'
+ className='flex-1 py-2 text-gray_r-12 btn-yellow'
+ >
Lihat Keranjang
</Link>
</div>
</div>
<div className='mt-8 mb-4'>
- <div className='text-h-sm font-semibold mb-6'>Kamu Mungkin Juga Suka</div>
+ <div className='text-h-sm font-semibold mb-6'>
+ Kamu Mungkin Juga Suka
+ </div>
<LazyLoad>
<ProductSimilar query={productSimilarQuery} />
</LazyLoad>
@@ -759,29 +856,33 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
</BottomPopup>
</div>
</DesktopView>
- )
-}
+ );
+};
const informationTabOptions = [
{ value: 'description', label: 'Deskripsi' },
- { value: 'information', label: 'Info Penting' }
-]
+ { value: 'information', label: 'Info Penting' },
+];
const TabButton = ({ children, active, ...props }) => {
const activeClassName = active
? 'text-danger-500 underline underline-offset-4'
- : 'text-gray_r-12/80'
+ : 'text-gray_r-12/80';
return (
- <button {...props} type='button' className={`font-medium ${activeClassName}`}>
+ <button
+ {...props}
+ type='button'
+ className={`font-medium ${activeClassName}`}
+ >
{children}
</button>
- )
-}
+ );
+};
const TabContent = ({ children, active, className = '', ...props }) => (
<div {...props} className={`${active ? 'block' : 'hidden'} ${className}`}>
{children}
</div>
-)
+);
-export default ProductDesktop
+export default ProductDesktop;
diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx
index e23e2fb9..e9e64469 100644
--- a/src/lib/product/components/Product/ProductMobile.jsx
+++ b/src/lib/product/components/Product/ProductMobile.jsx
@@ -1,60 +1,66 @@
-import Divider from '@/core/components/elements/Divider/Divider'
-import Image from '@/core/components/elements/Image/Image'
-import Link from '@/core/components/elements/Link/Link'
-import currencyFormat from '@/core/utils/currencyFormat'
-import { useEffect, useState } from 'react'
-import Select from 'react-select'
-import ProductSimilar from '../ProductSimilar'
-import LazyLoad from 'react-lazy-load'
-import { updateItemCart } from '@/core/utils/cart'
-import { HeartIcon } from '@heroicons/react/24/outline'
-import { useRouter } from 'next/router'
-import MobileView from '@/core/components/views/MobileView'
-import { toast } from 'react-hot-toast'
-import { createSlug } from '@/core/utils/slug'
-import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
-import whatsappUrl from '@/core/utils/whatsappUrl'
-import PromotionType from '@/lib/promotinProgram/components/PromotionType'
-import { gtagAddToCart } from '@/core/utils/googleTag'
-import odooApi from '@/core/api/odooApi'
-import ImageNext from 'next/image'
-import CountDown2 from '@/core/components/elements/CountDown/CountDown2'
-import Breadcrumb from './Breadcrumb'
-import useAuth from '@/core/hooks/useAuth'
-import { sellingProductFormat } from '@/core/utils/formatValue'
+import Divider from '@/core/components/elements/Divider/Divider';
+import Image from '@/core/components/elements/Image/Image';
+import Link from '@/core/components/elements/Link/Link';
+import currencyFormat from '@/core/utils/currencyFormat';
+import { useEffect, useState } from 'react';
+import Select from 'react-select';
+import ProductSimilar from '../ProductSimilar';
+import LazyLoad from 'react-lazy-load';
+import { updateItemCart } from '@/core/utils/cart';
+import { HeartIcon } from '@heroicons/react/24/outline';
+import { useRouter } from 'next/router';
+import MobileView from '@/core/components/views/MobileView';
+import { toast } from 'react-hot-toast';
+import { createSlug } from '@/core/utils/slug';
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup';
+import whatsappUrl from '@/core/utils/whatsappUrl';
+import PromotionType from '@/lib/promotinProgram/components/PromotionType';
+import { gtagAddToCart } from '@/core/utils/googleTag';
+import odooApi from '@/core/api/odooApi';
+import ImageNext from 'next/image';
+import CountDown2 from '@/core/components/elements/CountDown/CountDown2';
+import Breadcrumb from './Breadcrumb';
+import useAuth from '@/core/hooks/useAuth';
+import { sellingProductFormat } from '@/core/utils/formatValue';
+import ProductPromoSection from '~/modules/product-promo/components/Section';
const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
- const router = useRouter()
- const auth = useAuth()
- const { slug } = router.query
-
- const [quantity, setQuantity] = useState('1')
- const [selectedVariant, setSelectedVariant] = useState(null)
- const [informationTab, setInformationTab] = useState(informationTabOptions[0].value)
- const [addCartAlert, setAddCartAlert] = useState(false)
-
- const [isLoadingSLA, setIsLoadingSLA] = useState(true)
- const [promotionType, setPromotionType] = useState(false)
- const [promotionActiveId, setPromotionActiveId] = useState(null)
- const [backgorundFlashSale, setBackgorundFlashSale] = useState(null)
+ const router = useRouter();
+ const auth = useAuth();
+ const { slug } = router.query;
+
+ const [quantity, setQuantity] = useState('1');
+ const [selectedVariant, setSelectedVariant] = useState(null);
+ const [informationTab, setInformationTab] = useState(
+ informationTabOptions[0].value
+ );
+ const [addCartAlert, setAddCartAlert] = useState(false);
+
+ const [isLoadingSLA, setIsLoadingSLA] = useState(true);
+ const [promotionType, setPromotionType] = useState(false);
+ const [promotionActiveId, setPromotionActiveId] = useState(null);
+ const [backgorundFlashSale, setBackgorundFlashSale] = useState(null);
const getLowestPrice = () => {
- const prices = product.variants.map((variant) => variant.price)
+ const prices = product.variants.map((variant) => variant.price);
const lowest = prices.reduce((lowest, price) => {
- return price.priceDiscount < lowest.priceDiscount ? price : lowest
- }, prices[0])
- return lowest
- }
+ return price.priceDiscount < lowest.priceDiscount ? price : lowest;
+ }, prices[0]);
+ return lowest;
+ };
useEffect(() => {
const getBackgound = async () => {
- const get = await odooApi('GET', '/api/v1/banner?type=flash-sale-background-banner')
+ const get = await odooApi(
+ 'GET',
+ '/api/v1/banner?type=flash-sale-background-banner'
+ );
if (get.length > 0) {
- setBackgorundFlashSale(get[0].image)
+ setBackgorundFlashSale(get[0].image);
}
- }
- getBackgound()
- }, [])
+ };
+ getBackgound();
+ }, []);
const [activeVariant, setActiveVariant] = useState({
id: null,
@@ -64,40 +70,44 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
stock: product.stockTotal,
weight: product.weight,
hasProgram: false,
- qtySold: product.qtySold
- })
+ qtySold: product.qtySold,
+ });
const variantOptions = product.variants?.map((variant) => {
- let label = []
+ let label = [];
if (variant.isFlashsale) {
- label.push("<span class='blink-color-flash-sale'>&#128498;</span>")
+ label.push("<span class='blink-color-flash-sale'>&#128498;</span>");
}
if (variant.code) {
- label.push(`[${variant.code}]`)
+ label.push(`[${variant.code}]`);
}
if (variant.attributes.length > 0) {
- label.push(variant.attributes.join(', '))
+ label.push(variant.attributes.join(', '));
} else {
- label.push(product.name)
+ label.push(product.name);
}
return {
value: variant.id,
- label: label.join(' ')
- }
- })
+ label: label.join(' '),
+ };
+ });
useEffect(() => {
if (!selectedVariant && variantOptions.length == 1) {
- setSelectedVariant(variantOptions[0])
+ setSelectedVariant(variantOptions[0]);
}
- }, [selectedVariant, variantOptions])
+ }, [selectedVariant, variantOptions]);
useEffect(() => {
if (selectedVariant) {
- const variant = product.variants.find((variant) => variant.id == selectedVariant.value)
+ const variant = product.variants.find(
+ (variant) => variant.id == selectedVariant.value
+ );
const variantAttributes =
- variant.attributes.length > 0 ? ' - ' + variant.attributes.join(', ') : ''
+ variant.attributes.length > 0
+ ? ' - ' + variant.attributes.join(', ')
+ : '';
const newActiveVariant = {
id: variant.id,
@@ -108,60 +118,63 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
weight: variant.weight,
hasProgram: variant.hasProgram,
isFlashsale: variant.isFlashsale,
- qtySold: variant.qtySold
- }
+ qtySold: variant.qtySold,
+ };
- setActiveVariant(newActiveVariant)
+ setActiveVariant(newActiveVariant);
const fetchSLA = async () => {
- const dataSLA = await odooApi('GET', `/api/v1/product_variant/${variant.id}/stock`)
- setActiveVariant({ ...newActiveVariant, sla: dataSLA })
- }
- fetchSLA()
+ const dataSLA = await odooApi(
+ 'GET',
+ `/api/v1/product_variant/${variant.id}/stock`
+ );
+ setActiveVariant({ ...newActiveVariant, sla: dataSLA });
+ };
+ fetchSLA();
}
- }, [selectedVariant, product])
+ }, [selectedVariant, product]);
const validAction = () => {
- let isValid = true
+ let isValid = true;
if (!selectedVariant) {
- toast.error('Pilih varian terlebih dahulu')
- isValid = false
+ toast.error('Pilih varian terlebih dahulu');
+ isValid = false;
}
if (!quantity || quantity < 1 || isNaN(parseInt(quantity))) {
- toast.error('Jumlah barang minimal 1')
- isValid = false
+ toast.error('Jumlah barang minimal 1');
+ isValid = false;
}
- return isValid
- }
+ return isValid;
+ };
const redirectToLogin = (action) => {
- const nextURL = `/shop/product/${slug}?action=${action}&variantId=${activeVariant.id}&qty=${quantity}`
- router.push(`/login?next=${encodeURIComponent(nextURL)}`)
- return true
- }
+ const nextURL = `/shop/product/${slug}?action=${action}&variantId=${activeVariant.id}&qty=${quantity}`;
+ router.push(`/login?next=${encodeURIComponent(nextURL)}`);
+ return true;
+ };
const handleClickCart = () => {
- if (!validAction()) return
- gtagAddToCart(activeVariant, quantity)
+ if (!validAction()) return;
+ gtagAddToCart(activeVariant, quantity);
if (!auth) {
- return redirectToLogin('add_to_cart')
+ return redirectToLogin('add_to_cart');
}
updateItemCart({
productId: activeVariant.id,
quantity,
programLineId: promotionActiveId,
- selected: true
- })
- setAddCartAlert(true)
- }
+ selected: true,
+ });
+ setAddCartAlert(true);
+ };
const handleClickBuy = () => {
- if (!validAction()) return
+ if (!validAction()) return;
if (!auth) {
- return redirectToLogin('buy')
+ return redirectToLogin('buy');
}
updateItemCart({
@@ -169,58 +182,62 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
quantity,
programLineId: promotionActiveId,
selected: true,
- source: 'buy'
- })
- router.push(`/shop/checkout?source=buy`)
- }
+ source: 'buy',
+ });
+ router.push(`/shop/checkout?source=buy`);
+ };
const productSimilarQuery = [
product?.name,
`fq=-product_id_i:${product.id}`,
- `fq=-manufacture_id_i:${product.manufacture?.id || 0}`
- ].join('&')
+ `fq=-manufacture_id_i:${product.manufacture?.id || 0}`,
+ ].join('&');
return (
<MobileView>
<Breadcrumb productId={product.id} productName={product.name} />
<div className='relative'>
- {product?.flashSale?.remainingTime > 0 && activeVariant?.price.discountPercentage > 0 && (
- <div className={`absolute bottom-0 w-full`}>
- <div className='absolute bottom-0 w-full'>
- <ImageNext
- src={backgorundFlashSale || '/images/GAMBAR-BG-FLASH-SALE.jpg'}
- width={1000}
- height={100}
- />
- </div>
- <div className='relative'>
- <div className='flex gap-x-2 items-center p-2'>
- <div className='bg-yellow-400 rounded-full p-1 h-9 w-20 flex items-center justify-center '>
- <span className='text-lg font-bold'>
- {Math.floor(product.lowestPrice.discountPercentage)}%
- </span>
- </div>
- <div
- className={`bg-red-600 border border-solid border-yellow-400 rounded-full h-9 p-2 flex w-[50%] items-center justify-center gap-x-4`}
- >
- <ImageNext
- src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg'
- width={17}
- height={10}
- />
- <span className='text-white text-lg font-semibold'>
- {product?.flashSale?.tag != 'false' || product?.flashSale?.tag
- ? product?.flashSale?.tag
- : 'FLASH SALE'}
- </span>
- </div>
- <div>
- <CountDown2 initialTime={product.flashSale.remainingTime} />
+ {product?.flashSale?.remainingTime > 0 &&
+ activeVariant?.price.discountPercentage > 0 && (
+ <div className={`absolute bottom-0 w-full`}>
+ <div className='absolute bottom-0 w-full'>
+ <ImageNext
+ src={
+ backgorundFlashSale || '/images/GAMBAR-BG-FLASH-SALE.jpg'
+ }
+ width={1000}
+ height={100}
+ />
+ </div>
+ <div className='relative'>
+ <div className='flex gap-x-2 items-center p-2'>
+ <div className='bg-yellow-400 rounded-full p-1 h-9 w-20 flex items-center justify-center '>
+ <span className='text-lg font-bold'>
+ {Math.floor(product.lowestPrice.discountPercentage)}%
+ </span>
+ </div>
+ <div
+ className={`bg-red-600 border border-solid border-yellow-400 rounded-full h-9 p-2 flex w-[50%] items-center justify-center gap-x-4`}
+ >
+ <ImageNext
+ src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg'
+ width={17}
+ height={10}
+ />
+ <span className='text-white text-lg font-semibold'>
+ {product?.flashSale?.tag != 'false' ||
+ product?.flashSale?.tag
+ ? product?.flashSale?.tag
+ : 'FLASH SALE'}
+ </span>
+ </div>
+ <div>
+ <CountDown2 initialTime={product.flashSale.remainingTime} />
+ </div>
</div>
</div>
</div>
- </div>
- )}
+ )}
<Image
src={product.image}
alt={product.name}
@@ -232,7 +249,11 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
<div className='flex items-end mb-2'>
{product.manufacture?.name ? (
<Link
- href={createSlug('/shop/brands/', product.manufacture?.name, product.manufacture?.id)}
+ href={createSlug(
+ '/shop/brands/',
+ product.manufacture?.name,
+ product.manufacture?.id
+ )}
>
{product.manufacture?.name}
</Link>
@@ -249,18 +270,25 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
</div>
<h1 className='leading-6 font-medium mb-3'>{activeVariant?.name}</h1>
{product?.qtySold > 0 && (
- <div className='text-gray_r-9'>{sellingProductFormat(activeVariant?.qtySold) + ' Terjual'}</div>
+ <div className='text-gray_r-9'>
+ {sellingProductFormat(activeVariant?.qtySold) + ' Terjual'}
+ </div>
)}
{product.variants.length > 1 &&
activeVariant.price.priceDiscount > 0 &&
!selectedVariant && (
- <div className='text-gray_r-12/80 text-caption-2 mt-2 mb-1'>Harga mulai dari: </div>
+ <div className='text-gray_r-12/80 text-caption-2 mt-2 mb-1'>
+ Harga mulai dari:{' '}
+ </div>
)}
- {activeVariant.isFlashsale && activeVariant?.price?.discountPercentage > 0 ? (
+ {activeVariant.isFlashsale &&
+ activeVariant?.price?.discountPercentage > 0 ? (
<>
<div className='flex gap-x-1 items-center'>
- <div className='badge-solid-red'>{Math.floor(activeVariant?.price?.discountPercentage)}%</div>
+ <div className='badge-solid-red'>
+ {Math.floor(activeVariant?.price?.discountPercentage)}%
+ </div>
<div className='text-gray_r-11 line-through text-caption-1'>
{currencyFormat(activeVariant?.price?.price)}
</div>
@@ -270,7 +298,9 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
</div>
<div className='text-gray_r-9 text-base font-normal mt-1'>
Termasuk PPN:{' '}
- {currencyFormat(activeVariant?.price.priceDiscount * process.env.NEXT_PUBLIC_PPN)}
+ {currencyFormat(
+ activeVariant?.price.priceDiscount * process.env.NEXT_PUBLIC_PPN
+ )}
</div>
</>
) : (
@@ -280,7 +310,9 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
{currencyFormat(activeVariant?.price?.price)}
<div className='text-gray_r-9 text-base font-normal mt-1'>
Termasuk PPN:{' '}
- {currencyFormat(activeVariant?.price.price * process.env.NEXT_PUBLIC_PPN)}
+ {currencyFormat(
+ activeVariant?.price.price * process.env.NEXT_PUBLIC_PPN
+ )}
</div>
</>
) : (
@@ -289,7 +321,12 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
<a
href={whatsappUrl('product', {
name: product.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
+ url: createSlug(
+ '/shop/product/',
+ product.name,
+ product.id,
+ true
+ ),
})}
className='text-danger-500 underline'
>
@@ -307,13 +344,17 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
<div>
<label className='flex justify-between'>
Pilih Varian:
- <span className='text-gray_r-11'>{product?.variantTotal} Varian</span>
+ <span className='text-gray_r-11'>
+ {product?.variantTotal} Varian
+ </span>
</label>
<Select
name='variant'
classNamePrefix='form-select'
options={variantOptions}
- formatOptionLabel={({ label }) => <div dangerouslySetInnerHTML={{ __html: label }} />}
+ formatOptionLabel={({ label }) => (
+ <div dangerouslySetInnerHTML={{ __html: label }} />
+ )}
className='mt-2'
value={selectedVariant}
onChange={(option) => setSelectedVariant(option)}
@@ -342,15 +383,27 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
onChange={(e) => setQuantity(e.target.value)}
/>
</div>
- <button type='button' className='btn-yellow flex-1' onClick={handleClickCart}>
+ <button
+ type='button'
+ className='btn-yellow flex-1'
+ onClick={handleClickCart}
+ >
Keranjang
</button>
- <button type='button' className='btn-solid-red flex-1' onClick={handleClickBuy}>
+ <button
+ type='button'
+ className='btn-solid-red flex-1'
+ onClick={handleClickBuy}
+ >
Beli
</button>
</div>
+
+ <div className='h-4' />
</div>
+ <ProductPromoSection productId={activeVariant.id} />
+
<Divider />
<div className='p-4'>
@@ -380,12 +433,16 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
type='button'
title={`Masa Persiapan Barang ${activeVariant?.sla?.slaDate}`}
className={`flex gap-x-1 items-center p-2 h-8 rounded-lg w-full ${
- activeVariant?.sla?.slaDate === 'indent' ? 'bg-indigo-900' : 'btn-light'
+ activeVariant?.sla?.slaDate === 'indent'
+ ? 'bg-indigo-900'
+ : 'btn-light'
}`}
>
<div
className={`flex-1 text-sm ${
- activeVariant?.sla?.slaDate === 'indent' ? 'text-white' : ''
+ activeVariant?.sla?.slaDate === 'indent'
+ ? 'text-white'
+ : ''
}`}
>
{activeVariant?.sla?.slaDate}
@@ -397,7 +454,9 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
stroke='currentColor'
stroke-width='1.5'
className={`w-7 h-7 text-sm ${
- activeVariant?.sla?.slaDate === 'indent' ? 'text-white' : ''
+ activeVariant?.sla?.slaDate === 'indent'
+ ? 'text-white'
+ : ''
}`}
>
<path
@@ -436,7 +495,12 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
<a
href={whatsappUrl('product', {
name: product.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
+ url: createSlug(
+ '/shop/product/',
+ product.name,
+ product.id,
+ true
+ ),
})}
className='text-danger-500 font-medium'
>
@@ -445,12 +509,19 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
)}
</SpecificationContent>
<SpecificationContent label='Berat Barang'>
- {activeVariant?.weight > 0 && <span>{activeVariant?.weight} KG</span>}
+ {activeVariant?.weight > 0 && (
+ <span>{activeVariant?.weight} KG</span>
+ )}
{activeVariant?.weight == 0 && (
<a
href={whatsappUrl('productWeight', {
name: product.name,
- url: createSlug('/shop/product/', product.name, product.id, true)
+ url: createSlug(
+ '/shop/product/',
+ product.name,
+ product.id,
+ true
+ ),
})}
className='text-danger-500 font-medium'
>
@@ -464,7 +535,10 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
active={informationTab == 'description'}
className='leading-6 text-gray_r-11'
dangerouslySetInnerHTML={{
- __html: product.description != '' ? product.description : 'Belum ada deskripsi produk.'
+ __html:
+ product.description != ''
+ ? product.description
+ : 'Belum ada deskripsi produk.',
}}
/>
</div>
@@ -491,50 +565,63 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
className='h-20 object-contain object-center w-full border border-gray_r-4'
/>
</div>
- <div className='ml-3 flex flex-1 items-center text-sm font-normal'>{product.name}</div>
+ <div className='ml-3 flex flex-1 items-center text-sm font-normal'>
+ {product.name}
+ </div>
<div className='ml-3 flex items-center text-sm font-normal'>
- <Link href='/shop/cart' className='flex-1 py-2 text-gray_r-12 btn-yellow'>
+ <Link
+ href='/shop/cart'
+ className='flex-1 py-2 text-gray_r-12 btn-yellow'
+ >
Lihat Keranjang
</Link>
</div>
</div>
<div className='mt-8 mb-4'>
- <div className='text-h-sm font-semibold mb-6'>Kamu Mungkin Juga Suka</div>
+ <div className='text-h-sm font-semibold mb-6'>
+ Kamu Mungkin Juga Suka
+ </div>
<LazyLoad>
<ProductSimilar query={productSimilarQuery} />
</LazyLoad>
</div>
</BottomPopup>
</MobileView>
- )
-}
+ );
+};
const informationTabOptions = [
{ value: 'specification', label: 'Spesifikasi' },
{ value: 'description', label: 'Deskripsi' },
- { value: 'information', label: 'Info Penting' }
-]
+ { value: 'information', label: 'Info Penting' },
+];
const TabButton = ({ children, active, ...props }) => {
- const activeClassName = active ? 'text-danger-500 underline underline-offset-4' : 'text-gray_r-11'
+ const activeClassName = active
+ ? 'text-danger-500 underline underline-offset-4'
+ : 'text-gray_r-11';
return (
- <button {...props} type='button' className={`font-medium pb-1 ${activeClassName}`}>
+ <button
+ {...props}
+ type='button'
+ className={`font-medium pb-1 ${activeClassName}`}
+ >
{children}
</button>
- )
-}
+ );
+};
const TabContent = ({ children, active, className, ...props }) => (
<div {...props} className={`${active ? 'block' : 'hidden'} ${className}`}>
{children}
</div>
-)
+);
const SpecificationContent = ({ children, label }) => (
<div className='flex justify-between p-3 items-center'>
<span className='text-gray_r-11'>{label}</span>
{children}
</div>
-)
+);
-export default ProductMobile
+export default ProductMobile;
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>
-)
+);