전체적인 리팩토링

This commit is contained in:
2026-03-12 09:26:27 +09:00
parent 406af7408a
commit e51d767878
97 changed files with 13651 additions and 363 deletions

View File

@@ -10,6 +10,7 @@
*/
import { AlertCircle, Wallet2 } from "lucide-react";
import { RefreshCcw } from "lucide-react";
import { useRouter } from "next/navigation";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Button } from "@/components/ui/button";
import {
@@ -25,6 +26,7 @@ import {
formatPercent,
getChangeToneClass,
} from "@/features/dashboard/utils/dashboard-format";
import { useTradeNavigationStore } from "@/features/trade/store/use-trade-navigation-store";
import { cn } from "@/lib/utils";
import { usePriceFlash } from "@/features/dashboard/hooks/use-price-flash";
@@ -59,8 +61,22 @@ export function HoldingsList({
onRetry,
onSelect,
}: HoldingsListProps) {
const router = useRouter();
const setPendingTarget = useTradeNavigationStore(
(state) => state.setPendingTarget,
);
const handleNavigateToTrade = (holding: DashboardHoldingItem) => {
setPendingTarget({
symbol: holding.symbol,
name: holding.name,
market: holding.market,
});
router.push("/trade");
};
return (
<Card className="h-full">
<Card className="h-full border-brand-200/70 bg-background/90 shadow-sm dark:border-brand-800/45">
{/* ========== 카드 헤더: 타이틀 및 설명 ========== */}
<CardHeader className="pb-3">
<CardTitle className="flex items-center gap-2 text-base">
@@ -113,7 +129,7 @@ export function HoldingsList({
{/* 종목 리스트 렌더링 영역 */}
{holdings.length > 0 && (
<ScrollArea className="h-[420px] pr-3">
<ScrollArea className="h-[360px] pr-3">
<div className="space-y-2">
{holdings.map((holding) => (
<HoldingItemRow
@@ -121,6 +137,7 @@ export function HoldingsList({
holding={holding}
isSelected={selectedSymbol === holding.symbol}
onSelect={onSelect}
onNavigateToTrade={handleNavigateToTrade}
/>
))}
</div>
@@ -138,6 +155,8 @@ interface HoldingItemRowProps {
isSelected: boolean;
/** 클릭 핸들러 */
onSelect: (symbol: string) => void;
/** 거래 페이지 이동 핸들러 */
onNavigateToTrade: (holding: DashboardHoldingItem) => void;
}
/**
@@ -152,6 +171,7 @@ function HoldingItemRow({
holding,
isSelected,
onSelect,
onNavigateToTrade,
}: HoldingItemRowProps) {
// [State/Hook] 현재가 기반 가격 반짝임 효과 상태 관리
// @see use-price-flash.ts - 현재가 변경 감지 시 symbol을 기준으로 이펙트 발생 여부 결정
@@ -163,13 +183,16 @@ function HoldingItemRow({
return (
<button
type="button"
// [Step 1] 종목 클릭 시 부모의 선택 핸들러 호출
onClick={() => onSelect(holding.symbol)}
// [Step 1] 종목 클릭 시 선택 상태 갱신 후 거래 화면으로 이동
onClick={() => {
onSelect(holding.symbol);
onNavigateToTrade(holding);
}}
className={cn(
"w-full rounded-xl border px-3 py-3 text-left transition-all relative overflow-hidden",
"relative w-full overflow-hidden rounded-xl border px-3 py-3 text-left shadow-sm transition-all",
isSelected
? "border-brand-400 bg-brand-50/60 ring-1 ring-brand-300 dark:border-brand-600 dark:bg-brand-900/20 dark:ring-brand-700"
: "border-border/70 bg-background hover:border-brand-200 hover:bg-brand-50/30 dark:hover:border-brand-700 dark:hover:bg-brand-900/15",
: "border-border/70 bg-background hover:-translate-y-0.5 hover:border-brand-200 hover:bg-brand-50/30 hover:shadow-md dark:hover:border-brand-700 dark:hover:bg-brand-900/15",
)}
>
{/* ========== 행 상단: 종목명, 심볼 및 현재가 정보 ========== */}
@@ -180,7 +203,8 @@ function HoldingItemRow({
{holding.name}
</p>
<p className="text-xs text-muted-foreground">
{holding.symbol} · {holding.market} · {holding.quantity}
{holding.symbol} · {holding.market} · {holding.quantity} · {" "}
{holding.sellableQuantity}
</p>
</div>