전체적인 리팩토링
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { BarChart3, TrendingDown, TrendingUp } from "lucide-react";
|
||||
import { RefreshCcw } from "lucide-react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
@@ -22,6 +23,7 @@ interface MarketSummaryProps {
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
warning?: string | null;
|
||||
isWebSocketReady?: boolean;
|
||||
isRealtimePending?: boolean;
|
||||
onRetry?: () => void;
|
||||
}
|
||||
@@ -35,22 +37,46 @@ export function MarketSummary({
|
||||
isLoading,
|
||||
error,
|
||||
warning = null,
|
||||
isWebSocketReady = false,
|
||||
isRealtimePending = false,
|
||||
onRetry,
|
||||
}: MarketSummaryProps) {
|
||||
const realtimeBadgeText = isRealtimePending
|
||||
? "실시간 대기중"
|
||||
: isWebSocketReady
|
||||
? "실시간 수신중"
|
||||
: items.length > 0
|
||||
? "REST 데이터"
|
||||
: "데이터 준비중";
|
||||
|
||||
return (
|
||||
<Card className="overflow-hidden border-brand-200/80 bg-linear-to-br from-brand-50/50 to-background dark:border-brand-800/45 dark:from-brand-950/20 dark:to-background">
|
||||
<Card className="overflow-hidden border-brand-200/80 bg-linear-to-br from-brand-100/65 via-brand-50/30 to-background shadow-sm dark:border-brand-800/45 dark:from-brand-900/35 dark:via-brand-950/20 dark:to-background">
|
||||
<CardHeader className="pb-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="flex items-center gap-2 text-base text-brand-700 dark:text-brand-300">
|
||||
<BarChart3 className="h-4 w-4" />
|
||||
시장 지수
|
||||
</CardTitle>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={cn(
|
||||
"border-brand-300/70 bg-background/80 text-[11px] font-medium dark:border-brand-700/60 dark:bg-brand-950/30",
|
||||
isRealtimePending
|
||||
? "text-amber-700 dark:text-amber-300"
|
||||
: isWebSocketReady
|
||||
? "text-emerald-700 dark:text-emerald-300"
|
||||
: "text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{realtimeBadgeText}
|
||||
</Badge>
|
||||
</div>
|
||||
<CardDescription>실시간 코스피/코스닥 지수 현황입니다.</CardDescription>
|
||||
<CardDescription>
|
||||
코스피/코스닥 핵심 지수와 전일 대비 흐름을 빠르게 확인합니다.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="grid gap-3 sm:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2">
|
||||
<CardContent className="grid gap-3 sm:grid-cols-2">
|
||||
{/* ========== LOADING STATE ========== */}
|
||||
{isLoading && items.length === 0 && (
|
||||
<div className="col-span-full py-4 text-center text-sm text-muted-foreground animate-pulse">
|
||||
@@ -133,23 +159,23 @@ function IndexItem({ item }: { item: DashboardMarketIndexItem }) {
|
||||
: "text-muted-foreground";
|
||||
|
||||
const bgClass = isUp
|
||||
? "bg-red-50/50 dark:bg-red-950/10 border-red-100 dark:border-red-900/30"
|
||||
? "bg-linear-to-br from-red-50/90 to-background dark:from-red-950/20 dark:to-background border-red-100/80 dark:border-red-900/40"
|
||||
: isDown
|
||||
? "bg-blue-50/50 dark:bg-blue-950/10 border-blue-100 dark:border-blue-900/30"
|
||||
: "bg-muted/50 border-border/50";
|
||||
? "bg-linear-to-br from-blue-50/90 to-background dark:from-blue-950/20 dark:to-background border-blue-100/80 dark:border-blue-900/40"
|
||||
: "bg-linear-to-br from-muted/60 to-background border-border/50";
|
||||
|
||||
const flash = usePriceFlash(item.price, item.code);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"relative flex flex-col justify-between rounded-xl border p-4 transition-all hover:bg-background/80",
|
||||
"relative flex flex-col justify-between rounded-2xl border p-4 shadow-sm transition-all hover:-translate-y-0.5 hover:shadow-md",
|
||||
bgClass,
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm font-medium text-muted-foreground">
|
||||
{item.market}
|
||||
{item.name} ({item.market})
|
||||
</span>
|
||||
{isUp ? (
|
||||
<TrendingUp className="h-4 w-4 text-red-500/70" />
|
||||
@@ -158,7 +184,7 @@ function IndexItem({ item }: { item: DashboardMarketIndexItem }) {
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="mt-2 text-2xl font-bold tracking-tight relative w-fit">
|
||||
<div className="relative mt-2 w-fit text-2xl font-bold tracking-tight">
|
||||
{formatCurrency(item.price)}
|
||||
|
||||
{/* Flash Indicator */}
|
||||
@@ -176,14 +202,9 @@ function IndexItem({ item }: { item: DashboardMarketIndexItem }) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
"mt-1 flex items-center gap-2 text-sm font-medium",
|
||||
toneClass,
|
||||
)}
|
||||
>
|
||||
<div className={cn("mt-2 flex items-center gap-2 text-sm font-medium", toneClass)}>
|
||||
<span>{formatSignedCurrency(item.change)}</span>
|
||||
<span className="rounded-md bg-background/50 px-1.5 py-0.5 text-xs shadow-sm">
|
||||
<span className="rounded-md bg-background/70 px-1.5 py-0.5 text-xs shadow-sm">
|
||||
{formatSignedPercent(item.changeRate)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user