Files
goldenChart/frontend/src/components/strategyEditor/ConditionNodeSettings.tsx
T
2026-05-25 01:34:52 +09:00

124 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useEffect, useRef } from 'react';
import type { ConditionDSL } from '../../utils/strategyTypes';
import type { DefType } from '../../utils/strategyEditorShared';
import {
getConditionRightPeriod,
getConditionThreshold,
getConditionValuePeriod,
getCompositePeriodPresetOptions,
getPeriodPresetOptions,
getThresholdBounds,
getThresholdPresetOptions,
hasEditableThreshold,
setConditionRightPeriod,
setConditionThreshold,
setConditionValuePeriod,
usesValuePeriodField,
} from '../../utils/conditionPeriods';
import { compositeDisplayName, compositeElementLabel } from '../../utils/compositeIndicators';
import ComboNumberInput from './ComboNumberInput';
interface Props {
condition: ConditionDSL;
def: DefType;
onChange: (c: ConditionDSL) => void;
onClose: () => void;
popoverClassName?: string;
}
export default function ConditionNodeSettings({
condition, def, onChange, onClose, popoverClassName = 'se-flow-settings-pop',
}: Props) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const onDoc = (e: MouseEvent) => {
if (ref.current && !ref.current.contains(e.target as Node)) onClose();
};
document.addEventListener('mousedown', onDoc);
return () => document.removeEventListener('mousedown', onDoc);
}, [onClose]);
const rightThreshold = getConditionThreshold(condition, 'right');
const showThreshold = hasEditableThreshold(condition) && rightThreshold != null;
const periodPresets = getPeriodPresetOptions(condition.indicatorType, def);
const thresholdPresets = getThresholdPresetOptions(condition.indicatorType);
const thresholdBounds = getThresholdBounds(condition.indicatorType);
return (
<div
ref={ref}
className={popoverClassName}
role="dialog"
aria-label="지표 설정"
onClick={e => e.stopPropagation()}
>
<div className="se-flow-settings-head">
<span>지표 설정</span>
<button
type="button"
className="se-flow-settings-close"
aria-label="닫기"
title="닫기"
onClick={onClose}
>
×
</button>
</div>
{condition.composite ? (
<>
<label className="se-flow-settings-field">
<span>{compositeElementLabel(condition.indicatorType, 1)} 기준값 (기간, )</span>
<ComboNumberInput
key={`composite-left-${condition.indicatorType}-${getConditionValuePeriod(condition, def)}`}
value={getConditionValuePeriod(condition, def)}
options={getCompositePeriodPresetOptions(condition.indicatorType, def, 'left')}
min={1}
max={500}
onChange={p => onChange(setConditionValuePeriod(condition, p, def))}
/>
</label>
<label className="se-flow-settings-field">
<span>{compositeElementLabel(condition.indicatorType, 2)} 기준값 (기간, )</span>
<ComboNumberInput
key={`composite-right-${condition.indicatorType}-${getConditionRightPeriod(condition, def)}`}
value={getConditionRightPeriod(condition, def)}
options={getCompositePeriodPresetOptions(condition.indicatorType, def, 'right')}
min={1}
max={500}
onChange={p => onChange(setConditionRightPeriod(condition, p))}
/>
</label>
</>
) : usesValuePeriodField(condition) ? (
<label className="se-flow-settings-field">
<span>{condition.indicatorType} 기간 ()</span>
<ComboNumberInput
value={getConditionValuePeriod(condition, def)}
options={periodPresets}
min={1}
max={500}
onChange={p => onChange(setConditionValuePeriod(condition, p, def))}
/>
</label>
) : null}
{showThreshold && rightThreshold != null && (
<label className="se-flow-settings-field">
<span>임계값</span>
<ComboNumberInput
value={rightThreshold}
options={thresholdPresets}
min={thresholdBounds.min}
max={thresholdBounds.max}
allowDecimal
onChange={v => onChange(setConditionThreshold(condition, 'right', v))}
/>
</label>
)}
{condition.composite && (
<p className="se-flow-settings-hint">{compositeDisplayName(condition.indicatorType)}</p>
)}
</div>
);
}