diff options
| author | Miqdad <ahmadmiqdad27@gmail.com> | 2025-06-06 13:20:29 +0700 |
|---|---|---|
| committer | Miqdad <ahmadmiqdad27@gmail.com> | 2025-06-06 13:20:29 +0700 |
| commit | 56ba7cb194e8a664cb0144e7091159e10b8c56ab (patch) | |
| tree | a8ee81b818067a01434d21a5835b8d72b09bb81b | |
| parent | f42a816422a0c7fab40a98123cadf8268e05d37e (diff) | |
<miqdad> private banner section
| -rw-r--r-- | src/lib/home/components/BannerSection.jsx | 158 | ||||
| -rw-r--r-- | src/lib/home/components/CategoryHomeId.jsx | 2 | ||||
| -rw-r--r-- | src/pages/api/banner-section.js | 74 |
3 files changed, 178 insertions, 56 deletions
diff --git a/src/lib/home/components/BannerSection.jsx b/src/lib/home/components/BannerSection.jsx index 898f1bf5..1eac9592 100644 --- a/src/lib/home/components/BannerSection.jsx +++ b/src/lib/home/components/BannerSection.jsx @@ -1,62 +1,126 @@ import Link from '@/core/components/elements/Link/Link'; -import Image from 'next/image'; import { useEffect, useState } from 'react'; -import { bannerApi } from '../../../api/bannerApi'; - -const { useQuery } = require('react-query'); -const { default: bannerSectionApi } = require('../api/bannerSectionApi'); +import useDevice from '@/core/hooks/useDevice'; +import { Swiper, SwiperSlide } from 'swiper/react'; const BannerSection = () => { - const [data, setData] = useState(null); - const [shouldFetch, setShouldFetch] = useState(false); - + const [privateBrandData, setPrivateBrandData] = useState([]); + const [homeBannerData, setHomeBannerData] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const { isMobile, isDesktop } = useDevice(); useEffect(() => { - const fetchCategoryData = async () => { - const res = await fetch('/api/banner-section'); - const { data } = await res.json(); - if (data) { - setData(data); + const fetchAllBanners = async () => { + try { + // Fetch private brand banners + const privateBrandRes = await fetch( + '/api/banner-section?type=private-brand' + ); + if (privateBrandRes.ok) { + const privateBrandResult = await privateBrandRes.json(); + setPrivateBrandData(privateBrandResult.data || []); + } + + // Fetch home banners + const homeBannerRes = await fetch( + '/api/banner-section?type=home-banner' + ); + if (homeBannerRes.ok) { + const homeBannerResult = await homeBannerRes.json(); + setHomeBannerData(homeBannerResult.data || []); + } + } catch (err) { + setError('Network error'); + } finally { + setLoading(false); } }; - fetchCategoryData(); + fetchAllBanners(); }, []); - // const fetchBannerSection = async () => await bannerSectionApi(); - const getBannerSection = useQuery( - 'bannerSection', - bannerApi({ type: 'home-banner' }), - { - enabled: shouldFetch, - onSuccess: (data) => { - if (data) { - localStorage.setItem('Homepage_bannerSection', JSON.stringify(data)); - setData(data); - } - }, - } - ); + // if (loading) return <div>Loading...</div>; + // if (error) return <div>Error: {error}</div>; - const bannerSection = data; return ( - bannerSection && - bannerSection?.length > 0 && ( - <div className='grid grid-cols-1 sm:grid-cols-2 gap-4'> - {bannerSection?.map((banner) => ( - <Link key={banner.id} href={banner.url}> - <Image - width={1024} - height={512} - quality={85} - src={banner.image} - alt={banner.name} - className='h-auto w-full rounded' - loading='eager' - /> - </Link> - ))} - </div> - ) + <div className='space-y-12'> + {/* Private Brand Section */} + {privateBrandData && privateBrandData.length > 0 && ( + <div className='px-4 sm:px-0'> + <div + className='text-black font-semibold sm:text-h-lg mb-6' + id='private-brand' + > + Private Brand + </div> + + {/* Desktop Grid View */} + {isDesktop && ( + <div className='grid grid-cols-3 sm:grid-cols-3 gap-4 rounded-md'> + {privateBrandData.map((banner, index) => ( + <Link key={banner.id || index} href={banner.url || '#'}> + <img + width={439} + height={150} + quality={85} + src={banner.image} + alt={banner.name || `Private Brand Banner ${index + 1}`} + className='rounded hover:scale-105 transition duration-500 ease-in-out' + loading='eager' + /> + </Link> + ))} + </div> + )} + + {/* Mobile Swiper View */} + {isMobile && ( + <Swiper slidesPerView={1.1} spaceBetween={8} freeMode> + {privateBrandData.map((banner, index) => ( + <SwiperSlide key={banner.id || index}> + <Link href={banner.url || '#'}> + <img + width={350} + height={100} + quality={70} + src={banner.image} + alt={banner.name || `Private Brand Banner ${index + 1}`} + className='rounded' + loading='eager' + /> + </Link> + </SwiperSlide> + ))} + </Swiper> + )} + </div> + )} + + {/* Home Banner Section */} + {homeBannerData && homeBannerData.length > 0 && ( + <div className='grid grid-cols-1 sm:grid-cols-2 gap-4'> + {homeBannerData.map((banner, index) => ( + <div key={banner.id || index} className='relative'> + <Link href={banner.url || '#'}> + <img + width={1024} + height={512} + quality={85} + src={banner.image} + alt={banner.name || `Home Banner ${index + 1}`} + // className='h-40 w-full rounded object-cover transition-transform hover:scale-105' + className='h-auto w-full rounded' + loading='eager' + onError={(e) => { + e.target.style.display = 'none'; + }} + /> + </Link> + </div> + ))} + </div> + )} + </div> ); }; diff --git a/src/lib/home/components/CategoryHomeId.jsx b/src/lib/home/components/CategoryHomeId.jsx index 823795e2..db473a1c 100644 --- a/src/lib/home/components/CategoryHomeId.jsx +++ b/src/lib/home/components/CategoryHomeId.jsx @@ -8,7 +8,7 @@ const CategoryHomeId = () => { return ( <div> <h1 className='font-semibold text-[14px] sm:text-h-lg mb-6 px-4 sm:px-0'> - Kategori Paket Bundling / Paket UMKM + Paket Bundling / Paket UMKM </h1> <div className='flex flex-col gap-y-10'> {categoryHomeIds.data?.map((id) => ( diff --git a/src/pages/api/banner-section.js b/src/pages/api/banner-section.js index 7d7040c0..ab48f3f4 100644 --- a/src/pages/api/banner-section.js +++ b/src/pages/api/banner-section.js @@ -12,22 +12,81 @@ const connectRedis = async () => { }; export default async function handler(req, res) { + if (req.method !== 'GET') { + return res.status(405).json({ error: 'Method not allowed' }); + } + try { await connectRedis(); - const cacheKey = 'hero-banner'; - // await client.del(cacheKey); + + const type = req.query.type || 'home-banner'; + + if (type === 'private-brand') { + // Handle multiple private brand banner types + const bannerTypes = [ + 'banner-brand-footer', + 'banner-brand-tengah-footer', + 'banner-brand-kanan-footer', + ]; + + const allBanners = []; + + for (const brandType of bannerTypes) { + const brandCacheKey = `homepage_bannerSection_${brandType}`; + + let cachedData = await client.get(brandCacheKey); + + if (cachedData) { + const data = JSON.parse(cachedData); + allBanners.push(...(data || [])); + } else { + try { + const dataBannerSections = await odooApi( + 'GET', + `/api/v1/banner?type=${brandType}` + ); + + if (dataBannerSections && dataBannerSections.length > 0) { + await client.set( + brandCacheKey, + JSON.stringify(dataBannerSections), + 'EX', + 259200 + ); + allBanners.push(...dataBannerSections); + } + } catch (error) { + continue; + } + } + } + + return res.status(200).json({ + data: allBanners, + total: allBanners.length, + }); + } + + // Handle home-banner and other single types + let cacheKey; + let apiEndpoint; + + if (type === 'home-banner') { + cacheKey = 'hero-banner'; + apiEndpoint = '/api/v1/banner?type=home-banner'; + } else { + cacheKey = `homepage_bannerSection_${type}`; + apiEndpoint = `/api/v1/banner?type=${type}`; + } + let cachedData = await client.get(cacheKey); if (cachedData) { const data = JSON.parse(cachedData); return res.status(200).json({ data }); } else { - const dataBannerSections = await odooApi( - 'GET', - '/api/v1/banner?type=home-banner' - ); + const dataBannerSections = await odooApi('GET', apiEndpoint); - // Simpan hasil fetch ke Redis dengan masa kadaluarsa 3 hari (259200 detik) await client.set( cacheKey, JSON.stringify(dataBannerSections), @@ -38,7 +97,6 @@ export default async function handler(req, res) { return res.status(200).json({ data: dataBannerSections }); } } catch (error) { - console.error('Error interacting with Redis or fetching data:', error); return res.status(500).json({ error: 'Internal Server Error' }); } } |
