import { useState } from "react"; import { cn } from "~/lib/utils"; import { TrendingUp, TrendingDown, Wallet, Plus, BarChart3, ExternalLink, RefreshCw, Star, Bell, Eye, } from "lucide-react"; import { Button } from "@/routes/ui/button"; import { ChainIcon } from "../components/shared/ChainIcon"; export interface PortfolioHolding { tokenAddress: string; chain: string; symbol: string; name: string; amount: string; currentPrice: number; currentValue: number; change24h: number; change24hPercent: number; entryPrice?: number; pnl?: number; pnlPercent?: number; } export interface PortfolioAnalytics { bestPerformer: { symbol: string; change: number }; worstPerformer: { symbol: string; change: number }; winRate: number; avgHoldTime: number; totalTrades: number; } export interface PortfolioData { wallets: { address: string; chain: string; type: "metamask" | "phantom" | "coinbase"; }[]; totalValue: number; change24h: number; change24hPercent: number; holdings: PortfolioHolding[]; analytics: PortfolioAnalytics; } export interface PortfolioPanelProps { /** Portfolio data */ portfolio: PortfolioData; /** Callback when refresh is clicked */ onRefresh?: () => void; /** Callback when "Analyze" is clicked for a token */ onAnalyzeToken?: (holding: PortfolioHolding) => void; /** Callback when "Set Alert" is clicked for a token */ onSetAlert?: (holding: PortfolioHolding) => void; /** Callback when "View on DexScreener" is clicked */ onViewToken?: (holding: PortfolioHolding) => void; /** Callback when "Add Manual Position" is clicked */ onAddPosition?: () => void; /** Whether data is loading */ isLoading?: boolean; /** Additional class names */ className?: string; } /** * PortfolioPanel - Portfolio tracker with holdings and P&L * * Features: * - Total portfolio value and 24h change * - List of holdings with current value and P&L * - Performance analytics (best/worst performers, win rate) * - Quick actions per token (analyze, alert, view) * - Manual position entry */ export function PortfolioPanel({ portfolio, onRefresh, onAnalyzeToken, onSetAlert, onViewToken, onAddPosition, isLoading = false, className, }: PortfolioPanelProps) { const [isRefreshing, setIsRefreshing] = useState(false); const handleRefresh = async () => { setIsRefreshing(true); await onRefresh?.(); setTimeout(() => setIsRefreshing(false), 1000); }; const formatCurrency = (value: number) => { if (value >= 1000000) return `$${(value / 1000000).toFixed(2)}M`; if (value >= 1000) return `$${(value / 1000).toFixed(1)}K`; return `$${value.toFixed(2)}`; }; const formatPercent = (value: number) => { const sign = value >= 0 ? "+" : ""; return `${sign}${value.toFixed(2)}%`; }; return (
{portfolio.holdings.length} tokens