주식 트레이딩 페이지 고도화

This commit is contained in:
2026-01-28 02:13:56 +09:00
parent 7d01c72e58
commit 8fc7c2cb70
4 changed files with 426 additions and 266 deletions

View File

@@ -30,7 +30,7 @@ const normalizeIndices = (data) => {
if (Array.isArray(data)) {
return data.map((item) => ({
name: item?.name ?? '-',
name: item?.name ?? item?.key ?? '-',
value: item?.value ?? '-',
change: item?.change_value ?? item?.change ?? '',
percent: item?.change_percent ?? item?.percent ?? '',
@@ -40,7 +40,7 @@ const normalizeIndices = (data) => {
if (Array.isArray(data?.indices)) {
return data.indices.map((item) => ({
name: item?.name ?? '-',
name: item?.name ?? item?.key ?? '-',
value: item?.value ?? '-',
change: item?.change_value ?? item?.change ?? '',
percent: item?.change_percent ?? item?.percent ?? '',
@@ -146,9 +146,10 @@ const Stock = () => {
'KOSPI',
'KOSDAQ',
'KOSPI200',
'USD/KRW',
'NASDAQ',
'다우산업',
'나스닥',
'S&P500',
'원달러 환율',
];
const sortedIndices = [...indices].sort((a, b) => {
const aIndex = indexOrder.indexOf(a.name);
@@ -158,7 +159,7 @@ const Stock = () => {
}
return a.name.localeCompare(b.name);
});
const highlighted = new Set(['KOSPI', 'KOSDAQ', 'USD/KRW']);
const highlighted = new Set(['KOSPI', 'KOSDAQ', '원달러 환율']);
const activeNews =
newsCategory === 'domestic' ? newsDomestic : newsOverseas;
@@ -185,97 +186,85 @@ const Stock = () => {
</div>
</div>
<div className="stock-card">
<p className="stock-card__title">뉴스 요약</p>
<div className="stock-status">
<div>
<span>최신 발행</span>
<strong>{formatDate(latestPublished)}</strong>
</div>
<div>
<span>국내</span>
<strong>{newsDomestic.length}</strong>
</div>
<div>
<span>해외</span>
<strong>{newsOverseas.length}</strong>
</div>
</div>
<p className="stock-card__title">다음 업데이트 아이디어</p>
<ul className="stock-ideas">
<li>관심 종목 실적 캘린더/일정 보기</li>
<li>뉴스 감성 요약 키워드 트렌드</li>
<li>보유 종목 알림(수익률/목표가)</li>
</ul>
</div>
</header>
<section className="stock-grid">
<div className="stock-panel">
<div className="stock-panel__head">
<div>
<p className="stock-panel__eyebrow">스냅샷</p>
<h3>주요 지수</h3>
<p className="stock-panel__sub">
주요 지수 값과 등락을 함께 확인합니다.
</p>
</div>
<div className="stock-panel__actions">
{indicesLoading ? (
<span className="stock-chip">불러오는 </span>
) : null}
<button
className="button ghost small"
onClick={loadIndices}
disabled={indicesLoading}
>
새로고침
</button>
</div>
<section className="stock-panel stock-panel--wide">
<div className="stock-panel__head">
<div>
<p className="stock-panel__eyebrow">스냅샷</p>
<h3>주요 지수</h3>
<p className="stock-panel__sub">
주요 지수 값과 등락을 함께 확인합니다.
</p>
</div>
<div className="stock-snapshot">
{indicesError ? (
<p className="stock-empty">{indicesError}</p>
) : sortedIndices.length === 0 ? (
<p className="stock-empty">
지수 데이터가 없습니다.
</p>
) : (
sortedIndices.map((item) => {
const direction = getDirection(
item.change,
item.percent,
item.direction
);
const changeText = [
item.change,
item.percent,
]
.filter(Boolean)
.join(' ');
return (
<div
key={item.name}
className={`stock-snapshot__card ${
highlighted.has(item.name)
? 'is-highlight'
: ''
}`}
>
<p>{item.name}</p>
<strong>{item.value ?? '--'}</strong>
<span
className={`stock-snapshot__change ${
direction === 'up'
? 'is-up'
: direction === 'down'
? 'is-down'
: ''
}`}
>
{changeText || '--'}
</span>
</div>
);
})
)}
<div className="stock-panel__actions">
{indicesLoading ? (
<span className="stock-chip">불러오는 </span>
) : null}
<button
className="button ghost small"
onClick={loadIndices}
disabled={indicesLoading}
>
새로고침
</button>
</div>
</div>
<div className="stock-snapshot">
{indicesError ? (
<p className="stock-empty">{indicesError}</p>
) : sortedIndices.length === 0 ? (
<p className="stock-empty">
지수 데이터가 없습니다.
</p>
) : (
sortedIndices.map((item) => {
const direction = getDirection(
item.change,
item.percent,
item.direction
);
const changeText = [item.change, item.percent]
.filter(Boolean)
.join(' ');
return (
<div
key={item.name}
className={`stock-snapshot__card ${
highlighted.has(item.name)
? 'is-highlight'
: ''
}`}
>
<p>{item.name}</p>
<strong>{item.value ?? '--'}</strong>
<span
className={`stock-snapshot__change ${
direction === 'up'
? 'is-up'
: direction === 'down'
? 'is-down'
: ''
}`}
>
{changeText || '--'}
</span>
</div>
);
})
)}
</div>
</section>
<div className="stock-panel">
<section className="stock-filter-row">
<div className="stock-panel stock-panel--compact">
<div className="stock-panel__head">
<div>
<p className="stock-panel__eyebrow">필터</p>
@@ -306,6 +295,31 @@ const Stock = () => {
</p>
</div>
</div>
<div className="stock-panel stock-panel--compact">
<div className="stock-panel__head">
<div>
<p className="stock-panel__eyebrow">요약</p>
<h3>뉴스 요약</h3>
<p className="stock-panel__sub">
최신 발행 시각과 기사 수를 확인합니다.
</p>
</div>
</div>
<div className="stock-status">
<div>
<span>최신 발행</span>
<strong>{formatDate(latestPublished)}</strong>
</div>
<div>
<span>국내</span>
<strong>{newsDomestic.length}</strong>
</div>
<div>
<span>해외</span>
<strong>{newsOverseas.length}</strong>
</div>
</div>
</div>
</section>
<section className="stock-panel stock-panel--wide">