diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-05-22 15:27:01 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-05-22 15:27:01 +0700 |
| commit | 1e89e64ec0bccbe89b9cede0b2054547d40589fa (patch) | |
| tree | 7910f4fa4b8526ac23cff814aa0f3983aebb874d /src | |
| parent | 33da0fcb718335eb1d077af4321ac65e0146a2d6 (diff) | |
Refactor hero banner and popular product section
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/bannerApi.js (renamed from src/api/BannerApi.js) | 2 | ||||
| -rw-r--r-- | src/api/productApi.js | 10 | ||||
| -rw-r--r-- | src/components/skeleton/BannerSkeleton.jsx | 29 | ||||
| -rw-r--r-- | src/components/skeleton/PopularProductSkeleton.jsx | 22 | ||||
| -rw-r--r-- | src/components/ui/HeroBanner.jsx | 4 | ||||
| -rw-r--r-- | src/components/ui/HeroBannerSecondary.jsx | 4 | ||||
| -rw-r--r-- | src/components/ui/PopularProduct.jsx | 44 | ||||
| -rw-r--r-- | src/lib/home/components/PopularProduct.jsx | 42 | ||||
| -rw-r--r-- | src/lib/home/hooks/usePopularProduct.js | 13 | ||||
| -rw-r--r-- | src/pages/index.jsx | 23 |
10 files changed, 107 insertions, 86 deletions
diff --git a/src/api/BannerApi.js b/src/api/bannerApi.js index 8ebecd26..8bae131d 100644 --- a/src/api/BannerApi.js +++ b/src/api/bannerApi.js @@ -1,5 +1,5 @@ import odooApi from '@/core/api/odooApi' -export const BannerApi = ({ type }) => { +export const bannerApi = ({ type }) => { return async () => await odooApi('GET', `/api/v1/banner?type=${type}`) } diff --git a/src/api/productApi.js b/src/api/productApi.js new file mode 100644 index 00000000..cca052f7 --- /dev/null +++ b/src/api/productApi.js @@ -0,0 +1,10 @@ +import axios from 'axios' + +export const popularProductApi = () => { + return async () => { + const dataPopularProducts = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?q=*&page=1&orderBy=popular` + ) + return dataPopularProducts.data.response + } +} diff --git a/src/components/skeleton/BannerSkeleton.jsx b/src/components/skeleton/BannerSkeleton.jsx index 3de9c027..7cb3952d 100644 --- a/src/components/skeleton/BannerSkeleton.jsx +++ b/src/components/skeleton/BannerSkeleton.jsx @@ -1,19 +1,20 @@ +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() + + const deviceClassName = { + 'min-h-[460px]': isDesktop, + 'min-h-[230px]': isMobile + } + const defaultClassName = 'h-full' + const combinedClassName = classNames(defaultClassName, deviceClassName) + return ( - <div role='status' className='animate-pulse h-full min-h-[460px]'> - <div className='flex justify-center items-center h-full w-full mb-4 bg-gray-300 rounded' aria-busy> - <svg - className='w-20 h-20 text-gray-100' - xmlns='http://www.w3.org/2000/svg' - aria-hidden='true' - fill='currentColor' - viewBox='0 0 640 512' - > - <path d='M480 80C480 35.82 515.8 0 560 0C604.2 0 640 35.82 640 80C640 124.2 604.2 160 560 160C515.8 160 480 124.2 480 80zM0 456.1C0 445.6 2.964 435.3 8.551 426.4L225.3 81.01C231.9 70.42 243.5 64 256 64C268.5 64 280.1 70.42 286.8 81.01L412.7 281.7L460.9 202.7C464.1 196.1 472.2 192 480 192C487.8 192 495 196.1 499.1 202.7L631.1 419.1C636.9 428.6 640 439.7 640 450.9C640 484.6 612.6 512 578.9 512H55.91C25.03 512 .0006 486.1 .0006 456.1L0 456.1z' /> - </svg> - </div> - <span className='sr-only'>Loading...</span> - </div> + <Skeleton className={combinedClassName} count={1} containerClassName='w-full h-full block' /> ) } diff --git a/src/components/skeleton/PopularProductSkeleton.jsx b/src/components/skeleton/PopularProductSkeleton.jsx new file mode 100644 index 00000000..0aea5c59 --- /dev/null +++ b/src/components/skeleton/PopularProductSkeleton.jsx @@ -0,0 +1,22 @@ +import DesktopView from '@/core/components/views/DesktopView' +import MobileView from '@/core/components/views/MobileView' +import Skeleton from 'react-loading-skeleton' + +const PopularProductSkeleton = () => { + return ( + <> + <MobileView> + <div className='px-4'> + <Skeleton count={1} className='!w-36 h-8' /> + <Skeleton count={2} className='h-64' containerClassName='flex gap-x-2 mt-4' /> + </div> + </MobileView> + + <DesktopView> + <Skeleton count={1} className='h-full' /> + </DesktopView> + </> + ) +} + +export { PopularProductSkeleton } diff --git a/src/components/ui/HeroBanner.jsx b/src/components/ui/HeroBanner.jsx index 1b5bf165..96bd8917 100644 --- a/src/components/ui/HeroBanner.jsx +++ b/src/components/ui/HeroBanner.jsx @@ -9,7 +9,7 @@ import { useMemo } from 'react' import Link from '@/core/components/elements/Link/Link' import Image from '@/core/components/elements/Image/Image' import { useQuery } from 'react-query' -import { BannerApi } from '@/api/BannerApi' +import { bannerApi } from '@/api/bannerApi' import { HeroBannerSkeleton } from '../skeleton/BannerSkeleton' const swiperBanner = { @@ -24,7 +24,7 @@ const swiperBanner = { } const HeroBanner = () => { - const heroBanner = useQuery('heroBanner', BannerApi({ type: 'index-a-1' })) + const heroBanner = useQuery('heroBanner', bannerApi({ type: 'index-a-1' })) const swiperBannerMobile = { ...swiperBanner, diff --git a/src/components/ui/HeroBannerSecondary.jsx b/src/components/ui/HeroBannerSecondary.jsx index a3227002..b1023990 100644 --- a/src/components/ui/HeroBannerSecondary.jsx +++ b/src/components/ui/HeroBannerSecondary.jsx @@ -4,10 +4,10 @@ import Image from 'next/image' import { useMemo } from 'react' import { useQuery } from 'react-query' import { HeroBannerSkeleton } from '../skeleton/BannerSkeleton' -import { BannerApi } from '@/api/BannerApi' +import { bannerApi } from '@/api/bannerApi' const HeroBannerSecondary = () => { - const heroBannerSecondary = useQuery('heroBannerSecondary', BannerApi({ type: 'index-a-2' })) + const heroBannerSecondary = useQuery('heroBannerSecondary', bannerApi({ type: 'index-a-2' })) const randomIndex = useMemo(() => { if (!heroBannerSecondary.data) return null diff --git a/src/components/ui/PopularProduct.jsx b/src/components/ui/PopularProduct.jsx new file mode 100644 index 00000000..211291c8 --- /dev/null +++ b/src/components/ui/PopularProduct.jsx @@ -0,0 +1,44 @@ +import { popularProductApi } from '@/api/productApi' +import MobileView from '@/core/components/views/MobileView' +import ProductSlider from '@/lib/product/components/ProductSlider' +import { useQuery } from 'react-query' +import { PopularProductSkeleton } from '../skeleton/PopularProductSkeleton' +import DesktopView from '@/core/components/views/DesktopView' +import ProductCard from '@/lib/product/components/ProductCard' + +const PopularProduct = () => { + const popularProduct = useQuery('popularProduct', popularProductApi()) + + if (popularProduct.isLoading) return <PopularProductSkeleton /> + + return ( + popularProduct.data && ( + <> + <MobileView> + <div className='px-4'> + <div className='font-medium mb-4'>Produk Banyak Dilihat</div> + <ProductSlider products={popularProduct.data} simpleTitle /> + </div> + </MobileView> + + <DesktopView> + <div className='border border-gray_r-6 h-full overflow-auto'> + <div className='font-medium text-center p-4 bg-gray_r-1 border-b border-gray_r-6 sticky top-0 z-10'> + Produk Banyak Dilihat + </div> + <div className='h-full divide-y divide-gray_r-6'> + {popularProduct.data && + popularProduct.data.products.map((product) => ( + <div className='py-2' key={product.id}> + <ProductCard product={product} variant='horizontal' /> + </div> + ))} + </div> + </div> + </DesktopView> + </> + ) + ) +} + +export default PopularProduct diff --git a/src/lib/home/components/PopularProduct.jsx b/src/lib/home/components/PopularProduct.jsx deleted file mode 100644 index 3ce7527e..00000000 --- a/src/lib/home/components/PopularProduct.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import usePopularProduct from '../hooks/usePopularProduct' -import PopularProductSkeleton from './Skeleton/PopularProductSkeleton' -import ProductSlider from '@/lib/product/components/ProductSlider' -import DesktopView from '@/core/components/views/DesktopView' -import MobileView from '@/core/components/views/MobileView' -import ProductCard from '@/lib/product/components/ProductCard' - -const PopularProduct = () => { - const { popularProducts } = usePopularProduct() - - return ( - <> - <MobileView> - <div className='px-4'> - <div className='font-medium mb-4'>Produk Banyak Dilihat</div> - {popularProducts.isLoading && <PopularProductSkeleton />} - {!popularProducts.isLoading && ( - <ProductSlider products={popularProducts.data} simpleTitle /> - )} - </div> - </MobileView> - - <DesktopView> - <div className='border border-gray_r-6 h-full overflow-auto'> - <div className='font-medium text-center p-4 bg-gray_r-1 border-b border-gray_r-6 sticky top-0 z-10'> - Produk Banyak Dilihat - </div> - <div className='h-full divide-y divide-gray_r-6'> - {popularProducts.data && - popularProducts.data.products.map((product) => ( - <div className='py-2' key={product.id}> - <ProductCard product={product} variant='horizontal' /> - </div> - ))} - </div> - </div> - </DesktopView> - </> - ) -} - -export default PopularProduct diff --git a/src/lib/home/hooks/usePopularProduct.js b/src/lib/home/hooks/usePopularProduct.js deleted file mode 100644 index d0c34bb0..00000000 --- a/src/lib/home/hooks/usePopularProduct.js +++ /dev/null @@ -1,13 +0,0 @@ -import popularProductApi from '../api/popularProductApi' -import { useQuery } from 'react-query' - -const usePopularProduct = () => { - const fetchPopularProduct = async () => await popularProductApi() - const { data, isLoading } = useQuery('popularProduct', fetchPopularProduct) - - return { - popularProducts: { data, isLoading } - } -} - -export default usePopularProduct diff --git a/src/pages/index.jsx b/src/pages/index.jsx index ea4949b2..43a3b8c9 100644 --- a/src/pages/index.jsx +++ b/src/pages/index.jsx @@ -1,29 +1,28 @@ import dynamic from 'next/dynamic' -import ImageSkeleton from '@/core/components/elements/Skeleton/ImageSkeleton' -import PopularProductSkeleton from '@/lib/home/components/Skeleton/PopularProductSkeleton' import MobileView from '@/core/components/views/MobileView' import DesktopView from '@/core/components/views/DesktopView' import { useRef } from 'react' import Seo from '@/core/components/Seo' import DelayRender from '@/core/components/elements/DelayRender/DelayRender' -import HeroBannerSecondary from '@/components/ui/HeroBannerSecondary' import { HeroBannerSkeleton } from '@/components/skeleton/BannerSkeleton' +import { PopularProductSkeleton } from '@/components/skeleton/PopularProductSkeleton' const BasicLayout = dynamic(() => import('@/core/components/layouts/BasicLayout')) -const FlashSale = dynamic(() => import('@/lib/flashSale/components/FlashSale')) -const BannerSection = dynamic(() => import('@/lib/home/components/BannerSection')) const HeroBanner = dynamic(() => import('@/components/ui/HeroBanner'), { loading: () => <HeroBannerSkeleton /> }) -const PreferredBrand = dynamic(() => import('@/lib/home/components/PreferredBrand'), { - loading: () => <PopularProductSkeleton /> -}) -const PopularProduct = dynamic(() => import('@/lib/home/components/PopularProduct'), { - loading: () => <PopularProductSkeleton /> +const HeroBannerSecondary = dynamic(() => import('@/components/ui/HeroBannerSecondary'), { + loading: () => <HeroBannerSkeleton /> }) -const CategoryHomeId = dynamic(() => import('@/lib/home/components/CategoryHomeId'), { +const PopularProduct = dynamic(() => import('@/components/ui/PopularProduct'), { loading: () => <PopularProductSkeleton /> }) + +const PreferredBrand = dynamic(() => import('@/lib/home/components/PreferredBrand')) + +const FlashSale = dynamic(() => import('@/lib/flashSale/components/FlashSale')) +const BannerSection = dynamic(() => import('@/lib/home/components/BannerSection')) +const CategoryHomeId = dynamic(() => import('@/lib/home/components/CategoryHomeId')) const CustomerReviews = dynamic(() => import('@/lib/review/components/CustomerReviews')) export default function Home() { @@ -51,7 +50,7 @@ export default function Home() { <DesktopView> <div className='container mx-auto'> - <div className='flex h-[360px]' ref={wrapperRef} onLoad={handleOnLoad}> + <div className='flex min-h-[400px] h-[460px]' ref={wrapperRef} onLoad={handleOnLoad}> <div className='w-2/12'> <HeroBannerSecondary /> </div> |
