diff options
| author | HATEC\SPVDEV001 <tri.susilo@altama.co.id> | 2023-10-05 09:32:12 +0700 |
|---|---|---|
| committer | HATEC\SPVDEV001 <tri.susilo@altama.co.id> | 2023-10-05 09:32:12 +0700 |
| commit | e72c16eb549488e1ed847b022880f542d2a9c525 (patch) | |
| tree | 9f9bf6fbc29f97cb4fc0d897dcb813b062bdc63d | |
| parent | 427feacedcdc511fcead8d2289264aa58bafd038 (diff) | |
add component list product for cart, quotation, and checkout
| -rw-r--r-- | src/core/components/elements/Product/cartProductsList.jsx | 260 | ||||
| -rw-r--r-- | src/lib/cart/components/Cart.jsx | 257 | ||||
| -rw-r--r-- | src/lib/checkout/components/Checkout.jsx | 8 | ||||
| -rw-r--r-- | src/lib/product/components/Product/ProductDesktop.jsx | 4 | ||||
| -rw-r--r-- | src/lib/product/components/ProductCard.jsx | 6 | ||||
| -rw-r--r-- | src/lib/quotation/components/Quotation.jsx | 66 |
6 files changed, 276 insertions, 325 deletions
diff --git a/src/core/components/elements/Product/cartProductsList.jsx b/src/core/components/elements/Product/cartProductsList.jsx new file mode 100644 index 00000000..c1d96d96 --- /dev/null +++ b/src/core/components/elements/Product/cartProductsList.jsx @@ -0,0 +1,260 @@ +import Link from '@/core/components/elements/Link/Link' +import Image from '@/core/components/elements/Image/Image' +import LogoSpinner from '../Spinner/LogoSpinner' +import { TrashIcon } from '@heroicons/react/24/outline' +import { useEffect } from 'react' +import { createSlug } from '@/core/utils/slug' +import currencyFormat from '@/core/utils/currencyFormat' + +const CardProdcuctsList = ({ + isLoading, + products, + source, + handlePopUpPromo = () => {}, + toggleSelected = () => {}, + updateQuantity = () => {}, + setDeleteConfirmation = () => {} +}) => { + return ( + <table className='table-cart'> + <thead> + <tr> + <th colSpan={2}>Nama Produk</th> + <th>Jumlah</th> + <th>Harga</th> + <th>Subtotal</th> + {source == 'cart' && <th>Action</th>} + </tr> + </thead> + <tbody> + {isLoading && ( + <tr> + <td colSpan={6}> + <div className='container flex justify-center my-4'> + <LogoSpinner width={48} height={48} /> + </div> + </td> + </tr> + )} + {!isLoading && (!products || products?.length == 0) && ( + <tr> + <td colSpan={6}>Keranjang belanja anda masih kosong</td> + </tr> + )} + {products && + products?.map((product) => ( + <> + {product.hasProgram && ( + <tr className='!border-b-0 pb-0'> + <td colSpan={6}> + <div className='flex gap-x-2 bg-yellow-100 p-2 items-center'> + {product.program ? ( + <> + <div className='flex border border-solid border-red-600 rounded-md p-1'> + <span className='text-red-600'>{product.program.type.label}</span> + </div> + <div className='flex'> + {product.program.type.value == 'merchandise' ? ( + <>Selamat anda mendapatkan merchandise indoteknik.com</> + ) : ( + <> + Selamat! Pembelian anda lebih hemat + <span className='text-red-600 font-semibold ml-2'> + {' '} + {currencyFormat(product.program?.totalSavings)} + </span> + </> + )} + </div> + </> + ) : ( + <> + <div className='flex border border-solid border-red-600 rounded-md p-1'> + <span className='text-red-600'>Promo</span> + </div> + <div className='flex'>Pilih Promo Yang Tersedia Bisa lebih Hemat</div> + </> + )} + <div + onClick={() => + handlePopUpPromo(product.id, product.quantity, product.program?.id) + } + className='ml-auto text-red-500 flex gap-x-1 cursor-pointer' + > + <div className='font-semibold'> Cek Promo</div> + <div> + <svg + aria-hidden='true' + fill='none' + stroke='currentColor' + stroke-width='1.5' + viewBox='0 0 20 24' + className='h-5 w-5 font-semibold' + > + <path + d='M8.25 4.5l7.5 7.5-7.5 7.5' + stroke-linecap='round' + stroke-linejoin='round' + ></path> + </svg> + </div> + </div> + </div> + </td> + </tr> + )} + <tr + key={product.id} + className={`${product.hasProgram ? '!border-t-0 !border-b-0' : ''}`} + > + <td className='relative'> + <ComponentCanBuy canBuy={product.canBuy} /> + <input + type='checkbox' + onClick={() => toggleSelected(product.id)} + checked={product?.selected} + className='accent-danger-500 w-4' + /> + </td> + <td className='flex relative'> + <ComponentCanBuy canBuy={product.canBuy} /> + <Link + href={createSlug('/shop/product/', product?.parent.name, product?.parent.id)} + className='w-[20%] flex-shrink-0' + > + <Image + src={product?.parent?.image} + alt={product?.name} + className='object-contain object-center border border-gray_r-6 h-28 w-full rounded-md' + /> + </Link> + <div className='px-2 text-left'> + <Link + href={createSlug('/shop/product/', product?.parent.name, product?.parent.id)} + className='line-clamp-2 leading-6 !text-gray_r-12 font-normal' + > + {product?.parent?.name} + </Link> + <div className='text-gray_r-11 mt-2'> + {product?.code}{' '} + {product?.attributes.length > 0 ? `| ${product?.attributes.join(', ')}` : ''} + </div> + </div> + </td> + <td className='relative'> + <ComponentCanBuy canBuy={product.canBuy} /> + <input + className='form-input w-16 py-2 text-center bg-gray_r-1' + type='number' + value={product?.quantity} + disabled={source === 'cart' ? false : true} + onChange={(e) => updateQuantity(e.target.value, product?.id)} + onBlur={(e) => updateQuantity(e.target.value, product?.id, 'BLUR')} + /> + </td> + <td className='relative'> + <ComponentCanBuy canBuy={product.canBuy} /> + {product?.hasFlashsale ? ( + <> + <div className='flex gap-x-1 items-center justify-center mt-3'> + <div className='text-gray_r-11 line-through text-caption-1'> + {currencyFormat(product?.price?.price)} + </div> + <div className='badge-solid-red'>{product?.price?.discountPercentage}%</div> + </div> + <div className='font-normal mt-1'> + {currencyFormat(product?.price?.priceDiscount)} + </div> + </> + ) : ( + <div className='font-normal mt-1'>{currencyFormat(product?.price?.price)}</div> + )} + </td> + <td className='relative'> + <ComponentCanBuy canBuy={product.canBuy} /> + <div className='text-danger-500 font-medium'> + {currencyFormat(product?.price?.priceDiscount * product?.quantity)} + </div> + </td> + {source == 'cart' && ( + <td> + <div className='flex justify-center items-center h-full'> + <button + className='btn-red p-1 ml-1' + onClick={() => setDeleteConfirmation(product)} + > + <TrashIcon className='w-4' /> + </button> + </div> + </td> + )} + </tr> + {product?.program?.items && ( + <tr key={product.program.id} className='!border-t-0'> + {product.program.items.map((item) => ( + <> + <td className='relative'> + <ComponentCanBuy canBuy={product.canBuy} /> + </td> + <td className='flex relative'> + <ComponentCanBuy canBuy={product.canBuy} /> + <div className='w-[20%] flex-shrink-0'> + <Image + src={item.parent.image} + alt={item.name} + className='object-contain object-center border border-gray_r-6 h-28 w-full rounded-md' + /> + </div> + <div className='px-2 text-left'> + <div className=''> + <span className='border border-solid border-red-600 rounded-md p-1 text-red-600'> + {product.program.type.label} + </span> + </div> + <div className='mt-2 line-clamp-2 leading-6'>{item.name}</div> + </div> + </td> + <td className='relative'> + <ComponentCanBuy canBuy={product.canBuy} /> + <input + className='form-input w-16 py-2 text-center bg-gray_r-1' + type='number' + value={1} + disabled + /> + </td> + <td className='relative'> + <ComponentCanBuy canBuy={product.canBuy} /> + {item?.price?.discountPercentage > 0 && ( + <div className='flex gap-x-1 items-center justify-center mt-3'> + <div className='text-gray_r-11 line-through text-caption-1'> + {currencyFormat(product?.price?.price)} + </div> + </div> + )} + <div className='font-normal mt-1'> + {item?.price.priceDiscount > 0 ? 'Gratis' : ''} + </div> + </td> + <td className='relative'> + <ComponentCanBuy canBuy={product.canBuy} /> + <div className='text-danger-500 font-medium'> + {item.price.priceDiscount > 0 ? 'Gratis' : ''} + </div> + </td> + <td></td> + </> + ))} + </tr> + )} + </> + ))} + </tbody> + </table> + ) +} + +const ComponentCanBuy = ({ canBuy }) => + !canBuy && <div className='absolute w-full h-full bg-gray_r-3/40 top-0 left-0' /> + +export default CardProdcuctsList diff --git a/src/lib/cart/components/Cart.jsx b/src/lib/cart/components/Cart.jsx index 5716d01b..c6aaa596 100644 --- a/src/lib/cart/components/Cart.jsx +++ b/src/lib/cart/components/Cart.jsx @@ -23,6 +23,8 @@ import { getPromotionProgram } from '@/lib/promotinProgram/api/homepageApi' import PromotionType from '@/lib/promotinProgram/components/PromotionType' import { gtagBeginCheckout } from '@/core/utils/googleTag' import { useProductCartContext } from '@/contexts/ProductCartContext' +import CardProdcuctsList from '@/core/components/elements/Product/cartProductsList' +// import cardProdcuctsList from '@/core/components/elements/Product/cartProductsList' const Cart = () => { const router = useRouter() @@ -530,260 +532,7 @@ const Cart = () => { <div className='col-span-9 border border-gray_r-6 rounded bg-white p-4 pt-6'> <h1 className='text-title-sm font-semibold mb-6'>Keranjang</h1> - <table className='table-cart'> - <thead> - <tr> - <th colSpan={2}>Nama Produk</th> - <th>Jumlah</th> - <th>Harga</th> - <th>Subtotal</th> - <th>Action</th> - </tr> - </thead> - <tbody> - {isLoading && ( - <tr> - <td colSpan={6}> - <div className='container flex justify-center my-4'> - <LogoSpinner width={48} height={48} /> - </div> - </td> - </tr> - )} - {!isLoading && (!products || products?.length == 0) && ( - <tr> - <td colSpan={6}>Keranjang belanja anda masih kosong</td> - </tr> - )} - {products && - products?.map((product) => ( - <> - {product.hasProgram && ( - <tr className='!border-b-0 pb-0'> - <td colSpan={6}> - <div className='flex gap-x-2 bg-yellow-100 p-2 items-center'> - {product.program ? ( - <> - <div className='flex border border-solid border-red-600 rounded-md p-1'> - <span className='text-red-600'> - {product.program.type.label} - </span> - </div> - <div className='flex'> - {product.program.type.value == 'merchandise' ? ( - <>Selamat anda mendapatkan merchandise indoteknik.com</> - ) : ( - <> - Selamat! Pembelian anda lebih hemat - <span className='text-red-600 font-semibold ml-2'> - {' '} - {currencyFormat(product.program?.totalSavings)} - </span> - </> - )} - </div> - </> - ) : ( - <> - <div className='flex border border-solid border-red-600 rounded-md p-1'> - <span className='text-red-600'>Promo</span> - </div> - <div className='flex'> - Pilih Promo Yang Tersedia Bisa lebih Hemat - </div> - </> - )} - <div - onClick={() => - handlePopUpPromo( - product.id, - product.quantity, - product.program?.id - ) - } - className='ml-auto text-red-500 flex gap-x-1 cursor-pointer' - > - <div className='font-semibold'> Cek Promo</div> - <div> - <svg - aria-hidden='true' - fill='none' - stroke='currentColor' - stroke-width='1.5' - viewBox='0 0 20 24' - className='h-5 w-5 font-semibold' - > - <path - d='M8.25 4.5l7.5 7.5-7.5 7.5' - stroke-linecap='round' - stroke-linejoin='round' - ></path> - </svg> - </div> - </div> - </div> - </td> - </tr> - )} - <tr - key={product.id} - className={`${product.hasProgram ? '!border-t-0 !border-b-0' : ''}`} - > - <td className='relative'> - <ComponentCanBuy canBuy={product.canBuy} /> - <input - type='checkbox' - onClick={() => toggleSelected(product.id)} - checked={product?.selected} - className='accent-danger-500 w-4' - /> - </td> - <td className='flex relative'> - <ComponentCanBuy canBuy={product.canBuy} /> - <Link - href={createSlug( - '/shop/product/', - product?.parent.name, - product?.parent.id - )} - className='w-[20%] flex-shrink-0' - > - <Image - src={product?.parent?.image} - alt={product?.name} - className='object-contain object-center border border-gray_r-6 h-28 w-full rounded-md' - /> - </Link> - <div className='px-2 text-left'> - <Link - href={createSlug( - '/shop/product/', - product?.parent.name, - product?.parent.id - )} - className='line-clamp-2 leading-6 !text-gray_r-12 font-normal' - > - {product?.parent?.name} - </Link> - <div className='text-gray_r-11 mt-2'> - {product?.code}{' '} - {product?.attributes.length > 0 - ? `| ${product?.attributes.join(', ')}` - : ''} - </div> - </div> - </td> - <td className='relative'> - <ComponentCanBuy canBuy={product.canBuy} /> - <input - className='form-input w-16 py-2 text-center bg-gray_r-1' - type='number' - value={product?.quantity} - onChange={(e) => updateQuantity(e.target.value, product?.id)} - onBlur={(e) => updateQuantity(e.target.value, product?.id, 'BLUR')} - /> - </td> - <td className='relative'> - <ComponentCanBuy canBuy={product.canBuy} /> - {product?.hasFlashsale ? ( - <> - <div className='flex gap-x-1 items-center justify-center mt-3'> - <div className='text-gray_r-11 line-through text-caption-1'> - {currencyFormat(product?.price?.price)} - </div> - <div className='badge-solid-red'> - {product?.price?.discountPercentage}% - </div> - </div> - <div className='font-normal mt-1'> - {currencyFormat(product?.price?.priceDiscount)} - </div> - </> - ) : ( - <div className='font-normal mt-1'> - {currencyFormat(product?.price?.price)} - </div> - )} - </td> - <td className='relative'> - <ComponentCanBuy canBuy={product.canBuy} /> - <div className='text-danger-500 font-medium'> - {currencyFormat(product?.price?.priceDiscount * product?.quantity)} - </div> - </td> - <td> - <div className='flex justify-center items-center h-full'> - <button - className='btn-red p-1 ml-1' - onClick={() => setDeleteConfirmation(product)} - > - <TrashIcon className='w-4' /> - </button> - </div> - </td> - </tr> - {product?.program?.items && ( - <tr key={product.program.id} className='!border-t-0'> - {product.program.items.map((item) => ( - <> - <td className='relative'> - <ComponentCanBuy canBuy={product.canBuy} /> - </td> - <td className='flex relative'> - <ComponentCanBuy canBuy={product.canBuy} /> - <div className='w-[20%] flex-shrink-0'> - <Image - src={item.parent.image} - alt={item.name} - className='object-contain object-center border border-gray_r-6 h-28 w-full rounded-md' - /> - </div> - <div className='px-2 text-left'> - <div className=''> - <span className='border border-solid border-red-600 rounded-md p-1 text-red-600'> - {product.program.type.label} - </span> - </div> - <div className='mt-2 line-clamp-2 leading-6'>{item.name}</div> - </div> - </td> - <td className='relative'> - <ComponentCanBuy canBuy={product.canBuy} /> - <input - className='form-input w-16 py-2 text-center bg-gray_r-1' - type='number' - value={1} - disabled - /> - </td> - <td className='relative'> - <ComponentCanBuy canBuy={product.canBuy} /> - {item?.price?.discountPercentage > 0 && ( - <div className='flex gap-x-1 items-center justify-center mt-3'> - <div className='text-gray_r-11 line-through text-caption-1'> - {currencyFormat(product?.price?.price)} - </div> - </div> - )} - <div className='font-normal mt-1'> - {item?.price.priceDiscount > 0 ? 'Gratis' : ''} - </div> - </td> - <td className='relative'> - <ComponentCanBuy canBuy={product.canBuy} /> - <div className='text-danger-500 font-medium'> - {item.price.priceDiscount > 0 ? 'Gratis' : ''} - </div> - </td> - <td></td> - </> - ))} - </tr> - )} - </> - ))} - </tbody> - </table> + <CardProdcuctsList isLoading={isLoading} products={products} source='cart' handlePopUpPromo ={handlePopUpPromo} toggleSelected ={toggleSelected} updateQuantity ={updateQuantity} setDeleteConfirmation ={setDeleteConfirmation}/> <div className='pt-2 pb-6 flex items-center gap-x-3'> <NextImage diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 4739cd18..6b7852f2 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -32,6 +32,7 @@ import BottomPopup from '@/core/components/elements/Popup/BottomPopup' import { useQuery } from 'react-query' import { gtagPurchase } from '@/core/utils/googleTag' import { findVoucher, getVoucher } from '../api/getVoucher' +import CardProdcuctsList from '@/core/components/elements/Product/cartProductsList' const SELF_PICKUP_ID = 32 @@ -988,7 +989,10 @@ const Checkout = () => { <div className='p-4'> <div className='font-medium'>Detail Pesanan</div> - <table className='table-checkout'> + + <CardProdcuctsList isLoading={isLoading} products={products} /> + + {/* <table className='table-checkout'> <thead> <tr> <th>Nama Produk</th> @@ -1148,7 +1152,7 @@ const Checkout = () => { )) )} </tbody> - </table> + </table> */} </div> </div> <div className='w-1/4 pl-4'> diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index 5e827089..4c8c3ae9 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -594,7 +594,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { </div>{' '} </div> <div className=' text-caption-1 text-gray_r-11 mb-1'> - + PPN:{' '} + Inc. PPN:{' '} {currencyFormat( variant.price.priceDiscount * process.env.NEXT_PUBLIC_PPN )} @@ -608,7 +608,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { {currencyFormat(variant?.price?.price)} </div>{' '} <div className=' text-caption-1 text-gray_r-11 mb-1'> - + PPN:{' '} + Inc. PPN:{' '} {currencyFormat( variant?.price?.priceDiscount * process.env.NEXT_PUBLIC_PPN )} diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index 16c63c00..6a5e29ab 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -113,8 +113,8 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { {product?.lowestPrice.price > 0 ? ( <> {currencyFormat(product?.lowestPrice.price)} - <div className='text-gray_r-9 text-[11px] font-normal sm:text-caption-2 mt-2'> - + PPN: {currencyFormat(product.lowestPrice.price * process.env.NEXT_PUBLIC_PPN)} + <div className='text-gray_r-9 text-[10px] font-normal mt-2'> + Inc. PPN: {currencyFormat(product.lowestPrice.price * process.env.NEXT_PUBLIC_PPN )} </div> </> ) : ( @@ -217,7 +217,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { <> {currencyFormat(product?.lowestPrice.price)} <div className='text-gray_r-9 text-[11px] sm:text-caption-2 font-normal mt-2'> - + PPN: {currencyFormat(product.lowestPrice.price * process.env.NEXT_PUBLIC_PPN)} + Inc. PPN: {currencyFormat(product.lowestPrice.price * process.env.NEXT_PUBLIC_PPN)} </div> </> ) : ( diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx index cee35457..8c379ead 100644 --- a/src/lib/quotation/components/Quotation.jsx +++ b/src/lib/quotation/components/Quotation.jsx @@ -16,6 +16,7 @@ import MobileView from '@/core/components/views/MobileView' import DesktopView from '@/core/components/views/DesktopView' import Image from '@/core/components/elements/Image/Image' import { useQuery } from 'react-query' +import CardProdcuctsList from '@/core/components/elements/Product/cartProductsList' const { checkoutApi } = require('@/lib/checkout/api/checkoutApi') const { getProductsCheckout } = require('@/lib/checkout/api/checkoutApi') @@ -174,70 +175,7 @@ const Quotation = () => { <div className='container mx-auto py-10 flex'> <div className='w-3/4 border border-gray_r-6 rounded bg-white p-4'> <div className='font-medium'>Detail Barang</div> - <table className='table-checkout'> - <thead> - <tr> - <th>Nama Produk</th> - <th>Jumlah</th> - <th>Harga</th> - <th>Subtotal</th> - </tr> - </thead> - <tbody> - {products?.map((product) => ( - <tr key={product.id}> - <td className='flex'> - <div className='w-[30%] flex-shrink-0'> - <Image - src={product?.parent?.image} - alt={product?.name} - className='object-contain object-center border border-gray_r-6 h-40 w-full rounded-md' - /> - </div> - <div className='px-2 text-left'> - <div className='line-clamp-2 leading-6 !text-gray_r-12 font-normal'> - {product?.parent?.name} - </div> - <div className='text-gray_r-11 mt-2'> - {product?.code}{' '} - {product?.attributes.length > 0 - ? `| ${product?.attributes.join(', ')}` - : ''} - </div> - </div> - </td> - <td> - <input - className='form-input w-16 py-2 text-center bg-gray_r-1' - type='number' - value={product?.quantity} - disabled - /> - </td> - <td> - {product?.price?.discountPercentage > 0 && ( - <div className='flex gap-x-1 items-center justify-center mt-3'> - <div className='text-gray_r-11 line-through text-caption-1'> - {currencyFormat(product?.price?.price)} - </div> - <div className='badge-solid-red'> - {product?.price?.discountPercentage}% - </div> - </div> - )} - <div className='font-normal mt-1'> - {currencyFormat(product?.price?.priceDiscount)} - </div> - </td> - <td> - <div className='text-danger-500 font-medium'> - {currencyFormat(product?.price?.priceDiscount * product?.quantity)} - </div> - </td> - </tr> - ))} - </tbody> - </table> + <CardProdcuctsList isLoading={isLoading} products={products} source='checkout' /> </div> <div className='w-1/4 pl-4'> |
