summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrisusilo48 <tri.susilo@altama.co.id>2024-12-23 11:20:56 +0700
committertrisusilo48 <tri.susilo@altama.co.id>2024-12-23 11:20:56 +0700
commit21f3d78e6c58d9b509f3ea234af462807ef1301d (patch)
tree9bad9467325819888b73a86804222e313c6c9504
parentd1592286eef165533c21d52aec70dbb703cdcfd3 (diff)
parent9962d114e590bfc5e6c865489ab4dcd84de81ad9 (diff)
Merge branch 'new-release' into feature/integrasi_biteship
-rw-r--r--src-migrate/components/ui/modal.tsx2
-rw-r--r--src-migrate/modules/popup-information/index.tsx58
-rw-r--r--src-migrate/modules/register/components/FormBisnis.tsx7
-rw-r--r--src-migrate/modules/register/components/RegistrasiBisnis.tsx19
-rw-r--r--src-migrate/modules/register/components/TermCondition.tsx48
-rw-r--r--src-migrate/modules/register/index.tsx54
-rw-r--r--src-migrate/types/auth.ts9
-rw-r--r--src/components/ui/HeroBanner.jsx13
-rw-r--r--src/components/ui/HeroBannerSecondary.jsx6
-rw-r--r--src/core/components/elements/Navbar/Navbar.jsx6
-rw-r--r--src/core/components/elements/Navbar/NavbarDesktop.jsx93
-rw-r--r--src/core/components/elements/Navbar/NavbarMobile.jsx43
-rw-r--r--src/core/components/elements/Navbar/TopBanner.jsx1
-rw-r--r--src/core/components/elements/Sidebar/Sidebar.jsx2
-rw-r--r--src/core/components/layouts/BasicLayout.jsx4
-rw-r--r--src/lib/auth/components/Menu.jsx99
-rw-r--r--src/lib/brand/components/BrandCard.jsx2
-rw-r--r--src/lib/flashSale/components/FlashSale.jsx2
-rw-r--r--src/lib/home/components/BannerSection.jsx1
-rw-r--r--src/lib/home/components/CategoryDynamic.jsx178
-rw-r--r--src/lib/home/components/CategoryDynamicMobile.jsx2
-rw-r--r--src/lib/home/components/PromotionProgram.jsx59
-rw-r--r--src/lib/home/components/ServiceList.jsx4
-rw-r--r--src/lib/product/components/Product/ProductDesktop.jsx1
-rw-r--r--src/lib/product/components/Product/ProductMobile.jsx1
-rw-r--r--src/lib/product/components/ProductCard.jsx30
-rw-r--r--src/lib/product/components/ProductSlider.jsx2
-rw-r--r--src/lib/transaction/api/checkoutPoApi.js19
-rw-r--r--src/lib/transaction/components/Transaction.jsx132
-rw-r--r--src/lib/treckingAwb/component/Manifest.jsx1
-rw-r--r--src/pages/api/flashsale-header.js36
-rw-r--r--src/pages/api/hero-banner.js2
-rw-r--r--src/pages/api/search-flashsale.js26
-rw-r--r--src/pages/index.jsx31
-rw-r--r--src/pages/my/menu.jsx97
-rw-r--r--src/pages/sitemap/homepage.xml.js33
36 files changed, 731 insertions, 392 deletions
diff --git a/src-migrate/components/ui/modal.tsx b/src-migrate/components/ui/modal.tsx
index 34e1d1c3..50e7128f 100644
--- a/src-migrate/components/ui/modal.tsx
+++ b/src-migrate/components/ui/modal.tsx
@@ -71,7 +71,7 @@ export const Modal = ({
{title}
</div>
{close && (
- <button className="rounded-full h-10 w-10 flex justify-center items-center bg-white" type='button' onClick={close}>
+ <button className="rounded-full h-10 w-10 flex justify-center items-center bg-white" type='button' aria-label="Close" onClick={close}>
<XMarkIcon className='w-5 h-5 ' />
</button>
)}
diff --git a/src-migrate/modules/popup-information/index.tsx b/src-migrate/modules/popup-information/index.tsx
index 0d36f8e9..d50711cc 100644
--- a/src-migrate/modules/popup-information/index.tsx
+++ b/src-migrate/modules/popup-information/index.tsx
@@ -1,31 +1,63 @@
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
-import { Modal } from "~/components/ui/modal";
+import Image from 'next/image';
+import Link from 'next/link';
+import { Modal } from '~/components/ui/modal';
import { getAuth } from '~/libs/auth';
-import PageContent from '../page-content';
+import dynamic from 'next/dynamic';
const PagePopupInformation = () => {
const router = useRouter();
const isHomePage = router.pathname === '/';
const auth = getAuth();
const [active, setActive] = useState<boolean>(false);
+ const [data, setData] = useState<any>(null);
+ const [loading, setLoading] = useState(true);
+
useEffect(() => {
- if (isHomePage && !auth) setActive(true);
+ const getData = async () => {
+ const res = await fetch(`/api/hero-banner?type=popup-banner`);
+ const { data } = await res.json();
+ if (data) {
+ setData(data);
+ }
+ setLoading(false);
+ };
+
+ if (isHomePage && !auth) {
+ setActive(true);
+ getData();
+ }
}, [isHomePage, auth]);
return (
<div className='group'>
- <Modal
- active={active}
- className='!w-fit !bg-transparent !border-none overflow-hidden'
- close={() => setActive(false)}
- mode='desktop'
- >
- <div className='w-[350px] md:w-[530px]' onClick={() => setActive(false)}>
- <PageContent path='/onbording-popup' />
- </div>
- </Modal>
+ {data && !loading && (
+ <Modal
+ active={active}
+ className='!w-fit !bg-transparent !border-none overflow-hidden'
+ close={() => setActive(false)}
+ mode='desktop'
+ >
+ <div
+ className='w-[350px] md:w-[530px]'
+ onClick={() => setActive(false)}
+ >
+ <Link href={data[0].url === false ? '/' :data[0].url} aria-label='popup'>
+ <Image
+ src={data[0]?.image}
+ alt={data[0]?.name}
+ width={1152}
+ height={768}
+ loading='eager'
+ sizes='(max-width: 768px) 100vw, 50vw'
+ priority={true}
+ />
+ </Link>
+ </div>
+ </Modal>
+ )}
</div>
);
};
diff --git a/src-migrate/modules/register/components/FormBisnis.tsx b/src-migrate/modules/register/components/FormBisnis.tsx
index e4cf3442..12397956 100644
--- a/src-migrate/modules/register/components/FormBisnis.tsx
+++ b/src-migrate/modules/register/components/FormBisnis.tsx
@@ -1,9 +1,5 @@
import { ChangeEvent, useEffect, useMemo, useRef, useState } from 'react';
-import { useMutation } from 'react-query';
import { useRegisterStore } from '../stores/useRegisterStore';
-import { RegisterProps } from '~/types/auth';
-import { registerUser } from '~/services/auth';
-import { useRouter } from 'next/router';
import {
Button,
Checkbox,
@@ -11,12 +7,10 @@ import {
color,
useToast,
} from '@chakra-ui/react';
-import Link from 'next/link';
import getFileBase64 from '@/core/utils/getFileBase64';
import { Controller, useForm } from 'react-hook-form';
import HookFormSelect from '@/core/components/elements/Select/HookFormSelect';
import odooApi from '~/libs/odooApi';
-import { toast } from 'react-hot-toast';
import { EyeIcon } from '@heroicons/react/24/outline';
import BottomPopup from '@/core/components/elements/Popup/BottomPopup';
import Image from 'next/image';
@@ -60,7 +54,6 @@ const form: React.FC<FormProps> = ({
const [industries, setIndustries] = useState<industry_id[]>([]);
const [companyTypes, setCompanyTypes] = useState<companyType[]>([]);
- const router = useRouter();
const toast = useToast();
const emailRef = useRef<HTMLInputElement>(null);
diff --git a/src-migrate/modules/register/components/RegistrasiBisnis.tsx b/src-migrate/modules/register/components/RegistrasiBisnis.tsx
index ce4d3972..40caed65 100644
--- a/src-migrate/modules/register/components/RegistrasiBisnis.tsx
+++ b/src-migrate/modules/register/components/RegistrasiBisnis.tsx
@@ -1,19 +1,10 @@
-import { ChangeEvent, useEffect, useMemo, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import FormBisnis from './FormBisnis';
import Form from './Form';
-import TermCondition from './TermCondition';
-import FormCaptcha from './FormCaptcha';
import { Radio, RadioGroup, Stack, Divider, Button } from '@chakra-ui/react';
import React from 'react';
import { ChevronDownIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
import { useRegisterStore } from '../stores/useRegisterStore';
-import { useMutation } from 'react-query';
-import { RegisterProps } from '~/types/auth';
-import { registerUser } from '~/services/auth';
-import router from 'next/router';
-import { useRouter } from 'next/router';
-import { UseToastOptions, useToast } from '@chakra-ui/react';
-import Link from 'next/link';
interface FormProps {
chekValid: boolean;
buttonSubmitClick: boolean;
@@ -28,13 +19,7 @@ const RegistrasiBisnis: React.FC<FormProps> = ({
const [isBisnisClicked, setisBisnisClicked] = useState(true);
const [selectedValue, setSelectedValue] = useState('PKP');
const [selectedValueBisnis, setSelectedValueBisnis] = useState('false');
- const { form, isCheckedTNC, isValidCaptcha, errors, validate, updateForm } =
- useRegisterStore();
- const isFormValid = useMemo(() => Object.keys(errors).length === 0, [errors]);
- const toast = useToast();
- const mutation = useMutation({
- mutationFn: (data: RegisterProps) => registerUser(data),
- });
+ const { validate, updateForm } = useRegisterStore();
useEffect(() => {
if (selectedValue === 'PKP') {
diff --git a/src-migrate/modules/register/components/TermCondition.tsx b/src-migrate/modules/register/components/TermCondition.tsx
index d54fe921..44275917 100644
--- a/src-migrate/modules/register/components/TermCondition.tsx
+++ b/src-migrate/modules/register/components/TermCondition.tsx
@@ -1,34 +1,48 @@
-import { Checkbox } from '@chakra-ui/react'
-import React from 'react'
-import { Modal } from '~/components/ui/modal'
-import { useRegisterStore } from "../stores/useRegisterStore";
-import PageContent from '~/modules/page-content'
+import { Checkbox } from '@chakra-ui/react';
+import React from 'react';
+import { Modal } from '~/components/ui/modal';
+import { useRegisterStore } from '../stores/useRegisterStore';
+
+import dynamic from 'next/dynamic';
+const PageContent = dynamic(
+ () => import('@/lib/content/components/PageContent')
+);
const TermCondition = () => {
- const { isOpenTNC, closeTNC, isCheckedTNC, toggleCheckTNC, openTNC } = useRegisterStore()
+ const { isOpenTNC, closeTNC, isCheckedTNC, toggleCheckTNC, openTNC } =
+ useRegisterStore();
return (
<>
- <div className="mt-4 flex items-center gap-x-2">
- <Checkbox id='tnc' name='tnc' colorScheme='red' isChecked={isCheckedTNC} onChange={toggleCheckTNC} />
+ <div className='mt-4 flex items-center gap-x-2'>
+ <Checkbox
+ id='tnc'
+ name='tnc'
+ colorScheme='red'
+ isChecked={isCheckedTNC}
+ onChange={toggleCheckTNC}
+ />
<div>
- <label htmlFor="tnc" className="cursor-pointer">Dengan ini saya menyetujui</label>
- {' '}
+ <label htmlFor='tnc' className='cursor-pointer'>
+ Dengan ini saya menyetujui
+ </label>{' '}
<span
- className="font-medium text-danger-500 cursor-pointer"
+ className='font-medium text-danger-500 cursor-pointer'
onClick={openTNC}
>
syarat dan ketentuan
</span>
- <label htmlFor="tnc" className="ml-2 cursor-pointer">yang berlaku</label>
+ <label htmlFor='tnc' className='ml-2 cursor-pointer'>
+ yang berlaku
+ </label>
</div>
</div>
- <Modal active={isOpenTNC} close={closeTNC} >
- <PageContent path='/register#tnd' />
+ <Modal active={isOpenTNC} close={closeTNC}>
+ <PageContent path='/registerTnd' />
</Modal>
</>
- )
-}
+ );
+};
-export default TermCondition \ No newline at end of file
+export default TermCondition;
diff --git a/src-migrate/modules/register/index.tsx b/src-migrate/modules/register/index.tsx
index da41fd8b..0308e397 100644
--- a/src-migrate/modules/register/index.tsx
+++ b/src-migrate/modules/register/index.tsx
@@ -1,20 +1,24 @@
-import PageContent from '~/modules/page-content';
-import RegistrasiIndividu from './components/RegistrasiIndividu';
-import RegistrasiBisnis from './components/RegistrasiBisnis';
+import dynamic from 'next/dynamic';
import Link from 'next/link';
import Image from 'next/image';
-import IndoteknikLogo from '~/images/logo.png';
-import AccountActivation from '../account-activation';
import { useMemo, useState } from 'react';
-import { useRegisterStore } from './stores/useRegisterStore';
-import FormCaptcha from './components/FormCaptcha';
-import TermCondition from './components/TermCondition';
+import { useRouter } from 'next/router';
import { Button } from '@chakra-ui/react';
-import { useMutation } from 'react-query';
import { UseToastOptions, useToast } from '@chakra-ui/react';
-import { RegisterProps } from '~/types/auth';
+import { useMutation } from 'react-query';
+import { useRegisterStore } from './stores/useRegisterStore';
import { registerUser } from '~/services/auth';
-import { useRouter } from 'next/router';
+import IndoteknikLogo from '~/images/logo.png';
+import { RegisterProps } from '~/types/auth';
+
+const PageContent = dynamic(() => import('~/modules/page-content'));
+const RegistrasiIndividu = dynamic(
+ () => import('./components/RegistrasiIndividu')
+);
+const RegistrasiBisnis = dynamic(() => import('./components/RegistrasiBisnis'));
+const FormCaptcha = dynamic(() => import('./components/FormCaptcha'));
+const TermCondition = dynamic(() => import('./components/TermCondition'));
+const AccountActivation = dynamic(() => import('../account-activation'));
const LOGO_WIDTH = 150;
const LOGO_HEIGHT = LOGO_WIDTH / 3;
@@ -47,6 +51,7 @@ const Register = () => {
setIsIndividuClicked(false);
setIsBisnisClicked(true);
};
+
const handleSubmit = async () => {
if (!isFormValid) {
setNotValid(true);
@@ -98,10 +103,11 @@ const Register = () => {
break;
}
};
+
return (
<div className='container'>
<div className='grid grid-cols-1 md:grid-cols-2 gap-x-8 pt-10 px-2 md:pt-16'>
- <section className=''>
+ <section>
<div className='px-8 py-4 border'>
<Link href='/' className='block md:hidden'>
<Image
@@ -126,7 +132,7 @@ const Register = () => {
</label>
<div className='grid grid-cols-2 gap-x-3 mt-2 h-14 font-bold text-black hover:cursor-pointer'>
<div
- className={` border rounded-md flex justify-center items-center transition-colors duration-300 ease-in-out ${
+ className={`border rounded-md flex justify-center items-center transition-colors duration-300 ease-in-out ${
isIndividuClicked ? 'bg-red-500 text-white' : ''
}`}
onClick={handleIndividuClick}
@@ -134,7 +140,7 @@ const Register = () => {
<p>Individu</p>
</div>
<div
- className={` border rounded-md flex justify-center items-center transition-colors duration-300 ease-in-out ${
+ className={`border rounded-md flex justify-center items-center transition-colors duration-300 ease-in-out ${
isBisnisClicked ? 'bg-red-500 text-white' : ''
}`}
onClick={handleBisnisClick}
@@ -144,20 +150,16 @@ const Register = () => {
</div>
<div className='transition-opacity duration-300 ease-in-out'>
{isIndividuClicked && (
- <div className='opacity-100'>
- <RegistrasiIndividu
- chekValid={notValid}
- buttonSubmitClick={buttonSubmitClick}
- />
- </div>
+ <RegistrasiIndividu
+ chekValid={notValid}
+ buttonSubmitClick={buttonSubmitClick}
+ />
)}
{isBisnisClicked && (
- <div className='opacity-100'>
- <RegistrasiBisnis
- chekValid={notValid}
- buttonSubmitClick={buttonSubmitClick}
- />
- </div>
+ <RegistrasiBisnis
+ chekValid={notValid}
+ buttonSubmitClick={buttonSubmitClick}
+ />
)}
</div>
<section className='mt-2'>
diff --git a/src-migrate/types/auth.ts b/src-migrate/types/auth.ts
index 593e120f..8feac2e1 100644
--- a/src-migrate/types/auth.ts
+++ b/src-migrate/types/auth.ts
@@ -16,10 +16,11 @@ export type AuthProps = {
company: boolean;
pricelist: string | null;
token: string;
- feature : {
- onlyReadyStock : boolean,
- soApproval : boolean
- }
+ feature: {
+ onlyReadyStock: boolean;
+ soApproval: boolean;
+ };
+ partner_tempo: boolean;
};
export type AuthApiProps = OdooApiRes<AuthProps>;
diff --git a/src/components/ui/HeroBanner.jsx b/src/components/ui/HeroBanner.jsx
index 2eea5915..d5ff6247 100644
--- a/src/components/ui/HeroBanner.jsx
+++ b/src/components/ui/HeroBanner.jsx
@@ -7,9 +7,7 @@ import { Swiper, SwiperSlide } from 'swiper/react';
import Image from 'next/image';
import { useEffect, useMemo, useState } from 'react';
-import { useQuery } from 'react-query';
-import { bannerApi } from '@/api/bannerApi';
import Link from '@/core/components/elements/Link/Link';
import DesktopView from '@/core/components/views/DesktopView';
import MobileView from '@/core/components/views/MobileView';
@@ -52,28 +50,21 @@ const HeroBanner = () => {
pagination: { dynamicBullets: false, clickable: true },
};
- const customLoader = ({ src }) => {
- return src; // Loader yang mengembalikan URL gambar asli
- };
-
const BannerComponent = useMemo(() => {
if (!heroBanner) return null;
return heroBanner.map((banner, index) => (
<SwiperSlide key={index}>
- <Link href={banner.url} className='w-full h-auto'>
+ <Link href={banner?.url} aria-label={banner.name}>
<Image
- loader={customLoader}
src={banner.image}
alt={banner.name}
width={1152}
height={768}
- className='w-full h-auto'
- priority={index === 0}
- loading={index === 0 ? 'eager' : 'lazy'}
placeholder='blur'
blurDataURL='/images/indoteknik-placeholder.png'
sizes='(max-width: 768px) 100vw, 50vw'
+ priority={true}
/>
</Link>
</SwiperSlide>
diff --git a/src/components/ui/HeroBannerSecondary.jsx b/src/components/ui/HeroBannerSecondary.jsx
index 6074c9a6..0daf9c61 100644
--- a/src/components/ui/HeroBannerSecondary.jsx
+++ b/src/components/ui/HeroBannerSecondary.jsx
@@ -1,10 +1,8 @@
import Link from '@/core/components/elements/Link/Link';
import { getRandomInt } from '@/utils/getRandomInt';
import Image from 'next/image';
-import { useMemo, useEffect, useState } from 'react';
-import { useQuery } from 'react-query';
+import { useEffect, useMemo, useState } from 'react';
import { HeroBannerSkeleton } from '../skeleton/BannerSkeleton';
-import { bannerApi } from '@/api/bannerApi';
const HeroBannerSecondary = () => {
const [heroBannerSecondary, setHeroBannerSecondary] = useState([]);
@@ -45,7 +43,7 @@ const HeroBannerSecondary = () => {
height={1024}
alt={heroBannerSecondary[randomIndex]?.name}
className='object-cover object-center h-full'
- loading='lazy'
+ loading='eager'
placeholder='blur'
blurDataURL='/images/indoteknik-placeholder.png'
sizes='(max-width: 768px) 100vw, 50vw'
diff --git a/src/core/components/elements/Navbar/Navbar.jsx b/src/core/components/elements/Navbar/Navbar.jsx
index 57904498..59f743a2 100644
--- a/src/core/components/elements/Navbar/Navbar.jsx
+++ b/src/core/components/elements/Navbar/Navbar.jsx
@@ -3,10 +3,12 @@ import dynamic from 'next/dynamic'
const NavbarDesktop = dynamic(() => import('./NavbarDesktop'))
const NavbarMobile = dynamic(() => import('./NavbarMobile'))
-const Navbar = () => {
+const Navbar = ({isMobile} ) => {
+
+ if(isMobile) return <NavbarMobile />
+
return (
<>
- <NavbarMobile />
<NavbarDesktop />
</>
)
diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx
index fa3df5bf..253a2b03 100644
--- a/src/core/components/elements/Navbar/NavbarDesktop.jsx
+++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx
@@ -12,12 +12,9 @@ import {
MenuButton,
MenuItem,
MenuList,
- useDisclosure
+ useDisclosure,
} from '@chakra-ui/react';
-import {
- ChevronDownIcon,
- HeartIcon
-} from '@heroicons/react/24/outline';
+import { ChevronDownIcon, HeartIcon } from '@heroicons/react/24/outline';
import dynamic from 'next/dynamic';
import { default as Image, default as NextImage } from 'next/image';
import { useRouter } from 'next/router';
@@ -81,21 +78,17 @@ const NavbarDesktop = () => {
};
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);
- };
- }, []);
+ if (auth) {
+ loadCart(auth.id);
+ }
+ }, [auth]);
useEffect(() => {
setPendingTransactions(data);
@@ -115,20 +108,22 @@ const NavbarDesktop = () => {
}, [product, router]);
useEffect(() => {
- const handleCartChange = () => {
- const cart = async () => {
- const listCart = await getCountCart();
- setCartCount(listCart);
- };
- cart();
- };
- handleCartChange();
-
- window.addEventListener('localStorageChange', handleCartChange);
-
- return () => {
- window.removeEventListener('localStorageChange', handleCartChange);
- };
+ // const handleCartChange = () => {
+ // const cart = async () => {
+ // const listCart = await getCountCart();
+ // setCartCount(listCart);
+ // };
+ // cart();
+ // };
+ // handleCartChange();
+
+ setCartCount(cart?.products?.length)
+
+ // window.addEventListener('localStorageChange', handleCartChange);
+
+ // return () => {
+ // window.removeEventListener('localStorageChange', handleCartChange);
+ // };
}, [transactions.data, cart]);
useEffect(() => {
@@ -197,12 +192,14 @@ 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='/'>
+ <Link href='/' aria-label='Indoteknik Logo'>
<Image
src={IndoteknikLogo}
alt='Indoteknik Logo'
width={210}
- height={210 / 3}
+ height={70}
+ loading='eager'
+ priority={true}
/>
</Link>
<div className='flex-1 flex items-center'>
@@ -220,6 +217,7 @@ const NavbarDesktop = () => {
target='_blank'
rel='noreferrer'
href='/my/wishlist'
+ aria-label='Wishlist'
className='flex items-center gap-x-2 !text-gray_r-12/80'
>
<HeartIcon className='w-7' />
@@ -227,6 +225,7 @@ const NavbarDesktop = () => {
</Link>
<a
href={whatsappUrl(templateWA, payloadWA, urlPath)}
+ aria-label='Whatsapp'
target='_blank'
rel='noreferrer'
className='flex items-center gap-x-1 !text-gray_r-12/80'
@@ -236,6 +235,7 @@ const NavbarDesktop = () => {
alt='Whatsapp'
width={48}
height={48}
+ loading='eager'
/>
<div>
<div className='font-semibold'>Whatsapp</div>
@@ -268,6 +268,7 @@ const NavbarDesktop = () => {
<div className='w-6/12 flex px-1 divide-x divide-gray_r-6'>
<Link
href='/shop/promo'
+ aria-label='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
@@ -284,6 +285,7 @@ const NavbarDesktop = () => {
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`}
+ loading='eager'
/>
</div>
)}
@@ -301,6 +303,7 @@ const NavbarDesktop = () => {
<Link
href='/shop/brands'
+ aria-label='Brand'
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 group`}
@@ -313,6 +316,7 @@ const NavbarDesktop = () => {
</Link>
<Link
href='/shop/search?orderBy=stock'
+ aria-label='Ready Stock'
className={`${
router.asPath.includes('/shop/search?orderBy=stock') &&
'bg-gray_r-3'
@@ -326,6 +330,7 @@ const NavbarDesktop = () => {
</Link>
<Link
href='https://blog.indoteknik.com/'
+ aria-label='Blog Indoteknik'
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'
@@ -349,12 +354,14 @@ const NavbarDesktop = () => {
<>
<Link
href='/login'
+ aria-label='Login'
className='flex-1 flex justify-center items-center bg-danger-500 !text-gray_r-1 rounded-none rounded-t-xl'
>
Masuk
</Link>
<Link
href='/register'
+ aria-label='Register'
className='flex-1 flex justify-center items-center bg-danger-500 !text-gray_r-1 rounded-none rounded-t-xl'
>
Daftar
@@ -363,7 +370,7 @@ const NavbarDesktop = () => {
)}
{auth && (
<>
- <div href='/' className='navbar-user-dropdown-button'>
+ <div href='/' className='navbar-user-dropdown-button' aria-label='User'>
<span>Halo, {auth?.name}</span>
<div className='ml-auto'>
<ChevronDownIcon className='w-6' />
@@ -388,24 +395,28 @@ const SocialMedias = () => (
target='_blank'
rel='noreferrer'
href='https://www.youtube.com/@indoteknikcom'
+ aria-label='Youtube - Indoteknik.com'
>
<NextImage
src='/images/socials/youtube.webp'
- // alt='Youtube - Indoteknik.com'
+ alt='Ytube'
width={24}
height={24}
+ loading='eager'
/>
</a>
<a
target='_blank'
rel='noreferrer'
href='https://www.tiktok.com/@indoteknikcom'
+ aria-label='TikTok - Indoteknik.com'
>
<NextImage
src='/images/socials/tiktok.png'
- // alt='TikTok - Indoteknik.com'
+ alt='TikTok'
width={24}
height={24}
+ loading='eager'
/>
</a>
{/* <a target='_blank' rel='noreferrer' href={whatsappUrl(null)}>
@@ -420,48 +431,56 @@ const SocialMedias = () => (
target='_blank'
rel='noreferrer'
href='https://www.facebook.com/indoteknikcom'
+ aria-label='Facebook - Indoteknik.com'
>
<NextImage
src='/images/socials/Facebook.png'
- // alt='Facebook - Indoteknik.com'
+ alt='FB'
width={24}
height={24}
+ loading='eager'
/>
</a>
<a
target='_blank'
rel='noreferrer'
href='https://www.instagram.com/indoteknikcom/'
+ aria-label='Instagram - Indoteknik.com'
>
<NextImage
src='/images/socials/Instagram.png'
- // alt='Instagram - Indoteknik.com'
+ alt='IG'
width={24}
height={24}
+ loading='eager'
/>
</a>
<a
target='_blank'
rel='noreferrer'
href='https://www.linkedin.com/company/pt-indoteknik-dotcom-gemilang/'
+ aria-label='Linkedin - Indoteknik.com'
>
<NextImage
src='/images/socials/Linkedin.png'
- // alt='Linkedin - Indoteknik.com'
+ alt='Linkedin'
width={24}
height={24}
+ loading='eager'
/>
</a>
<a
target='_blank'
rel='noreferrer'
href='https://goo.gl/maps/GF8EmDjpQTHZPsJ1A'
+ aria-label='Maps - Indoteknik.com'
>
<NextImage
src='/images/socials/g_maps.png'
- // alt='Maps - Indoteknik.com'
+ alt='Maps'
width={24}
height={24}
+ loading='eager'
/>
</a>
</div>
diff --git a/src/core/components/elements/Navbar/NavbarMobile.jsx b/src/core/components/elements/Navbar/NavbarMobile.jsx
index 90314671..47182a47 100644
--- a/src/core/components/elements/Navbar/NavbarMobile.jsx
+++ b/src/core/components/elements/Navbar/NavbarMobile.jsx
@@ -12,30 +12,44 @@ import { useEffect, useState } from 'react';
import MobileView from '../../views/MobileView';
import Link from '../Link/Link';
import TopBanner from './TopBanner';
+import { useCartStore } from '~/modules/cart/stores/useCartStore';
+import useAuth from '@/core/hooks/useAuth';
const Search = dynamic(() => import('./Search'));
const NavbarMobile = () => {
const { Sidebar, open } = useSidebar();
+ const auth = useAuth();
const [cartCount, setCartCount] = useState(0);
+ const { loadCart, cart, summary, updateCartItem } = useCartStore();
- useEffect(() => {
- const handleCartChange = () => {
- const cart = async () => {
- const listCart = await getCountCart();
- setCartCount(listCart);
- };
- cart();
- };
- handleCartChange();
+ // useEffect(() => {
+ // const handleCartChange = () => {
+ // const cart = async () => {
+ // const listCart = await getCountCart();
+ // setCartCount(listCart);
+ // };
+ // cart();
+ // };
+ // handleCartChange();
+
+ // window.addEventListener('localStorageChange', handleCartChange);
- window.addEventListener('localStorageChange', handleCartChange);
+ // return () => {
+ // window.removeEventListener('localStorageChange', handleCartChange);
+ // };
+ // }, []);
- return () => {
- window.removeEventListener('localStorageChange', handleCartChange);
- };
- }, []);
+ useEffect(() => {
+ if(auth){
+ loadCart(auth?.id);
+ }
+ }, [auth]);
+
+ useEffect(() => {
+ setCartCount(cart?.products?.length);
+ }, [cart]);
return (
<MobileView>
@@ -48,6 +62,7 @@ const NavbarMobile = () => {
alt='Indoteknik Logo'
width={120}
height={40}
+ loading='eager'
/>
</Link>
<div className='flex gap-x-3'>
diff --git a/src/core/components/elements/Navbar/TopBanner.jsx b/src/core/components/elements/Navbar/TopBanner.jsx
index 709495ce..7d44846c 100644
--- a/src/core/components/elements/Navbar/TopBanner.jsx
+++ b/src/core/components/elements/Navbar/TopBanner.jsx
@@ -50,6 +50,7 @@ const TopBanner = ({ onLoad = () => {} }) => {
<Link
href={data?.url}
className='block bg-cover bg-center h-3 md:h-6 lg:h-[36px]'
+ aria-label='panduan pick up barang'
style={{
backgroundImage: `url('${data?.image}')`,
}}
diff --git a/src/core/components/elements/Sidebar/Sidebar.jsx b/src/core/components/elements/Sidebar/Sidebar.jsx
index ddae3e20..08498759 100644
--- a/src/core/components/elements/Sidebar/Sidebar.jsx
+++ b/src/core/components/elements/Sidebar/Sidebar.jsx
@@ -140,7 +140,7 @@ const Sidebar = ({ active, close }) => {
<SidebarLink className={itemClassName} href='/tentang-kami'>
Tentang Indoteknik
</SidebarLink>
- <SidebarLink className={itemClassName} href='/contact-us'>
+ <SidebarLink className={itemClassName} href='/hubungi-kami'>
Hubungi Kami
</SidebarLink>
<button
diff --git a/src/core/components/layouts/BasicLayout.jsx b/src/core/components/layouts/BasicLayout.jsx
index 1b62bf05..2998fa63 100644
--- a/src/core/components/layouts/BasicLayout.jsx
+++ b/src/core/components/layouts/BasicLayout.jsx
@@ -112,7 +112,7 @@ const BasicLayout = ({ children }) => {
onAnimationEnd={() => setHighlight(false)}
/>
)}
- <Navbar />
+ <Navbar isMobile = {isMobile} />
<AnimationLayout>
{children}
<div
@@ -149,6 +149,7 @@ const BasicLayout = ({ children }) => {
className='block sm:hidden'
width={36}
height={36}
+ loading='eager'
/>
<Image
src='/images/socials/WHATSAPP.svg'
@@ -156,6 +157,7 @@ const BasicLayout = ({ children }) => {
className='hidden sm:block'
width={44}
height={44}
+ loading='eager'
/>
</a>
</div>
diff --git a/src/lib/auth/components/Menu.jsx b/src/lib/auth/components/Menu.jsx
index f475db1f..9cd10ab4 100644
--- a/src/lib/auth/components/Menu.jsx
+++ b/src/lib/auth/components/Menu.jsx
@@ -1,76 +1,129 @@
-import Link from '@/core/components/elements/Link/Link'
-import { useRouter } from 'next/router'
-import ImageNext from 'next/image'
-import whatsappUrl from '@/core/utils/whatsappUrl'
-
+import Link from '@/core/components/elements/Link/Link';
+import { useRouter } from 'next/router';
+import ImageNext from 'next/image';
+import whatsappUrl from '@/core/utils/whatsappUrl';
+import { deleteAuth } from '@/core/utils/auth';
const Menu = () => {
- const router = useRouter()
+ const router = useRouter();
+
+ const routeStartWith = (route) => router.pathname.startsWith(route);
- const routeStartWith = (route) => router.pathname.startsWith(route)
+ const logout = async () => {
+ deleteAuth().then(() => {
+ router.push('/login');
+ });
+ };
return (
<div className='grid grid-cols-1 bg-white border border-gray_r-6 rounded py-2 px-4 sticky top-48'>
<div className='mt-4 mb-1 font-medium'>Menu</div>
<LinkItem href='/my/quotations' active={routeStartWith('/my/quotations')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_quotation.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_quotation.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Quotation</p>
</div>
</LinkItem>
- <LinkItem href='/my/transactions' active={routeStartWith('/my/transactions')}>
+ <LinkItem
+ href='/my/transactions'
+ active={routeStartWith('/my/transactions')}
+ >
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_transaksi.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_transaksi.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Transaksi</p>
</div>
</LinkItem>
<LinkItem href='/my/shipments' active={routeStartWith('/my/shipments')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_pengiriman.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_pengiriman.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Pengiriman</p>
</div>
</LinkItem>
<LinkItem href='/my/invoices' active={routeStartWith('/my/invoices')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_invoice.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_invoice.svg'
+ width={18}
+ height={20}
+ />
<p>Invoice & Faktur Pajak</p>
</div>
</LinkItem>
<LinkItem href='/my/wishlist' active={routeStartWith('/my/wishlist')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_wishlist.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_wishlist.svg'
+ width={18}
+ height={20}
+ />
<p>Wishlist</p>
</div>
</LinkItem>
<div className='mt-4 mb-1 font-medium'>Pusat Bantuan</div>
- <LinkItem href={whatsappUrl('', '', '')} rel='noopener noreferrer' target='_blank'>
+ <LinkItem
+ href={whatsappUrl('', '', '')}
+ rel='noopener noreferrer'
+ target='_blank'
+ >
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_layanan_pelanggan.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_layanan_pelanggan.svg'
+ width={18}
+ height={20}
+ />
<p>Layanan Pelanggan</p>
</div>
</LinkItem>
<div className='mt-4 mb-1 font-medium'>Pengaturan Akun</div>
<LinkItem href='/my/address' active={routeStartWith('/my/address')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_alamat.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_alamat.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Alamat</p>
</div>
</LinkItem>
<LinkItem href='/my/profile' active={routeStartWith('/my/profile')}>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_profile.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_profile.svg'
+ width={18}
+ height={20}
+ />
<p>Profil Saya</p>
</div>
</LinkItem>
- <button type='button' className='text-gray_r-12/80 p-2 text-left'>
+ <button
+ type='button'
+ onClick={logout}
+ className='text-gray_r-12/80 p-2 text-left'
+ >
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_logout.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_logout.svg'
+ width={18}
+ height={20}
+ />
<p>Keluar Akun</p>
</div>
</button>
</div>
- )
-}
+ );
+};
const LinkItem = ({ children, ...props }) => (
<Link
@@ -81,6 +134,6 @@ const LinkItem = ({ children, ...props }) => (
>
{children}
</Link>
-)
+);
-export default Menu
+export default Menu;
diff --git a/src/lib/brand/components/BrandCard.jsx b/src/lib/brand/components/BrandCard.jsx
index ebd41a67..dff61b24 100644
--- a/src/lib/brand/components/BrandCard.jsx
+++ b/src/lib/brand/components/BrandCard.jsx
@@ -11,6 +11,7 @@ const BrandCard = ({ brand }) => {
className={`py-1 px-2 border-gray_r-6 flex justify-center items-center hover:scale-110 transition duration-500 ease-in-out ${
isMobile ? 'h-16' : 'h-24'
}`}
+ aria-label={brand.name}
>
{brand.logo && (
<NextImage
@@ -20,6 +21,7 @@ const BrandCard = ({ brand }) => {
height={500}
quality={85}
className='h-full w-[122px] object-contain object-center'
+ loading='eager'
/>
)}
{!brand.logo && (
diff --git a/src/lib/flashSale/components/FlashSale.jsx b/src/lib/flashSale/components/FlashSale.jsx
index 6d90cad7..f4be279e 100644
--- a/src/lib/flashSale/components/FlashSale.jsx
+++ b/src/lib/flashSale/components/FlashSale.jsx
@@ -47,6 +47,7 @@ const FlashSale = () => {
width={1080}
height={192}
className='w-full rounded mb-4 hidden sm:block'
+ loading='eager'
/>
<Image
src={flashSale.bannerMobile}
@@ -54,6 +55,7 @@ const FlashSale = () => {
width={256}
height={48}
className='w-full rounded mb-4 block sm:hidden'
+ loading='eager'
/>
<FlashSaleProduct
flashSaleId={flashSale.pricelistId}
diff --git a/src/lib/home/components/BannerSection.jsx b/src/lib/home/components/BannerSection.jsx
index 303b5c4b..898f1bf5 100644
--- a/src/lib/home/components/BannerSection.jsx
+++ b/src/lib/home/components/BannerSection.jsx
@@ -51,6 +51,7 @@ const BannerSection = () => {
src={banner.image}
alt={banner.name}
className='h-auto w-full rounded'
+ loading='eager'
/>
</Link>
))}
diff --git a/src/lib/home/components/CategoryDynamic.jsx b/src/lib/home/components/CategoryDynamic.jsx
index cc4f42b7..b6994f60 100644
--- a/src/lib/home/components/CategoryDynamic.jsx
+++ b/src/lib/home/components/CategoryDynamic.jsx
@@ -9,6 +9,7 @@ import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
import { Pagination } from 'swiper';
+import { LazyLoadComponent } from 'react-lazy-load-image-component';
const CategoryDynamic = () => {
const [categoryManagement, setCategoryManagement] = useState([]);
@@ -22,12 +23,17 @@ const CategoryDynamic = () => {
if (data) {
setCategoryManagement(data);
}
- setIsLoading(false);
};
fetchCategoryData();
}, []);
+ useEffect(() => {
+ if (categoryManagement?.length > 0) {
+ setIsLoading(false);
+ }
+ }, [categoryManagement]);
+
const swiperBanner = {
modules: [Pagination],
classNames: 'mySwiper',
@@ -44,95 +50,105 @@ const CategoryDynamic = () => {
{categoryManagement &&
categoryManagement.map((category) => (
<Skeleton key={category.id} isLoaded={!isLoading}>
- <div key={category.id}>
- <div className='bagian-judul flex flex-row justify-start items-center gap-3 mb-4 mt-4'>
- <h1 className='font-semibold text-[14px] sm:text-h-lg mr-2'>
- {category.name}
- </h1>
- <Link
- href={createSlug(
- '/shop/category/',
- category?.name,
- category?.category_id
- )}
- className='!text-red-500 font-semibold'
- >
- Lihat Semua
- </Link>
- </div>
+ <LazyLoadComponent key={category.id}>
+ <div key={category.id}>
+ <div className='bagian-judul flex flex-row justify-start items-center gap-3 mb-4 mt-4'>
+ <h1 className='font-semibold text-[14px] sm:text-h-lg mr-2'>
+ {category.name}
+ </h1>
+ <Link
+ href={createSlug(
+ '/shop/category/',
+ category?.name,
+ category?.category_id
+ )}
+ className='!text-red-500 font-semibold'
+ >
+ Lihat Semua
+ </Link>
+ </div>
- <Swiper {...swiperBanner}>
- {category?.categories?.map((subCategory) => (
- <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'>
- <h2 className='font-semibold text-lg mr-2'>
- {subCategory?.name}
- </h2>
- <Link
- href={createSlug(
- '/shop/category/',
- subCategory?.name,
- subCategory?.id_level_2
- )}
- 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.child_frontend_id_i.map(
- (childCategory) => (
- <div key={childCategory.id} className=''>
+ <Swiper {...swiperBanner}>
+ {category?.categories?.map((subCategory) => (
+ <LazyLoadComponent key={subCategory.id}>
+ <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'
+ loading='eager'
+ />
+ <div className='bagian-judul flex flex-col justify-center items-start gap-2 ml-2'>
+ <h2 className='font-semibold text-lg mr-2'>
+ {subCategory?.name}
+ </h2>
<Link
href={createSlug(
'/shop/category/',
- childCategory?.name,
- childCategory?.id_level_3
+ subCategory?.name,
+ subCategory?.id_level_2
)}
- className='flex flex-row gap-2 border rounded group hover:border-red-500'
+ className='!text-red-500 font-semibold'
>
- <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'>
- <h3 className='font-semibold line-clamp-2 group-hover:text-red-500 text-sm mr-2'>
- {childCategory.name}
- </h3>
- </div>
+ 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.child_frontend_id_i.map(
+ (childCategory) => (
+ <LazyLoadComponent key={childCategory.id}>
+ <div key={childCategory.id} className=''>
+ <Link
+ href={createSlug(
+ '/shop/category/',
+ childCategory?.name,
+ childCategory?.id_level_3
+ )}
+ 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}
+ placeholder='blur'
+ blurDataURL='/icon.jpg'
+ loading='eager'
+ />
+ <div className='bagian-judul flex flex-col justify-center items-center gap-2 break-words line-clamp-2 group-hover:text-red-500'>
+ <h3 className='font-semibold line-clamp-2 group-hover:text-red-500 text-sm mr-2'>
+ {childCategory.name}
+ </h3>
+ </div>
+ </Link>
+ </div>
+ </LazyLoadComponent>
+ )
+ )}
+ </div>
+ </div>
</div>
- </div>
- </div>
- </SwiperSlide>
- ))}
- </Swiper>
- </div>
+ </SwiperSlide>
+ </LazyLoadComponent>
+ ))}
+ </Swiper>
+ </div>
+ </LazyLoadComponent>
</Skeleton>
))}
</div>
diff --git a/src/lib/home/components/CategoryDynamicMobile.jsx b/src/lib/home/components/CategoryDynamicMobile.jsx
index 67ae6f5f..5d9e872c 100644
--- a/src/lib/home/components/CategoryDynamicMobile.jsx
+++ b/src/lib/home/components/CategoryDynamicMobile.jsx
@@ -90,6 +90,7 @@ const CategoryDynamicMobile = () => {
width={30}
height={30}
className=''
+ loading='eager'
/>
<div className='bagian-judul flex flex-col justify-center items-start gap-1 ml-2'>
<h2 className='font-semibold text-[10px] line-clamp-1'>
@@ -123,6 +124,7 @@ const CategoryDynamicMobile = () => {
width={40}
height={40}
className='p-2'
+ loading='eager'
/>
<div className='bagian-judul flex flex-col justify-center items-start gap-1 break-words line-clamp-2 group-hover:text-red-500'>
<h3 className='font-semibold line-clamp-2 group-hover:text-red-500 text-[10px]'>
diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx
index 562fa138..d8bf3edb 100644
--- a/src/lib/home/components/PromotionProgram.jsx
+++ b/src/lib/home/components/PromotionProgram.jsx
@@ -4,56 +4,35 @@ import { bannerApi } from '@/api/bannerApi';
import useDevice from '@/core/hooks/useDevice';
import { Swiper, SwiperSlide } from 'swiper/react';
import BannerPromoSkeleton from '../components/Skeleton/BannerPromoSkeleton';
+
import { useEffect, useState } from 'react';
const { useQuery } = require('react-query');
const BannerSection = () => {
const { isMobile, isDesktop } = useDevice();
const [data, setData] = useState(null);
const [shouldFetch, setShouldFetch] = useState(false);
+ const [ isLoading, setIsLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
- const res = await fetch(`/api/hero-banner?type=banner-promotion`);
- const { data } = await res.json();
- if (data) {
- setData(data);
+ try {
+ const res = await fetch(`/api/hero-banner?type=banner-promotion`);
+ const { data } = await res.json();
+ if (data) {
+ setData(data);
+ }
+ } catch (e) {
+ console.log(e);
+ } finally {
+ setIsLoading(false);
}
};
fetchData();
}, []);
- // useEffect(() => {
- // const localData = localStorage.getItem('Homepage_promotionProgram');
- // if (localData) {
- // setData(JSON.parse(localData));
- // } else {
- // setShouldFetch(true);
- // }
- // }, []);
-
- // const getPromotionProgram = useQuery(
- // 'promotionProgram',
- // bannerApi({ type: 'banner-promotion' }),
- // {
- // enabled: shouldFetch,
- // onSuccess: (data) => {
- // if (data) {
- // localStorage.setItem(
- // 'Homepage_promotionProgram',
- // JSON.stringify(data)
- // );
- // setData(data);
- // }
- // },
- // }
- // );
-
const promotionProgram = data;
- // if (getPromotionProgram?.isLoading && !data) {
- // return <BannerPromoSkeleton />;
- // }
- if (!data) {
+ if (isLoading) {
return <BannerPromoSkeleton />;
}
@@ -90,7 +69,8 @@ const BannerSection = () => {
quality={85}
src={banner.image}
alt={banner.name}
- className='h-auto w-full rounded hover:scale-105 transition duration-500 ease-in-out'
+ className='rounded hover:scale-105 transition duration-500 ease-in-out'
+ loading='eager'
/>
</Link>
))}
@@ -103,12 +83,13 @@ const BannerSection = () => {
<SwiperSlide key={banner.id}>
<Link key={banner.id} href={banner.url}>
<Image
- width={439}
- height={150}
- quality={85}
+ width={350}
+ height={100}
+ quality={70}
src={banner.image}
alt={banner.name}
- className='h-auto w-full rounded '
+ className='rounded '
+ loading='eager'
/>
</Link>
</SwiperSlide>
diff --git a/src/lib/home/components/ServiceList.jsx b/src/lib/home/components/ServiceList.jsx
index b3cc8fe5..6d03a587 100644
--- a/src/lib/home/components/ServiceList.jsx
+++ b/src/lib/home/components/ServiceList.jsx
@@ -18,6 +18,7 @@ const ServiceList = () => {
src='/images/icon_service/ONE-STOP-SOLUTIONS.svg'
alt=''
className='h-20 w-20 rounded'
+ loading='eager'
/>
</div>
<div className=''>
@@ -43,6 +44,7 @@ const ServiceList = () => {
src='/images/icon_service/WARRANTY.svg'
alt=''
className='h-20 w-20 rounded'
+ loading='eager'
/>
</div>
<div>
@@ -68,6 +70,7 @@ const ServiceList = () => {
src='/images/icon_service/DUE-PAYMENT.svg'
alt=''
className='h-20 w-20 rounded'
+ loading='eager'
/>
</div>
<div>
@@ -93,6 +96,7 @@ const ServiceList = () => {
src='/images/icon_service/TAX.svg'
alt=''
className='h-20 w-20 rounded'
+ loading='eager'
/>
</div>
<div>
diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx
index 444ddd8e..19e76a2b 100644
--- a/src/lib/product/components/Product/ProductDesktop.jsx
+++ b/src/lib/product/components/Product/ProductDesktop.jsx
@@ -255,6 +255,7 @@ const ProductDesktop = ({ products, wishlist, toggleWishlist }) => {
>
<ImageNext
src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg'
+ alt='Flash Sale'
width={17}
height={10}
/>
diff --git a/src/lib/product/components/Product/ProductMobile.jsx b/src/lib/product/components/Product/ProductMobile.jsx
index 113a1e42..4cfd3755 100644
--- a/src/lib/product/components/Product/ProductMobile.jsx
+++ b/src/lib/product/components/Product/ProductMobile.jsx
@@ -219,6 +219,7 @@ const ProductMobile = ({ product, wishlist, toggleWishlist }) => {
>
<ImageNext
src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg'
+ alt='Flash Sale'
width={17}
height={10}
/>
diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx
index 3e6a6913..a8ed90a4 100644
--- a/src/lib/product/components/ProductCard.jsx
+++ b/src/lib/product/components/ProductCard.jsx
@@ -18,7 +18,9 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
const [discount, setDiscount] = useState(0);
const { isDesktop, isMobile } = useDevice();
let voucherPastiHemat = 0;
- voucherPastiHemat = product?.newVoucherPastiHemat[0];
+ voucherPastiHemat = product?.newVoucherPastiHemat[0]
+ ? product?.newVoucherPastiHemat[0]
+ : product?.newVoucherPastiHemat;
const callForPriceWhatsapp = whatsappUrl('product', {
name: product.name,
@@ -72,7 +74,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
if (variant == 'vertical') {
return (
<div className='rounded shadow-sm border border-gray_r-4 bg-white h-[330px] md:h-[380px]'>
- <Link href={URL.product} className='border-b border-gray_r-4 relative'>
+ <Link href={URL.product} className='border-b border-gray_r-4 relative' aria-label='Produk'>
<div className='relative'>
<Image
src={image}
@@ -88,6 +90,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
className='w-4 h-5 object-contain object-top sm:h-6'
width={50}
height={50}
+ loading='eager'
/>
)}
</div>
@@ -99,6 +102,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
className='w-11 h-6 object-contain object-top ml-1 mr-1 sm:h-6'
width={50}
height={50}
+ loading='eager'
/>
)}
</div>
@@ -113,6 +117,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
className='h-full'
width={1000}
height={100}
+ loading='eager'
/>
</div>
<div className='relative'>
@@ -125,8 +130,10 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
<div className='bg-red-600 border border-solid border-yellow-400 p-2 rounded-full h-6 flex w-fit items-center justify-center gap-x-2'>
<ImageNext
src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg'
+ alt='flash sale'
width={13}
height={5}
+ loading='eager'
/>
<span className='text-white text-[9px] md:text-[10px] font-semibold'>
{product?.flashSale?.tag != 'false' ||
@@ -148,26 +155,28 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
<div className='p-2 sm:p-3 pb-3 text-caption-2 sm:text-body-2 leading-5'>
<div className='flex justify-between '>
{product?.manufacture?.name ? (
- <Link href={URL.manufacture} className='mb-1 mt-1 truncate'>
+ <Link href={URL.manufacture} className='mb-1 mt-1 truncate' aria-label={product.manufacture.name}>
{product.manufacture.name}
</Link>
) : (
<div>-</div>
)}
{product?.isInBu && (
- <Link href='/panduan-pick-up-service' className='group'>
+ <Link href='/panduan-pick-up-service' className='group' aria-label='pickup now'>
<Image
src='/images/PICKUP-NOW.png'
className='group-hover:scale-105 transition-transform duration-200'
alt='pickup now'
width={90}
height={12}
+ loading='eager'
/>
</Link>
)}
</div>
<Link
href={URL.product}
+ aria-label={product?.name}
className={`mb-2 !text-gray_r-12 leading-6 block line-clamp-3 h-[64px]`}
title={product?.name}
>
@@ -192,6 +201,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
rel='noopener noreferrer'
target='_blank'
href={callForPriceWhatsapp}
+ aria-label='Call for Inquiry'
>
Call for Inquiry
</a>
@@ -215,6 +225,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
rel='noopener noreferrer'
target='_blank'
href={callForPriceWhatsapp}
+ aria-label='Call for Inquiry'
>
Call for Inquiry
</a>
@@ -249,7 +260,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
return (
<div className='flex bg-white'>
<div className='w-4/12'>
- <Link href={URL.product} className='relative'>
+ <Link href={URL.product} className='relative' aria-label={product?.name}>
<div className='relative'>
<Image
src={image}
@@ -265,6 +276,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
className='w-4 h-5 object-contain object-top sm:h-6'
width={50}
height={50}
+ loading='eager'
/>
)}
</div>
@@ -276,6 +288,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
className='w-11 h-6 object-contain object-top ml-1 sm:h-6'
width={50}
height={50}
+ loading='eager'
/>
)}
</div>
@@ -293,8 +306,10 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
<div className='bg-red-600 rounded-full mb-1 p-2 pl-3 pr-3 flex w-fit items-center gap-x-1'>
<ImageNext
src='/images/ICON_FLASH_SALE_WEBSITE_INDOTEKNIK.svg'
+ alt='flash sae'
width={15}
height={10}
+ loading='eager'
/>
<span className='text-white text-xs font-semibold'>
{' '}
@@ -306,7 +321,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
)}
{product?.manufacture?.name ? (
<div className='flex justify-between'>
- <Link href={URL.manufacture} className='mb-1'>
+ <Link href={URL.manufacture} className='mb-1' aria-label={product?.manufacture.name}>
{product.manufacture.name}
</Link>
{/* {product?.is_in_bu && (
@@ -322,6 +337,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
)}
<Link
href={URL.product}
+ aria-label={product?.name}
className={`mb-3 !text-gray_r-12 leading-6 line-clamp-3`}
>
{product?.name}
@@ -348,6 +364,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
rel='noopener noreferrer'
target='_blank'
href={callForPriceWhatsapp}
+ aria-label='Call for Inquiry'
>
Call for Inquiry
</a>
@@ -371,6 +388,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
rel='noopener noreferrer'
target='_blank'
href={callForPriceWhatsapp}
+ aria-label='Call for Inquiry'
>
Call for Inquiry
</a>
diff --git a/src/lib/product/components/ProductSlider.jsx b/src/lib/product/components/ProductSlider.jsx
index 54f209cc..91d199a6 100644
--- a/src/lib/product/components/ProductSlider.jsx
+++ b/src/lib/product/components/ProductSlider.jsx
@@ -35,7 +35,7 @@ const ProductSlider = ({ products, simpleTitle = false, bannerMode = false }) =>
<>
{bannerMode && (
<SwiperSlide>
- <Link href={products.banner.url} className='w-full h-full block'></Link>
+ <Link href={products.banner.url} className='w-full h-full block' aria-label={products.banner.name}></Link>
</SwiperSlide>
)}
{products?.products?.map((product, index) => (
diff --git a/src/lib/transaction/api/checkoutPoApi.js b/src/lib/transaction/api/checkoutPoApi.js
index 04421368..3376e773 100644
--- a/src/lib/transaction/api/checkoutPoApi.js
+++ b/src/lib/transaction/api/checkoutPoApi.js
@@ -1,13 +1,14 @@
-import odooApi from '@/core/api/odooApi'
-import { getAuth } from '@/core/utils/auth'
+import odooApi from '@/core/api/odooApi';
+import { getAuth } from '@/core/utils/auth';
-const checkoutPoApi = async ({ id }) => {
- const auth = getAuth()
+const checkoutPoApi = async ({ id, status }) => {
+ const auth = getAuth();
const dataCheckout = await odooApi(
'POST',
- `/api/v1/partner/${auth?.partnerId}/sale_order/${id}/checkout`
- )
- return dataCheckout
-}
+ `/api/v1/partner/${auth?.partnerId}/sale_order/${id}/checkout`,
+ { status }
+ );
+ return dataCheckout;
+};
-export default checkoutPoApi
+export default checkoutPoApi;
diff --git a/src/lib/transaction/components/Transaction.jsx b/src/lib/transaction/components/Transaction.jsx
index d001c7f4..f5dc507a 100644
--- a/src/lib/transaction/components/Transaction.jsx
+++ b/src/lib/transaction/components/Transaction.jsx
@@ -38,7 +38,9 @@ import aprpoveApi from '../api/approveApi';
import rejectApi from '../api/rejectApi';
import rejectProductApi from '../api/rejectProductApi';
import { useRouter } from 'next/router';
-
+import { gtagPurchase } from '@/core/utils/googleTag';
+import { deleteItemCart } from '@/core/utils/cart';
+import axios from 'axios';
const Transaction = ({ id }) => {
const router = useRouter();
const [isModalOpen, setIsModalOpen] = useState(false);
@@ -46,9 +48,8 @@ const Transaction = ({ id }) => {
const [reason, setReason] = useState('');
const auth = useAuth();
const { transaction } = useTransaction({ id });
-
const statusApprovalWeb = transaction.data?.approvalStep;
-
+ const [isLoading, setIsLoading] = useState(false);
const { queryAirwayBill } = useAirwayBill({ orderId: id });
const [airwayBillPopup, setAirwayBillPopup] = useState(null);
@@ -84,8 +85,26 @@ const Transaction = ({ id }) => {
};
const [cancelTransaction, setCancelTransaction] = useState(false);
+ const [continueNoPo, setContinueNoPo] = useState(false);
+ const [continueTransaction, setContinueTransaction] = useState(false);
const openCancelTransaction = () => setCancelTransaction(true);
+ const openContinueTransaction = () => {
+ if (auth.partnerTempo) {
+ checkout();
+ } else {
+ if (!transaction.data?.purchaseOrderFile) {
+ setContinueTransaction(true);
+ } else {
+ checkoutNoPO();
+ }
+ }
+ };
+ // const ContinueTransaction = () => {
+ // setContinueNoPo(true);
+ // checkoutNoPO();
+ // };
const closeCancelTransaction = () => setCancelTransaction(false);
+ const closeContinueTransaction = () => setContinueTransaction(false);
const [rejectTransaction, setRejectTransaction] = useState(false);
@@ -101,15 +120,70 @@ const Transaction = ({ id }) => {
}
closeCancelTransaction();
};
-
const checkout = async () => {
if (!transaction.data?.purchaseOrderFile) {
toast.error('Mohon upload dokumen PO anda sebelum melanjutkan pesanan');
return;
}
- await checkoutPoApi({ id });
+ await checkoutPoApi({ id, status: true });
+ toast.success('Berhasil melanjutkan pesanan');
+ transaction.refetch();
+ };
+
+ const checkoutNoPO = async () => {
+ setIsLoading(true);
+ gtagPurchase(
+ transaction.data.products,
+ transaction.data.deliveryAmount,
+ transaction.data.name
+ );
+
+ gtag('event', 'conversion', {
+ send_to: 'AW-954540379/nDymCL3BhaQYENvClMcD',
+ value:
+ transaction.data?.amountTotal +
+ Math.round(parseInt(transaction.data.deliveryAmount * 1.1) / 1000) *
+ 1000,
+ currency: 'IDR',
+ transaction_id: transaction.data.id,
+ });
+
+ for (const product of transaction.data.products)
+ deleteItemCart({ productId: product.id });
+ if (transaction.data?.amountTotal > 0) {
+ const payment = await axios.post(
+ `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/midtrans-payment?transactionId=${transaction.data.id}`
+ );
+ setIsLoading(false);
+ window.location.href = payment.data.redirectUrl;
+ } else {
+ window.location.href = `${
+ process.env.NEXT_PUBLIC_SELF_HOST
+ }/shop/checkout/success?order_id=${transaction.data.name.replace(
+ /\//g,
+ '-'
+ )}`;
+ }
toast.success('Berhasil melanjutkan pesanan');
transaction.refetch();
+
+ /* const midtrans = async () => {
+ for (const product of products) deleteItemCart({ productId: product.id });
+ if (grandTotal > 0) {
+ const payment = await axios.post(
+ `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/midtrans-payment?transactionId=${isCheckouted.id}`
+ );
+ setIsLoading(false);
+ window.location.href = payment.data.redirectUrl;
+ } else {
+ window.location.href = `${
+ process.env.NEXT_PUBLIC_SELF_HOST
+ }/shop/checkout/success?order_id=${isCheckouted.name.replace(
+ /\//g,
+ '-'
+ )}`;
+ }
+ };*/
};
const handleApproval = async () => {
@@ -208,6 +282,32 @@ const Transaction = ({ id }) => {
transaction.data?.name && (
<>
<BottomPopup
+ active={continueTransaction}
+ close={closeContinueTransaction}
+ title='Lanjutkan Transaksi'
+ >
+ <div className='leading-7 text-gray_r-12/80'>
+ Apakah anda yakin melanjutkan tanpa upload PO?{' '}
+ <span className='underline'>{transaction.data?.name}</span>?
+ </div>
+ <div className='flex justify-end mt-6 gap-x-4'>
+ <button
+ className='btn-solid-red w-full md:w-fit'
+ type='button'
+ onClick={checkoutNoPO}
+ >
+ Ya, Lanjutkan
+ </button>
+ <button
+ className='btn-light w-full md:w-fit'
+ type='button'
+ onClick={closeContinueTransaction}
+ >
+ Batal
+ </button>
+ </div>
+ </BottomPopup>
+ <BottomPopup
active={cancelTransaction}
close={closeCancelTransaction}
title='Batalkan Transaksi'
@@ -469,7 +569,10 @@ const Transaction = ({ id }) => {
)}
{transaction.data?.status == 'draft' &&
!auth?.feature?.soApproval && (
- <button className='btn-yellow w-full mt-4' onClick={checkout}>
+ <button
+ className='btn-yellow w-full mt-4'
+ onClick={openContinueTransaction}
+ >
Lanjutkan Transaksi
</button>
)}
@@ -563,7 +666,10 @@ const Transaction = ({ id }) => {
)}
{transaction.data?.status == 'draft' &&
!auth?.feature.soApproval && (
- <button className='btn-yellow' onClick={checkout}>
+ <button
+ className='btn-yellow'
+ onClick={openContinueTransaction}
+ >
Lanjutkan Transaksi
</button>
)}
@@ -778,10 +884,14 @@ const Transaction = ({ id }) => {
? `| ${product?.attributes.join(', ')}`
: ''}
</div>
- <div className='text-[10px] text-red-500 italic mt-2'>
- {product.availableQuantity} barang ini bisa di
- pickup maksimal pukul 16.00
- </div>
+ {product.soQty && product.reservedStockQty && (
+ <div className='text-[10px] text-red-500 italic mt-2'>
+ {product.soQty !== product.reservedStockQty
+ ? 'Barang sedang disiapkan'
+ : `${product.reservedStockQty} barang bisa di
+ kirim/pickup`}
+ </div>
+ )}
</div>
</td>
{/* <td>
diff --git a/src/lib/treckingAwb/component/Manifest.jsx b/src/lib/treckingAwb/component/Manifest.jsx
index 02d0bc7a..87e01e38 100644
--- a/src/lib/treckingAwb/component/Manifest.jsx
+++ b/src/lib/treckingAwb/component/Manifest.jsx
@@ -10,7 +10,6 @@ import { list } from 'postcss';
const Manifest = ({ idAWB, closePopup }) => {
const [manifests, setManifests] = useState(null);
const [isLoading, setIsLoading] = useState(false);
- console.log('manifests', manifests);
const formatCustomDate = (date) => {
const months = [
'Jan',
diff --git a/src/pages/api/flashsale-header.js b/src/pages/api/flashsale-header.js
index 31f8efdd..578801ae 100644
--- a/src/pages/api/flashsale-header.js
+++ b/src/pages/api/flashsale-header.js
@@ -15,23 +15,41 @@ export default async function handler(req, res) {
try {
await connectRedis();
const cacheKey = `flashsale_header`;
- // await client.del(cacheKey);
+
+ // Cek data yang ada di Redis
let cachedData = await client.get(cacheKey);
if (cachedData) {
const data = JSON.parse(cachedData);
+
+ // Periksa apakah data adalah array dan panjangnya 0
+ if (!data || (Array.isArray(data) && data.length === 0)) {
+ await client.del(cacheKey); // Hapus kunci jika data kosong
+ return res.status(200).json({ data: [] });
+ }
+ // Periksa apakah end_date lebih besar dari waktu saat ini
+ const currentTime = new Date();
+ if (data[0].endDate && new Date(data[0].endDate) < currentTime) {
+ await client.del(cacheKey); // Hapus kunci jika end_date lebih kecil dari waktu saat ini
+ return res.status(200).json({ data: [] });
+ }
return res.status(200).json({ data });
} else {
const flashSale = await odooApi('GET', `/api/v1/flashsale/header`);
+ if (flashSale.length === 0) {
+ return res.status(200).json({ data: [] });
+ } else {
+ await client.set(
+ cacheKey,
+ JSON.stringify(flashSale),
+ 'EX',
+ flashSale.duration
+ );
- await client.set(
- cacheKey,
- JSON.stringify(flashSale),
- 'EX',
- flashSale.duration
- );
- cachedData = await client.get(cacheKey);
- return res.status(200).json({ data: cachedData });
+ cachedData = await client.get(cacheKey);
+ const data = JSON.parse(cachedData);
+ return res.status(200).json({ data });
+ }
}
} catch (error) {
console.error('Error interacting with Redis or fetching data:', error);
diff --git a/src/pages/api/hero-banner.js b/src/pages/api/hero-banner.js
index 7a348cfa..b7f3c1c5 100644
--- a/src/pages/api/hero-banner.js
+++ b/src/pages/api/hero-banner.js
@@ -28,6 +28,8 @@ export default async function handler(req, res) {
`/api/v1/banner?type=${type}`
);
+ if(!dataBannerSections) return res.status(200).json({ data: [] });
+
// Simpan hasil fetch ke Redis dengan masa kadaluarsa 3 hari (259200 detik)
await client.set(
cacheKey,
diff --git a/src/pages/api/search-flashsale.js b/src/pages/api/search-flashsale.js
index d9e56c83..c00f6c64 100644
--- a/src/pages/api/search-flashsale.js
+++ b/src/pages/api/search-flashsale.js
@@ -23,20 +23,28 @@ export default async function handler(req, res) {
if (cachedData) {
const data = JSON.parse(cachedData);
+ // Periksa apakah data adalah array dan panjangnya 0
+ if (!data || (Array.isArray(data) && data.length === 0)) {
+ await client.del(cacheKey); // Hapus kunci jika data kosong
+ return res.status(200).json({ data: [] });
+ }
return res.status(200).json({ data });
} else {
const dataProductSearch = await axios(
`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?${query}&operation=${operation}]`
);
-
- await client.set(
- cacheKey,
- JSON.stringify(dataProductSearch.data),
- 'EX',
- duration
- );
- cachedData = await client.get(cacheKey);
- return res.status(200).json({ data: cachedData });
+ if (dataProductSearch.data.length === 0) {
+ return res.status(200).json({ data: [] });
+ } else {
+ await client.set(
+ cacheKey,
+ JSON.stringify(dataProductSearch.data),
+ 'EX',
+ duration
+ );
+ cachedData = await client.get(cacheKey);
+ return res.status(200).json({ data: cachedData });
+ }
}
} catch (error) {
console.error('Error interacting with Redis or fetching data:', error);
diff --git a/src/pages/index.jsx b/src/pages/index.jsx
index 2ec1231a..fce2202a 100644
--- a/src/pages/index.jsx
+++ b/src/pages/index.jsx
@@ -1,22 +1,26 @@
import { HeroBannerSkeleton } from '@/components/skeleton/BannerSkeleton';
import { PopularProductSkeleton } from '@/components/skeleton/PopularProductSkeleton';
-import odooApi from '@/core/api/odooApi';
import Seo from '@/core/components/Seo';
import DelayRender from '@/core/components/elements/DelayRender/DelayRender';
import DesktopView from '@/core/components/views/DesktopView';
import MobileView from '@/core/components/views/MobileView';
-import { FlashSaleSkeleton } from '@/lib/flashSale/skeleton/FlashSaleSkeleton';
-import BannerPromoSkeleton from '@/lib/home/components/Skeleton/BannerPromoSkeleton';
import PreferredBrandSkeleton from '@/lib/home/components/Skeleton/PreferredBrandSkeleton';
import dynamic from 'next/dynamic';
-import { useEffect, useRef, useState } from 'react';
+import { useRef } from 'react';
import { getAuth } from '~/libs/auth';
-import PagePopupIformation from '~/modules/popup-information'; // need change to dynamic and ssr : false
-import CategoryPilihan from '../lib/home/components/CategoryPilihan';
-// import { getAuth } from '~/libs/auth';
const BasicLayout = dynamic(() =>
- import('@/core/components/layouts/BasicLayout'),{ssr: false}
+ import('@/core/components/layouts/BasicLayout')
+);
+
+const PagePopupIformation = dynamic(() =>
+ import('~/modules/popup-information'), {
+ ssr: false
+ }
+);
+
+const CategoryPilihan = dynamic(() =>
+ import('../lib/home/components/CategoryPilihan')
);
const HeroBanner = dynamic(() => import('@/components/ui/HeroBanner'), {
loading: () => <HeroBannerSkeleton />,
@@ -40,24 +44,17 @@ const PreferredBrand = dynamic(
const FlashSale = dynamic(
() => import('@/lib/flashSale/components/FlashSale'),
- {
- loading: () => <FlashSaleSkeleton />,
- }
);
const ProgramPromotion = dynamic(
- () => import('@/lib/home/components/PromotionProgram'),
- {
- loading: () => <BannerPromoSkeleton />,
- }
+ () => import('@/lib/home/components/PromotionProgram')
);
const BannerSection = dynamic(() =>
import('@/lib/home/components/BannerSection')
);
const CategoryHomeId = dynamic(
- () => import('@/lib/home/components/CategoryHomeId'),
- { ssr: false }
+ () => import('@/lib/home/components/CategoryHomeId')
);
const CategoryDynamic = dynamic(() =>
diff --git a/src/pages/my/menu.jsx b/src/pages/my/menu.jsx
index a0ce223e..1b35d6ba 100644
--- a/src/pages/my/menu.jsx
+++ b/src/pages/my/menu.jsx
@@ -1,24 +1,24 @@
-import Divider from '@/core/components/elements/Divider/Divider'
-import Link from '@/core/components/elements/Link/Link'
-import AppLayout from '@/core/components/layouts/AppLayout'
-import useAuth from '@/core/hooks/useAuth'
-import { deleteAuth } from '@/core/utils/auth'
-import IsAuth from '@/lib/auth/components/IsAuth'
-import { ChevronRightIcon, UserIcon } from '@heroicons/react/24/solid'
-import { signOut, useSession } from 'next-auth/react'
-import { useRouter } from 'next/router'
-import ImageNext from 'next/image'
-
+import Divider from '@/core/components/elements/Divider/Divider';
+import Link from '@/core/components/elements/Link/Link';
+import AppLayout from '@/core/components/layouts/AppLayout';
+import useAuth from '@/core/hooks/useAuth';
+import { deleteAuth } from '@/core/utils/auth';
+import IsAuth from '@/lib/auth/components/IsAuth';
+import { ChevronRightIcon, UserIcon } from '@heroicons/react/24/solid';
+import { signOut, useSession } from 'next-auth/react';
+import { useRouter } from 'next/router';
+import ImageNext from 'next/image';
+import whatsappUrl from '@/core/utils/whatsappUrl';
export default function Menu() {
- const auth = useAuth()
- const router = useRouter()
- const { data: session } = useSession()
+ const auth = useAuth();
+ const router = useRouter();
+ const { data: session } = useSession();
const logout = () => {
deleteAuth().then(() => {
- router.push('/login')
- })
- }
+ router.push('/login');
+ });
+ };
return (
<IsAuth>
@@ -29,8 +29,12 @@ export default function Menu() {
</div>
<div className='ml-4'>
<div className='font-semibold text-gray_r-12'>{auth?.name}</div>
- {auth?.company && <div className='badge-solid-red mt-1'>Akun Bisnis</div>}
- {!auth?.company && <div className='badge-gray mt-1'>Akun Individu</div>}
+ {auth?.company && (
+ <div className='badge-solid-red mt-1'>Akun Bisnis</div>
+ )}
+ {!auth?.company && (
+ <div className='badge-gray mt-1'>Akun Individu</div>
+ )}
</div>
<div className='ml-auto !text-gray_r-12'>
<ChevronRightIcon className='w-6' />
@@ -47,32 +51,52 @@ export default function Menu() {
<LinkItem href='/my/quotations'>
{' '}
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_quotation.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_quotation.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Quotation</p>
</div>
</LinkItem>
<LinkItem href='/my/transactions'>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_transaksi.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_transaksi.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Transaksi</p>
</div>
</LinkItem>
<LinkItem href='/my/shipments'>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_pengiriman.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_pengiriman.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Pengiriman</p>
</div>
</LinkItem>
<LinkItem href='/my/invoices'>
{' '}
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_invoice.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_invoice.svg'
+ width={18}
+ height={20}
+ />
<p>Invoice & Faktur Pajak</p>
</div>
</LinkItem>
<LinkItem href='/my/wishlist'>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_wishlist.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_wishlist.svg'
+ width={18}
+ height={20}
+ />
<p>Wishlist</p>
</div>
</LinkItem>
@@ -83,10 +107,14 @@ export default function Menu() {
<MenuHeader>Pusat Bantuan</MenuHeader>
<div className='divide-y divide-gray_r-6 border-y border-gray_r-6 mt-4'>
- <LinkItem href='/'>
+ <LinkItem href={whatsappUrl('', '', '')}>
{' '}
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_layanan_pelanggan.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_layanan_pelanggan.svg'
+ width={18}
+ height={20}
+ />
<p>Layanan Pelanggan</p>
</div>
</LinkItem>
@@ -99,7 +127,11 @@ export default function Menu() {
<div className='divide-y divide-gray_r-6 border-y border-gray_r-6 mt-4'>
<LinkItem href='/my/address'>
<div className='flex gap-x-3 items-center'>
- <ImageNext src='/images/icon/icon_daftar_alamat.svg' width={18} height={20} />
+ <ImageNext
+ src='/images/icon/icon_daftar_alamat.svg'
+ width={18}
+ height={20}
+ />
<p>Daftar Alamat</p>
</div>
</LinkItem>
@@ -112,20 +144,23 @@ export default function Menu() {
</div>
</AppLayout>
</IsAuth>
- )
+ );
}
const MenuHeader = ({ children, ...props }) => (
<div {...props} className='font-medium px-4 flex'>
{children}
</div>
-)
+);
const LinkItem = ({ children, ...props }) => (
- <Link {...props} className='!text-gray_r-12/70 !font-normal p-4 flex items-center'>
+ <Link
+ {...props}
+ className='!text-gray_r-12/70 !font-normal p-4 flex items-center'
+ >
{children}
<div className='ml-auto !text-gray_r-11'>
<ChevronRightIcon className='w-5' />
</div>
</Link>
-)
+);
diff --git a/src/pages/sitemap/homepage.xml.js b/src/pages/sitemap/homepage.xml.js
new file mode 100644
index 00000000..08c52112
--- /dev/null
+++ b/src/pages/sitemap/homepage.xml.js
@@ -0,0 +1,33 @@
+import { create } from 'xmlbuilder';
+
+export async function getServerSideProps({ res }) {
+ const links = [
+ { label: 'Hubungi Kami', url: 'https://indoteknik.com/hubungi-kami' },
+ { label: 'Tentang Kami', url: 'https://indoteknik.com/tentang-kami' },
+ { label: 'Karir', url: 'https://indoteknik.com/karir' },
+ { label: 'Daftar Tempo', url: 'https://indoteknik.com/my/pembayaran-tempo' },
+ ];
+ const sitemap = create('urlset', { encoding: 'utf-8' }).att(
+ 'xmlns',
+ 'http://www.sitemaps.org/schemas/sitemap/0.9'
+ )
+
+ const date = new Date()
+ links.forEach((link) => {
+ const url = sitemap.ele('url')
+ url.ele('loc', link.url)
+ url.ele('lastmod', date.toISOString().slice(0, 10))
+ url.ele('changefreq', 'daily')
+ url.ele('priority', '1.0')
+ })
+
+ res.setHeader('Content-Type', 'text/xml')
+ res.write(sitemap.end())
+ res.end()
+
+ return { props: {} }
+}
+
+export default function SitemapProducts() {
+ return null
+}