전략편집기 팝업 기능 적용
This commit is contained in:
@@ -191,6 +191,11 @@ function readRightPanelWidth(): number {
|
||||
interface Props {
|
||||
theme: Theme;
|
||||
onNavigateToBacktest?: () => void;
|
||||
/** 팝업(임베드) — 전략평가 등 */
|
||||
variant?: 'page' | 'modal';
|
||||
onClose?: () => void;
|
||||
initialStrategyId?: number | null;
|
||||
onStrategiesChanged?: () => void;
|
||||
}
|
||||
|
||||
function toEditorState(
|
||||
@@ -262,13 +267,25 @@ function isDuplicateStrategyName(
|
||||
return strategies.some(s => s.name.trim() === trimmed && s.id !== excludeId);
|
||||
}
|
||||
|
||||
export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Props) {
|
||||
export default function StrategyEditorPage({
|
||||
theme,
|
||||
onNavigateToBacktest,
|
||||
variant = 'page',
|
||||
onClose,
|
||||
initialStrategyId = null,
|
||||
onStrategiesChanged,
|
||||
}: Props) {
|
||||
const { getParams, getVisualConfig, settingsRevision, settingsLoaded } = useIndicatorSettings();
|
||||
const DEF = useMemo(
|
||||
() => buildStrategyEditorDefFromSettings(getParams, getVisualConfig),
|
||||
[getParams, getVisualConfig, settingsRevision],
|
||||
);
|
||||
const settingsSyncRef = useRef(-1);
|
||||
const initialStrategyAppliedRef = useRef(false);
|
||||
|
||||
const notifyStrategiesChanged = useCallback(() => {
|
||||
onStrategiesChanged?.();
|
||||
}, [onStrategiesChanged]);
|
||||
|
||||
const [strategies, setStrategies] = useState<StrategyDto[]>(() => loadStratsLocal());
|
||||
const [selectedId, setSelectedId] = useState<number | null>(null);
|
||||
@@ -953,6 +970,16 @@ export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Prop
|
||||
})();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (variant !== 'modal' || initialStrategyId == null || initialStrategyAppliedRef.current) return;
|
||||
if (strategies.length === 0) return;
|
||||
const found = strategies.find(s => s.id === initialStrategyId);
|
||||
if (!found) return;
|
||||
initialStrategyAppliedRef.current = true;
|
||||
handleSelectStrategy(found);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [variant, initialStrategyId, strategies]);
|
||||
|
||||
const handleNew = () => {
|
||||
setSelectedId(null);
|
||||
setStratName('');
|
||||
@@ -1045,6 +1072,7 @@ export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Prop
|
||||
} else {
|
||||
showSnack('전략이 저장되었습니다');
|
||||
}
|
||||
notifyStrategiesChanged();
|
||||
} catch (e) {
|
||||
showSnack(e instanceof Error ? e.message : '저장 실패', false);
|
||||
} finally {
|
||||
@@ -1061,6 +1089,7 @@ export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Prop
|
||||
setDeleteOpen(false);
|
||||
setDeleteId(null);
|
||||
showSnack('전략이 삭제되었습니다');
|
||||
notifyStrategiesChanged();
|
||||
};
|
||||
|
||||
const applyImportedFlowLayout = useCallback((layout: StrategyFlowLayoutStore | undefined, tab: 'buy' | 'sell' = signalTab) => {
|
||||
@@ -1617,7 +1646,7 @@ export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Prop
|
||||
selectedPaletteKey === paletteKey(type, id);
|
||||
|
||||
return (
|
||||
<div className={`se-page se-page--${theme}`}>
|
||||
<div className={`se-page se-page--${theme}${variant === 'modal' ? ' se-page--modal' : ''}`}>
|
||||
{needsPointerPaletteDrag() ? <PaletteDragOverlay /> : null}
|
||||
{saveToast && (
|
||||
<div className="se-save-toast">전략이 DB에 성공적으로 저장되었습니다.</div>
|
||||
@@ -1711,6 +1740,17 @@ export default function StrategyEditorPage({ theme, onNavigateToBacktest }: Prop
|
||||
</div>
|
||||
|
||||
<div className="se-header-actions">
|
||||
{variant === 'modal' && onClose && (
|
||||
<button
|
||||
type="button"
|
||||
className="se-btn se-btn--ghost se-btn--icon se-btn--modal-close"
|
||||
title="닫기"
|
||||
aria-label="전략 편집 닫기"
|
||||
onClick={onClose}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className="se-btn se-btn--ghost se-btn--icon se-btn--desc"
|
||||
|
||||
Reference in New Issue
Block a user