diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-03-20 17:14:16 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-03-20 17:14:16 +0700 |
| commit | d178a520534af7d1cbcc03134034ad8a2327b461 (patch) | |
| tree | 488606d5e19782d2c0942402ab7c6e7c8d16bc1c /src/lib/product/components/Product/ProductDesktop.jsx | |
| parent | 833488811b4164d7fbdce9bd70e171f06d62bf8d (diff) | |
product detail and cart header
Diffstat (limited to 'src/lib/product/components/Product/ProductDesktop.jsx')
| -rw-r--r-- | src/lib/product/components/Product/ProductDesktop.jsx | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx new file mode 100644 index 00000000..ac17ec6e --- /dev/null +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -0,0 +1,268 @@ +import Image from '@/core/components/elements/Image/Image' +import Link from '@/core/components/elements/Link/Link' +import DesktopView from '@/core/components/views/DesktopView' +import currencyFormat from '@/core/utils/currencyFormat' +import { HeartIcon } from '@heroicons/react/24/outline' +import { useRef, useState } from 'react' +import LazyLoad from 'react-lazy-load' +import ProductSimilar from '../ProductSimilar' +import { toast } from 'react-hot-toast' +import { updateItemCart } from '@/core/utils/cart' + +const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { + const [informationTab, setInformationTab] = useState(informationTabOptions[0].value) + + const variantQuantityRefs = useRef([]) + + const setVariantQuantityRef = (variantId) => (element) => { + variantQuantityRefs.current[variantId] = element + } + + const validQuantity = (quantity) => { + let isValid = true + if (!quantity || quantity < 1 || isNaN(parseInt(quantity))) { + toast.error('Jumlah barang minimal 1') + isValid = false + } + return isValid + } + + const handleAddToCart = (variantId) => { + const quantity = variantQuantityRefs.current[variantId].value + if (!validQuantity(quantity)) return + updateItemCart({ + productId: variantId, + quantity + }) + toast.success('Berhasil menambahkan ke keranjang') + } + + const variantSectionRef = useRef(null) + const goToVariantSection = () => { + if (variantSectionRef.current) { + const position = variantSectionRef.current.getBoundingClientRect() + window.scrollTo({ + top: position.top - 120 + window.pageYOffset, + behavior: 'smooth' + }) + } + } + + const productSimilarQuery = [ + product?.name.replace(/[()/"&]/g, ''), + `fq=-product_id:${product.id}`, + `fq=-manufacture_id:${product.manufacture?.id || 0}` + ].join('&') + + return ( + <DesktopView> + <div className='container mx-auto pt-10'> + <div className='flex'> + <div className='w-[30%]'> + <Image + src={product.image} + alt={product.name} + className='h-96 object-contain object-center w-full border border-gray_r-4' + /> + </div> + <div className='w-[50%] px-4'> + <h1 className='text-title-md leading-10 font-medium'>{product?.name}</h1> + <div className='mt-10'> + <div className='flex p-3'> + <div className='w-1/4 text-gray_r-12/70'>Nomor SKU</div> + <div className='w-3/4'>SKU-{product.id}</div> + </div> + <div className='flex p-3 bg-gray_r-4'> + <div className='w-1/4 text-gray_r-12/70'>Part Number</div> + <div className='w-3/4'>{product.code || '-'}</div> + </div> + <div className='flex p-3'> + <div className='w-1/4 text-gray_r-12/70'>Manufacture</div> + <div className='w-3/4'> + {product.manufacture?.name ? ( + <Link href='/'>{product.manufacture?.name}</Link> + ) : ( + <div>-</div> + )} + </div> + </div> + <div className='flex p-3 bg-gray_r-4'> + <div className='w-1/4 text-gray_r-12/70'>Berat Barang</div> + <div className='w-3/4'> + {product?.weight > 0 && <span>{product?.weight} KG</span>} + {product?.weight == 0 && ( + <a href='https://wa.me' className='text-red_r-11 font-medium'> + Tanya Berat + </a> + )} + </div> + </div> + </div> + </div> + + <div className='w-[20%]'> + {product.variants.length > 1 && product.lowestPrice.priceDiscount > 0 && ( + <div className='text-gray_r-12/80'>Harga mulai dari: </div> + )} + {product?.lowestPrice.discountPercentage > 0 && ( + <div className='flex gap-x-1 items-center mt-2'> + <div className='badge-solid-red text-caption-1'> + {product?.lowestPrice.discountPercentage}% + </div> + <div className='text-gray_r-11 line-through text-caption-1'> + {currencyFormat(product?.lowestPrice.price)} + </div> + </div> + )} + <h3 className='text-red_r-11 font-semibold mt-1 text-title-md'> + {product?.lowestPrice.priceDiscount > 0 ? ( + currencyFormat(product?.lowestPrice.priceDiscount) + ) : ( + <span className='text-gray_r-11 leading-6 font-normal'> + Hubungi kami untuk dapatkan harga terbaik, + <a href='https://wa.me/' className='text-red_r-11 underline'> + klik disini + </a> + </span> + )} + </h3> + <button + type='button' + onClick={goToVariantSection} + className='btn-solid-red w-full mt-6' + > + Lihat Varian + </button> + + <div className='flex mt-4'> + <button className='flex items-center gap-x-1' onClick={toggleWishlist}> + {wishlist.data?.productTotal > 0 ? ( + <HeartIcon className='w-6 fill-red_r-11 text-red_r-11' /> + ) : ( + <HeartIcon className='w-6' /> + )} + Wishlist + </button> + </div> + </div> + </div> + + <div className='mt-12' ref={variantSectionRef}> + <div className='text-h-lg font-semibold mb-6'>Varian Produk</div> + <div className='table-specification'> + <table> + <thead> + <tr> + <th>Part Number</th> + <th>Harga</th> + <th>Jumlah</th> + <th>Action</th> + </tr> + </thead> + <tbody> + {product.variants.map((variant) => ( + <tr key={variant.id}> + <td>{variant.code}</td> + <td> + {variant.price.discountPercentage > 0 && ( + <> + <span className='line-through text-caption-1 text-gray_r-11'> + {currencyFormat(variant.price.price)} + </span>{' '} + </> + )} + {currencyFormat(variant.price.priceDiscount)} + </td> + <td> + <input + type='number' + className='form-input w-16 py-2 text-center bg-gray_r-1' + ref={setVariantQuantityRef(variant.id)} + defaultValue={1} + /> + </td> + <td className='flex gap-x-3'> + <button + type='button' + onClick={() => handleAddToCart(variant.id)} + className='flex-1 py-2 btn-yellow' + > + Keranjang + </button> + <button type='button' className='flex-1 py-2 btn-solid-red'> + Beli + </button> + </td> + </tr> + ))} + </tbody> + </table> + </div> + </div> + + <div className='mt-12'> + <div className='text-h-lg font-semibold'>Informasi Produk</div> + <div className='flex gap-x-4 mt-6 mb-4'> + {informationTabOptions.map((option) => ( + <TabButton + value={option.value} + key={option.value} + active={informationTab == option.value} + onClick={() => setInformationTab(option.value)} + > + {option.label} + </TabButton> + ))} + </div> + <div className='flex'> + <div className='w-3/4 leading-7 product__description'> + <TabContent active={informationTab == 'description'}> + <span + dangerouslySetInnerHTML={{ + __html: + product.description != '' + ? product.description + : 'Belum ada deskripsi produk.' + }} + /> + </TabContent> + + <TabContent active={informationTab == 'information'}>Belum ada informasi.</TabContent> + </div> + </div> + </div> + + <div className='my-12'> + <div className='text-h-lg font-semibold mb-6'>Kamu Mungkin Juga Suka</div> + <LazyLoad> + <ProductSimilar query={productSimilarQuery} /> + </LazyLoad> + </div> + </div> + </DesktopView> + ) +} + +const informationTabOptions = [ + { value: 'description', label: 'Deskripsi' }, + { value: 'information', label: 'Info Penting' } +] + +const TabButton = ({ children, active, ...props }) => { + const activeClassName = active + ? 'text-red_r-11 underline underline-offset-4' + : 'text-gray_r-12/80' + return ( + <button {...props} type='button' className={`font-medium ${activeClassName}`}> + {children} + </button> + ) +} + +const TabContent = ({ children, active, className = '', ...props }) => ( + <div {...props} className={`${active ? 'block' : 'hidden'} ${className}`}> + {children} + </div> +) + +export default ProductDesktop |
