← back to Wine Finder Next
app/portfolio/page.tsx
131 lines
// app/portfolio/page.tsx
import { getUserPortfolio } from '@/lib/portfolio';
import Link from 'next/link';
export const dynamic = 'force-dynamic';
export default async function PortfolioPage() {
// Demo user ID - replace with real auth
const userId = 1;
const rows = getUserPortfolio(userId);
const totalValue = rows.reduce((sum: number, r: any) => sum + (r.market_value || 0), 0);
const totalCost = rows.reduce((sum: number, r: any) => sum + (r.cost_total || 0), 0);
const totalGainLoss = totalValue - totalCost;
const totalGainLossPercent = totalCost > 0 ? ((totalGainLoss / totalCost) * 100) : 0;
return (
<main className="max-w-6xl mx-auto p-6 space-y-6">
<div className="flex justify-between items-center">
<h1 className="text-3xl font-bold text-gray-900">🍷 My Wine Portfolio</h1>
<Link href="/wines" className="px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition">
Browse Wines
</Link>
</div>
{/* Portfolio Summary */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-6">
<div className="bg-white p-6 rounded-lg shadow-md border">
<div className="text-2xl font-bold text-gray-900">${totalValue.toLocaleString()}</div>
<div className="text-gray-600">Total Portfolio Value</div>
</div>
<div className="bg-white p-6 rounded-lg shadow-md border">
<div className="text-2xl font-bold text-gray-900">${totalCost.toLocaleString()}</div>
<div className="text-gray-600">Total Cost Basis</div>
</div>
<div className="bg-white p-6 rounded-lg shadow-md border">
<div className={`text-2xl font-bold ${totalGainLoss >= 0 ? 'text-green-600' : 'text-red-600'}`}>
${Math.abs(totalGainLoss).toLocaleString()}
</div>
<div className="text-gray-600">
{totalGainLoss >= 0 ? 'Total Gain' : 'Total Loss'}
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow-md border">
<div className={`text-2xl font-bold ${totalGainLossPercent >= 0 ? 'text-green-600' : 'text-red-600'}`}>
{totalGainLossPercent >= 0 ? '+' : ''}{totalGainLossPercent.toFixed(1)}%
</div>
<div className="text-gray-600">Total Return</div>
</div>
</div>
{/* Holdings Table */}
<div className="bg-white rounded-lg shadow-md border overflow-hidden">
<div className="px-6 py-4 bg-gray-50 border-b">
<h2 className="text-xl font-semibold text-gray-900">Holdings</h2>
</div>
{rows.length === 0 ? (
<div className="p-8 text-center">
<h3 className="text-lg font-medium text-gray-500 mb-2">No wines in portfolio</h3>
<p className="text-gray-400 mb-4">Start building your collection!</p>
<Link href="/wines" className="inline-block px-6 py-3 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition">
Browse Wines
</Link>
</div>
) : (
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Wine</th>
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Units</th>
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Cost/Unit</th>
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Current Price</th>
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Market Value</th>
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Gain/Loss</th>
<th className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">% Change</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
{rows.map((r: any) => (
<tr key={r.id} className="hover:bg-gray-50">
<td className="px-6 py-4">
<Link href={`/wines/${r.wine_id}`} className="font-medium text-purple-600 hover:underline">
{r.name}
</Link>
<div className="text-sm text-gray-500">
{r.varietal} • {r.region} • {r.country}
</div>
</td>
<td className="px-6 py-4 text-right text-sm font-medium">{r.units}</td>
<td className="px-6 py-4 text-right text-sm">
${r.cost_basis?.toFixed(2) ?? '-'}
</td>
<td className="px-6 py-4 text-right text-sm font-medium">
${r.current_price?.toFixed(2) ?? '-'}
</td>
<td className="px-6 py-4 text-right text-sm font-bold">
${r.market_value?.toFixed(2) ?? '-'}
</td>
<td className="px-6 py-4 text-right text-sm">
{r.current_price && r.cost_basis ? (
<span className={`font-medium ${
(r.current_price - r.cost_basis) >= 0 ? 'text-green-600' : 'text-red-600'
}`}>
{(r.current_price - r.cost_basis) >= 0 ? '+' : ''}
${((r.current_price - r.cost_basis) * r.units).toFixed(2)}
</span>
) : (
'-'
)}
</td>
<td className="px-6 py-4 text-right text-sm">
{r.pct_change != null ? (
<span className={`font-medium ${r.pct_change >= 0 ? 'text-green-600' : 'text-red-600'}`}>
{r.pct_change >= 0 ? '+' : ''}{r.pct_change.toFixed(1)}%
</span>
) : (
'-'
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
)}
</div>
</main>
);
}