Files
sam-react-prod/src/stores/menuStore.ts
유병철 07374c826c refactor(WEB): claudedocs 재정리 및 AuthContext/Zustand/유틸 코드 개선
- claudedocs 폴더 구조 재정리: archive/sessions, guides/migration·mobile·universal-list, refactoring 분류
- 오래된 세션 컨텍스트/체크리스트 문서 정리 (아카이브 이동 또는 삭제)
- AuthContext → authStore(Zustand) 전환 시작, RootProvider 간소화
- GenericCRUDDialog 공통 다이얼로그 컴포넌트 추가
- PermissionDialog 삭제 → GenericCRUDDialog로 대체
- RankDialog/TitleDialog GenericCRUDDialog 기반으로 리팩토링
- toast-utils.ts 삭제 (미사용)
- fileDownload.ts 개선, excel-download.ts 정리
- menuStore/themeStore Zustand 셀렉터 최적화
- useColumnSettings/useTableColumnStore 기능 보강
- 세금계산서/견적/작업자화면/결재 등 소규모 개선

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 17:17:13 +09:00

84 lines
2.4 KiB
TypeScript

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { LucideIcon } from 'lucide-react';
// localStorage 저장용 (icon을 문자열로 저장)
export interface SerializableMenuItem {
id: string;
label: string;
iconName: string; // 문자열로 저장 (예: 'dashboard', 'folder')
path: string;
children?: SerializableMenuItem[];
}
// 실제 사용용 (icon을 컴포넌트로 사용)
export interface MenuItem {
id: string;
label: string;
icon: LucideIcon;
path: string;
component?: React.ComponentType;
children?: MenuItem[];
}
interface MenuState {
activeMenu: string;
menuItems: MenuItem[];
sidebarCollapsed: boolean;
_hasHydrated: boolean;
setActiveMenu: (menuId: string) => void;
setMenuItems: (items: MenuItem[]) => void;
toggleSidebar: () => void;
setSidebarCollapsed: (collapsed: boolean) => void;
setHasHydrated: (hydrated: boolean) => void;
}
export const useMenuStore = create<MenuState>()(
persist(
(set) => ({
activeMenu: 'dashboard',
menuItems: [],
sidebarCollapsed: false,
_hasHydrated: false,
setActiveMenu: (menuId: string) => set({ activeMenu: menuId }),
setMenuItems: (items: MenuItem[]) => set({ menuItems: items }),
toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),
setSidebarCollapsed: (collapsed: boolean) => set({ sidebarCollapsed: collapsed }),
setHasHydrated: (hydrated: boolean) => set({ _hasHydrated: hydrated }),
}),
{
name: 'sam-menu',
// menuItems는 함수(icon)를 포함하므로 localStorage에서 제외
partialize: (state) => ({
activeMenu: state.activeMenu,
sidebarCollapsed: state.sidebarCollapsed,
}),
onRehydrateStorage: () => (state) => {
state?.setHasHydrated(true);
},
}
)
);
// ===== 셀렉터 훅 =====
/** 사이드바 접힘 상태만 구독 */
export const useSidebarCollapsed = () =>
useMenuStore((state) => state.sidebarCollapsed);
/** 활성 메뉴 ID만 구독 */
export const useActiveMenu = () =>
useMenuStore((state) => state.activeMenu);
/** 메뉴 아이템 목록만 구독 */
export const useMenuItems = () =>
useMenuStore((state) => state.menuItems);
/** 하이드레이션 완료 여부만 구독 */
export const useMenuHydrated = () =>
useMenuStore((state) => state._hasHydrated);