알림목록 수정
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* 매매 시그널 알림 — 차트 전체화면 모달
|
||||
* 알림 아이템에 이미 표시된 캔들+보조지표 차트를 전체 화면으로 확대 표시
|
||||
*/
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import type { Theme } from '../../types';
|
||||
import type { TradeNotificationItem } from '../../contexts/TradeNotificationContext';
|
||||
import type { StrategyDto } from '../../utils/backendApi';
|
||||
import { loadStrategy } from '../../utils/backendApi';
|
||||
import { buildStrategyChartIndicators, candleTypeToTimeframe } from '../../utils/strategyToChartIndicators';
|
||||
import { useIndicatorSettings } from '../../hooks/useIndicatorSettings';
|
||||
import { formatStrategyCandleLabel } from '../../utils/strategyStartNodes';
|
||||
import TradeSignalMiniChart from './TradeSignalMiniChart';
|
||||
import { TRADE_BUY_COLOR, TRADE_SELL_COLOR } from '../../utils/tradeSignalColors';
|
||||
import { formatSignalTime } from '../../utils/tradeSignalDisplay';
|
||||
import { formatUpbitKrwPrice } from '../../utils/safeFormat';
|
||||
|
||||
const MAX_INDICATOR_CARDS = 8;
|
||||
|
||||
interface Props {
|
||||
item: TradeNotificationItem;
|
||||
theme: Theme;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const FullscreenChartModal: React.FC<Props> = ({ item, theme, onClose }) => {
|
||||
const { getParams, getVisualConfig } = useIndicatorSettings();
|
||||
const [strategy, setStrategy] = useState<StrategyDto | null>(null);
|
||||
|
||||
/* 전략 로딩 */
|
||||
useEffect(() => {
|
||||
if (!item.strategyId) return;
|
||||
loadStrategy(item.strategyId)
|
||||
.then(s => setStrategy(s))
|
||||
.catch(() => {});
|
||||
}, [item.strategyId]);
|
||||
|
||||
/* 보조지표 config */
|
||||
const allIndicatorConfigs = useMemo(() => {
|
||||
if (!strategy) return [];
|
||||
const all = buildStrategyChartIndicators(strategy, getParams, getVisualConfig);
|
||||
return all.slice(0, MAX_INDICATOR_CARDS);
|
||||
}, [strategy, getParams, getVisualConfig]);
|
||||
|
||||
const timeframe = candleTypeToTimeframe(item.candleType ?? '1m');
|
||||
const isBuy = item.signalType === 'BUY';
|
||||
const accentColor = isBuy ? TRADE_BUY_COLOR : TRADE_SELL_COLOR;
|
||||
const sym = item.market.replace(/^KRW-/, '');
|
||||
const tfLabel = formatStrategyCandleLabel(item.candleType ?? '1m');
|
||||
|
||||
/* ESC 키로 닫기 */
|
||||
const handleKeyDown = useCallback((e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') onClose();
|
||||
}, [onClose]);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
return () => document.removeEventListener('keydown', handleKeyDown);
|
||||
}, [handleKeyDown]);
|
||||
|
||||
/* body 스크롤 막기 */
|
||||
useEffect(() => {
|
||||
const prev = document.body.style.overflow;
|
||||
document.body.style.overflow = 'hidden';
|
||||
return () => { document.body.style.overflow = prev; };
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="tnl-chart-fs-overlay"
|
||||
onClick={onClose}
|
||||
role="dialog"
|
||||
aria-modal
|
||||
aria-label="차트 전체화면"
|
||||
>
|
||||
<div
|
||||
className="tnl-chart-fs-inner"
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
{/* 헤더 */}
|
||||
<div className="tnl-chart-fs-header">
|
||||
<div className="tnl-chart-fs-title">
|
||||
<span
|
||||
className={`tnl-chart-fs-signal-badge${isBuy ? ' tnl-chart-fs-signal-badge--buy' : ' tnl-chart-fs-signal-badge--sell'}`}
|
||||
style={{ background: accentColor }}
|
||||
>
|
||||
{item.signalType}
|
||||
</span>
|
||||
<span className="tnl-chart-fs-market">{sym}</span>
|
||||
<span className="tnl-chart-fs-tf">{tfLabel}</span>
|
||||
<span className="tnl-chart-fs-price" style={{ color: accentColor }}>
|
||||
₩{formatUpbitKrwPrice(item.price)}
|
||||
</span>
|
||||
<span className="tnl-chart-fs-time">
|
||||
{formatSignalTime(item.candleTime)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="tnl-chart-fs-actions">
|
||||
{item.strategyName && (
|
||||
<span className="tnl-chart-fs-strategy">{item.strategyName}</span>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="tnl-chart-fs-close"
|
||||
onClick={onClose}
|
||||
aria-label="닫기 (ESC)"
|
||||
title="닫기 (ESC)"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 차트 바디 */}
|
||||
<div className="tnl-chart-fs-body">
|
||||
<TradeSignalMiniChart
|
||||
market={item.market}
|
||||
timeframe={timeframe}
|
||||
theme={theme}
|
||||
indicators={allIndicatorConfigs}
|
||||
enabled
|
||||
fillHeight
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FullscreenChartModal;
|
||||
Reference in New Issue
Block a user