diff --git a/app/tiktok/page.tsx b/app/tiktok/page.tsx index c39925e..3845535 100644 --- a/app/tiktok/page.tsx +++ b/app/tiktok/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { Music2, Link2, Unlink, Loader2, AlertTriangle } from "lucide-react"; +import { Music2, Link2, Unlink, Loader2, AlertTriangle, Eye, EyeOff } from "lucide-react"; import { useEffect, useState } from "react"; import { useRouter, useSearchParams } from "next/navigation"; @@ -17,12 +17,43 @@ interface TikTokStats { plan: "free" | "pro" | "elite" | "team"; } +type CardId = "followers" | "likes" | "videos" | "views" | "ratio"; + +const defaultVisibleCards: Record = { + followers: true, + likes: true, + videos: true, + views: true, + ratio: true, +}; + +const visibleCardsStorageKey = "tiktok.visibleCards"; + +function parseVisibleCards(value: string | null): Record { + if (!value) return defaultVisibleCards; + + try { + const parsed = JSON.parse(value) as Partial>; + return { + followers: typeof parsed.followers === "boolean" ? parsed.followers : defaultVisibleCards.followers, + likes: typeof parsed.likes === "boolean" ? parsed.likes : defaultVisibleCards.likes, + videos: typeof parsed.videos === "boolean" ? parsed.videos : defaultVisibleCards.videos, + views: typeof parsed.views === "boolean" ? parsed.views : defaultVisibleCards.views, + ratio: typeof parsed.ratio === "boolean" ? parsed.ratio : defaultVisibleCards.ratio, + }; + } catch { + return defaultVisibleCards; + } +} + export default function TikTokPage() { const [stats, setStats] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [disconnecting, setDisconnecting] = useState(false); const [showDisconnectConfirm, setShowDisconnectConfirm] = useState(false); + const [visibleCards, setVisibleCards] = useState>(defaultVisibleCards); + const [visibleCardsHydrated, setVisibleCardsHydrated] = useState(false); const searchParams = useSearchParams(); const router = useRouter(); @@ -48,9 +79,17 @@ export default function TikTokPage() { } useEffect(() => { + const persisted = parseVisibleCards(window.localStorage.getItem(visibleCardsStorageKey)); + setVisibleCards(persisted); + setVisibleCardsHydrated(true); loadStats(); }, []); + useEffect(() => { + if (!visibleCardsHydrated) return; + window.localStorage.setItem(visibleCardsStorageKey, JSON.stringify(visibleCards)); + }, [visibleCards, visibleCardsHydrated]); + async function handleDisconnect() { if (disconnecting) return; setDisconnecting(true); @@ -66,6 +105,49 @@ export default function TikTokPage() { const urlError = searchParams.get("error"); + const cards = stats + ? [ + { + id: "followers" as const, + label: "Followers", + value: stats.followers.toLocaleString("fr-FR"), + sub: "Abonnés totaux", + accent: "purple" as const, + }, + { + id: "likes" as const, + label: "Likes totaux", + value: stats.likes.toLocaleString("fr-FR"), + sub: "Cumul likes", + accent: "red" as const, + }, + { + id: "videos" as const, + label: "Vidéos publiées", + value: stats.videoCount.toLocaleString("fr-FR"), + sub: "Vidéos au total", + accent: "blue" as const, + }, + { + id: "views" as const, + label: "Vues vidéos", + value: stats.views.toLocaleString("fr-FR"), + sub: "Vues totales des vidéos", + accent: "green" as const, + }, + { + id: "ratio" as const, + label: "Ratio likes/vidéo", + value: stats.videoCount > 0 ? Math.round(stats.likes / stats.videoCount).toLocaleString("fr-FR") : "—", + sub: "Moy. likes par vidéo", + accent: "gold" as const, + }, + ] + : []; + + const shownCards = cards.filter((card) => visibleCards[card.id]); + const hiddenCards = cards.filter((card) => !visibleCards[card.id]); + return (
{/* Header */} @@ -124,38 +206,69 @@ export default function TikTokPage() {
)} -
- - - - - 0 ? Math.round(stats.likes / stats.videoCount).toLocaleString("fr-FR") : "—"} - sub="Moy. likes par vidéo" - accent="gold" - /> -
+ {hiddenCards.length > 0 && ( +
+ {hiddenCards.map((card) => ( + + ))} + +
+ )} + + {shownCards.length > 0 ? ( +
+ {shownCards.map((card) => ( +
+ + +
+ ))} +
+ ) : ( +
+

+ Toutes les cartes sont masquées +

+ +
+ )} {/* Graph */}