import { useState } from "react"; export default function PortfolioView() { // Placeholder portfolio data - ideally would come from props const [portfolio] = useState({ totalValue: 156842.75, cashBalance: 12467.32, performance: { daily: 1.24, weekly: -0.52, monthly: 3.87, yearly: 14.28, }, holdings: [ { symbol: "AAPL", name: "Apple Inc.", shares: 45, price: 187.32, value: 8429.4, change: 1.2, allocation: 5.8, avgCost: 162.5, }, { symbol: "MSFT", name: "Microsoft Corporation", shares: 30, price: 403.78, value: 12113.4, change: 0.5, allocation: 8.4, avgCost: 340.25, }, { symbol: "AMZN", name: "Amazon.com Inc.", shares: 25, price: 178.75, value: 4468.75, change: -0.8, allocation: 3.1, avgCost: 145.3, }, { symbol: "GOOGL", name: "Alphabet Inc.", shares: 20, price: 164.85, value: 3297.0, change: 2.1, allocation: 2.3, avgCost: 125.75, }, { symbol: "NVDA", name: "NVIDIA Corporation", shares: 35, price: 875.28, value: 30634.8, change: 3.4, allocation: 21.3, avgCost: 520.4, }, { symbol: "TSLA", name: "Tesla, Inc.", shares: 40, price: 175.9, value: 7036.0, change: -1.2, allocation: 4.9, avgCost: 190.75, }, ], }); const [activeTab, setActiveTab] = useState<"holdings" | "performance">( "holdings", ); const [sortConfig, setSortConfig] = useState<{ key: string; direction: "asc" | "desc"; }>({ key: "allocation", direction: "desc", }); const [selectedHolding, setSelectedHolding] = useState(null); const sortedHoldings = [...portfolio.holdings].sort((a, b) => { if ( a[sortConfig.key as keyof typeof a] < b[sortConfig.key as keyof typeof b] ) { return sortConfig.direction === "asc" ? -1 : 1; } if ( a[sortConfig.key as keyof typeof a] > b[sortConfig.key as keyof typeof b] ) { return sortConfig.direction === "asc" ? 1 : -1; } return 0; }); const requestSort = (key: string) => { let direction: "asc" | "desc" = "asc"; if (sortConfig.key === key && sortConfig.direction === "asc") { direction = "desc"; } setSortConfig({ key, direction }); }; const formatCurrency = (value: number) => { return new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", }).format(value); }; const formatPercent = (value: number) => { return `${value > 0 ? "+" : ""}${value.toFixed(2)}%`; }; // Faux chart data for selected holding const generateChartData = (symbol: string) => { const data = []; const basePrice = portfolio.holdings.find((h) => h.symbol === symbol)?.price || 100; for (let i = 0; i < 30; i++) { const date = new Date(); date.setDate(date.getDate() - 30 + i); const randomFactor = (Math.sin(i / 5) + Math.random() - 0.5) * 0.05; const price = basePrice * (1 + randomFactor * (i / 3)); data.push({ date: date.toLocaleDateString("en-US", { month: "short", day: "numeric", }), price: parseFloat(price.toFixed(2)), }); } return data; }; // Calculate total value and percent change for display const totalValue = portfolio.totalValue; const totalChange = portfolio.holdings.reduce( (acc, curr) => acc + (curr.price - curr.avgCost) * curr.shares, 0, ); const totalPercentChange = (totalChange / (portfolio.totalValue - totalChange)) * 100; const selectedStock = selectedHolding ? portfolio.holdings.find((h) => h.symbol === selectedHolding) : null; const chartData = selectedHolding ? generateChartData(selectedHolding) : []; return (

Portfolio Summary

Updated: {new Date().toLocaleString()}

Total Value

{formatCurrency(portfolio.totalValue)}

= 0 ? "text-green-600" : "text-red-600"}`} > {totalPercentChange >= 0 ? ( ) : ( )} {formatPercent(totalPercentChange)} All Time

Cash Balance

{formatCurrency(portfolio.cashBalance)}

{((portfolio.cashBalance / portfolio.totalValue) * 100).toFixed( 1, )} % of portfolio

Daily Change

= 0 ? "text-green-600" : "text-red-600"}`} > {formatPercent(portfolio.performance.daily)}

