summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/components/ScrollToTop.jsx24
-rw-r--r--src/core/components/elements/Footer/BasicFooter.jsx127
-rw-r--r--src/core/components/elements/Footer/SimpleFooter.jsx2
-rw-r--r--src/core/components/elements/Navbar/NavbarDesktop.jsx238
-rw-r--r--src/core/components/elements/Navbar/NavbarMobile.jsx69
-rw-r--r--src/core/components/elements/Navbar/NavbarUserDropdown.jsx5
-rw-r--r--src/core/components/elements/Navbar/TopBanner.jsx61
-rw-r--r--src/core/components/elements/Skeleton/TopBannerSkeleton.jsx24
-rw-r--r--src/core/components/layouts/AppLayout.jsx18
-rw-r--r--src/core/components/layouts/BasicLayout.jsx90
-rw-r--r--src/core/utils/auth.js2
-rw-r--r--src/core/utils/googleTag.js26
-rw-r--r--src/core/utils/slug.js34
-rw-r--r--src/core/utils/whatsappUrl.js2
14 files changed, 459 insertions, 263 deletions
diff --git a/src/core/components/ScrollToTop.jsx b/src/core/components/ScrollToTop.jsx
new file mode 100644
index 00000000..f8e85167
--- /dev/null
+++ b/src/core/components/ScrollToTop.jsx
@@ -0,0 +1,24 @@
+import { useEffect } from 'react';
+import { useRouter } from 'next/router';
+
+const ScrollToTop = () => {
+ const router = useRouter();
+
+ useEffect(() => {
+ const handleRouteChange = (url, { shallow }) => {
+ if (!shallow) {
+ window.scrollTo(0, 0);
+ }
+ };
+
+ router.events.on('routeChangeComplete', handleRouteChange);
+
+ return () => {
+ router.events.off('routeChangeComplete', handleRouteChange);
+ };
+ }, [router.events]);
+
+ return null;
+};
+
+export default ScrollToTop;
diff --git a/src/core/components/elements/Footer/BasicFooter.jsx b/src/core/components/elements/Footer/BasicFooter.jsx
index 28a3764c..6129143d 100644
--- a/src/core/components/elements/Footer/BasicFooter.jsx
+++ b/src/core/components/elements/Footer/BasicFooter.jsx
@@ -41,6 +41,8 @@ const BasicFooter = () => {
<Form />
<CustomerGuide />
<Payments />
+ <Shippings />
+ <Secures />
</div>
<div className='w-full mt-8 leading-5 text-caption-2 text-gray_r-12/80'>
@@ -53,7 +55,7 @@ const BasicFooter = () => {
<DesktopView>
<footer className='bg-gray_r-3 py-6'>
<div className='container mx-auto flex flex-wrap justify-between'>
- <div className='w-3/12'>
+ <div className='w-4/12'>
<NextImage
src={IndoteknikLogo}
alt='Logo Indoteknik'
@@ -64,27 +66,40 @@ const BasicFooter = () => {
PT. Indoteknik Dotcom Gemilang
</div>
<InformationCenter />
+ <div className='h-4' />
+ <OfficeLocation />
+ <div className='h-4' />
+ <OpenHours />
</div>
- <CustomerGuide />
- <Form />
- <AboutUs />
+
+ <div className='w-2/12'>
+ <CustomerGuide />
+ <div className='h-6' />
+ <Form />
+ </div>
+
+ <div className='w-2/12'>
+ <AboutUs />
+ </div>
+
<div className='w-3/12'>
- <div className='grid grid-cols-1 gap-y-4'>
- <OfficeLocation />
- {/* <WarehouseLocation /> */}
- <OpenHours />
+ <div className='grid grid-cols-1 gap-y-6'>
<Payments />
+ <Shippings />
+ <Secures />
</div>
</div>
+
<hr className='w-full my-4 border-gray_r-7' />
+
<div className='w-full flex justify-between items-center'>
<div className='text-caption-1'>
Copyright © 2007 - {new Date().getFullYear()}, PT. Indoteknik
Dotcom Gemilang
</div>
- <div>
+ {/* <div>
<SocialMedias />
- </div>
+ </div> */}
</div>
</div>
</footer>
@@ -256,7 +271,7 @@ const InformationCenter = () => (
<li className='text-gray_r-12/80 flex items-center'>
<DevicePhoneMobileIcon className='w-[18px] mr-2' />
<a href={whatsappUrl()} target='_blank' rel='noreferrer'>
- 0812-8080-622
+ 0817-1718-1922
</a>
</li>
</ul>
@@ -286,7 +301,7 @@ const SocialMedias = () => (
<a
target='_blank'
rel='noreferrer'
- href='https://www.youtube.com/@indoteknikb2bindustriale-c778'
+ href='https://www.youtube.com/@indoteknikcom'
>
<NextImage
src='/images/socials/youtube.webp'
@@ -369,57 +384,43 @@ const SocialMedias = () => (
const Payments = () => (
<div>
- <div className={headerClassName}>Pembayaran</div>
- <div className='flex flex-wrap gap-2'>
- <NextImage
- src='/images/payments/bca.png'
- alt='Bank BCA Logo'
- width={48}
- height={24}
- />
- <NextImage
- src='/images/payments/bni.png'
- alt='Bank BNI Logo'
- width={48}
- height={24}
- />
- <NextImage
- src='/images/payments/bri.png'
- alt='Bank BRI Logo'
- width={48}
- height={24}
- />
- <NextImage
- src='/images/payments/gopay.png'
- alt='Gopay Logo'
- width={48}
- height={24}
- />
- <NextImage
- src='/images/payments/mandiri.png'
- alt='Bank Mandiri Logo'
- width={48}
- height={24}
- />
- <NextImage
- src='/images/payments/mastercard.png'
- alt='Mastercard Logo'
- width={48}
- height={24}
- />
- <NextImage
- src='/images/payments/permata.png'
- alt='Bank Permata Logo'
- width={48}
- height={24}
- />
- <NextImage
- src='/images/payments/visa.png'
- alt='Visa Logo'
- width={48}
- height={24}
- />
- </div>
+ <div className={headerClassName}>Metode Pembayaran</div>
+ <NextImage
+ src='/images/footer/payment-method-new.png'
+ alt='Metode Pembayaran - Indoteknik'
+ width={512}
+ height={512}
+ quality={100}
+ className='w-full'
+ />
+ </div>
+);
+
+const Shippings = () => (
+ <div>
+ <div className={headerClassName}>Jasa Pengiriman</div>
+ <NextImage
+ src='/images/footer/shippings.png'
+ alt='Jasa Pengiriman - Indoteknik'
+ width={512}
+ height={512}
+ quality={100}
+ className='w-full'
+ />
+ </div>
+);
+
+const Secures = () => (
+ <div>
+ <div className={headerClassName}>Keamanan Belanja</div>
+ <NextImage
+ src='/images/footer/secures.png'
+ alt='Keamanan Belanja - Indoteknik'
+ width={512}
+ height={512}
+ quality={100}
+ className='w-full'
+ />
</div>
);
diff --git a/src/core/components/elements/Footer/SimpleFooter.jsx b/src/core/components/elements/Footer/SimpleFooter.jsx
index 26f7f786..371b1652 100644
--- a/src/core/components/elements/Footer/SimpleFooter.jsx
+++ b/src/core/components/elements/Footer/SimpleFooter.jsx
@@ -22,7 +22,7 @@ const SimpleFooter = () => (
<li className='text-gray_r-12/80 flex items-center'>
<DevicePhoneMobileIcon className='w-[18px] mr-2' />
<a href={whatsappUrl()} target='_blank' rel='noreferrer'>
- 0812-8080-622
+ 081717181922
</a>
</li>
</ul>
diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx
index d9f5658e..308f2623 100644
--- a/src/core/components/elements/Navbar/NavbarDesktop.jsx
+++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx
@@ -1,85 +1,86 @@
+import { useProductContext } from '@/contexts/ProductContext';
+import useAuth from '@/core/hooks/useAuth';
+import { getCountCart } from '@/core/utils/cart';
+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 Category from '@/lib/category/components/Category';
import {
ChevronDownIcon,
+ DocumentCheckIcon,
HeartIcon,
- ShoppingCartIcon,
- DocumentCheckIcon
-} from '@heroicons/react/24/outline'
-import Link from '../Link/Link'
-import Image from 'next/image'
-import DesktopView from '../../views/DesktopView'
-import dynamic from 'next/dynamic'
-import IndoteknikLogo from '@/images/logo.png'
-import Category from '@/lib/category/components/Category'
-import { useCallback, useContext, useEffect, useState } from 'react'
-import useAuth from '@/core/hooks/useAuth'
-import NavbarUserDropdown from './NavbarUserDropdown'
-import { getCartApi, getCountCart } from '@/core/utils/cart'
-import whatsappUrl from '@/core/utils/whatsappUrl'
-import { useRouter } from 'next/router'
-import { getAuth, setAuth } from '@/core/utils/auth'
-import { createSlug, getIdFromSlug } from '@/core/utils/slug'
-import { TopBannerSkeleton } from '../Skeleton/TopBannerSkeleton'
-import { useProductContext } from '@/contexts/ProductContext'
-import Cardheader from '@/lib/cart/components/Cartheader'
-
-const Search = dynamic(() => import('./Search'))
-const TopBanner = dynamic(() => import('./TopBanner'), {
- loading: () => <TopBannerSkeleton />
-})
+} 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 DesktopView from '../../views/DesktopView';
+import Link from '../Link/Link';
+import NavbarUserDropdown from './NavbarUserDropdown';
+import NextImage from 'next/image';
+
+const Search = dynamic(() => import('./Search'), { ssr: false });
+const TopBanner = dynamic(() => import('./TopBanner'), { ssr: false });
const NavbarDesktop = () => {
- const [isOpenCategory, setIsOpenCategory] = useState(false)
- const auth = useAuth()
+ const [isOpenCategory, setIsOpenCategory] = useState(false);
+ const auth = useAuth();
- const [cartCount, setCartCount] = useState(0)
+ const [cartCount, setCartCount] = useState(0);
- const [templateWA, setTemplateWA] = useState(null)
- const [payloadWA, setPayloadWa] = useState(null)
- const [urlPath, setUrlPath] = useState(null)
+ const [templateWA, setTemplateWA] = useState(null);
+ const [payloadWA, setPayloadWa] = useState(null);
+ const [urlPath, setUrlPath] = useState(null);
- const router = useRouter()
+ const router = useRouter();
- const { product } = useProductContext()
+ const { product } = useProductContext();
useEffect(() => {
if (router.pathname === '/shop/product/[slug]') {
setPayloadWa({
name: product?.name,
manufacture: product?.manufacture.name,
- url: createSlug('/shop/product/', product?.name, product?.id, true)
- })
- setTemplateWA('product')
+ url: createSlug('/shop/product/', product?.name, product?.id, true),
+ });
+ setTemplateWA('product');
- setUrlPath(router.asPath)
+ setUrlPath(router.asPath);
}
- }, [product, router])
+ }, [product, router]);
useEffect(() => {
const handleCartChange = () => {
const cart = async () => {
- const listCart = await getCountCart()
- setCartCount(listCart)
- }
- cart()
- }
- handleCartChange()
+ const listCart = await getCountCart();
+ setCartCount(listCart);
+ };
+ cart();
+ };
+ handleCartChange();
- window.addEventListener('localStorageChange', handleCartChange)
+ window.addEventListener('localStorageChange', handleCartChange);
return () => {
- window.removeEventListener('localStorageChange', handleCartChange)
- }
- }, [])
+ window.removeEventListener('localStorageChange', handleCartChange);
+ };
+ }, []);
return (
<DesktopView>
<TopBanner />
- <div className='py-3 bg-warning-400' id='desktop-nav-top'>
+ <div className='py-2 bg-warning-400' id='desktop-nav-top'>
<div className='container mx-auto flex justify-between'>
- <Link href='/tentang-kami' className='!text-gray_r-12'>
- Tentang Indoteknik.com
- </Link>
+ <div className='flex items-start gap-5'>
+ <div>
+ <SocialMedias />
+ </div>
+ </div>
<div className='flex gap-x-6'>
+ <Link href='/tentang-kami' className='!text-gray_r-12'>
+ Tentang Indoteknik.com
+ </Link>
<Link href='/my/pembayaran-tempo' className='!text-gray_r-12'>
Pembayaran Tempo
</Link>
@@ -93,7 +94,12 @@ const NavbarDesktop = () => {
<nav className='pt-6 sticky top-0 z-50 bg-white border-b-2 border-danger-500'>
<div className='container mx-auto flex gap-x-6'>
<Link href='/'>
- <Image src={IndoteknikLogo} alt='Indoteknik Logo' width={210} height={210 / 3} />
+ <Image
+ src={IndoteknikLogo}
+ alt='Indoteknik Logo'
+ width={210}
+ height={210 / 3}
+ />
</Link>
<div className='flex-1 flex items-center'>
<Search />
@@ -128,10 +134,15 @@ const NavbarDesktop = () => {
rel='noreferrer'
className='flex items-center gap-x-1 !text-gray_r-12/80'
>
- <Image src='/images/socials/Whatsapp-2.png' alt='Whatsapp' width={48} height={48} />
+ <Image
+ src='/images/socials/Whatsapp-2.png'
+ alt='Whatsapp'
+ width={48}
+ height={48}
+ />
<div>
<div className='font-semibold'>Whatsapp</div>
- 0812 8080 622 (Chat)
+ 0817 1718 1922 (Chat)
</div>
</a>
</div>
@@ -146,16 +157,24 @@ const NavbarDesktop = () => {
className='w-3/12 p-4 font-semibold border border-gray_r-6 rounded-t-xl flex items-center relative'
>
<div>Kategori Produk</div>
- <ChevronDownIcon className={`ml-auto w-6 ${isOpenCategory ? 'rotate-180' : ''}`} />
+ <ChevronDownIcon
+ className={`ml-auto w-6 ${isOpenCategory ? 'rotate-180' : ''}`}
+ />
- <div className={`category-mega-box-wrapper ${isOpenCategory ? 'show' : ''}`}>
+ <div
+ className={`category-mega-box-wrapper ${
+ isOpenCategory ? 'show' : ''
+ }`}
+ >
<Category />
</div>
</button>
<div className='w-6/12 flex px-1 divide-x divide-gray_r-6'>
<Link
href='/shop/brands'
- className='p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition'
+ 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`}
target='_blank'
rel='noreferrer'
>
@@ -163,7 +182,10 @@ const NavbarDesktop = () => {
</Link>
<Link
href='/shop/search?orderBy=stock'
- className='p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition'
+ 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`}
target='_blank'
rel='noreferrer'
>
@@ -179,7 +201,9 @@ const NavbarDesktop = () => {
</Link>
<Link
href='/video'
- className='p-4 flex-1 flex justify-center items-center !text-gray_r-12/80 hover:bg-gray_r-3 idt-transition'
+ 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`}
target='_blank'
rel='noreferrer'
>
@@ -220,7 +244,95 @@ const NavbarDesktop = () => {
</div>
</nav>
</DesktopView>
- )
-}
+ );
+};
+
+const SocialMedias = () => (
+ <div>
+ {/* <div className={headerClassName + 'block md:hidden'}>Temukan Kami</div> */}
+ <div className='flex flex-wrap gap-3 items-start'>
+ <a
+ target='_blank'
+ rel='noreferrer'
+ href='https://www.youtube.com/@indoteknikcom'
+ >
+ <NextImage
+ src='/images/socials/youtube.webp'
+ alt='Youtube - Indoteknik.com'
+ width={24}
+ height={24}
+ />
+ </a>
+ <a
+ target='_blank'
+ rel='noreferrer'
+ href='https://www.tiktok.com/@indoteknikcom'
+ >
+ <NextImage
+ src='/images/socials/tiktok.png'
+ alt='TikTok - Indoteknik.com'
+ width={24}
+ height={24}
+ />
+ </a>
+ {/* <a target='_blank' rel='noreferrer' href={whatsappUrl(null)}>
+ <NextImage
+ src='/images/socials/Whatsapp.png'
+ alt='Whatsapp - Indoteknik.com'
+ width={24}
+ height={24}
+ />
+ </a> */}
+ <a
+ target='_blank'
+ rel='noreferrer'
+ href='https://www.facebook.com/indoteknikcom'
+ >
+ <NextImage
+ src='/images/socials/Facebook.png'
+ alt='Facebook - Indoteknik.com'
+ width={24}
+ height={24}
+ />
+ </a>
+ <a
+ target='_blank'
+ rel='noreferrer'
+ href='https://www.instagram.com/indoteknikcom/'
+ >
+ <NextImage
+ src='/images/socials/Instagram.png'
+ alt='Instagram - Indoteknik.com'
+ width={24}
+ height={24}
+ />
+ </a>
+ <a
+ target='_blank'
+ rel='noreferrer'
+ href='https://www.linkedin.com/company/pt-indoteknik-dotcom-gemilang/'
+ >
+ <NextImage
+ src='/images/socials/Linkedin.png'
+ alt='Linkedin - Indoteknik.com'
+ width={24}
+ height={24}
+ />
+ </a>
+ <a
+ target='_blank'
+ rel='noreferrer'
+ href='https://goo.gl/maps/GF8EmDjpQTHZPsJ1A'
+ >
+ <NextImage
+ src='/images/socials/g_maps.png'
+ alt='Maps - Indoteknik.com'
+ width={24}
+ height={24}
+ />
+ </a>
+ </div>
+ </div>
+);
-export default NavbarDesktop
+export default NavbarDesktop;
diff --git a/src/core/components/elements/Navbar/NavbarMobile.jsx b/src/core/components/elements/Navbar/NavbarMobile.jsx
index 704e91b6..bcf45e0a 100644
--- a/src/core/components/elements/Navbar/NavbarMobile.jsx
+++ b/src/core/components/elements/Navbar/NavbarMobile.jsx
@@ -1,51 +1,60 @@
-import Image from 'next/image'
-import MobileView from '../../views/MobileView'
-import Link from '../Link/Link'
-import { Bars3Icon, HeartIcon, ShoppingCartIcon } from '@heroicons/react/24/outline'
-import useSidebar from '@/core/hooks/useSidebar'
-import dynamic from 'next/dynamic'
-import IndoteknikLogo from '@/images/logo.png'
-import { useEffect, useState } from 'react'
-import { getCart, getCountCart } from '@/core/utils/cart'
-import TopBanner from './TopBanner'
+import useSidebar from '@/core/hooks/useSidebar';
+import { getCountCart } from '@/core/utils/cart';
+import IndoteknikLogo from '@/images/logo.png';
+import {
+ Bars3Icon,
+ HeartIcon,
+ ShoppingCartIcon,
+} from '@heroicons/react/24/outline';
+import dynamic from 'next/dynamic';
+import Image from 'next/image';
+import { useEffect, useState } from 'react';
+import MobileView from '../../views/MobileView';
+import Link from '../Link/Link';
+// import TopBanner from './TopBanner';
-const Search = dynamic(() => import('./Search'))
+const Search = dynamic(() => import('./Search'));
const NavbarMobile = () => {
- const { Sidebar, open } = useSidebar()
+ const { Sidebar, open } = useSidebar();
- const [cartCount, setCartCount] = useState(0)
+ const [cartCount, setCartCount] = useState(0);
useEffect(() => {
const handleCartChange = () => {
const cart = async () => {
- const listCart = await getCountCart()
- setCartCount(listCart)
- }
- cart()
- }
- handleCartChange()
+ const listCart = await getCountCart();
+ setCartCount(listCart);
+ };
+ cart();
+ };
+ handleCartChange();
- window.addEventListener('localStorageChange', handleCartChange)
+ window.addEventListener('localStorageChange', handleCartChange);
return () => {
- window.removeEventListener('localStorageChange', handleCartChange)
- }
- }, [])
+ window.removeEventListener('localStorageChange', handleCartChange);
+ };
+ }, []);
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='/'>
- <Image src={IndoteknikLogo} alt='Indoteknik Logo' width={120} height={40} />
+ <Image
+ src={IndoteknikLogo}
+ alt='Indoteknik Logo'
+ width={120}
+ height={40}
+ />
</Link>
<div className='flex gap-x-3'>
- <Link href='/my/wishlist'>
+ <Link href='/my/wishlist' aria-label='Wishlist'>
<HeartIcon className='w-6 text-gray_r-12' />
</Link>
- <Link href='/shop/cart' className='relative'>
+ <Link href='/shop/cart' className='relative' aria-label='Cart'>
<ShoppingCartIcon className='w-6 text-gray_r-12' />
{cartCount > 0 && (
<span className='absolute -top-2 -right-2 badge-solid-red rounded-full w-5 h-5 flex items-center justify-center'>
@@ -62,7 +71,7 @@ const NavbarMobile = () => {
</nav>
{Sidebar}
</MobileView>
- )
-}
+ );
+};
-export default NavbarMobile
+export default NavbarMobile;
diff --git a/src/core/components/elements/Navbar/NavbarUserDropdown.jsx b/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
index 1851ce84..42bdc12a 100644
--- a/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
+++ b/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
@@ -2,9 +2,11 @@ import { deleteAuth } from '@/core/utils/auth'
import Link from '../Link/Link'
import { useRouter } from 'next/router'
import { signOut, useSession } from 'next-auth/react'
+import useAuth from '@/core/hooks/useAuth'
const NavbarUserDropdown = () => {
const router = useRouter()
+ const atuh = useAuth()
const logout = async () => {
deleteAuth().then(() => {
@@ -21,6 +23,9 @@ const NavbarUserDropdown = () => {
<Link href='/my/invoices'>Invoice & Faktur Pajak</Link>
<Link href='/my/wishlist'>Wishlist</Link>
<Link href='/my/address'>Daftar Alamat</Link>
+ {!atuh?.external &&
+ <Link href='/my/recomendation'>Dashboard Recomendation</Link>
+ }
<button type='button' onClick={logout}>
Keluar Akun
</button>
diff --git a/src/core/components/elements/Navbar/TopBanner.jsx b/src/core/components/elements/Navbar/TopBanner.jsx
index a757c260..722a7501 100644
--- a/src/core/components/elements/Navbar/TopBanner.jsx
+++ b/src/core/components/elements/Navbar/TopBanner.jsx
@@ -1,33 +1,40 @@
-import odooApi from '@/core/api/odooApi'
-import { useQuery } from 'react-query'
-import Image from 'next/image'
-import Link from '../Link/Link'
-import { TopBannerSkeleton } from '../Skeleton/TopBannerSkeleton'
+import Image from 'next/image';
+import { useQuery } from 'react-query';
+
+import odooApi from '@/core/api/odooApi';
+import SmoothRender from '~/components/ui/smooth-render';
+import Link from '../Link/Link';
const TopBanner = () => {
- const fetchTopBanner = async () => await odooApi('GET', '/api/v1/banner?type=top-banner')
- const topBanner = useQuery('topBanner', fetchTopBanner, { refetchOnWindowFocus: false })
+ const topBanner = useQuery({
+ queryKey: 'topBanner',
+ queryFn: async () => await odooApi('GET', '/api/v1/banner?type=top-banner'),
+ refetchOnWindowFocus: false,
+ });
- if (topBanner.isLoading) {
- return <TopBannerSkeleton />
- }
+ const backgroundColor = topBanner.data?.[0]?.backgroundColor || 'transparent';
+ const hasData = topBanner.data?.length > 0;
+ const data = topBanner.data?.[0] || null;
return (
- topBanner.isFetched &&
- topBanner.data?.length > 0 && (
- <div style={{ backgroundColor: topBanner.data[0]?.backgroundColor || 'transparent' }}>
- <Link href={topBanner.data[0]?.url}>
- <Image
- src={topBanner.data[0].image}
- alt={topBanner.data[0].name}
- width={1440}
- height={40}
- className='object-cover object-center h-full mx-auto'
- />
- </Link>
- </div>
- )
- )
-}
+ <SmoothRender
+ isLoaded={hasData}
+ 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>
+ );
+};
-export default TopBanner
+export default TopBanner;
diff --git a/src/core/components/elements/Skeleton/TopBannerSkeleton.jsx b/src/core/components/elements/Skeleton/TopBannerSkeleton.jsx
index f7d2e748..8d1a51d2 100644
--- a/src/core/components/elements/Skeleton/TopBannerSkeleton.jsx
+++ b/src/core/components/elements/Skeleton/TopBannerSkeleton.jsx
@@ -1,19 +1,17 @@
-import useDevice from '@/core/hooks/useDevice'
-import classNames from 'classnames'
-import Skeleton from 'react-loading-skeleton'
+import useDevice from '@/core/hooks/useDevice';
+import classNames from 'classnames';
+import { Skeleton } from '@chakra-ui/react';
const TopBannerSkeleton = () => {
- const { isDesktop, isMobile } = useDevice()
+ const { isDesktop, isMobile } = useDevice();
const deviceClassName = {
- 'h-10': isDesktop,
- 'h-2.5': isMobile
- }
- const combinedClassName = classNames(deviceClassName)
+ '!h-[36px]': isDesktop,
+ 'h-2.5': isMobile,
+ };
+ const combinedClassName = classNames(deviceClassName);
- return (
- <Skeleton className={combinedClassName} count={1} containerClassName='w-full h-full block' />
- )
-}
+ return <Skeleton className={combinedClassName} />;
+};
-export { TopBannerSkeleton }
+export { TopBannerSkeleton };
diff --git a/src/core/components/layouts/AppLayout.jsx b/src/core/components/layouts/AppLayout.jsx
index d74d61e3..ebbc1ad5 100644
--- a/src/core/components/layouts/AppLayout.jsx
+++ b/src/core/components/layouts/AppLayout.jsx
@@ -1,6 +1,12 @@
-import AppBar from '../elements/Appbar/Appbar'
-import BasicFooter from '../elements/Footer/BasicFooter'
-import AnimationLayout from './AnimationLayout'
+import dynamic from 'next/dynamic';
+import AnimationLayout from './AnimationLayout';
+
+const AppBar = dynamic(() => import('../elements/Appbar/Appbar'), {
+ ssr: false,
+});
+const BasicFooter = dynamic(() => import('../elements/Footer/BasicFooter'), {
+ ssr: false,
+});
const AppLayout = ({ children, title, withFooter = true }) => {
return (
@@ -11,7 +17,7 @@ const AppLayout = ({ children, title, withFooter = true }) => {
</AnimationLayout>
{withFooter && <BasicFooter />}
</>
- )
-}
+ );
+};
-export default AppLayout
+export default AppLayout;
diff --git a/src/core/components/layouts/BasicLayout.jsx b/src/core/components/layouts/BasicLayout.jsx
index 9441dbd7..a4f3a856 100644
--- a/src/core/components/layouts/BasicLayout.jsx
+++ b/src/core/components/layouts/BasicLayout.jsx
@@ -1,55 +1,63 @@
-import dynamic from 'next/dynamic'
-import BasicFooter from '../elements/Footer/BasicFooter'
-import Image from 'next/image'
-import whatsappUrl from '@/core/utils/whatsappUrl'
-import { useEffect, useState } from 'react'
-import axios from 'axios'
-import odooApi from '@/core/api/odooApi'
-import { useRouter } from 'next/router'
-import productApi from '@/lib/product/api/productApi'
-import { getAuth, setAuth } from '@/core/utils/auth'
-import { createSlug, getIdFromSlug } from '@/core/utils/slug'
-import { useSession } from 'next-auth/react'
-import { setCookie } from 'cookies-next'
-import { useProductContext } from '@/contexts/ProductContext'
+import dynamic from 'next/dynamic';
+import Image from 'next/image';
+import { useRouter } from 'next/router';
+import { useEffect, useState } from 'react';
-const Navbar = dynamic(() => import('../elements/Navbar/Navbar'))
-const AnimationLayout = dynamic(() => import('./AnimationLayout'))
+import { useProductContext } from '@/contexts/ProductContext';
+import odooApi from '@/core/api/odooApi';
+import whatsappUrl from '@/core/utils/whatsappUrl';
+import Navbar from '../elements/Navbar/Navbar';
+
+const AnimationLayout = dynamic(() => import('./AnimationLayout'), {
+ ssr: false,
+});
+const BasicFooter = dynamic(() => import('../elements/Footer/BasicFooter'), {
+ ssr: false,
+});
const BasicLayout = ({ children }) => {
- const [templateWA, setTemplateWA] = useState(null)
- const [payloadWA, setPayloadWa] = useState(null)
- const [urlPath, setUrlPath] = useState(null)
+ const [templateWA, setTemplateWA] = useState(null);
+ const [payloadWA, setPayloadWa] = useState(null);
+ const [urlPath, setUrlPath] = useState(null);
- const router = useRouter()
+ const router = useRouter();
- const { product } = useProductContext()
+ const { product } = useProductContext();
useEffect(() => {
- if (router.pathname === '/shop/product/[slug]' || router.pathname === '/shop/product/variant/[slug]') {
+ if (
+ router.pathname === '/shop/product/[slug]' ||
+ router.pathname === '/shop/product/variant/[slug]'
+ ) {
setPayloadWa({
name: product?.name,
manufacture: product?.manufacture.name,
- url: process.env.NEXT_PUBLIC_SELF_HOST + router.asPath
- })
- setTemplateWA('product')
+ url: process.env.NEXT_PUBLIC_SELF_HOST + router.asPath,
+ });
+ setTemplateWA('product');
- setUrlPath(router.asPath)
+ setUrlPath(router.asPath);
}
- }, [product, router])
+ }, [product, router]);
+
+ const recordActivity = async (pathname) => {
+ const ONLY_ON_PATH = false;
+ const recordedPath = [];
+ if (ONLY_ON_PATH && !recordedPath.includes(pathname)) return;
+
+ const ip = await odooApi('GET', '/api/ip-address');
+ const data = new URLSearchParams({
+ page_title: document.title,
+ url: window.location.href,
+ ip,
+ });
+ fetch(`/api/user-activity?${data.toString()}`);
+ };
useEffect(() => {
- const getIP = async () => {
- const ip = await odooApi('GET', '/api/ip-address')
- const data = {
- page_title: document.title,
- url: window.location.href,
- ip: ip
- }
- axios.get(`/api/user-activity?page_title=${data.page_title}&url=${data.url}&ip=${data.ip}`)
- }
- getIP()
- }, [])
+ recordActivity(router.pathname);
+ }, [router.pathname]);
+
return (
<>
<Navbar />
@@ -82,7 +90,7 @@ const BasicLayout = ({ children }) => {
</AnimationLayout>
<BasicFooter />
</>
- )
-}
+ );
+};
-export default BasicLayout
+export default BasicLayout;
diff --git a/src/core/utils/auth.js b/src/core/utils/auth.js
index a7244747..03b20ae2 100644
--- a/src/core/utils/auth.js
+++ b/src/core/utils/auth.js
@@ -29,7 +29,7 @@ const setAuth = (user) => {
* @returns {boolean} - Returns `true`.
*/
const deleteAuth = async() => {
- // await signOut()
+ await signOut()
deleteCookie('auth')
return true
}
diff --git a/src/core/utils/googleTag.js b/src/core/utils/googleTag.js
index 6d7476bd..96a6bd2e 100644
--- a/src/core/utils/googleTag.js
+++ b/src/core/utils/googleTag.js
@@ -2,7 +2,7 @@ const mapVariants = (variants) => {
return variants.map((variant) => {
const res = {
item_id: variant.id,
- item_name: variant.parent.name,
+ item_name: variant.name,
discount: variant.price.price - variant.price.priceDiscount,
item_brand: variant.manufacture?.name,
item_variant: variant.code || variant.id,
@@ -33,6 +33,20 @@ const sumTotal = (variants) => {
}
}
+const mapProducts = (product) => {
+ const res = {
+ item_id: product.id,
+ item_name: product.name,
+ discount: product.lowest_price.price_discount || 0,
+ // index: 0,
+ item_brand: product.manufacture.name,
+ item_category: product.categories,
+ item_variant: product.variants,
+ price: product.lowest_price.price,
+ quantity: product.stock_total
+ }
+ return res
+}
export const gtagAddToCart = (variant, quantity) => {
const param = {
currency: 'IDR',
@@ -77,3 +91,13 @@ export const gtagPurchase = (variants, shipping, transactionId) => {
}
gtag('event', 'purchase', param)
}
+
+export const gtagProductDetail = (product) => {
+ const items = mapProducts(product)
+ const param = {
+ currency: 'IDR',
+ value: product.id,
+ items
+ }
+ gtag('event', 'view_item', param)
+} \ No newline at end of file
diff --git a/src/core/utils/slug.js b/src/core/utils/slug.js
index e91bcf83..19c7b115 100644
--- a/src/core/utils/slug.js
+++ b/src/core/utils/slug.js
@@ -1,4 +1,4 @@
-import toTitleCase from './toTitleCase'
+import toTitleCase from './toTitleCase';
/**
* Creates a slug from input parameters by converting the name and appending it with an ID.
@@ -10,19 +10,20 @@ import toTitleCase from './toTitleCase'
* @returns {string} - The generated slug with the prefix, name, and ID.
*/
const createSlug = (prefix, name, id, withHost = false) => {
+ name ||= '';
let slug =
name
?.trim()
.replace(new RegExp(/[^A-Za-z0-9]/, 'g'), '-')
.toLowerCase() +
'-' +
- id
- let splitSlug = slug.split('-')
- let filterSlugFromEmptyChar = splitSlug.filter((x) => x != '')
- slug = prefix + filterSlugFromEmptyChar.join('-')
- if (withHost) slug = process.env.NEXT_PUBLIC_SELF_HOST + slug
- return slug
-}
+ id;
+ let splitSlug = slug.split('-');
+ let filterSlugFromEmptyChar = splitSlug.filter((x) => x != '');
+ slug = prefix + filterSlugFromEmptyChar.join('-');
+ if (withHost) slug = process.env.NEXT_PUBLIC_SELF_HOST + slug;
+ return slug;
+};
/**
* Extracts the ID from a slug.
@@ -32,9 +33,9 @@ const createSlug = (prefix, name, id, withHost = false) => {
* @returns {string} - The extracted ID from the slug.
*/
const getIdFromSlug = (slug) => {
- let id = slug.split('-')
- return id[id.length - 1]
-}
+ let id = slug.split('-');
+ return id[id.length - 1];
+};
/**
* Extracts the name from a slug.
@@ -45,9 +46,10 @@ const getIdFromSlug = (slug) => {
* @returns {string} - The extracted name from the slug in title case.
*/
const getNameFromSlug = (slug) => {
- let name = slug.split('-')
- name.pop()
- return toTitleCase(name.join(' '))
-}
+ let name = slug.split('-');
+ name.pop();
+ return toTitleCase(name.join(' '));
+};
+
+export { createSlug, getIdFromSlug, getNameFromSlug };
-export { createSlug, getIdFromSlug, getNameFromSlug }
diff --git a/src/core/utils/whatsappUrl.js b/src/core/utils/whatsappUrl.js
index 9a92f424..7a129aa6 100644
--- a/src/core/utils/whatsappUrl.js
+++ b/src/core/utils/whatsappUrl.js
@@ -7,7 +7,7 @@ const whatsappUrl = (template = 'default', payload, urlPath = null) => {
if(!urlPath) return '/login'
}
let parentName = user.parentName || '-'
- let url = 'https://wa.me/628128080622'
+ let url = 'https://wa.me/6281717181922'
let text = 'Hallo Indoteknik.com,'
switch (template) {
case 'product':