summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIT Fixcomart <it@fixcomart.co.id>2025-10-16 10:59:56 +0000
committerIT Fixcomart <it@fixcomart.co.id>2025-10-16 10:59:56 +0000
commit5590a8cf2423c14baa991abf18ca31179a62c2bd (patch)
treed263d376c68279f6b7eecb6bebe5fb5fb81365f3
parentf6b1aea824192572b241f94157ab3731dec6a4ea (diff)
parent9fa82a1c56e6e1628ef5a255ba3f66fb6aec83ec (diff)
Merged in media_banner (pull request #469)
Media banner
-rw-r--r--src/lib/brand/components/BrandCard.jsx1
-rw-r--r--src/lib/brand/components/MediaCard.jsx42
-rw-r--r--src/lib/home/api/mediaNews.js0
-rw-r--r--src/lib/home/components/MediaNews.jsx80
-rw-r--r--src/lib/home/components/Skeleton/MediaNewsSkeleton.jsx21
-rw-r--r--src/pages/index.jsx3
6 files changed, 147 insertions, 0 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/api/mediaNews.js b/src/lib/home/api/mediaNews.js
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/lib/home/api/mediaNews.js
diff --git a/src/lib/home/components/MediaNews.jsx b/src/lib/home/components/MediaNews.jsx
new file mode 100644
index 00000000..6a0efbfe
--- /dev/null
+++ b/src/lib/home/components/MediaNews.jsx
@@ -0,0 +1,80 @@
+import { Swiper, SwiperSlide } from 'swiper/react';
+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';
+
+const MediaNews = () => {
+ const [isLoading, setIsLoading] = useState(true);
+ const [media, setMedia] = useState([]);
+ const { isMobile, isDesktop } = useDevice();
+
+ 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);
+ }
+ }, []);
+
+ useEffect(() => {
+ loadMedia();
+ }, [loadMedia]);
+
+ 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 },
+ };
+
+ const preferredMediaData = media.slice(0, 20);
+
+ const shouldUseSlider = isMobile || (isDesktop && preferredMediaData.length > 8);
+
+ if (!isLoading && preferredMediaData.length === 0) {
+ return null;
+ }
+
+ 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="/" className="!text-black font-semibold">
+ Telah Diliput Media
+ </Link>
+ </h1>
+ </div>
+
+ {isLoading ? (
+ <MediaNewsSkeleton />
+ ) : shouldUseSlider ? (
+ <Swiper {...swiperConfig}>
+ {preferredMediaData.map((item) => (
+ <SwiperSlide key={item.id}>
+ <MediaCard media={item} />
+ </SwiperSlide>
+ ))}
+ </Swiper>
+ ) : (
+ <div className="flex flex-wrap justify-center gap-4">
+ {preferredMediaData.map((item) => (
+ <MediaCard key={item.id} media={item} />
+ ))}
+ </div>
+ )}
+ </div>
+ );
+};
+
+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..28db4d3e 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')
@@ -139,6 +140,7 @@ export default function Home({ categoryId }) {
<div className='my-16 flex flex-col gap-y-8'>
<ServiceList />
+ <MediaNews />
<div id='flashsale'>
<PreferredBrand />
</div>
@@ -169,6 +171,7 @@ export default function Home({ categoryId }) {
<div className='flex flex-col gap-y-4 my-6'>
<DelayRender renderAfter={400}>
<ServiceList />
+ <MediaNews />
</DelayRender>
<DelayRender renderAfter={400}>
<div id='flashsale'>