= 0 ? "text-green-600" : "text-red-600"}`} > {formatCurrency( (portfolio.totalValue * portfolio.performance.daily) / 100, )}

{activeTab === "holdings" && !selectedHolding && (
{sortedHoldings.map((holding) => ( setSelectedHolding(holding.symbol)} > ))}
requestSort("symbol")} className="group px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100" >
Symbol {sortConfig.key === "symbol" ? sortConfig.direction === "asc" ? "↑" : "↓" : "↕"}
Company requestSort("shares")} className="group px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100" >
Shares {sortConfig.key === "shares" ? sortConfig.direction === "asc" ? "↑" : "↓" : "↕"}
requestSort("price")} className="group px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100" >
Price {sortConfig.key === "price" ? sortConfig.direction === "asc" ? "↑" : "↓" : "↕"}
requestSort("change")} className="group px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100" >
Change {sortConfig.key === "change" ? sortConfig.direction === "asc" ? "↑" : "↓" : "↕"}
requestSort("value")} className="group px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100" >
Value {sortConfig.key === "value" ? sortConfig.direction === "asc" ? "↑" : "↓" : "↕"}
requestSort("allocation")} className="group px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer hover:bg-gray-100" >
Allocation {sortConfig.key === "allocation" ? sortConfig.direction === "asc" ? "↑" : "↓" : "↕"}
{holding.symbol} {holding.name} {holding.shares.toLocaleString()} {formatCurrency(holding.price)} = 0 ? "text-green-600" : "text-red-600"}`} > {holding.change >= 0 ? ( ) : ( )} {formatPercent(holding.change)} {formatCurrency(holding.value)}
= 0 ? "bg-green-500" : "bg-red-500"}`} style={{ width: `${Math.min(100, holding.allocation * 3)}%`, }} >
{holding.allocation.toFixed(1)}%
)} {activeTab === "holdings" && selectedHolding && selectedStock && (

{selectedStock.symbol}

{selectedStock.name}
{formatCurrency(selectedStock.price)} = 0 ? "text-green-600" : "text-red-600"}`} > {selectedStock.change >= 0 ? "▲" : "▼"}{" "} {formatPercent(selectedStock.change)}
{chartData.map((point, index) => { const maxPrice = Math.max(...chartData.map((d) => d.price)); const minPrice = Math.min(...chartData.map((d) => d.price)); const range = maxPrice - minPrice; const heightPercent = range === 0 ? 50 : ((point.price - minPrice) / range) * 80 + 10; return (
= chartData[Math.max(0, index - 1)].price ? "bg-green-500" : "bg-red-500"}`} style={{ height: `${heightPercent}%` }} >
{index % 5 === 0 && ( {point.date} )}
); })}

Shares Owned

{selectedStock.shares.toLocaleString()}

Market Value

{formatCurrency(selectedStock.value)}

Avg. Cost

{formatCurrency(selectedStock.avgCost)}

Cost Basis

{formatCurrency( selectedStock.avgCost * selectedStock.shares, )}

Gain/Loss

= 0 ? "text-green-600" : "text-red-600"}`} > {formatCurrency( (selectedStock.price - selectedStock.avgCost) * selectedStock.shares, )}

Allocation

{selectedStock.allocation.toFixed(2)}%

)} {activeTab === "performance" && (

Performance Overview

Daily

= 0 ? "text-green-600" : "text-red-600"}`} > {portfolio.performance.daily >= 0 ? ( ) : ( )} {formatPercent(portfolio.performance.daily)}

Weekly

= 0 ? "text-green-600" : "text-red-600"}`} > {portfolio.performance.weekly >= 0 ? ( ) : ( )} {formatPercent(portfolio.performance.weekly)}

Monthly

= 0 ? "text-green-600" : "text-red-600"}`} > {portfolio.performance.monthly >= 0 ? ( ) : ( )} {formatPercent(portfolio.performance.monthly)}

Yearly

= 0 ? "text-green-600" : "text-red-600"}`} > {portfolio.performance.yearly >= 0 ? ( ) : ( )} {formatPercent(portfolio.performance.yearly)}

Portfolio Allocation

{sortedHoldings.map((holding) => (
= 0 ? "bg-green-500" : "bg-red-500"}`} >
{holding.symbol}
{holding.allocation.toFixed(1)}%
))}

Portfolio Diversification

{[ "Technology", "Consumer Cyclical", "Communication Services", "Financial", "Other", ].map((sector, index) => { const widths = [42, 23, 18, 10, 7]; // example percentages const colors = [ "bg-indigo-600", "bg-blue-500", "bg-green-500", "bg-yellow-500", "bg-red-500", ]; return (
); })}
{[ "Technology", "Consumer Cyclical", "Communication Services", "Financial", "Other", ].map((sector, index) => { const widths = [42, 23, 18, 10, 7]; // example percentages const colors = [ "text-indigo-600", "text-blue-500", "text-green-500", "text-yellow-500", "text-red-500", ]; return (
{sector} {widths[index]}%
); })}
)}
); }