410 lines
14 KiB
TypeScript
410 lines
14 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Image from "next/image";
|
|
import { getListArticle } from "@/service/article";
|
|
import { ScrollArea } from "@/components/ui/scroll-area"; // pastikan ada komponen ini
|
|
import { Calendar } from "lucide-react";
|
|
import Link from "next/link";
|
|
import { getAdvertise } from "@/service/advertisement";
|
|
|
|
type Article = {
|
|
id: number;
|
|
title: string;
|
|
description: string;
|
|
categoryName: string;
|
|
createdAt: string;
|
|
createdByName: string;
|
|
thumbnailUrl: string;
|
|
files: { fileUrl: string; file_alt: string }[];
|
|
};
|
|
|
|
type Advertise = {
|
|
id: number;
|
|
title: string;
|
|
description: string;
|
|
placement: string;
|
|
contentFileUrl: string;
|
|
redirectLink: string;
|
|
};
|
|
|
|
export default function News() {
|
|
const [articles, setArticles] = useState<Article[]>([]);
|
|
const [recentPosts, setRecentPosts] = useState<Article[]>([]);
|
|
const [bannerAd, setBannerAd] = useState<Advertise | null>(null);
|
|
const [bannerImageAd, setBannerImageAd] = useState<Advertise | null>(null);
|
|
useEffect(() => {
|
|
initStateAdver();
|
|
}, []);
|
|
|
|
async function initStateAdver() {
|
|
const req = {
|
|
limit: 100,
|
|
page: 1,
|
|
sort: "desc",
|
|
sortBy: "created_at",
|
|
isPublish: true,
|
|
};
|
|
|
|
try {
|
|
const res = await getAdvertise(req);
|
|
const data: Advertise[] = res?.data?.data || [];
|
|
|
|
// ambil iklan placement jumbotron
|
|
const jumbotron = data.find((ad) => ad.placement === "jumbotron");
|
|
if (jumbotron) setBannerAd(jumbotron);
|
|
|
|
// ambil iklan placement banner
|
|
const banner = data.find((ad) => ad.placement === "banner");
|
|
if (banner) setBannerImageAd(banner);
|
|
} catch (err) {
|
|
console.error("Error fetching advertisement:", err);
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
fetchArticles();
|
|
fetchRecentPosts();
|
|
}, []);
|
|
|
|
async function fetchArticles() {
|
|
try {
|
|
const req = {
|
|
limit: "8", // ambil 8 artikel untuk konten utama
|
|
page: 1,
|
|
search: "",
|
|
categorySlug: "",
|
|
sort: "desc",
|
|
isPublish: true,
|
|
sortBy: "created_at",
|
|
};
|
|
|
|
const res = await getListArticle(req);
|
|
setArticles(res?.data?.data || []);
|
|
} catch (error) {
|
|
console.error("Gagal memuat artikel utama:", error);
|
|
}
|
|
}
|
|
|
|
async function fetchRecentPosts() {
|
|
try {
|
|
const req = {
|
|
limit: "5", // ambil 5 artikel untuk recent posts
|
|
page: 1,
|
|
search: "",
|
|
categorySlug: "",
|
|
sort: "desc",
|
|
isPublish: true,
|
|
sortBy: "created_at",
|
|
};
|
|
|
|
const res = await getListArticle(req);
|
|
setRecentPosts(res?.data?.data || []);
|
|
} catch (error) {
|
|
console.error("Gagal memuat recent posts:", error);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="max-w-[1300px] mx-auto grid grid-cols-1 lg:grid-cols-3 gap-6 py-10 bg-white">
|
|
{/* Scrollable Left Section */}
|
|
<ScrollArea className="lg:col-span-2 pl-4 pr-4 md:pr-4">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
{articles.slice(0, 4).map((article) => (
|
|
<div key={article.id}>
|
|
<Link href={`/detail/${article?.id}`}>
|
|
<div className="w-full h-[280px] relative overflow-hidden">
|
|
<Image
|
|
src={
|
|
article.thumbnailUrl ||
|
|
article.files?.[0]?.fileUrl ||
|
|
"/default.jpg"
|
|
}
|
|
alt={article.title}
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
</div>
|
|
<p className="text-xs text-[#717582] mt-2 ">
|
|
{article.categoryName}
|
|
</p>
|
|
<h2 className="text-2xl font-semibold font-serif text-[#2481D3] hover:text-blue-400 mt-2">
|
|
{article.title}
|
|
</h2>
|
|
<p className="mt-2 text-[#717582] text-[14px] line-clamp-3">
|
|
{article.description}
|
|
</p>
|
|
<div className="flex flex-row item-center gap-3">
|
|
<div className="text-sm text-black">
|
|
{article.createdByName}{" "}
|
|
</div>
|
|
<div className="text-blue-400 mt-1">
|
|
<Calendar size={12} />
|
|
</div>
|
|
<div className="text-sm ">
|
|
{new Date(article.createdAt).toLocaleDateString("en-GB", {
|
|
day: "2-digit",
|
|
month: "long",
|
|
year: "numeric",
|
|
})}
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Banner */}
|
|
<div className="relative w-full my-10 h-[160px] md:h-[188px] overflow-hidden flex items-center border">
|
|
{bannerImageAd ? (
|
|
<a
|
|
href={bannerImageAd.redirectLink}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="w-full h-full relative"
|
|
>
|
|
<Image
|
|
src={bannerImageAd.contentFileUrl}
|
|
alt={bannerImageAd.title || "Iklan Banner"}
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
</a>
|
|
) : (
|
|
<Image
|
|
src="/image-kolom.png"
|
|
alt="Banner Default"
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
{/* Artikel kedua */}
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
|
{articles.slice(4, 8).map((article) => (
|
|
<div key={article.id}>
|
|
<Link href={`/detail/${article?.id}`}>
|
|
<div className="w-full h-[280px] relative overflow-hidden">
|
|
<Image
|
|
src={
|
|
article.thumbnailUrl ||
|
|
article.files?.[0]?.fileUrl ||
|
|
"/default.jpg"
|
|
}
|
|
alt={article.title}
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
</div>
|
|
<p className="text-xs text-[#717582] mt-2 ">
|
|
{article.categoryName}
|
|
</p>
|
|
<h2 className="text-2xl font-semibold font-serif text-[#2481D3] hover:text-blue-400 mt-2">
|
|
{article.title}
|
|
</h2>
|
|
<p className="mt-2 text-[#717582] text-[14px] line-clamp-3">
|
|
{article.description}
|
|
</p>
|
|
<div className="flex flex-row item-center gap-3">
|
|
<div className="text-sm text-black">
|
|
{article.createdByName}{" "}
|
|
</div>
|
|
<div className="text-blue-400 mt-1">
|
|
<Calendar size={12} />
|
|
</div>
|
|
<div className="text-sm ">
|
|
{new Date(article.createdAt).toLocaleDateString("en-GB", {
|
|
day: "2-digit",
|
|
month: "long",
|
|
year: "numeric",
|
|
})}
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Banner */}
|
|
<div className="relative w-full my-10 h-[160px] md:h-[188px] overflow-hidden flex items-center border">
|
|
{bannerImageAd ? (
|
|
<a
|
|
href={bannerImageAd.redirectLink}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="w-full h-full relative"
|
|
>
|
|
<Image
|
|
src={bannerImageAd.contentFileUrl}
|
|
alt={bannerImageAd.title || "Iklan Banner"}
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
</a>
|
|
) : (
|
|
<Image
|
|
src="/image-kolom.png"
|
|
alt="Banner Default"
|
|
fill
|
|
className="object-cover"
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
{/* Pagination (sementara statis, bisa pakai API meta untuk dinamis) */}
|
|
<div className="flex justify-end gap-3">
|
|
<button className="w-8 h-8 flex items-center justify-center rounded-full bg-[#2481D3] text-white font-semibold">
|
|
1
|
|
</button>
|
|
<button className="w-8 h-8 flex items-center justify-center rounded-full border border-blue-300 text-[#2481D3] font-semibold hover:bg-blue-80">
|
|
2
|
|
</button>
|
|
<div className="w-8 h-8 flex items-center justify-center text-blue-500 font-semibold">
|
|
...
|
|
</div>
|
|
<button className="w-8 h-8 flex items-center justify-center rounded-full border border-blue-300 text-[#2481D3] font-semibold hover:bg-blue-80">
|
|
7
|
|
</button>
|
|
<button className="w-8 h-8 flex items-center justify-center rounded-full border border-blue-300 text-[#2481D3] hover:bg-blue-100">
|
|
<svg
|
|
className="w-4 h-4"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth={2}
|
|
viewBox="0 0 24 24"
|
|
>
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
d="M9 5l7 7-7 7"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</ScrollArea>
|
|
|
|
{/* Fixed Right Section */}
|
|
<div className="sticky top-10 h-fit bg-white mx-3 md:mx-0">
|
|
<h3 className="text-xl font-semibold text-[#2481D3] border-b pb-2 mb-4">
|
|
Recent Posts
|
|
</h3>
|
|
|
|
<div className="space-y-8">
|
|
{recentPosts.map((item) => (
|
|
<div key={item.id}>
|
|
<Link
|
|
className="flex items-start gap-3"
|
|
href={`/detail/${item?.id}`}
|
|
>
|
|
<div className="w-[80px] h-[80px] relative shrink-0">
|
|
<Image
|
|
src={
|
|
item.thumbnailUrl ||
|
|
item.files?.[0]?.fileUrl ||
|
|
"/default.jpg"
|
|
}
|
|
alt={item.title}
|
|
fill
|
|
className="object-cover "
|
|
/>
|
|
</div>
|
|
<div className="text-sm flex flex-col gap-1">
|
|
<p className="text-[#717582] text-xs font-bold">
|
|
{item.categoryName}
|
|
</p>
|
|
<p className="text-[#2481D3] hover:text-blue-400 font-semibold line-clamp-2 w-10/12">
|
|
{item.title}
|
|
</p>
|
|
<p className="text-xs text-[#717582]">
|
|
{new Date(item.createdAt).toLocaleDateString("en-GB", {
|
|
day: "2-digit",
|
|
month: "long",
|
|
year: "numeric",
|
|
})}
|
|
</p>
|
|
</div>
|
|
</Link>
|
|
</div>
|
|
))}
|
|
|
|
{/* Ads / Subscribe */}
|
|
<div className="relative rounded w-full md:w-[300px] border ">
|
|
{bannerAd ? (
|
|
<a
|
|
href={bannerAd.redirectLink}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="block w-full"
|
|
>
|
|
<div className="relative w-full h-[350px] flex justify-center">
|
|
<Image
|
|
src={bannerAd.contentFileUrl}
|
|
alt={bannerAd.title || "Iklan Banner"}
|
|
width={1200} // ukuran dasar untuk responsive
|
|
height={350}
|
|
className="object-cover w-full h-full"
|
|
/>
|
|
</div>
|
|
</a>
|
|
) : (
|
|
<Image
|
|
src="/kolom.png"
|
|
alt="Berita Utama"
|
|
width={1200}
|
|
height={188}
|
|
className="object-contain w-full h-[188px]"
|
|
/>
|
|
)}
|
|
</div>
|
|
<div className="border p-5 w-full md:w-[300px] ">
|
|
<h3 className="text-[#2481D3] text-lg font-semibold mb-2 w-10/12">
|
|
Subscribe us to get the latest news!
|
|
</h3>
|
|
<label htmlFor="email" className="text-sm font-semibold block mb-2">
|
|
Email:
|
|
</label>
|
|
<input
|
|
type="email"
|
|
id="email"
|
|
placeholder="Your email address"
|
|
className="w-full px-4 py-2 border border-gray-300 rounded mb-3 text-sm"
|
|
/>
|
|
<button className="bg-[#2481D3] text-white px-4 py-2 rounded text-sm hover:bg-blue-700 transition">
|
|
SUBSCRIBE
|
|
</button>
|
|
</div>
|
|
<div className="relative rounded w-full md:w-[300px] border ">
|
|
{bannerAd ? (
|
|
<a
|
|
href={bannerAd.redirectLink}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="block w-full"
|
|
>
|
|
<div className="relative w-full h-[350px] flex justify-center">
|
|
<Image
|
|
src={bannerAd.contentFileUrl}
|
|
alt={bannerAd.title || "Iklan Banner"}
|
|
width={1200} // ukuran dasar untuk responsive
|
|
height={350}
|
|
className="object-cover w-full h-full"
|
|
/>
|
|
</div>
|
|
</a>
|
|
) : (
|
|
<Image
|
|
src="/kolom.png"
|
|
alt="Berita Utama"
|
|
width={1200}
|
|
height={188}
|
|
className="object-contain w-full h-[188px]"
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|