diff options
| author | Indoteknik . <andrifebriyadiputra@gmail.com> | 2025-08-16 09:52:55 +0700 |
|---|---|---|
| committer | Indoteknik . <andrifebriyadiputra@gmail.com> | 2025-08-16 09:52:55 +0700 |
| commit | d32ed92902d52934a55cdb9efe110ef11cd920d8 (patch) | |
| tree | 912307287d6aa919310098c2e17f439c1016b679 /src/lib/home/components | |
| parent | 8158cf84d27334362ac618afd42a8f0c759915a8 (diff) | |
(andri) make component card mediacard
Diffstat (limited to 'src/lib/home/components')
| -rw-r--r-- | src/lib/home/components/MediaNews.jsx | 137 | ||||
| -rw-r--r-- | src/lib/home/components/Skeleton/MediaNewsSkeleton.jsx | 21 |
2 files changed, 73 insertions, 85 deletions
diff --git a/src/lib/home/components/MediaNews.jsx b/src/lib/home/components/MediaNews.jsx index 1e538d48..1c76398f 100644 --- a/src/lib/home/components/MediaNews.jsx +++ b/src/lib/home/components/MediaNews.jsx @@ -1,101 +1,68 @@ -import Link from '@/core/components/elements/Link/Link'; -import Image from 'next/image'; -import { bannerApi } from '@/api/bannerApi'; -import useDevice from '@/core/hooks/useDevice'; import { Swiper, SwiperSlide } from 'swiper/react'; -import BannerPromoSkeleton from '../components/Skeleton/BannerPromoSkeleton'; +import { Navigation, Pagination, Autoplay } from 'swiper'; +import { useEffect, useState, useCallback } from 'react'; +import MediaNewsSkeleton from './Skeleton/MediaNewsSkeleton'; +import MediaCard from '@/lib/brand/components/MediaCard'; +import useDevice from '@/core/hooks/useDevice'; +import Link from '@/core/components/elements/Link/Link'; -import { useEffect, useState } from 'react'; -const { useQuery } = require('react-query'); -const BannerSection = () => { +const MediaNews = () => { + const [isLoading, setIsLoading] = useState(true); + const [media, setMedia] = useState([]); const { isMobile, isDesktop } = useDevice(); - const [data, setData] = useState(null); - const [shouldFetch, setShouldFetch] = useState(false); - const [ isLoading, setIsLoading] = useState(true); - useEffect(() => { - const fetchData = async () => { - 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(); + const loadMedia = useCallback(async () => { + try { + setIsLoading(true); + const res = await fetch(`/api/hero-banner?type=media-berita`); + const result = await res.json(); + setMedia(result.data || []); + } catch (err) { + console.error('Failed to load media:', err); + } finally { + setIsLoading(false); + } }, []); - const promotionProgram = data; + useEffect(() => { + loadMedia(); + }, [loadMedia]); - if (isLoading) { - return <BannerPromoSkeleton />; - } + const swiperConfig = { + modules: [Navigation, Pagination, Autoplay], + autoplay: { delay: 4000, disableOnInteraction: false }, + loop: true, + className: 'h-[70px] md:h-[100px] w-full', + slidesPerView: isMobile ? 4 : 8, + spaceBetween: isMobile ? 12 : 0, + pagination: { dynamicBullets: true, dynamicMainBullets: isMobile ? 6 : 8, clickable: true }, + }; - if (!promotionProgram || promotionProgram.length === 0) { - return null; - } + const preferredMediaData = media.slice(0, 20); return ( - <div className='px-4 sm:px-0'> - <div className='flex justify-between items-center mb-4 '> - <h1 className='font-semibold text-[14px] sm:text-h-lg'> - {' '} - <Link href='/shop/promo' className='!text-black font-semibold'> - Promo Tersedia + <div className="px-4 sm:px-0"> + <div className="flex justify-between items-center mb-4"> + <h1 className="font-semibold text-[14px] sm:text-h-lg"> + <Link href="/shop/media" className="!text-black font-semibold"> + Media Berita </Link> </h1> - {isDesktop && ( - <Link href='/shop/promo' className='!text-red-500 font-semibold'> - Lihat Semua - </Link> - )} - {isMobile && ( - <Link - href='/shop/promo' - className='!text-red-500 font-semibold sm:text-h-sm' - > - Lihat Semua - </Link> - )} + <Link + href="/shop/media" + className="!text-red-500 font-semibold sm:text-h-sm" + > + Lihat Semua + </Link> </div> - {isDesktop && promotionProgram && promotionProgram?.length > 0 && ( - <div className='grid grid-cols-3 sm:grid-cols-3 gap-4 rounded-md'> - {promotionProgram?.map((banner) => ( - <Link key={banner.id} href={banner.url}> - <Image - width={439} - height={150} - quality={85} - src={banner.image} - alt={banner.name} - className='rounded hover:scale-105 transition duration-500 ease-in-out' - loading='eager' - /> - </Link> - ))} - </div> - )} - {isMobile && ( - <Swiper slidesPerView={1.1} spaceBetween={8} freeMode> - {promotionProgram?.map((banner) => ( - <SwiperSlide key={banner.id}> - <Link key={banner.id} href={banner.url}> - <Image - width={350} - height={100} - quality={70} - src={banner.image} - alt={banner.name} - className='rounded ' - loading='eager' - /> - </Link> + {isLoading ? ( + <MediaNewsSkeleton /> + ) : ( + <Swiper {...swiperConfig}> + {preferredMediaData.map((item) => ( + <SwiperSlide key={item.id}> + <MediaCard media={item} /> </SwiperSlide> ))} </Swiper> @@ -104,4 +71,4 @@ const BannerSection = () => { ); }; -export default BannerSection; +export default MediaNews; diff --git a/src/lib/home/components/Skeleton/MediaNewsSkeleton.jsx b/src/lib/home/components/Skeleton/MediaNewsSkeleton.jsx new file mode 100644 index 00000000..c0151efd --- /dev/null +++ b/src/lib/home/components/Skeleton/MediaNewsSkeleton.jsx @@ -0,0 +1,21 @@ +import useDevice from '@/core/hooks/useDevice' +import Skeleton from 'react-loading-skeleton' + +const MediaNewsSkeleton = () => { + 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 + key={index} + count={1} + height={isDesktop ? 84 : 56} + className="rounded-lg" + /> + ))} + </div> + ) +} + +export default MediaNewsSkeleton |
