diff options
| author | trisusilo <tri.susilo@altama.co.id> | 2023-08-09 03:45:50 +0000 |
|---|---|---|
| committer | trisusilo <tri.susilo@altama.co.id> | 2023-08-09 03:45:50 +0000 |
| commit | 8c1dc9781db9aa9f2c3be13548a83f7b3acbdc5b (patch) | |
| tree | 675d0981a6259b814c3deb7bd053a85892fea53b /src/lib | |
| parent | 863047e92834479ce8edb576b57b129c611821a8 (diff) | |
| parent | 407af81fb2d9ebdf3415fe7b34d08996ed7c80ec (diff) | |
Merged in CR/flash_sale (pull request #45)
CR/flash sale
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/product/api/productSimilarApi.js | 23 | ||||
| -rw-r--r-- | src/lib/product/components/Product/ProductDesktop.jsx | 91 | ||||
| -rw-r--r-- | src/lib/product/components/Product/ProductMobile.jsx | 128 | ||||
| -rw-r--r-- | src/lib/product/components/ProductCard.jsx | 53 | ||||
| -rw-r--r-- | src/lib/product/components/ProductSimilar.jsx | 3 | ||||
| -rw-r--r-- | src/lib/product/components/ProductSlider.jsx | 2 | ||||
| -rw-r--r-- | src/lib/product/hooks/useProductSimilar.js | 5 |
7 files changed, 250 insertions, 55 deletions
diff --git a/src/lib/product/api/productSimilarApi.js b/src/lib/product/api/productSimilarApi.js index d62077eb..c1bccd59 100644 --- a/src/lib/product/api/productSimilarApi.js +++ b/src/lib/product/api/productSimilarApi.js @@ -1,9 +1,30 @@ +import odooApi from '@/core/api/odooApi' import axios from 'axios' +import productSearchApi from './productSearchApi' -const productSimilarApi = async ({ query }) => { +const productSimilarApi = async ({ query, source }) => { + let dataflashSale = null + const flashSale = await odooApi('GET', '/api/v1/flashsale/header') + if (flashSale && flashSale.length > 0) { + const dataFlash = await productSearchApi({ + query: `fq=flashsale_id_i:${flashSale[0].pricelistId}&fq=flashsale_price_f:[1 TO *]&limit=${ + source === 'bottom' ? '4' : '1' + }`, + operation: 'AND' + }) + if (source === 'bottom') { + dataflashSale = dataFlash.response.products.slice('2', '4') + } else { + dataflashSale = dataFlash.response.products + } + } const dataProductSimilar = await axios( `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?q=${query}&page=1&orderBy=popular-weekly&operation=OR` ) + dataProductSimilar.data.response.products = [ + ...dataflashSale, + ...dataProductSimilar.data.response.products, + ]; return dataProductSimilar.data.response } diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index 372ad3ba..187ab3c9 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -18,6 +18,9 @@ import odooApi from '@/core/api/odooApi' import { Button, Spinner } from 'flowbite-react' 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 CountDown from '@/core/components/elements/CountDown/CountDown' const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { const router = useRouter() @@ -33,6 +36,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { const [promotionType, setPromotionType] = useState(false) const [promotionActiveId, setPromotionActiveId] = useState(null) const [selectVariantPromoActive, setSelectVariantPromoActive] = useState(null) + const [backgorundFlashSale, setBackgorundFlashSale] = useState(null) const getLowestPrice = useCallback(() => { const prices = product.variants.map((variant) => variant.price) @@ -47,6 +51,16 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { setLowestPrice(lowest) }, [getLowestPrice]) + useEffect(() => { + const getBackgound = async () => { + const get = await odooApi('GET', '/api/v1/banner?type=flash-sale-background-banner') + setBackgorundFlashSale(get[0].image) + } + getBackgound() + }, []) + + console.log('ini set', backgorundFlashSale) + const [informationTab, setInformationTab] = useState(informationTabOptions[0].value) const variantQuantityRefs = useRef([]) @@ -57,7 +71,6 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { product.variants[variantIndex].quantity = element?.value } variantQuantityRefs.current[variantId] = element - } const validQuantity = (quantity) => { @@ -97,7 +110,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { router.push(`/login?next=/shop/product/${slug}`) return } - + const quantity = variantQuantityRefs.current[variantId].value if (!validQuantity(quantity)) return @@ -108,13 +121,13 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { } 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 @@ -152,7 +165,8 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { useEffect(() => { const loadProductSimilarInBrand = async () => { const productSimilarQuery = [product?.name, `fq=-product_id_i:${product.id}`].join('&') - const dataProductSimilar = await productSimilarApi({ query: productSimilarQuery }) + const source = 'right' + const dataProductSimilar = await productSimilarApi({ query: productSimilarQuery, source }) setProductSimilarInBrand(dataProductSimilar.products) } if (!productSimilarInBrand) loadProductSimilarInBrand() @@ -181,11 +195,52 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { <div className='flex'> <div className='w-full flex flex-wrap'> <div className='w-5/12'> - <Image - src={product.image} - alt={product.name} - className='h-[430px] object-contain object-center w-full border border-gray_r-4' - /> + <div className='relative mb-2'> + {product?.flashSale?.remainingTime > 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'> + {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 || 'FLASH SALE'} + </span> + </div> + <div> + <CountDown2 initialTime={product.flashSale.remainingTime} /> + </div> + </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'> @@ -385,6 +440,18 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { <div className='text-gray_r-11 line-through text-caption-1'> {currencyFormat(lowestPrice?.price)} </div> + {product.flashSale.remainingTime > 0 && ( + <div className='bg-red-600 rounded-full mb-1 p-2 pl-3 pr-3 flex w-fit items-center gap-x-1'> + <ImageNext + src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg' + width={15} + height={10} + /> + <span className='text-white text-xs font-semibold'> + {product.flashSale.tag || 'FLASH SALE'} + </span> + </div> + )} </div> )} <h3 className='text-danger-500 font-semibold mt-1 text-title-md'> diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx index 2edd1a5f..d25d0861 100644 --- a/src/lib/product/components/Product/ProductMobile.jsx +++ b/src/lib/product/components/Product/ProductMobile.jsx @@ -18,6 +18,8 @@ import PromotionType from '@/lib/promotinProgram/components/PromotionType' import { gtagAddToCart } from '@/core/utils/googleTag' import odooApi from '@/core/api/odooApi' import { Button, Spinner } from 'flowbite-react' +import ImageNext from 'next/image' +import CountDown2 from '@/core/components/elements/CountDown/CountDown2' const ProductMobile = ({ product, wishlist, toggleWishlist }) => { const router = useRouter() @@ -30,6 +32,7 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { 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) @@ -39,6 +42,16 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { return lowest } + useEffect(() => { + const getBackgound = async () => { + const get = await odooApi('GET', '/api/v1/banner?type=flash-sale-background-banner') + if (get.length > 0) { + setBackgorundFlashSale(get[0].image) + } + } + getBackgound() + }, []) + const [activeVariant, setActiveVariant] = useState({ id: null, code: product.code, @@ -69,11 +82,11 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { product.variants = variantData setIsLoadingSLA(false) - if(product.variants.length === 1){ + if (product.variants.length === 1) { setActiveVariant({ id: product.variants[0].id, code: product.variants[0].code, - name: product.variants[0].parent.name , + name: product.variants[0].parent.name, price: product.variants[0].price, stock: product.variants[0].stock, weight: product.variants[0].weight, @@ -143,7 +156,7 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { quantity, programLineId: promotionActiveId, selected: true, - source : 'buy' + source: 'buy' }) router.push(`/shop/checkout?source=buy`) } @@ -156,11 +169,48 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { return ( <MobileView> - <Image - src={product.image} - alt={product.name} - className='h-72 object-contain object-center w-full border-b border-gray_r-4' - /> + <div className='relative'> + {product?.flashSale?.remainingTime > 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'> + {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 || 'FLASH SALE'} + </span> + </div> + <div> + <CountDown2 initialTime={product.flashSale.remainingTime} /> + </div> + </div> + </div> + </div> + )} + <Image + src={product.image} + alt={product.name} + className='h-72 object-contain object-center w-full border-b border-gray_r-4' + /> + </div> <div className='p-4'> <div className='flex items-end mb-2'> @@ -294,40 +344,44 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { <Spinner aria-label='Alternate spinner button example' /> <span className='pl-3'>Loading...</span> </Button> - ) : selectedVariant ? activeVariant?.sla?.slaDate != '-' ? ( - <button - 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' - }`} - > - <div - className={`flex-1 text-sm ${ - activeVariant?.sla?.slaDate === 'indent' ? 'text-white' : '' + ) : selectedVariant ? ( + activeVariant?.sla?.slaDate != '-' ? ( + <button + 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} - </div> - <div className='flex-end'> - <svg - aria-hidden='true' - fill='none' - stroke='currentColor' - stroke-width='1.5' - className={`w-7 h-7 text-sm ${ + <div + className={`flex-1 text-sm ${ activeVariant?.sla?.slaDate === 'indent' ? 'text-white' : '' }`} > - <path - d='M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z' - stroke-linecap='round' - stroke-linejoin='round' - ></path> - </svg> - </div> - </button> - ):('-') : ( + {activeVariant?.sla?.slaDate} + </div> + <div className='flex-end'> + <svg + aria-hidden='true' + fill='none' + stroke='currentColor' + stroke-width='1.5' + className={`w-7 h-7 text-sm ${ + activeVariant?.sla?.slaDate === 'indent' ? 'text-white' : '' + }`} + > + <path + d='M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z' + stroke-linecap='round' + stroke-linejoin='round' + ></path> + </svg> + </div> + </button> + ) : ( + '-' + ) + ) : ( '-' )} </span> diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 13fe07fd..5b859905 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -1,14 +1,31 @@ +import CountDown2 from '@/core/components/elements/CountDown/CountDown2' import Image from '@/core/components/elements/Image/Image' import Link from '@/core/components/elements/Link/Link' import currencyFormat from '@/core/utils/currencyFormat' import { createSlug } from '@/core/utils/slug' import whatsappUrl from '@/core/utils/whatsappUrl' +import ImageNext from 'next/image' +import Product from './Product/Product' +import { useRouter } from 'next/router' +import { useEffect, useState } from 'react' +import odooApi from '@/core/api/odooApi' const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { + const router = useRouter() + + const [backgorundFlashSale, setBackgorundFlashSale] = useState(null) + const callForPriceWhatsapp = whatsappUrl('product', { name: product.name, url: createSlug('/shop/product/', product.name, product.id, true) }) + useEffect(() => { + const getBackgound = async () => { + const get = await odooApi('GET', '/api/v1/banner?type=flash-sale-background-banner') + setBackgorundFlashSale(get[0].image) + } + getBackgound() + }, []) if (variant == 'vertical') { return ( @@ -22,6 +39,32 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { alt={product?.name} className='w-full object-contain object-center h-36 sm:h-48' /> + {router.pathname != '/' && product?.flashSale?.id > 0 && ( + <div className='absolute bottom-0 w-full grid'> + <div className='absolute bottom-0 w-full h-full'> + <ImageNext src='/images/GAMBAR-BG-FLASH-SALE.jpg' className='h-full' width={1000} height={100} /> + </div> + <div className='relative'> + <div className='flex gap-x-1 items-center p-2 justify-center'> + <div className='bg-yellow-400 rounded-full p-1 h-6 w-19 flex items-center justify-center '> + <span className='text-sm font-bold text-black'> + {product?.lowestPrice.discountPercentage}% + </span> + </div> + <div className='bg-red-600 border border-solid border-yellow-400 p-2 rounded-full h-6 flex w-fit items-center justify-center gap-x-2'> + <ImageNext + src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg' + width={13} + height={5} + /> + <span className='text-white text-[11px] font-semibold'> + {product?.flashSale?.tag} + </span> + </div> + </div> + </div> + </div> + )} {product.variantTotal > 1 && ( <div className='absolute badge-gray bottom-1.5 left-1.5'> {product.variantTotal} Varian @@ -101,6 +144,16 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { </Link> </div> <div className='w-8/12 p-2'> + {product.flashSale.id > 0 && ( + <div className='bg-red-600 rounded-full mb-1 p-2 pl-3 pr-3 flex w-fit items-center gap-x-1'> + <ImageNext + src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg' + width={15} + height={10} + /> + <span className='text-white text-xs font-semibold'>FLASH SALE</span> + </div> + )} {product?.manufacture?.name ? ( <Link href={createSlug( diff --git a/src/lib/product/components/ProductSimilar.jsx b/src/lib/product/components/ProductSimilar.jsx index 63a33089..1b82c2e5 100644 --- a/src/lib/product/components/ProductSimilar.jsx +++ b/src/lib/product/components/ProductSimilar.jsx @@ -3,7 +3,8 @@ import useProductSimilar from '../hooks/useProductSimilar' import ProductSlider from './ProductSlider' const ProductSimilar = ({ query }) => { - const { productSimilar } = useProductSimilar({ query }) + const source = "bottom" + const { productSimilar } = useProductSimilar({ query, source }) if (productSimilar.isLoading) { return <PopularProductSkeleton /> diff --git a/src/lib/product/components/ProductSlider.jsx b/src/lib/product/components/ProductSlider.jsx index b511eea5..dedbd6ab 100644 --- a/src/lib/product/components/ProductSlider.jsx +++ b/src/lib/product/components/ProductSlider.jsx @@ -66,7 +66,7 @@ const ProductSlider = ({ products, simpleTitle = false, bannerMode = false }) => </MobileView> <DesktopView> - <Swiper slidesPerView={5.6} spaceBetween={16} {...swiperProps}> + <Swiper slidesPerView={6.7} spaceBetween={16} {...swiperProps}> {swiperContent} </Swiper> </DesktopView> diff --git a/src/lib/product/hooks/useProductSimilar.js b/src/lib/product/hooks/useProductSimilar.js index d16e4c58..712d07ad 100644 --- a/src/lib/product/hooks/useProductSimilar.js +++ b/src/lib/product/hooks/useProductSimilar.js @@ -1,10 +1,9 @@ import productSimilarApi from '../api/productSimilarApi' import { useQuery } from 'react-query' -const useProductSimilar = ({ query }) => { - const fetchProductSimilar = async () => await productSimilarApi({ query }) +const useProductSimilar = ({ query, source }) => { + const fetchProductSimilar = async () => await productSimilarApi({ query, source }) const { data, isLoading } = useQuery(`productSimilar-${query}`, fetchProductSimilar) - return { productSimilar: { data, isLoading } } |
