대시보드 추가기능 + 계좌인증

This commit is contained in:
2026-02-12 17:16:41 +09:00
parent 434a814246
commit 12feeb2775
20 changed files with 1847 additions and 156 deletions

View File

@@ -14,6 +14,8 @@ interface StatusHeaderProps {
summary: DashboardBalanceSummary | null;
isKisRestConnected: boolean;
isWebSocketReady: boolean;
isProfileVerified: boolean;
verifiedAccountNo: string | null;
isRefreshing: boolean;
lastUpdatedAt: string | null;
onRefresh: () => void;
@@ -27,6 +29,8 @@ export function StatusHeader({
summary,
isKisRestConnected,
isWebSocketReady,
isProfileVerified,
verifiedAccountNo,
isRefreshing,
lastUpdatedAt,
onRefresh,
@@ -53,22 +57,31 @@ export function StatusHeader({
<p className="mt-1 text-xs text-muted-foreground">
{summary ? `${formatCurrency(summary.cashBalance)}` : "-"}
</p>
<p className="mt-1 text-xs text-muted-foreground">
{summary ? `${formatCurrency(summary.netAssetAmount)}` : "-"}
</p>
</div>
{/* ========== PROFIT/LOSS ========== */}
<div className="rounded-xl border border-border/70 bg-background/90 px-4 py-3">
<p className="text-xs font-medium text-muted-foreground"> </p>
<p className="text-xs font-medium text-muted-foreground"> </p>
<p className={cn("mt-1 text-xl font-semibold tracking-tight", toneClass)}>
{summary ? `${formatCurrency(summary.totalProfitLoss)}` : "-"}
</p>
<p className={cn("mt-1 text-xs font-medium", toneClass)}>
{summary ? formatPercent(summary.totalProfitRate) : "-"}
</p>
<p className="mt-1 text-xs text-muted-foreground">
{summary ? `${formatCurrency(summary.evaluationAmount)}` : "-"}
</p>
<p className="mt-1 text-xs text-muted-foreground">
{summary ? `${formatCurrency(summary.purchaseAmount)}` : "-"}
</p>
</div>
{/* ========== CONNECTION STATUS ========== */}
<div className="rounded-xl border border-border/70 bg-background/90 px-4 py-3">
<p className="text-xs font-medium text-muted-foreground"> </p>
<p className="text-xs font-medium text-muted-foreground"> </p>
<div className="mt-2 flex flex-wrap items-center gap-2 text-xs font-medium">
<span
className={cn(
@@ -79,7 +92,7 @@ export function StatusHeader({
)}
>
<Wifi className="h-3.5 w-3.5" />
REST {isKisRestConnected ? "연결됨" : "연결 끊김"}
{isKisRestConnected ? "연결됨" : "연결 끊김"}
</span>
<span
className={cn(
@@ -90,11 +103,28 @@ export function StatusHeader({
)}
>
<Activity className="h-3.5 w-3.5" />
WS {isWebSocketReady ? "준비됨" : "미연결"}
{isWebSocketReady ? "연결됨" : "미연결"}
</span>
<span
className={cn(
"inline-flex items-center gap-1 rounded-full px-2 py-1",
isProfileVerified
? "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400"
: "bg-amber-500/10 text-amber-700 dark:text-amber-400",
)}
>
<Activity className="h-3.5 w-3.5" />
{isProfileVerified ? "완료" : "미완료"}
</span>
</div>
<p className="mt-2 text-xs text-muted-foreground">
{updatedLabel}
{updatedLabel}
</p>
<p className="mt-1 text-xs text-muted-foreground">
{maskAccountNo(verifiedAccountNo)}
</p>
<p className="mt-1 text-xs text-muted-foreground">
{summary ? `${formatCurrency(summary.loanAmount)}` : "-"}
</p>
</div>
@@ -110,7 +140,7 @@ export function StatusHeader({
<RefreshCcw
className={cn("h-4 w-4", isRefreshing ? "animate-spin" : "")}
/>
</Button>
<Button
asChild
@@ -118,7 +148,7 @@ export function StatusHeader({
>
<Link href="/settings">
<Settings2 className="h-4 w-4" />
</Link>
</Button>
</div>
@@ -126,3 +156,16 @@ export function StatusHeader({
</Card>
);
}
/**
* @description 계좌번호를 마스킹해 표시합니다.
* @param value 계좌번호(8-2)
* @returns 마스킹 문자열
* @see features/dashboard/components/StatusHeader.tsx 시스템 상태 영역 계좌 표시
*/
function maskAccountNo(value: string | null) {
if (!value) return "-";
const digits = value.replace(/\D/g, "");
if (digits.length !== 10) return "********";
return "********-**";
}