qudoco-fe/components/landing-page/news-services-article-secti...

170 lines
4.9 KiB
TypeScript

"use client";
import Link from "next/link";
import { Badge } from "@/components/ui/badge";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import type { PublicArticle } from "@/lib/articles-public";
import {
NEWS_SERVICES_TAB_ORDER,
NEWS_TAB_LABEL,
type NewsServicesTab,
} from "@/constants/news-services";
import { formatDate } from "@/utils/global";
import ArticleThumbnail from "@/components/landing-page/article-thumbnail";
const BADGE_COLORS = [
"bg-red-600",
"bg-yellow-500",
"bg-yellow-600",
"bg-[#0f3b63]",
];
function firstTag(tags: string | undefined): string {
if (!tags?.trim()) return "";
const t = tags
.split(",")
.map((s) => s.trim())
.filter(Boolean)[0];
return t ?? "";
}
function articleHref(a: PublicArticle) {
return `/news/detail/${a.id}-${a.slug}`;
}
type Props = {
id?: string;
title: string;
articlesByTab: Record<NewsServicesTab, PublicArticle[]>;
showViews?: boolean;
exploreHref?: string;
exploreLabel?: string;
};
export default function NewsServicesArticleSection({
id,
title,
articlesByTab,
showViews,
exploreHref = "#konten-terpopuler",
exploreLabel = "Lihat konten terpopuler",
}: Props) {
const defaultTab = NEWS_SERVICES_TAB_ORDER[0];
return (
<section id={id} className="py-20">
<div className="container mx-auto px-6">
<div className="mb-12 flex flex-col items-center">
<h2 className="mb-6 text-3xl font-bold">{title}</h2>
<Tabs defaultValue={defaultTab} className="w-full">
<div className="relative w-full pb-3">
<div className="flex justify-center">
<TabsList
className="gap-8 bg-transparent p-0"
variant={"line"}
>
{NEWS_SERVICES_TAB_ORDER.map((tab) => (
<TabsTrigger
key={tab}
value={tab}
className="px-0 pb-2 data-[state=active]:text-[#b07c18]"
>
{NEWS_TAB_LABEL[tab]}
</TabsTrigger>
))}
</TabsList>
</div>
<Link
href={exploreHref}
className="absolute top-1/2 right-0 hidden -translate-y-1/2 cursor-pointer text-sm text-muted-foreground hover:text-black md:block"
>
{exploreLabel}
</Link>
</div>
{NEWS_SERVICES_TAB_ORDER.map((tab) => (
<TabsContent key={tab} value={tab} className="mt-12">
<CardGrid
articles={articlesByTab[tab] ?? []}
showViews={showViews}
/>
</TabsContent>
))}
</Tabs>
</div>
</div>
</section>
);
}
function CardGrid({
articles,
showViews,
}: {
articles: PublicArticle[];
showViews?: boolean;
}) {
if (articles.length === 0) {
return (
<p className="text-center text-muted-foreground">
Belum ada konten yang dipublikasikan untuk tab ini.
</p>
);
}
return (
<div className="grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-4">
{articles.map((item) => {
const badgeClass = BADGE_COLORS[item.id % BADGE_COLORS.length];
const category =
item.categoryName?.trim() || "Berita";
const tag = firstTag(item.tags);
const dateSrc = item.publishedAt || item.createdAt;
return (
<Link
key={item.id}
href={articleHref(item)}
className="block overflow-hidden rounded-2xl bg-white shadow-sm transition-all duration-300 hover:shadow-lg"
>
<div className="relative h-[220px]">
<ArticleThumbnail
src={item.thumbnailUrl}
alt={item.title}
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 25vw"
/>
</div>
<div className="space-y-3 p-5">
<div className="flex flex-wrap items-center gap-3">
<Badge
className={`${badgeClass} px-2 py-1 text-xs text-white`}
>
{category}
</Badge>
{tag ? (
<span className="text-xs text-muted-foreground">{tag}</span>
) : null}
</div>
<p className="text-xs text-muted-foreground">
{formatDate(dateSrc)}
{showViews && item.viewCount != null ? (
<span className="ml-2">· {item.viewCount} tayangan</span>
) : null}
</p>
<h3 className="line-clamp-3 text-sm font-semibold leading-snug transition hover:text-[#b07c18]">
{item.title}
</h3>
</div>
</Link>
);
})}
</div>
);
}