"use client"; import { useEffect } from "react"; import { useLocale, useTranslations } from "next-intl"; import { CreditCard } from "lucide-react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Progress } from "@/components/ui/progress"; import type { DashboardSnapshot } from "@/hooks/use-dashboard-snapshot"; import { normalizeTier } from "@/lib/polar-products"; import { formatCredits } from "@/lib/credits-activity"; import { cn } from "@/lib/utils"; import { toast } from "@/lib/toast"; const TIER_BADGE_STYLES: Record = { free: "bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400", starter: "bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-400", pro: "bg-purple-100 text-purple-700 dark:bg-purple-900/40 dark:text-purple-400", max: "bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-400", }; // --------------------------------------------------------------------------- // Component // --------------------------------------------------------------------------- const LOW_CREDITS_THRESHOLD = 20; type CreditOverviewProps = { balance?: DashboardSnapshot["balance"]; subscription?: DashboardSnapshot["subscription"]; usageStats?: DashboardSnapshot["usageStats"]; }; export function CreditOverview({ balance, subscription, usageStats }: CreditOverviewProps) { const t = useTranslations('toasts'); const router = useRouter(); const locale = useLocale(); useEffect(() => { if (balance === undefined) return; const available = balance.available; if (available <= 0 || available >= LOW_CREDITS_THRESHOLD) return; const key = "ls-low-credits-dashboard"; if (typeof window !== "undefined" && sessionStorage.getItem(key)) return; sessionStorage.setItem(key, "1"); toast.action(t('billing.lowCreditsTitle'), { description: t('billing.lowCreditsDesc', { remaining: available }), label: t('billing.topUp'), onClick: () => router.push("/settings/billing"), type: "warning", }); }, [t, balance, router]); // ── Loading State ────────────────────────────────────────────────────── if ( balance === undefined || subscription === undefined || usageStats === undefined ) { return (
{Array.from({ length: 3 }).map((_, i) => (
))}
); } // ── Computed Values ──────────────────────────────────────────────────── const tier = normalizeTier(subscription.tier); const monthlyCredits = usageStats.monthlyCredits; const usagePercent = monthlyCredits > 0 ? Math.min(100, Math.round((usageStats.monthlyUsage / monthlyCredits) * 100)) : 0; const progressColorClass = usagePercent > 95 ? "[&>[data-slot=progress-indicator]]:bg-destructive" : usagePercent >= 80 ? "[&>[data-slot=progress-indicator]]:bg-amber-500" : ""; return (
{/* ── Block A: Verfügbare Credits ──────────────────────────────── */}

Verfügbare Credits

{formatCredits(balance.available, locale)} {tier.charAt(0).toUpperCase() + tier.slice(1)}
{balance.reserved > 0 && (

({formatCredits(balance.reserved, locale)} reserviert)

)}
{/* ── Block B: Monatlicher Verbrauch ───────────────────────────── */}

Monatlicher Verbrauch

{usagePercent}%
{formatCredits(usageStats.monthlyUsage, locale)} von{" "} {formatCredits(monthlyCredits, locale)} verwendet {usageStats.totalGenerations} Generierungen
{/* ── Block C: Aufladen ───────────────────────────────────────── */}
); }