'use client'; import { useMemo, useState } from 'react'; import { FoxListContainer, type FoxListColumn, } from '@fox/core/components/fox-list-container'; import { FoxStatusIndicator } from '@fox/core/components/fox-status-indicator'; import { buildMenuTree, collectNodeIds, flattenOpenNodes, formatActiveLabel, formatOptionalValue, type SystemMenu, type SystemMenuNode, } from '@/lib/domain/system-menu'; import { MenuFormModal } from './menu-form-modal'; import { MenuRowActions } from './menu-row-actions'; import styles from './menu-tree.module.scss'; interface MenuTreeListProps { items: SystemMenu[]; } type FormTarget = | { mode: 'edit'; node: SystemMenuNode } | { mode: 'create'; parent: SystemMenuNode }; /** 깊이만큼 이름을 밀어 넣는다. 표 칸이라 여백은 인라인으로 준다. */ const INDENT_REM = 2; export function MenuTreeList({ items }: MenuTreeListProps) { const tree = useMemo(() => buildMenuTree(items), [items]); const byId = useMemo(() => new Map(items.map((item) => [item.id, item])), [items]); const [closedIds, setClosedIds] = useState>(new Set()); const [target, setTarget] = useState(null); const isOpen = (id: string) => !closedIds.has(id); function toggle(id: string) { setClosedIds((prev) => { const next = new Set(prev); if (next.has(id)) { next.delete(id); } else { next.add(id); } return next; }); } const allBranchIds = useMemo(() => collectNodeIds(tree), [tree]); const isAllOpen = closedIds.size === 0; function toggleAll() { setClosedIds(isAllOpen ? new Set(allBranchIds) : new Set()); } const rows = flattenOpenNodes(tree, isOpen); const columns: FoxListColumn[] = [ { key: 'id', header: '번호', width: 100 }, { key: 'toggle', align: 'center', header: (