"use client"; import { useFormatter, useLocale } from "next-intl"; import { Activity, Coins } from "lucide-react"; import { useEffect, useState } from "react"; import { Badge } from "@/components/ui/badge"; import type { DashboardSnapshot } from "@/hooks/use-dashboard-snapshot"; import { formatCredits } from "@/lib/credits-activity"; import { cn } from "@/lib/utils"; // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function statusBadge(status: string) { switch (status) { case "committed": return Abgeschlossen; case "reserved": return ( Reserviert ); case "released": return ( Rückerstattet ); case "failed": return Fehlgeschlagen; default: return Unbekannt; } } function truncatedDescription(text: string, maxLen = 40) { if (text.length <= maxLen) return text; return text.slice(0, maxLen) + "…"; } // --------------------------------------------------------------------------- // Component // --------------------------------------------------------------------------- type RecentTransactionsProps = { recentTransactions?: DashboardSnapshot["recentTransactions"]; }; export function RecentTransactions({ recentTransactions }: RecentTransactionsProps) { const format = useFormatter(); const locale = useLocale(); const [now, setNow] = useState(null); useEffect(() => { const updateNow = () => { setNow(Date.now()); }; const initialTimeout = window.setTimeout(updateNow, 0); const interval = window.setInterval(updateNow, 60_000); return () => { window.clearTimeout(initialTimeout); window.clearInterval(interval); }; }, []); const transactions = recentTransactions ?? []; const formatRelativeTime = (timestamp: number) => { const referenceNow = now ?? timestamp; const diff = referenceNow - timestamp; const minutes = Math.floor(diff / 60000); const hours = Math.floor(diff / 3600000); const days = Math.floor(diff / 86400000); if (minutes < 1) return "Gerade eben"; if (minutes < 60) return `vor ${minutes} Min.`; if (hours < 24) return `vor ${hours} Std.`; if (days < 7) return days === 1 ? "vor 1 Tag" : `vor ${days} Tagen`; return format.dateTime(timestamp, { day: "numeric", month: "short" }); }; // ── Loading State ────────────────────────────────────────────────────── if (recentTransactions === undefined) { return ( Letzte Aktivität {Array.from({ length: 5 }).map((_, i) => ( ))} ); } // ── Empty State ──────────────────────────────────────────────────────── if (transactions.length === 0) { return ( Letzte Aktivität Noch keine Aktivität Erstelle dein erstes Bild im Canvas (Prompt-Knoten) ); } // ── Transaction List ─────────────────────────────────────────────────── return ( Letzte Aktivität {transactions.map((t: NonNullable[number]) => { const isCredit = t.amount > 0; return ( {/* Status Indicator */} {statusBadge(t.status)} {/* Description */} {truncatedDescription(t.description)} {formatRelativeTime(t._creationTime)} {/* Credits */} {isCredit ? "+" : "−"} {formatCredits(Math.abs(t.amount), locale)} ); })} ); }
Noch keine Aktivität
Erstelle dein erstes Bild im Canvas (Prompt-Knoten)
{truncatedDescription(t.description)}
{formatRelativeTime(t._creationTime)}