diff options
Diffstat (limited to 'src/lib')
33 files changed, 330 insertions, 1931 deletions
diff --git a/src/lib/brand/components/BrandCard.jsx b/src/lib/brand/components/BrandCard.jsx index 2d78d956..731214ff 100644 --- a/src/lib/brand/components/BrandCard.jsx +++ b/src/lib/brand/components/BrandCard.jsx @@ -8,7 +8,7 @@ const BrandCard = ({ brand }) => { return ( <Link href={createSlug('/shop/brands/', brand.name, brand.id)} - className={`py-1 px-2 border-gray_r-6 flex justify-center items-center hover:scale-110 transition duration-500 ease-in-out ${ + className={`py-1 px-2 rounded border border-gray_r-6 flex justify-center items-center ${ isMobile ? 'h-16' : 'h-24' }`} > @@ -16,9 +16,9 @@ const BrandCard = ({ brand }) => { <Image src={brand.logo} alt={brand.name} - width={50} - height={50} - className='h-full w-[122px] object-contain object-center' + width={128} + height={128} + className='h-full w-full object-contain object-center' /> )} {!brand.logo && ( diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx index 6967d180..19f79bc9 100644 --- a/src/lib/cart/components/Cartheader.jsx +++ b/src/lib/cart/components/Cartheader.jsx @@ -1,20 +1,14 @@ import { useCallback, useEffect, useMemo, useState } from 'react' import { getCartApi } from '../api/CartApi' -import currencyFormat from '@/core/utils/currencyFormat' -import { createSlug } from '@/core/utils/slug' import useAuth from '@/core/hooks/useAuth' import { useRouter } from 'next/router' import odooApi from '@/core/api/odooApi' import { useProductCartContext } from '@/contexts/ProductCartContext' -import Image from '@/core/components/elements/Image/Image' -import whatsappUrl from '@/core/utils/whatsappUrl' -import { AnimatePresence, motion } from 'framer-motion' -import style from '../../../../src-migrate/modules/cart/styles/item-promo.module.css' + const { ShoppingCartIcon, PhotoIcon } = require('@heroicons/react/24/outline') const { default: Link } = require('next/link') const Cardheader = (cartCount) => { - const router = useRouter() const [subTotal, setSubTotal] = useState(null) const [buttonLoading, SetButtonTerapkan] = useState(false) @@ -25,7 +19,7 @@ const Cardheader = (cartCount) => { useProductCartContext() const [isHovered, setIsHovered] = useState(false) - const [isTop, setIsTop] = useState(true) + const products = useMemo(() => { return productCart?.products || [] }, [productCart]) @@ -81,26 +75,14 @@ const Cardheader = (cartCount) => { useEffect(() => { setCountCart(cartCount.cartCount) - setRefreshCart(false) }, [cartCount]) - useEffect(() => { - const handleScroll = () => { - setIsTop(window.scrollY === 0) - } - window.addEventListener('scroll', handleScroll) - return () => { - window.removeEventListener('scroll', handleScroll) - } - }, []) - const handleCheckout = async () => { SetButtonTerapkan(true) let checkoutAll = await odooApi('POST', `/api/v1/user/${auth.id}/cart/select-all`) router.push('/shop/checkout') } - return ( <div className='relative group'> <div> @@ -127,246 +109,6 @@ const Cardheader = (cartCount) => { </span> </Link> </div> - <AnimatePresence> - {isHovered && ( - <> - <motion.div - initial={{ opacity: 0 }} - animate={{ opacity: 1, top: isTop ? 230 : 155 }} - exit={{ opacity: 0 }} - transition={{ duration: 0.15, top: { duration: 0.3 } }} - className={`fixed left-0 w-full h-full bg-black/50 z-10`} - /> - <motion.div - initial={{ opacity: 0 }} - animate={{ opacity: 1, transition: { duration: 0.2 } }} - exit={{ opacity: 0, transition: { duration: 0.3 } }} - className='absolute z-10 left-0 w-96' - onMouseEnter={handleMouseEnter} - onMouseLeave={handleMouseLeave} - > - <motion.div - initial={{ height: 0 }} - animate={{ height: 'auto' }} - exit={{ height: 0 }} - className='w-full max-w-md p-2 bg-white border border-gray-200 rounded-lg shadow overflow-hidden' - > - <div className='p-2 flex justify-between items-center'> - <h5 className='text-base font-semibold leading-none'>Keranjang Belanja</h5> - <Link href='/shop/cart' class='text-sm font-medium text-red-600 underline'> - Lihat Semua - </Link> - </div> - <hr className='mt-3 mb-3 border border-gray-100' /> - <div className='flow-root max-h-[250px] overflow-y-auto'> - {!auth && ( - <div className='justify-center p-4'> - <p className='text-gray-500 text-center '> - Silahkan{' '} - <Link href='/login' className='text-red-600 underline leading-6'> - Login - </Link>{' '} - Untuk Melihat Daftar Keranjang Belanja Anda - </p> - </div> - )} - {isLoading && - itemLoading.map((item) => ( - <div key={item} role='status' className='max-w-sm animate-pulse'> - <div className='flex items-center space-x-4 mb- 2'> - <div className='flex-shrink-0'> - <PhotoIcon className='h-16 w-16 text-gray-500' /> - </div> - <div className='flex-1 min-w-0'> - <div className='h-2.5 bg-gray-200 rounded-full dark:bg-gray-700 w-48 mb-4'></div> - <div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px] mb-2.5'></div> - <div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 mb-2.5'></div> - </div> - </div> - </div> - ))} - {auth && products.length === 0 && !isLoading && ( - <div className='justify-center p-4'> - <p className='text-gray-500 text-center '> - Tidak Ada Produk di Keranjang Belanja Anda - </p> - </div> - )} - {auth && products.length > 0 && !isLoading && ( - <> - <ul role='list' className='divide-y divide-gray-200 dark:divide-gray-700'> - {products && - products?.map((product, index) => ( - <> - <li className='py-1 sm:py-2'> - <div className='flex items-center space-x-4'> - <div className='bagian gambar flex-shrink-0'> - {product.cartType === 'promotion' && ( - <Image - src={product.imageProgram[0]} - alt={product.name} - className='object-contain object-center border border-gray_r-6 h-16 w-16 rounded-md' - /> - )} - {product.cartType === 'product' && ( - <Link - href={createSlug( - '/shop/product/', - product?.parent.name, - product?.parent.id - )} - className='line-clamp-2 leading-6 !text-gray_r-12 font-normal' - > - <Image - src={product?.parent?.image} - alt={product?.name} - className='object-contain object-center border border-gray_r-6 h-16 w-16 rounded-md' - /> - </Link> - )} - </div> - <div className='bagian tulisan dan harga flex-1 min-w-0'> - {product.cartType === 'promotion' && ( - <p className='text-caption-2 font-medium text-gray-900 truncate dark:text-white'> - {product.name} - </p> - )} - {product.cartType === 'product' && ( - <Link - href={createSlug( - '/shop/product/', - product?.parent.name, - product?.parent.id - )} - className='line-clamp-2 leading-6 !text-gray_r-12 font-normal' - > - {' '} - <p className='text-caption-2 font-medium text-gray-900 truncate dark:text-white'> - {product.parent.name} - </p> - </Link> - )} - {product?.hasFlashsale && ( - <div className='flex gap-x-1 items-center mb-2 mt-1'> - <div className='badge-solid-red'> - {product?.price?.discountPercentage}% - </div> - <div className='text-gray_r-11 line-through text-caption-2'> - {currencyFormat(product?.price?.price)} - </div> - </div> - )} - - <div className='flex justify-between items-center'> - <div className='font-semibold text-sm text-red-600'> - {product?.price?.priceDiscount > 0 ? ( - currencyFormat(product?.price?.priceDiscount) - ) : ( - <span className='text-gray_r-12/90 font-normal text-caption-1'> - <a - href={whatsappUrl('product', { - name: product.name, - manufacture: product.manufacture?.name, - url: createSlug( - '/shop/product/', - product.name, - product.id, - true - ) - })} - className='text-danger-500 underline' - rel='noopener noreferrer' - target='_blank' - > - Call For Price - </a> - </span> - )} - </div> - </div> - </div> - </div> - <div className="flex flex-col w-3/4"> - {product.products?.map((product) => - <div key={product.id} className='md:ml-8 ml-4 mt-2 flex'> - <Link href={createSlug('/shop/product/', product.parent.name, product.parent.id.toString())} className='md:h-12 md:w-12 md:min-w-[48px] h-10 w-10 min-w-[40px] border border-gray-300 rounded '> - {product?.image && <Image src={product.image} alt={product.name} width={40} height={40} className='w-full h-full object-fill' />} - </Link> - - <div className="ml-4 w-full flex flex-col gap-y-1"> - <Link href={createSlug('/shop/product/', product.parent.name, product.parent.id.toString())} className="text-caption-2 font-medium text-gray-900 truncate dark:text-white"> - {product.displayName} - </Link> - - <div className='flex w-full'> - <div className="flex flex-col"> - {/* <div className="text-gray-500 text-caption-1">{product.code}</div> */} - <div> - <span className="text-gray-500 text-caption-1">Berat Barang: </span> - <span className="text-gray-500 text-caption-1">{product.packageWeight} Kg</span> - </div> - </div> - </div> - </div> - - </div> - )} - {product.freeProducts?.map((product) => - <div key={product.id} className='md:ml-8 ml-4 mt-2 flex'> - <Link href={createSlug('/shop/product/', product.parent.name, product.parent.id.toString())} className='md:h-12 md:w-12 md:min-w-[48px] h-10 w-10 min-w-[40px] border border-gray-300 rounded '> - {product?.image && <Image src={product.image} alt={product.name} width={40} height={40} className='w-full h-full object-fill' />} - </Link> - - <div className="ml-4 w-full flex flex-col gap-y-1"> - <Link href={createSlug('/shop/product/', product.parent.name, product.parent.id.toString())} className="text-caption-2 font-medium text-gray-900 truncate dark:text-white"> - {product.displayName} - </Link> - - <div className='flex w-full'> - <div className="flex flex-col"> - {/* <div className="text-gray-500 text-caption-1">{product.code}</div> */} - <div> - <span className="text-gray-500 text-caption-1">Berat Barang: </span> - <span className="text-gray-500 text-caption-1">{product.packageWeight} Kg</span> - </div> - </div> - </div> - </div> - - </div> - )} - </div> - </li> - </> - ))} - </ul> - <hr /> - </> - )} - </div> - {auth && products.length > 0 && !isLoading && ( - <> - <div className='mt-3'> - <span className='text-gray-400 text-caption-2'>Subtotal Sebelum PPN : </span> - <span className='font-semibold text-red-600'>{currencyFormat(subTotal)}</span> - </div> - <div className='mt-5 mb-2'> - <button - type='button' - className='btn-solid-red rounded-lg w-full' - onClick={handleCheckout} - disabled={buttonLoading} - > - {buttonLoading ? 'Loading...' : 'Lanjutkan Ke Pembayaran'} - </button> - </div> - </> - )} - </motion.div> - </motion.div> - </> - )} - </AnimatePresence> </div> ) } diff --git a/src/lib/category/api/popularProduct.js b/src/lib/category/api/popularProduct.js deleted file mode 100644 index e17e0ae5..00000000 --- a/src/lib/category/api/popularProduct.js +++ /dev/null @@ -1,31 +0,0 @@ - -export const fetchPromoItemsSolr = async (category_id_ids) => { - let sort ='sort=qty_sold_f desc'; - try { - const queryParams = new URLSearchParams({ q: category_id_ids }); - const response = await fetch(`/solr/product/select?${queryParams.toString()}&rows=2000&fl=manufacture_name_s,manufacture_id_i,id,display_name_s&${sort}`); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - const data = await response.json(); - const promotions = await map(data.response.docs); - return promotions; - } catch (error) { - console.error("Error fetching promotion data:", error); - return []; - } - }; - - const map = async (promotions) => { - const result = []; - for (const promotion of promotions) { - const data = { - id: promotion.id, - name: promotion.display_name_s, - manufacture_name: promotion.manufacture_name_s, - manufacture_id: promotion.manufacture_id_i, - }; - result.push(data); - } - return result; - };
\ No newline at end of file diff --git a/src/lib/category/components/Category.jsx b/src/lib/category/components/Category.jsx index ff958378..e6ea5acf 100644 --- a/src/lib/category/components/Category.jsx +++ b/src/lib/category/components/Category.jsx @@ -2,15 +2,10 @@ import odooApi from '@/core/api/odooApi' import Link from '@/core/components/elements/Link/Link' import DesktopView from '@/core/components/views/DesktopView' import { createSlug } from '@/core/utils/slug' -import { ChevronRightIcon } from '@heroicons/react/24/outline' -import Image from 'next/image' import { useEffect, useState } from 'react' -import PopularBrand from './PopularBrand' const Category = () => { const [categories, setCategories] = useState([]) - const [openCategories, setOpenCategory] = useState([]); - useEffect(() => { const loadCategories = async () => { @@ -31,65 +26,46 @@ const Category = () => { } loadCategories() }, []) - // console.log("categories",categories) return ( <DesktopView> <div className='category-mega-box'> {categories?.map((category) => ( - <div key={category.id} className='flex'> + <div key={category.id}> <Link href={createSlug('/shop/category/', category.name, category.id)} - className='category-mega-box__parent flex items-center' + className='category-mega-box__parent' > - <div className='w-6 h-6 border mr-2 rounded-full flex justify-center items-center'> - <Image src={category.image} alt='' width={16} height={16} /> - </div> {category.name} </Link> <div className='category-mega-box__child-wrapper'> - <div className='grid grid-cols-3 gap-x-4 gap-y-6 max-h-full !w-[590px] overflow-auto'> + <div className='grid grid-cols-3 gap-x-4 gap-y-6 max-h-full overflow-auto'> {category.childs.map((child1Category) => ( - <div key={child1Category.id} className='w-full'> + <div key={child1Category.id}> <Link href={createSlug('/shop/category/', child1Category.name, child1Category.id)} - className='category-mega-box__child-one mb-4 w-full h-8 flex justify-center line-clamp-2' + className='category-mega-box__child-one mb-4' > {child1Category.name} </Link> - <div className='flex flex-col gap-y-3 w-full'> - {child1Category.childs.map((child2Category, index) => ( - (index < 4) && ( - <Link - href={createSlug('/shop/category/', child2Category.name, child2Category.id)} - className='category-mega-box__child-two truncate' - key={child2Category.id} - > - {child2Category.name} - </Link> - ) + <div className='flex flex-col gap-y-3'> + {child1Category.childs.map((child2Category) => ( + <Link + href={createSlug( + '/shop/category/', + child2Category.name, + child2Category.id + )} + className='category-mega-box__child-two' + key={child2Category.id} + > + {child2Category.name} + </Link> ))} - {child1Category.childs.length > 5 && ( - <div className='flex hover:bg-gray_r-8/35 rounded-10'> - <Link - href={createSlug('/shop/category/', child1Category.name, child1Category.id)} - className='category-mega-box__child-one flex items-center gap-4 font-bold hover:ml-4' - > - <p className='mt-2 mb-0 text-danger-500 font-semibold'>Lihat Semua</p> - <ChevronRightIcon className='w-4 text-danger-500 font-bold' /> - </Link> - </div> - )} </div> </div> ))} </div> - <div className='category-mega-box__child-wrapper !w-[260px] !flex !flex-col !gap-4'> - <PopularBrand category={category} /> - <div className='flex w-60 h-20 object-cover'> - <Image src='https://erp.indoteknik.com/api/image/x_banner.banner/x_banner_image/397' alt='' width={275} height={4} /> - </div> - </div> </div> </div> ))} diff --git a/src/lib/category/components/PopularBrand.jsx b/src/lib/category/components/PopularBrand.jsx deleted file mode 100644 index 09c0f8a1..00000000 --- a/src/lib/category/components/PopularBrand.jsx +++ /dev/null @@ -1,83 +0,0 @@ -import odooApi from '@/core/api/odooApi' -import React, { useEffect, useState } from 'react' -import axios from 'axios'; -import { useQuery } from 'react-query' -import Link from '@/core/components/elements/Link/Link' -import { createSlug } from '@/core/utils/slug' -import Image from 'next/image' -import { ChevronRightIcon } from '@heroicons/react/24/outline' -import useProductSearch from '../../../lib/product/hooks/useProductSearch'; -import { SolrResponse } from "~/types/solr"; -import { fetchPromoItemsSolr } from '../api/popularProduct' - -const SOLR_HOST = process.env.SOLR_HOST - -const PopularBrand = ({ category }) => { - const [topBrands, setTopBrands] = useState([]); - - const fetchTopBrands = async () => { - try { - const items = await fetchPromoItemsSolr(`category_id_ids:(${category?.categoryDataIds?.join(' OR ')})`); - // console.log("id",items) - // Fungsi untuk deduplikasi dan mengambil 12 nama brand teratas - const getTop12UniqueBrands = (prod) => { - const brandSet = new Set(); - const topBrands = []; - - for (const product of prod) { - if (!brandSet.has(product.manufacture_name)) { - brandSet.add(product.manufacture_name); - topBrands.push({ name: product.manufacture_name, id: product.manufacture_id }); - }else{ - } - if (topBrands.length === 18) break; - } - return topBrands; - } - - // Menggunakan hasil pencarian produk - const products = items; - const top12UniqueBrands = getTop12UniqueBrands(products); - - // console.log('top12UniqueBrands', top12UniqueBrands); - setTopBrands(top12UniqueBrands); - } catch (error) { - console.error("Error fetching data from Solr", error); - throw error; - } - } - - useEffect(() => { - fetchTopBrands(); - }, [category]); - - return ( - <div className='flex flex-col'> - <div className='grid grid-cols-3 max-h-full w-full gap-2'> - {topBrands.map((brand, index) => ( - <div key={index} className='w-full flex items-center justify-center pb-2'> - <Link - href={createSlug('/shop/brands/', brand.name, brand.id)} - className='category-mega-box__child-one w-8 h-full flex items-center justify-center ' - > - <Image src={`https://erp.indoteknik.com/api/image/x_manufactures/x_logo_manufacture/${brand.id}` } alt={`${brand.name}`} width={104} height={44} objectFit='cover' /> - </Link> - </div> - ))} - </div> - {/* {topBrands.length > 8 && ( - <div className='flex hover:bg-gray_r-8/35 rounded-10'> - <Link - href={createSlug('/shop/category/', category.name, category.id)} - className='category-mega-box__child-one flex items-center gap-4 font-bold hover:ml-4' - > - <p className='mt-2 mb-0 text-danger-500 font-semibold'>Lihat Semua Brand</p> - <ChevronRightIcon className='w-4 text-danger-500 font-bold' /> - </Link> - </div> - )} */} - </div> - ) -} - -export default PopularBrand; diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx index 6deba693..09a791ee 100644 --- a/src/lib/checkout/components/Checkout.jsx +++ b/src/lib/checkout/components/Checkout.jsx @@ -1004,7 +1004,7 @@ const Checkout = () => { <div className='p-4 flex flex-col gap-y-4'> {!!products && snakecaseKeys(products).map((item, index) => ( - <CartItem key={index} item={item} editable={false} selfPicking={selectedExpedisi === '1,32' ? true : false}/> + <CartItem key={index} item={item} editable={false} /> ))} </div> @@ -1295,7 +1295,7 @@ const Checkout = () => { <div className='flex flex-col gap-y-8 border-t border-gray-300 pt-8'> {!!products && snakecaseKeys(products).map((item, index) => ( - <CartItem key={index} item={item} editable={false} selfPicking={selectedExpedisi === '1,32' ? true : false} /> + <CartItem key={index} item={item} editable={false} /> ))} </div> </div> diff --git a/src/lib/flashSale/components/FlashSale.jsx b/src/lib/flashSale/components/FlashSale.jsx index 5be6d4e3..85afb818 100644 --- a/src/lib/flashSale/components/FlashSale.jsx +++ b/src/lib/flashSale/components/FlashSale.jsx @@ -26,38 +26,41 @@ const FlashSale = () => { } return ( - flashSales?.length > 0 && ( - <div className='px-4 sm:px-0 grid grid-cols-1 gap-y-8'> - {flashSales.map((flashSale, index) => ( - <div key={index}> - <div className='flex gap-x-3 mb-4 justify-between sm:justify-start'> - <div className='font-medium sm:text-h-lg mt-1.5'> - {flashSale.name} + <div className='sm:mt-4'> + {flashSales?.length > 0 && ( + <div className='px-4 sm:px-0 grid grid-cols-1 gap-y-8 sm:mt-4'> + {flashSales.map((flashSale, index) => ( + <div key={index}> + <div className='flex gap-x-3 mb-4 justify-between sm:justify-start'> + <div className='font-medium sm:text-h-lg mt-1.5'> + {flashSale.name} + </div> + <CountDown initialTime={flashSale.duration} /> + </div> + + <div className='relative'> + <Image + src={flashSale.banner} + alt={flashSale.name} + width={1080} + height={192} + className='w-full rounded mb-4 hidden sm:block' + /> + <Image + src={flashSale.bannerMobile} + alt={flashSale.name} + width={256} + height={48} + className='w-full rounded mb-4 block sm:hidden' + /> + <FlashSaleProduct flashSaleId={flashSale.pricelistId} /> </div> - <CountDown initialTime={flashSale.duration} /> - </div> - - <div className='relative'> - <Image - src={flashSale.banner} - alt={flashSale.name} - width={1080} - height={192} - className='w-full rounded mb-4 hidden sm:block' - /> - <Image - src={flashSale.bannerMobile} - alt={flashSale.name} - width={256} - height={48} - className='w-full rounded mb-4 block sm:hidden' - /> - <FlashSaleProduct flashSaleId={flashSale.pricelistId} /> </div> - </div> - ))} - </div> - ) + ))} + </div> + )} + + </div> ); }; diff --git a/src/lib/flashSale/components/FlashSaleNonDisplay.jsx b/src/lib/flashSale/components/FlashSaleNonDisplay.jsx index 0068c98d..6e379500 100644 --- a/src/lib/flashSale/components/FlashSaleNonDisplay.jsx +++ b/src/lib/flashSale/components/FlashSaleNonDisplay.jsx @@ -13,21 +13,19 @@ import { useRouter } from 'next/router' const FlashSaleNonDisplay = () => { const [flashSales, setFlashSales] = useState(null); const [isLoading, setIsLoading] = useState(true); - const [pencarian, setPencarian] = useState(''); const router = useRouter() useEffect(() => { const loadFlashSales = async () => { const dataFlashSales = await flashSaleApi(); setFlashSales(dataFlashSales); - setPencarian(`fq=-flashsale_id_i:${dataFlashSales[0]?.pricelistId}&fq=flashsale_price_f:[1 TO *]&orderBy=flashsale-discount-desc`) setIsLoading(false); }; loadFlashSales(); }, []); const handleSubmit = () => { - router.push(`/shop/search?${pencarian}`) + router.push(`/shop/search?penawaran=${flashSales[0]?.pricelistId}`) } if (isLoading) { diff --git a/src/lib/home/api/CategoryPilihanApi.js b/src/lib/home/api/CategoryPilihanApi.js deleted file mode 100644 index 8a0b38d3..00000000 --- a/src/lib/home/api/CategoryPilihanApi.js +++ /dev/null @@ -1,8 +0,0 @@ -import odooApi from '@/core/api/odooApi' - -const categoryPilihanApi = async () => { - const dataCategoryPilihan = await odooApi('GET', '/api/v1/lob_homepage') - return dataCategoryPilihan -} - -export default categoryPilihanApi diff --git a/src/lib/home/api/categoryManagementApi.js b/src/lib/home/api/categoryManagementApi.js deleted file mode 100644 index b70d60ce..00000000 --- a/src/lib/home/api/categoryManagementApi.js +++ /dev/null @@ -1,8 +0,0 @@ -import odooApi from '@/core/api/odooApi' - -const categoryManagementApi = async () => { - const dataCategoryManagement = await odooApi('GET', '/api/v1/categories_management') - return dataCategoryManagement -} - -export default categoryManagementApi diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx deleted file mode 100644 index 0cc43d91..00000000 --- a/src/lib/home/components/CategoryDynamic.jsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import useCategoryManagement from '../hooks/useCategoryManagement'; -import NextImage from 'next/image'; -import Link from "next/link"; -import { createSlug } from '@/core/utils/slug'; -import odooApi from '@/core/api/odooApi'; -import { Skeleton} from '@chakra-ui/react' - -const CategoryDynamic = () => { - const { categoryManagement } = useCategoryManagement(); - const [categoryData, setCategoryData] = useState({}); - const [subCategoryData, setSubCategoryData] = useState({}); - - useEffect(() => { - const fetchCategoryData = async () => { - if (categoryManagement && categoryManagement.data) { - const updatedCategoryData = {}; - const updatedSubCategoryData = {}; - - for (const category of categoryManagement.data) { - const countLevel1 = await odooApi('GET', `/api/v1/category/numFound?parent_id=${category.categoryIdI}`); - - updatedCategoryData[category.categoryIdI] = countLevel1?.numFound; - - for (const subCategory of countLevel1.children) { - updatedSubCategoryData[subCategory.id] = subCategory.numFound; - } - } - - setCategoryData(updatedCategoryData); - setSubCategoryData(updatedSubCategoryData); - } - }; - - fetchCategoryData(); - }, [categoryManagement.isLoading]); - - return ( - <div> - {categoryManagement && categoryManagement.data?.map((category) => { - const countLevel1 = categoryData[category.categoryIdI] || 0; - - return ( - <Skeleton key={category.id} isLoaded={categoryManagement}> - <div key={category.id}> - <div className='bagian-judul flex flex-row justify-start items-center gap-3 mb-4 mt-4'> - <div className='font-semibold sm:text-h-lg mr-2'>{category.name}</div> - <Skeleton isLoaded={countLevel1 !=0}> - <p className={`text-gray_r-10 text-sm`}>{countLevel1} Produk tersedia</p> - </Skeleton> - <Link href={createSlug('/shop/category/', category?.name, category?.categoryIdI)} className="!text-red-500 font-semibold">Lihat Semua</Link> - </div> - <div className='grid grid-cols-3 gap-2'> - {category.categories.map((subCategory) => { - const countLevel2 = subCategoryData[subCategory.idLevel2] || 0; - - return ( - <div key={subCategory.id} className='border rounded justify-start items-start'> - <div className='p-3'> - <div className='flex flex-row border rounded mb-2 justify-start items-center'> - <NextImage - src={subCategory.image ? subCategory.image : "/images/noimage.jpeg"} - alt={subCategory.name} - width={90} - height={30} - className='object-fit' - /> - <div className='bagian-judul flex flex-col justify-center items-start gap-2 ml-2'> - <div className='font-semibold text-lg mr-2'>{subCategory.name}</div> - <Skeleton isLoaded={countLevel2 != 0}> - <p className={`text-gray_r-10 text-sm`}> - {countLevel2} Produk tersedia - </p> - </Skeleton> - <Link href={createSlug('/shop/category/', subCategory?.name, subCategory?.idLevel2)} className="!text-red-500 font-semibold">Lihat Semua</Link> - </div> - </div> - <div className='grid grid-cols-2 gap-2 overflow-y-auto max-h-[240px]'> - {subCategory.childFrontendIdI.map((childCategory) => ( - <div key={childCategory.id}> - <Link href={createSlug('/shop/category/', childCategory?.name, childCategory?.idLevel3)} className="flex flex-row gap-2 border rounded group hover:border-red-500"> - <NextImage - src={childCategory.image ? childCategory.image : "/images/noimage.jpeg"} - alt={childCategory.name} - width={40} - height={40} - /> - <div className='bagian-judul flex flex-col justify-center items-center gap-2 break-words line-clamp-2 group-hover:text-red-500'> - <div className='font-semibold line-clamp-2 group-hover:text-red-500 text-sm mr-2'>{childCategory.name}</div> - </div> - </Link> - </div> - ))} - </div> - </div> - </div> - ); - })} - </div> - </div> - </Skeleton> - ); - })} - </div> - ); -}; - -export default CategoryDynamic; diff --git a/src/lib/home/components/CategoryDynamicMobile.jsx b/src/lib/home/components/CategoryDynamicMobile.jsx deleted file mode 100644 index c1433a2d..00000000 --- a/src/lib/home/components/CategoryDynamicMobile.jsx +++ /dev/null @@ -1,101 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import useCategoryManagement from '../hooks/useCategoryManagement'; -import NextImage from 'next/image'; -import Link from "next/link"; -import { createSlug } from '@/core/utils/slug'; -import { Swiper, SwiperSlide } from 'swiper/react'; -import 'swiper/css'; - -const CategoryDynamicMobile = () => { - const { categoryManagement } = useCategoryManagement() - const [selectedCategory, setSelectedCategory] = useState({}); - - useEffect(() => { - const loadPromo = async () => { - try { - if (categoryManagement.data?.length > 0) { - const initialSelections = categoryManagement.data.reduce((acc, category) => { - if (category.categories.length > 0) { - acc[category.id] = category.categories[0].idLevel2; - } - return acc; - }, {}); - setSelectedCategory(initialSelections); - } - } catch (loadError) { - // console.error("Error loading promo items:", loadError); - } - }; - - loadPromo(); - }, [categoryManagement.data]); - - const handleCategoryLevel2Click = (categoryIdI, idLevel2) => { - setSelectedCategory(prev => ({ - ...prev, - [categoryIdI]: idLevel2 - })); - }; - - return ( - <div className='p-4'> - {categoryManagement.data && categoryManagement.data.map((category) => ( - <div key={category.id}> - <div className='bagian-judul flex flex-row justify-between items-center gap-3 mb-4 mt-4'> - <div className='font-semibold sm:text-h-sm mr-2'>{category.name}</div> - <Link href={createSlug('/shop/category/', category?.name, category?.categoryIdI)} className="!text-red-500 font-semibold text-sm">Lihat Semua</Link> - </div> - <Swiper slidesPerView={2.3} spaceBetween={10}> - {category.categories.map((index) => ( - <SwiperSlide key={index.id}> - <div - onClick={() => handleCategoryLevel2Click(category.id, index?.idLevel2)} - className={`border flex justify-start items-center max-w-48 max-h-16 rounded ${selectedCategory[category.id] === index?.idLevel2 ? 'bg-red-50 border-red-500 text-red-500' : 'border-gray-200 text-gray-900'}`} - > - <div className='p-1 flex justify-start items-center'> - <div className='flex flex-row justify-center items-center'> - <NextImage - src={index.image ? index.image : "/images/noimage.jpeg"} - alt={index.name} - width={30} - height={30} - className='object-' - /> - <div className='bagian-judul flex flex-col justify-center items-start gap-1 ml-2'> - <div className='font-semibold text-[10px] line-clamp-1'>{index.name}</div> - <p className='text-gray_r-10 text-[10px]'>999 rb+ Produk</p> - </div> - </div> - </div> - </div> - </SwiperSlide> - ))} - </Swiper> - <div className='p-3 mt-2 border'> - <div className='grid grid-cols-2 gap-2 overflow-y-auto max-h-[240px]'> - {category.categories.map((index) => ( - selectedCategory[category.id] === index?.idLevel2 && index.childFrontendIdI.map((x) => ( - <div key={x.id}> - <Link href={createSlug('/shop/category/', x?.name, x?.idLevel3)} className="flex flex-row gap-1 border rounded group hover:border-red-500"> - <NextImage - src={x.image ? x.image : "/images/noimage.jpeg"} - alt={x.name} - width={40} - height={40} - /> - <div className='bagian-judul flex flex-col justify-center items-start gap-1 break-words line-clamp-2 group-hover:text-red-500'> - <div className='font-semibold line-clamp-2 group-hover:text-red-500 text-[10px]'>{x.name}</div> - </div> - </Link> - </div> - )) - ))} - </div> - </div> - </div> - ))} - </div> - ); -}; - -export default CategoryDynamicMobile; diff --git a/src/lib/home/components/CategoryPilihan.jsx b/src/lib/home/components/CategoryPilihan.jsx deleted file mode 100644 index 6568621c..00000000 --- a/src/lib/home/components/CategoryPilihan.jsx +++ /dev/null @@ -1,120 +0,0 @@ -import Image from 'next/image' -import useCategoryHome from '../hooks/useCategoryHome' -import Link from '@/core/components/elements/Link/Link' -import { createSlug } from '@/core/utils/slug' -import { useEffect, useState } from 'react'; -import { bannerApi } from '../../../api/bannerApi'; -const { useQuery } = require('react-query') -import { HeroBannerSkeleton } from '../../../components/skeleton/BannerSkeleton'; -import useCategoryPilihan from '../hooks/useCategoryPilihan'; -import useDevice from '@/core/hooks/useDevice' -import { Swiper, SwiperSlide } from 'swiper/react'; -import 'swiper/css'; - -const CategoryPilihan = ({ id, categories }) => { - const { isDesktop, isMobile } = useDevice() - const { categoryPilihan } = useCategoryPilihan(); - const heroBanner = useQuery('categoryPilihan', bannerApi({ type: 'banner-category-list' })); - return ( - <section> - {isDesktop && ( - <div> - <div className='flex flex-row items-center mb-4'> - <div className='font-semibold sm:text-h-lg mr-2'>LOB Kategori Pilihan</div> - <p className='text-gray_r-10 text-sm'>200 Rb+ Produk Unggulan & 800+ Brand Rekomendasi tersedia!</p> - </div> - {heroBanner.data && - heroBanner.data?.length > 0 && ( - <div className='flex w-full h-full justify-center mb-4 bg-cover bg-center'> - <Link key={heroBanner.data[0].id} href={heroBanner.data[0].url}> - <Image - width={1260} - height={170} - quality={100} - src={heroBanner.data[0].image} - alt={heroBanner.data[0].name} - className='h-full object-cover w-full' - /> - </Link> - </div> - )} - <div className="group/item grid grid-cols-6 gap-y-2 w-full h-full col-span-2 "> - {categoryPilihan?.data?.map((category) => ( - <div key={category.id} className="KartuInti h-48 w-60 max-w-sm lg:max-w-full flex flex-col border-[1px] border-gray-200 relative group"> - <div className='KartuB absolute h-48 w-60 inset-0 flex items-center justify-center '> - <div className="group/edit flex items-center justify-end h-48 w-60 flex-col group-hover/item:visible"> - <div className=' h-36 flex justify-end items-end'> - <Image className='group-hover:scale-105 transition-transform duration-300 ' src={category?.image? category?.image : '/images/noimage.jpeg'} width={120} height={120} alt={category?.name} /> - </div> - <h2 className="text-gray-700 content-center h-12 border-t-[1px] px-1 w-60 border-gray-200 font-normal text-sm text-center">{category?.industries}</h2> - </div> - </div> - <div className='KartuA relative inset-0 flex h-36 w-60 items-center justify-center opacity-0 group-hover:opacity-75 group-hover:bg-[#E20613] transition-opacity '> - <Link - href={createSlug('/shop/lob/', category?.industries, category?.id)} - className='category-mega-box__parent text-white rounded-lg' - > - Lihat semua - </Link> - </div> - </div> - ))} - </div> - </div> - )} - {isMobile && ( - <div className='p-4'> - <div className='flex flex-row items-center mb-4'> - <div className='font-semibold sm:text-h-md mr-2'>LOB Kategori Pilihan</div> - {/* <p className='text-gray_r-10 text-sm'>200 Rb+ Produk Unggulan & 800+ Brand Rekomendasi tersedia!</p> */} - </div> - <div className='flex'> - {heroBanner.data && - heroBanner.data?.length > 0 && ( - <div className=' object-fill '> - <Link key={heroBanner.data[0].id} href={heroBanner.data[0].url}> - <Image - width={439} - height={150} - quality={100} - src={heroBanner.data[0].image} - alt={heroBanner.data[0].name} - className='object-cover' - /> - </Link> - </div> - )} - </div> - <Swiper slidesPerView={2.1} spaceBetween={10}> - {categoryPilihan?.data?.map((category) => ( - <SwiperSlide key={category.id}> - <div key={category.id} className="KartuInti mt-2 h-48 w-48 max-w-sm lg:max-w-full flex flex-col border-[1px] border-gray-200 relative group"> - <div className='KartuB absolute h-48 w-48 inset-0 flex items-center justify-center '> - <div className="group/edit flex items-center justify-end h-48 w-48 flex-col group-hover/item:visible"> - <div className=' h-36 flex justify-end items-end'> - <Image className='group-hover:scale-105 transition-transform duration-300 ' src={category?.image? category?.image : '/images/noimage.jpeg'} width={120} height={120} alt={category?.name} /> - </div> - <h2 className="text-gray-700 content-center h-12 border-t-[1px] px-1 w-48 border-gray-200 font-normal text-sm text-center">{category?.industries}</h2> - </div> - </div> - <div className='KartuA relative inset-0 flex h-36 w-48 items-center justify-center opacity-0 group-hover:opacity-75 group-hover:bg-[#E20613] transition-opacity '> - <Link - href={createSlug('/shop/lob/', category?.industries, category?.id)} - className='category-mega-box__parent text-white rounded-lg' - > - Lihat semua - </Link> - </div> - </div> - </SwiperSlide> - ))} - - </Swiper> - - </div> - )} - </section> - ) -} - -export default CategoryPilihan diff --git a/src/lib/home/components/PreferredBrand.jsx b/src/lib/home/components/PreferredBrand.jsx index ae12505d..6b64a444 100644 --- a/src/lib/home/components/PreferredBrand.jsx +++ b/src/lib/home/components/PreferredBrand.jsx @@ -1,5 +1,4 @@ import { Swiper, SwiperSlide } from 'swiper/react' -import { Navigation, Pagination, Autoplay } from 'swiper'; import { useCallback, useEffect, useState } from 'react' import usePreferredBrand from '../hooks/usePreferredBrand' import PreferredBrandSkeleton from './Skeleton/PreferredBrandSkeleton' @@ -39,23 +38,7 @@ const PreferredBrand = () => { const { preferredBrands } = usePreferredBrand(query) const { isMobile, isDesktop } = useDevice() - const swiperBanner = { - modules:[Navigation, Pagination, Autoplay], - autoplay: { - delay: 4000, - disableOnInteraction: false - }, - loop: true, - className: 'h-[70px] md:h-[100px] w-full', - slidesPerView: isMobile ? 4 : 8, - spaceBetween: isMobile ? 12 : 0, - pagination: { - dynamicBullets: true, - dynamicMainBullets: isMobile ? 6 : 8, - clickable: true, - } - } - const preferredBrandsData = manufactures ? manufactures.slice(0, 20) : [] + return ( <div className='px-4 sm:px-0'> <div className='flex justify-between items-center mb-4'> @@ -65,21 +48,24 @@ const PreferredBrand = () => { Lihat Semua </Link> )} - </div> - <div className='border rounded border-gray_r-6'> - {manufactures.isLoading && <PreferredBrandSkeleton />} - {!manufactures.isLoading && ( - <Swiper {...swiperBanner}> - {preferredBrandsData.map((manufacture) => ( - <SwiperSlide key={manufacture.id}> - <BrandCard brand={manufacture} /> - </SwiperSlide> - ))} - </Swiper> + {isMobile && ( + <Link href='/shop/brands' className='!text-red-500 font-semibold sm:text-h-sm'> + Lihat Semua + </Link> )} </div> + {manufactures.isLoading && <PreferredBrandSkeleton />} + {!manufactures.isLoading && ( + <Swiper slidesPerView={isMobile ? 3.5 : 7.5} spaceBetween={isMobile ? 12 : 24} freeMode> + {manufactures.map((manufacture) => ( + <SwiperSlide key={manufacture.id}> + <BrandCard brand={manufacture} /> + </SwiperSlide> + ))} + </Swiper> + )} </div> ) } -export default PreferredBrand
\ No newline at end of file +export default PreferredBrand diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx index c2f76069..99258d94 100644 --- a/src/lib/home/components/PromotionProgram.jsx +++ b/src/lib/home/components/PromotionProgram.jsx @@ -3,16 +3,11 @@ import Image from 'next/image' import { bannerApi } from '@/api/bannerApi'; import useDevice from '@/core/hooks/useDevice' import { Swiper, SwiperSlide } from 'swiper/react'; -import BannerPromoSkeleton from '../components/Skeleton/BannerPromoSkeleton'; const { useQuery } = require('react-query') const BannerSection = () => { const promotionProgram = useQuery('promotionProgram', bannerApi({ type: 'banner-promotion' })); const { isMobile, isDesktop } = useDevice() - if (promotionProgram.isLoading) { - return <BannerPromoSkeleton />; - } - return ( <div className='px-4 sm:px-0'> <div className='flex justify-between items-center mb-4 '> diff --git a/src/lib/home/components/Skeleton/BannerPromoSkeleton.jsx b/src/lib/home/components/Skeleton/BannerPromoSkeleton.jsx deleted file mode 100644 index c5f39f19..00000000 --- a/src/lib/home/components/Skeleton/BannerPromoSkeleton.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import useDevice from '@/core/hooks/useDevice' -import Skeleton from 'react-loading-skeleton' - -const BannerPromoSkeleton = () => { - const { isDesktop } = useDevice() - - return ( - <div className='grid grid-cols-1 md:grid-cols-3 gap-x-3'> - {Array.from({ length: isDesktop ? 3 : 1.2 }, (_, index) => ( - <Skeleton count={1} height={isDesktop ? 60 : 36} key={index} /> - ))} - </div> - ) -} - -export default BannerPromoSkeleton diff --git a/src/lib/home/hooks/useCategoryManagement.js b/src/lib/home/hooks/useCategoryManagement.js deleted file mode 100644 index c1dda585..00000000 --- a/src/lib/home/hooks/useCategoryManagement.js +++ /dev/null @@ -1,13 +0,0 @@ -import categoryManagementApi from '../api/categoryManagementApi' -import { useQuery } from 'react-query' - -const useCategoryManagement = () => { - const fetchCategoryManagement = async () => await categoryManagementApi() - const { isLoading, data } = useQuery('categoryManagementApi', fetchCategoryManagement) - - return { - categoryManagement: { data, isLoading } - } -} - -export default useCategoryManagement
\ No newline at end of file diff --git a/src/lib/home/hooks/useCategoryPilihan.js b/src/lib/home/hooks/useCategoryPilihan.js deleted file mode 100644 index 12a86f7e..00000000 --- a/src/lib/home/hooks/useCategoryPilihan.js +++ /dev/null @@ -1,13 +0,0 @@ -import categoryPilihanApi from '../api/CategoryPilihanApi' -import { useQuery } from 'react-query' - -const useCategoryPilihan = () => { - const fetchCategoryPilihan = async () => await categoryPilihanApi() - const { isLoading, data } = useQuery('categoryPilihanApi', fetchCategoryPilihan) - - return { - categoryPilihan: { data, isLoading } - } -} - -export default useCategoryPilihan
\ No newline at end of file diff --git a/src/lib/lob/components/Breadcrumb.jsx b/src/lib/lob/components/Breadcrumb.jsx deleted file mode 100644 index 5722fd39..00000000 --- a/src/lib/lob/components/Breadcrumb.jsx +++ /dev/null @@ -1,55 +0,0 @@ -import odooApi from '@/core/api/odooApi' -import { createSlug } from '@/core/utils/slug' -import { - Breadcrumb as ChakraBreadcrumb, - BreadcrumbItem, - BreadcrumbLink, - Skeleton -} from '@chakra-ui/react' -import Link from 'next/link' -import React from 'react' -import { useQuery } from 'react-query' - -/** - * Render a breadcrumb component. - * - * @param {object} categoryId - The ID of the category. - * @return {JSX.Element} The breadcrumb component. - */ -const Breadcrumb = ({ categoryId }) => { - const breadcrumbs = useQuery( - `lob-breadcrumbs/${categoryId}`, - async () => await odooApi('GET', `/api/v1/lob_homepage/${categoryId}/category_id`) - ) - return ( - <div className='container mx-auto py-4 md:py-6'> - <Skeleton isLoaded={!breadcrumbs.isLoading} className='w-2/3'> - <ChakraBreadcrumb> - <BreadcrumbItem> - <BreadcrumbLink as={Link} href='/' className='!text-danger-500 whitespace-nowrap'> - Home - </BreadcrumbLink> - </BreadcrumbItem> - - {breadcrumbs?.data?.map((category, index) => ( - <BreadcrumbItem key={index} isCurrentPage={index === breadcrumbs.data.length - 1}> - {index === breadcrumbs.data.length - 1 ? ( - <BreadcrumbLink className='whitespace-nowrap'>{category.industries}</BreadcrumbLink> - ) : ( - <BreadcrumbLink - as={Link} - href={createSlug('/shop/lob/', category.industries, category.id)} - className='!text-danger-500 whitespace-nowrap' - > - {category.industries} - </BreadcrumbLink> - )} - </BreadcrumbItem> - ))} - </ChakraBreadcrumb> - </Skeleton> - </div> - ) -} - -export default Breadcrumb diff --git a/src/lib/product/components/CategorySection.jsx b/src/lib/product/components/CategorySection.jsx deleted file mode 100644 index 2af3db10..00000000 --- a/src/lib/product/components/CategorySection.jsx +++ /dev/null @@ -1,104 +0,0 @@ -import Image from "next/image"; -import Link from 'next/link'; -import { createSlug } from '@/core/utils/slug'; -import useDevice from '@/core/hooks/useDevice'; -import { Swiper, SwiperSlide } from 'swiper/react'; -import 'swiper/css'; -import { useQuery } from 'react-query'; -import { useRouter } from 'next/router'; -import { - ChevronDownIcon, - ChevronUpIcon, // Import ChevronUpIcon for toggling - DocumentCheckIcon, - HeartIcon, -} from '@heroicons/react/24/outline'; -import { useState } from 'react'; // Import useState -import { getIdFromSlug } from '@/core/utils/slug' - -const CategorySection = ({ categories }) => { - const { isDesktop, isMobile } = useDevice(); - const [isOpenCategory, setIsOpenCategory] = useState(false); // State to manage category visibility - - const handleToggleCategories = () => { - setIsOpenCategory(!isOpenCategory); - }; - - - const displayedCategories = isOpenCategory ? categories : categories.slice(0, 10); - - return ( - <section> - {isDesktop && ( - <div className="group/item grid grid-cols-5 gap-y-2 gap-x-2 w-full h-full col-span-2 "> - {displayedCategories.map((category) => ( - <Link href={createSlug('/shop/category/', category?.name, category?.id)} key={category?.id} passHref> - <div className="group transition-colors duration-300 "> - <div className="KartuInti h-12 w-26 max-w-sm lg:max-w-full flex flex-col border-[2px] border-gray-200 group-hover:border-red-400 rounded relative "> - <div className="flex items-center justify-start h-full px-1 flex-row "> - <Image className="h-full" src={category?.image1920 ? category?.image1920 : '/images/noimage.jpeg'} width={56} height={48} alt={category?.name} /> - <h2 className="text-gray-700 group-hover:text-[#E20613] line-clamp-2 content-center h-fit w-60 px-1 font-semibold text-sm text-start">{category?.name}</h2> - </div> - </div> - </div> - </Link> - ))} - </div> - )} - {isDesktop && categories.length > 10 && ( - <div className="w-full flex justify-center mt-4"> - <button - onClick={handleToggleCategories} - className="flex justify-end mt-4 text-red-500 font-bold px-4 py-2 rounded" - > - {isOpenCategory ? 'Sembunyikan' : 'Lihat semua'} - {isOpenCategory ? ( - <ChevronUpIcon className="ml-auto w-5 font-bold" /> - ) : ( - <ChevronDownIcon className="ml-auto w-5 font-bold" /> - )} - </button> - </div> - )} - - {isMobile && ( - <div className="py-4"> - <Swiper slidesPerView={2.3} spaceBetween={10}> - {displayedCategories.map((category) => ( - <SwiperSlide key={category?.id}> - <Link href={createSlug('/shop/category/', category?.name, category?.id)} passHref> - <div className="group transition-colors duration-300"> - <div className="KartuInti min-h-16 max-h-16 w-26 max-w-sm lg:max-w-full flex flex-col border-[2px] border-gray-200 group-hover:bg-red-200 group-hover:border-red-400 rounded relative"> - <div className="flex items-center justify-center h-full px-1 flex-row"> - <Image - src={category?.image1920 ? category?.image1920 : '/images/noimage.jpeg'} - width={56} - height={48} - alt={category?.name} - /> - <h2 className="text-gray-700 group-hover:text-[#E20613] line-clamp-2 content-center h-fit w-60 px-1 font-semibold text-sm text-start"> - {category?.name} - </h2> - </div> - </div> - </div> - </Link> - </SwiperSlide> - ))} - </Swiper> - {categories.length > 10 && ( - <div className="w-full flex justify-end mt-4"> - <button - onClick={handleToggleCategories} - className="flex justify-end mt-4 bg-red-500 text-white text-sm px-4 py-2 rounded" - > - {isOpenCategory ? 'Sembunyikan Semua' : 'Lihat Semua'} - </button> - </div> - )} - </div> - )} - </section> - ) -} - -export default CategorySection diff --git a/src/lib/product/components/LobSectionCategory.jsx b/src/lib/product/components/LobSectionCategory.jsx deleted file mode 100644 index 03d6e8c0..00000000 --- a/src/lib/product/components/LobSectionCategory.jsx +++ /dev/null @@ -1,81 +0,0 @@ -import Image from "next/image"; -import Link from 'next/link'; -import { createSlug } from '@/core/utils/slug'; -import useDevice from '@/core/hooks/useDevice'; -import { Swiper, SwiperSlide } from 'swiper/react'; -import 'swiper/css'; -import { useQuery } from 'react-query'; -import { useRouter } from 'next/router'; -import { - ChevronDownIcon, - ChevronUpIcon, // Import ChevronUpIcon for toggling - DocumentCheckIcon, - HeartIcon, -} from '@heroicons/react/24/outline'; -import { useState } from 'react'; // Import useState -import { getIdFromSlug } from '@/core/utils/slug' - -const LobSectionCategory = ({ categories }) => { - const { isDesktop, isMobile } = useDevice(); - const [isOpenCategory, setIsOpenCategory] = useState(false); // State to manage category visibility - - const handleToggleCategories = () => { - setIsOpenCategory(!isOpenCategory); - }; - - const displayedCategories = categories[0]?.categoryIds; - - return ( - <section> - {isDesktop && ( - <div className="group/item grid grid-flow-col gap-y-2 gap-x-4 w-full h-full"> - {displayedCategories?.map((category) => ( - <Link - href={createSlug('/shop/category/', category?.name, category?.id)} - key={category?.id} - passHref - className="block hover:scale-105 transition-transform duration-300 bg-cover bg-center h-[144px]" - style={{ - backgroundImage: `url('${category?.image ? category?.image : 'https://erp.indoteknik.com/web/image?model=x_banner.banner&id=5&field=x_banner_image&unique=09202023100557'}')`, - }} - > - </Link> - ))} - </div> - )} - - {isMobile && ( - <div className="py-4"> - <Swiper slidesPerView={1.2} spaceBetween={10}> - {displayedCategories?.map((category) => ( - <SwiperSlide key={category?.id}> - <Link - href={createSlug('/shop/category/', category?.name, category?.id)} - key={category?.id} - passHref - className="block bg-cover bg-center h-[144px]" - style={{ - backgroundImage: `url('${category?.image ? category?.image : 'https://erp.indoteknik.com/web/image?model=x_banner.banner&id=5&field=x_banner_image&unique=09202023100557'}')`, - }} - > - </Link> - </SwiperSlide> - ))} - </Swiper> - {categories.length > 10 && ( - <div className="w-full flex justify-end mt-4"> - <button - onClick={handleToggleCategories} - className="flex justify-end mt-4 bg-red-500 text-white text-sm px-4 py-2 rounded" - > - {isOpenCategory ? 'Sembunyikan Semua' : 'Lihat Semua'} - </button> - </div> - )} - </div> - )} - </section> - ) -} - -export default LobSectionCategory diff --git a/src/lib/product/components/Product/ProductDesktopVariant.jsx b/src/lib/product/components/Product/ProductDesktopVariant.jsx index c8a5a205..09b30a44 100644 --- a/src/lib/product/components/Product/ProductDesktopVariant.jsx +++ b/src/lib/product/components/Product/ProductDesktopVariant.jsx @@ -6,11 +6,6 @@ import { useRouter } from 'next/router'; import { useCallback, useEffect, useRef, useState } from 'react'; import { toast } from 'react-hot-toast'; import LazyLoad from 'react-lazy-load'; -import { Button } from '@chakra-ui/react' -import { MessageCircleIcon, Share2Icon } from 'lucide-react' -import AddToWishlist from '../../../../../src-migrate/modules/product-detail/components/AddToWishlist' -import { RWebShare } from 'react-web-share' -// import Link from 'next/link' import { useProductCartContext } from '@/contexts/ProductCartContext'; import odooApi from '@/core/api/odooApi'; @@ -23,14 +18,11 @@ import { updateItemCart } from '@/core/utils/cart'; import currencyFormat from '@/core/utils/currencyFormat'; import { createSlug } from '@/core/utils/slug'; import whatsappUrl from '@/core/utils/whatsappUrl'; -import Breadcrumb from '../../../../../src-migrate/modules/product-detail/components/Breadcrumb'; import productSimilarApi from '../../api/productSimilarApi'; import ProductCard from '../ProductCard'; import ProductSimilar from '../ProductSimilar'; -const SELF_HOST = process.env.NEXT_PUBLIC_SELF_HOST - const ProductDesktopVariant = ({ product, wishlist, @@ -40,7 +32,7 @@ const ProductDesktopVariant = ({ const router = useRouter(); const auth = useAuth(); const { slug } = router.query; - const [ askAdminUrl, setAskAdminUrl ] = useState() + const [lowestPrice, setLowestPrice] = useState(null); const [addCartAlert, setAddCartAlert] = useState(false); @@ -61,20 +53,6 @@ const ProductDesktopVariant = ({ setLowestPrice(lowest); }, [getLowestPrice]); - useEffect(() => { - const createdAskUrl = whatsappUrl({ - template: 'product', - payload: { - manufacture: product.manufacture.name, - productName: product.name, - url: process.env.NEXT_PUBLIC_SELF_HOST + router.asPath - }, - fallbackUrl: router.asPath - }) - - setAskAdminUrl(createdAskUrl) - }, [router.asPath, product.manufacture.name, product.name, setAskAdminUrl]) - const [informationTab, setInformationTab] = useState( informationTabOptions[0].value ); @@ -137,25 +115,20 @@ const ProductDesktopVariant = ({ }); } }; - const regex = /\b(?![A-Z\s]+\b)[A-Za-z\s]+\b/g; - const matches = product?.parent?.name?.match(regex); - const extractedName = matches ? matches.join(' ').trim() : ''; - console.log("extractedName",extractedName) const productSimilarQuery = [ product?.name, `fq=-product_id_i:${product.id}`, `fq=-manufacture_id_i:${product.manufacture?.id || 0}`, ].join('&'); - + const [productSimilarInBrand, setProductSimilarInBrand] = useState(null); - + useEffect(() => { const loadProductSimilarInBrand = async () => { const productSimilarQuery = [ product?.name, `fq=-product_id_i:${product.id}`, - `fq=display_name_s:${extractedName}`, ].join('&'); const dataProductSimilar = await productSimilarApi({ query: productSimilarQuery, @@ -181,7 +154,6 @@ const ProductDesktopVariant = ({ return ( <DesktopView> <div className='container mx-auto pt-10'> - <Breadcrumb id={product.id} name={product.parent.name} /> <div className='flex'> <div className='w-full flex flex-wrap'> <div className='w-5/12'> @@ -291,42 +263,9 @@ const ProductDesktopVariant = ({ </div> </div> </div> - <div className='h-6' /> - <div className="flex gap-x-5"> - <Button - as={Link} - href={askAdminUrl} - variant='link' - target='_blank' - colorScheme='gray' - leftIcon={<MessageCircleIcon size={18} />} - > - Ask Admin - </Button> - - <AddToWishlist productId={product.id} /> - - <RWebShare - data={{ - text: 'Check out this product', - title: `${product.name} - Indoteknik.com`, - url: SELF_HOST + router.asPath - }} - > - <Button - variant='link' - colorScheme='gray' - leftIcon={<Share2Icon size={18} />} - > - Share - </Button> - </RWebShare> - </div> </div> - - - <div className='p-4 md:p-6 md:bg-gray-50 rounded-xl w-[99%]'> + <div className='p-4 md:p-6 md:bg-gray-50 rounded-xl'> <h2 className='text-h-md md:text-h-lg font-medium'>Informasi Produk</h2> <div className='h-4' /> <div @@ -340,7 +279,7 @@ const ProductDesktopVariant = ({ /> </div> </div> - <div className='w-[35%]'> + <div className='w-[25%]'> {product?.isFlashsale > 0 && product?.price?.discountPercentage > 0 ? ( <> @@ -420,11 +359,24 @@ const ProductDesktopVariant = ({ Beli </button> </div> + <div className='flex mt-4'> + <button + className='flex items-center gap-x-1' + onClick={toggleWishlist} + > + {wishlist.data?.productTotal > 0 ? ( + <HeartIcon className='w-6 fill-danger-500 text-danger-500' /> + ) : ( + <HeartIcon className='w-6' /> + )} + Wishlist + </button> + </div> <div className='border border-gray_r-6 overflow-auto mt-4'> <div className='font-medium text-center p-4 bg-gray_r-1 border-b border-gray_r-6 sticky top-0 z-10'> Produk Serupa </div> - <div className='h-full divide-y divide-gray_r-6 max-h-[500px]'> + <div className='h-full divide-y divide-gray_r-6 max-h-96'> {productSimilarInBrand && productSimilarInBrand?.map((product) => ( <div className='py-2' key={product.id}> diff --git a/src/lib/product/components/Product/ProductMobileVariant.jsx b/src/lib/product/components/Product/ProductMobileVariant.jsx index ce836d5b..af9e52bb 100644 --- a/src/lib/product/components/Product/ProductMobileVariant.jsx +++ b/src/lib/product/components/Product/ProductMobileVariant.jsx @@ -16,14 +16,8 @@ import currencyFormat from '@/core/utils/currencyFormat'; import { gtagAddToCart } from '@/core/utils/googleTag'; import { createSlug } from '@/core/utils/slug'; import whatsappUrl from '@/core/utils/whatsappUrl'; -import Breadcrumb from '../../../../../src-migrate/modules/product-detail/components/Breadcrumb'; -import { Button } from '@chakra-ui/react' -import { MessageCircleIcon, Share2Icon } from 'lucide-react' -import AddToWishlist from '../../../../../src-migrate/modules/product-detail/components/AddToWishlist' -import { RWebShare } from 'react-web-share' -import ProductSimilar from '../ProductSimilar'; -const SELF_HOST = process.env.NEXT_PUBLIC_SELF_HOST +import ProductSimilar from '../ProductSimilar'; const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { const router = useRouter(); @@ -34,7 +28,7 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { informationTabOptions[0].value ); const [addCartAlert, setAddCartAlert] = useState(false); - const [ askAdminUrl, setAskAdminUrl ] = useState() + const [isLoadingSLA, setIsLoadingSLA] = useState(true); const getLowestPrice = () => { @@ -66,20 +60,6 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { } }, [selectedVariant, product]); - useEffect(() => { - const createdAskUrl = whatsappUrl({ - template: 'product', - payload: { - manufacture: product.manufacture.name, - productName: product.name, - url: process.env.NEXT_PUBLIC_SELF_HOST + router.asPath - }, - fallbackUrl: router.asPath - }) - - setAskAdminUrl(createdAskUrl) - }, [router.asPath, product.manufacture.name, product.name, setAskAdminUrl]) - const validAction = () => { let isValid = true; if (!selectedVariant) { @@ -140,17 +120,14 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { return ( <MobileView> - <div className='p-4'> - <Breadcrumb id={product.id} name={product.name} /> - </div> <Image src={product.image + '?variant=True'} alt={product.name} - className='h-72 object-contain mt-4 object-center w-full border-b border-gray_r-4' + className='h-72 object-contain object-center w-full border-b border-gray_r-4' /> <div className='p-4'> - <div className='flex items-center mb-2'> + <div className='flex items-end mb-2'> {product.manufacture?.name ? ( <Link href={createSlug( @@ -164,45 +141,15 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { ) : ( <div>-</div> )} - <div className="ml-2 flex gap-x-5"> - <Button - as={Link} - href={askAdminUrl} - variant='link' - target='_blank' - colorScheme='gray' - leftIcon={<MessageCircleIcon size={18} />} - > - Ask Admin - </Button> - - <AddToWishlist productId={product.id} /> - - <RWebShare - data={{ - text: 'Check out this product', - title: `${product.name} - Indoteknik.com`, - url: SELF_HOST + router.asPath - }} - > - <Button - variant='link' - colorScheme='gray' - leftIcon={<Share2Icon size={18} />} - > - Share - </Button> - </RWebShare> - </div> - {/* <button type='button' className='ml-auto' onClick={toggleWishlist}> + <button type='button' className='ml-auto' onClick={toggleWishlist}> {wishlist.data?.productTotal > 0 ? ( <HeartIcon className='w-6 fill-danger-500 text-danger-500' /> ) : ( <HeartIcon className='w-6' /> )} - </button> */} + </button> </div> - <h1 className='font-medium text-h-lg leading-8 md:text-title-md md:leading-10 mb-3'>{activeVariant?.name}</h1> + <h1 className='leading-6 font-medium mb-3'>{activeVariant?.name}</h1> {activeVariant.isFlashSale && activeVariant?.price?.discountPercentage > 0 ? ( @@ -226,11 +173,11 @@ const ProductMobileVariant = ({ product, wishlist, toggleWishlist }) => { </div> </> ) : ( - <h3 className='font-medium text-danger-500 text-title-md mt-1'> + <h3 className='text-danger-500 font-semibold mt-1'> {activeVariant?.price?.price > 0 ? ( <> {currencyFormat(activeVariant?.price?.price)} - <div className='text-gray_r-9 text-base font-medium mt-1'> + <div className='text-gray_r-9 text-base font-normal mt-1'> Termasuk PPN:{' '} {currencyFormat( activeVariant?.price.price * process.env.NEXT_PUBLIC_PPN diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx index a1491c7f..35e2a665 100644 --- a/src/lib/product/components/ProductCard.jsx +++ b/src/lib/product/components/ProductCard.jsx @@ -146,20 +146,13 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { )} </Link> <div className='p-2 sm:p-3 pb-3 text-caption-2 sm:text-body-2 leading-5'> - <div className='flex justify-between '> - {product?.manufacture?.name ? ( - <Link href={URL.manufacture} className='mb-1 mt-1'> - {product.manufacture.name} - </Link> - ) : ( - <div>-</div> - )} - {product?.is_in_bu && ( - <div className=''> - <Image src='/images/PICKUP-NOW.png' alt='pickup now' width={90} height={12} /> - </div> - )} - </div> + {product?.manufacture?.name ? ( + <Link href={URL.manufacture} className='mb-1'> + {product.manufacture.name} + </Link> + ) : ( + <div>-</div> + )} <Link href={URL.product} className={`mb-2 !text-gray_r-12 leading-6 block line-clamp-3 h-[64px]`} @@ -299,18 +292,9 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => { </div> )} {product?.manufacture?.name ? ( - <div className='flex justify-between'> - <Link href={URL.manufacture} className='mb-1'> + <Link href={URL.manufacture} className='mb-1'> {product.manufacture.name} </Link> - {/* {product?.is_in_bu && ( - <div className='bg-red-500 rounded'> - <span className='p-[6px] text-xs text-white'> - Click & Pickup - </span> - </div> - )} */} - </div> ) : ( <div>-</div> )} diff --git a/src/lib/product/components/ProductFilter.jsx b/src/lib/product/components/ProductFilter.jsx index d52fcb90..dd9ec8f4 100644 --- a/src/lib/product/components/ProductFilter.jsx +++ b/src/lib/product/components/ProductFilter.jsx @@ -62,6 +62,7 @@ const ProductFilter = ({ active, close, brands, categories, prefixUrl, defaultBr const handleSubmit = () => { let params = { + penawaran: router.query.penawaran, q: router.query.q, orderBy: order, brand, diff --git a/src/lib/product/components/ProductFilterDesktop.jsx b/src/lib/product/components/ProductFilterDesktop.jsx index 1933c5f0..2bdf962a 100644 --- a/src/lib/product/components/ProductFilterDesktop.jsx +++ b/src/lib/product/components/ProductFilterDesktop.jsx @@ -93,6 +93,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu const handleSubmit = () => { let params = { + penawaran: router.query.penawaran, q: router.query.q, orderBy: order, brand: brandValues.join(','), @@ -107,11 +108,7 @@ const ProductFilterDesktop = ({ brands, categories, prefixUrl, defaultBrand = nu const slug = Array.isArray(router.query.slug) ? router.query.slug[0] : router.query.slug; if (slug) { - if(prefixUrl.includes('category') || prefixUrl.includes('lob')){ - router.push(`${prefixUrl}?${params}`) - }else{ - router.push(`${prefixUrl}/${slug}?${params}`) - } + router.push(`${prefixUrl}/${slug}?${params}`) } else { router.push(`${prefixUrl}?${params}`) } diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx index a83e5e1e..a427e134 100644 --- a/src/lib/product/components/ProductSearch.jsx +++ b/src/lib/product/components/ProductSearch.jsx @@ -142,6 +142,23 @@ const ProductSearch = ({ } }, [prefixUrl,dataCategoriesProduct, query, finalQuery]); + useEffect(() => { + const checkIfPenawaran = async () => { + if (router.asPath.includes('penawaran')) { + query = { + ...query, + fq: [ + `-flashsale_id_i:${router.query.penawaran}`, + `flashsale_price_f:[1 TO *]` + ], + orderBy: 'flashsale-discount-desc' + }; + setOrderBy('flashsale-discount-desc') + } + }; + checkIfPenawaran(); + }, [router]); + const { productSearch } = useProductSearch({ query: queryFinal, operation: 'AND', @@ -340,6 +357,7 @@ const ProductSearch = ({ const handleDeleteFilter = async (source, value) => { let params = { + penawaran: router.query.penawaran, q: router.query.q, orderBy: orderBy, brand: brandValues.join(','), @@ -367,6 +385,7 @@ const ProductSearch = ({ break; case 'delete': params = { + penawaran: router.query.penawaran, q: router.query.q, orderBy: orderBy, }; diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx index 0ad042de..df234dc2 100644 --- a/src/lib/quotation/components/Quotation.jsx +++ b/src/lib/quotation/components/Quotation.jsx @@ -9,7 +9,6 @@ import _ from 'lodash'; import { deleteItemCart, getCart, getItemCart } from '@/core/utils/cart'; import currencyFormat from '@/core/utils/currencyFormat'; import { toast } from 'react-hot-toast'; -import { useProductCartContext } from '@/contexts/ProductCartContext'; // import checkoutApi from '@/lib/checkout/api/checkoutApi' import { useRouter } from 'next/router'; import VariantGroupCard from '@/lib/variant/components/VariantGroupCard'; @@ -39,12 +38,11 @@ const { getProductsCheckout } = require('@/lib/checkout/api/checkoutApi'); const Quotation = () => { const router = useRouter(); const auth = useAuth(); - + const { data: cartCheckout } = useQuery('cartCheckout', () => getProductsCheckout() -); + ); -const { setRefreshCart } = useProductCartContext(); const SELF_PICKUP_ID = 32; const [products, setProducts] = useState(null); @@ -295,7 +293,6 @@ const { setRefreshCart } = useProductCartContext(); if (isSuccess?.id) { for (const product of products) deleteItemCart({ productId: product.id }); router.push(`/shop/quotation/finish?id=${isSuccess.id}`); - setRefreshCart(true); return; } diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx deleted file mode 100644 index 4529c977..00000000 --- a/src/lib/quotation/components/Quotationheader.jsx +++ /dev/null @@ -1,265 +0,0 @@ -import { useCallback, useEffect, useMemo, useState } from 'react'; -import { createSlug } from '@/core/utils/slug'; -import useAuth from '@/core/hooks/useAuth'; -import { useRouter } from 'next/router'; -import odooApi from '@/core/api/odooApi'; -import { useProductCartContext } from '@/contexts/ProductCartContext'; -import Image from '@/core/components/elements/Image/Image'; -import whatsappUrl from '@/core/utils/whatsappUrl'; -import { AnimatePresence, motion } from 'framer-motion'; -import style from '../../../../src-migrate/modules/cart/styles/item-promo.module.css'; -import useTransactions from '../../transaction/hooks/useTransactions'; -import currencyFormat from '@/core/utils/currencyFormat'; -const { DocumentCheckIcon, PhotoIcon } = require('@heroicons/react/24/outline'); -const { default: Link } = require('next/link'); - -const Quotationheader = (quotationCount) => { - const auth = useAuth(); - const query = { - context: 'quotation', - site: auth?.webRole === null && auth?.site ? auth.site : null, - }; - - const router = useRouter(); - const [subTotal, setSubTotal] = useState(null); - const [buttonLoading, SetButtonTerapkan] = useState(false); - const itemLoading = [1, 2, 3]; - const [countQuotation, setCountQuotation] = useState(null); - const { productCart, setProductCart, refreshCart, setRefreshCart, isLoading, setIsloading, productQuotation, setProductQuotation } = - useProductCartContext(); - - const [isHovered, setIsHovered] = useState(false); - const [isTop, setIsTop] = useState(true); - - const qotation = useMemo(() => { - return productQuotation || []; - }, [productQuotation]); - - const handleMouseEnter = () => { - setIsHovered(true); - getCart(); - }; - - const handleMouseLeave = () => { - setIsHovered(false); - }; - - const getCart = () => { - if (!productQuotation && auth) { - refreshCartf(); - } - }; - let { transactions } = useTransactions({ query }); - - const refreshCartf = useCallback(async () => { - setIsloading(true); - let pendingTransactions = transactions?.data?.saleOrders.filter(transaction => transaction.status === 'draft'); - setProductQuotation(pendingTransactions); - setCountQuotation(pendingTransactions?.length ? pendingTransactions?.length : pendingTransactions?.length); - setIsloading(false); - }, [setProductQuotation, setIsloading]); - - useEffect(() => { - if (!qotation) return - - let calculateTotalDiscountAmount = 0 - for (const product of qotation) { - // if (qotation.quantity == '') continue - calculateTotalDiscountAmount += product.amountUntaxed - } - let subTotal = calculateTotalDiscountAmount - setSubTotal(subTotal) - }, [qotation]) - - useEffect(() => { - if (refreshCart) { - refreshCartf(); - } - setRefreshCart(false); - }, [ refreshCartf, setRefreshCart]); - - useEffect(() => { - setCountQuotation(quotationCount.quotationCount); - setProductQuotation(quotationCount.data); - }, [quotationCount]); - - useEffect(() => { - const handleScroll = () => { - setIsTop(window.scrollY === 0); - }; - window.addEventListener('scroll', handleScroll); - return () => { - window.removeEventListener('scroll', handleScroll); - }; - }, []); - - const handleCheckout = async () => { - SetButtonTerapkan(true); - let checkoutAll = await odooApi('POST', `/api/v1/user/${auth.id}/cart/select-all`); - router.push('/my/quotations'); - }; - - return ( - <div className='relative group'> - <div> - <Link - href='/my/quotations' - target='_blank' - rel='noreferrer' - className='flex items-center gap-x-2 !text-gray_r-12/80' - onMouseEnter={handleMouseEnter} - onMouseLeave={handleMouseLeave} - > - <div className={`relative ${countQuotation > 0 && 'mr-2'}`}> - <DocumentCheckIcon className='w-7' /> - {countQuotation > 0 && ( - <span className='absolute -top-2 -right-2 badge-solid-red rounded-full w-5 h-5 flex items-center justify-center'> - {countQuotation} - </span> - )} - </div> - <span> - List - <br /> - Quotation - </span> - </Link> - </div> - <AnimatePresence> - {isHovered && ( - <> - <motion.div - initial={{ opacity: 0 }} - animate={{ opacity: 1, top: isTop ? 230 : 155 }} - exit={{ opacity: 0 }} - transition={{ duration: 0.15, top: { duration: 0.3 } }} - className={`fixed left-0 w-full h-full bg-black/50 z-10`} - /> - <motion.div - initial={{ opacity: 0 }} - animate={{ opacity: 1, transition: { duration: 0.2 } }} - exit={{ opacity: 0, transition: { duration: 0.3 } }} - className='absolute z-10 left-0 w-96' - onMouseEnter={handleMouseEnter} - onMouseLeave={handleMouseLeave} - > - <motion.div - initial={{ height: 0 }} - animate={{ height: 'auto' }} - exit={{ height: 0 }} - className='w-full max-w-md p-2 bg-white border border-gray-200 rounded-lg shadow overflow-hidden' - > - <div className='p-2 flex justify-between items-center'> - <h5 className='text-base font-semibold leading-none'>Daftar Quotation</h5> - </div> - <hr className='mt-3 mb-3 border border-gray-100' /> - <div className='flow-root max-h-[250px] overflow-y-auto'> - {!auth && ( - <div className='justify-center p-4'> - <p className='text-gray-500 text-center '> - Silahkan{' '} - <Link href='/login' className='text-red-600 underline leading-6'> - Login - </Link>{' '} - Untuk Melihat Daftar Quotation Anda - </p> - </div> - )} - {isLoading && - itemLoading.map((item) => ( - <div key={item} role='status' className='max-w-sm animate-pulse'> - <div className='flex items-center space-x-4 mb- 2'> - <div className='flex-shrink-0'> - <PhotoIcon className='h-16 w-16 text-gray-500' /> - </div> - <div className='flex-1 min-w-0'> - <div className='h-2.5 bg-gray-200 rounded-full dark:bg-gray-700 w-48 mb-4'></div> - <div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 max-w-[360px] mb-2.5'></div> - <div className='h-2 bg-gray-200 rounded-full dark:bg-gray-700 mb-2.5'></div> - </div> - </div> - </div> - ))} - {auth && qotation.length === 0 && !isLoading && ( - <div className='justify-center p-4'> - <p className='text-gray-500 text-center '> - Tidak Ada Quotation - </p> - </div> - )} - {auth && qotation.length > 0 && !isLoading && ( - <> - <ul role='list' className='divide-y divide-gray-200 dark:divide-gray-700'> - {qotation && - qotation?.map((product, index) => ( - <> - <li className='py-1 sm:py-2'> - <div className='flex justify-between border p-2 flex-col gap-y-2 hover:border-red-500'> - <Link - href={`/my/quotations/${product?.id}`} - className='hover:border-red-500' - > - <div className='flex justify-between mb-2'> - <div className='flex flex-row items-center'> - <p className='tanggal text-xs opacity-80 mr-[2px]'>Sales : </p> - <p className='tanggal text-xs text-red-500 font-semibold'>{product.sales}</p> - </div> - <div className='flex flex-row items-center'> - <p className='text-xs opacity-80 mr-[2px]'>Status :</p> - <p className='badge-red h-fit text-xs whitespace-nowrap'>Pending Quotation</p> - </div> - </div> - <div className='flex justify-between mb-2'> - <div className='flex flex-col items-start'> - <p className=' text-xs opacity-80 mr-[2px]'>No. Transaksi</p> - <p className=' text-sm text-red-500 font-semibold'> {product.name}</p> - </div> - <div className='flex flex-col items-end'> - <p className='text-xs opacity-80 mr-[2px]'>No. Purchase Order</p> - <p className='font-semibold text-sm text-red-500'> {product.purchaseOrderName ? product.purchaseOrderName : '-'}</p> - </div> - </div> - {/* <div className='my-0.5 h-0.5 bg-gray-200'></div> */} - <hr className='mt-3 mb-3 border border-gray-100' /> - <div className='bagian bawah flex justify-between mt-2'> - <p className='font-semibold text-sm'>Total</p> - <p className='font-semibold text-sm'>{currencyFormat(product.amountUntaxed)}</p> - </div> - </Link> - </div> - </li> - </> - ))} - </ul> - <hr /> - </> - )} - </div> - {auth && qotation.length > 0 && !isLoading && ( - <> - <div className='mt-3 ml-1'> - <span className='text-gray-400 text-caption-2'>Subtotal Sebelum PPN : </span> - <span className='font-semibold text-red-600'>{currencyFormat(subTotal)}</span> - </div> - <div className='mt-5 mb-2'> - <button - type='button' - className='btn-solid-red rounded-lg w-full' - onClick={handleCheckout} - disabled={buttonLoading} - > - {buttonLoading ? 'Loading...' : 'Lihat Semua'} - </button> - </div> - </> - )} - </motion.div> - </motion.div> - </> - )} - </AnimatePresence> - </div> - ); -}; - -export default Quotationheader; diff --git a/src/lib/tracking-order/api/trackingOrder.js b/src/lib/tracking-order/api/trackingOrder.js deleted file mode 100644 index cc48c40c..00000000 --- a/src/lib/tracking-order/api/trackingOrder.js +++ /dev/null @@ -1,8 +0,0 @@ -import odooApi from "@/core/api/odooApi"; - -export const trackingOrder = async ({query}) => { - const params = new URLSearchParams(query).toString(); - const list = await odooApi('GET', `/api/v1/tracking_order?${params}`) - - return list; -} diff --git a/src/lib/tracking-order/component/TrackingOrder.jsx b/src/lib/tracking-order/component/TrackingOrder.jsx deleted file mode 100644 index 394979c1..00000000 --- a/src/lib/tracking-order/component/TrackingOrder.jsx +++ /dev/null @@ -1,139 +0,0 @@ -import { yupResolver } from '@hookform/resolvers/yup' -import React, { useEffect, useState } from 'react' -import { useForm } from 'react-hook-form' -import * as Yup from 'yup' -import Manifest from '@/lib/treckingAwb/component/Manifest' -import { trackingOrder } from '../api/trackingOrder' -import { useQuery } from 'react-query' -import { Spinner } from '@chakra-ui/react'; -import { Search } from 'lucide-react'; -import whatsappUrl from '@/core/utils/whatsappUrl'; -import Link from 'next/link' - -const TrackingOrder = () => { - const [idAWB, setIdAWB] = useState(null) - const [inputQuery, setInputQuery] = useState(null) - const [buttonClick, setButtonClick] = useState(false) - const [apiError, setApiError] = useState(null) // State to store API error message - - const closePopup = () => { - setIdAWB(null) - setButtonClick(false) - setInputQuery(null) - setApiError(null) // Reset error message on close - } - - const { - register, - handleSubmit, - formState: { errors }, - control, - reset - } = useForm({ - resolver: yupResolver(validationSchema), - defaultValues - }) - - const query = { - email: inputQuery?.email, - so: inputQuery?.id - } - - const { data: tracking, isLoading, isError, error } = useQuery( - ['tracking', query], - () => trackingOrder({ query: query }), - { - enabled: !!query.email && !!query.so, - onSuccess: (data) => { - if (buttonClick) { - if (data?.code === 403 || data?.code === 400 || data?.code === 404) { - setApiError(data?.description); - } else if (data?.pickings?.length > 0) { - setIdAWB(data.pickings[0]?.id); - } else { - setApiError('No pickings data available'); - } - setButtonClick(false); - setInputQuery(null); - } - }, - } - ); - - const onSubmitHandler = async (values) => { - setInputQuery(values) - setButtonClick(true) - } - - return ( - <div className='container mx-auto flex py-10 flex-col'> - <h1 className='text-h-sm md:text-title-sm font-semibold mb-6'>Tracking Order</h1> - <div className='flex justify-start items-start'> - <span className='text-base w-full'> - {`Untuk melacak pesanan Anda, masukkan Nomor Transaksi di kotak bawah ini dan masukkan Email login anda lalu tekan tombol "Lacak". Nomor Transaksi ini dapat Anda lihat dalam menu `} - <Link href='/my/transactions' className='text-red-500'> - Daftar Transaksi - </Link> - {`. Jika mengalami kesulitan `} - <Link href='https://wa.me/6281717181922' target='_blank' rel='noreferrer' className='text-red-500'> - hubungi kami - </Link> - {`.`} - </span> - </div> - <div> - <form onSubmit={handleSubmit(onSubmitHandler)} className='flex mt-4 flex-row w-full '> - <div className='w-[90%] grid grid-cols-2 gap-4'> - <div className='flex flex-col '> - <label className='form-label mb-2'>ID Pesanan*</label> - <input - {...register('id')} - placeholder='dapat dilihat pada email konfirmasi anda' - type='text' - className='form-input mb-2' - aria-invalid={errors.id?.message} - /> - <div className='text-caption-2 text-danger-500 mt-1'>{errors.id?.message}</div> - </div> - <div className='flex flex-col '> - <label className='form-label mb-2'>Email Penagihan*</label> - <input - {...register('email')} - placeholder='Email yang anda gunakan saat pembayaran' - type='text' - className='form-input' - aria-invalid={errors.email?.message} - /> - <div className='text-caption-2 text-danger-500 mt-1'>{errors.email?.message}</div> - </div> - </div> - <div className={` ${errors.id?.message ? 'mt-2' : 'mt-5'} flex items-center ml-4`}> - <button - type='submit' - className='bg-red-600 border border-red-600 rounded-md text-sm text-white w-24 h-11 mb-1 content-center flex flex-row justify-center items-center' - > - {isLoading && <Spinner size='xs' className='mr-2'/>} - {!isLoading && <Search size={16} strokeWidth={1} className='mr-2'/>} - <p>Lacak</p> - </button> - </div> - </form> - {/* Display the API error message */} - {apiError && <div className='text-danger-500 mt-4'>{apiError}</div>} - <Manifest idAWB={idAWB} closePopup={closePopup} /> - </div> - </div> - ) -} - -const validationSchema = Yup.object().shape({ - email: Yup.string().email('Format harus seperti contoh@email.com').required('Harus di-isi'), - id: Yup.string().required('Harus di-isi'), -}) - -const defaultValues = { - email: '', - id: '' -} - -export default TrackingOrder diff --git a/src/lib/transaction/api/checkoutPoApi.js b/src/lib/transaction/api/checkoutPoApi.js index af41d277..04421368 100644 --- a/src/lib/transaction/api/checkoutPoApi.js +++ b/src/lib/transaction/api/checkoutPoApi.js @@ -1,11 +1,11 @@ import odooApi from '@/core/api/odooApi' import { getAuth } from '@/core/utils/auth' -const checkoutPoApi = async ({ id, status }) => { +const checkoutPoApi = async ({ id }) => { const auth = getAuth() const dataCheckout = await odooApi( 'POST', - `/api/v1/partner/${auth?.partnerId}/sale_order/${id}/checkout`,{status} + `/api/v1/partner/${auth?.partnerId}/sale_order/${id}/checkout` ) return dataCheckout } diff --git a/src/lib/transaction/components/Transaction.jsx b/src/lib/transaction/components/Transaction.jsx index a9e04c0e..9bef895a 100644 --- a/src/lib/transaction/components/Transaction.jsx +++ b/src/lib/transaction/components/Transaction.jsx @@ -1,12 +1,10 @@ import Spinner from '@/core/components/elements/Spinner/Spinner'; import NextImage from 'next/image'; -import rejectImage from '../../../../public/images/reject.png'; +import rejectImage from "../../../../public/images/reject.png" import useTransaction from '../hooks/useTransaction'; import TransactionStatusBadge from './TransactionStatusBadge'; import Divider from '@/core/components/elements/Divider/Divider'; import { useEffect, useMemo, useRef, useState } from 'react'; -import { Button, Tooltip } from '@chakra-ui/react'; -import clsxm from '~/libs/clsxm'; import ImageNext from 'next/image'; import { downloadPurchaseOrder, @@ -42,7 +40,7 @@ import rejectProductApi from '../api/rejectProductApi'; import { useRouter } from 'next/router'; const Transaction = ({ id }) => { - const router = useRouter(); + const router = useRouter() const [isModalOpen, setIsModalOpen] = useState(false); const [selectedProduct, setSelectedProduct] = useState(null); const [reason, setReason] = useState(''); @@ -109,7 +107,7 @@ const Transaction = ({ id }) => { toast.error('Mohon upload dokumen PO anda sebelum melanjutkan pesanan'); return; } - await checkoutPoApi({ id, status: true }); + await checkoutPoApi({ id }); toast.success('Berhasil melanjutkan pesanan'); transaction.refetch(); }; @@ -154,10 +152,7 @@ const Transaction = ({ id }) => { const memoizeVariantGroupCardReject = useMemo( () => ( <div className='p-4 pt-0 flex flex-col gap-y-3'> - <VariantGroupCard - variants={transaction.data?.productsRejectLine} - buyMore - /> + <VariantGroupCard variants={transaction.data?.productsRejectLine} buyMore /> </div> ), [transaction.data] @@ -187,25 +182,26 @@ const Transaction = ({ id }) => { }; const handleRejectProduct = async () => { - try { + try{ if (!reason.trim()) { toast.error('Masukkan alasan terlebih dahulu'); return; - } else { - let idSo = transaction?.data.id; - let idProduct = selectedProduct?.id; - await rejectProductApi({ idSo, idProduct, reason }); + }else{ + let idSo = transaction?.data.id + let idProduct = selectedProduct?.id + await rejectProductApi({ idSo, idProduct, reason}); closeModal(); - toast.success('Produk berhasil di reject'); + toast.success("Produk berhasil di reject") setTimeout(() => { window.location.reload(); - }, 1500); + }, 1500); } - } catch (error) { + }catch(error){ toast.error('Gagal reject produk. Silakan coba lagi.'); } }; + return ( transaction.data?.name && ( <> @@ -394,20 +390,14 @@ const Transaction = ({ id }) => { <p className='text-gray_r-11 leading-none'>Dokumen PO</p> <button type='button' - className='inline-block text-danger-500' + className='btn-light py-1.5 px-3 ml-auto' onClick={ transaction.data?.purchaseOrderFile ? () => downloadPurchaseOrder(transaction.data) - : transaction?.data.invoices.length < 1 - ? openUploadPo - : '' + : openUploadPo } > - {transaction?.data?.purchaseOrderFile - ? 'Download' - : transaction?.data.invoices.length < 1 - ? 'Upload' - : '-'} + {transaction.data?.purchaseOrderFile ? 'Download' : 'Upload'} </button> </div> </div> @@ -416,13 +406,13 @@ const Transaction = ({ id }) => { <Divider /> <div className='font-medium p-4'>Detail Produk</div> - {transaction?.data?.products.length > 0 ? ( - <div>{memoizeVariantGroupCard}</div> - ) : ( - <div className='badge-red text-sm px-2 ml-4'> - Semua produk telah di reject + {transaction?.data?.products.length > 0? ( + <div> + {memoizeVariantGroupCard} </div> - )} + ) : ( + <div className='badge-red text-sm px-2 ml-4'>Semua produk telah di reject</div> + )} {transaction?.data?.productsRejectLine.length > 0 && ( <div> @@ -565,27 +555,10 @@ const Transaction = ({ id }) => { )} {transaction.data?.status == 'draft' && !auth?.feature.soApproval && ( - <div> - <Tooltip - label={clsxm({ - 'Mohon upload dokumen PO anda sebelum melanjutkan pesanan': !transaction?.data?.purchaseOrderFile, - })}> - <Button colorScheme='yellow' onClick={checkout} - isDisabled={ - // transaction.data?.status === 'draft' - // ? true - // : false || - auth?.webRole === statusApprovalWeb - ? true - : false || transaction?.data?.purchaseOrderFile === true ? false : true - } - > - Lanjutkan Transaksi - </Button> - </Tooltip> - - </div> - )} + <button className='btn-yellow' onClick={checkout}> + Lanjutkan Transaksi + </button> + )} {transaction.data?.status != 'draft' && !auth?.feature.soApproval && ( <button @@ -621,16 +594,12 @@ const Transaction = ({ id }) => { onClick={ transaction.data?.purchaseOrderFile ? () => downloadPurchaseOrder(transaction.data) - : transaction?.data.invoices.length < 1 - ? openUploadPo - : '' + : openUploadPo } > {transaction?.data?.purchaseOrderFile ? 'Download' - : transaction?.data.invoices.length < 1 - ? 'Upload' - : '-'} + : 'Upload'} </button> </div> </> @@ -659,11 +628,9 @@ const Transaction = ({ id }) => { <div className='text-h-sm font-semibold mt-10 mb-4'> Pengiriman </div> - {transaction?.data?.pickings.length == 0 && ( - <div className='badge-red text-sm'> - Belum ada pengiriman - </div> - )} + {transaction?.data?.pickings.length == 0 && ( + <div className='badge-red text-sm'>Belum ada pengiriman</div> + )} <div className='grid grid-cols-1 gap-1 w-2/3'> {transaction?.data?.pickings?.map((airway) => ( <button @@ -679,9 +646,7 @@ const Transaction = ({ id }) => { </div> <div className='flex gap-x-2'> <div className='text-sm text-gray-600 badge-green leading-[1.5] mt-1'> - {airway?.delivered - ? 'Pesanan Tiba' - : 'Sedang Dikirim'} + {airway?.delivered ? 'Pesanan Tiba' : 'Sedang Dikirim'} </div> <ChevronRightIcon className='w-5 stroke-2' /> </div> @@ -690,53 +655,51 @@ const Transaction = ({ id }) => { </div> </div> <div className='invoice w-1/2 '> - <div className='text-h-sm font-semibold mt-10 mb-4 '> - Invoice - </div> - {transaction.data?.invoices?.length === 0 && ( - <div className='badge-red text-sm'>Belum ada invoice</div> - )} - <div className='grid grid-cols-1 gap-1 w-2/3 '> - {transaction.data?.invoices?.map((invoice, index) => ( - <Link href={`/my/invoices/${invoice.id}`} key={index}> - <div className='shadow rounded-md p-4 text-gray_r-12 font-normal flex justify-between'> - <div> - <p className='mb-1'>{invoice?.name}</p> - <div className='flex items-center gap-x-1'> - {invoice.amountResidual > 0 ? ( - <div className='badge-red'>Belum Lunas</div> - ) : ( - <div className='badge-green'>Lunas</div> - )} - <p className='text-caption-2 text-gray_r-11'> - {currencyFormat(invoice.amountTotal)} - </p> + <div className='text-h-sm font-semibold mt-10 mb-4 '>Invoice</div> + {transaction.data?.invoices?.length === 0 && ( + <div className='badge-red text-sm'>Belum ada invoice</div> + )} + <div className='grid grid-cols-1 gap-1 w-2/3 '> + {transaction.data?.invoices?.map((invoice, index) => ( + <Link href={`/my/invoices/${invoice.id}`} key={index}> + <div className='shadow rounded-md p-4 text-gray_r-12 font-normal flex justify-between'> + <div> + <p className='mb-1'>{invoice?.name}</p> + <div className='flex items-center gap-x-1'> + {invoice.amountResidual > 0 ? ( + <div className='badge-red'>Belum Lunas</div> + ) : ( + <div className='badge-green'>Lunas</div> + )} + <p className='text-caption-2 text-gray_r-11'> + {currencyFormat(invoice.amountTotal)} + </p> + </div> </div> + <ChevronRightIcon className='w-5 stroke-2' /> </div> - <ChevronRightIcon className='w-5 stroke-2' /> - </div> - </Link> - ))} - </div> + </Link> + ))} + </div> </div> </div> <div className='text-h-sm font-semibold mt-4 mb-4'> Rincian Pembelian </div> - {transaction?.data?.products?.length > 0 ? ( - <table className='table-data'> - <thead> - <tr> - <th>Nama Produk</th> - {/* <th>Diskon</th> */} - <th>Jumlah</th> - <th>Harga</th> - <th>Subtotal</th> - <th></th> - </tr> - </thead> - <tbody> + {transaction?.data?.products?.length > 0? ( + <table className='table-data'> + <thead> + <tr> + <th>Nama Produk</th> + {/* <th>Diskon</th> */} + <th>Jumlah</th> + <th>Harga</th> + <th>Subtotal</th> + <th></th> + </tr> + </thead> + <tbody> {transaction?.data?.products?.map((product) => ( <tr key={product.id}> <td className='flex'> @@ -748,37 +711,37 @@ const Transaction = ({ id }) => { )} className='w-[20%] flex-shrink-0' > - <div className='relative'> + <div className='relative'> <Image src={product?.parent?.image} alt={product?.name} className='object-contain object-center border border-gray_r-6 h-32 w-full rounded-md' /> - <div className='absolute top-0 right-4 flex mt-3'> - <div className='gambarB '> - {product.isSni && ( - <ImageNext - src='/images/sni-logo.png' - alt='SNI Logo' - className='w-2 h-4 object-contain object-top sm:h-4' - width={50} - height={50} - /> - )} - </div> - <div className='gambarC '> - {product.isTkdn && ( - <ImageNext - src='/images/TKDN.png' - alt='TKDN' - className='w-5 h-4 object-contain object-top ml-1 sm:h-4' - width={50} - height={50} - /> - )} - </div> + <div className='absolute top-0 right-4 flex mt-3'> + <div className='gambarB '> + {product.isSni && ( + <ImageNext + src='/images/sni-logo.png' + alt='SNI Logo' + className='w-2 h-4 object-contain object-top sm:h-4' + width={50} + height={50} + /> + )} + </div> + <div className='gambarC '> + {product.isTkdn && ( + <ImageNext + src='/images/TKDN.png' + alt='TKDN' + className='w-5 h-4 object-contain object-top ml-1 sm:h-4' + width={50} + height={50} + /> + )} </div> </div> + </div> </Link> <div className='px-2 text-left'> <Link @@ -811,42 +774,33 @@ const Transaction = ({ id }) => { {currencyFormat(product.price.price)} </div> )} */} - <div> - {currencyFormat(product.price.priceDiscount)} - </div> + <div>{currencyFormat(product.price.priceDiscount)}</div> </td> <td>{currencyFormat(product.price.subtotal)}</td> {/* {auth?.feature.soApproval && (auth.webRole == 2 || auth.webRole == 3) && (transaction.data.isReaject == false) && ( */} - {auth?.feature.soApproval && - (auth.webRole == 2 || auth.webRole == 3) && - router.asPath.includes('/my/quotations/') && - transaction.data?.status == 'draft' && ( - <td> - <button - className='bg-red-500 text-white py-1 px-3 rounded' - onClick={() => openModal(product)} - > - Reject - </button> - </td> - )} + {auth?.feature.soApproval && (auth.webRole == 2 || auth.webRole == 3) && (router.asPath.includes("/my/quotations/")) && transaction.data?.status == 'draft' && ( + <td> + <button + className="bg-red-500 text-white py-1 px-3 rounded" + onClick={() => openModal(product)} + > + Reject + </button> + </td> + )} </tr> ))} </tbody> </table> ) : ( - <div className='badge-red text-sm'> - Semua produk telah di reject - </div> + <div className='badge-red text-sm'>Semua produk telah di reject</div> )} - + {isModalOpen && ( <div className='fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center'> - <div - className='bg-white p-4 rounded w-96 + <div className='bg-white p-4 rounded w-96 ease-in-out opacity-100 - transform transition-transform duration-300 scale-100' - > + transform transition-transform duration-300 scale-100'> <h2 className='text-lg mb-2'>Berikan Alasan</h2> <textarea value={reason} @@ -872,116 +826,117 @@ const Transaction = ({ id }) => { </div> )} - {transaction?.data?.products?.length > 0 && ( - <div className='flex justify-end mt-4'> - <div className='w-1/4 grid grid-cols-2 gap-y-3 text-gray_r-12/80'> - <div className='text-right'>Subtotal</div> - <div className='text-right font-medium'> - {currencyFormat(transaction.data?.amountUntaxed)} - </div> + {transaction?.data?.products?.map((product) => ( + <div className='flex justify-end mt-4' key={product.id}> + <div className='w-1/4 grid grid-cols-2 gap-y-3 text-gray_r-12/80'> + <div className='text-right'>Subtotal</div> + <div className='text-right font-medium'> + {currencyFormat(transaction.data?.amountUntaxed)} + </div> - <div className='text-right'>PPN 11%</div> - <div className='text-right font-medium'> - {currencyFormat(transaction.data?.amountTax)} - </div> + <div className='text-right'>PPN 11%</div> + <div className='text-right font-medium'> + {currencyFormat(transaction.data?.amountTax)} + </div> - <div className='text-right whitespace-nowrap'> - Biaya Pengiriman - </div> - <div className='text-right font-medium'> - {currencyFormat(transaction.data?.deliveryAmount)} - </div> + <div className='text-right whitespace-nowrap'> + Biaya Pengiriman + </div> + <div className='text-right font-medium'> + {currencyFormat(transaction.data?.deliveryAmount)} + </div> - <div className='text-right'>Grand Total</div> - <div className='text-right font-medium text-gray_r-12'> - {currencyFormat(transaction.data?.amountTotal)} - </div> + <div className='text-right'>Grand Total</div> + <div className='text-right font-medium text-gray_r-12'> + {currencyFormat(transaction.data?.amountTotal)} </div> </div> - )} + </div> + ))} + + {transaction?.data?.productsRejectLine.length > 0 && ( - <div className='text-h-sm font-semibold mt-10 mb-4'> - Rincian Produk Reject - </div> + <div className='text-h-sm font-semibold mt-10 mb-4'> + Rincian Produk Reject + </div> )} {transaction?.data?.productsRejectLine.length > 0 && ( - <table className='table-data'> - <thead> - <tr> - <th>Nama Produk</th> - {/* <th>Diskon</th> */} - <th>Jumlah</th> - <th>Harga</th> - <th>Subtotal</th> - </tr> - </thead> - <tbody> - {transaction?.data?.productsRejectLine?.map((product) => ( - <tr key={product.id}> - <td className='flex'> - <Link - href={createSlug( - '/shop/product/', - product?.parent.name, - product?.parent.id - )} - className='w-[20%] flex-shrink-0' - > - <Image - src={product?.parent?.image} - alt={product?.name} - className='object-contain object-center border border-gray_r-6 h-32 w-full rounded-md' - /> - </Link> - <div className='px-2 text-left'> + <table className='table-data'> + <thead> + <tr> + <th>Nama Produk</th> + {/* <th>Diskon</th> */} + <th>Jumlah</th> + <th>Harga</th> + <th>Subtotal</th> + </tr> + </thead> + <tbody> + {transaction?.data?.productsRejectLine?.map((product) => ( + <tr key={product.id}> + <td className='flex'> <Link href={createSlug( '/shop/product/', product?.parent.name, product?.parent.id )} - className='line-clamp-2 leading-6 !text-gray_r-12 font-normal' + className='w-[20%] flex-shrink-0' > - {product?.parent?.name} + <Image + src={product?.parent?.image} + alt={product?.name} + className='object-contain object-center border border-gray_r-6 h-32 w-full rounded-md' + /> </Link> - <div className='text-gray_r-11 mt-2'> - {product?.code}{' '} - {product?.attributes.length > 0 - ? `| ${product?.attributes.join(', ')}` - : ''} + <div className='px-2 text-left'> + <Link + href={createSlug( + '/shop/product/', + product?.parent.name, + product?.parent.id + )} + className='line-clamp-2 leading-6 !text-gray_r-12 font-normal' + > + {product?.parent?.name} + </Link> + <div className='text-gray_r-11 mt-2'> + {product?.code}{' '} + {product?.attributes.length > 0 + ? `| ${product?.attributes.join(', ')}` + : ''} + </div> </div> - </div> - </td> - {/* <td> + </td> + {/* <td> {product.price.discountPercentage > 0 ? `${product.price.discountPercentage}%` : ''} </td> */} - <td>{product.quantity}</td> - <td> - {/* {product.price.discountPercentage > 0 && ( + <td>{product.quantity}</td> + <td> + {/* {product.price.discountPercentage > 0 && ( <div className='line-through mb-1 text-caption-1 text-gray_r-12/70'> {currencyFormat(product.price.price)} </div> )} */} - <div> - {currencyFormat(product.price.priceDiscount)} - </div> - </td> - <td className='flex justify-center'> - <NextImage - src={rejectImage} - alt='Reject' - width={90} - height={30} - /> - </td> - </tr> - ))} - </tbody> - </table> + <div>{currencyFormat(product.price.priceDiscount)}</div> + </td> + <td className='flex justify-center'> + <NextImage + src={rejectImage} + alt='Reject' + width={90} + height={30} + /> + </td> + </tr> + ))} + </tbody> + </table> )} + </div> </div> </DesktopView> |
