diff options
Diffstat (limited to 'src-migrate')
23 files changed, 87 insertions, 523 deletions
diff --git a/src-migrate/modules/cart/components/Item.tsx b/src-migrate/modules/cart/components/Item.tsx index a54d4648..47893498 100644 --- a/src-migrate/modules/cart/components/Item.tsx +++ b/src-migrate/modules/cart/components/Item.tsx @@ -17,11 +17,11 @@ import CartItemSelect from './ItemSelect' type Props = { item: CartItemProps editable?: boolean - selfPicking?: boolean pilihSemuaCart?: boolean } -const CartItem = ({ item, editable = true, selfPicking}: Props) => { +const CartItem = ({ item, editable = true,}: Props) => { + return ( <div className={style.wrapper}> {item.cart_type === 'promotion' && ( @@ -53,12 +53,6 @@ const CartItem = ({ item, editable = true, selfPicking}: Props) => { <CartItem.Image item={item} /> <div className={style.details}> - {/* disini */} - {selfPicking && (item.is_in_bu) && (item.on_hand_qty >= item.quantity) && ( - <div className='text-[10px] text-red-500 italic'> - *Barang ini bisa di pickup maksimal pukul 16.00 - </div> - )} <CartItem.Name item={item} /> <div className='mt-2 flex justify-between w-full'> diff --git a/src-migrate/modules/cart/components/ItemAction.tsx b/src-migrate/modules/cart/components/ItemAction.tsx index e73d507b..e5e7f314 100644 --- a/src-migrate/modules/cart/components/ItemAction.tsx +++ b/src-migrate/modules/cart/components/ItemAction.tsx @@ -11,6 +11,7 @@ import { deleteUserCart, upsertUserCart } from '~/services/cart' import { useDebounce } from 'usehooks-ts' import { useCartStore } from '../stores/useCartStore' +import { useProductCartContext } from '@/contexts/ProductCartContext' type Props = { @@ -19,7 +20,7 @@ type Props = { const CartItemAction = ({ item }: Props) => { const auth = getAuth() - + const { setRefreshCart } = useProductCartContext() const [isLoadDelete, setIsLoadDelete] = useState<boolean>(false) const [isLoadQuantity, setIsLoadQuantity] = useState<boolean>(false) @@ -36,6 +37,7 @@ const CartItemAction = ({ item }: Props) => { await deleteUserCart(auth.id, [item.cart_id]) await loadCart(auth.id) setIsLoadDelete(false) + setRefreshCart(true) } const decreaseQty = () => { setQuantity((quantity) => quantity -= 1) } diff --git a/src-migrate/modules/cart/components/ItemSelect.tsx b/src-migrate/modules/cart/components/ItemSelect.tsx index 2faf5172..d4a1b537 100644 --- a/src-migrate/modules/cart/components/ItemSelect.tsx +++ b/src-migrate/modules/cart/components/ItemSelect.tsx @@ -26,9 +26,11 @@ const CartItemSelect = ({ item }: Props) => { ? { ...cartItem, selected: e.target.checked } : cartItem ); + // Update the entire cart const updatedCart = { ...cart, products: updatedCartItems }; updateCartItem(updatedCart); + setIsLoad(false); } diff --git a/src-migrate/modules/cart/stores/useCartStore.ts b/src-migrate/modules/cart/stores/useCartStore.ts index ae551846..3b50ec32 100644 --- a/src-migrate/modules/cart/stores/useCartStore.ts +++ b/src-migrate/modules/cart/stores/useCartStore.ts @@ -48,6 +48,7 @@ export const useCartStore = create<State & Action>((set, get) => ({ const summary = computeSummary(updatedCart); set({ summary }); }, + })); const computeSummary = (cart: CartProps) => { diff --git a/src-migrate/modules/product-card/components/ProductCard.tsx b/src-migrate/modules/product-card/components/ProductCard.tsx index 931f8f2f..0febfadb 100644 --- a/src-migrate/modules/product-card/components/ProductCard.tsx +++ b/src-migrate/modules/product-card/components/ProductCard.tsx @@ -10,10 +10,6 @@ import formatCurrency from '~/libs/formatCurrency' import { formatToShortText } from '~/libs/formatNumber' import { createSlug } from '~/libs/slug' import { IProduct } from '~/types/product' -import { useRouter } from 'next/router'; -import currencyFormat from '@/core/utils/currencyFormat'; -import whatsappUrl from '@/core/utils/whatsappUrl'; -import { sellingProductFormat } from '@/core/utils/formatValue'; type Props = { product: IProduct @@ -22,17 +18,7 @@ type Props = { const ProductCard = ({ product, layout = 'vertical' }: Props) => { const utmSource = useUtmSource() - const router = useRouter(); - - const ppnString = process.env.NEXT_PUBLIC_PPN; - const ppnNumber = ppnString !== undefined ? Number(ppnString) : 0; - - const id = product.id.toString () - const callForPriceWhatsapp = whatsappUrl('product', { - name: product.name, - manufacture: product.manufacture?.name, - url: createSlug('/shop/product/', product.name, id, true), - }); + const URL = { product: createSlug('/shop/product/', product.name, product.id.toString()) + `?utm_source=${utmSource}`, @@ -89,42 +75,6 @@ const ProductCard = ({ product, layout = 'vertical' }: Props) => { </div> </div> </div> - {layout === 'vertical' && ( - <div> - {router.pathname != '/' && product?.flash_sale.id > 0 && ( - <div className='absolute left-0 bottom-0 w-full grid'> - <div className='absolute bottom-0 w-full h-full'> - <ImageNext - src='/images/BG-FLASH-SALE.jpg' - className='h-full' - width={1000} - height={100} alt={''} /> - </div> - <div className='relative'> - <div className='flex gap-x-1 items-center p-2 justify-center'> - <div className='bg-yellow-400 rounded-lg p-1 h-6 w-19 flex items-center justify-center '> - <span className='text-sm font-bold text-black'> - {Math.floor(product?.lowest_price.discount_percentage ? product?.lowest_price.discount_percentage : product?.lowest_price.discountPercentage)}% - </span> - </div> - <div className='bg-red-600 border border-solid border-yellow-400 p-2 rounded-full h-6 flex w-fit items-center justify-center gap-x-2'> - <ImageNext - src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg' - width={13} - height={5} alt={''} /> - <span className='text-white text-[9px] md:text-[10px] font-semibold'> - {product?.flash_sale?.tag != 'false' || - product?.flash_sale?.tag - ? product?.flash_sale?.tag - : 'FLASH SALE'} - </span> - </div> - </div> - </div> - </div> - )} - </div> - )} {product.variant_total > 1 && ( <div className={style['variant-badge']}>{product.variant_total} Varian</div> @@ -136,24 +86,6 @@ const ProductCard = ({ product, layout = 'vertical' }: Props) => { [style['content-v']]: layout === 'vertical', [style['content-h']]: layout === 'horizontal', })}> - {layout === 'horizontal' && ( - <div> - {product.flash_sale.id > 0 && ( - <div className='bg-red-600 rounded-full mb-1 p-2 pl-3 pr-3 flex w-fit items-center gap-x-1'> - <ImageNext - src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg' - width={15} - height={10} alt={''} /> - <span className='text-white text-xs font-semibold'> - {' '} - {product?.flash_sale?.tag != 'false' || product?.flash_sale?.tag - ? product?.flash_sale?.tag - : 'FLASH SALE'} - </span> - </div> - )} - </div> - )} <Link href={URL.manufacture} className={style['brand']} @@ -172,78 +104,33 @@ const ProductCard = ({ product, layout = 'vertical' }: Props) => { > {product.name} </Link> - <div className='h-1.5' /> - {product?.lowest_price.discountPercentage === undefined ? ( - <div> - {product?.flash_sale?.id > 0 && - product?.lowest_price.discount_percentage > 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.lowest_price.price)} - </div> - <div className='badge-solid-red'> - {Math.floor(product?.lowest_price.discount_percentage)}% - </div> - </div> - <div className='text-danger-500 font-semibold mb-2'> - {product?.lowest_price.price_discount > 0 ? ( - currencyFormat(product?.lowest_price.price_discount) - ) : ( - <a - rel='noopener noreferrer' - target='_blank' - href={callForPriceWhatsapp} - > - Call for Inquiry - </a> - )} - </div> - </> - ) : ( - <div className='text-danger-500 font-semibold mb-2 min-h-[40px]'> - {product?.lowest_price.price > 0 ? ( - <> - {currencyFormat(product?.lowest_price.price)} - <div className='text-gray_r-9 text-[10px] font-normal mt-2'> - Inc. PPN:{' '} - {currencyFormat( - product.lowest_price.price * ppnNumber - )} - </div> - </> - ) : ( - <a - rel='noopener noreferrer' - target='_blank' - href={callForPriceWhatsapp} - > - Call for Inquiry - </a> - )} - </div> - )} - <div className='flex w-full items-center gap-x-1 '> - {product?.stock_total > 0 && ( - <div className='badge-solid-red'>Ready Stock</div> - )} - {/* <div className='badge-gray'>{product?.stockTotal > 5 ? '> 5' : '< 5'}</div> */} - {product?.qty_sold > 0 && ( - <div className='text-gray_r-9 text-[11px]'> - {sellingProductFormat(product?.qty_sold) + ' Terjual'} - </div> - )} - </div> + <div className={style['price']}> + Rp {formatCurrency(product.lowest_price.price)} </div> - ) : ( - <div> - + + <div className='h-1.5' /> + + <div className={style['price-inc']}> + Inc PPN: + Rp {formatCurrency(Math.round(product.lowest_price.price * 1.11))} </div> - )} - + <div className='h-1' /> + + <div className='flex items-center gap-x-2.5'> + {product.stock_total > 0 && ( + <div className={style['ready-stock']}> + Ready Stock + </div> + )} + {product.qty_sold > 0 && ( + <div className={style['sold']}> + {formatToShortText(product.qty_sold)} Terjual + </div> + )} + </div> </div> </div> diff --git a/src-migrate/modules/product-detail/components/AddToCart.tsx b/src-migrate/modules/product-detail/components/AddToCart.tsx index a5284637..097db98a 100644 --- a/src-migrate/modules/product-detail/components/AddToCart.tsx +++ b/src-migrate/modules/product-detail/components/AddToCart.tsx @@ -1,35 +1,19 @@ -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import style from '../styles/price-action.module.css'; -import { Button, Link, useToast } from '@chakra-ui/react' -import product from 'next-seo/lib/jsonld/product' +import { Button, useToast } from '@chakra-ui/react' import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' -import Image from '~/components/ui/image' + import { getAuth } from '~/libs/auth' import { upsertUserCart } from '~/services/cart' -import LazyLoad from 'react-lazy-load'; -import ProductSimilar from '../../../../src/lib/product/components/ProductSimilar'; -import { IProductDetail } from '~/types/product'; -import ImageNext from 'next/image'; -import { useProductCartContext } from '@/contexts/ProductCartContext' -import { createSlug } from '~/libs/slug' -import formatCurrency from '~/libs/formatCurrency' -import { useProductDetail } from '../stores/useProductDetail'; type Props = { variantId: number | null, quantity?: number; source?: 'buy' | 'add_to_cart'; - products : IProductDetail } -type Status = 'idle' | 'loading' | 'success' - const AddToCart = ({ variantId, quantity = 1, - source = 'add_to_cart', - products + source = 'add_to_cart' }: Props) => { const auth = getAuth() const router = useRouter() @@ -38,65 +22,40 @@ const AddToCart = ({ isClosable: true }) - const { - askAdminUrl, - } = useProductDetail(); - - const [product, setProducts] = useState(products); - const [status, setStatus] = useState<Status>('idle') - const { productCart, setRefreshCart, setProductCart, refreshCart, isLoading, setIsloading } = - useProductCartContext() - - const productSimilarQuery = [ - product?.name, - `fq=-product_id_i:${product.id}`, - `fq=-manufacture_id_i:${product.manufacture?.id || 0}`, - ].join('&'); - const [addCartAlert, setAddCartAlert] = useState(false); - - const handleButton = async () => { + const handleClick = async () => { if (typeof auth !== 'object') { const currentUrl = encodeURIComponent(router.asPath) router.push(`/login?next=${currentUrl}`) return; } - + if ( !variantId || isNaN(quantity) || typeof auth !== 'object' ) return; - if (status === 'success') return - setStatus('loading') - await upsertUserCart({ - userId: auth.id, + + toast.promise( + upsertUserCart({ + userId: auth.id, type: 'product', id: variantId, qty: quantity, selected: true, source: source, qtyAppend: true - }) - setStatus('idle') - setRefreshCart(true); - setAddCartAlert(true); - - toast({ - title: 'Tambah ke keranjang', - description: 'Berhasil menambahkan barang ke keranjang belanja', - status: 'success', - duration: 3000, - isClosable: true, - position: 'top', - }) - + }), + { + loading: { title: 'Menambahkan ke keranjang', description: 'Mohon tunggu...' }, + success: { title: 'Menambahkan ke keranjang', description: 'Berhasil menambahkan ke keranjang belanja' }, + error: { title: 'Menambahkan ke keranjang', description: 'Gagal menambahkan ke keranjang belanja' }, + } + ) + if (source === 'buy') { router.push('/shop/checkout?source=buy') } } - useEffect(() => { - if (status === 'success') setTimeout(() => { setStatus('idle') }, 3000) - }, [status]) const btnConfig = { 'add_to_cart': { @@ -110,98 +69,10 @@ const AddToCart = ({ } return ( - <div className='w-full'> - <Button onClick={handleButton} colorScheme={btnConfig[source].colorScheme} className='w-full'> - {btnConfig[source].text} - </Button> - <BottomPopup - className='!container' - title='Berhasil Ditambahkan' - active={addCartAlert} - close={() => { - setAddCartAlert(false); - }} - > - <div className='flex mt-4'> - <div className='w-[10%]'> - <ImageNext - src={product.image} - alt={product.name} - className='h-32 object-contain object-center w-full border border-gray_r-4' - width={80} - height={80} - /> - </div> - <div className='ml-3 flex flex-1 items-start font-medium justify-center flex-col gap-y-1'> - {!!product.manufacture.name ? ( - <Link - href={createSlug('/shop/brands/', product.manufacture.name, product.manufacture.id.toString())} - className=' hover:underline' - color={"red"} - > - {product.manufacture.name} - </Link> - ) : '-'} - <p className='text-ellipsis overflow-hidden'> - {product.name} - </p> - <p> - {product.code} - </p> - {!!product.lowest_price && product.lowest_price.price > 0 && ( - <> - <div className='flex items-end gap-x-2'> - {product.lowest_price.discount_percentage > 0 && ( - <> - <div className='badge-solid-red'> - {Math.floor(product.lowest_price.discount_percentage)}% - </div> - <div className='text-gray_r-11 line-through text-[11px] sm:text-caption-2'> - Rp {formatCurrency(product.lowest_price.price || 0)} - </div> - </> - )} - <div className='text-danger-500 font-semibold'> - Rp {formatCurrency(product.lowest_price.price_discount || 0)} - </div> - </div> - </> - )} - - {!!product.lowest_price && product.lowest_price.price === 0 && ( - <span> - Hubungi kami untuk dapatkan harga terbaik,{' '} - <Link - href={askAdminUrl} - target='_blank' - className='font-medium underline' - color={'red'} - > - klik disini - </Link> - </span> - )} - </div> - <div className='ml-3 flex items-center font-normal'> - <Link - href='/shop/cart' - className='flex-1 py-2 text-gray_r-12 btn-yellow' - > - Lihat Keranjang - </Link> - </div> - </div> - <div className='mt-8 mb-4'> - <div className='text-h-sm font-semibold mb-6'> - Kamu Mungkin Juga Suka - </div> - <LazyLoad> - <ProductSimilar query={productSimilarQuery} /> - </LazyLoad> - </div> - </BottomPopup> - </div> + <Button onClick={handleClick} colorScheme={btnConfig[source].colorScheme} className='w-full'> + {btnConfig[source].text} + </Button> ) } -export default AddToCart
\ No newline at end of file +export default AddToCart
\ No newline at end of file diff --git a/src-migrate/modules/product-detail/components/PriceAction.tsx b/src-migrate/modules/product-detail/components/PriceAction.tsx index 9021264e..81271f6e 100644 --- a/src-migrate/modules/product-detail/components/PriceAction.tsx +++ b/src-migrate/modules/product-detail/components/PriceAction.tsx @@ -97,14 +97,12 @@ const PriceAction = ({ product }: Props) => { className={style['quantity-input']} /> <AddToCart - products={product} variantId={activeVariantId} quantity={Number(quantityInput)} /> {!isApproval && ( <AddToCart source='buy' - products={product} variantId={activeVariantId} quantity={Number(quantityInput)} /> diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx index 169e1903..fad35a7d 100644 --- a/src-migrate/modules/product-detail/components/ProductDetail.tsx +++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx @@ -37,7 +37,7 @@ const ProductDetail = ({ product }: Props) => { const router = useRouter() const auth = getAuth() const { setAskAdminUrl, askAdminUrl, activeVariantId, setIsApproval, isApproval } = useProductDetail() - + useEffect(() => { gtagProductDetail(product); },[product]) @@ -129,7 +129,7 @@ const ProductDetail = ({ product }: Props) => { )} <div className='h-4 md:h-10' /> - {!!activeVariantId && !isApproval && <ProductPromoSection product={product} productId={activeVariantId} />} + {!!activeVariantId && !isApproval && <ProductPromoSection productId={activeVariantId} />} <div className={style['section-card']}> <h2 className={style['heading']}> @@ -178,7 +178,7 @@ const ProductDetail = ({ product }: Props) => { <div className='h-6' /> <LazyLoadComponent> - <SimilarBottom product={product} source={'bottom'}/> + <SimilarBottom product={product} /> </LazyLoadComponent> </div> diff --git a/src-migrate/modules/product-detail/components/SimilarBottom.tsx b/src-migrate/modules/product-detail/components/SimilarBottom.tsx index f2daf664..40d4dd82 100644 --- a/src-migrate/modules/product-detail/components/SimilarBottom.tsx +++ b/src-migrate/modules/product-detail/components/SimilarBottom.tsx @@ -5,17 +5,16 @@ import { IProductDetail } from '~/types/product' type Props = { product: IProductDetail - source: string } -const SimilarBottom = ({ product, source }: Props) => { +const SimilarBottom = ({ product }: Props) => { const productSimilar = useProductSimilar({ name: product.name, - except: { productId: product.id, manufactureId: product.manufacture.id }, - source: source + except: { productId: product.id } }) const products = productSimilar.data?.products || [] + return ( <Skeleton isLoaded={!productSimilar.isLoading} diff --git a/src-migrate/modules/product-detail/components/SimilarSide.tsx b/src-migrate/modules/product-detail/components/SimilarSide.tsx index 2ba8fa21..d70a314d 100644 --- a/src-migrate/modules/product-detail/components/SimilarSide.tsx +++ b/src-migrate/modules/product-detail/components/SimilarSide.tsx @@ -11,7 +11,7 @@ type Props = { const SimilarSide = ({ product }: Props) => { const productSimilar = useProductSimilar({ name: product.name, - except: { productId: product.id }, + except: { productId: product.id, manufactureId: product.manufacture.id }, }) const products = productSimilar.data?.products || [] diff --git a/src-migrate/modules/product-promo/components/AddToCart.tsx b/src-migrate/modules/product-promo/components/AddToCart.tsx index 3d0955e3..87017c14 100644 --- a/src-migrate/modules/product-promo/components/AddToCart.tsx +++ b/src-migrate/modules/product-promo/components/AddToCart.tsx @@ -9,39 +9,19 @@ import { IPromotion } from '~/types/promotion' import DesktopView from '../../../../src/core/components/views/DesktopView'; import MobileView from '../../../../src/core/components/views/MobileView'; -import BottomPopup from '@/core/components/elements/Popup/BottomPopup' -import ImageNext from 'next/image'; -import Link from 'next/link' -import LazyLoad from 'react-lazy-load' -import ProductSimilar from '../../../../src/lib/product/components/ProductSimilar'; -import { IProductDetail } from '~/types/product'; -import { useProductCartContext } from '@/contexts/ProductCartContext' -import { createSlug } from '~/libs/slug' -import formatCurrency from '~/libs/formatCurrency' -import { useProductDetail } from '../../product-detail/stores/useProductDetail'; + type Props = { promotion: IPromotion - product: IProductDetail } type Status = 'idle' | 'loading' | 'success' -const ProductPromoAddToCart = ({product, promotion }: Props) => { - +const ProductPromoAddToCart = ({ promotion }: Props) => { const auth = getAuth() const toast = useToast() const router = useRouter() - const {askAdminUrl} = useProductDetail(); const [status, setStatus] = useState<Status>('idle') - const { productCart, setRefreshCart, setProductCart, refreshCart, isLoading, setIsloading } = - useProductCartContext() - - const productSimilarQuery = [ - promotion?.name, - `fq=-product_id_i:${promotion.products[0].product_id}`, - ].join('&'); - const [addCartAlert, setAddCartAlert] = useState(false); const handleButton = async () => { if (typeof auth !== 'object') { @@ -62,8 +42,7 @@ const ProductPromoAddToCart = ({product, promotion }: Props) => { qtyAppend: true }) setStatus('idle') - setRefreshCart(true); - setAddCartAlert(true); + toast({ title: 'Tambah ke keranjang', description: 'Berhasil menambahkan barang ke keranjang belanja', @@ -113,92 +92,6 @@ const ProductPromoAddToCart = ({product, promotion }: Props) => { {status === 'success' && <span>Berhasil</span>} {status !== 'success' && <span>Keranjang</span>} </Button> - <BottomPopup - className='!container' - title='Berhasil Ditambahkan' - active={addCartAlert} - close={() => { - setAddCartAlert(false); - }} - > - <div className='flex mt-4'> - <div className='w-[10%]'> - <ImageNext - src={product.image} - alt={product.name} - className='h-32 object-contain object-center w-full border border-gray_r-4' - width={80} - height={80} - /> - </div> - <div className='ml-3 flex flex-1 items-start font-medium justify-center flex-col gap-y-1'> - {!!product?.manufacture?.name ? ( - <Link - href={createSlug('/shop/brands/', product.manufacture.name, product.manufacture.id.toString())} - className=' hover:underline' - color={"red"} - > - {product.manufacture.name} - </Link> - ) : '-'} - <p className='text-ellipsis overflow-hidden'> - {product.name} - </p> - <p> - {product.code} - </p> - {!!product.lowest_price && product.lowest_price.price > 0 && ( - <> - <div className='flex items-end gap-x-2'> - {product.lowest_price.discount_percentage > 0 && ( - <> - <div className='badge-solid-red'> - {Math.floor(product.lowest_price.discount_percentage)}% - </div> - <div className='text-gray_r-11 line-through text-[11px] sm:text-caption-2'> - Rp {formatCurrency(product.lowest_price.price || 0)} - </div> - </> - )} - <div className='text-danger-500 font-semibold'> - Rp {formatCurrency(product.lowest_price.price_discount || 0)} - </div> - </div> - </> - )} - - {!!product.lowest_price && product.lowest_price.price === 0 && ( - <span> - Hubungi kami untuk dapatkan harga terbaik,{' '} - <Link - href={askAdminUrl} - target='_blank' - className='font-medium underline' - color={'red'} - > - klik disini - </Link> - </span> - )} - </div> - <div className='ml-3 flex items-center font-normal'> - <Link - href='/shop/cart' - className='flex-1 py-2 text-gray_r-12 btn-yellow' - > - Lihat Keranjang - </Link> - </div> - </div> - <div className='mt-8 mb-4'> - <div className='text-h-sm font-semibold mb-6'> - Kamu Mungkin Juga Suka - </div> - <LazyLoad> - <ProductSimilar query={productSimilarQuery} /> - </LazyLoad> - </div> - </BottomPopup> </DesktopView> </div> ) diff --git a/src-migrate/modules/product-promo/components/Card.tsx b/src-migrate/modules/product-promo/components/Card.tsx index 5c323276..728d23ca 100644 --- a/src-migrate/modules/product-promo/components/Card.tsx +++ b/src-migrate/modules/product-promo/components/Card.tsx @@ -15,16 +15,16 @@ import clsxm from '~/libs/clsxm' import ProductPromoItem from './Item' import ProductPromoAddToCart from "./AddToCart" import ProductPromoCardCountdown from "./CardCountdown" -import { IProductDetail } from '~/types/product'; + import MobileView from '../../../../src/core/components/views/MobileView'; import DesktopView from '../../../../src/core/components/views/DesktopView'; type Props = { promotion: IPromotion - product: IProductDetail + } -const ProductPromoCard = ({product, promotion}: Props) => { +const ProductPromoCard = ({ promotion}: Props) => { const [products, setProducts] = useState<IProductVariantPromo[]>([]) const [freeProducts, setFreeProducts] = useState<IProductVariantPromo[]>([]) const [error, setError] = useState<string | null>(null) @@ -132,7 +132,7 @@ const ProductPromoCard = ({product, promotion}: Props) => { </div> <div> - <ProductPromoAddToCart product={product} promotion={promotion} /> + <ProductPromoAddToCart promotion={promotion} /> </div> </div> @@ -189,7 +189,7 @@ const ProductPromoCard = ({product, promotion}: Props) => { </div> </div> <div> - <ProductPromoAddToCart product={product} promotion={promotion} /> + <ProductPromoAddToCart promotion={promotion} /> </div> </div> diff --git a/src-migrate/modules/product-promo/components/Modal.tsx b/src-migrate/modules/product-promo/components/Modal.tsx index 1722b9df..0de672c2 100644 --- a/src-migrate/modules/product-promo/components/Modal.tsx +++ b/src-migrate/modules/product-promo/components/Modal.tsx @@ -3,12 +3,8 @@ import { Modal } from "~/components/ui/modal" import { useModalStore } from '../stores/useModalStore' import ProductPromoCategoryTab from './CategoryTab' import ProductPromoModalContent from './ModalContent' -import { IProductDetail } from '~/types/product'; -type Props = { - product: IProductDetail -} -const ProductPromoModal = ({product}:Props) => { +const ProductPromoModal = () => { const { active, closeModal } = useModalStore() return ( @@ -21,7 +17,7 @@ const ProductPromoModal = ({product}:Props) => { <div className='h-4' /> - <ProductPromoModalContent product={product} /> + <ProductPromoModalContent /> </Modal> ) } diff --git a/src-migrate/modules/product-promo/components/ModalContent.tsx b/src-migrate/modules/product-promo/components/ModalContent.tsx index 256ef61a..ab5129f8 100644 --- a/src-migrate/modules/product-promo/components/ModalContent.tsx +++ b/src-migrate/modules/product-promo/components/ModalContent.tsx @@ -6,11 +6,7 @@ import { getVariantPromoByCategory } from "~/services/productVariant" import { useModalStore } from "../stores/useModalStore" import ProductPromoCard from "./Card" -import { IProductDetail } from '~/types/product'; -type Props = { - product: IProductDetail -} -const ProductPromoModalContent = ({product}:Props) => { +const ProductPromoModalContent = () => { const { activeTab, variantId } = useModalStore() const promotionsQuery = useQuery( @@ -28,7 +24,7 @@ const ProductPromoModalContent = ({product}:Props) => { <Skeleton isLoaded={!promotionsQuery.isLoading} className='min-h-[70vh] max-h-[70vh]'> <div className="grid grid-cols-1 gap-y-6 pb-6"> {promotions?.data.map((promo) => ( - <ProductPromoCard key={promo.id} promotion={promo} product={product} /> + <ProductPromoCard key={promo.id} promotion={promo} /> ))} {promotions?.data.length === 0 && ( <div className="py-10 rounded-lg h-fit text-center text-body-1 font-semibold text-gray-800 bg-gray-200">Belum ada promo pada kategori ini</div> diff --git a/src-migrate/modules/product-promo/components/Section.tsx b/src-migrate/modules/product-promo/components/Section.tsx index e1719998..4e8a7dd5 100644 --- a/src-migrate/modules/product-promo/components/Section.tsx +++ b/src-migrate/modules/product-promo/components/Section.tsx @@ -9,14 +9,12 @@ import { IPromotion } from '~/types/promotion' import { useModalStore } from "../stores/useModalStore" import ProductPromoCard from './Card' import ProductPromoModal from "./Modal" -import { IProductDetail } from '~/types/product'; type Props = { productId: number; - product: IProductDetail; } -const ProductPromoSection = ({ product, productId }: Props) => { +const ProductPromoSection = ({ productId }: Props) => { const promotionsQuery = useQuery({ queryKey: [`promotions.highlight`, productId], queryFn: async () => await fetch(`/api/product-variant/${productId}/promotion/highlight`).then((res) => res.json()) as { data: IPromotion[] } @@ -25,13 +23,14 @@ const ProductPromoSection = ({ product, productId }: Props) => { const promotions = promotionsQuery.data const { openModal } = useModalStore() + return ( <SmoothRender isLoaded={(promotions?.data && promotions?.data.length > 0) || false} height='450px' duration='700ms' > - <ProductPromoModal product={product}/> + <ProductPromoModal /> {promotions?.data && promotions?.data.length > 0 && ( <div className={style.titleWrapper}> @@ -51,7 +50,7 @@ const ProductPromoSection = ({ product, productId }: Props) => { > {promotions?.data.map((promotion) => ( <div key={promotion.id} className="min-w-[400px] max-w-[400px]"> - <ProductPromoCard product={product} promotion={promotion} /> + <ProductPromoCard promotion={promotion} /> </div> ))} </Skeleton> diff --git a/src-migrate/modules/promo/components/PromoList.tsx b/src-migrate/modules/promo/components/PromoList.tsx index 4d0db3c2..42725034 100644 --- a/src-migrate/modules/promo/components/PromoList.tsx +++ b/src-migrate/modules/promo/components/PromoList.tsx @@ -114,7 +114,7 @@ const PromoList: React.FC<PromoListProps> = ({ selectedPromo }) => { {promoData?.map((promotion: IPromotion) => ( <SwiperSlide key={promotion.id}> <div className="min-w-36 max-w-[400px] mb-[20px] sm:w-full md:w-full lg:w-full xl:w-full"> - <ProductPromoCard product={promoItems} promotion={promotion} /> + <ProductPromoCard promotion={promotion} /> </div> </SwiperSlide> ))} @@ -122,7 +122,7 @@ const PromoList: React.FC<PromoListProps> = ({ selectedPromo }) => { )} {isMobile && (promoData?.map((promotion: IPromotion) => ( <div key={promotion.id} className="min-w-[400px] max-w-[400px]"> - <ProductPromoCard product={promoItems} promotion={promotion} /> + <ProductPromoCard promotion={promotion} /> </div> )))} diff --git a/src-migrate/pages/shop/cart/index.tsx b/src-migrate/pages/shop/cart/index.tsx index 5aac64cf..5e3e042a 100644 --- a/src-migrate/pages/shop/cart/index.tsx +++ b/src-migrate/pages/shop/cart/index.tsx @@ -34,7 +34,6 @@ const CartPage = () => { const [isTop, setIsTop] = useState(true); const [hasChanged, setHasChanged] = useState(false); const prevCartRef = useRef<CartItem[] | null>(null); - const [isLoadQuantity, setIsLoadQuantity] = useState<boolean>(false) useEffect(() => { const handleScroll = () => { @@ -49,18 +48,14 @@ const CartPage = () => { useEffect(() => { if (typeof auth === 'object' && !cart) { - setIsLoadQuantity(true) loadCart(auth.id); - setIsLoadQuantity(false) setIsStepApproval(auth?.feature?.soApproval); } }, [auth, loadCart, cart, isButtonChek]); useEffect(() => { if (typeof auth === 'object' && !cart) { - setIsLoadQuantity(true) loadCart(auth.id); - setIsLoadQuantity(false) setIsStepApproval(auth?.feature?.soApproval); } }, [auth, loadCart, cart, isButtonChek]); @@ -83,7 +78,6 @@ const CartPage = () => { setHasChanged(false) } - // Update the ref to the current cart state prevCartRef.current = cart ? [...cart.products] : null; }, [cart]); @@ -121,10 +115,8 @@ const CartPage = () => { }) ); try { - setIsLoadQuantity(true) await Promise.all(upsertPromises); await loadCart(auth.id); - setIsLoadQuantity(false) } catch (error) { console.error('Failed to update cart items:', error); } @@ -148,7 +140,7 @@ const CartPage = () => { const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => { - // Ensure that cart is not null before attempting to update + if (cart) { const updatedCart = { ...cart, @@ -158,7 +150,7 @@ const CartPage = () => { })) }; - updateCartItem(updatedCart); // Pass only valid CartProps to updateCartItem + updateCartItem(updatedCart); if(hasSelectedAll){ setIsSelectedAll(false); }else{ @@ -174,10 +166,8 @@ const CartPage = () => { setIsLoadDelete(true) for (const item of cart.products) { if(item.selected === true){ - setIsLoadQuantity(true) await deleteUserCart(auth.id, [item.cart_id]) await loadCart(auth.id) - setIsLoadQuantity(false) } } setIsLoadDelete(false) @@ -294,7 +284,7 @@ const CartPage = () => { <Button colorScheme='yellow' w='full' - isDisabled={hasSelectedPromo || !hasSelected || isLoadQuantity} + isDisabled={hasSelectedPromo || !hasSelected} onClick={handleQuotation} > Quotation @@ -310,7 +300,7 @@ const CartPage = () => { <Button colorScheme='red' w='full' - isDisabled={!hasSelected || hasSelectNoPrice || isLoadQuantity} + isDisabled={!hasSelected || hasSelectNoPrice} onClick={handleCheckout} > Checkout diff --git a/src-migrate/pages/shop/promo/index.tsx b/src-migrate/pages/shop/promo/index.tsx index 2ebfc008..3bc2afb4 100644 --- a/src-migrate/pages/shop/promo/index.tsx +++ b/src-migrate/pages/shop/promo/index.tsx @@ -24,10 +24,10 @@ const PromoPage = () => { /> <PromoList selectedPromo={selectedPromo} /> </LazyLoadComponent> - <h1 className='sm:h-1'></h1> <LazyLoadComponent> <FlashSale /> </LazyLoadComponent> + <h1 className='h-1'></h1> <LazyLoadComponent> <FlashSaleNonDisplay /> </LazyLoadComponent> diff --git a/src-migrate/services/product.ts b/src-migrate/services/product.ts index a5039ad9..fe415d11 100644 --- a/src-migrate/services/product.ts +++ b/src-migrate/services/product.ts @@ -2,7 +2,6 @@ import { IProduct, IProductDetail } from '~/types/product'; import snakeCase from 'snakecase-keys'; import odooApi from '~/libs/odooApi'; import { ICategoryBreadcrumb } from '~/types/category'; -import productSearchApi from '../../src/lib/product/api/productSearchApi' const SELF_HOST = process.env.NEXT_PUBLIC_SELF_HOST; @@ -21,7 +20,6 @@ export const getProductById = async ( }; export interface GetProductSimilarProps { - source?: string; name: string; except?: { productId?: number; @@ -35,78 +33,30 @@ export interface GetProductSimilarRes { num_found: number; num_found_exact: boolean; start: number; - source: string; } export const getProductSimilar = async ({ name, except, limit = 30, - source, }: GetProductSimilarProps): Promise<GetProductSimilarRes> => { - let dataflashSale = null - const flashSale = await odooApi('GET', '/api/v1/flashsale/header') - if (flashSale && flashSale.length > 0) { - const dataFlash = await productSearchApi({ - query: `fq=flashsale_id_i:${flashSale[0].pricelist_id}&fq=flashsale_price_f:[1 TO *]&limit=${ - source === 'bottom' ? '4' : '1' - }`, - operation: 'AND' - }) - - dataflashSale = dataFlash.response.products.map((product: { - qtySold: any; - stockTotal: any; - flashSale: any; - lowestPrice: any; - }) => ({ - ...product, - lowest_price: { - discount_percentage: product.lowestPrice.discountPercentage, - price: product.lowestPrice.price, - price_discount: product.lowestPrice.priceDiscount, - }, - flash_sale: product.flashSale, - stock_total: product.stockTotal, - qty_sold: product.qtySold, - })); - if (source === 'bottom') { - dataflashSale = dataflashSale.slice('2', '4') - } else { - dataflashSale = dataflashSale - } - } - - const regex = /\b(?![A-Z\s]+\b)[A-Za-z\s]+\b/g; - const matches = name?.match(regex); - const extractedName = matches ? matches.join(' ').trim() : ''; - console.log("extractedName",extractedName); const query = [ - `q=${extractedName}`, + `q=${name}`, 'page=1', 'orderBy=popular-weekly', 'operation=OR', 'priceFrom=1', ]; + if (except?.productId) query.push(`fq=-product_id_i:${except.productId}`); if (except?.manufactureId) query.push(`fq=-manufacture_id_i:${except.manufactureId}`); + const url = `${SELF_HOST}/api/shop/search?${query.join('&')}`; - const fetchedData = await fetch(url) + return await fetch(url) .then((res) => res.json()) .then((res) => snakeCase(res.response)); - - if (dataflashSale) { - fetchedData.products = [ - ...dataflashSale, - ...fetchedData.products - ] - } else { - fetchedData.products = [...fetchedData.products] - } - - return fetchedData; }; export const getProductCategoryBreadcrumb = async ( diff --git a/src-migrate/types/cart.ts b/src-migrate/types/cart.ts index a3115103..4e3c8b99 100644 --- a/src-migrate/types/cart.ts +++ b/src-migrate/types/cart.ts @@ -32,8 +32,6 @@ export type CartItem = { id: number; name: string; stock: number; - is_in_bu: boolean; - on_hand_qty: number; weight: number; attributes: string[]; parent: { diff --git a/src-migrate/types/product.ts b/src-migrate/types/product.ts index 565eccdb..681cdc8e 100644 --- a/src-migrate/types/product.ts +++ b/src-migrate/types/product.ts @@ -1,8 +1,6 @@ import { IProductVariantDetail } from './productVariant'; export interface IProduct { - qtySold: number; - stockTotal: number; id: number; image: string; code: string; @@ -14,20 +12,17 @@ export interface IProduct { variant_total: number; description: string; isSni: boolean; - is_in_bu: boolean; isTkdn: boolean; categories: { id: string; name: string; }[]; flash_sale: { - id: number; + id: string; remaining_time: number; tag: string; }; lowest_price: { - priceDiscount: number; - discountPercentage: number; price: number; price_discount: number; discount_percentage: number; diff --git a/src-migrate/types/productVariant.ts b/src-migrate/types/productVariant.ts index 5f6bded5..861b216a 100644 --- a/src-migrate/types/productVariant.ts +++ b/src-migrate/types/productVariant.ts @@ -8,10 +8,6 @@ export interface IProductVariantDetail { remaining_time: number; is_flashsale: boolean; }; - categories: { - id: string; - name: string; - }[]; price: { price: number; price_discount: number; diff --git a/src-migrate/types/promotion.ts b/src-migrate/types/promotion.ts index 217bba33..85190aad 100644 --- a/src-migrate/types/promotion.ts +++ b/src-migrate/types/promotion.ts @@ -10,18 +10,15 @@ export interface IPromotion { limit_user: number; limit_trx: number; price: number; - image: string; total_qty: number; products: { product_id: number; qty: number; - name: string; }[]; free_products: { product_id: number; qty: number; }[]; - } export interface IProductVariantPromo { |
