@@ -19,6 +19,7 @@ import { ChangePasswordView } from "./views/ChangePasswordView";
1919import { ForgotPasswordView } from "./views/ForgotPasswordView" ;
2020import { SetupWizardView } from "./views/SetupWizardView" ;
2121import { LedgerView } from "../../../modules/ledger/frontend/LedgerView" ;
22+ import { MODULE_SUB_NAV } from "./moduleConfig" ;
2223
2324// ─── Helpers ──────────────────────────────────────────────────
2425
@@ -27,14 +28,23 @@ const CORE_ROUTES = ["login", "forgot-password", "home", "marketplace", "admin",
2728// 모듈 라우트 — module.json name 기준 (서버 레지스트리와 일치)
2829const MODULE_ROUTES : string [ ] = [ "ledger" ] ;
2930
31+ /** 해시에서 베이스 라우트만 추출 ("ledger/import" → "ledger") */
3032function getRouteFromHash ( rawHash : string ) : RouteKey {
3133 const hash = rawHash . replace ( "#" , "" ) ;
32- if ( hash === "settings" ) return "home" ;
33- if ( ( CORE_ROUTES as readonly string [ ] ) . includes ( hash ) ) return hash as RouteKey ;
34- if ( MODULE_ROUTES . includes ( hash ) ) return hash as RouteKey ;
34+ const base = hash . split ( "/" ) [ 0 ] ?? hash ;
35+ if ( base === "settings" ) return "home" ;
36+ if ( ( CORE_ROUTES as readonly string [ ] ) . includes ( base ) ) return base as RouteKey ;
37+ if ( MODULE_ROUTES . includes ( base ) ) return base as RouteKey ;
3538 return "login" ;
3639}
3740
41+ /** 해시에서 서브 라우트만 추출 ("ledger/import" → "import", "ledger" → "") */
42+ function getSubRouteFromHash ( rawHash : string ) : string {
43+ const hash = rawHash . replace ( "#" , "" ) ;
44+ const parts = hash . split ( "/" ) ;
45+ return parts . length > 1 ? parts . slice ( 1 ) . join ( "/" ) : "" ;
46+ }
47+
3848// ─── Theme ────────────────────────────────────────────────────
3949type ThemeSetting = "light" | "dark" | "system" ;
4050
@@ -158,11 +168,14 @@ function App() {
158168 const [ isPinModalOpen , setIsPinModalOpen ] = useState ( false ) ;
159169 const [ notice , setNotice ] = useState ( "" ) ;
160170 const [ route , setRoute ] = useState < RouteKey > ( ( ) => getRouteFromHash ( window . location . hash ) ) ;
171+ const [ subRoute , setSubRoute ] = useState < string > ( ( ) => getSubRouteFromHash ( window . location . hash ) ) ;
161172
162173 useEffect ( ( ) => {
163174 const handleHashChange = ( ) => {
164175 const next = getRouteFromHash ( window . location . hash ) ;
176+ const nextSub = getSubRouteFromHash ( window . location . hash ) ;
165177 setRoute ( next ) ;
178+ setSubRoute ( nextSub ) ;
166179 // 비인증 상태에서 app route로 hash 변경 시 redirect 대상 갱신
167180 const appRoutes : RouteKey [ ] = [ "home" , "marketplace" , "admin" ] ;
168181 if ( sessionStorage . getItem ( SS . auth ) !== "true" && ( appRoutes as string [ ] ) . includes ( next ) ) {
@@ -463,6 +476,8 @@ function App() {
463476 ) }
464477 < AppShell
465478 route = { effectiveRoute }
479+ subRoute = { subRoute }
480+ moduleSubNav = { MODULE_SUB_NAV }
466481 isAdmin = { isAdmin }
467482 currentUser = { currentUser }
468483 notice = { notice }
@@ -487,7 +502,7 @@ function App() {
487502 />
488503 ) }
489504 { /* ── 모듈 뷰 ────────────────────────────────────── */ }
490- { effectiveRoute === "ledger" && < LedgerView /> }
505+ { effectiveRoute === "ledger" && < LedgerView subRoute = { subRoute } /> }
491506 { isSettingsOpen && (
492507 < SettingsView
493508 theme = { theme }
0 commit comments