/** * 보조지표 일괄 설정 — Main 16종 + 전체 보조지표, 검색 필터 */ import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react'; import { useDraggablePanel } from '../hooks/useDraggablePanel'; import type { IndicatorConfig } from '../types'; import type { PlotDef, HLineDef } from '../utils/indicatorRegistry'; import { buildAllIndicatorDraftMap, applyAllDraftToChart, allDraftListFromMap, indicatorTypesOnChart, type MainIndicatorDraftMap, } from '../utils/indicatorMainConfig'; import { resetConfigToDefaults } from '../utils/indicatorSettingsEditor'; import { getSettingsIndicatorTypes, filterSettingsIndicatorTypes, partitionFilteredTypes, } from '../utils/indicatorSettingsList'; import IndicatorSettingsListSearch from './IndicatorSettingsListSearch'; import IndicatorSettingsListRow from './IndicatorSettingsListRow'; import type { IchimokuCloudColors } from '../utils/ichimokuConfig'; import { MAIN_INDICATOR_TYPES } from '../utils/indicatorMainTab'; export interface IndicatorBulkSettingsModalProps { open: boolean; indicators: IndicatorConfig[]; chartMarket?: string; onApply: (result: { chartIndicators: IndicatorConfig[]; allConfigs: IndicatorConfig[]; }) => void; onLiveChartChange: (chartIndicators: IndicatorConfig[]) => void; onClose: () => void; getParams: (type: string, defaults: Record) => Record; getVisualConfig: ( type: string, defaultPlots?: PlotDef[], defaultHlines?: HLineDef[], ) => { plots: PlotDef[]; hlines: HLineDef[]; cloudColors?: IchimokuCloudColors }; } const ALL_TYPES = getSettingsIndicatorTypes(); const IndicatorBulkSettingsModal: React.FC = ({ open, indicators, chartMarket = '', onApply, onLiveChartChange, onClose, getParams, getVisualConfig, }) => { const [draftMap, setDraftMap] = useState({}); const [expandedTypes, setExpandedTypes] = useState>(new Set()); const [search, setSearch] = useState(''); const { panelRef: dialogRef, dragging, onHeaderPointerDown, headerTouchStyle, panelStyle, headerCursor, } = useDraggablePanel({ centerOnMount: true }); const onChartTypes = useMemo(() => indicatorTypesOnChart(indicators), [indicators]); const filtered = useMemo( () => filterSettingsIndicatorTypes(ALL_TYPES, search), [search], ); const { main: filteredMain, other: filteredOther } = useMemo( () => partitionFilteredTypes(filtered), [filtered], ); const prevOpenRef = useRef(false); useEffect(() => { if (open && !prevOpenRef.current) { setDraftMap(buildAllIndicatorDraftMap(indicators, getParams, getVisualConfig)); setExpandedTypes(new Set()); setSearch(''); } prevOpenRef.current = open; }, [open, indicators, getParams, getVisualConfig]); const setTypeEnabled = useCallback((type: string, enabled: boolean) => { const next = new Set(onChartTypes); if (enabled) next.add(type); else next.delete(type); onLiveChartChange(applyAllDraftToChart(indicators, draftMap, next)); }, [onChartTypes, indicators, draftMap, onLiveChartChange]); const updateType = useCallback((type: string, updated: IndicatorConfig) => { setDraftMap(prev => ({ ...prev, [type]: updated })); }, []); const toggleExpand = useCallback((type: string) => { setExpandedTypes(prev => { const next = new Set(prev); if (next.has(type)) next.delete(type); else next.add(type); return next; }); }, []); const handleResetAll = useCallback(() => { if (!window.confirm('목록에 있는 모든 보조지표 설정을 기본값으로 되돌릴까요?')) return; setDraftMap(prev => { const next = { ...prev }; for (const type of ALL_TYPES) { const cfg = next[type]; if (!cfg) continue; const reset = resetConfigToDefaults(cfg); const active = indicators.find(i => i.type === type); next[type] = { ...reset, id: onChartTypes.has(type) && active ? active.id : `template_${type}`, }; } return next; }); }, [indicators, onChartTypes]); const handleApply = useCallback(() => { const allConfigs = allDraftListFromMap(draftMap); const chartIndicators = applyAllDraftToChart(indicators, draftMap, onChartTypes); onApply({ chartIndicators, allConfigs }); onClose(); }, [draftMap, onChartTypes, indicators, onApply, onClose]); const renderRows = (types: string[]) => types.map(type => { const cfg = draftMap[type]; if (!cfg) return null; return ( toggleExpand(type)} onToggleEnabled={on => setTypeEnabled(type, on)} onChange={updated => updateType(type, updated)} /> ); }); if (!open) return null; return (
{ if (e.target === e.currentTarget) onClose(); }}>
e.stopPropagation()} style={{ ...panelStyle, zIndex: 5001, cursor: dragging ? 'grabbing' : undefined, }} >
📊 보조지표 설정

Main 탭 {MAIN_INDICATOR_TYPES.length}종을 상단에 두었습니다. 우측 스위치로 차트에 즉시 추가·제거하고, ▼에서 파라미터·색상을 편집할 수 있습니다. 적용 시 DB 기본값에 저장됩니다.

{filtered.length === 0 ? (
'{search}' 검색 결과 없음
) : ( <> {filteredMain.length > 0 && (

Main 보조지표 {filteredMain.length}

{renderRows(filteredMain)}
)} {filteredOther.length > 0 && (

기타 보조지표 {filteredOther.length}

{renderRows(filteredOther)}
)} )}
); }; export default IndicatorBulkSettingsModal;