summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIndoteknik . <andrifebriyadiputra@gmail.com>2025-08-16 09:52:55 +0700
committerIndoteknik . <andrifebriyadiputra@gmail.com>2025-08-16 09:52:55 +0700
commitd32ed92902d52934a55cdb9efe110ef11cd920d8 (patch)
tree912307287d6aa919310098c2e17f439c1016b679
parent8158cf84d27334362ac618afd42a8f0c759915a8 (diff)
(andri) make component card mediacard
-rw-r--r--src/lib/brand/components/BrandCard.jsx1
-rw-r--r--src/lib/brand/components/MediaCard.jsx42
-rw-r--r--src/lib/home/components/MediaNews.jsx137
-rw-r--r--src/lib/home/components/Skeleton/MediaNewsSkeleton.jsx21
-rw-r--r--src/pages/index.jsx3
5 files changed, 119 insertions, 85 deletions
diff --git a/src/lib/brand/components/BrandCard.jsx b/src/lib/brand/components/BrandCard.jsx
index dff61b24..411e2669 100644
--- a/src/lib/brand/components/BrandCard.jsx
+++ b/src/lib/brand/components/BrandCard.jsx
@@ -5,6 +5,7 @@ import { createSlug } from '@/core/utils/slug';
const BrandCard = ({ brand }) => {
const { isMobile } = useDevice();
+ // console.log("Brand logo:", brand.logo);
return (
<Link
href={createSlug('/shop/brands/', brand.name, brand.id)}
diff --git a/src/lib/brand/components/MediaCard.jsx b/src/lib/brand/components/MediaCard.jsx
new file mode 100644
index 00000000..a6591abd
--- /dev/null
+++ b/src/lib/brand/components/MediaCard.jsx
@@ -0,0 +1,42 @@
+import NextImage from 'next/image';
+import Link from '@/core/components/elements/Link/Link';
+import useDevice from '@/core/hooks/useDevice';
+import { createSlug } from '@/core/utils/slug';
+
+const MediaCard = ({ media }) => {
+ const { isMobile } = useDevice();
+
+// console.log("Media logo:", media);
+
+ return (
+ <Link
+ href={createSlug('/shop/media/', media.name, media.id)}
+ 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={media.name}
+ >
+ {media.image ? (
+ <NextImage
+ src={media.image}
+ alt={media.name}
+ width={500}
+ height={500}
+ quality={85}
+ className="h-full w-[122px] object-contain object-center"
+ />
+ ) : (
+ <span
+ className="text-center"
+ style={{ fontSize: `${16 - media.name.length * 0.5}px` }}
+ >
+ {media.name}
+ </span>
+ )}
+ </Link>
+ );
+};
+
+export default MediaCard;
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
diff --git a/src/pages/index.jsx b/src/pages/index.jsx
index 809f00ae..bb375c53 100644
--- a/src/pages/index.jsx
+++ b/src/pages/index.jsx
@@ -9,6 +9,7 @@ import PagePopupInformation from '@/lib/home/components/PopupBannerPromotion';
import dynamic from 'next/dynamic';
import { useRef } from 'react';
import { getAuth } from '~/libs/auth';
+import MediaNews from '../lib/home/components/MediaNews';
const BasicLayout = dynamic(() =>
import('@/core/components/layouts/BasicLayout')
@@ -138,6 +139,7 @@ export default function Home({ categoryId }) {
</div>
<div className='my-16 flex flex-col gap-y-8'>
+ <MediaNews />
<ServiceList />
<div id='flashsale'>
<PreferredBrand />
@@ -168,6 +170,7 @@ export default function Home({ categoryId }) {
</DelayRender>
<div className='flex flex-col gap-y-4 my-6'>
<DelayRender renderAfter={400}>
+ <MediaNews />
<ServiceList />
</DelayRender>
<DelayRender renderAfter={400}>