diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-10-14 18:39:36 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-10-14 18:39:36 +0700 |
| commit | 44862321cf5974c07d13a00c72f2b53567f98a47 (patch) | |
| tree | 43a183603e4c0b3a32dffd908ed840c4273a8d80 | |
| parent | f6b1aea824192572b241f94157ab3731dec6a4ea (diff) | |
<Miqdad> product card change renca
| -rw-r--r-- | src/lib/product/components/ProductCard.jsx | 610 |
1 files changed, 453 insertions, 157 deletions
diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index f4f5882e..d5188d5c 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -11,6 +11,10 @@ import { createSlug } from '@/core/utils/slug'; import whatsappUrl from '@/core/utils/whatsappUrl'; import useUtmSource from '~/hooks/useUtmSource'; import useDevice from '@/core/hooks/useDevice'; +import { BadgePercent, Tag } from 'lucide-react'; +import { TicketIcon } from '@heroicons/react/24/outline'; +import DesktopView from '@/core/components/views/DesktopView'; +import MobileView from '@/core/components/views/MobileView'; const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { const router = useRouter(); @@ -73,186 +77,470 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { if (variant == 'vertical') { return ( - <div className='rounded shadow-sm border border-gray_r-4 bg-white'> - <Link href={URL.product} className='border-b border-gray_r-4 relative' aria-label='Produk'> - <div className='relative'> - <Image - src={image} - alt={product?.name} - className='gambarA w-full object-contain object-center h-36 sm:h-48' - /> - <div className='absolute top-0 right-0 flex mt-3'> - <div className='gambarB '> - {product?.isSni && ( - <ImageNext - src='/images/sni-logo.png' - alt='SNI Logo' - className='w-4 h-5 object-contain object-top sm:h-6' - width={50} - height={50} - loading='eager' - /> + <> + <DesktopView> + <div className='rounded shadow-sm border border-gray_r-4 bg-white'> + <Link + href={URL.product} + className='border-b border-gray_r-4 relative' + aria-label='Produk' + > + <div className='relative'> + <Image + src={image} + alt={product?.name} + className='gambarA w-full object-contain object-center h-36 sm:h-48' + /> + <div className='absolute top-0 right-0 flex mt-3'> + <div className='gambarB '> + {product?.isSni && ( + <ImageNext + src='/images/sni-logo.png' + alt='SNI Logo' + className='w-4 h-5 object-contain object-top sm:h-6' + width={50} + height={50} + loading='eager' + /> + )} + </div> + <div className='gambarC '> + {product?.isTkdn && ( + <ImageNext + src='/images/TKDN.png' + alt='TKDN' + className='w-11 h-6 object-contain object-top ml-1 mr-1 sm:h-6' + width={50} + height={50} + loading='eager' + /> + )} + </div> + </div> + </div> + + {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/BG-FLASH-SALE.jpg' + className='h-full' + width={1000} + height={100} + loading='eager' + /> + </div> + <div className='relative'> + <div className='flex gap-x-1 items-center p-2 justify-center'> + <div className='bg-yellow-400 rounded-lg p-1 h-6 w-19 flex items-center justify-center '> + <span className='text-sm font-bold text-black'> + {Math.floor(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' + alt='flash sale' + width={13} + height={5} + loading='eager' + /> + <span className='text-white text-[9px] md:text-[10px] font-semibold'> + {product?.flashSale?.tag != 'false' || + product?.flashSale?.tag + ? product?.flashSale?.tag + : 'FLASH SALE'} + </span> + </div> + </div> + </div> + </div> + )} + {product.variantTotal > 1 && ( + <div className='absolute badge-gray bottom-1.5 left-1.5'> + {product.variantTotal} Varian + </div> + )} + </Link> + <div className='p-2 sm:p-3 pb-3 text-caption-2 sm:text-body-2 leading-5'> + <div className='flex justify-between '> + {product?.manufacture?.name ? ( + <Link + href={URL.manufacture} + className='mb-1 mt-1 truncate' + aria-label={product.manufacture.name} + > + {product.manufacture.name} + </Link> + ) : ( + <div>-</div> + )} + {product?.isInBu && ( + <Link + href='/panduan-pick-up-service' + className='group' + aria-label='pickup now' + > + <Image + src='/images/PICKUP-NOW.png' + className='group-hover:scale-105 transition-transform duration-200' + alt='pickup now' + width={90} + height={12} + loading='eager' + /> + </Link> )} </div> - <div className='gambarC '> - {product?.isTkdn && ( - <ImageNext - src='/images/TKDN.png' - alt='TKDN' - className='w-11 h-6 object-contain object-top ml-1 mr-1 sm:h-6' - width={50} - height={50} - loading='eager' - /> + <Link + href={URL.product} + aria-label={product?.name} + className={`mb-2 !text-gray_r-12 leading-6 block line-clamp-3 h-[64px]`} + title={product?.name} + > + {product?.name} + </Link> + {product?.flashSale?.id > 0 && + product?.lowestPrice.discountPercentage > 0 ? ( + <> + <div className='flex gap-x-1 mb-1 items-center'> + <div className='text-gray_r-11 line-through text-[11px] sm:text-caption-2'> + {currencyFormat(product.lowestPrice.price)} + </div> + <div className='badge-solid-red'> + {Math.floor(product?.lowestPrice.discountPercentage)}% + </div> + </div> + <div className='text-danger-500 font-semibold mb-2'> + {product?.lowestPrice.priceDiscount > 0 ? ( + currencyFormat(product?.lowestPrice.priceDiscount) + ) : ( + <a + rel='noopener noreferrer' + target='_blank' + href={callForPriceWhatsapp} + aria-label='Call for Inquiry' + > + Call for Inquiry + </a> + )} + </div> + </> + ) : ( + <div className='text-danger-500 font-semibold mb-2 min-h-[40px]'> + {product?.lowestPrice.price > 0 ? ( + <> + {currencyFormat(product?.lowestPrice.price)} + <div className='text-gray_r-9 text-[10px] font-normal mt-2'> + Inc. PPN:{' '} + {currencyFormat( + product.lowestPrice.price * + process.env.NEXT_PUBLIC_PPN + )} + </div> + </> + ) : ( + <a + rel='noopener noreferrer' + target='_blank' + href={callForPriceWhatsapp} + aria-label='Call for Inquiry' + > + Call for Inquiry + </a> + )} + </div> + )} + {discount > 0 && product?.flashSale?.id < 1 && ( + <div className='flex gap-x-1 mb-1 text-sm'> + <div className='inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20'> + Voucher : {currencyFormat(discount)} + </div> + </div> + )} + + <div className='flex w-full items-center gap-x-1 '> + {product?.stockTotal > 0 && ( + <div className='badge-solid-red'>Ready Stock</div> + )} + {/* <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div> */} + {product?.qtySold > 0 && ( + <div className='text-gray_r-9 text-[11px]'> + {sellingProductFormat(product?.qtySold) + ' Terjual'} + </div> )} </div> </div> </div> + </DesktopView> - {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/BG-FLASH-SALE.jpg' - className='h-full' - width={1000} - height={100} - loading='eager' + <MobileView> + <div className='rounded shadow-sm border border-gray_r-4 bg-white'> + <Link + href={URL.product} + className='border-b border-gray_r-4 relative' + aria-label='Produk' + > + <div className='relative'> + <Image + src={image} + alt={product?.name} + className='gambarA w-full object-contain object-center h-36 sm:h-48' /> + <div className='absolute top-0 right-0 flex mt-3'> + <div className='gambarB '> + {product?.isSni && ( + <ImageNext + src='/images/sni-logo.png' + alt='SNI Logo' + className='w-4 h-5 object-contain object-top sm:h-6' + width={50} + height={50} + loading='eager' + /> + )} + </div> + <div className='gambarC '> + {product?.isTkdn && ( + <ImageNext + src='/images/TKDN.png' + alt='TKDN' + className='w-11 h-6 object-contain object-top ml-1 mr-1 sm:h-6' + width={50} + height={50} + loading='eager' + /> + )} + </div> + </div> </div> - <div className='relative'> - <div className='flex gap-x-1 items-center p-2 justify-center'> - <div className='bg-yellow-400 rounded-lg p-1 h-6 w-19 flex items-center justify-center '> - <span className='text-sm font-bold text-black'> - {Math.floor(product?.lowestPrice.discountPercentage)}% - </span> + {/* BADGE DISKON KIRI-ATAS */} + {(product?.lowestPrice?.discountPercentage ?? 0) > 0 && ( + <div className='absolute top-2 left-0 z-10'> + <div + className=' + bg-red-600 text-white + px-2 py-1 + rounded-r-lg shadow-sm + text-xs font-bold leading-none + ' + > + {Math.floor(product.lowestPrice.discountPercentage)}% </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'> + </div> + )} + + {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/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg' - alt='flash sale' - width={13} - height={5} + src='/images/BG-FLASH-SALE.jpg' + className='h-full' + width={1000} + height={100} loading='eager' /> - <span className='text-white text-[9px] md:text-[10px] font-semibold'> - {product?.flashSale?.tag != 'false' || - product?.flashSale?.tag - ? product?.flashSale?.tag - : 'FLASH SALE'} - </span> + </div> + <div className='relative'> + {/* Old */} + {/* <div className='flex gap-x-1 items-center p-2 justify-center'> + <div className='bg-yellow-400 rounded-lg p-1 h-6 w-19 flex items-center justify-center '> + <span className='text-sm font-bold text-black'> + {Math.floor(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' + alt='flash sale' + width={13} + height={5} + loading='eager' + /> + <span className='text-white text-[9px] md:text-[10px] font-semibold'> + {product?.flashSale?.tag != 'false' || + product?.flashSale?.tag + ? product?.flashSale?.tag + : 'FLASH SALE'} + </span> + </div> + </div> */} </div> </div> - </div> - </div> - )} - {product.variantTotal > 1 && ( - <div className='absolute badge-gray bottom-1.5 left-1.5'> - {product.variantTotal} Varian - </div> - )} - </Link> - <div className='p-2 sm:p-3 pb-3 text-caption-2 sm:text-body-2 leading-5'> - <div className='flex justify-between '> - {product?.manufacture?.name ? ( - <Link href={URL.manufacture} className='mb-1 mt-1 truncate' aria-label={product.manufacture.name}> - {product.manufacture.name} - </Link> - ) : ( - <div>-</div> - )} - {product?.isInBu && ( - <Link href='/panduan-pick-up-service' className='group' aria-label='pickup now'> - <Image - src='/images/PICKUP-NOW.png' - className='group-hover:scale-105 transition-transform duration-200' - alt='pickup now' - width={90} - height={12} - loading='eager' - /> - </Link> - )} - </div> - <Link - href={URL.product} - aria-label={product?.name} - className={`mb-2 !text-gray_r-12 leading-6 block line-clamp-3 h-[64px]`} - title={product?.name} - > - {product?.name} - </Link> - {product?.flashSale?.id > 0 && - product?.lowestPrice.discountPercentage > 0 ? ( - <> - <div className='flex gap-x-1 mb-1 items-center'> - <div className='text-gray_r-11 line-through text-[11px] sm:text-caption-2'> - {currencyFormat(product.lowestPrice.price)} - </div> - <div className='badge-solid-red'> - {Math.floor(product?.lowestPrice.discountPercentage)}% + )} + {product.variantTotal > 1 && ( + <div className='absolute badge-gray bottom-1.5 left-1.5'> + {product.variantTotal} Varian </div> - </div> - <div className='text-danger-500 font-semibold mb-2'> - {product?.lowestPrice.priceDiscount > 0 ? ( - currencyFormat(product?.lowestPrice.priceDiscount) + )} + </Link> + <div className='p-2 sm:p-3 pb-3 text-caption-2 sm:text-body-2 leading-5'> + <div className='flex justify-between '> + {product?.manufacture?.name ? ( + <Link + href={URL.manufacture} + className='mb-1 mt-1 truncate' + aria-label={product.manufacture.name} + > + {product.manufacture.name} + </Link> ) : ( - <a - rel='noopener noreferrer' - target='_blank' - href={callForPriceWhatsapp} - aria-label='Call for Inquiry' + <div>-</div> + )} + {/* PICK UP NOW badge (kanan-atas gambar) */} + {product?.isInBu && ( + <Link + href='/panduan-pick-up-service' + aria-label='Pick Up Now' + className='absolute top-2 right-2 z-10' > - Call for Inquiry - </a> + <span + className=' + inline-flex items-center + rounded-full bg-cyan-500/90 px-3 py-1 + text-[10px] font-extrabold tracking-wide text-white + shadow-sm ring-1 ring-inset ring-white/30 + backdrop-blur-[1px] + ' + > + PICK UP NOW + </span> + </Link> )} + + {/* Old */} + {/* {product?.isInBu && ( + <Link + href='/panduan-pick-up-service' + className='group' + aria-label='pickup now' + > + <Image + src='/images/PICKUP-NOW.png' + className='group-hover:scale-105 transition-transform duration-200' + alt='pickup now' + width={90} + height={12} + loading='eager' + /> + </Link> + )} */} </div> - </> - ) : ( - <div className='text-danger-500 font-semibold mb-2 min-h-[40px]'> - {product?.lowestPrice.price > 0 ? ( - <> - {currencyFormat(product?.lowestPrice.price)} - <div className='text-gray_r-9 text-[10px] font-normal mt-2'> - Inc. PPN:{' '} - {currencyFormat( - product.lowestPrice.price * process.env.NEXT_PUBLIC_PPN - )} + <Link + href={URL.product} + aria-label={product?.name} + className={`mb-2 !text-gray_r-12 leading-6 block line-clamp-3 h-[64px]`} + title={product?.name} + > + {product?.name} + </Link> + {product?.flashSale?.id > 0 && + product?.lowestPrice.discountPercentage > 0 ? ( + <div className='mb-2'> + <div className='flex items-baseline gap-2'> + {/* harga sekarang (merah) */} + <span className='text-danger-500 font-semibold tabular-nums'> + {product?.lowestPrice.priceDiscount > 0 ? ( + currencyFormat(product?.lowestPrice.price) + ) : ( + <a + rel='noopener noreferrer' + target='_blank' + href={callForPriceWhatsapp} + aria-label='Call for Inquiry' + > + Call for Inquiry + </a> + )} + </span> + + {/* harga lama (abu, dicoret) */} + <span className='text-gray_r-11 line-through text-[11px] sm:text-caption-2 tabular-nums'> + {currencyFormat(product.lowestPrice.price)} + </span> </div> - </> + </div> ) : ( - <a - rel='noopener noreferrer' - target='_blank' - href={callForPriceWhatsapp} - aria-label='Call for Inquiry' - > - Call for Inquiry - </a> + // === BLOK ELSE PUNYA KAMU, TIDAK DIUBAH === + <div className='text-danger-500 font-semibold mb-2 min-h-[40px]'> + {product?.lowestPrice.price > 0 ? ( + <> + {currencyFormat(product?.lowestPrice.priceDiscount)} + <div className='text-gray_r-9 text-[10px] font-normal mt-2'> + Include PPN:{' '} + {currencyFormat( + product.lowestPrice.price * + process.env.NEXT_PUBLIC_PPN + )} + </div> + </> + ) : ( + <a + rel='noopener noreferrer' + target='_blank' + href={callForPriceWhatsapp} + aria-label='Call for Inquiry' + > + Call for Inquiry + </a> + )} + </div> )} - </div> - )} - {discount > 0 && product?.flashSale?.id < 1 && ( - <div className='flex gap-x-1 mb-1 text-sm'> - <div className='inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20'> - Voucher : {currencyFormat(discount)} - </div> - </div> - )} - <div className='flex w-full items-center gap-x-1 '> - {product?.stockTotal > 0 && ( - <div className='badge-solid-red'>Ready Stock</div> - )} - {/* <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div> */} - {product?.qtySold > 0 && ( - <div className='text-gray_r-9 text-[11px]'> - {sellingProductFormat(product?.qtySold) + ' Terjual'} - </div> - )} + {discount > 0 && (product?.flashSale?.id ?? 0) < 1 && ( + <div className='mb-1'> + <div className='inline-flex items-center gap-2 text-green-600'> + {/* Label polos (bukan dalam kotak) */} + <span className='text-sm font-semibold'>Pakai Voucher</span> + + {/* Chip: ikon + nominal */} + <span + className=' + inline-flex items-center gap-1.5 + rounded bg-green-50 px-2.5 py-0.5 + ring-1 ring-inset ring-green-300 + ' + > + <Tag className='h-3.5 w-3.5' /> + + <span className='text-sm font-extrabold tabular-nums'> + {currencyFormat(discount)} + </span> + </span> + </div> + </div> + )} + + {(product?.stockTotal > 0 || product?.qtySold > 0) && ( + <div className='flex w-full items-center gap-x-2'> + {product?.stockTotal > 0 && ( + <div className='badge-solid-red'>Ready Stock</div> + )} + + {product?.qtySold > 0 && ( + <div className='text-gray_r-9 text-[11px] whitespace-nowrap'> + {sellingProductFormat(product?.qtySold)} Terjual + </div> + )} + </div> + )} + + {/* Old */} + {/* <div className='flex w-full items-center gap-x-1 '> + {product?.stockTotal > 0 && ( + <div className='badge-solid-red'>Ready Stock</div> + )} + <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div> + {product?.qtySold > 0 && ( + <div className='text-gray_r-9 text-[11px]'> + {sellingProductFormat(product?.qtySold) + ' Terjual'} + </div> + )} + </div> */} + </div> </div> - </div> - </div> + </MobileView> + </> ); } @@ -260,7 +548,11 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { return ( <div className='flex bg-white'> <div className='w-4/12'> - <Link href={URL.product} className='relative' aria-label={product?.name}> + <Link + href={URL.product} + className='relative' + aria-label={product?.name} + > <div className='relative'> <Image src={image} @@ -321,7 +613,11 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { )} {product?.manufacture?.name ? ( <div className='flex justify-between'> - <Link href={URL.manufacture} className='mb-1' aria-label={product?.manufacture.name}> + <Link + href={URL.manufacture} + className='mb-1' + aria-label={product?.manufacture.name} + > {product.manufacture.name} </Link> {/* {product?.is_in_bu && ( |
