fix: Fix group section accordion not working
This commit is contained in:
@@ -11,7 +11,7 @@ import {
|
|||||||
getPresetDiff,
|
getPresetDiff,
|
||||||
} from '../utils/strategyPresets'
|
} from '../utils/strategyPresets'
|
||||||
|
|
||||||
// ── 타입 ──────────────────────────────────────
|
// ── 타입 ──────────────────────────────────────────────
|
||||||
|
|
||||||
interface StrategyConfig {
|
interface StrategyConfig {
|
||||||
id: number
|
id: number
|
||||||
@@ -28,7 +28,7 @@ interface StrategyConfig {
|
|||||||
updated_by: string | null
|
updated_by: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 그룹 한글 레이블 ────────────────────────────
|
// ── 그룹 한글 레이블 ────────────────────────────────────────
|
||||||
|
|
||||||
const GROUP_LABELS: Record<string, string> = {
|
const GROUP_LABELS: Record<string, string> = {
|
||||||
INDICATOR: '기술 지표',
|
INDICATOR: '기술 지표',
|
||||||
@@ -59,7 +59,7 @@ const CORE_PARAMS = [
|
|||||||
'DAY_TRADE_ENABLED',
|
'DAY_TRADE_ENABLED',
|
||||||
]
|
]
|
||||||
|
|
||||||
// ── 프리셋 카드 컴포넌트 ────────────────────────────
|
// ── 프리셋 카드 컴포넌트 ────────────────────────────────────────
|
||||||
|
|
||||||
interface PresetCardProps {
|
interface PresetCardProps {
|
||||||
presetKey: PresetKey
|
presetKey: PresetKey
|
||||||
@@ -113,7 +113,7 @@ function PresetCard({ presetKey, isSelected, onSelect }: PresetCardProps) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 개별 파라미터 행 컴포넌트 ────────────────────────
|
// ── 개별 파라미터 행 컴포넌트 ────────────────────────────────
|
||||||
|
|
||||||
interface ConfigRowProps {
|
interface ConfigRowProps {
|
||||||
cfg: StrategyConfig
|
cfg: StrategyConfig
|
||||||
@@ -233,7 +233,7 @@ function ConfigRow({ cfg, onSave, onToggle, onReset, isSaving }: ConfigRowProps)
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 그룹 섹션 컴포넌트 ──────────────────────────────
|
// ── 그룹 섹션 컴포넌트 ──────────────────────────────────────────────
|
||||||
|
|
||||||
interface GroupSectionProps {
|
interface GroupSectionProps {
|
||||||
groupKey: string
|
groupKey: string
|
||||||
@@ -242,19 +242,33 @@ interface GroupSectionProps {
|
|||||||
onToggle: (key: string) => void
|
onToggle: (key: string) => void
|
||||||
onReset: (key: string) => void
|
onReset: (key: string) => void
|
||||||
isSaving: boolean
|
isSaving: boolean
|
||||||
defaultExpanded?: boolean
|
isExpanded: boolean
|
||||||
|
onToggleExpand: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function GroupSection({ groupKey, configs, onSave, onToggle, onReset, isSaving, defaultExpanded = false }: GroupSectionProps) {
|
function GroupSection({
|
||||||
const [collapsed, setCollapsed] = useState(!defaultExpanded)
|
groupKey,
|
||||||
|
configs,
|
||||||
|
onSave,
|
||||||
|
onToggle,
|
||||||
|
onReset,
|
||||||
|
isSaving,
|
||||||
|
isExpanded,
|
||||||
|
onToggleExpand
|
||||||
|
}: GroupSectionProps) {
|
||||||
const modifiedCount = configs.filter(c => c.value !== c.default_value).length
|
const modifiedCount = configs.filter(c => c.value !== c.default_value).length
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* 그룹 헤더 */}
|
{/* 그룹 헤더 */}
|
||||||
<button
|
<button
|
||||||
onClick={() => setCollapsed(!collapsed)}
|
onClick={(e) => {
|
||||||
className="w-full flex items-center justify-between py-2 mb-3 group"
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
onToggleExpand()
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
className="w-full flex items-center justify-between py-2 mb-3 group hover:bg-slate-800/30 rounded px-2 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span>{GROUP_ICONS[groupKey] || '📁'}</span>
|
<span>{GROUP_ICONS[groupKey] || '📁'}</span>
|
||||||
@@ -268,14 +282,14 @@ function GroupSection({ groupKey, configs, onSave, onToggle, onReset, isSaving,
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{collapsed
|
{isExpanded
|
||||||
? <ChevronRight size={15} className="text-slate-500" />
|
? <ChevronDown size={15} className="text-slate-500 group-hover:text-slate-300 transition-colors" />
|
||||||
: <ChevronDown size={15} className="text-slate-500" />
|
: <ChevronRight size={15} className="text-slate-500 group-hover:text-slate-300 transition-colors" />
|
||||||
}
|
}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* 파라미터 카드 그리드 */}
|
{/* 파라미터 카드 그리드 */}
|
||||||
{!collapsed && (
|
{isExpanded && (
|
||||||
<div className="grid grid-cols-3 gap-2 mb-4">
|
<div className="grid grid-cols-3 gap-2 mb-4">
|
||||||
{configs.map((cfg) => (
|
{configs.map((cfg) => (
|
||||||
<ConfigRow
|
<ConfigRow
|
||||||
@@ -293,18 +307,31 @@ function GroupSection({ groupKey, configs, onSave, onToggle, onReset, isSaving,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 메인 페이지 ──────────────────────────────────────
|
// ── 메인 페이지 ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
const StrategySettings = () => {
|
const StrategySettings = () => {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const [notification, setNotification] = useState<{ type: 'success' | 'error'; msg: string } | null>(null)
|
const [notification, setNotification] = useState<{ type: 'success' | 'error'; msg: string } | null>(null)
|
||||||
const [showPresets, setShowPresets] = useState(true)
|
const [showPresets, setShowPresets] = useState(true)
|
||||||
|
const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set())
|
||||||
|
|
||||||
const showNotification = (type: 'success' | 'error', msg: string) => {
|
const showNotification = (type: 'success' | 'error', msg: string) => {
|
||||||
setNotification({ type, msg })
|
setNotification({ type, msg })
|
||||||
setTimeout(() => setNotification(null), 3000)
|
setTimeout(() => setNotification(null), 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleGroupExpand = (groupKey: string) => {
|
||||||
|
setExpandedGroups(prev => {
|
||||||
|
const next = new Set(prev)
|
||||||
|
if (next.has(groupKey)) {
|
||||||
|
next.delete(groupKey)
|
||||||
|
} else {
|
||||||
|
next.add(groupKey)
|
||||||
|
}
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 전략 파라미터 목록 조회
|
// 전략 파라미터 목록 조회
|
||||||
const { data: configs = [], isLoading, refetch } = useQuery<StrategyConfig[]>({
|
const { data: configs = [], isLoading, refetch } = useQuery<StrategyConfig[]>({
|
||||||
queryKey: ['strategy-config'],
|
queryKey: ['strategy-config'],
|
||||||
@@ -558,7 +585,8 @@ const StrategySettings = () => {
|
|||||||
onToggle={(key) => toggleMutation.mutate(key)}
|
onToggle={(key) => toggleMutation.mutate(key)}
|
||||||
onReset={(key) => resetOneMutation.mutate(key)}
|
onReset={(key) => resetOneMutation.mutate(key)}
|
||||||
isSaving={updateMutation.isPending}
|
isSaving={updateMutation.isPending}
|
||||||
defaultExpanded={false}
|
isExpanded={expandedGroups.has(groupKey)}
|
||||||
|
onToggleExpand={() => toggleGroupExpand(groupKey)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user