goldenChat base source add
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* 설정 화면 — 보조지표 기본값 (Main 16종 상단 + 전체 지표, 검색 필터)
|
||||
*/
|
||||
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
||||
import type { IndicatorConfig } from '../types';
|
||||
import type { PlotDef, HLineDef } from '../utils/indicatorRegistry';
|
||||
import { buildMainIndicatorConfig } from '../utils/indicatorMainConfig';
|
||||
import { indicatorTypesOnChart } from '../utils/indicatorMainConfig';
|
||||
import IndicatorSettingsForm from './IndicatorSettingsForm';
|
||||
import { resetConfigToDefaults } from '../utils/indicatorSettingsEditor';
|
||||
import type { IchimokuCloudColors } from '../utils/ichimokuConfig';
|
||||
import {
|
||||
getSettingsIndicatorTypes,
|
||||
filterSettingsIndicatorTypes,
|
||||
partitionFilteredTypes,
|
||||
} from '../utils/indicatorSettingsList';
|
||||
import IndicatorSettingsListSearch from './IndicatorSettingsListSearch';
|
||||
import IndicatorSettingsListRow from './IndicatorSettingsListRow';
|
||||
import { MAIN_INDICATOR_TYPES } from '../utils/indicatorMainTab';
|
||||
|
||||
export interface IndicatorMainDefaultsPanelProps {
|
||||
chartIndicators: IndicatorConfig[];
|
||||
onAddToChart: (type: string, config?: IndicatorConfig) => void;
|
||||
onRemoveFromChart: (type: string) => void;
|
||||
getParams: (type: string, defaults: Record<string, number | string | boolean>) => Record<string, number | string | boolean>;
|
||||
saveParams: (type: string, params: Record<string, number | string | boolean>) => void;
|
||||
getVisualConfig: (
|
||||
type: string,
|
||||
defaultPlots?: PlotDef[],
|
||||
defaultHlines?: HLineDef[],
|
||||
) => { plots: PlotDef[]; hlines: HLineDef[]; cloudColors?: IchimokuCloudColors };
|
||||
saveVisual: (
|
||||
type: string,
|
||||
plots?: PlotDef[],
|
||||
hlines?: HLineDef[],
|
||||
cloudColors?: IchimokuCloudColors,
|
||||
) => void;
|
||||
}
|
||||
|
||||
function persistDefaults(
|
||||
updated: IndicatorConfig,
|
||||
saveParams: IndicatorMainDefaultsPanelProps['saveParams'],
|
||||
saveVisual: IndicatorMainDefaultsPanelProps['saveVisual'],
|
||||
) {
|
||||
saveParams(updated.type, updated.params);
|
||||
saveVisual(updated.type, updated.plots, updated.hlines, updated.cloudColors);
|
||||
}
|
||||
|
||||
const ALL_TYPES = getSettingsIndicatorTypes();
|
||||
|
||||
const IndicatorMainDefaultsPanel: React.FC<IndicatorMainDefaultsPanelProps> = ({
|
||||
chartIndicators,
|
||||
onAddToChart,
|
||||
onRemoveFromChart,
|
||||
getParams,
|
||||
saveParams,
|
||||
getVisualConfig,
|
||||
saveVisual,
|
||||
}) => {
|
||||
const onChartTypes = useMemo(() => indicatorTypesOnChart(chartIndicators), [chartIndicators]);
|
||||
const [expandedTypes, setExpandedTypes] = useState<Set<string>>(() => new Set());
|
||||
const [configs, setConfigs] = useState<Record<string, IndicatorConfig>>({});
|
||||
const [search, setSearch] = useState('');
|
||||
|
||||
const filtered = useMemo(
|
||||
() => filterSettingsIndicatorTypes(ALL_TYPES, search),
|
||||
[search],
|
||||
);
|
||||
const { main: filteredMain, other: filteredOther } = useMemo(
|
||||
() => partitionFilteredTypes(filtered),
|
||||
[filtered],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const next: Record<string, IndicatorConfig> = {};
|
||||
for (const type of ALL_TYPES) {
|
||||
const cfg = buildMainIndicatorConfig(type, chartIndicators, getParams, getVisualConfig);
|
||||
if (cfg) next[type] = cfg;
|
||||
}
|
||||
setConfigs(next);
|
||||
}, [chartIndicators, getParams, getVisualConfig]);
|
||||
|
||||
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 handleConfigChange = useCallback((type: string, updated: IndicatorConfig) => {
|
||||
setConfigs(prev => ({ ...prev, [type]: updated }));
|
||||
}, []);
|
||||
|
||||
const handleToggleChart = useCallback((type: string, enabled: boolean) => {
|
||||
if (enabled) {
|
||||
onAddToChart(type, configs[type]);
|
||||
} else {
|
||||
onRemoveFromChart(type);
|
||||
}
|
||||
}, [configs, onAddToChart, onRemoveFromChart]);
|
||||
|
||||
const handleRowDefaults = useCallback((type: string) => {
|
||||
const base = configs[type];
|
||||
if (!base) return;
|
||||
const reset = resetConfigToDefaults(base);
|
||||
persistDefaults(reset, saveParams, saveVisual);
|
||||
handleConfigChange(type, reset);
|
||||
}, [configs, saveParams, saveVisual, handleConfigChange]);
|
||||
|
||||
const handleResetAll = useCallback(() => {
|
||||
if (!window.confirm('목록에 있는 모든 보조지표 기본값을 초기화할까요?')) return;
|
||||
const next: Record<string, IndicatorConfig> = {};
|
||||
for (const type of ALL_TYPES) {
|
||||
const base = configs[type] ?? buildMainIndicatorConfig(type, [], getParams, getVisualConfig);
|
||||
if (!base) continue;
|
||||
const reset = resetConfigToDefaults(base);
|
||||
next[type] = reset;
|
||||
persistDefaults(reset, saveParams, saveVisual);
|
||||
}
|
||||
setConfigs(next);
|
||||
}, [configs, getParams, getVisualConfig, saveParams, saveVisual]);
|
||||
|
||||
const renderRows = (types: string[]) => types.map(type => {
|
||||
const cfg = configs[type];
|
||||
if (!cfg) return null;
|
||||
return (
|
||||
<IndicatorSettingsListRow
|
||||
key={type}
|
||||
type={type}
|
||||
config={cfg}
|
||||
enabled={onChartTypes.has(type)}
|
||||
expanded={expandedTypes.has(type)}
|
||||
variant="settings"
|
||||
onToggleExpand={() => toggleExpand(type)}
|
||||
onToggleEnabled={on => handleToggleChart(type, on)}
|
||||
onChange={updated => {
|
||||
persistDefaults(updated, saveParams, saveVisual);
|
||||
handleConfigChange(type, updated);
|
||||
}}
|
||||
onRowDefaults={() => handleRowDefaults(type)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="stg-ind-intro">
|
||||
<p>
|
||||
지표 추가 팝업 <strong>Main</strong> 탭 {MAIN_INDICATOR_TYPES.length}종을 상단에 두었고, 그 아래에 등록된 모든 보조지표가 있습니다.
|
||||
우측 스위치로 차트에 바로 추가·제거할 수 있으며, 파라미터·색상 변경은 DB 기본값에 자동 저장됩니다.
|
||||
</p>
|
||||
<button type="button" className="stg-ind-reset-all" onClick={handleResetAll}>
|
||||
전체 기본값 복원
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<IndicatorSettingsListSearch
|
||||
value={search}
|
||||
onChange={setSearch}
|
||||
totalCount={ALL_TYPES.length}
|
||||
filteredCount={filtered.length}
|
||||
className="stg-ind-search-block"
|
||||
/>
|
||||
|
||||
<div className="stg-ind-list">
|
||||
{filtered.length === 0 ? (
|
||||
<div className="no-results ind-settings-no-results">
|
||||
'{search}' 검색 결과 없음
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{filteredMain.length > 0 && (
|
||||
<section className="ind-settings-section">
|
||||
<h3 className="ind-settings-section-title">
|
||||
Main 보조지표 <span className="ind-settings-section-count">{filteredMain.length}</span>
|
||||
</h3>
|
||||
{renderRows(filteredMain)}
|
||||
</section>
|
||||
)}
|
||||
{filteredOther.length > 0 && (
|
||||
<section className="ind-settings-section">
|
||||
<h3 className="ind-settings-section-title">
|
||||
기타 보조지표 <span className="ind-settings-section-count">{filteredOther.length}</span>
|
||||
</h3>
|
||||
{renderRows(filteredOther)}
|
||||
</section>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default IndicatorMainDefaultsPanel;
|
||||
Reference in New Issue
Block a user