kontenhumas-fe/components/landing-page/media-update.tsx

653 lines
21 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import Image from "next/image";
import { Button } from "@/components/ui/button";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Card } from "@/components/ui/card";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css";
import "swiper/css/navigation";
import { Navigation } from "swiper/modules";
import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
import { listData, listArticles } from "@/service/landing/landing";
import { toggleBookmark, getBookmarkSummaryForUser } from "@/service/content";
import { getCookiesDecrypt } from "@/lib/utils";
import Link from "next/link";
import { ThumbsUp, ThumbsDown } from "lucide-react";
// 🔹 Fungsi format tanggal ke WIB
function formatTanggal(dateString: string) {
if (!dateString) return "";
return (
new Date(dateString)
.toLocaleString("id-ID", {
day: "2-digit",
month: "short",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
hour12: false,
timeZone: "Asia/Jakarta",
})
.replace(/\./g, ":") + " WIB"
);
}
export default function MediaUpdate() {
const [tipeKonten, setTipeKonten] = useState<
"image" | "video" | "text" | "audio"
>("image");
const [urutan, setUrutan] = useState<"latest" | "popular">("latest");
const [dataKonten, setDataKonten] = useState<any[]>([]);
const [bookmarkedIds, setBookmarkedIds] = useState<Set<number>>(new Set());
const [loading, setLoading] = useState(true);
const MySwal = withReactContent(Swal);
// 🔹 Pemetaan tipe konten ke typeId API
const typeMap: Record<typeof tipeKonten, number> = {
image: 1,
video: 2,
text: 3,
audio: 4,
};
useEffect(() => {
ambilData();
}, [tipeKonten, urutan]);
async function ambilData() {
try {
setLoading(true);
const typeId = typeMap[tipeKonten];
const sortBy = urutan === "latest" ? "createdAt" : "viewCount";
// 🔹 Panggil API baru
const response = await listArticles(
1,
20,
typeId,
undefined,
undefined,
sortBy
);
let hasil: any[] = [];
if (response?.error) {
console.error(
"Gagal ambil data dari listArticles, fallback ke listData"
);
const fallback = await listData(
String(typeId),
"",
"",
20,
0,
urutan === "latest" ? "createdAt" : "clickCount",
"",
"",
""
);
hasil = fallback?.data?.data?.content || [];
} else {
hasil = response?.data?.data || [];
}
// 🔹 Normalisasi data artikel
const dataBaru = hasil.map((a: any) => ({
id: a.id,
title: a.title,
category:
a.categoryName ||
(a.categories && a.categories[0]?.title) ||
"Tanpa Kategori",
createdAt: a.createdAt,
smallThumbnailLink: a.thumbnailUrl,
typeId: a.typeId,
}));
setDataKonten(dataBaru);
// 🔹 Sinkronisasi data bookmark
const roleId = Number(getCookiesDecrypt("urie"));
if (roleId && !isNaN(roleId)) {
const simpananLocal = localStorage.getItem("bookmarkedIds");
let localSet = new Set<number>();
if (simpananLocal) {
localSet = new Set(JSON.parse(simpananLocal));
setBookmarkedIds(localSet);
}
const res = await getBookmarkSummaryForUser();
const bookmarks =
res?.data?.data?.recentBookmarks ||
res?.data?.data?.bookmarks ||
res?.data?.data ||
[];
const ids = new Set<number>(
(Array.isArray(bookmarks) ? bookmarks : [])
.map((b: any) => Number(b.articleId ?? b.id ?? b.article?.id))
.filter((x) => !isNaN(x))
);
const gabungan = new Set([...localSet, ...ids]);
setBookmarkedIds(gabungan);
localStorage.setItem(
"bookmarkedIds",
JSON.stringify(Array.from(gabungan))
);
}
} catch (err) {
console.error("Gagal memuat data:", err);
} finally {
setLoading(false);
}
}
// 🔹 Simpan bookmark
const handleSave = async (id: number) => {
const roleId = Number(getCookiesDecrypt("urie"));
if (!roleId || isNaN(roleId)) {
MySwal.fire({
icon: "warning",
title: "Login diperlukan",
text: "Silakan login terlebih dahulu untuk menyimpan artikel.",
confirmButtonText: "Login Sekarang",
confirmButtonColor: "#d33",
});
return;
}
try {
const res = await toggleBookmark(id);
if (res?.error) {
MySwal.fire({
icon: "error",
title: "Gagal",
text: "Tidak dapat menyimpan artikel.",
confirmButtonColor: "#d33",
});
} else {
const updated = new Set(bookmarkedIds);
updated.add(Number(id));
setBookmarkedIds(updated);
localStorage.setItem(
"bookmarkedIds",
JSON.stringify(Array.from(updated))
);
MySwal.fire({
icon: "success",
title: "Berhasil",
text: "Artikel berhasil disimpan ke bookmark.",
timer: 1500,
showConfirmButton: false,
});
}
} catch (err) {
console.error("Error menyimpan bookmark:", err);
MySwal.fire({
icon: "error",
title: "Kesalahan",
text: "Terjadi kesalahan saat menyimpan artikel.",
});
}
};
return (
<section className="bg-white px-4 py-10 border max-w-[1350px] mx-auto rounded-md border-[#CDD5DF] my-10">
<div className="max-w-screen-xl mx-auto">
<h2 className="text-2xl font-semibold text-center mb-6">
Media Update
</h2>
{/* 🔸 Tab Urutan */}
<div className="flex justify-center mb-8 bg-white">
<Card className="bg-[#FFFFFF] rounded-xl flex flex-row p-3 gap-2">
<button
onClick={() => setUrutan("latest")}
className={`px-5 py-2 rounded-lg text-sm font-medium ${
urutan === "latest"
? "bg-[#C6A455] text-white"
: "text-[#C6A455]"
}`}
>
Terbaru
</button>
<button
onClick={() => setUrutan("popular")}
className={`px-5 py-2 rounded-lg text-sm font-medium ${
urutan === "popular"
? "bg-[#C6A455] text-white"
: "text-[#C6A455]"
}`}
>
Terpopuler
</button>
</Card>
</div>
{/* 🔸 Tabs Tipe Konten */}
<Tabs value={tipeKonten} onValueChange={(v: any) => setTipeKonten(v)}>
<TabsList className="flex mb-6 pb-2 bg-transparent">
{["image", "video", "text", "audio"].map((tipe) => (
<TabsTrigger
key={tipe}
value={tipe}
className={`px-5 py-2 rounded-lg text-sm font-medium mx-1 border ${
tipeKonten === tipe
? "bg-[#C6A455] text-white border-[#C6A455]"
: "text-[#C6A455] border-[#C6A455]"
}`}
>
{tipe.charAt(0).toUpperCase() + tipe.slice(1)}
</TabsTrigger>
))}
</TabsList>
</Tabs>
{/* 🔸 Konten */}
{loading ? (
<p className="text-center">Memuat konten...</p>
) : (
<Swiper
modules={[Navigation]}
navigation
spaceBetween={20}
slidesPerView={1}
breakpoints={{
640: { slidesPerView: 2 },
1024: { slidesPerView: 4 },
}}
>
{dataKonten.map((item) => (
<SwiperSlide key={item.id}>
<div className="rounded-xl shadow-md overflow-hidden bg-white">
<div className="w-full h-[204px] relative">
<Image
src={item.smallThumbnailLink || "/placeholder.png"}
alt={item.title || "No Title"}
fill
className="object-cover"
/>
</div>
<div className="p-3">
<div className="flex gap-2 mb-1">
<span className="text-xs text-white px-2 py-0.5 rounded bg-blue-600">
{item.category || "Tanpa Kategori"}
</span>
<span className="text-xs font-medium text-[#b3882e] capitalize">
{tipeKonten}
</span>
</div>
<p className="text-xs text-gray-500 mb-1">
{formatTanggal(item.createdAt)}
</p>
<p className="text-sm font-semibold mb-3 line-clamp-2">
{item.title}
</p>
<div className="flex items-center justify-between">
<div className="flex gap-2 text-gray-600">
<ThumbsUp className="w-4 h-4 cursor-pointer" />
<ThumbsDown className="w-4 h-4 cursor-pointer" />
</div>
<Button
onClick={() => handleSave(item.id)}
disabled={bookmarkedIds.has(Number(item.id))}
variant="default"
size="sm"
className={`rounded px-4 ${
bookmarkedIds.has(Number(item.id))
? "bg-gray-400 cursor-not-allowed text-white"
: "bg-blue-600 text-white hover:bg-blue-700"
}`}
>
{bookmarkedIds.has(Number(item.id))
? "Tersimpan"
: "Simpan"}
</Button>
</div>
</div>
</div>
</SwiperSlide>
))}
</Swiper>
)}
{/* 🔸 Tombol Lihat Lebih Banyak */}
<div className="text-center mt-10">
<Link
href={`/${tipeKonten}/filter?sortBy=${urutan}`}
className="inline-block border border-[#b3882e] text-[#b3882e] px-6 py-2 rounded-md text-sm font-medium hover:bg-[#b3882e]/10 transition"
>
Lihat Lebih Banyak
</Link>
</div>
</div>
</section>
);
}
// "use client";
// import { useState, useEffect } from "react";
// import Image from "next/image";
// import { Button } from "@/components/ui/button";
// import { ThumbsUp, ThumbsDown } from "lucide-react";
// import { Card } from "../ui/card";
// import Link from "next/link";
// import { listData, listArticles } from "@/service/landing/landing";
// import { toggleBookmark, getBookmarkSummaryForUser } from "@/service/content";
// import { getCookiesDecrypt } from "@/lib/utils";
// import { Swiper, SwiperSlide } from "swiper/react";
// import "swiper/css";
// import "swiper/css/navigation";
// import { Navigation } from "swiper/modules";
// import Swal from "sweetalert2";
// import withReactContent from "sweetalert2-react-content";
// // Format tanggal
// function formatTanggal(dateString: string) {
// if (!dateString) return "";
// return (
// new Date(dateString)
// .toLocaleString("id-ID", {
// day: "2-digit",
// month: "short",
// year: "numeric",
// hour: "2-digit",
// minute: "2-digit",
// hour12: false,
// timeZone: "Asia/Jakarta",
// })
// .replace(/\./g, ":") + " WIB"
// );
// }
// export default function MediaUpdate() {
// const [tab, setTab] = useState<"latest" | "popular">("latest");
// const [dataToRender, setDataToRender] = useState<any[]>([]);
// const [bookmarkedIds, setBookmarkedIds] = useState<Set<number>>(new Set());
// const [loading, setLoading] = useState(true);
// const MySwal = withReactContent(Swal);
// useEffect(() => {
// fetchData(tab);
// }, [tab]);
// async function fetchData(section: "latest" | "popular") {
// try {
// setLoading(true);
// const response = await listArticles(
// 1,
// 20,
// 1, // typeId = image
// undefined,
// undefined,
// section === "latest" ? "createdAt" : "viewCount"
// );
// let articlesData: any[] = [];
// if (response?.error) {
// console.error("Articles API failed, fallback ke old API");
// const fallbackRes = await listData(
// "1",
// "",
// "",
// 20,
// 0,
// section === "latest" ? "createdAt" : "clickCount",
// "",
// "",
// ""
// );
// articlesData = fallbackRes?.data?.data?.content || [];
// } else {
// articlesData = response?.data?.data || [];
// }
// // 🔹 Normalisasi struktur data
// const transformedData = articlesData.map((article: any) => ({
// id: article.id,
// title: article.title,
// category:
// article.categoryName ||
// (article.categories && article.categories[0]?.title) ||
// "Tanpa Kategori",
// createdAt: article.createdAt,
// smallThumbnailLink: article.thumbnailUrl,
// label:
// article.typeId === 1
// ? "Image"
// : article.typeId === 2
// ? "Video"
// : article.typeId === 3
// ? "Text"
// : article.typeId === 4
// ? "Audio"
// : "",
// ...article,
// }));
// setDataToRender(transformedData);
// // 🔹 Sinkronisasi bookmark
// const roleId = Number(getCookiesDecrypt("urie"));
// if (roleId && !isNaN(roleId)) {
// const savedLocal = localStorage.getItem("bookmarkedIds");
// let localSet = new Set<number>();
// if (savedLocal) {
// localSet = new Set(JSON.parse(savedLocal));
// setBookmarkedIds(localSet);
// }
// const res = await getBookmarkSummaryForUser();
// const bookmarks =
// res?.data?.data?.recentBookmarks ||
// res?.data?.data?.bookmarks ||
// res?.data?.data ||
// [];
// const ids = new Set<number>(
// (Array.isArray(bookmarks) ? bookmarks : [])
// .map((b: any) => Number(b.articleId ?? b.id ?? b.article?.id))
// .filter((x) => !isNaN(x))
// );
// const merged = new Set([...localSet, ...ids]);
// setBookmarkedIds(merged);
// localStorage.setItem(
// "bookmarkedIds",
// JSON.stringify(Array.from(merged))
// );
// }
// } catch (err) {
// console.error("Gagal memuat data:", err);
// } finally {
// setLoading(false);
// }
// }
// // 🔹 Simpan perubahan bookmark ke localStorage
// useEffect(() => {
// if (bookmarkedIds.size > 0) {
// localStorage.setItem(
// "bookmarkedIds",
// JSON.stringify(Array.from(bookmarkedIds))
// );
// }
// }, [bookmarkedIds]);
// const handleSave = async (id: number) => {
// const roleId = Number(getCookiesDecrypt("urie"));
// if (!roleId || isNaN(roleId)) {
// MySwal.fire({
// icon: "warning",
// title: "Login diperlukan",
// text: "Silakan login terlebih dahulu untuk menyimpan artikel.",
// confirmButtonText: "Login Sekarang",
// confirmButtonColor: "#d33",
// });
// return;
// }
// try {
// const res = await toggleBookmark(id);
// if (res?.error) {
// MySwal.fire({
// icon: "error",
// title: "Gagal",
// text: "Gagal menyimpan artikel.",
// confirmButtonColor: "#d33",
// });
// } else {
// const updated = new Set(bookmarkedIds);
// updated.add(Number(id));
// setBookmarkedIds(updated);
// localStorage.setItem(
// "bookmarkedIds",
// JSON.stringify(Array.from(updated))
// );
// MySwal.fire({
// icon: "success",
// title: "Berhasil",
// text: "Artikel berhasil disimpan ke bookmark.",
// timer: 1500,
// showConfirmButton: false,
// });
// }
// } catch (err) {
// console.error("Error saving bookmark:", err);
// MySwal.fire({
// icon: "error",
// title: "Kesalahan",
// text: "Terjadi kesalahan saat menyimpan artikel.",
// });
// }
// };
// return (
// <section className="bg-white px-4 py-10 border max-w-[1350px] mx-auto rounded-md border-[#CDD5DF] my-10">
// <div className="max-w-screen-xl mx-auto">
// <h2 className="text-2xl font-semibold text-center mb-6">
// Media Update
// </h2>
// {/* Tab */}
// <div className="flex justify-center mb-8 bg-white">
// <Card className="bg-[#FFFFFF] rounded-xl flex flex-row p-3 gap-2">
// <button
// onClick={() => setTab("latest")}
// className={`px-5 py-2 rounded-lg text-sm font-medium ${
// tab === "latest" ? "bg-[#C6A455] text-white" : "text-[#C6A455]"
// }`}
// >
// Konten Terbaru
// </button>
// <button
// onClick={() => setTab("popular")}
// className={`px-5 py-2 rounded-lg text-sm font-medium ${
// tab === "popular" ? "bg-[#C6A455] text-white" : "text-[#C6A455]"
// }`}
// >
// Konten Terpopuler
// </button>
// </Card>
// </div>
// {/* Slider */}
// {loading ? (
// <p className="text-center">Loading...</p>
// ) : (
// <Swiper
// modules={[Navigation]}
// navigation
// spaceBetween={20}
// slidesPerView={1}
// breakpoints={{
// 640: { slidesPerView: 2 },
// 1024: { slidesPerView: 4 },
// }}
// >
// {dataToRender.map((item) => (
// <SwiperSlide key={item.id}>
// <div className="rounded-xl shadow-md overflow-hidden bg-white">
// <div className="w-full h-[204px] relative">
// <Image
// src={item.smallThumbnailLink || "/placeholder.png"}
// alt={item.title || "No Title"}
// fill
// className="object-cover"
// />
// </div>
// <div className="p-3">
// <div className="flex gap-2 mb-1">
// <span className="text-xs text-white px-2 py-0.5 rounded bg-blue-600">
// {item.category || "Tanpa Kategori"}
// </span>
// <span className="text-xs font-medium text-[#b3882e]">
// {item.label || ""}
// </span>
// </div>
// <p className="text-xs text-gray-500 mb-1">
// {formatTanggal(item.createdAt)}
// </p>
// <p className="text-sm font-semibold mb-3 line-clamp-2">
// {item.title}
// </p>
// <div className="flex items-center justify-between">
// <div className="flex gap-2 text-gray-600">
// <ThumbsUp className="w-4 h-4 cursor-pointer" />
// <ThumbsDown className="w-4 h-4 cursor-pointer" />
// </div>
// <Button
// onClick={() => handleSave(item.id)}
// disabled={bookmarkedIds.has(Number(item.id))}
// variant="default"
// size="sm"
// className={`rounded px-4 ${
// bookmarkedIds.has(Number(item.id))
// ? "bg-gray-400 cursor-not-allowed text-white"
// : "bg-blue-600 text-white hover:bg-blue-700"
// }`}
// >
// {bookmarkedIds.has(Number(item.id)) ? "Saved" : "Save"}
// </Button>
// </div>
// </div>
// </div>
// </SwiperSlide>
// ))}
// </Swiper>
// )}
// {/* Lihat lebih banyak */}
// <div className="text-center mt-10">
// <Link
// href={
// tab === "latest"
// ? "https://mediahub.polri.go.id/"
// : "https://tribratanews.polri.go.id/"
// }
// >
// <Button
// size={"lg"}
// className="text-[#b3882e] bg-transparent border border-[#b3882e] px-6 py-2 rounded-s-sm text-sm font-medium hover:bg-[#b3882e]/10 transition"
// >
// Lihat Lebih Banyak
// </Button>
// </Link>
// </div>
// </div>
// </section>
// );
// }