diff options
Diffstat (limited to 'src/core/components')
9 files changed, 327 insertions, 54 deletions
diff --git a/src/core/components/elements/Footer/BasicFooter.jsx b/src/core/components/elements/Footer/BasicFooter.jsx index 6129143d..4beea604 100644 --- a/src/core/components/elements/Footer/BasicFooter.jsx +++ b/src/core/components/elements/Footer/BasicFooter.jsx @@ -259,7 +259,7 @@ const InformationCenter = () => ( <li className='text-gray_r-12/80 flex items-center'> <PhoneArrowUpRightIcon className='w-[18px] mr-2' /> <a href='tel:02129338828' target='_blank' rel='noreferrer'> - (021) 2933-8828 / 29 + (021) 2933-8828 </a> </li> <li className='text-gray_r-12/80 flex items-center'> diff --git a/src/core/components/elements/Footer/PromoOffer.tsx b/src/core/components/elements/Footer/PromoOffer.tsx new file mode 100644 index 00000000..a5432b6a --- /dev/null +++ b/src/core/components/elements/Footer/PromoOffer.tsx @@ -0,0 +1,112 @@ + +import React from "react"; +// import { useGeneralSetting } from "@/common/state-management/general-setting"; +import { FormEvent, useEffect, useState } from "react"; +import toast from "react-hot-toast"; +import style from "../Footer/style/promoOffer.module.css" +const PromoOffer = ()=>{ + // const { data, isLoading, fetchData } = useGeneralSetting(); + const [formData, setFormData] = useState<FormData>({ + email: "", + name: "", + telephone: "", + message: "", + }); + + useEffect(() => { + // fetchData(); + }, []); + + type FormData = { + email: string; + name: string; + telephone: string; + message: string; + }; + + const [errors, setErrors] = useState({ + email: false, + name: false, + message: false, + }); + + +const handleGetOffer = async (e: FormEvent) => { + e.preventDefault(); + let loadingToast; + try { + loadingToast = toast.loading("Mengirimkan formulir..."); + const response = await fetch("/api/contactus", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ ...formData, from: "newsletter" }), + }); + + if (response.ok) { + toast.dismiss(loadingToast); + toast.success("Terima kasih telah menghubungi kami"); + setFormData({ + email: "", + name: "", + telephone: "", + message: "", + }); + } else { + toast.dismiss(loadingToast); + toast.error("Gagal mengirimkan formulir. Silakan coba lagi nanti."); + } + } catch (error) { + toast.dismiss(loadingToast); + console.error("Gagal mengirimkan formulir", error); + toast.error("Terjadi kesalahan. Silakan coba lagi nanti."); + } + }; + + + + + return( + <div className=" py-3 mb-3"> + <div className="md:flex container mx-auto md:justify-between md:items-center md:gap-x-20"> + <div className=""> + <span className="text-black font-semibold text-sm md:text-lg"> + Dapatkan Promo Menarik Setiap Bulan{" "} + </span> + <p> + Promo produk dengan penawaran terbatas setiap bulannya! + </p> + </div> + <div className=" flex-1 flex items-center h-full justify-end text-sm text-slate-950"> + <form onSubmit={handleGetOffer} className={style['form-input']}> + <div className="flex justify-start w-full"> + <div className="flex justify-end"> + <input + type="email" + value={formData.email} + onChange={(e) => + setFormData({ ...formData, email: e.target.value }) + } + className={style['input']} + placeholder="Masukkan email anda disini" + /> + <button + type="submit" + className={style['button']} + > + Dapatkan + </button> + </div> + + + </div> + </form> + + </div> + </div> + </div> + ) + }; + + export default PromoOffer; diff --git a/src/core/components/elements/Footer/style/promoOffer.module.css b/src/core/components/elements/Footer/style/promoOffer.module.css new file mode 100644 index 00000000..3184182d --- /dev/null +++ b/src/core/components/elements/Footer/style/promoOffer.module.css @@ -0,0 +1,39 @@ +.form-input { + @apply + h-full + w-[514px] + text-slate-950 + flex + justify-center; +} + +.input{ + @apply w-[320px] + sm:w-[320px] + md:w-[500px] + xl:w-[514px] + lg:w-[514px] + 2xl:w-[514px] + text-black + py-2 + h-11 + md:py-3 + px-4 + bg-[#FDF1C7] + rounded-3xl + focus:outline-none + ; +} + +.button{ + @apply bg-[#FAD147] + absolute + py-1.5 + rounded-3xl + text-black + md:py-2.5 + px-4 + h-11 + z-0 + ; +}
\ No newline at end of file diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 9de761a2..6454c414 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -5,16 +5,19 @@ 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, HeartIcon, + ArrowUpRightIcon, } from '@heroicons/react/24/outline'; import dynamic from 'next/dynamic'; import Image from 'next/image'; import { useRouter } from 'next/router'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import DesktopView from '../../views/DesktopView'; import Link from '../Link/Link'; import NavbarUserDropdown from './NavbarUserDropdown'; @@ -27,6 +30,8 @@ import { MenuList, 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 }); @@ -36,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); @@ -45,8 +51,64 @@ 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); + + const handleTopBannerLoad = useCallback(() => { + const showTimer = setTimeout(() => { + setShowPopup(true); + }, 500); + + const hideTimer = setTimeout(() => { + // setShowPopup(false); + }, 9500); + + return () => { + clearTimeout(showTimer); + clearTimeout(hideTimer); + }; + }, []); + + useEffect(() => { + const handleScroll = () => { + setIsTop(window.scrollY < 100); + }; + + window.addEventListener('scroll', handleScroll); + return () => { + window.removeEventListener('scroll', handleScroll); + }; + }, []); + + useEffect(() => { + const handleScroll = () => { + setIsTop(window.scrollY < 100); + }; + + window.addEventListener('scroll', handleScroll); + return () => { + window.removeEventListener('scroll', handleScroll); + }; + }, []); useEffect(() => { + setPendingTransactions(data); + }, [transactions.data]); + + + useEffect(() => { if (router.pathname === '/shop/product/[slug]') { setPayloadWa({ name: product?.name, @@ -54,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 () => { @@ -67,18 +129,34 @@ 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 /> + <TopBanner onLoad={handleTopBannerLoad} /> <div className='py-2 bg-warning-400' id='desktop-nav-top'> <div className='container mx-auto flex justify-between'> <div className='flex items-start gap-5'> @@ -138,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} /> @@ -203,45 +271,76 @@ const NavbarDesktop = () => { </div> </button> <div className='w-6/12 flex px-1 divide-x divide-gray_r-6'> + + <Link + href="/shop/promo" + className={`${ + router.asPath === '/shop/promo' && 'bg-gray_r-3' + } flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition group relative`} // Added relative position + target="_blank" + rel="noreferrer" + > + {showPopup && ( + <div className='w-full h-full relative justify-end items-start'> + <Image + src='/images/penawaran-terbatas.jpg' + alt='penawaran terbatas' + width={1440} + height={160} + quality={100} + // className={`fixed ${isTop ? 'md:top-[145px] lg:top-[160px] ' : 'lg:top-[85px] top-[80px]'} rounded-3xl md:left-1/4 lg:left-1/4 xl:left-1/4 left-2/3 w-40 h-12 p-2 z-50 transition-all duration-300 animate-pulse`} + className={`inline-block relative -top-8 transition-all duration-300 z-20 animate-pulse`} + /> + </div> + )} + <p className="absolute inset-0 flex justify-center items-center group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200 z-10">Semua Promo</p> + </Link> + {/* {showPopup && router.pathname === '/' && ( + <div className={`fixed ${isTop ? 'top-[170px]' : 'top-[90px]'} rounded-3xl left-[700px] w-fit object-center bg-green-50 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20 text-center p-2 z-50 transition-all duration-300`}> + <p className='w-36 h-3'> + Penawaran Terbatas + </p> + </div> + )} */} + + <Link href='/shop/brands' - className={`${ + className={`${ router.asPath === '/shop/brands' && 'bg-gray_r-3' - } p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition`} + } p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition group`} target='_blank' rel='noreferrer' > - Semua Brand + <p className="group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200">Semua Brand</p> </Link> <Link href='/shop/search?orderBy=stock' className={`${ router.asPath === '/shop/search?orderBy=stock' && 'bg-gray_r-3' - } p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition`} + } p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition group`} target='_blank' rel='noreferrer' > - Ready Stock + <p className="group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200">Ready Stock</p> </Link> <Link href='https://blog.indoteknik.com/' - className='p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition' + className='p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition group' target='_blank' rel='noreferrer noopener' > - Blog Indoteknik + <p className="group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200">Blog Indoteknik</p> </Link> - <Link + {/* <Link href='/video' - className={`${ - router.asPath === '/video' && 'bg-gray_r-3' - } p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition`} + className='p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition' target='_blank' rel='noreferrer' > Indoteknik TV - </Link> + </Link> */} </div> <div className='w-3/12 flex gap-x-1 relative'> 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 722a7501..302db5c4 100644 --- a/src/core/components/elements/Navbar/TopBanner.jsx +++ b/src/core/components/elements/Navbar/TopBanner.jsx @@ -1,39 +1,45 @@ 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 = () => { +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; + useEffect(() => { + if (hasData) { + onLoad(); + } + }, [hasData, 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/elements/Navbar/style/NavbarDesktop.module.css b/src/core/components/elements/Navbar/style/NavbarDesktop.module.css new file mode 100644 index 00000000..9cddb127 --- /dev/null +++ b/src/core/components/elements/Navbar/style/NavbarDesktop.module.css @@ -0,0 +1,14 @@ +/* navbarDesktop.module.css */ +@keyframes blink { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0; + } +} + +.blink { + animation: blink 0.8s infinite; +} + diff --git a/src/core/components/elements/Sidebar/Sidebar.jsx b/src/core/components/elements/Sidebar/Sidebar.jsx index 38fcdef8..55838890 100644 --- a/src/core/components/elements/Sidebar/Sidebar.jsx +++ b/src/core/components/elements/Sidebar/Sidebar.jsx @@ -117,6 +117,9 @@ const Sidebar = ({ active, close }) => { </> )} </div> + <SidebarLink className={itemClassName} href='/shop/promo'> + Semua Promo + </SidebarLink> <SidebarLink className={itemClassName} href='/shop/brands'> Semua Brand </SidebarLink> @@ -128,9 +131,9 @@ const Sidebar = ({ active, close }) => { > Blog Indoteknik </SidebarLink> - <SidebarLink className={itemClassName} href='/video'> + {/* <SidebarLink className={itemClassName} href='/video'> Indoteknik TV - </SidebarLink> + </SidebarLink> */} <SidebarLink className={itemClassName} href='/tentang-kami'> Tentang Indoteknik </SidebarLink> diff --git a/src/core/components/layouts/BasicLayout.jsx b/src/core/components/layouts/BasicLayout.jsx index a4f3a856..ba51022d 100644 --- a/src/core/components/layouts/BasicLayout.jsx +++ b/src/core/components/layouts/BasicLayout.jsx @@ -93,4 +93,4 @@ const BasicLayout = ({ children }) => { ); }; -export default BasicLayout; +export default BasicLayout;
\ No newline at end of file |
