2025-09-16 08:29:07 +00:00
|
|
|
"use client";
|
|
|
|
|
|
2025-10-15 17:03:41 +00:00
|
|
|
import { useState, useEffect } from "react";
|
2025-10-12 18:28:33 +00:00
|
|
|
import Image from "next/image";
|
|
|
|
|
import Link from "next/link";
|
2025-10-15 17:03:41 +00:00
|
|
|
import { Button } from "@/components/ui/button";
|
2025-10-31 16:21:05 +00:00
|
|
|
import { Card } from "@/components/ui/card";
|
|
|
|
|
import { Archive, Star, Trash2, Undo2, HeartOff } from "lucide-react";
|
2025-10-12 18:28:33 +00:00
|
|
|
import Swal from "sweetalert2";
|
|
|
|
|
import withReactContent from "sweetalert2-react-content";
|
2025-10-31 16:21:05 +00:00
|
|
|
import { getBookmarks, BookmarkItem } from "@/service/content";
|
|
|
|
|
import {
|
|
|
|
|
Pagination,
|
|
|
|
|
PaginationContent,
|
|
|
|
|
PaginationItem,
|
|
|
|
|
PaginationLink,
|
|
|
|
|
PaginationNext,
|
|
|
|
|
PaginationPrevious,
|
|
|
|
|
} from "@/components/ui/pagination";
|
|
|
|
|
|
2025-10-12 18:28:33 +00:00
|
|
|
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"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getLink(item: BookmarkItem) {
|
|
|
|
|
switch (item.article?.typeId) {
|
|
|
|
|
case 1:
|
|
|
|
|
return `/content/image/detail/${item.article?.id}`;
|
|
|
|
|
case 2:
|
|
|
|
|
return `/content/video/detail/${item.article?.id}`;
|
|
|
|
|
case 3:
|
|
|
|
|
return `/content/text/detail/${item.article?.id}`;
|
|
|
|
|
case 4:
|
|
|
|
|
return `/content/audio/detail/${item.article?.id}`;
|
|
|
|
|
default:
|
|
|
|
|
return "#";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-15 17:03:41 +00:00
|
|
|
type ForYouCardGridProps = {
|
|
|
|
|
filterType: "My Collections" | "Archives" | "Favorites";
|
2025-10-31 16:21:05 +00:00
|
|
|
selectedCategory?: string; // ✅ tambahkan ini
|
2025-09-16 08:29:07 +00:00
|
|
|
};
|
|
|
|
|
|
2025-10-15 17:03:41 +00:00
|
|
|
export default function ForYouCardGrid({ filterType }: ForYouCardGridProps) {
|
2025-10-12 18:28:33 +00:00
|
|
|
const [bookmarks, setBookmarks] = useState<BookmarkItem[]>([]);
|
|
|
|
|
const [loading, setLoading] = useState(true);
|
2025-10-19 03:53:16 +00:00
|
|
|
const [contentType, setContentType] = useState<
|
|
|
|
|
"image" | "video" | "text" | "audio"
|
|
|
|
|
>("image");
|
2025-10-31 16:21:05 +00:00
|
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
|
|
|
const [totalPages, setTotalPages] = useState(1);
|
|
|
|
|
const [totalData, setTotalData] = useState(0);
|
|
|
|
|
const itemsPerPage = 6;
|
2025-10-12 18:28:33 +00:00
|
|
|
const MySwal = withReactContent(Swal);
|
2025-09-16 08:29:07 +00:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
2025-10-12 18:28:33 +00:00
|
|
|
fetchBookmarks();
|
2025-10-31 16:21:05 +00:00
|
|
|
}, [filterType, currentPage]);
|
2025-09-16 08:29:07 +00:00
|
|
|
|
2025-10-12 18:28:33 +00:00
|
|
|
const fetchBookmarks = async () => {
|
2025-10-10 16:30:17 +00:00
|
|
|
try {
|
2025-10-12 18:28:33 +00:00
|
|
|
setLoading(true);
|
2025-10-31 16:21:05 +00:00
|
|
|
const response = await getBookmarks(
|
|
|
|
|
currentPage,
|
|
|
|
|
itemsPerPage,
|
|
|
|
|
filterType,
|
|
|
|
|
);
|
2025-10-12 18:28:33 +00:00
|
|
|
if (!response?.error) {
|
2025-10-31 16:21:05 +00:00
|
|
|
const data = response.data?.data || [];
|
|
|
|
|
const meta = response.data?.meta;
|
|
|
|
|
const totalCount = meta?.count ?? data.length ?? 0;
|
|
|
|
|
const totalPageCount = Math.max(
|
|
|
|
|
1,
|
|
|
|
|
Math.ceil(totalCount / itemsPerPage)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
setBookmarks(data);
|
|
|
|
|
setTotalPages(totalPageCount);
|
|
|
|
|
setTotalData(totalCount);
|
|
|
|
|
|
|
|
|
|
if (currentPage > totalPageCount) setCurrentPage(1);
|
2025-10-12 18:28:33 +00:00
|
|
|
} else {
|
2025-10-15 17:03:41 +00:00
|
|
|
MySwal.fire("Error", "Gagal memuat bookmark.", "error");
|
2025-10-12 18:28:33 +00:00
|
|
|
}
|
|
|
|
|
} catch (err) {
|
2025-10-15 17:03:41 +00:00
|
|
|
console.error(err);
|
|
|
|
|
MySwal.fire("Error", "Terjadi kesalahan saat memuat bookmark.", "error");
|
2025-10-12 18:28:33 +00:00
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
2025-10-10 16:30:17 +00:00
|
|
|
}
|
2025-10-12 18:28:33 +00:00
|
|
|
};
|
|
|
|
|
|
2025-10-19 03:53:16 +00:00
|
|
|
const handleAction = (action: string, title: string) => {
|
|
|
|
|
MySwal.fire({
|
|
|
|
|
icon: "info",
|
|
|
|
|
title: action,
|
|
|
|
|
text: `${title} berhasil di${action.toLowerCase()}.`,
|
|
|
|
|
timer: 1200,
|
|
|
|
|
showConfirmButton: false,
|
|
|
|
|
});
|
2025-10-12 18:28:33 +00:00
|
|
|
};
|
2025-09-16 08:29:07 +00:00
|
|
|
|
2025-10-19 03:53:16 +00:00
|
|
|
const renderButtons = (bookmark: BookmarkItem) => {
|
|
|
|
|
const title = bookmark.article?.title || "Konten";
|
|
|
|
|
|
|
|
|
|
if (filterType === "Archives") {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex gap-2 mt-3 justify-center">
|
2025-10-15 17:03:41 +00:00
|
|
|
<Button
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="outline"
|
2025-10-19 03:53:16 +00:00
|
|
|
onClick={() => handleAction("Unarchive", title)}
|
2025-10-31 16:21:05 +00:00
|
|
|
className="text-blue-600 border-blue-200 hover:bg-blue-50"
|
2025-10-15 17:03:41 +00:00
|
|
|
>
|
2025-10-19 03:53:16 +00:00
|
|
|
<Undo2 className="w-[10px] h-[10px]" />
|
2025-10-31 16:21:05 +00:00
|
|
|
Unarchive
|
2025-10-15 17:03:41 +00:00
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="outline"
|
2025-10-19 03:53:16 +00:00
|
|
|
onClick={() => handleAction("Delete", title)}
|
2025-10-31 16:21:05 +00:00
|
|
|
className="text-red-600 border-red-200 hover:bg-red-50"
|
2025-10-15 17:03:41 +00:00
|
|
|
>
|
2025-10-19 03:53:16 +00:00
|
|
|
<Trash2 className="w-[10px] h-[10px]" />
|
2025-10-31 16:21:05 +00:00
|
|
|
Delete
|
2025-10-15 17:03:41 +00:00
|
|
|
</Button>
|
|
|
|
|
</div>
|
2025-10-19 03:53:16 +00:00
|
|
|
);
|
|
|
|
|
}
|
2025-10-12 18:28:33 +00:00
|
|
|
|
2025-10-19 03:53:16 +00:00
|
|
|
if (filterType === "Favorites") {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex gap-2 mt-3 justify-center">
|
2025-10-15 17:03:41 +00:00
|
|
|
<Button
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="outline"
|
2025-10-19 03:53:16 +00:00
|
|
|
onClick={() => handleAction("Archive", title)}
|
2025-10-31 16:21:05 +00:00
|
|
|
className="text-gray-700 border-gray-300 hover:bg-gray-100"
|
2025-10-15 17:03:41 +00:00
|
|
|
>
|
2025-10-19 03:53:16 +00:00
|
|
|
<Archive className="w-[10px] h-[10px]" />
|
2025-10-31 16:21:05 +00:00
|
|
|
Archive
|
2025-10-15 17:03:41 +00:00
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="outline"
|
2025-10-19 03:53:16 +00:00
|
|
|
onClick={() => handleAction("Unfavorite", title)}
|
2025-10-31 16:21:05 +00:00
|
|
|
className="text-yellow-600 border-yellow-200 hover:bg-yellow-50"
|
2025-10-15 17:03:41 +00:00
|
|
|
>
|
2025-10-19 03:53:16 +00:00
|
|
|
<HeartOff className="w-[10px] h-[10px]" />
|
2025-10-31 16:21:05 +00:00
|
|
|
Unfavorite
|
2025-10-15 17:03:41 +00:00
|
|
|
</Button>
|
|
|
|
|
</div>
|
2025-10-19 03:53:16 +00:00
|
|
|
);
|
|
|
|
|
}
|
2025-10-12 18:28:33 +00:00
|
|
|
|
2025-10-19 03:53:16 +00:00
|
|
|
return (
|
|
|
|
|
<div className="flex gap-2 mt-3 justify-center">
|
2025-10-15 17:03:41 +00:00
|
|
|
<Button
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="outline"
|
2025-10-19 03:53:16 +00:00
|
|
|
onClick={() => handleAction("Archive", title)}
|
2025-10-31 16:21:05 +00:00
|
|
|
className="text-gray-700 border-gray-300 hover:bg-gray-100"
|
2025-10-15 17:03:41 +00:00
|
|
|
>
|
2025-10-19 03:53:16 +00:00
|
|
|
<Archive className="w-[10px] h-[10px]" />
|
2025-10-31 16:21:05 +00:00
|
|
|
Archive
|
2025-10-15 17:03:41 +00:00
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
size="sm"
|
|
|
|
|
variant="outline"
|
2025-10-19 03:53:16 +00:00
|
|
|
onClick={() => handleAction("Favorite", title)}
|
2025-10-31 16:21:05 +00:00
|
|
|
className="text-yellow-600 border-yellow-200 hover:bg-yellow-50"
|
2025-10-15 17:03:41 +00:00
|
|
|
>
|
2025-10-19 03:53:16 +00:00
|
|
|
<Star className="w-[10px] h-[10px]" />
|
2025-10-31 16:21:05 +00:00
|
|
|
Favorite
|
2025-10-15 17:03:41 +00:00
|
|
|
</Button>
|
|
|
|
|
</div>
|
2025-10-19 03:53:16 +00:00
|
|
|
);
|
|
|
|
|
};
|
2025-10-15 17:03:41 +00:00
|
|
|
|
2025-10-19 03:53:16 +00:00
|
|
|
const renderCard = (bookmark: BookmarkItem) => (
|
|
|
|
|
<div className="rounded-xl shadow-md bg-white hover:shadow-lg transition-shadow overflow-hidden">
|
|
|
|
|
{/* Gambar / ikon */}
|
|
|
|
|
{bookmark.article?.typeId === 3 ? (
|
|
|
|
|
// 📝 TEXT
|
|
|
|
|
<div className="bg-[#e0c350] flex items-center justify-center h-[200px] text-white">
|
|
|
|
|
<svg
|
|
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
width="80"
|
|
|
|
|
height="80"
|
|
|
|
|
viewBox="0 0 16 16"
|
|
|
|
|
>
|
|
|
|
|
<path
|
|
|
|
|
fill="currentColor"
|
|
|
|
|
d="M5 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V5.414a1.5 1.5 0 0 0-.44-1.06L9.647 1.439A1.5 1.5 0 0 0 8.586 1zM4 3a1 1 0 0 1 1-1h3v2.5A1.5 1.5 0 0 0 9.5 6H12v7a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1zm7.793 2H9.5a.5.5 0 0 1-.5-.5V2.207z"
|
|
|
|
|
/>
|
|
|
|
|
</svg>
|
|
|
|
|
</div>
|
|
|
|
|
) : bookmark.article?.typeId === 4 ? (
|
|
|
|
|
// 🎵 AUDIO
|
|
|
|
|
<div className="flex items-center justify-center bg-[#bb3523] w-full h-[200px] text-white">
|
|
|
|
|
<svg
|
|
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
width="100"
|
|
|
|
|
height="100"
|
|
|
|
|
viewBox="0 0 20 20"
|
|
|
|
|
>
|
|
|
|
|
<path
|
|
|
|
|
fill="currentColor"
|
|
|
|
|
d="M14.702 2.226A1 1 0 0 1 16 3.18v6.027a5.5 5.5 0 0 0-1-.184V6.18L8 8.368V15.5a2.5 2.5 0 1 1-1-2V5.368a1 1 0 0 1 .702-.955zM8 7.32l7-2.187V3.18L8 5.368zM5.5 14a1.5 1.5 0 1 0 0 3a1.5 1.5 0 0 0 0-3m13.5.5a4.5 4.5 0 1 1-9 0a4.5 4.5 0 0 1 9 0m-2.265-.436l-2.994-1.65a.5.5 0 0 0-.741.438v3.3a.5.5 0 0 0 .741.438l2.994-1.65a.5.5 0 0 0 0-.876"
|
|
|
|
|
/>
|
|
|
|
|
</svg>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
// 📸 / 🎬
|
|
|
|
|
<div className="relative w-full h-[200px]">
|
|
|
|
|
<Link href={getLink(bookmark)}>
|
|
|
|
|
<Image
|
|
|
|
|
src={bookmark.article?.thumbnailUrl || "/placeholder.png"}
|
|
|
|
|
alt={bookmark.article?.title || "No Title"}
|
|
|
|
|
fill
|
|
|
|
|
className="object-cover cursor-pointer hover:opacity-90 transition"
|
|
|
|
|
/>
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2025-10-12 18:28:33 +00:00
|
|
|
|
2025-10-19 03:53:16 +00:00
|
|
|
{/* Caption */}
|
|
|
|
|
<div className="p-3">
|
|
|
|
|
<p className="text-xs text-gray-500 mb-1">
|
|
|
|
|
Disimpan: {formatTanggal(bookmark.createdAt)}
|
|
|
|
|
</p>
|
|
|
|
|
<Link href={getLink(bookmark)}>
|
|
|
|
|
<p className="text-sm font-semibold line-clamp-2 hover:text-blue-600 transition-colors">
|
|
|
|
|
{bookmark.article?.title}
|
|
|
|
|
</p>
|
|
|
|
|
</Link>
|
|
|
|
|
{renderButtons(bookmark)}
|
2025-09-16 08:29:07 +00:00
|
|
|
</div>
|
2025-10-19 03:53:16 +00:00
|
|
|
</div>
|
|
|
|
|
);
|
2025-09-16 08:29:07 +00:00
|
|
|
|
2025-10-31 16:21:05 +00:00
|
|
|
// Filter sesuai tab
|
|
|
|
|
const filtered = bookmarks.filter((b) => {
|
|
|
|
|
const t = b.article?.typeId;
|
|
|
|
|
switch (contentType) {
|
|
|
|
|
case "image":
|
|
|
|
|
return t === 1;
|
|
|
|
|
case "video":
|
|
|
|
|
return t === 2;
|
|
|
|
|
case "text":
|
|
|
|
|
return t === 3;
|
|
|
|
|
case "audio":
|
|
|
|
|
return t === 4;
|
|
|
|
|
default:
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-10-15 17:03:41 +00:00
|
|
|
|
|
|
|
|
return (
|
2025-10-19 03:53:16 +00:00
|
|
|
<section className="bg-white px-4 py-6 border rounded-md border-[#CDD5DF]">
|
2025-10-31 16:21:05 +00:00
|
|
|
{/* Tabs */}
|
2025-10-19 03:53:16 +00:00
|
|
|
<div className="flex justify-center mb-8">
|
|
|
|
|
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-2xl p-4 border-2 border-blue-100 shadow-lg">
|
|
|
|
|
<div className="flex flex-wrap justify-center gap-2">
|
|
|
|
|
{["image", "video", "audio", "text"].map((type) => (
|
|
|
|
|
<button
|
|
|
|
|
key={type}
|
2025-10-31 16:21:05 +00:00
|
|
|
onClick={() => {
|
|
|
|
|
setContentType(type as any);
|
|
|
|
|
setCurrentPage(1);
|
|
|
|
|
}}
|
2025-10-19 03:53:16 +00:00
|
|
|
className={`px-4 py-2 rounded-full text-xs font-semibold transition-all duration-300 transform hover:scale-105 ${
|
|
|
|
|
contentType === type
|
|
|
|
|
? "bg-gradient-to-r from-orange-500 to-red-600 text-white shadow-lg ring-2 ring-orange-300"
|
|
|
|
|
: "bg-white text-orange-600 border-2 border-orange-200 hover:border-orange-400 hover:shadow-md"
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
{type === "image"
|
|
|
|
|
? "📸 Foto"
|
|
|
|
|
: type === "video"
|
|
|
|
|
? "🎬 Audio Visual"
|
|
|
|
|
: type === "audio"
|
|
|
|
|
? "🎵 Audio"
|
|
|
|
|
: "📝 Text"}
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-10-31 16:21:05 +00:00
|
|
|
{/* Grid + Pagination */}
|
|
|
|
|
{loading ? (
|
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
|
|
|
{[...Array(6)].map((_, i) => (
|
|
|
|
|
<Card key={i} className="p-4 animate-pulse">
|
|
|
|
|
<div className="w-full h-48 bg-gray-200 rounded-lg mb-4"></div>
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<div className="h-4 bg-gray-200 rounded w-3/4"></div>
|
|
|
|
|
<div className="h-4 bg-gray-200 rounded w-1/2"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</Card>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
) : filtered.length > 0 ? (
|
|
|
|
|
<>
|
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 mb-6">
|
|
|
|
|
{filtered.map((b) => renderCard(b))}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{totalPages > 1 && (
|
|
|
|
|
<div className="flex flex-col items-center space-y-2">
|
|
|
|
|
<Pagination>
|
|
|
|
|
<PaginationContent>
|
|
|
|
|
<PaginationItem>
|
|
|
|
|
<PaginationPrevious
|
|
|
|
|
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
|
|
|
|
className={
|
|
|
|
|
currentPage === 1
|
|
|
|
|
? "pointer-events-none opacity-50"
|
|
|
|
|
: "cursor-pointer"
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</PaginationItem>
|
|
|
|
|
|
|
|
|
|
{Array.from({ length: totalPages }, (_, i) => i + 1).map(
|
|
|
|
|
(n) => (
|
|
|
|
|
<PaginationItem key={n}>
|
|
|
|
|
<PaginationLink
|
|
|
|
|
onClick={() => setCurrentPage(n)}
|
|
|
|
|
isActive={currentPage === n}
|
|
|
|
|
>
|
|
|
|
|
{n}
|
|
|
|
|
</PaginationLink>
|
|
|
|
|
</PaginationItem>
|
|
|
|
|
)
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<PaginationItem>
|
|
|
|
|
<PaginationNext
|
|
|
|
|
onClick={() =>
|
|
|
|
|
setCurrentPage((p) => Math.min(totalPages, p + 1))
|
|
|
|
|
}
|
|
|
|
|
className={
|
|
|
|
|
currentPage === totalPages
|
|
|
|
|
? "pointer-events-none opacity-50"
|
|
|
|
|
: "cursor-pointer"
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</PaginationItem>
|
|
|
|
|
</PaginationContent>
|
|
|
|
|
</Pagination>
|
|
|
|
|
|
|
|
|
|
<p className="text-xs text-gray-500">
|
|
|
|
|
Menampilkan halaman {currentPage} dari {totalPages} • Total{" "}
|
|
|
|
|
{totalData} konten
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<Card className="p-8 text-center">
|
|
|
|
|
<p className="text-gray-600 text-sm">Tidak ada bookmark ditemukan.</p>
|
|
|
|
|
</Card>
|
|
|
|
|
)}
|
2025-10-19 03:53:16 +00:00
|
|
|
</section>
|
2025-09-16 08:29:07 +00:00
|
|
|
);
|
|
|
|
|
}
|
2025-10-10 16:30:17 +00:00
|
|
|
|
|
|
|
|
// "use client";
|
|
|
|
|
|
2025-10-31 16:21:05 +00:00
|
|
|
// import { useState, useEffect } from "react";
|
|
|
|
|
// import Image from "next/image";
|
|
|
|
|
// import Link from "next/link";
|
|
|
|
|
// import { Button } from "@/components/ui/button";
|
|
|
|
|
// import { Archive, Star, Trash2, Box, Undo2, HeartOff } from "lucide-react";
|
|
|
|
|
// import Swal from "sweetalert2";
|
|
|
|
|
// import withReactContent from "sweetalert2-react-content";
|
|
|
|
|
// import { getBookmarks } from "@/service/content";
|
|
|
|
|
// import { BookmarkItem } from "@/service/content";
|
|
|
|
|
// import { Swiper, SwiperSlide } from "swiper/react";
|
|
|
|
|
// import "swiper/css";
|
|
|
|
|
// import "swiper/css/navigation";
|
|
|
|
|
// import { Navigation } from "swiper/modules";
|
|
|
|
|
|
|
|
|
|
// 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"
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// function getLink(item: BookmarkItem) {
|
|
|
|
|
// switch (item.article?.typeId) {
|
|
|
|
|
// case 1:
|
|
|
|
|
// return `/content/image/detail/${item.article?.id}`;
|
|
|
|
|
// case 2:
|
|
|
|
|
// return `/content/video/detail/${item.article?.id}`;
|
|
|
|
|
// case 3:
|
|
|
|
|
// return `/content/text/detail/${item.article?.id}`;
|
|
|
|
|
// case 4:
|
|
|
|
|
// return `/content/audio/detail/${item.article?.id}`;
|
|
|
|
|
// default:
|
|
|
|
|
// return "#";
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// type ForYouCardGridProps = {
|
|
|
|
|
// filterType: "My Collections" | "Archives" | "Favorites";
|
|
|
|
|
// selectedCategory?: string;
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// export default function ForYouCardGrid({ filterType }: ForYouCardGridProps) {
|
|
|
|
|
// const [bookmarks, setBookmarks] = useState<BookmarkItem[]>([]);
|
|
|
|
|
// const [loading, setLoading] = useState(true);
|
|
|
|
|
// const [contentType, setContentType] = useState<
|
|
|
|
|
// "image" | "video" | "text" | "audio"
|
|
|
|
|
// >("image");
|
|
|
|
|
// const MySwal = withReactContent(Swal);
|
|
|
|
|
|
|
|
|
|
// useEffect(() => {
|
|
|
|
|
// fetchBookmarks();
|
|
|
|
|
// }, [filterType]);
|
|
|
|
|
|
|
|
|
|
// const fetchBookmarks = async () => {
|
|
|
|
|
// try {
|
|
|
|
|
// setLoading(true);
|
|
|
|
|
// const response = await getBookmarks(1, 50, filterType);
|
|
|
|
|
// if (!response?.error) {
|
|
|
|
|
// setBookmarks(response.data?.data || []);
|
|
|
|
|
// } else {
|
|
|
|
|
// MySwal.fire("Error", "Gagal memuat bookmark.", "error");
|
|
|
|
|
// }
|
|
|
|
|
// } catch (err) {
|
|
|
|
|
// console.error(err);
|
|
|
|
|
// MySwal.fire("Error", "Terjadi kesalahan saat memuat bookmark.", "error");
|
|
|
|
|
// } finally {
|
|
|
|
|
// setLoading(false);
|
|
|
|
|
// }
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// const filtered = bookmarks.filter((b) => {
|
|
|
|
|
// const t = b.article?.typeId;
|
|
|
|
|
// switch (contentType) {
|
|
|
|
|
// case "image":
|
|
|
|
|
// return t === 1;
|
|
|
|
|
// case "video":
|
|
|
|
|
// return t === 2;
|
|
|
|
|
// case "text":
|
|
|
|
|
// return t === 3;
|
|
|
|
|
// case "audio":
|
|
|
|
|
// return t === 4;
|
|
|
|
|
// default:
|
|
|
|
|
// return true;
|
|
|
|
|
// }
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// const handleAction = (action: string, title: string) => {
|
|
|
|
|
// MySwal.fire({
|
|
|
|
|
// icon: "info",
|
|
|
|
|
// title: action,
|
|
|
|
|
// text: `${title} berhasil di${action.toLowerCase()}.`,
|
|
|
|
|
// timer: 1200,
|
|
|
|
|
// showConfirmButton: false,
|
|
|
|
|
// });
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// const renderButtons = (bookmark: BookmarkItem) => {
|
|
|
|
|
// const title = bookmark.article?.title || "Konten";
|
|
|
|
|
|
|
|
|
|
// if (filterType === "Archives") {
|
|
|
|
|
// return (
|
|
|
|
|
// <div className="flex gap-2 mt-3 justify-center">
|
|
|
|
|
// <Button
|
|
|
|
|
// size="sm"
|
|
|
|
|
// variant="outline"
|
|
|
|
|
// onClick={() => handleAction("Unarchive", title)}
|
|
|
|
|
// className="flex items-center text-xs gap-1 text-blue-600 border-blue-200 hover:bg-blue-50 cursor-pointer"
|
|
|
|
|
// >
|
|
|
|
|
// <Undo2 className="w-[10px] h-[10px]" />
|
|
|
|
|
// <p className="text-[10px]">Unarchive</p>
|
|
|
|
|
// </Button>
|
|
|
|
|
// <Button
|
|
|
|
|
// size="sm"
|
|
|
|
|
// variant="outline"
|
|
|
|
|
// onClick={() => handleAction("Delete", title)}
|
|
|
|
|
// className="flex items-center text-xs gap-1 text-red-600 border-red-200 hover:bg-red-50 cursor-pointer"
|
|
|
|
|
// >
|
|
|
|
|
// <Trash2 className="w-[10px] h-[10px]" />
|
|
|
|
|
// <p className="text-[10px]">Delete</p>
|
|
|
|
|
// </Button>
|
|
|
|
|
// </div>
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (filterType === "Favorites") {
|
|
|
|
|
// return (
|
|
|
|
|
// <div className="flex gap-2 mt-3 justify-center">
|
|
|
|
|
// <Button
|
|
|
|
|
// size="sm"
|
|
|
|
|
// variant="outline"
|
|
|
|
|
// onClick={() => handleAction("Archive", title)}
|
|
|
|
|
// className="flex items-center text-xs gap-1 text-gray-700 border-gray-300 hover:bg-gray-100 cursor-pointer"
|
|
|
|
|
// >
|
|
|
|
|
// <Archive className="w-[10px] h-[10px]" />
|
|
|
|
|
// <p className="text-[10px]">Archive</p>
|
|
|
|
|
// </Button>
|
|
|
|
|
// <Button
|
|
|
|
|
// size="sm"
|
|
|
|
|
// variant="outline"
|
|
|
|
|
// onClick={() => handleAction("Unfavorite", title)}
|
|
|
|
|
// className="flex items-center gap-1 text-yellow-600 border-yellow-200 hover:bg-yellow-50 cursor-pointer"
|
|
|
|
|
// >
|
|
|
|
|
// <HeartOff className="w-[10px] h-[10px]" />
|
|
|
|
|
// <p className="text-[10px]">Unfavorite</p>
|
|
|
|
|
// </Button>
|
|
|
|
|
// </div>
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// return (
|
|
|
|
|
// <div className="flex gap-2 mt-3 justify-center">
|
|
|
|
|
// <Button
|
|
|
|
|
// size="sm"
|
|
|
|
|
// variant="outline"
|
|
|
|
|
// onClick={() => handleAction("Archive", title)}
|
|
|
|
|
// className="flex items-center text-xs gap-1 text-gray-700 border-gray-300 hover:bg-gray-100 cursor-pointer"
|
|
|
|
|
// >
|
|
|
|
|
// <Archive className="w-[10px] h-[10px]" />
|
|
|
|
|
// <p className="text-[10px]">Archive</p>
|
|
|
|
|
// </Button>
|
|
|
|
|
// <Button
|
|
|
|
|
// size="sm"
|
|
|
|
|
// variant="outline"
|
|
|
|
|
// onClick={() => handleAction("Favorite", title)}
|
|
|
|
|
// className="flex items-center gap-1 text-yellow-600 border-yellow-200 hover:bg-yellow-50 cursor-pointer"
|
|
|
|
|
// >
|
|
|
|
|
// <Star className="w-[10px] h-[10px]" />
|
|
|
|
|
// <p className="text-[10px]">Favorite</p>
|
|
|
|
|
// </Button>
|
|
|
|
|
// </div>
|
|
|
|
|
// );
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// const renderCard = (bookmark: BookmarkItem) => (
|
|
|
|
|
// <div className="rounded-xl shadow-md bg-white hover:shadow-lg transition-shadow overflow-hidden">
|
|
|
|
|
// {/* Gambar / ikon */}
|
|
|
|
|
// {bookmark.article?.typeId === 3 ? (
|
|
|
|
|
// // 📝 TEXT
|
|
|
|
|
// <div className="bg-[#e0c350] flex items-center justify-center h-[200px] text-white">
|
|
|
|
|
// <svg
|
|
|
|
|
// xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
// width="80"
|
|
|
|
|
// height="80"
|
|
|
|
|
// viewBox="0 0 16 16"
|
|
|
|
|
// >
|
|
|
|
|
// <path
|
|
|
|
|
// fill="currentColor"
|
|
|
|
|
// d="M5 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V5.414a1.5 1.5 0 0 0-.44-1.06L9.647 1.439A1.5 1.5 0 0 0 8.586 1zM4 3a1 1 0 0 1 1-1h3v2.5A1.5 1.5 0 0 0 9.5 6H12v7a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1zm7.793 2H9.5a.5.5 0 0 1-.5-.5V2.207z"
|
|
|
|
|
// />
|
|
|
|
|
// </svg>
|
|
|
|
|
// </div>
|
|
|
|
|
// ) : bookmark.article?.typeId === 4 ? (
|
|
|
|
|
// // 🎵 AUDIO
|
|
|
|
|
// <div className="flex items-center justify-center bg-[#bb3523] w-full h-[200px] text-white">
|
|
|
|
|
// <svg
|
|
|
|
|
// xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
// width="100"
|
|
|
|
|
// height="100"
|
|
|
|
|
// viewBox="0 0 20 20"
|
|
|
|
|
// >
|
|
|
|
|
// <path
|
|
|
|
|
// fill="currentColor"
|
|
|
|
|
// d="M14.702 2.226A1 1 0 0 1 16 3.18v6.027a5.5 5.5 0 0 0-1-.184V6.18L8 8.368V15.5a2.5 2.5 0 1 1-1-2V5.368a1 1 0 0 1 .702-.955zM8 7.32l7-2.187V3.18L8 5.368zM5.5 14a1.5 1.5 0 1 0 0 3a1.5 1.5 0 0 0 0-3m13.5.5a4.5 4.5 0 1 1-9 0a4.5 4.5 0 0 1 9 0m-2.265-.436l-2.994-1.65a.5.5 0 0 0-.741.438v3.3a.5.5 0 0 0 .741.438l2.994-1.65a.5.5 0 0 0 0-.876"
|
|
|
|
|
// />
|
|
|
|
|
// </svg>
|
|
|
|
|
// </div>
|
|
|
|
|
// ) : (
|
|
|
|
|
// // 📸 / 🎬
|
|
|
|
|
// <div className="relative w-full h-[200px]">
|
|
|
|
|
// <Link href={getLink(bookmark)}>
|
|
|
|
|
// <Image
|
|
|
|
|
// src={bookmark.article?.thumbnailUrl || "/placeholder.png"}
|
|
|
|
|
// alt={bookmark.article?.title || "No Title"}
|
|
|
|
|
// fill
|
|
|
|
|
// className="object-cover cursor-pointer hover:opacity-90 transition"
|
|
|
|
|
// />
|
|
|
|
|
// </Link>
|
|
|
|
|
// </div>
|
|
|
|
|
// )}
|
|
|
|
|
|
|
|
|
|
// {/* Caption */}
|
|
|
|
|
// <div className="p-3">
|
|
|
|
|
// <p className="text-xs text-gray-500 mb-1">
|
|
|
|
|
// Disimpan: {formatTanggal(bookmark.createdAt)}
|
|
|
|
|
// </p>
|
|
|
|
|
// <Link href={getLink(bookmark)}>
|
|
|
|
|
// <p className="text-sm font-semibold line-clamp-2 hover:text-blue-600 transition-colors">
|
|
|
|
|
// {bookmark.article?.title}
|
|
|
|
|
// </p>
|
|
|
|
|
// </Link>
|
|
|
|
|
// {renderButtons(bookmark)}
|
|
|
|
|
// </div>
|
|
|
|
|
// </div>
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
// if (loading)
|
|
|
|
|
// return (
|
|
|
|
|
// <div className="text-center py-12 text-gray-500">Memuat konten...</div>
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
// // if (filtered.length === 0)
|
|
|
|
|
// // return (
|
|
|
|
|
// // <div className="text-center py-12">
|
|
|
|
|
// // <div className="text-gray-400 text-6xl mb-4">📂</div>
|
|
|
|
|
// // <h3 className="text-xl font-semibold text-gray-600 mb-2">
|
|
|
|
|
// // Tidak Ada Konten di {filterType}
|
|
|
|
|
// // </h3>
|
|
|
|
|
// // </div>
|
|
|
|
|
// // );
|
|
|
|
|
|
|
|
|
|
// return (
|
|
|
|
|
// <section className="bg-white px-4 py-6 border rounded-md border-[#CDD5DF]">
|
|
|
|
|
// {/* Tab Filter Konten */}
|
|
|
|
|
// <div className="flex justify-center mb-8">
|
|
|
|
|
// <div className="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-2xl p-4 border-2 border-blue-100 shadow-lg">
|
|
|
|
|
// <div className="flex flex-wrap justify-center gap-2">
|
|
|
|
|
// {["image", "video", "audio", "text"].map((type) => (
|
|
|
|
|
// <button
|
|
|
|
|
// key={type}
|
|
|
|
|
// onClick={() => setContentType(type as any)}
|
|
|
|
|
// className={`px-4 py-2 rounded-full text-xs font-semibold transition-all duration-300 transform hover:scale-105 ${
|
|
|
|
|
// contentType === type
|
|
|
|
|
// ? "bg-gradient-to-r from-orange-500 to-red-600 text-white shadow-lg ring-2 ring-orange-300"
|
|
|
|
|
// : "bg-white text-orange-600 border-2 border-orange-200 hover:border-orange-400 hover:shadow-md"
|
|
|
|
|
// }`}
|
|
|
|
|
// >
|
|
|
|
|
// {type === "image"
|
|
|
|
|
// ? "📸 Foto"
|
|
|
|
|
// : type === "video"
|
|
|
|
|
// ? "🎬 Audio Visual"
|
|
|
|
|
// : type === "audio"
|
|
|
|
|
// ? "🎵 Audio"
|
|
|
|
|
// : "📝 Text"}
|
|
|
|
|
// </button>
|
|
|
|
|
// ))}
|
|
|
|
|
// </div>
|
|
|
|
|
// </div>
|
|
|
|
|
// </div>
|
|
|
|
|
|
|
|
|
|
// {/* 🔹 Jika tidak ada data */}
|
|
|
|
|
// {filtered.length === 0 ? (
|
|
|
|
|
// <div className="text-center py-12 text-gray-500">
|
|
|
|
|
// Tidak ada konten di {filterType}.
|
|
|
|
|
// </div>
|
|
|
|
|
// ) : (
|
|
|
|
|
// /* 🔹 Swiper hanya muncul kalau ada data */
|
|
|
|
|
// <div className="w-full overflow-hidden">
|
|
|
|
|
// <Swiper
|
|
|
|
|
// modules={[Navigation]}
|
|
|
|
|
// navigation
|
|
|
|
|
// spaceBetween={16}
|
|
|
|
|
// slidesPerView="auto"
|
|
|
|
|
// centeredSlides={false}
|
|
|
|
|
// className="!overflow-hidden px-2"
|
|
|
|
|
// breakpoints={{
|
|
|
|
|
// 320: { slidesPerView: 1.2, spaceBetween: 12 },
|
|
|
|
|
// 640: { slidesPerView: 2, spaceBetween: 16 },
|
|
|
|
|
// 1024: { slidesPerView: 3, spaceBetween: 20 },
|
|
|
|
|
// 1280: { slidesPerView: 4, spaceBetween: 24 },
|
|
|
|
|
// }}
|
|
|
|
|
// style={{
|
|
|
|
|
// maxWidth: "100%",
|
|
|
|
|
// overflow: "hidden",
|
|
|
|
|
// }}
|
|
|
|
|
// >
|
|
|
|
|
// {filtered.map((bookmark) => (
|
|
|
|
|
// <SwiperSlide
|
|
|
|
|
// key={bookmark.id}
|
|
|
|
|
// className="!w-[280px] sm:!w-[320px] md:!w-[190px] !h-auto"
|
|
|
|
|
// >
|
|
|
|
|
// {renderCard(bookmark)}
|
|
|
|
|
// </SwiperSlide>
|
|
|
|
|
// ))}
|
|
|
|
|
// </Swiper>
|
|
|
|
|
// </div>
|
|
|
|
|
// )}
|
|
|
|
|
// </section>
|
|
|
|
|
// );
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// "use client";
|
|
|
|
|
|
2025-10-10 16:30:17 +00:00
|
|
|
// import { useEffect, useState } from "react";
|
|
|
|
|
// import PublicationKlFilter from "./publication-filter";
|
|
|
|
|
// import { Button } from "@/components/ui/button";
|
|
|
|
|
// import { mediaWishlist } from "@/service/landing/landing";
|
|
|
|
|
|
|
|
|
|
// const itemsPerPage = 9;
|
|
|
|
|
|
|
|
|
|
// type PublicationCardGridProps = {
|
|
|
|
|
// selectedCategory: string;
|
|
|
|
|
// title?: string;
|
|
|
|
|
// refresh?: boolean;
|
|
|
|
|
// categoryFilter?: string[];
|
|
|
|
|
// formatFilter?: string[];
|
|
|
|
|
// isInstitute?: boolean;
|
|
|
|
|
// instituteId?: string;
|
|
|
|
|
// sortBy?: string;
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// export default function ForYouCardGrid({
|
|
|
|
|
// selectedCategory,
|
|
|
|
|
// title,
|
|
|
|
|
// refresh,
|
|
|
|
|
|
|
|
|
|
// isInstitute = false,
|
|
|
|
|
// instituteId = "",
|
|
|
|
|
// }: PublicationCardGridProps) {
|
|
|
|
|
// const [currentPage, setCurrentPage] = useState(0);
|
|
|
|
|
// const [contentImage, setContentImage] = useState([]);
|
|
|
|
|
// const [totalPages, setTotalPages] = useState(1);
|
|
|
|
|
// const [categoryFilter] = useState([]);
|
|
|
|
|
// const [formatFilter] = useState([]);
|
|
|
|
|
// const [sortBy] = useState();
|
|
|
|
|
|
|
|
|
|
// useEffect(() => {
|
|
|
|
|
// getDataImage();
|
|
|
|
|
// }, [currentPage, selectedCategory, title, refresh]);
|
|
|
|
|
|
|
|
|
|
// async function getDataImage() {
|
|
|
|
|
// const filter =
|
|
|
|
|
// categoryFilter?.length > 0
|
|
|
|
|
// ? categoryFilter?.sort().join(",")
|
|
|
|
|
// : selectedCategory || "";
|
|
|
|
|
|
|
|
|
|
// const name = title ?? "";
|
|
|
|
|
// const format = formatFilter?.join(",") ?? "";
|
|
|
|
|
|
|
|
|
|
// const response = await mediaWishlist(
|
|
|
|
|
// "1",
|
|
|
|
|
// isInstitute ? instituteId : "",
|
|
|
|
|
// name,
|
|
|
|
|
// filter,
|
|
|
|
|
// "12",
|
|
|
|
|
// currentPage,
|
|
|
|
|
// sortBy,
|
|
|
|
|
// format
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
// setTotalPages(response?.data?.data?.totalPages || 1);
|
|
|
|
|
// setContentImage(response?.data?.data?.content || []);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// const goToPage = (page: number) => {
|
|
|
|
|
// setCurrentPage(page);
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// return (
|
|
|
|
|
// <div className="space-y-6">
|
|
|
|
|
// {/* Grid Card */}
|
|
|
|
|
// <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
|
|
|
// {contentImage.length === 0 ? (
|
|
|
|
|
// <div className="col-span-3 text-center text-muted-foreground">
|
|
|
|
|
// Tidak ada konten ditemukan.
|
|
|
|
|
// </div>
|
|
|
|
|
// ) : (
|
|
|
|
|
// contentImage.map((item: any, idx: number) => (
|
|
|
|
|
// <PublicationKlFilter
|
|
|
|
|
// key={item.id}
|
|
|
|
|
// id={item.id} // ✅ tambahkan ini
|
|
|
|
|
// image={item.mediaUpload?.smallThumbnailLink}
|
|
|
|
|
// label={item.mediaType?.name ?? "UNKNOWN"}
|
|
|
|
|
// category={item.tags ?? "-"}
|
|
|
|
|
// date={new Date(item?.mediaUpload?.createdAt).toLocaleString(
|
|
|
|
|
// "id-ID",
|
|
|
|
|
// {
|
|
|
|
|
// day: "2-digit",
|
|
|
|
|
// month: "short",
|
|
|
|
|
// year: "numeric",
|
|
|
|
|
// hour: "2-digit",
|
|
|
|
|
// minute: "2-digit",
|
|
|
|
|
// timeZoneName: "short",
|
|
|
|
|
// }
|
|
|
|
|
// )}
|
|
|
|
|
// title={item?.mediaUpload?.title}
|
|
|
|
|
// description={""} // Optional: Tambahkan jika tersedia dari API
|
|
|
|
|
// />
|
|
|
|
|
// ))
|
|
|
|
|
// )}
|
|
|
|
|
// </div>
|
|
|
|
|
|
|
|
|
|
// {/* Pagination */}
|
|
|
|
|
// <div className="flex justify-center gap-2">
|
|
|
|
|
// {Array.from({ length: totalPages }, (_, i) => (
|
|
|
|
|
// <Button
|
|
|
|
|
// key={i}
|
|
|
|
|
// variant={currentPage === i + 1 ? "default" : "outline"}
|
|
|
|
|
// size="sm"
|
|
|
|
|
// onClick={() => goToPage(i + 1)}
|
|
|
|
|
// >
|
|
|
|
|
// {i + 1}
|
|
|
|
|
// </Button>
|
|
|
|
|
// ))}
|
|
|
|
|
// </div>
|
|
|
|
|
// </div>
|
|
|
|
|
// );
|
|
|
|
|
// }
|