summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRafi Zadanly <zadanlyr@gmail.com>2023-08-08 10:39:34 +0700
committerRafi Zadanly <zadanlyr@gmail.com>2023-08-08 10:39:34 +0700
commit16fed2e7d00252f5df3f9b5bdf0a5a2b2a094f76 (patch)
tree53d9f4d8991ba699b30eacfac1b2498ae1b0bf48 /src
parentf862f6426c28fb9245d13fb7386a88b209639d64 (diff)
Improve home page performance
Diffstat (limited to 'src')
-rw-r--r--src/components/skeleton/BannerSkeleton.jsx1
-rw-r--r--src/core/components/elements/Navbar/NavbarDesktop.jsx5
-rw-r--r--src/core/components/elements/Navbar/Search.jsx30
-rw-r--r--src/core/components/elements/Navbar/TopBanner.jsx5
-rw-r--r--src/core/components/elements/Skeleton/TopBannerSkeleton.jsx19
-rw-r--r--src/core/components/layouts/BasicLayout.jsx1
-rw-r--r--src/lib/flashSale/components/FlashSale.jsx13
-rw-r--r--src/lib/flashSale/skeleton/FlashSaleSkeleton.jsx36
-rw-r--r--src/lib/home/components/Skeleton/PreferredBrandSkeleton.jsx22
-rw-r--r--src/lib/product/components/ProductCard.jsx2
-rw-r--r--src/pages/_app.jsx1
-rw-r--r--src/pages/index.jsx36
12 files changed, 122 insertions, 49 deletions
diff --git a/src/components/skeleton/BannerSkeleton.jsx b/src/components/skeleton/BannerSkeleton.jsx
index 7cb3952d..da86aef9 100644
--- a/src/components/skeleton/BannerSkeleton.jsx
+++ b/src/components/skeleton/BannerSkeleton.jsx
@@ -1,7 +1,6 @@
import useDevice from '@/core/hooks/useDevice'
import classNames from 'classnames'
import Skeleton from 'react-loading-skeleton'
-import 'react-loading-skeleton/dist/skeleton.css'
const HeroBannerSkeleton = () => {
const { isDesktop, isMobile } = useDevice()
diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx
index 1f5204cd..acd2d1ee 100644
--- a/src/core/components/elements/Navbar/NavbarDesktop.jsx
+++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx
@@ -14,14 +14,17 @@ import { useEffect, useState } from 'react'
import useAuth from '@/core/hooks/useAuth'
import NavbarUserDropdown from './NavbarUserDropdown'
import { getCountCart } from '@/core/utils/cart'
-import TopBanner from './TopBanner'
import whatsappUrl from '@/core/utils/whatsappUrl'
import { useRouter } from 'next/router'
import { getAuth } from '@/core/utils/auth'
import { createSlug, getIdFromSlug } from '@/core/utils/slug'
import productApi from '@/lib/product/api/productApi'
+import { TopBannerSkeleton } from '../Skeleton/TopBannerSkeleton'
const Search = dynamic(() => import('./Search'))
+const TopBanner = dynamic(() => import('./TopBanner'), {
+ loading: () => <TopBannerSkeleton />
+})
const NavbarDesktop = () => {
const [isOpenCategory, setIsOpenCategory] = useState(false)
diff --git a/src/core/components/elements/Navbar/Search.jsx b/src/core/components/elements/Navbar/Search.jsx
index 47a9c235..f4a8ab3a 100644
--- a/src/core/components/elements/Navbar/Search.jsx
+++ b/src/core/components/elements/Navbar/Search.jsx
@@ -64,21 +64,21 @@ const Search = () => {
<MagnifyingGlassIcon className='w-6' />
</button>
- {suggestions.length > 0 && (
- <>
- <div className='absolute w-full top-[50px] rounded-b bg-gray_r-1 border border-gray_r-6 divide-y divide-gray_r-6 z-50'>
- {suggestions.map((suggestion, index) => (
- <Link
- href={`/shop/search?q=${suggestion.term}`}
- key={index}
- className='px-3 py-3 !text-gray_r-12 font-normal'
- >
- {suggestion.term}
- </Link>
- ))}
- </div>
- </>
- )}
+ <div
+ className={`absolute w-full top-[50px] rounded-b bg-gray_r-1 border border-gray_r-6 divide-y divide-gray_r-6 z-50 ${
+ suggestions.length > 0 ? 'block' : 'hidden'
+ }`}
+ >
+ {suggestions.map((suggestion, index) => (
+ <Link
+ href={`/shop/search?q=${suggestion.term}`}
+ key={index}
+ className='px-3 py-3 !text-gray_r-12 font-normal'
+ >
+ {suggestion.term}
+ </Link>
+ ))}
+ </div>
</form>
</>
)
diff --git a/src/core/components/elements/Navbar/TopBanner.jsx b/src/core/components/elements/Navbar/TopBanner.jsx
index 9efd0a8d..dca2e930 100644
--- a/src/core/components/elements/Navbar/TopBanner.jsx
+++ b/src/core/components/elements/Navbar/TopBanner.jsx
@@ -2,11 +2,16 @@ 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'
const TopBanner = () => {
const fetchTopBanner = async () => await odooApi('GET', '/api/v1/banner?type=top-banner')
const topBanner = useQuery('topBanner', fetchTopBanner)
+ if (topBanner.isLoading) {
+ return <TopBannerSkeleton />
+ }
+
return (
topBanner.isFetched &&
topBanner.data?.length > 0 && (
diff --git a/src/core/components/elements/Skeleton/TopBannerSkeleton.jsx b/src/core/components/elements/Skeleton/TopBannerSkeleton.jsx
new file mode 100644
index 00000000..f7d2e748
--- /dev/null
+++ b/src/core/components/elements/Skeleton/TopBannerSkeleton.jsx
@@ -0,0 +1,19 @@
+import useDevice from '@/core/hooks/useDevice'
+import classNames from 'classnames'
+import Skeleton from 'react-loading-skeleton'
+
+const TopBannerSkeleton = () => {
+ const { isDesktop, isMobile } = useDevice()
+
+ const deviceClassName = {
+ 'h-10': isDesktop,
+ 'h-2.5': isMobile
+ }
+ const combinedClassName = classNames(deviceClassName)
+
+ return (
+ <Skeleton className={combinedClassName} count={1} containerClassName='w-full h-full block' />
+ )
+}
+
+export { TopBannerSkeleton }
diff --git a/src/core/components/layouts/BasicLayout.jsx b/src/core/components/layouts/BasicLayout.jsx
index 073303fe..554f587d 100644
--- a/src/core/components/layouts/BasicLayout.jsx
+++ b/src/core/components/layouts/BasicLayout.jsx
@@ -46,7 +46,6 @@ const BasicLayout = ({ children }) => {
}
getProduct()
setTemplateWA('product')
-
}
}, [])
return (
diff --git a/src/lib/flashSale/components/FlashSale.jsx b/src/lib/flashSale/components/FlashSale.jsx
index e4a4a25c..87545d8d 100644
--- a/src/lib/flashSale/components/FlashSale.jsx
+++ b/src/lib/flashSale/components/FlashSale.jsx
@@ -1,21 +1,28 @@
import { useEffect, useState } from 'react'
import flashSaleApi from '../api/flashSaleApi'
-import Image from '@/core/components/elements/Image/Image'
+import Image from 'next/image'
import CountDown from '@/core/components/elements/CountDown/CountDown'
import productSearchApi from '@/lib/product/api/productSearchApi'
import ProductSlider from '@/lib/product/components/ProductSlider'
+import { FlashSaleSkeleton } from '../skeleton/FlashSaleSkeleton'
const FlashSale = () => {
const [flashSales, setFlashSales] = useState(null)
+ const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
const loadFlashSales = async () => {
const dataFlashSales = await flashSaleApi()
setFlashSales(dataFlashSales)
+ setIsLoading(false)
}
loadFlashSales()
}, [])
+ if (isLoading) {
+ return <FlashSaleSkeleton />
+ }
+
return (
flashSales?.length > 0 && (
<div className='px-4 sm:px-0 grid grid-cols-1 gap-y-8'>
@@ -30,11 +37,15 @@ const FlashSale = () => {
<Image
src={flashSale.banner}
alt={flashSale.name}
+ width={1080}
+ height={192}
className='w-full rounded mb-4 hidden sm:block'
/>
<Image
src={flashSale.bannerMobile}
alt={flashSale.name}
+ width={256}
+ height={48}
className='w-full rounded mb-4 block sm:hidden'
/>
<FlashSaleProduct flashSaleId={flashSale.pricelistId} />
diff --git a/src/lib/flashSale/skeleton/FlashSaleSkeleton.jsx b/src/lib/flashSale/skeleton/FlashSaleSkeleton.jsx
new file mode 100644
index 00000000..e9a200d9
--- /dev/null
+++ b/src/lib/flashSale/skeleton/FlashSaleSkeleton.jsx
@@ -0,0 +1,36 @@
+import useDevice from '@/core/hooks/useDevice'
+import PopularProductSkeleton from '@/lib/home/components/Skeleton/PopularProductSkeleton'
+import Skeleton from 'react-loading-skeleton'
+
+const FlashSaleSkeleton = () => {
+ return (
+ <div className='px-4 md:px-0'>
+ <TitleSkeleton />
+ <div className='my-4'>
+ <BannerSkeleton />
+ </div>
+ <PopularProductSkeleton />
+ </div>
+ )
+}
+
+const TitleSkeleton = () => {
+ return (
+ <div className='w-full md:w-[36%] flex gap-x-4'>
+ <Skeleton containerClassName='block w-1/2' height={24} />
+ <div className='w-1/2 flex gap-x-1'>
+ <Skeleton height={40} containerClassName='w-full' />
+ <Skeleton height={40} containerClassName='w-full' />
+ <Skeleton height={40} containerClassName='w-full' />
+ <Skeleton height={40} containerClassName='w-full' />
+ </div>
+ </div>
+ )
+}
+
+const BannerSkeleton = () => {
+ const { isDesktop } = useDevice()
+ return <Skeleton duration={1.2} height={isDesktop ? 192 : 48} containerClassName='w-full' />
+}
+
+export { FlashSaleSkeleton, TitleSkeleton, BannerSkeleton }
diff --git a/src/lib/home/components/Skeleton/PreferredBrandSkeleton.jsx b/src/lib/home/components/Skeleton/PreferredBrandSkeleton.jsx
index 00589342..bd783053 100644
--- a/src/lib/home/components/Skeleton/PreferredBrandSkeleton.jsx
+++ b/src/lib/home/components/Skeleton/PreferredBrandSkeleton.jsx
@@ -1,12 +1,16 @@
-import BrandSkeleton from '@/core/components/elements/Skeleton/BrandSkeleton'
+import useDevice from '@/core/hooks/useDevice'
+import Skeleton from 'react-loading-skeleton'
-const PreferredBrandSkeleton = () => (
- <div className='grid grid-cols-4 gap-x-3'>
- <BrandSkeleton />
- <BrandSkeleton />
- <BrandSkeleton />
- <BrandSkeleton />
- </div>
-)
+const PreferredBrandSkeleton = () => {
+ const { isDesktop } = useDevice()
+
+ return (
+ <div className='grid grid-cols-4 md:grid-cols-8 gap-x-3'>
+ {Array.from({ length: isDesktop ? 8 : 4 }, (_, index) => (
+ <Skeleton count={1} height={isDesktop ? 84 : 56} key={index} />
+ ))}
+ </div>
+ )
+}
export default PreferredBrandSkeleton
diff --git a/src/lib/product/components/ProductCard.jsx b/src/lib/product/components/ProductCard.jsx
index a8964310..51a369c4 100644
--- a/src/lib/product/components/ProductCard.jsx
+++ b/src/lib/product/components/ProductCard.jsx
@@ -12,7 +12,7 @@ const ProductCard = ({ product, simpleTitle, variant = 'vertical' }) => {
if (variant == 'vertical') {
return (
- <div className='rounded shadow-sm border border-gray_r-4 bg-white h-[350px]'>
+ <div className='rounded shadow-sm border border-gray_r-4 bg-white h-[280px] md:h-[320px]'>
<Link
href={createSlug('/shop/product/', product?.name, product?.id)}
className='border-b border-gray_r-4 relative'
diff --git a/src/pages/_app.jsx b/src/pages/_app.jsx
index 4c4fed89..03147219 100644
--- a/src/pages/_app.jsx
+++ b/src/pages/_app.jsx
@@ -1,4 +1,5 @@
import '../styles/globals.css'
+import 'react-loading-skeleton/dist/skeleton.css'
import NextProgress from 'next-progress'
import { useRouter, Router } from 'next/router'
import { AnimatePresence, motion } from 'framer-motion'
diff --git a/src/pages/index.jsx b/src/pages/index.jsx
index 12d2ab46..47a0a493 100644
--- a/src/pages/index.jsx
+++ b/src/pages/index.jsx
@@ -7,6 +7,8 @@ import DelayRender from '@/core/components/elements/DelayRender/DelayRender'
import { HeroBannerSkeleton } from '@/components/skeleton/BannerSkeleton'
import { PopularProductSkeleton } from '@/components/skeleton/PopularProductSkeleton'
import PromotinProgram from '@/lib/promotinProgram/components/HomePage'
+import PreferredBrandSkeleton from '@/lib/home/components/Skeleton/PreferredBrandSkeleton'
+import { FlashSaleSkeleton } from '@/lib/flashSale/skeleton/FlashSaleSkeleton'
const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout'))
const HeroBanner = dynamic(() => import('@/components/ui/HeroBanner'), {
@@ -19,9 +21,13 @@ const PopularProduct = dynamic(() => import('@/components/ui/PopularProduct'), {
loading: () => <PopularProductSkeleton />
})
-const PreferredBrand = dynamic(() => import('@/lib/home/components/PreferredBrand'))
+const PreferredBrand = dynamic(() => import('@/lib/home/components/PreferredBrand'), {
+ loading: () => <PreferredBrandSkeleton />
+})
-const FlashSale = dynamic(() => import('@/lib/flashSale/components/FlashSale'))
+const FlashSale = dynamic(() => import('@/lib/flashSale/components/FlashSale'), {
+ loading: () => <FlashSaleSkeleton />
+})
const BannerSection = dynamic(() => import('@/lib/home/components/BannerSection'))
const CategoryHomeId = dynamic(() => import('@/lib/home/components/CategoryHomeId'))
const CustomerReviews = dynamic(() => import('@/lib/review/components/CustomerReviews'))
@@ -66,22 +72,12 @@ export default function Home() {
</div>
<div className='my-16 flex flex-col gap-y-16'>
- <DelayRender renderAfter={400}>
- <PreferredBrand />
- </DelayRender>
- <DelayRender renderAfter={600}>
- <FlashSale />
- </DelayRender>
- <DelayRender renderAfter={600}>
- <PromotinProgram />
- </DelayRender>
- <DelayRender renderAfter={1000}>
- <CategoryHomeId />
- <BannerSection />
- </DelayRender>
- <DelayRender renderAfter={1200}>
- <CustomerReviews />
- </DelayRender>
+ <PreferredBrand />
+ <FlashSale />
+ <PromotinProgram />
+ <CategoryHomeId />
+ <BannerSection />
+ <CustomerReviews />
</div>
</div>
</DesktopView>
@@ -98,8 +94,8 @@ export default function Home() {
<FlashSale />
</DelayRender>
<DelayRender renderAfter={600}>
- <PromotinProgram />
- </DelayRender>
+ <PromotinProgram />
+ </DelayRender>
<DelayRender renderAfter={800}>
<PopularProduct />
</DelayRender>