diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-03-31 16:39:25 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-03-31 16:39:25 +0700 |
| commit | 0de043b180c1529b2d57d900523eece703e543a2 (patch) | |
| tree | 47990d05913b5517c7fd9e59e22bfe92b8714018 /src | |
| parent | 8c97d9f88c52e625f32d64c94718b5808e9c4dca (diff) | |
cart, product
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/components/elements/Popup/BottomPopup.jsx | 2 | ||||
| -rw-r--r-- | src/lib/cart/components/Cart.jsx | 2 | ||||
| -rw-r--r-- | src/lib/cart/hooks/useCart.js | 10 | ||||
| -rw-r--r-- | src/lib/product/components/Product/ProductDesktop.jsx | 74 | ||||
| -rw-r--r-- | src/lib/product/components/Product/ProductMobile.jsx | 101 | ||||
| -rw-r--r-- | src/lib/product/components/ProductCard.jsx | 99 | ||||
| -rw-r--r-- | src/pages/api/shop/search.js | 4 |
7 files changed, 114 insertions, 178 deletions
diff --git a/src/core/components/elements/Popup/BottomPopup.jsx b/src/core/components/elements/Popup/BottomPopup.jsx index 5e9f68c7..4fd17ed0 100644 --- a/src/core/components/elements/Popup/BottomPopup.jsx +++ b/src/core/components/elements/Popup/BottomPopup.jsx @@ -53,7 +53,7 @@ const BottomPopup = ({ children, active = false, title, close }) => { animate={{ bottom: '50%', opacity: 1 }} exit={{ bottom: '45%', opacity: 0 }} transition={transition} - className='fixed left-1/2 -translate-x-1/2 w-2/5 border border-gray_r-6 rounded-xl z-[60] p-4 pt-0 bg-white' + className='fixed left-1/2 -translate-x-1/2 translate-y-1/2 w-2/5 border border-gray_r-6 rounded-xl z-[60] p-4 pt-0 bg-white' > <div className='flex justify-between py-4'> <div className='font-semibold text-h-sm'>{title}</div> diff --git a/src/lib/cart/components/Cart.jsx b/src/lib/cart/components/Cart.jsx index 8400857d..1131fed7 100644 --- a/src/lib/cart/components/Cart.jsx +++ b/src/lib/cart/components/Cart.jsx @@ -288,7 +288,7 @@ const Cart = () => { <DesktopView> <div className='container mx-auto py-10 flex'> - <div className='w-9/12 border border-gray_r-6 rounded bg-white p-4'> + <div className='w-9/12 border border-gray_r-6 rounded bg-white p-4 pt-6'> <h1 className='text-title-sm font-semibold mb-6'>Daftar Produk Belanja</h1> <table className='table-cart'> diff --git a/src/lib/cart/hooks/useCart.js b/src/lib/cart/hooks/useCart.js index bc1ea7ea..b91c8d90 100644 --- a/src/lib/cart/hooks/useCart.js +++ b/src/lib/cart/hooks/useCart.js @@ -4,14 +4,12 @@ import _ from 'lodash' import CartApi from '../api/CartApi' const useCart = ({ enabled }) => { - const cart = getCart() - const variantIds = _.keys(cart).join(',') + const cartStorage = getCart() + const variantIds = _.keys(cartStorage).join(',') const fetchCart = async () => CartApi({ variantIds }) - const { data, isLoading } = useQuery('cart', fetchCart, { enabled }) + const cart = useQuery('cart', fetchCart, { enabled }) - return { - cart: { data, isLoading } - } + return { cart } } export default useCart diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index c7554242..e0d2a959 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -3,19 +3,32 @@ 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 { useCallback, useEffect, 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' -import useProductPrice from '../../hooks/useProductPrice' -import PriceSkeleton from '@/core/components/elements/Skeleton/PriceSkeleton' import { useRouter } from 'next/router' import { createSlug } from '@/core/utils/slug' const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { const router = useRouter() - const { productPrice } = useProductPrice({ id: product.id }) + + const [lowestPrice, setLowestPrice] = useState(null) + + const getLowestPrice = useCallback(() => { + const prices = product.variants.map((variant) => variant.price) + const lowest = prices.reduce((lowest, price) => { + return price.priceDiscount < lowest.priceDiscount ? price : lowest + }, prices[0]) + return lowest + }, [product]) + + useEffect(() => { + const lowest = getLowestPrice() + setLowestPrice(lowest) + }, [getLowestPrice]) + const [informationTab, setInformationTab] = useState(informationTabOptions[0].value) const variantQuantityRefs = useRef([]) @@ -63,8 +76,8 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { const productSimilarQuery = [ product?.name.replace(/[()/"&]/g, ''), - `fq=-product_id:${product.id}`, - `fq=-manufacture_id:${product.manufacture?.id || 0}` + `fq=-product_id_i:${product.id}`, + `fq=-manufacture_id_i:${product.manufacture?.id || 0}` ].join('&') return ( @@ -125,33 +138,30 @@ const ProductDesktop = ({ product, wishlist, toggleWishlist }) => { {product.variants.length > 1 && product.lowestPrice.priceDiscount > 0 && ( <div className='text-gray_r-12/80'>Harga mulai dari: </div> )} - {productPrice.isLoading && <PriceSkeleton />} - {productPrice.isFetched && ( - <> - {productPrice?.data?.discount > 0 && ( - <div className='flex gap-x-1 items-center mt-2'> - <div className='badge-solid-red text-caption-1'> - {productPrice?.data?.discount}% - </div> - <div className='text-gray_r-11 line-through text-caption-1'> - {currencyFormat(productPrice?.data?.priceExclude)} - </div> - </div> - )} - <h3 className='text-red_r-11 font-semibold mt-1 text-title-md'> - {productPrice?.data?.priceExcludeAfterDiscount > 0 ? ( - currencyFormat(productPrice?.data?.priceExcludeAfterDiscount) - ) : ( - <span className='text-gray_r-12/90 font-normal text-h-sm'> - Hubungi kami untuk dapatkan harga terbaik, - <a href='https://wa.me/' className='text-red_r-11 underline'> - klik disini - </a> - </span> - )} - </h3> - </> + + {lowestPrice?.discountPercentage > 0 && ( + <div className='flex gap-x-1 items-center mt-2'> + <div className='badge-solid-red text-caption-1'> + {lowestPrice?.discountPercentage}% + </div> + <div className='text-gray_r-11 line-through text-caption-1'> + {currencyFormat(lowestPrice?.price)} + </div> + </div> )} + <h3 className='text-red_r-11 font-semibold mt-1 text-title-md'> + {lowestPrice?.priceDiscount > 0 ? ( + currencyFormat(lowestPrice?.priceDiscount) + ) : ( + <span className='text-gray_r-12/90 font-normal text-h-sm'> + 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} diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx index e560639c..13b02354 100644 --- a/src/lib/product/components/Product/ProductMobile.jsx +++ b/src/lib/product/components/Product/ProductMobile.jsx @@ -11,24 +11,28 @@ import { HeartIcon } from '@heroicons/react/24/outline' import { useRouter } from 'next/router' import MobileView from '@/core/components/views/MobileView' import { toast } from 'react-hot-toast' -import useVariantPrice from '@/lib/variant/hooks/useVariantPrice' -import PriceSkeleton from '@/core/components/elements/Skeleton/PriceSkeleton' -import useProductPrice from '../../hooks/useProductPrice' import { createSlug } from '@/core/utils/slug' const ProductMobile = ({ product, wishlist, toggleWishlist }) => { const router = useRouter() - const { productPrice } = useProductPrice({ id: product.id }) const [quantity, setQuantity] = useState('1') const [selectedVariant, setSelectedVariant] = useState(null) const [informationTab, setInformationTab] = useState(informationTabOptions[0].value) + const getLowestPrice = () => { + const prices = product.variants.map((variant) => variant.price) + const lowest = prices.reduce((lowest, price) => { + return price.priceDiscount < lowest.priceDiscount ? price : lowest + }, prices[0]) + return lowest + } + const [activeVariant, setActiveVariant] = useState({ id: null, code: product.code, name: product.name, - price: product.lowestPrice, + price: getLowestPrice(), stock: product.stockTotal, weight: product.weight }) @@ -93,8 +97,8 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { const productSimilarQuery = [ product?.name.replace(/[()/"&]/g, ''), - `fq=-product_id:${product.id}`, - `fq=-manufacture_id:${product.manufacture?.id || 0}` + `fq=-product_id_i:${product.id}`, + `fq=-manufacture_id_i:${product.manufacture?.id || 0}` ].join('&') return ( @@ -124,36 +128,32 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { )} </button> </div> - <h1 className='leading-6 font-medium'>{activeVariant?.name}</h1> - {activeVariant.id && <VariantPrice id={activeVariant.id} />} - {product.variants?.length > 1 && !activeVariant.id && productPrice.isLoading && ( - <PriceSkeleton /> + <h1 className='leading-6 font-medium mb-3'>{activeVariant?.name}</h1> + + {product.variants.length > 1 && activeVariant.price.priceDiscount > 0 && !selectedVariant && ( + <div className='text-gray_r-12/80 text-caption-2 mt-2 mb-1'>Harga mulai dari: </div> )} - {product.variants?.length > 1 && !activeVariant.id && productPrice.isFetched && ( - <> - <div className='text-gray_r-12/80 text-caption-2 mt-2 mb-1'>Harga mulai dari: </div> - {productPrice?.data?.discount > 0 && ( - <div className='flex gap-x-1 items-center'> - <div className='text-gray_r-11 line-through text-caption-1'> - {currencyFormat(productPrice?.data?.priceExclude)} - </div> - <div className='badge-solid-red'>{productPrice?.data?.discount}%</div> - </div> - )} - <h3 className='text-red_r-11 font-semibold mt-1'> - {productPrice?.data?.priceExcludeAfterDiscount > 0 ? ( - currencyFormat(productPrice?.data?.priceExcludeAfterDiscount) - ) : ( - <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> - </> + + {activeVariant?.price?.discountPercentage > 0 && ( + <div className='flex gap-x-1 items-center'> + <div className='text-gray_r-11 line-through text-caption-1'> + {currencyFormat(activeVariant?.price?.price)} + </div> + <div className='badge-solid-red'>{activeVariant?.price?.discountPercentage}%</div> + </div> )} + <h3 className='text-red_r-11 font-semibold mt-1'> + {activeVariant?.price?.priceDiscount > 0 ? ( + currencyFormat(activeVariant?.price?.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> </div> <Divider /> @@ -268,37 +268,6 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => { ) } -const VariantPrice = ({ id }) => { - const { variantPrice } = useVariantPrice({ id }) - - if (variantPrice.isLoading) return <PriceSkeleton /> - - return ( - <> - {variantPrice?.data?.discount > 0 && ( - <div className='flex gap-x-1 items-center mt-2'> - <div className='text-gray_r-11 line-through text-caption-1'> - {currencyFormat(variantPrice?.data?.priceExclude)} - </div> - <div className='badge-solid-red'>{variantPrice?.data?.discount}%</div> - </div> - )} - <h3 className='text-red_r-11 font-semibold mt-1'> - {variantPrice?.data?.priceExcludeAfterDiscount > 0 ? ( - currencyFormat(variantPrice?.data?.priceExcludeAfterDiscount) - ) : ( - <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> - </> - ) -} - const informationTabOptions = [ { value: 'specification', label: 'Spesifikasi' }, { value: 'description', label: 'Deskripsi' }, diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index e48ab88a..df709394 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -2,9 +2,6 @@ import Image from '@/core/components/elements/Image/Image' import Link from '@/core/components/elements/Link/Link' import currencyFormat from '@/core/utils/currencyFormat' import { createSlug } from '@/core/utils/slug' -import useProductPrice from '../hooks/useProductPrice' -import { LazyLoadComponent } from 'react-lazy-load-image-component' -import PriceSkeleton from '@/core/components/elements/Skeleton/PriceSkeleton' const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { if (variant == 'vertical') { @@ -48,9 +45,23 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { > {product?.name} </Link> - <LazyLoadComponent> - <ProductCardPrice variant='vertical' id={product.id} /> - </LazyLoadComponent> + {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'>{product?.lowestPrice.discountPercentage}%</div> + </div> + )} + + <div className='text-red_r-11 font-semibold mb-2'> + {product?.lowestPrice.priceDiscount > 0 ? ( + currencyFormat(product?.lowestPrice.priceDiscount) + ) : ( + <a href='https://wa.me/'>Call for price</a> + )} + </div> + {product?.stockTotal > 0 && ( <div className='flex gap-x-1'> <div className='badge-solid-red'>Ready Stock</div> @@ -106,83 +117,31 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { {product?.name} </Link> - <LazyLoadComponent> - <ProductCardPrice variant='horizontal' id={product.id} /> - </LazyLoadComponent> - {product?.stockTotal > 0 && ( - <div className='flex gap-x-1'> - <div className='badge-solid-red'>Ready Stock</div> - <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div> - </div> - )} - </div> - </div> - ) - } -} - -const ProductCardPrice = ({ variant, id }) => { - const { productPrice } = useProductPrice({ id }) - - if (productPrice.isLoading) return <PriceSkeleton /> - - if (variant == 'vertical') { - return ( - productPrice.isFetched && ( - <> - {productPrice?.data?.discount > 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( - productPrice?.data?.priceStartFrom || productPrice?.data?.priceExclude - )} + <div className='badge-solid-red'>{product?.lowestPrice?.discountPercentage}%</div> + <div className='text-gray_r-11 line-through text-caption-2'> + {currencyFormat(product?.lowestPrice?.price)} </div> - <div className='badge-solid-red'>{productPrice?.data?.discount}%</div> </div> )} <div className='text-red_r-11 font-semibold mb-2'> - {productPrice?.data?.priceExcludeAfterDiscount > 0 ? ( - currencyFormat( - productPrice?.data?.priceDiscStartFrom || - productPrice?.data?.priceExcludeAfterDiscount - ) + {product?.lowestPrice?.priceDiscount > 0 ? ( + currencyFormat(product?.lowestPrice?.priceDiscount) ) : ( <a href='https://wa.me/'>Call for price</a> )} </div> - </> - ) - ) - } - if (variant == 'horizontal') { - return ( - productPrice.isFetched && ( - <> - {productPrice?.data?.discount > 0 && ( - <div className='flex gap-x-1 mb-1 items-center'> - <div className='badge-solid-red'>{productPrice?.data?.discount}%</div> - <div className='text-gray_r-11 line-through text-caption-2'> - {currencyFormat( - productPrice?.data?.priceStartFrom || productPrice?.data?.priceExclude - )} - </div> + {product?.stockTotal > 0 && ( + <div className='flex gap-x-1'> + <div className='badge-solid-red'>Ready Stock</div> + <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div> </div> )} - - <div className='text-red_r-11 font-semibold mb-2'> - {productPrice?.data?.priceExcludeAfterDiscount > 0 ? ( - currencyFormat( - productPrice?.data?.priceDiscStartFrom || - productPrice?.data?.priceExcludeAfterDiscount - ) - ) : ( - <a href='https://wa.me/'>Call for price</a> - )} - </div> - </> - ) + </div> + </div> ) } } diff --git a/src/pages/api/shop/search.js b/src/pages/api/shop/search.js index d6829f6e..e174b06f 100644 --- a/src/pages/api/shop/search.js +++ b/src/pages/api/shop/search.js @@ -10,8 +10,8 @@ const productResponseMap = (products) => { name: product.name_s || '', lowestPrice: { price: product.price_f || 0, - priceDiscount: product.discount_f || 0, - discountPercentage: product.price_discount_f || 0 + priceDiscount: product.price_discount_f || 0, + discountPercentage: product.discount_f || 0 }, variantTotal: product.variant_total_i || 0, stockTotal: product.stock_total_f || 0, |
