Files
web-page/src/pages/stock/screener/Screener.jsx

130 lines
4.8 KiB
JavaScript

import React, { useState, lazy, Suspense } from 'react';
import { Link } from 'react-router-dom';
import './Screener.css';
import { useScreenerMeta } from './hooks/useScreenerMeta';
import { useScreenerSettings } from './hooks/useScreenerSettings';
import { useScreenerRun } from './hooks/useScreenerRun';
import { useScreenerHistory } from './hooks/useScreenerHistory';
import { useScreenerMode } from './hooks/useScreenerMode';
import { useIsMobile } from '../../../hooks/useIsMobile';
import GatePanel from './components/GatePanel';
import NodePanel from './components/NodePanel';
import GlobalControls from './components/GlobalControls';
import ResultTable from './components/ResultTable';
import TelegramPreview from './components/TelegramPreview';
import RunHistoryList from './components/RunHistoryList';
import ModeToggle from './components/ModeToggle';
const CanvasLayout = lazy(() => import('./components/canvas/CanvasLayout'));
export default function Screener() {
const { meta, loading: metaLoading } = useScreenerMeta();
const { settings, dirty, setLocal, save } = useScreenerSettings();
const { result, running, previewHistory, runPreview, runSave, selectPreview } = useScreenerRun();
const { runs, runs_loading, selectRun, selectedRun } = useScreenerHistory();
const { mode, setMode } = useScreenerMode();
const isMobile = useIsMobile();
const effectiveMode = isMobile ? 'form' : mode;
const [compareId, setCompareId] = useState(null);
const compareItem = previewHistory.find((p) => p.id === compareId);
const compareResult = compareItem?.result ?? null;
const activeResult = selectedRun || result;
if (metaLoading || !meta || !settings) {
return <div className="screener-loading">로딩 </div>;
}
return (
<div className="screener-page">
<header className="screener-header">
<div>
<h1>스크리너</h1>
<p className="meta">
최근 자동 : {runs?.find(r => r.mode === 'auto')?.asof ?? '-'}
· 분석 기준일: {activeResult?.asof ?? settings.asof ?? '-'}
</p>
</div>
<div className="screener-header-right">
{!isMobile && <ModeToggle value={mode} onChange={setMode} />}
<nav>
<Link to="/stock">시장</Link>
<Link to="/stock/trade">트레이드</Link>
</nav>
</div>
</header>
{effectiveMode === 'form' ? (
<div className="screener-grid">
<aside className="screener-left">
<GatePanel
meta={meta.gate_nodes[0]}
value={settings.gate_params}
onChange={(p) => setLocal({ ...settings, gate_params: p })}
/>
<NodePanel
meta={meta.score_nodes}
weights={settings.weights}
params={settings.node_params}
onWeights={(w) => setLocal({ ...settings, weights: w })}
onParams={(p) => setLocal({ ...settings, node_params: p })}
/>
<GlobalControls
settings={settings} setSettings={setLocal}
onRun={() => runPreview(settings)}
onSave={() => runSave(settings)}
onPersist={save}
dirty={dirty}
running={running}
/>
</aside>
<main className="screener-center">
<ResultTable
result={activeResult}
compareWith={compareResult}
compareLabel={compareItem ? new Date(compareItem.timestamp).toLocaleTimeString() : null}
/>
<TelegramPreview payload={activeResult?.telegram_payload} />
</main>
<aside className="screener-right">
<RunHistoryList
runs={runs}
loading={runs_loading}
onSelect={selectRun}
selectedId={selectedRun?.meta?.id}
previewHistory={previewHistory}
onSelectPreview={selectPreview}
onSetCompare={setCompareId}
compareId={compareId}
/>
</aside>
</div>
) : (
<Suspense fallback={<div className="screener-loading">캔버스 로딩 </div>}>
<CanvasLayout
meta={meta}
settings={settings}
setLocal={setLocal}
save={save}
dirty={dirty}
result={result}
running={running}
previewHistory={previewHistory}
runPreview={runPreview}
runSave={runSave}
selectPreview={selectPreview}
runs={runs}
runs_loading={runs_loading}
selectRun={selectRun}
selectedRun={selectedRun}
compareId={compareId}
setCompareId={setCompareId}
/>
</Suspense>
)}
</div>
);
}