diff options
| author | trisusilo <tri.susilo@altama.co.id> | 2023-10-18 09:21:18 +0000 |
|---|---|---|
| committer | trisusilo <tri.susilo@altama.co.id> | 2023-10-18 09:21:18 +0000 |
| commit | 0a88ef1da1c04f4d40c0133edb7d27701c7a9746 (patch) | |
| tree | ae3768ba44054d51b1abcc0dcc90d18d4895e412 /src/lib/product/components/Product | |
| parent | b4b17e22832a4665042a45030b77c3744fe61534 (diff) | |
| parent | 2a84fb3ce03cfa46cb3c7664e988957e1bd2731b (diff) | |
Merged in CR/UI (pull request #104)
CR/UI
Diffstat (limited to 'src/lib/product/components/Product')
| -rw-r--r-- | src/lib/product/components/Product/Breadcrumb.jsx | 69 | ||||
| -rw-r--r-- | src/lib/product/components/Product/Product.jsx | 38 | ||||
| -rw-r--r-- | src/lib/product/components/Product/ProductDesktop.jsx | 126 | ||||
| -rw-r--r-- | src/lib/product/components/Product/ProductMobile.jsx | 31 |
4 files changed, 181 insertions, 83 deletions
diff --git a/src/lib/product/components/Product/Breadcrumb.jsx b/src/lib/product/components/Product/Breadcrumb.jsx new file mode 100644 index 00000000..0554dba5 --- /dev/null +++ b/src/lib/product/components/Product/Breadcrumb.jsx @@ -0,0 +1,69 @@ +import odooApi from '@/core/api/odooApi' +import { createSlug } from '@/core/utils/slug' +import { + Breadcrumb as ChakraBreadcrumb, + BreadcrumbItem, + BreadcrumbLink, + Skeleton +} from '@chakra-ui/react' +import classNames from 'classnames' +import Link from 'next/link' +import { useQuery } from 'react-query' + +/** + * Renders a breadcrumb component based on the provided `productId`. + * + * @param {Object} props - The properties passed to the component. + * @param {number} props.productId - The ID of the product. + * @param {string} props.productName - The ID of the product. + * @return {ReactElement} The rendered breadcrumb component. + */ +const Breadcrumb = ({ productId, productName }) => { + const categories = useQuery( + `detail/categories/${productId}`, + async () => await odooApi('GET', `/api/v1/product/${productId}/category-breadcrumb`), + { + enabled: !!productId + } + ) + + return ( + <Skeleton + isLoaded={!categories.isLoading} + className={classNames({ + 'w-2/3': categories.isLoading, + 'w-full': !categories.isLoading + })} + > + <ChakraBreadcrumb + mb={10} + overflowX={'auto'} + className='text-caption-2 md:text-body-2 p-4 md:p-0' + > + <BreadcrumbItem> + <BreadcrumbLink as={Link} href='/' className='!text-danger-500 whitespace-nowrap'> + Home + </BreadcrumbLink> + </BreadcrumbItem> + + {categories.data?.map((category) => ( + <BreadcrumbItem key={category.id}> + <BreadcrumbLink + as={Link} + href={createSlug('/shop/category/', category.name, category.id)} + className='!text-danger-500 whitespace-nowrap' + > + {category.name} + </BreadcrumbLink> + </BreadcrumbItem> + ))} + + <BreadcrumbItem isCurrentPage> + <BreadcrumbLink className='whitespace-nowrap'>{productName}</BreadcrumbLink> + </BreadcrumbItem> + </ChakraBreadcrumb> + </Skeleton> + ) +} + +export default Breadcrumb diff --git a/src/lib/product/components/Product/Product.jsx b/src/lib/product/components/Product/Product.jsx index 54490c26..6e983c2e 100644 --- a/src/lib/product/components/Product/Product.jsx +++ b/src/lib/product/components/Product/Product.jsx @@ -36,29 +36,21 @@ const Product = ({ product, isVariant = false }) => { } }, [product, isVariant]) - if (isVariant == true) { - return ( - <> - <ProductDesktopVariant - product={product} - wishlist={wishlist} - toggleWishlist={toggleWishlist} - /> - <ProductMobileVariant - product={product} - wishlist={wishlist} - toggleWishlist={toggleWishlist} - /> - </> - ) - } else { - return ( - <> - <ProductMobile product={product} wishlist={wishlist} toggleWishlist={toggleWishlist} /> - <ProductDesktop products={product} wishlist={wishlist} toggleWishlist={toggleWishlist} /> - </> - ) - } + return isVariant == true ? ( + <> + <ProductDesktopVariant + product={product} + wishlist={wishlist} + toggleWishlist={toggleWishlist} + /> + <ProductMobileVariant product={product} wishlist={wishlist} toggleWishlist={toggleWishlist} /> + </> + ) : ( + <> + <ProductMobile product={product} wishlist={wishlist} toggleWishlist={toggleWishlist} /> + <ProductDesktop products={product} wishlist={wishlist} toggleWishlist={toggleWishlist} /> + </> + ) } export default Product diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index aa771eab..11c34009 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -24,6 +24,8 @@ import ColumnsSLA from './ColumnsSLA' import { useProductCartContext } from '@/contexts/ProductCartContext' import { Box, Skeleton, Tooltip } from '@chakra-ui/react' import { Info } from 'lucide-react' +import Breadcrumb from './Breadcrumb' +import { sellingProductFormat } from '@/core/utils/formatValue' const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { const router = useRouter() @@ -89,38 +91,38 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { } const updateCart = (variantId, quantity, source) => { - let dataUpdate + let dataUpdate = { + productId: variantId, + quantity, + selected: true, + source: source === 'buy' ? 'buy' : null + } + if (product.variants.length > 1) { let variantIndex = product.variants.findIndex((varian) => varian.id == variantId) - dataUpdate = { - productId: variantId, - quantity, - programLineId: product.variants[variantIndex].programActive, - selected: true, - source: source === 'buy' ? 'buy' : null - } + dataUpdate['programLineId'] = product.variants[variantIndex].programActive } else { - dataUpdate = { - productId: variantId, - quantity, - programLineId: promotionActiveId, - selected: true, - source: source === 'buy' ? 'buy' : null - } + dataUpdate['programLineId'] = promotionActiveId } + updateItemCart(dataUpdate) } - const handleAddToCart = (variantId) => { - if (!auth) { - router.push(`/login?next=/shop/product/${slug}`) - return - } + const redirectToLogin = (action, variantId, quantity) => { + const nextURL = `/shop/product/${slug}?action=${action}&variantId=${variantId}&qty=${quantity}` + router.push(`/login?next=${encodeURIComponent(nextURL)}`) + return true + } + const handleAddToCart = (variantId) => { const quantity = variantQuantityRefs.current[variantId].value if (!validQuantity(quantity)) return + if (!auth) { + return redirectToLogin('add_to_cart', variantId, quantity) + } + let source = 'cart' updateCart(variantId, quantity, source) setRefreshCart(true) @@ -140,6 +142,10 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { const quantity = variantQuantityRefs.current[variant].value if (!validQuantity(quantity)) return + if (!auth) { + return redirectToLogin('buy', variant, quantity) + } + let source = 'buy' updateCart(variant, quantity, source) router.push(`/shop/checkout?source=buy`) @@ -199,47 +205,49 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { return ( <DesktopView> <div className='container mx-auto pt-10'> + <Breadcrumb productId={product.id} productName={product.name} /> <div className='flex'> <div className='w-full flex flex-wrap'> <div className='w-5/12'> <div className='relative mb-2'> - {product?.flashSale?.remainingTime > 0 && lowestPrice?.price.discountPercentage > 0 && ( - <div className={`absolute bottom-0 w-full`}> - <div className='absolute bottom-0 w-full h-full'> - <ImageNext - src={backgorundFlashSale || '/images/GAMBAR-BG-FLASH-SALE.jpg'} - width={1000} - height={100} - /> - </div> - <div className='relative'> - <div className='flex gap-x-2 items-center p-2'> - <div className='bg-yellow-400 rounded-full p-1 h-9 w-20 flex items-center justify-center '> - <span className='text-lg font-bold'> - {Math.floor(product.lowestPrice.discountPercentage)}% - </span> - </div> - <div - className={`bg-red-600 border border-solid border-yellow-400 rounded-full h-9 p-2 flex w-[50%] items-center justify-center gap-x-4`} - > - <ImageNext - src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg' - width={17} - height={10} - /> - <span className='text-white text-lg font-semibold'> - {product?.flashSale?.tag != 'false' || product?.flashSale?.tag - ? product?.flashSale?.tag - : 'FLASH SALE'} - </span> - </div> - <div> - <CountDown2 initialTime={product.flashSale.remainingTime} /> + {product?.flashSale?.remainingTime > 0 && + lowestPrice?.price.discountPercentage > 0 && ( + <div className={`absolute bottom-0 w-full`}> + <div className='absolute bottom-0 w-full h-full'> + <ImageNext + src={backgorundFlashSale || '/images/GAMBAR-BG-FLASH-SALE.jpg'} + width={1000} + height={100} + /> + </div> + <div className='relative'> + <div className='flex gap-x-2 items-center p-2'> + <div className='bg-yellow-400 rounded-full p-1 h-9 w-20 flex items-center justify-center '> + <span className='text-lg font-bold'> + {Math.floor(product.lowestPrice.discountPercentage)}% + </span> + </div> + <div + className={`bg-red-600 border border-solid border-yellow-400 rounded-full h-9 p-2 flex w-[50%] items-center justify-center gap-x-4`} + > + <ImageNext + src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg' + width={17} + height={10} + /> + <span className='text-white text-lg font-semibold'> + {product?.flashSale?.tag != 'false' || product?.flashSale?.tag + ? product?.flashSale?.tag + : 'FLASH SALE'} + </span> + </div> + <div> + <CountDown2 initialTime={product.flashSale.remainingTime} /> + </div> </div> </div> </div> - </div> - )} + )} <Image src={product.image} alt={product.name} @@ -390,7 +398,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { ))} </div> <div className='flex'> - <div className='w-3/4 leading-7 product__description'> + <div className='w-3/4 leading-8 product__description'> <TabContent active={informationTab == 'description'}> <span dangerouslySetInnerHTML={{ @@ -411,7 +419,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { </div> </div> - <div className='w-[25%]'> + <div className='w-[30%]'> {product.variants.length > 1 && product.lowestPrice.priceDiscount > 0 && ( <div className='text-gray_r-12/80'>Harga mulai dari: </div> )} @@ -440,7 +448,11 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => { )} </div> )} */} - + {product?.qtySold > 0 && ( + <div className='text-gray_r-9'> + {sellingProductFormat(product?.qtySold) + ' Terjual'} + </div> + )} {lowestPrice?.isFlashsale && lowestPrice?.price.discountPercentage > 0 ? ( <> <div className='flex gap-x-1 items-center mt-2'> diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx index ffa75f72..ef2c0002 100644 --- a/src/lib/product/components/Product/ProductMobile.jsx +++ b/src/lib/product/components/Product/ProductMobile.jsx @@ -19,9 +19,14 @@ import { gtagAddToCart } from '@/core/utils/googleTag' import odooApi from '@/core/api/odooApi' import ImageNext from 'next/image' import CountDown2 from '@/core/components/elements/CountDown/CountDown2' +import Breadcrumb from './Breadcrumb' +import useAuth from '@/core/hooks/useAuth' +import { sellingProductFormat } from '@/core/utils/formatValue' const ProductMobile = ({ product, wishlist, toggleWishlist }) => { const router = useRouter() + const auth = useAuth() + const { slug } = router.query const [quantity, setQuantity] = useState('1') const [selectedVariant, setSelectedVariant] = useState(null) @@ -58,7 +63,8 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { price: getLowestPrice(), stock: product.stockTotal, weight: product.weight, - hasProgram: false + hasProgram: false, + qtySold: product.qtySold }) const variantOptions = product.variants?.map((variant) => { @@ -101,7 +107,8 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { stock: variant.stock, weight: variant.weight, hasProgram: variant.hasProgram, - isFlashsale: variant.isFlashsale + isFlashsale: variant.isFlashsale, + qtySold: variant.qtySold } setActiveVariant(newActiveVariant) @@ -127,9 +134,20 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { return isValid } + const redirectToLogin = (action) => { + const nextURL = `/shop/product/${slug}?action=${action}&variantId=${activeVariant.id}&qty=${quantity}` + router.push(`/login?next=${encodeURIComponent(nextURL)}`) + return true + } + const handleClickCart = () => { if (!validAction()) return gtagAddToCart(activeVariant, quantity) + + if (!auth) { + return redirectToLogin('add_to_cart') + } + updateItemCart({ productId: activeVariant.id, quantity, @@ -142,6 +160,10 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { const handleClickBuy = () => { if (!validAction()) return + if (!auth) { + return redirectToLogin('buy') + } + updateItemCart({ productId: activeVariant.id, quantity, @@ -160,6 +182,7 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { return ( <MobileView> + <Breadcrumb productId={product.id} productName={product.name} /> <div className='relative'> {product?.flashSale?.remainingTime > 0 && activeVariant?.price.discountPercentage > 0 && ( <div className={`absolute bottom-0 w-full`}> @@ -225,7 +248,9 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { </button> </div> <h1 className='leading-6 font-medium mb-3'>{activeVariant?.name}</h1> - + {product?.qtySold > 0 && ( + <div className='text-gray_r-9'>{sellingProductFormat(activeVariant?.qtySold) + ' Terjual'}</div> + )} {product.variants.length > 1 && activeVariant.price.priceDiscount > 0 && !selectedVariant && ( |
