--- app/(protected)/(basic)/_components/admin-shell.tsx
+++ app/(protected)/(basic)/_components/admin-shell.tsx
... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 |
'use client'; |
| 2 | 2 |
|
| 3 |
-import { useSidebar } from '@/app/(protected)/(basic)/_hooks/use-sidebar';
|
|
| 3 |
+import type { SidebarMenu } from '@/lib/domain/sidebar-menu';
|
|
| 4 | 4 |
import { AdminFooter } from './admin-footer';
|
| 5 | 5 |
import { AdminHeader } from './admin-header';
|
| 6 | 6 |
import { AdminSidebar } from './admin-sidebar';
|
... | ... | @@ -9,25 +9,25 @@ |
| 9 | 9 |
children: React.ReactNode; |
| 10 | 10 |
/** 헤더 프로필에 표시할 관리자 이름 — 세션을 읽는 상위 Server Component가 넘긴다. */ |
| 11 | 11 |
adminName: string; |
| 12 |
+ /** 계정 권한에 맞춰 서버가 구성한 사이드바 메뉴. */ |
|
| 13 |
+ menu: SidebarMenu; |
|
| 12 | 14 |
} |
| 13 | 15 |
|
| 14 | 16 |
/** |
| 15 |
- * Basic 레이아웃의 상호작용 경계 — 헤더·사이드바·풋터를 조립하고 사이드바 상태(useSidebar)를 |
|
| 16 |
- * 소유한다. page 콘텐츠(children)는 상위 Server Component가 렌더한 결과를 props로 그대로 |
|
| 17 |
- * 통과시켜 RSC를 유지한다 — 이 컴포넌트 자신은 children의 내용을 알거나 가공하지 않는다. |
|
| 17 |
+ * Basic 레이아웃의 상호작용 경계 — 헤더·사이드바·풋터를 조립한다. page 콘텐츠(children)는 |
|
| 18 |
+ * 상위 Server Component가 렌더한 결과를 props로 그대로 통과시켜 RSC를 유지한다 — 이 컴포넌트 |
|
| 19 |
+ * 자신은 children의 내용을 알거나 가공하지 않는다. |
|
| 20 |
+ * |
|
| 21 |
+ * 사이드바 열림/접힘 상태(useSidebar)는 더 이상 여기서 소유하지 않는다. 시안의 헤더·사이드바 |
|
| 22 |
+ * 어디에도 그 토글이 없어 헤더 구현 때 함께 걷어냈다 — 접힘 모양이 시안에 정의되면 그때 |
|
| 23 |
+ * 다시 붙인다. |
|
| 18 | 24 |
*/ |
| 19 |
-export function AdminShell({ children, adminName }: AdminShellProps) {
|
|
| 20 |
- const sidebar = useSidebar(); |
|
| 21 |
- |
|
| 25 |
+export function AdminShell({ children, adminName, menu }: AdminShellProps) {
|
|
| 22 | 26 |
return ( |
| 23 | 27 |
<div className="flex min-h-screen flex-col"> |
| 24 | 28 |
<AdminHeader adminName={adminName} />
|
| 25 | 29 |
<div className="flex flex-1"> |
| 26 |
- <AdminSidebar |
|
| 27 |
- isMobileOpen={sidebar.isMobileOpen}
|
|
| 28 |
- isDesktopCollapsed={sidebar.isDesktopCollapsed}
|
|
| 29 |
- onCloseMobile={sidebar.closeMobile}
|
|
| 30 |
- /> |
|
| 30 |
+ <AdminSidebar menu={menu} />
|
|
| 31 | 31 |
<div className="flex flex-1 flex-col"> |
| 32 | 32 |
<main className="flex flex-1 flex-col">{children}</main>
|
| 33 | 33 |
<AdminFooter /> |
--- app/(protected)/(basic)/layout.tsx
+++ app/(protected)/(basic)/layout.tsx
... | ... | @@ -1,21 +1,31 @@ |
| 1 | 1 |
import { getSessionAdmin } from '@/lib/auth/dal';
|
| 2 |
+import { fetchSidebarMenu } from '@/lib/data/repositories/sidebar-menu-repository';
|
|
| 3 |
+import type { SidebarMenu } from '@/lib/domain/sidebar-menu';
|
|
| 2 | 4 |
import { AdminShell } from './_components/admin-shell';
|
| 5 |
+ |
|
| 6 |
+const EMPTY_MENU: SidebarMenu = { favorites: [], sections: [] };
|
|
| 3 | 7 |
|
| 4 | 8 |
// Basic 레이아웃 — 헤더·사이드바·풋터가 있는 일반 관리자 화면 진입점. 보안 강제는 상위 |
| 5 | 9 |
// `(protected)/layout.tsx`가 담당하므로 여기서는 크롬 조립(AdminShell)만 책임진다. page |
| 6 | 10 |
// 콘텐츠는 Server Component로 렌더된 그대로 AdminShell의 children으로 통과한다. |
| 7 | 11 |
// |
| 8 |
-// 헤더 프로필에 쓸 이름만 세션에서 읽는다. **인증 판단은 하지 않는다** — 레이아웃은 Partial |
|
| 9 |
-// Rendering 때문에 인증 체크 지점으로 부적합하다는 상위 레이아웃의 판단을 그대로 따르므로, |
|
| 10 |
-// redirect하는 `verifySession()`이 아니라 null을 돌려주는 `getSessionAdmin()`을 쓴다. |
|
| 12 |
+// **사이드바 메뉴는 여기서 조회한다.** 계정 권한마다 항목이 달라 화면이 들고 있을 수 없는 |
|
| 13 |
+// 값이라, 세션의 권한으로 서버에서 구성해 내려보낸다 — 클라이언트가 나중에 불러오면 첫 |
|
| 14 |
+// 페인트에 메뉴가 비었다가 채워지고, 조회에 쓰는 토큰도 브라우저로 내려가야 한다. |
|
| 15 |
+// |
|
| 16 |
+// 세션이 없으면 빈 메뉴다. **인증 판단은 하지 않는다** — 레이아웃은 Partial Rendering 때문에 |
|
| 17 |
+// 인증 체크 지점으로 부적합하다는 상위 레이아웃의 판단을 그대로 따른다. |
|
| 11 | 18 |
export default async function Layout({
|
| 12 | 19 |
children, |
| 13 | 20 |
}: Readonly<{
|
| 14 | 21 |
children: React.ReactNode; |
| 15 | 22 |
}>) {
|
| 16 | 23 |
const admin = await getSessionAdmin(); |
| 24 |
+ const menu = admin ? await fetchSidebarMenu(admin.roleCode) : EMPTY_MENU; |
|
| 17 | 25 |
|
| 18 | 26 |
return ( |
| 19 |
- <AdminShell adminName={admin?.name ?? '관리자'}>{children}</AdminShell>
|
|
| 27 |
+ <AdminShell adminName={admin?.name ?? '관리자'} menu={menu}>
|
|
| 28 |
+ {children}
|
|
| 29 |
+ </AdminShell> |
|
| 20 | 30 |
); |
| 21 | 31 |
} |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?