diff options
Diffstat (limited to 'src/lib/promotinProgram/components')
| -rw-r--r-- | src/lib/promotinProgram/components/HomePage.jsx | 116 | ||||
| -rw-r--r-- | src/lib/promotinProgram/components/PromotionType.jsx | 304 |
2 files changed, 420 insertions, 0 deletions
diff --git a/src/lib/promotinProgram/components/HomePage.jsx b/src/lib/promotinProgram/components/HomePage.jsx new file mode 100644 index 00000000..c0968161 --- /dev/null +++ b/src/lib/promotinProgram/components/HomePage.jsx @@ -0,0 +1,116 @@ +import React, { use, useEffect, useState } from 'react' +import { Swiper, SwiperSlide } from 'swiper/react' +import 'swiper/swiper.min.css' +import Image from '@/core/components/elements/Image/Image' +import useDevice from '@/core/hooks/useDevice' +import odooApi from '@/core/api/odooApi' +import { LazyLoadComponent } from 'react-lazy-load-image-component' +import ProductSlider from '@/lib/product/components/ProductSlider' +import { PopularProductSkeleton } from '@/components/skeleton/PopularProductSkeleton' + +const { useQuery } = require('react-query') +const { getPromotionHome } = require('../api/homepageApi') +const { getProductPromotionHome } = require('../api/homepageApi') + +const HomePage = () => { + const [activeTab, setActiveTab] = useState(null) + const [activeId, setActiveId] = useState(null) + const [activeBanner, setActiveBanner] = useState(null) + const [parentPromotions, setparentPromotions] = useState(null) + + const { data: titlePromotion } = useQuery('titlePromotion', getPromotionHome) + const { data: productPromotion, refetch: productPromotionRefetch } = useQuery( + ['productPromotion', activeId], + async () => { + if (!activeId) return null + return await getProductPromotionHome({ id: activeId }) + } + ) + + useEffect(() => { + if (titlePromotion && titlePromotion.length > 0) { + setActiveTab(titlePromotion[0].name) + setActiveId(titlePromotion[0].id) + setparentPromotions(titlePromotion) + setActiveBanner(titlePromotion[0].banner) + productPromotionRefetch() + } + }, [titlePromotion, productPromotionRefetch]) + + useEffect(() => { + if (productPromotion) { + setparentPromotions((parentPromotions) => { + return parentPromotions.map((title) => { + if (title.id === activeId && title.products === undefined) { + return { + ...title, + products: productPromotion + } + } + return title + }) + }) + } + }, [productPromotion, activeId]) + + const { isMobile, isDesktop } = useDevice() + const handleTabClick = (id, label, banner) => { + setActiveTab(label) + setActiveId(id) + setActiveBanner(banner) + } + + return ( + activeBanner && ( + <div className='px-4 sm:px-0'> + <div className='flex justify-between items-center mb-4'> + <div className='font-medium sm:text-h-lg'>{activeTab}</div> + </div> + <div className='mb-4'> + <Image src={activeBanner} alt='' className='h-full w-full object-contain object-center' /> + </div> + <Swiper slidesPerView={isMobile ? 3.5 : 7.5} spaceBetween={isMobile ? 12 : 20}> + {titlePromotion?.map((item, index) => ( + <SwiperSlide key={index}> + <button + className={`py-1 px-2 rounded border flex justify-center items-center h-30 ${ + activeTab === item.name ? 'border-red-500' : 'border-gray_r-6' + }`} + onClick={() => handleTabClick(item.id, item.name, item.banner)} + > + {' '} + <Image + src={item.icon} + alt='' + className='h-full w-full object-contain object-center' + /> + </button> + </SwiperSlide> + ))} + </Swiper> + <div className='mt-4 relative min-h-[150px]'> + {parentPromotions && + parentPromotions?.map((item, index) => ( + <div + key={index} + className={`${activeId === item.id ? 'block' : 'hidden'} rounded-md`} + > + {item.products ? ( + <ProductSlider + key={index} + products={{ + products: item.products + }} + /> + ) : ( + <PopularProductSkeleton /> + )} + </div> + ))} + </div> + </div> + ) + ) +} + +export default HomePage diff --git a/src/lib/promotinProgram/components/PromotionType.jsx b/src/lib/promotinProgram/components/PromotionType.jsx new file mode 100644 index 00000000..ad7185e3 --- /dev/null +++ b/src/lib/promotinProgram/components/PromotionType.jsx @@ -0,0 +1,304 @@ +import React, { useEffect, useState } from 'react' +import Image from '@/core/components/elements/Image/Image' +import BottomPopup from '@/core/components/elements/Popup/BottomPopup' +import CountDown2 from '@/core/components/elements/CountDown/CountDown2' +import currencyFormat from '@/core/utils/currencyFormat' +import { getPromotionProgram } from '../api/homepageApi' + +const PromotionType = ({ + isModal = false, + variantId, + setPromotionActiveId, + promotionActiveId, + quantity, + product = null, + setProducts = null +}) => { + const [selectedPromo, setSelectedPromo] = useState(null) + const [promotionType, setPromotionType] = useState(false) + const [promos, setPromotionList] = useState(null) + const [activeTitle, setActiveTitle] = useState(null) + const [quantitySet, setQuantity] = useState(null) + + useEffect(() => { + const id = variantId + const listProgram = async () => { + const programs = await getPromotionProgram({ id }) + if (programs.length > 0) { + setPromotionList(programs) + setActiveTitle(programs?.[0].type.value) + } + } + listProgram() + setSelectedPromo(promotionActiveId) + if (product) { + const variant = product.variants.find((variant) => variant.id === variantId) + setQuantity(variant.quantity) + }else{ + setQuantity(quantity) + } + }, []) + + const groupingData = promos?.reduce((groups, item) => { + const promoType = item.type.value + if (!groups[promoType]) { + groups[promoType] = [] + } + groups[promoType].push(item) + + return groups + }, {}) + + const handlePromoClick = (promoId, minQty) => { + if (quantitySet >= minQty) { + if (promoId == selectedPromo) { + setSelectedPromo(null) + setPromotionActiveId(null) + if (product) { + const updateProdcuts = () => { + let variantIndex = product.variants.findIndex((varian) => varian.id == variantId) + product.variants[variantIndex].programActive = null + + setProducts(product) + } + updateProdcuts() + } + } else { + setSelectedPromo(promoId) + setPromotionActiveId(promoId) + if (product) { + const updateProdcuts = () => { + let variantIndex = product.variants.findIndex((varian) => varian.id == variantId) + product.variants[variantIndex].programActive = promoId + + setProducts(product) + } + updateProdcuts() + } + } + } + } + + const handlePopUp = () => { + if (isModal == false) { + setPromotionType(true) + } + } + + return ( + promos && ( + <> + <div className='h-[50%] relative'> + <div className='relative rounded-lg border border-solid border-gray-300 mb-2 w-full'> + <Image src='https://placehold.co/537x50.png' alt='' layout='fill' objectFit='cover' /> + <div className='h-full absolute top-0 left-0 w-full flex items-center justify-between p-2'> + <span className='font-semibold text-lg text-white'>Promo Tersedia</span> + <button type='button' onClick={() => handlePopUp()} className='py-2 btn-yellow'> + Lihat Semua + </button> + </div> + </div> + <div + className={`w-full ${ + isModal == true ? '' : 'grid grid-cols-3 gap-1 bg-gray-200 ' + } p-2 rounded-lg`} + > + {isModal === true ? ( + <div> + <div className='flex gap-2 mb-3'> + {Object.keys(groupingData).map((index) => { + return ( + <> + <button + onClick={() => setActiveTitle(index)} + className={`py-1 px-2 rounded-lg flex justify-center items-center text-sm ${ + activeTitle === index ? 'badge-yellow text-black' : '' + } `} + > + {groupingData[index][0].type.label} + </button> + </> + ) + })} + </div> + {activeTitle && + groupingData[activeTitle].map((item, i) => ( + <div + key={i} + onClick={() => handlePromoClick(item.id, item.minimumPurchaseQty)} + className={`border border-solid mb-5 w-full hover:cursor-pointer ${ + selectedPromo + ? selectedPromo === item.id + ? 'opacity-100 border-red-500 bg-red-100' + : 'opacity-50 pointer-events-none' + : 'opacity-100' + } ${ + quantitySet >= item.minimumPurchaseQty + ? '' + : 'opacity-50 pointer-events-none' + } `} + > + <div className={`flex`}> + <div className=''> + <Image + src={item.Image} + alt={item.name} + className={`flex-1 w-[170px] object-cover`} + /> + </div> + <div className='p-2 w-full'> + <div className='flex justify-between mb-1'> + <div className='text-danger-500 font-semibold mb-1 mt-1'> + Waktu Tersisa + </div> + <div> + <CountDown2 initialTime={item.remainingTime}></CountDown2> + </div> + </div> + <p className='text-justify text-gray-500 line-clamp-3'>{item.name}</p> + <div className='mt-4'> + {/* {item.type.value === 'bundling' && ( + <> */} + <div className='flex gap-x-2 mt-3 justify-between items-center'> + <div className='flex gap-x-2 items-center '> + <div className='text-gray_r-11 line-through text-caption-1 mt-1'> + {currencyFormat(item.totalSavings)} + </div> + <div className='text-danger-500 font-semibold '>Gratis</div> + </div> + <div className='text-danger-500 font-semibold '> + {quantitySet < item.minimumPurchaseQty + ? 'Tambah ' + + (parseInt(item.minimumPurchaseQty) - + parseInt(quantitySet)) + + ' lagi' + : ''} + </div> + </div> + {/* </> + )} */} + {/* {item.type.value === 'special_price' && ( + <> + <div className='flex gap-x-2 mt-3 items-center'> + <div className='text-danger-500 font-semibold '> {currencyFormat(item.totalSavings)}</div> + </div> + </> + )} + {item.type.value === 'discount_loading' && ( + <> + <div className='flex justify-between'> + <div className='text-danger-500 font-semibold '> + {currencyFormat(item.totalSavings)} + </div> + <div className='text-danger-500 font-semibold '> + {quantitySet < item.minimumPurchaseQty + ? 'Tambah ' + + (parseInt(item.minimumPurchaseQty) - + parseInt(quantitySet)) + + ' lagi' + : ''} + </div> + </div> + </> + )} */} + </div> + </div> + </div> + </div> + ))} + </div> + ) : ( + promos.map((promo, index) => { + if (index > 2) { + return null + } else { + if (index === 2 && promos.length > 2) { + return ( + <> + <div + onClick={() => setPromotionType(true)} + className={` border border-solid bg-white mb-5 w-full hover:cursor-pointer opacity-100 flex flex-col justify-center items-center`} + > + <div className='flex justify-center items-center'> + <div className='rounded-full shadow-lg w-10 h-10 flex justify-center items-center'> + <svg + aria-hidden='true' + fill='none' + stroke='currentColor' + stroke-width='1.5' + viewBox='0 0 24 24' + className='text-red-500 w-20 h-20' + > + <path + d='M12 6v12m6-6H6' + stroke-linecap='round' + stroke-linejoin='round' + ></path> + </svg> + </div> + </div> + + <span className='mt-2 text-sm'>Lihat Promo Lainya</span> + </div> + </> + ) + } + return ( + <> + <div + key={promo.id} + onClick={() => setPromotionType(true)} + className={`border border-solid bg-white mb-5 w-full hover:cursor-pointer`} + > + <div className={`items-center`}> + <div className=''> + <Image + src={promo.Image} + alt={promo.name} + className={`flex-1 w-full object-cover`} + /> + </div> + <div className='p-2'> + <div className='badge-yellow text-black mb-1'>{promo.type.label}</div> + <p className='text-justify line-clamp-2'>{promo.name}</p> + <div className='text-danger-500 font-semibold mb-1 mt-1'> + {/* {currencyFormat(promo.totalSavings)} */} + </div> + {/* <div className='w-full bg-yellow-200 rounded-full h-1.5 mb-2'> + <div className='bg-yellow-500 h-1.5 rounded-full w-[45%]'></div> + </div> */} + <div> + <CountDown2 initialTime={promo.remainingTime}></CountDown2> + </div> + </div> + </div> + </div> + </> + ) + } + }) + )} + <BottomPopup + className=' !h-[75%]' + title='Pakai Promo' + active={promotionType} + close={() => setPromotionType(false)} + > + <div className='flex mt-4'> + <PromotionType + isModal={true} + variantId={variantId} + setPromotionActiveId={setPromotionActiveId} + promotionActiveId={promotionActiveId} + quantity={quantitySet} + ></PromotionType> + </div> + </BottomPopup> + </div> + </div> + </> + ) + ) +} + +export default PromotionType |
