diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/home/components/Skeleton/PopularProductSkeleton.jsx | 23 | ||||
| -rw-r--r-- | src/lib/product/api/productSimilarApi.js | 2 | ||||
| -rw-r--r-- | src/lib/product/components/ProductDesktop.jsx | 123 | ||||
| -rw-r--r-- | src/lib/product/components/ProductMobile.jsx | 18 |
4 files changed, 134 insertions, 32 deletions
diff --git a/src/lib/home/components/Skeleton/PopularProductSkeleton.jsx b/src/lib/home/components/Skeleton/PopularProductSkeleton.jsx index 18a1b3d3..29fda966 100644 --- a/src/lib/home/components/Skeleton/PopularProductSkeleton.jsx +++ b/src/lib/home/components/Skeleton/PopularProductSkeleton.jsx @@ -1,10 +1,25 @@ import ProductCardSkeleton from '@/core/components/elements/Skeleton/ProductCardSkeleton' +import DesktopView from '@/core/components/views/DesktopView' +import MobileView from '@/core/components/views/MobileView' const PopularProductSkeleton = () => ( - <div className='grid grid-cols-2 gap-x-3'> - <ProductCardSkeleton /> - <ProductCardSkeleton /> - </div> + <> + <MobileView> + <div className='grid grid-cols-2 gap-x-3'> + <ProductCardSkeleton /> + <ProductCardSkeleton /> + </div> + </MobileView> + <DesktopView> + <div className='grid grid-cols-5 gap-x-3'> + <ProductCardSkeleton /> + <ProductCardSkeleton /> + <ProductCardSkeleton /> + <ProductCardSkeleton /> + <ProductCardSkeleton /> + </div> + </DesktopView> + </> ) export default PopularProductSkeleton diff --git a/src/lib/product/api/productSimilarApi.js b/src/lib/product/api/productSimilarApi.js index 8fd17ab9..93c7f22c 100644 --- a/src/lib/product/api/productSimilarApi.js +++ b/src/lib/product/api/productSimilarApi.js @@ -2,7 +2,7 @@ import axios from 'axios' const productSimilarApi = async ({ query }) => { const dataProductSimilar = await axios( - `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?q=${query}&page=1&orderBy=popular` + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?q=${query}&page=1&orderBy=popular&operation=OR` ) return dataProductSimilar.data.response } diff --git a/src/lib/product/components/ProductDesktop.jsx b/src/lib/product/components/ProductDesktop.jsx index dc733eac..6eba2aed 100644 --- a/src/lib/product/components/ProductDesktop.jsx +++ b/src/lib/product/components/ProductDesktop.jsx @@ -3,14 +3,17 @@ 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 { useEffect, useState } from 'react' +import { Fragment, useEffect, useRef, useState } from 'react' +import LazyLoad from 'react-lazy-load' +import ProductSimilar from './ProductSimilar' const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { const [variantQuantity, setVariantQuantity] = useState(null) + const [informationTab, setInformationTab] = useState(informationTabOptions[0].value) useEffect(() => { const mapVariantQuantity = product.variants.reduce((acc, cur) => { - acc[cur.id] = 1 + acc[cur.id] = '1' return acc }, {}) setVariantQuantity(mapVariantQuantity) @@ -20,6 +23,23 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { setVariantQuantity((variantQuantity) => ({ ...variantQuantity, [variantId]: quantity })) } + 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 mt-10'> @@ -32,18 +52,18 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { /> </div> <div className='w-6/12 px-4'> - <h1 className='text-title-md leading-8 font-medium'>{product?.name}</h1> - <div className='mt-6 flex flex-col gap-y-4'> - <div className='flex'> - <div className='w-1/4 text-gray_r-12/60'>Nomor SKU</div> + <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'> - <div className='w-1/4 text-gray_r-12/60'>Part Number</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'> - <div className='w-1/4 text-gray_r-12/60'>Manufacture</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> @@ -52,8 +72,8 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { )} </div> </div> - <div className='flex'> - <div className='w-1/4 text-gray_r-12/60'>Berat Barang</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 && ( @@ -65,6 +85,7 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { </div> </div> </div> + <div className='w-3/12'> {product.variants.length > 1 && product.lowestPrice.priceDiscount > 0 && ( <div className='text-gray_r-12/80'>Harga mulai dari: </div> @@ -79,7 +100,7 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { </div> </div> )} - <h3 className='text-red_r-11 font-semibold mt-1 text-title-lg'> + <h3 className='text-red_r-11 font-semibold mt-1 text-title-md'> {product?.lowestPrice.priceDiscount > 0 ? ( currencyFormat(product?.lowestPrice.priceDiscount) ) : ( @@ -91,7 +112,11 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { </span> )} </h3> - <button type='button' className='btn-solid-red w-full mt-6'> + <button + type='button' + onClick={goToVariantSection} + className='btn-solid-red w-full mt-6' + > Lihat Varian </button> @@ -108,13 +133,13 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { </div> </div> - <div className='mt-12'> + <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>No. SKU</th> + <th>Part Number</th> <th>Harga</th> <th>Jumlah</th> <th>Action</th> @@ -137,8 +162,8 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { <td> <input type='number' - className='form-input w-16 text-center' - value={variantQuantity[variant.id]} + className='form-input w-16 py-2 text-center bg-gray_r-1' + value={variantQuantity?.[variant.id]} onChange={(e) => changeQuantity(variant.id, e.target.value)} /> </td> @@ -152,9 +177,71 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { </table> </div> </div> + + <div className='mt-12'> + <div className='text-h-lg font-semibold'>Informasi Produk</div> + <div className='my-5 h-0.5 bg-gray_r-6' /> + <div className='flex gap-x-4 mb-5'> + {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 rounded'> + <TabContent active={informationTab == 'description'}> + <div className='w-3/4 leading-7 product__description'> + <span + dangerouslySetInnerHTML={{ + __html: + product.description != '' + ? product.description + : 'Belum ada deskripsi produk.' + }} + /> + </div> + </TabContent> + + <TabContent active={informationTab == 'information'}>Belum ada informasi.</TabContent> + </div> + </div> + + <div className='mt-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 diff --git a/src/lib/product/components/ProductMobile.jsx b/src/lib/product/components/ProductMobile.jsx index 790fcd57..07da876e 100644 --- a/src/lib/product/components/ProductMobile.jsx +++ b/src/lib/product/components/ProductMobile.jsx @@ -17,7 +17,7 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { const [quantity, setQuantity] = useState('1') const [selectedVariant, setSelectedVariant] = useState(null) - const [informationTab, setInformationTab] = useState(null) + const [informationTab, setInformationTab] = useState(informationTabOptions[0].value) const [activeVariant, setActiveVariant] = useState({ id: product.id, @@ -58,12 +58,6 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { } }, [selectedVariant, product]) - useEffect(() => { - if (!informationTab) { - setInformationTab(informationTabOptions[0].value) - } - }, [informationTab]) - const validAction = () => { let isValid = true if (!selectedVariant) { @@ -91,6 +85,12 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { router.push(`/shop/checkout?productId=${activeVariant.id}&quantity=${quantity}`) } + const productSimilarQuery = [ + product?.name.replace(/[()/"&]/g, ''), + `fq=-product_id:${product.id}`, + `fq=-manufacture_id:${product.manufacture?.id || 0}` + ].join('&') + return ( <MobileView> <Image @@ -242,7 +242,7 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { <div className='p-4'> <h2 className='font-semibold mb-4'>Kamu Mungkin Juga Suka</h2> <LazyLoad> - <ProductSimilar query={product?.name.split(' ').slice(1, 3).join(' ')} /> + <ProductSimilar query={productSimilarQuery} /> </LazyLoad> </div> </MobileView> @@ -252,7 +252,7 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { const informationTabOptions = [ { value: 'specification', label: 'Spesifikasi' }, { value: 'description', label: 'Deskripsi' }, - { value: 'important', label: 'Info Penting' } + { value: 'information', label: 'Info Penting' } ] const TabButton = ({ children, active, ...props }) => { |
