Files
goldenChart/frontend/src/components/trendSearch/TrendSearchResultsCardGrid.tsx
T

109 lines
3.5 KiB
TypeScript

import React, { useMemo } from 'react';
import type { TrendSearchResultDto } from '../../utils/trendSearchApi';
import { sortTrendSearchByStrength } from '../../utils/trendSearchMetrics';
import type { Theme } from '../../types';
import type { ChartRealtimeSource } from '../../hooks/useChartRealtimeData';
import type { TickerData } from '../../hooks/useMarketTicker';
import TrendSearchResultCard, { type TrendSearchDisplayMode } from './TrendSearchResultCard';
interface Props {
results: TrendSearchResultDto[];
timeframe: string;
displayMode: TrendSearchDisplayMode;
loading?: boolean;
selectedMarket?: string | null;
onSelect?: (row: TrendSearchResultDto) => void;
flashMarkets?: Set<string>;
theme?: Theme;
chartRealtimeSource?: ChartRealtimeSource;
chartCandleAreaPriceLabels?: boolean;
chartSeriesPriceLabels?: boolean;
chartPaneSeparator?: import('../../types/chartPaneSeparator').ChartPaneSeparatorOptions;
tickers?: Map<string, TickerData>;
lastUpdatedAt?: number;
isInTargets?: (market: string) => boolean;
isPinned?: (market: string) => boolean;
onAddTarget?: (row: TrendSearchResultDto) => void;
onRemoveTarget?: (market: string) => void;
targetBusyMarket?: string | null;
}
const TrendSearchResultsCardGrid: React.FC<Props> = ({
results,
timeframe,
displayMode,
loading,
selectedMarket,
onSelect,
flashMarkets,
theme = 'dark',
chartRealtimeSource = 'BACKEND_STOMP',
chartCandleAreaPriceLabels = true,
chartSeriesPriceLabels = true,
chartPaneSeparator,
tickers,
lastUpdatedAt,
isInTargets,
isPinned,
onAddTarget,
onRemoveTarget,
targetBusyMarket = null,
}) => {
const sortedResults = useMemo(
() => sortTrendSearchByStrength(results),
[results],
);
if (loading && results.length === 0) {
return (
<div className="vtd-grid-wrap">
<div className="vtd-grid-empty">
<p className="vtd-muted">스캔 중…</p>
</div>
</div>
);
}
if (!loading && results.length === 0) {
return (
<div className="vtd-grid-wrap">
<div className="vtd-grid-empty">
<p className="vtd-muted">검색 결과가 없습니다. 조건·캔들 주기를 조정하거나 잠시 다시 시도해 보세요.</p>
</div>
</div>
);
}
return (
<div className="vtd-grid-wrap">
<div className={`vtd-grid${displayMode === 'chart' ? ' vtd-grid--chart-mode' : ''}`}>
{sortedResults.map(row => (
<TrendSearchResultCard
key={row.market}
result={row}
timeframe={timeframe}
displayMode={displayMode}
selected={selectedMarket === row.market}
onSelect={onSelect ? () => onSelect(row) : undefined}
theme={theme}
chartRealtimeSource={chartRealtimeSource}
chartCandleAreaPriceLabels={chartCandleAreaPriceLabels}
chartSeriesPriceLabels={chartSeriesPriceLabels}
chartPaneSeparator={chartPaneSeparator}
ticker={tickers?.get(row.market)}
updatedAt={lastUpdatedAt}
flash={flashMarkets?.has(row.market)}
inTargets={isInTargets?.(row.market) ?? false}
targetPinned={isPinned?.(row.market) ?? false}
targetBusy={targetBusyMarket === row.market}
onAddTarget={onAddTarget ? () => onAddTarget(row) : undefined}
onRemoveTarget={onRemoveTarget ? () => onRemoveTarget(row.market) : undefined}
/>
))}
</div>
</div>
);
};
export default TrendSearchResultsCardGrid;