diff --git a/components/landing-page/header.tsx b/components/landing-page/header.tsx index 65b3c87..dcaf242 100644 --- a/components/landing-page/header.tsx +++ b/components/landing-page/header.tsx @@ -14,9 +14,6 @@ import { toggleBookmark, getBookmarkSummaryForUser } from "@/service/content"; export default function Header() { const [data, setData] = useState([]); const [bookmarkedIds, setBookmarkedIds] = useState>(new Set()); - const [userId, setUserId] = useState( - getCookiesDecrypt("uie") || null - ); const router = useRouter(); const params = useParams(); const MySwal = withReactContent(Swal); @@ -29,7 +26,7 @@ export default function Header() { const response = await listArticles( 1, 5, - 1, // ⬅️ tambahkan typeId = 1 (image only) + 1, // hanya typeId = 1 (image) undefined, undefined, "createdAt", @@ -39,7 +36,6 @@ export default function Header() { let articlesData: any[] = []; if (response?.error) { - // Jika gagal, fallback tetap filter typeId = 1 const fallback = await listData( "", "", @@ -49,7 +45,7 @@ export default function Header() { "createdAt", "", "", - "1" // ⬅️ tambahkan filter typeId = 1 di fallback juga + "1" ); articlesData = fallback?.data?.data?.content || []; } else { @@ -69,39 +65,50 @@ export default function Header() { fetchData(); }, [slug]); + // ✅ Sinkronisasi bookmark: dari localStorage + backend user login useEffect(() => { - const fetchBookmarks = async () => { - const currentUserId: any = getCookiesDecrypt("uie"); - setUserId(currentUserId); - - if (!currentUserId) { - setBookmarkedIds(new Set()); - return; - } - + const syncBookmarks = async () => { try { - const res = await getBookmarkSummaryForUser(); - const bookmarks = - res?.data?.data?.recentBookmarks || - res?.data?.data?.bookmarks || - res?.data?.data || - []; + const roleId = Number(getCookiesDecrypt("urie")); + let localSet = new Set(); - const ids = new Set( - (Array.isArray(bookmarks) ? bookmarks : []) - .map((b: any) => Number(b.articleId ?? b.id ?? b.article?.id)) - .filter((x) => !isNaN(x)) - ); + const simpananLocal = localStorage.getItem("bookmarkedIds"); + if (simpananLocal) { + localSet = new Set(JSON.parse(simpananLocal)); + } - setBookmarkedIds(ids); + // Jika user login, gabungkan dengan data dari backend + if (roleId && !isNaN(roleId)) { + const res = await getBookmarkSummaryForUser(); + const bookmarks = + res?.data?.data?.recentBookmarks || + res?.data?.data?.bookmarks || + res?.data?.data || + []; + + const ids = new Set( + (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)) + ); + } else { + // Jika belum login, pakai local saja + setBookmarkedIds(localSet); + } } catch (err) { - console.error("Gagal memuat bookmark user:", err); - setBookmarkedIds(new Set()); + console.error("Gagal sinkronisasi bookmark:", err); } }; - fetchBookmarks(); - }, [userId]); + syncBookmarks(); + }, []); return (
@@ -111,17 +118,8 @@ export default function Header() { key={data[0].id} item={data[0]} isBig - isInitiallyBookmarked={bookmarkedIds.has(Number(data[0].id))} - onSaved={(id) => - setBookmarkedIds((prev) => new Set([...prev, Number(id)])) - } - onRemoved={(id) => - setBookmarkedIds((prev) => { - const next = new Set(prev); - next.delete(Number(id)); - return next; - }) - } + bookmarkedIds={bookmarkedIds} + setBookmarkedIds={setBookmarkedIds} /> )} @@ -130,17 +128,8 @@ export default function Header() { - setBookmarkedIds((prev) => new Set([...prev, Number(id)])) - } - onRemoved={(id) => - setBookmarkedIds((prev) => { - const next = new Set(prev); - next.delete(Number(id)); - return next; - }) - } + bookmarkedIds={bookmarkedIds} + setBookmarkedIds={setBookmarkedIds} /> ))} @@ -158,7 +147,7 @@ export default function Header() { ); } -// 🔹 Helper function untuk transform data +// 🔹 Helper function function itemTransform(article: any) { return { id: article.id, @@ -185,29 +174,25 @@ function itemTransform(article: any) { }; } +// 🔹 Komponen Card function Card({ item, isBig = false, - isInitiallyBookmarked = false, - onSaved, - onRemoved, + bookmarkedIds, + setBookmarkedIds, }: { item: any; isBig?: boolean; - isInitiallyBookmarked?: boolean; - onSaved?: (id: number) => void; - onRemoved?: (id: number) => void; + bookmarkedIds: Set; + setBookmarkedIds: React.Dispatch>>; }) { const router = useRouter(); const MySwal = withReactContent(Swal); const [isSaving, setIsSaving] = useState(false); - const [isBookmarked, setIsBookmarked] = useState(isInitiallyBookmarked); - useEffect(() => { - setIsBookmarked(isInitiallyBookmarked); - }, [isInitiallyBookmarked]); + const isBookmarked = bookmarkedIds.has(Number(item.id)); - const getLink = () => `/content/image/detail/${item?.id}`; + const getLink = () => `/content/image/detail/${item?.id}`; const handleToggleBookmark = async () => { const roleId = Number(getCookiesDecrypt("urie")); @@ -234,18 +219,27 @@ function Card({ confirmButtonColor: "#d33", }); } else { - const nowBookmarked = !isBookmarked; - setIsBookmarked(nowBookmarked); - if (nowBookmarked) onSaved?.(item.id); - else onRemoved?.(item.id); + const updated = new Set(bookmarkedIds); + let pesan = ""; + + if (isBookmarked) { + updated.delete(Number(item.id)); + pesan = "Dihapus dari bookmark."; + } else { + updated.add(Number(item.id)); + pesan = "Artikel disimpan ke bookmark."; + } + + setBookmarkedIds(updated); + localStorage.setItem( + "bookmarkedIds", + JSON.stringify(Array.from(updated)) + ); MySwal.fire({ icon: "success", - title: nowBookmarked ? "Disimpan!" : "Dihapus!", - text: nowBookmarked - ? "Artikel berhasil disimpan ke bookmark." - : "Artikel dihapus dari bookmark.", - confirmButtonColor: "#3085d6", + title: isBookmarked ? "Dihapus!" : "Disimpan!", + text: pesan, timer: 1500, showConfirmButton: false, }); @@ -264,30 +258,26 @@ function Card({ }; return ( -
-
-
- - {item.title} - -
+
+
+ + {item.title} + +
-
+
+
{item.clientName} @@ -317,31 +307,31 @@ function Card({ {item.title} +
-
-
- - -
- - +
+
+ +
+ +
diff --git a/components/main/category-tabs.tsx b/components/main/category-tabs.tsx index a1efa17..6d7cbfb 100644 --- a/components/main/category-tabs.tsx +++ b/components/main/category-tabs.tsx @@ -1,7 +1,10 @@ "use client"; import { useState, useEffect } from "react"; -import { getPublicClients, PublicClient } from "@/service/client/public-clients"; +import { + getPublicClients, + PublicClient, +} from "@/service/client/public-clients"; type CategoryTabsProps = { selectedCategory: string; @@ -15,17 +18,21 @@ export default function CategoryTabs({ const [clients, setClients] = useState([]); const [loading, setLoading] = useState(true); - // Fetch public clients + // ✅ Fetch public clients dari API useEffect(() => { async function fetchClients() { try { const response = await getPublicClients(); if (response?.data?.success && response.data.data) { - setClients(response.data.data); + // 🔹 Filter hanya client aktif (boolean true) + const activeClients = response.data.data.filter( + (client: PublicClient) => client.isActive === true + ); + setClients(activeClients); } } catch (error) { console.error("Error fetching public clients:", error); - // Fallback to empty array if API fails + // Fallback ke data statis jika API gagal setClients([]); } finally { setLoading(false); @@ -35,9 +42,22 @@ export default function CategoryTabs({ fetchClients(); }, []); - // Create categories array with "SEMUA" first, then client names - const categories = ["SEMUA", ...clients.map(client => client.name)]; + // 🔹 Fallback jika API gagal + const fallbackClients = [ + { id: 1, name: "DIV HUMAS POLRI" }, + { id: 2, name: "POLDASUMUT" }, + { id: 3, name: "POLDAMETROJAYA" }, + { id: 4, name: "POLDARIYAD" }, + { id: 5, name: "POLDABALI" }, + ]; + const displayClients = + clients.length > 0 ? clients : (fallbackClients as any); + + // 🔹 Susun kategori: “SEMUA” di awal + const categories = ["SEMUA", ...displayClients.map((c: any) => c.name)]; + + // 🔹 Tampilkan skeleton saat loading if (loading) { return (
@@ -51,6 +71,7 @@ export default function CategoryTabs({ ); } + // 🔹 Render kategori client return (
{categories.map((cat, idx) => ( @@ -59,8 +80,8 @@ export default function CategoryTabs({ onClick={() => onCategoryChange(cat)} className={`px-4 py-1 text-sm rounded font-medium border transition-colors ${ selectedCategory === cat - ? "bg-[#C6A455] text-white" - : "bg-white text-gray-800 hover:bg-gray-50" + ? "bg-[#C6A455] text-white border-[#C6A455]" + : "bg-white text-gray-800 hover:bg-gray-50 border-gray-300" }`} > {cat.toUpperCase()} @@ -69,3 +90,75 @@ export default function CategoryTabs({
); } + +// "use client"; + +// import { useState, useEffect } from "react"; +// import { getPublicClients, PublicClient } from "@/service/client/public-clients"; + +// type CategoryTabsProps = { +// selectedCategory: string; +// onCategoryChange: (category: string) => void; +// }; + +// export default function CategoryTabs({ +// selectedCategory, +// onCategoryChange, +// }: CategoryTabsProps) { +// const [clients, setClients] = useState([]); +// const [loading, setLoading] = useState(true); + +// // Fetch public clients +// useEffect(() => { +// async function fetchClients() { +// try { +// const response = await getPublicClients(); +// if (response?.data?.success && response.data.data) { +// setClients(response.data.data); +// } +// } catch (error) { +// console.error("Error fetching public clients:", error); +// // Fallback to empty array if API fails +// setClients([]); +// } finally { +// setLoading(false); +// } +// } + +// fetchClients(); +// }, []); + +// // Create categories array with "SEMUA" first, then client names +// const categories = ["SEMUA", ...clients.map(client => client.name)]; + +// if (loading) { +// return ( +//
+// {Array.from({ length: 6 }).map((_, idx) => ( +//
+// ))} +//
+// ); +// } + +// return ( +//
+// {categories.map((cat, idx) => ( +// +// ))} +//
+// ); +// }