diff options
Diffstat (limited to 'src/core/components')
| -rw-r--r-- | src/core/components/elements/Footer/BasicFooter.jsx | 7 | ||||
| -rw-r--r-- | src/core/components/elements/Navbar/NavbarDesktop.jsx | 60 | ||||
| -rw-r--r-- | src/core/components/elements/Navbar/NavbarMobile.jsx | 4 | ||||
| -rw-r--r-- | src/core/components/elements/Navbar/TopBanner.jsx | 33 | ||||
| -rw-r--r-- | src/core/components/layouts/BasicLayout.jsx | 98 | ||||
| -rw-r--r-- | src/core/components/layouts/BasicLayout.module.css | 13 |
6 files changed, 154 insertions, 61 deletions
diff --git a/src/core/components/elements/Footer/BasicFooter.jsx b/src/core/components/elements/Footer/BasicFooter.jsx index 4beea604..8f024d86 100644 --- a/src/core/components/elements/Footer/BasicFooter.jsx +++ b/src/core/components/elements/Footer/BasicFooter.jsx @@ -175,7 +175,7 @@ const CustomerGuide = () => ( <div> <div className={headerClassName}>Bantuan & Panduan</div> <ul className='flex flex-col gap-y-3'> - <li> + <li > <InternalItemLink href='/metode-pembayaran'> Metode Pembayaran </InternalItemLink> @@ -210,6 +210,11 @@ const CustomerGuide = () => ( Panduan Pick Up Service </InternalItemLink> </li> + <li> + <InternalItemLink href='/tracking-order'> + Tracking Order + </InternalItemLink> + </li> </ul> </div> ); diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 2ddf5efe..6454c414 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 "../../../../../src/lib/quotation/components/Quotationheader.jsx" import Category from '@/lib/category/components/Category'; +import { useProductCartContext } from '@/contexts/ProductCartContext'; import { ChevronDownIcon, DocumentCheckIcon, @@ -29,6 +31,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 }); @@ -38,7 +41,8 @@ const NavbarDesktop = () => { const auth = useAuth(); const [cartCount, setCartCount] = useState(0); - + const [quotationCount, setQuotationCount] = useState(0); + const [pendingTransactions, setPendingTransactions] = useState([]) const [templateWA, setTemplateWA] = useState(null); const [payloadWA, setPayloadWa] = useState(null); const [urlPath, setUrlPath] = useState(null); @@ -47,6 +51,17 @@ 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 data = transactions?.data?.saleOrders.filter( + (transaction) => transaction.status === 'draft' + ); const [showPopup, setShowPopup] = useState(false); const [isTop, setIsTop] = useState(true); @@ -89,6 +104,11 @@ const NavbarDesktop = () => { }, []); useEffect(() => { + setPendingTransactions(data); + }, [transactions.data]); + + + useEffect(() => { if (router.pathname === '/shop/product/[slug]') { setPayloadWa({ name: product?.name, @@ -96,11 +116,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 () => { @@ -109,15 +129,31 @@ const NavbarDesktop = () => { }; cart(); }; - handleCartChange(); - + handleCartChange(); + window.addEventListener('localStorageChange', handleCartChange); - + return () => { window.removeEventListener('localStorageChange', handleCartChange); }; }, []); + useEffect(() => { + const handleQuotationChange = () => { + const quotation = async () => { + setQuotationCount(pendingTransactions?.length); + }; + quotation(); + }; + handleQuotationChange(); + + window.addEventListener('localStorageChange', handleQuotationChange); + + return () => { + window.removeEventListener('localStorageChange', handleQuotationChange); + }; + }, [pendingTransactions]); + return ( <DesktopView> <TopBanner onLoad={handleTopBannerLoad} /> @@ -180,17 +216,7 @@ 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} data={pendingTransactions} /> <Cardheader cartCount={cartCount} /> diff --git a/src/core/components/elements/Navbar/NavbarMobile.jsx b/src/core/components/elements/Navbar/NavbarMobile.jsx index bcf45e0a..90314671 100644 --- a/src/core/components/elements/Navbar/NavbarMobile.jsx +++ b/src/core/components/elements/Navbar/NavbarMobile.jsx @@ -11,7 +11,7 @@ import Image from 'next/image'; import { useEffect, useState } from 'react'; import MobileView from '../../views/MobileView'; import Link from '../Link/Link'; -// import TopBanner from './TopBanner'; +import TopBanner from './TopBanner'; const Search = dynamic(() => import('./Search')); @@ -39,7 +39,7 @@ const NavbarMobile = () => { return ( <MobileView> - {/* <TopBanner /> */} + <TopBanner /> <nav className='px-4 py-2 pb-3 sticky top-0 z-50 bg-white shadow'> <div className='flex justify-between items-center mb-2'> <Link href='/'> diff --git a/src/core/components/elements/Navbar/TopBanner.jsx b/src/core/components/elements/Navbar/TopBanner.jsx index 7bc8fb6a..b035eea4 100644 --- a/src/core/components/elements/Navbar/TopBanner.jsx +++ b/src/core/components/elements/Navbar/TopBanner.jsx @@ -1,19 +1,18 @@ import Image from 'next/image'; -import { useQuery } from 'react-query'; - +import { useQuery } from 'react-query';import useDevice from '@/core/hooks/useDevice' import odooApi from '@/core/api/odooApi'; import SmoothRender from '~/components/ui/smooth-render'; import Link from '../Link/Link'; import { useEffect } from 'react'; -const TopBanner = ({ onLoad }) => { +const TopBanner = ({ onLoad = () => {} }) => { const topBanner = useQuery({ queryKey: 'topBanner', queryFn: async () => await odooApi('GET', '/api/v1/banner?type=top-banner'), refetchOnWindowFocus: false, }); - const backgroundColor = topBanner.data?.[0]?.backgroundColor || 'transparent'; + // const backgroundColor = topBanner.data?.[0]?.backgroundColor || 'transparent'; const hasData = topBanner.data?.length > 0; const data = topBanner.data?.[0] || null; @@ -26,21 +25,21 @@ const TopBanner = ({ onLoad }) => { return ( <SmoothRender isLoaded={hasData} - height='36px' + // height='36px' duration='700ms' delay='300ms' - style={{ backgroundColor }} - > - <Link href={data?.url}> - <Image - src={data?.image} - alt={data?.name} - width={1440} - height={40} - className='object-cover object-center h-full mx-auto' - /> - </Link> - </SmoothRender> + className='h-auto' + > + <Link + href={data?.url} + className="block bg-cover bg-center h-3 md:h-6 lg:h-[36px]" + style={{ + backgroundImage: `url('${data?.image}')`, + }} + > + </Link> + + </SmoothRender> ); }; diff --git a/src/core/components/layouts/BasicLayout.jsx b/src/core/components/layouts/BasicLayout.jsx index a4f3a856..5f5f3aca 100644 --- a/src/core/components/layouts/BasicLayout.jsx +++ b/src/core/components/layouts/BasicLayout.jsx @@ -1,12 +1,13 @@ import dynamic from 'next/dynamic'; import Image from 'next/image'; import { useRouter } from 'next/router'; -import { useEffect, useState } from 'react'; +import { useEffect, useState, useRef } from 'react'; import { useProductContext } from '@/contexts/ProductContext'; import odooApi from '@/core/api/odooApi'; import whatsappUrl from '@/core/utils/whatsappUrl'; import Navbar from '../elements/Navbar/Navbar'; +import styles from './BasicLayout.module.css'; // Import modul CSS const AnimationLayout = dynamic(() => import('./AnimationLayout'), { ssr: false, @@ -19,10 +20,15 @@ const BasicLayout = ({ children }) => { const [templateWA, setTemplateWA] = useState(null); const [payloadWA, setPayloadWa] = useState(null); const [urlPath, setUrlPath] = useState(null); + const [highlight, setHighlight] = useState(false); + const [buttonPosition, setButtonPosition] = useState(null); + const [wobble, setWobble] = useState(false); const router = useRouter(); + const buttonRef = useRef(null); const { product } = useProductContext(); + useEffect(() => { if ( router.pathname === '/shop/product/[slug]' || @@ -39,6 +45,32 @@ const BasicLayout = ({ children }) => { } }, [product, router]); + useEffect(() => { + const handleMouseOut = (event) => { + const rect = buttonRef.current.getBoundingClientRect(); + if (event.clientY <= 0) { + setButtonPosition(rect) + setHighlight(true); + } else { + setHighlight(false); + } + }; + + window.addEventListener('mouseout', handleMouseOut); + + return () => { + window.removeEventListener('mouseout', handleMouseOut); + }; + }, []); + + useEffect(() => { + if (highlight) { + // Set wobble animation after overlay highlight animation completes + const timer = setTimeout(() => setWobble(true), 1000); // Adjust timing if needed + return () => clearTimeout(timer); + } + }, [highlight]); + const recordActivity = async (pathname) => { const ONLY_ON_PATH = false; const recordedPath = []; @@ -60,32 +92,50 @@ const BasicLayout = ({ children }) => { return ( <> + {highlight && buttonPosition && ( + <div + className={styles['overlay-highlight']} + style={{ + '--button-x': `${buttonPosition.x + buttonPosition.width / 2}px`, + '--button-y': `${buttonPosition.y + buttonPosition.height / 2}px`, + '--button-radius': `${Math.max(buttonPosition.width, buttonPosition.height) / 2}px` + }} + onAnimationEnd={() => setHighlight(false)} + /> + )} <Navbar /> <AnimationLayout> {children} <div className='fixed bottom-4 right-4 sm:bottom-14 sm:right-10 z-50'> - <a - href={whatsappUrl(templateWA, payloadWA, urlPath)} - className='py-2 pl-3 pr-4 rounded-full bg-[#4FB84A] border border-green-300 flex items-center' - rel='noopener noreferrer' - target='_blank' - > - <Image - src='/images/socials/WHATSAPP.svg' - alt='Whatsapp' - className='block sm:hidden' - width={36} - height={36} - /> - <Image - src='/images/socials/WHATSAPP.svg' - alt='Whatsapp' - className='hidden sm:block' - width={44} - height={44} - /> - <span className='text-white font-bold ml-1.5'>Whatsapp</span> - </a> + <div className='flex flex-row items-center'> + <a href={whatsappUrl(templateWA, payloadWA, urlPath)} className='flex flex-row items-center' rel='noopener noreferrer' target='_blank'> + <span className={`text-green-300 text-lg font-bold mr-4 ${wobble ? 'animate-wobble' : ''}`} onAnimationEnd={() => setWobble(false)}> + Whatsapp + </span> + </a> + <a + href={whatsappUrl(templateWA, payloadWA, urlPath)} + className='elemen-whatsapp p-4 rounded-full bg-[#4FB84A] border border-green-300 flex items-center' + rel='noopener noreferrer' + target='_blank' + ref={buttonRef} + > + <Image + src='/images/socials/WHATSAPP.svg' + alt='Whatsapp' + className='block sm:hidden' + width={36} + height={36} + /> + <Image + src='/images/socials/WHATSAPP.svg' + alt='Whatsapp' + className='hidden sm:block' + width={44} + height={44} + /> + </a> + </div> </div> </AnimationLayout> <BasicFooter /> @@ -93,4 +143,4 @@ const BasicLayout = ({ children }) => { ); }; -export default BasicLayout; +export default BasicLayout;
\ No newline at end of file diff --git a/src/core/components/layouts/BasicLayout.module.css b/src/core/components/layouts/BasicLayout.module.css new file mode 100644 index 00000000..4945c420 --- /dev/null +++ b/src/core/components/layouts/BasicLayout.module.css @@ -0,0 +1,13 @@ +.overlay-highlight { + @apply fixed top-0 left-0 w-full h-full bg-[#4FB84A]/30 z-[900]; + animation: closeOverlay 1s forwards; + } + + @keyframes closeOverlay { + from { + clip-path: circle(100% at 50% 50%); + } + to { + clip-path: circle(var(--button-radius) at var(--button-x) var(--button-y)); + } + } |
