summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-10-14 18:39:36 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-10-14 18:39:36 +0700
commit44862321cf5974c07d13a00c72f2b53567f98a47 (patch)
tree43a183603e4c0b3a32dffd908ed840c4273a8d80
parentf6b1aea824192572b241f94157ab3731dec6a4ea (diff)
<Miqdad> product card change renca
-rw-r--r--src/lib/product/components/ProductCard.jsx610
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 && (