summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/contexts/ProductQuotationContext.js17
-rw-r--r--src/core/components/elements/Navbar/NavbarDesktop.jsx58
-rw-r--r--src/lib/quotation/components/Quotationheader.jsx189
3 files changed, 249 insertions, 15 deletions
diff --git a/src/contexts/ProductQuotationContext.js b/src/contexts/ProductQuotationContext.js
new file mode 100644
index 00000000..f9e17830
--- /dev/null
+++ b/src/contexts/ProductQuotationContext.js
@@ -0,0 +1,17 @@
+import React, { createContext, useContext, useState } from 'react';
+
+const ProductQuotationContext = createContext();
+
+export const useProductQuotationContext = () => useContext(ProductQuotationContext);
+
+export const ProductQuotationProvider = ({ children }) => {
+ const [productQuotation, setProductQuotation] = useState([]);
+ const [refreshQuotation, setRefreshQuotation] = useState(false);
+ const [isLoading, setIsloading] = useState(false);
+
+ return (
+ <ProductQuotationContext.Provider value={{ productQuotation, setProductQuotation, refreshQuotation, setRefreshQuotation, isLoading, setIsloading }}>
+ {children}
+ </ProductQuotationContext.Provider>
+ );
+};
diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx
index 7d9e4264..49c4cd6e 100644
--- a/src/core/components/elements/Navbar/NavbarDesktop.jsx
+++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx
@@ -5,7 +5,9 @@ import { createSlug } from '@/core/utils/slug';
import whatsappUrl from '@/core/utils/whatsappUrl';
import IndoteknikLogo from '@/images/logo.png';
import Cardheader from '@/lib/cart/components/Cartheader';
+import Quotationheader from '@/lib/quotation/components/QuotationHeader'
import Category from '@/lib/category/components/Category';
+import { useProductQuotationContext } from '@/contexts/ProductQuotationContext'
import {
ChevronDownIcon,
DocumentCheckIcon,
@@ -28,6 +30,7 @@ import {
useDisclosure,
} from '@chakra-ui/react';
import style from "./style/NavbarDesktop.module.css";
+import useTransactions from '@/lib/transaction/hooks/useTransactions';
const Search = dynamic(() => import('./Search'), { ssr: false });
const TopBanner = dynamic(() => import('./TopBanner'), { ssr: false });
@@ -37,6 +40,8 @@ const NavbarDesktop = () => {
const auth = useAuth();
const [cartCount, setCartCount] = useState(0);
+ const [quotationCount, setQuotationCount] = useState(0);
+ // const { setProductQuotation, refreshQuotation, setRefreshQuotation, isLoading, setIsloading } = useProductQuotationContext()
const [templateWA, setTemplateWA] = useState(null);
const [payloadWA, setPayloadWa] = useState(null);
@@ -47,6 +52,16 @@ const NavbarDesktop = () => {
const { product } = useProductContext();
const { isOpen, onOpen, onClose } = useDisclosure();
+ const query = {
+ context: 'quotation',
+ site:
+ (auth?.webRole === null && auth?.site ? auth.site : null),
+ };
+
+ const { transactions } = useTransactions({query});
+ const pendingTransactions = transactions?.data?.saleOrders.filter(transaction => transaction.status === 'draft');
+
+
useEffect(() => {
if (router.pathname === '/shop/product/[slug]') {
setPayloadWa({
@@ -55,11 +70,11 @@ const NavbarDesktop = () => {
url: createSlug('/shop/product/', product?.name, product?.id, true),
});
setTemplateWA('product');
-
+
setUrlPath(router.asPath);
}
}, [product, router]);
-
+
useEffect(() => {
const handleCartChange = () => {
const cart = async () => {
@@ -69,14 +84,36 @@ const NavbarDesktop = () => {
cart();
};
handleCartChange();
-
+
window.addEventListener('localStorageChange', handleCartChange);
-
+
return () => {
window.removeEventListener('localStorageChange', handleCartChange);
};
}, []);
+
+ // useEffect(() => {
+ // setProductQuotation(pendingTransactions)
+ // }, [transactions, ])
+ // console.log("Pending Transactions", pendingTransactions);
+ // console.log("pendingTransactions.length", pendingTransactions.length);
+
+ useEffect(() => {
+ const handleQuotationChange = () => {
+ const quotation = async () => {
+ setQuotationCount(pendingTransactions?.length);
+ };
+ quotation();
+ };
+ handleQuotationChange();
+ window.addEventListener('localStorageChange', handleQuotationChange);
+
+ return () => {
+ window.removeEventListener('localStorageChange', handleQuotationChange);
+ };
+ }, []);
+ console.log("quotationCount",quotationCount)
return (
<DesktopView>
<TopBanner />
@@ -139,17 +176,8 @@ const NavbarDesktop = () => {
<Search />
</div>
<div className='flex gap-x-4 items-center'>
- <Link
- href='/my/transactions'
- target='_blank'
- rel='noreferrer'
- className='flex items-center gap-x-2 !text-gray_r-12/80'
- >
- <DocumentCheckIcon className='w-7' />
- Daftar
- <br />
- Quotation
- </Link>
+
+ <Quotationheader quotationCount={quotationCount} />
<Cardheader cartCount={cartCount} />
diff --git a/src/lib/quotation/components/Quotationheader.jsx b/src/lib/quotation/components/Quotationheader.jsx
new file mode 100644
index 00000000..141b731e
--- /dev/null
+++ b/src/lib/quotation/components/Quotationheader.jsx
@@ -0,0 +1,189 @@
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import { getQuotationApi } from '../api/QuotationApi';
+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 { useProductQuotationContext } from '@/contexts/ProductQuotationContext';
+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';
+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 { productQuotation, setProductQuotation, refreshQuotation, setRefreshQuotation, isLoading, setIsloading } =
+ useProductQuotationContext();
+
+ 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();
+ }
+ };
+ const refreshCartf = useCallback(async () => {
+ setIsloading(true);
+ let { transactions } = await useTransactions({ query });
+ let pendingTransactions = transactions?.data?.saleOrders.filter(transaction => transaction.status === 'draft');
+ setProductQuotation(pendingTransactions);
+ setCountQuotation(pendingTransactions.length);
+ setIsloading(false);
+ }, [setProductQuotation, setIsloading]);
+
+ useEffect(() => {
+ if (refreshQuotation) {
+ refreshCartf();
+ }
+ setRefreshQuotation(false);
+ }, [refreshQuotation, refreshCartf, setRefreshQuotation]);
+
+ useEffect(() => {
+ setCountQuotation(quotationCount.cartCount);
+ }, [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('/shop/quotation');
+ };
+
+ 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>
+ Daftar
+ <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>
+ <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 && qotation.length === 0 && !isLoading && (
+ <div className='justify-center p-4'>
+ <p className='text-gray-500 text-center '>
+ Tidak Ada Quotation
+ </p>
+ </div>
+ )}
+ </div>
+ </motion.div>
+ </motion.div>
+ </>
+ )}
+ </AnimatePresence>
+ </div>
+ );
+};
+
+export default Quotationheader;