summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/cart/components/Cartheader.jsx264
-rw-r--r--src/lib/category/components/Category.jsx4
-rw-r--r--src/lib/category/components/PopularBrand.jsx88
-rw-r--r--src/lib/checkout/components/Checkout.jsx29
-rw-r--r--src/lib/home/api/categoryManagementApi.js47
-rw-r--r--src/lib/home/components/CategoryDynamic.jsx196
-rw-r--r--src/lib/home/components/CategoryDynamicMobile.jsx4
-rw-r--r--src/lib/home/components/PreferredBrand.jsx5
-rw-r--r--src/lib/product/api/productSearchApi.js2
-rw-r--r--src/lib/product/components/ProductSearch.jsx1
-rw-r--r--src/lib/promo/api/productSearchApi.js11
-rw-r--r--src/lib/promo/hooks/usePromotionSearch.js15
-rw-r--r--src/lib/quotation/components/Quotation.jsx7
-rw-r--r--src/lib/quotation/components/Quotationheader.jsx265
14 files changed, 784 insertions, 154 deletions
diff --git a/src/lib/cart/components/Cartheader.jsx b/src/lib/cart/components/Cartheader.jsx
index 19f79bc9..ddb77c1f 100644
--- a/src/lib/cart/components/Cartheader.jsx
+++ b/src/lib/cart/components/Cartheader.jsx
@@ -1,14 +1,20 @@
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)
@@ -19,7 +25,7 @@ const Cardheader = (cartCount) => {
useProductCartContext()
const [isHovered, setIsHovered] = useState(false)
-
+ const [isTop, setIsTop] = useState(true)
const products = useMemo(() => {
return productCart?.products || []
}, [productCart])
@@ -42,7 +48,7 @@ const Cardheader = (cartCount) => {
setIsloading(true)
let cart = await getCartApi()
setProductCart(cart)
- setCountCart(cart.productTotal)
+ setCountCart(cart?.productTotal)
setIsloading(false)
}, [setProductCart, setIsloading])
@@ -75,14 +81,26 @@ 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>
@@ -109,6 +127,246 @@ 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/components/Category.jsx b/src/lib/category/components/Category.jsx
index f76e6e42..91553295 100644
--- a/src/lib/category/components/Category.jsx
+++ b/src/lib/category/components/Category.jsx
@@ -86,14 +86,14 @@ const Category = () => {
</div>
))}
</div>
- <div className='category-mega-box__child-wrapper !w-[260px] !flex !flex-col !gap-4'>
+ {/* <div className='category-mega-box__child-wrapper !w-[260px] !flex !flex-col !gap-4'>
<PopularBrand category={category} />
{Array.isArray(promotionProgram?.data) && promotionProgram?.data.length > 0 && promotionProgram?.data[0]?.map((banner, index) => (
<div key={index} className='flex w-60 h-20 object-cover'>
<Image src={`${banner.image}`} alt={`${banner.name}`} width={275} height={4} />
</div>
))}
- </div>
+ </div> */}
</div>
</div>
))}
diff --git a/src/lib/category/components/PopularBrand.jsx b/src/lib/category/components/PopularBrand.jsx
index 4777fded..8124b5b4 100644
--- a/src/lib/category/components/PopularBrand.jsx
+++ b/src/lib/category/components/PopularBrand.jsx
@@ -13,60 +13,60 @@ import { fetchPopulerProductSolr } from '../api/popularProduct'
const SOLR_HOST = process.env.SOLR_HOST
const PopularBrand = ({ category }) => {
- const [topBrands, setTopBrands] = useState([]);
+ // const [topBrands, setTopBrands] = useState([]);
- const fetchTopBrands = async () => {
- try {
- const items = await fetchPopulerProductSolr(`category_id_ids:(${category?.categoryDataIds?.join(' OR ')})`);
- const getTop12UniqueBrands = (prod) => {
- const brandMap = new Map();
+ // const fetchTopBrands = async () => {
+ // try {
+ // const items = await fetchPopulerProductSolr(`category_id_ids:(${category?.categoryDataIds?.join(' OR ')})`);
+ // const getTop12UniqueBrands = (prod) => {
+ // const brandMap = new Map();
- for (const product of prod) {
- const { manufacture_name, manufacture_id, qty_sold } = product;
+ // for (const product of prod) {
+ // const { manufacture_name, manufacture_id, qty_sold } = product;
- if (brandMap.has(manufacture_name)) {
- // Update the existing brand's qty_sold
- brandMap.set(manufacture_name, {
- name: manufacture_name,
- id: manufacture_id,
- qty_sold: brandMap.get(manufacture_name).qty_sold + qty_sold
- });
- } else {
- // Add a new brand to the map
- brandMap.set(manufacture_name, {
- name: manufacture_name,
- id: manufacture_id,
- qty_sold
- });
- }
- }
+ // if (brandMap.has(manufacture_name)) {
+ // // Update the existing brand's qty_sold
+ // brandMap.set(manufacture_name, {
+ // name: manufacture_name,
+ // id: manufacture_id,
+ // qty_sold: brandMap.get(manufacture_name).qty_sold + qty_sold
+ // });
+ // } else {
+ // // Add a new brand to the map
+ // brandMap.set(manufacture_name, {
+ // name: manufacture_name,
+ // id: manufacture_id,
+ // qty_sold
+ // });
+ // }
+ // }
- // Convert the map to an array and sort by qty_sold in descending order
- const sortedBrands = Array.from(brandMap.values()).sort((a, b) => b.qty_sold - a.qty_sold);
+ // // Convert the map to an array and sort by qty_sold in descending order
+ // const sortedBrands = Array.from(brandMap.values()).sort((a, b) => b.qty_sold - a.qty_sold);
- // Return the top 12 brands
- return sortedBrands.slice(0, 18);
- };
+ // // Return the top 12 brands
+ // return sortedBrands.slice(0, 18);
+ // };
- // Using the fetched products
- const products = items;
- const top12UniqueBrands = getTop12UniqueBrands(products);
+ // // Using the fetched products
+ // const products = items;
+ // const top12UniqueBrands = getTop12UniqueBrands(products);
- // Set the top 12 brands to the state
- setTopBrands(top12UniqueBrands);
- } catch (error) {
- console.error("Error fetching data from Solr", error);
- throw error;
- }
- }
+ // // Set the top 12 brands to the state
+ // setTopBrands(top12UniqueBrands);
+ // } catch (error) {
+ // console.error("Error fetching data from Solr", error);
+ // throw error;
+ // }
+ // }
- useEffect(() => {
- fetchTopBrands();
- }, [category]);
+ // useEffect(() => {
+ // fetchTopBrands();
+ // }, [category]);
return (
<div className='flex flex-col'>
- <div className='grid grid-cols-3 max-h-full w-full gap-2'>
+ {/* <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
@@ -77,7 +77,7 @@ const PopularBrand = ({ category }) => {
</Link>
</div>
))}
- </div>
+ </div> */}
{/* {topBrands.length > 8 && (
<div className='flex hover:bg-gray_r-8/35 rounded-10'>
<Link
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx
index 54acdf7c..f63ef457 100644
--- a/src/lib/checkout/components/Checkout.jsx
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -174,7 +174,6 @@ const Checkout = () => {
}
return; // Hentikan eksekusi lebih lanjut pada iterasi ini
}
-
// Memeriksa apakah subtotal memenuhi syarat minimal pembelian
if (cartCheckout?.subtotal < addNewLine.minPurchaseAmount) {
SetSelisihHargaCode(
@@ -191,7 +190,9 @@ const Checkout = () => {
// Tambahkan voucher ke list dan set voucher aktif
SetListVoucher((prevList) => [addNewLine, ...prevList]);
- SetActiveVoucher(addNewLine.code);
+ if (addNewLine.canApply) {
+ SetActiveVoucher(addNewLine.code);
+ }
} else {
// Mencari voucher dalam listVoucherShippings
let checkList = listVoucherShippings?.findIndex(
@@ -227,7 +228,9 @@ const Checkout = () => {
// Tambahkan voucher ke list pengiriman dan set voucher aktif pengiriman
SetListVoucherShipping((prevList) => [addNewLine, ...prevList]);
- setActiveVoucherShipping(addNewLine.code);
+ if (addNewLine.canApply) {
+ setActiveVoucherShipping(addNewLine.code);
+ }
}
});
@@ -407,7 +410,7 @@ const Checkout = () => {
Math.round(parseInt(finalShippingAmt * 1.1) / 1000) * 1000;
const finalGT = GT < 0 ? 0 : GT;
setGrandTotal(finalGT);
- }, [biayaKirim, cartCheckout?.grandTotal, activeVoucher]);
+ }, [biayaKirim, cartCheckout?.grandTotal, activeVoucher, activeVoucherShipping]);
const checkout = async () => {
const file = poFile.current.files[0];
@@ -494,7 +497,7 @@ const Checkout = () => {
}
}
- const midtrans = async () => {
+ /* const midtrans = async () => {
for (const product of products) deleteItemCart({ productId: product.id });
if (grandTotal > 0) {
const payment = await axios.post(
@@ -510,7 +513,7 @@ const Checkout = () => {
'-'
)}`;
}
- };
+ };*/
};
const handlingActivateCode = async () => {
@@ -701,7 +704,9 @@ const Checkout = () => {
{listVoucherShippings && listVoucherShippings?.length > 0 && (
<div>
- <h3 className='font-semibold mb-4'>Promo Extra Potongan Ongkir</h3>
+ <h3 className='font-semibold mb-4'>
+ Promo Extra Potongan Ongkir
+ </h3>
{listVoucherShippings?.map((item) => (
<div key={item.id} className='relative'>
<div
@@ -1028,7 +1033,7 @@ const Checkout = () => {
</div>
<span className='leading-5'>
Jika mengalami kesulitan dalam melakukan pembelian di website
- Indoteknik. Hubungi kami disini
+ Indoteknik. <a href={whatsappUrl()}>Hubungi kami disini</a>
</span>
</Alert>
</div>
@@ -1184,7 +1189,7 @@ const Checkout = () => {
<div className='text-gray_r-11'>
Biaya Kirim <p className='text-xs mt-1'>{etdFix}</p>
</div>
- <div>{currencyFormat(biayaKirim)}</div>
+ <div>{currencyFormat(Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000)}</div>
</div>
{activeVoucherShipping && voucherShippingAmt && (
<div className='flex gap-x-2 justify-between'>
@@ -1236,10 +1241,10 @@ const Checkout = () => {
className='object-contain object-center h-6 rounded-md'
/>
</span>
- {activeVoucher ? (
+ {activeVoucher || activeVoucherShipping ? (
<div className=''>
<div className='text-left text-sm text-black font-semibold'>
- Potongan Senilai {currencyFormat(discountVoucher)}
+ Potongan Senilai {currencyFormat(totalDiscountVoucher)}
</div>
<div className='text-left mt-1 text-green-600 text-xs'>
Voucher berhasil digunakan
@@ -1485,7 +1490,7 @@ const Checkout = () => {
Biaya Kirim
<p className='text-xs mt-1'>{etdFix}</p>
</div>
- <div>{currencyFormat(biayaKirim)}</div>
+ <div>{currencyFormat(Math.round(parseInt(biayaKirim * 1.1) / 1000) * 1000) }</div>
</div>
{activeVoucherShipping && voucherShippingAmt && (
<div className='flex gap-x-2 justify-between'>
diff --git a/src/lib/home/api/categoryManagementApi.js b/src/lib/home/api/categoryManagementApi.js
index b70d60ce..63edd629 100644
--- a/src/lib/home/api/categoryManagementApi.js
+++ b/src/lib/home/api/categoryManagementApi.js
@@ -1,8 +1,43 @@
-import odooApi from '@/core/api/odooApi'
+// import odooApi from '@/core/api/odooApi'
-const categoryManagementApi = async () => {
- const dataCategoryManagement = await odooApi('GET', '/api/v1/categories_management')
- return dataCategoryManagement
-}
+// const categoryManagementApi = async () => {
+// const dataCategoryManagement = await odooApi('GET', '/api/v1/categories_management')
+// return dataCategoryManagement
+// }
-export default categoryManagementApi
+// export default categoryManagementApi
+
+
+
+export const fetchPopulerProductSolr = 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/category_management/query?q=*:*&q.op=OR&indent=true`);
+ 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.name_s,
+ image: promotion.image_s,
+ sequence: promotion.sequence_i,
+ numFound: promotion.numFound_i,
+ categories_level_2:promotion.categories_level_2
+ };
+ result.push(data);
+ }
+ return result;
+ }; \ No newline at end of file
diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx
index b7798a24..11a15d6d 100644
--- a/src/lib/home/components/CategoryDynamic.jsx
+++ b/src/lib/home/components/CategoryDynamic.jsx
@@ -1,105 +1,149 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, useCallback } from 'react';
import useCategoryManagement from '../hooks/useCategoryManagement';
+import {fetchPopulerProductSolr} from '../api/categoryManagementApi'
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'
+import { Skeleton } from '@chakra-ui/react';
+import { Swiper, SwiperSlide } from 'swiper/react';
+import 'swiper/css';
+import 'swiper/css/navigation';
+import 'swiper/css/pagination';
+import { Navigation, Pagination, Autoplay } from 'swiper';
const CategoryDynamic = () => {
+
+ const [manufactures, setManufactures] = useState([])
+ const loadBrand = useCallback(async () => {
+ // setIsLoading(true)
+ //Get brand from odoo
+ /*const result = await odooApi(
+ 'GET',
+ `/api/v1/manufacture?limit=0&offset=${manufactures.length}&name=${name}`
+ )*/
+
+ // Change get brands from solr
+ const items = await fetchPopulerProductSolr();
+
+ console.log("items",items)
+
+ // setIsLoading(false)
+ // setManufactures((manufactures) => [...result.data])
+ }, [])
+
+ useEffect(() => {
+ loadBrand()
+ }, [loadBrand])
const { categoryManagement } = useCategoryManagement();
- const [categoryData, setCategoryData] = useState({});
- const [subCategoryData, setSubCategoryData] = useState({});
+ // const [categoryData, setCategoryData] = useState({});
+ // const [subCategoryData, setSubCategoryData] = useState({});
- useEffect(() => {
- const fetchCategoryData = async () => {
- if (categoryManagement && categoryManagement.data) {
- const updatedCategoryData = {};
- const updatedSubCategoryData = {};
+ // 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}`);
+ // for (const category of categoryManagement.data) {
+ // const countLevel1 = await odooApi('GET', `/api/v1/category/numFound?parent_id=${category.categoryIdI}`);
- updatedCategoryData[category.categoryIdI] = countLevel1?.numFound;
+ // updatedCategoryData[category.categoryIdI] = countLevel1?.numFound;
- for (const subCategory of countLevel1.children) {
- updatedSubCategoryData[subCategory.id] = subCategory.numFound;
- }
- }
+ // for (const subCategory of countLevel1?.children) {
+ // updatedSubCategoryData[subCategory.id] = subCategory?.numFound;
+ // }
+ // }
- setCategoryData(updatedCategoryData);
- setSubCategoryData(updatedSubCategoryData);
- }
- };
+ // setCategoryData(updatedCategoryData);
+ // setSubCategoryData(updatedSubCategoryData);
+ // }
+ // };
- fetchCategoryData();
- }, [categoryManagement.isLoading]);
+ // fetchCategoryData();
+ // }, [categoryManagement.isLoading]);
+
+ const swiperBanner = {
+ modules: [Pagination, ],
+ classNames:'mySwiper',
+ slidesPerView: 3,
+ spaceBetween:10,
+ pagination: {
+ dynamicBullets: true,
+ clickable: true,
+ }
+ };
return (
<div>
{categoryManagement && categoryManagement.data?.map((category) => {
- const countLevel1 = categoryData[category.categoryIdI] || 0;
+ // 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;
+ <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>
+
+ {/* Swiper for SubCategories */}
+ <Swiper {...swiperBanner}
+ >
+ {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}
- className='p-2 ml-1'
- 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>
+ return (
+ <SwiperSlide key={subCategory.id}>
+ <div 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 p-4'
+ />
+ <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] min-h-[240px] content-start'>
+ {subCategory.childFrontendIdI.map((childCategory) => (
+ <div key={childCategory.id} className=''>
+ <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}
+ className='p-2 ml-1'
+ 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>
- </Link>
+ ))}
</div>
- ))}
+ </div>
</div>
- </div>
- </div>
- );
- })}
+ </SwiperSlide>
+ );
+ })}
+ </Swiper>
</div>
- </div>
- </Skeleton>
+ </Skeleton>
);
})}
</div>
diff --git a/src/lib/home/components/CategoryDynamicMobile.jsx b/src/lib/home/components/CategoryDynamicMobile.jsx
index c1433a2d..2877a5a7 100644
--- a/src/lib/home/components/CategoryDynamicMobile.jsx
+++ b/src/lib/home/components/CategoryDynamicMobile.jsx
@@ -59,11 +59,10 @@ const CategoryDynamicMobile = () => {
alt={index.name}
width={30}
height={30}
- className='object-'
+ className=''
/>
<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>
@@ -82,6 +81,7 @@ const CategoryDynamicMobile = () => {
alt={x.name}
width={40}
height={40}
+ className='p-2'
/>
<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>
diff --git a/src/lib/home/components/PreferredBrand.jsx b/src/lib/home/components/PreferredBrand.jsx
index 56268db7..b30fa5c9 100644
--- a/src/lib/home/components/PreferredBrand.jsx
+++ b/src/lib/home/components/PreferredBrand.jsx
@@ -65,11 +65,6 @@ const PreferredBrand = () => {
Lihat Semua
</Link>
)}
- {isMobile && (
- <Link href='/shop/brands' className='!text-red-500 font-semibold sm:text-h-sm'>
- Lihat Semua
- </Link>
- )}
</div>
<div className=''>
{manufactures.isLoading && <PreferredBrandSkeleton />}
diff --git a/src/lib/product/api/productSearchApi.js b/src/lib/product/api/productSearchApi.js
index 1626b7b7..8ff8e57d 100644
--- a/src/lib/product/api/productSearchApi.js
+++ b/src/lib/product/api/productSearchApi.js
@@ -1,7 +1,7 @@
import _ from 'lodash-contrib'
import axios from 'axios'
-const productSearchApi = async ({ query, operation = 'AND' }) => {
+const productSearchApi = async ({ query, operation = 'OR' }) => {
const dataProductSearch = await axios(
`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?${query}&operation=${operation}`
)
diff --git a/src/lib/product/components/ProductSearch.jsx b/src/lib/product/components/ProductSearch.jsx
index d6e649a8..1edc31c9 100644
--- a/src/lib/product/components/ProductSearch.jsx
+++ b/src/lib/product/components/ProductSearch.jsx
@@ -87,7 +87,6 @@ const ProductSearch = ({
recurse(category);
return ids;
};
-
useEffect(() => {
if(prefixUrl.includes('category')){
const ids = collectIds(dataCategoriesProduct);
diff --git a/src/lib/promo/api/productSearchApi.js b/src/lib/promo/api/productSearchApi.js
new file mode 100644
index 00000000..2f792fd4
--- /dev/null
+++ b/src/lib/promo/api/productSearchApi.js
@@ -0,0 +1,11 @@
+import _ from 'lodash-contrib'
+import axios from 'axios'
+
+const productSearchApi = async ({ query, operation = 'AND' }) => {
+ const dataProductSearch = await axios(
+ `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/promo?${query}&operation=${operation}`
+ )
+ return dataProductSearch.data
+}
+
+export default productSearchApi
diff --git a/src/lib/promo/hooks/usePromotionSearch.js b/src/lib/promo/hooks/usePromotionSearch.js
new file mode 100644
index 00000000..1a194646
--- /dev/null
+++ b/src/lib/promo/hooks/usePromotionSearch.js
@@ -0,0 +1,15 @@
+import { useQuery } from 'react-query'
+import productSearchApi from '../api/productSearchApi'
+import _ from 'lodash-contrib'
+
+const usePromotionSearch = ({ query, operation }) => {
+ const queryString = _.toQuery(query)
+ const fetchProductSearch = async () => await productSearchApi({ query: queryString , operation : operation})
+ const productSearch = useQuery(`promoSearch-${queryString}`, fetchProductSearch)
+
+ return {
+ productSearch
+ }
+}
+
+export default usePromotionSearch
diff --git a/src/lib/quotation/components/Quotation.jsx b/src/lib/quotation/components/Quotation.jsx
index df234dc2..0ad042de 100644
--- a/src/lib/quotation/components/Quotation.jsx
+++ b/src/lib/quotation/components/Quotation.jsx
@@ -9,6 +9,7 @@ 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';
@@ -38,11 +39,12 @@ 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);
@@ -293,6 +295,7 @@ const Quotation = () => {
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
new file mode 100644
index 00000000..4529c977
--- /dev/null
+++ b/src/lib/quotation/components/Quotationheader.jsx
@@ -0,0 +1,265 @@
+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;