- Sparkline for summary cards - AreaChart for asset trends - DonutChart for sector allocation - BarChart for portfolio comparison Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
228 lines
6.9 KiB
TypeScript
228 lines
6.9 KiB
TypeScript
'use client';
|
|
|
|
import { DashboardLayout } from '@/components/layout/dashboard-layout';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import { Sparkline, AreaChart, DonutChart, BarChart } from '@/components/charts';
|
|
import { Wallet, TrendingUp, Briefcase, RefreshCw } from 'lucide-react';
|
|
|
|
// Sample data for sparklines
|
|
const totalAssetSparkline = [
|
|
{ value: 9500000 },
|
|
{ value: 9800000 },
|
|
{ value: 10000000 },
|
|
{ value: 9700000 },
|
|
{ value: 10200000 },
|
|
{ value: 10500000 },
|
|
{ value: 10800000 },
|
|
];
|
|
|
|
const returnSparkline = [
|
|
{ value: 2.5 },
|
|
{ value: 3.1 },
|
|
{ value: 2.8 },
|
|
{ value: 4.2 },
|
|
{ value: 5.1 },
|
|
{ value: 4.8 },
|
|
{ value: 5.5 },
|
|
];
|
|
|
|
// Sample data for asset trend chart
|
|
const assetTrendData = [
|
|
{ date: '2024-01', value: 10000000 },
|
|
{ date: '2024-02', value: 10500000 },
|
|
{ date: '2024-03', value: 10200000 },
|
|
{ date: '2024-04', value: 10800000 },
|
|
{ date: '2024-05', value: 11200000 },
|
|
{ date: '2024-06', value: 11000000 },
|
|
{ date: '2024-07', value: 11500000 },
|
|
{ date: '2024-08', value: 12000000 },
|
|
{ date: '2024-09', value: 11800000 },
|
|
{ date: '2024-10', value: 12500000 },
|
|
{ date: '2024-11', value: 13000000 },
|
|
{ date: '2024-12', value: 13500000 },
|
|
];
|
|
|
|
// Sample data for sector allocation
|
|
const sectorData = [
|
|
{ name: '기술', value: 40, color: '#3b82f6' },
|
|
{ name: '금융', value: 30, color: '#10b981' },
|
|
{ name: '헬스케어', value: 20, color: '#f59e0b' },
|
|
{ name: '기타', value: 10, color: '#6b7280' },
|
|
];
|
|
|
|
// Sample data for portfolio comparison
|
|
const portfolioComparisonData = [
|
|
{ name: '포트폴리오 A', value: 12.5 },
|
|
{ name: '포트폴리오 B', value: 8.3 },
|
|
{ name: '포트폴리오 C', value: -2.1 },
|
|
{ name: 'KOSPI', value: 5.7 },
|
|
{ name: 'S&P 500', value: 15.2 },
|
|
];
|
|
|
|
const summaryCards = [
|
|
{
|
|
title: '총 자산',
|
|
value: '₩135,000,000',
|
|
description: '전체 포트폴리오 가치',
|
|
icon: Wallet,
|
|
sparklineData: totalAssetSparkline,
|
|
sparklineColor: '#3b82f6',
|
|
},
|
|
{
|
|
title: '총 수익률',
|
|
value: '+35.0%',
|
|
description: '전체 수익률',
|
|
icon: TrendingUp,
|
|
sparklineData: returnSparkline,
|
|
sparklineColor: '#10b981',
|
|
},
|
|
{
|
|
title: '포트폴리오',
|
|
value: '3',
|
|
description: '활성 포트폴리오 수',
|
|
icon: Briefcase,
|
|
sparklineData: null,
|
|
sparklineColor: null,
|
|
},
|
|
{
|
|
title: '리밸런싱',
|
|
value: '2',
|
|
description: '예정된 리밸런싱',
|
|
icon: RefreshCw,
|
|
sparklineData: null,
|
|
sparklineColor: null,
|
|
},
|
|
];
|
|
|
|
const formatKRW = (value: number) => {
|
|
if (value >= 100000000) {
|
|
return `${(value / 100000000).toFixed(1)}억`;
|
|
}
|
|
if (value >= 10000) {
|
|
return `${(value / 10000).toFixed(0)}만`;
|
|
}
|
|
return value.toLocaleString();
|
|
};
|
|
|
|
const formatPercent = (value: number) => `${value.toFixed(1)}%`;
|
|
|
|
export default function DashboardPage() {
|
|
return (
|
|
<DashboardLayout>
|
|
<div className="space-y-6">
|
|
{/* Summary Cards */}
|
|
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
{summaryCards.map((card) => {
|
|
const Icon = card.icon;
|
|
return (
|
|
<Card key={card.title}>
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
<CardTitle className="text-sm font-medium">
|
|
{card.title}
|
|
</CardTitle>
|
|
<Icon className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="text-2xl font-bold">{card.value}</div>
|
|
<p className="text-xs text-muted-foreground">
|
|
{card.description}
|
|
</p>
|
|
{card.sparklineData && (
|
|
<Sparkline
|
|
data={card.sparklineData}
|
|
color={card.sparklineColor || '#3b82f6'}
|
|
height={32}
|
|
className="mt-2"
|
|
/>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* Main Charts */}
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>포트폴리오 성과</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<AreaChart
|
|
data={assetTrendData}
|
|
height={280}
|
|
color="#3b82f6"
|
|
formatValue={formatKRW}
|
|
showLegend={false}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>자산 배분</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<DonutChart
|
|
data={sectorData}
|
|
height={280}
|
|
innerRadius={50}
|
|
outerRadius={90}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
|
|
{/* Secondary Charts */}
|
|
<div className="grid gap-4 md:grid-cols-2">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>포트폴리오 비교</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<BarChart
|
|
data={portfolioComparisonData}
|
|
height={240}
|
|
layout="horizontal"
|
|
formatValue={formatPercent}
|
|
colorByValue={true}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>알림</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-3">
|
|
<div className="flex items-center gap-3 p-3 rounded-lg bg-muted/50">
|
|
<RefreshCw className="h-4 w-4 text-blue-500" />
|
|
<div className="flex-1">
|
|
<p className="text-sm font-medium">리밸런싱 예정</p>
|
|
<p className="text-xs text-muted-foreground">포트폴리오 A - 2일 후</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-3 p-3 rounded-lg bg-muted/50">
|
|
<TrendingUp className="h-4 w-4 text-green-500" />
|
|
<div className="flex-1">
|
|
<p className="text-sm font-medium">목표 수익률 달성</p>
|
|
<p className="text-xs text-muted-foreground">포트폴리오 B - 오늘</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-3 p-3 rounded-lg bg-muted/50">
|
|
<Briefcase className="h-4 w-4 text-amber-500" />
|
|
<div className="flex-1">
|
|
<p className="text-sm font-medium">배당금 입금</p>
|
|
<p className="text-xs text-muted-foreground">삼성전자 - 3일 후</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
</DashboardLayout>
|
|
);
|
|
}
|