aurora5분
관리자 페이지 레이아웃 통합
2025년 8월 30일
Aurora 프로젝트 - 관리자 페이지 UI 레이아웃 통합
기존 관리자 페이지의 복잡한 레이아웃 구조를 단순화하고, ProjectSidebar와 AdminSidebar를 통합하여 효율적인 관리자 인터페이스를 구축하고자 했다.
마주한 문제들
1. 중복된 사이드바 레이아웃 문제
기존 AdminLayout에서 ProjectSidebar와 AdminSidebar가 분리되어 불필요한 여백과 복잡한 레이아웃 구조를 만들었다.
typescript// 문제가 된 기존 구조
ServersLayout: [ProjectSidebar] [AdminLayout (전체 중간 영역)] [UserSidebar]
AdminLayout: [AdminSidebar] [메인 콘텐츠]
// 결과: ProjectSidebar와 AdminSidebar 사이에 큰 여백 발생
문제점들:
- ProjectSidebar와 AdminSidebar 사이의 불필요한 여백
- AdminLayout이
flex-1을 받아서 중간 공간을 모두 차지 - 레이아웃 컴포넌트 중복으로 인한 복잡성 증가
- 일관성 없는 UI 구조
2. 조건부 렌더링 부재
관리자 페이지에서도 채널 목록이 표시되고, 일반 페이지에서는 관리자 메뉴에 접근할 수 없는 구조적 문제가 있었다.
부족했던 기능들:
- 경로별 적절한 콘텐츠 표시
- 관리자/일반 사용자 구분 UI
- 동적 사이드바 콘텐츠 변경
해결책: 통합된 사이드바 시스템 구축
1. ProjectSidebar 조건부 렌더링 구현
typescript// frontend/src/app/(servers)/components/ProjectSidebar.tsx
import { usePathname } from "next/navigation";
import { useAdminSidebar } from "../hooks/useAdmin";
export const ProjectSidebar: React.FC<ProjectSidebarProps> = ({
serverId,
projectId,
channelId,
isProjectActive,
isProjectSelected,
}) => {
const pathname = usePathname();
// Admin 페이지인지 확인
const isAdminPage = pathname.includes("/admin");
const {
isLoading: adminLoading,
error: adminError,
pendingRequestsCount,
} = useAdminSidebar();
// Admin 메뉴 아이템들
const adminMenuItems = [
{
href: `/${serverId}/admin/join-requests`,
label: "서버 가입 요청",
icon: "👥",
badge: pendingRequestsCount > 0 ? pendingRequestsCount : undefined,
},
{
href: `/${serverId}/admin/members`,
label: "사람과 사용자",
icon: "👤",
},
{
href: `/${serverId}/admin/roles`,
label: "역할",
icon: "🏷️",
},
{
href: `/${serverId}/admin/invitations`,
label: "초대",
icon: "📨",
},
{
href: `/${serverId}/admin/settings`,
label: "서버 삭제",
icon: "🗑️",
},
];
// 현재 admin 링크가 활성화된 상태인지 확인
const isActiveAdminLink = (href: string) => {
return pathname === href;
};
2. 헤더 동적 변경 시스템
typescript// 프로젝트 헤더 - 경로에 따른 동적 변경
<h1 className="text-white font-semibold text-lg">
{isAdminPage
? `${serverInfo?.serverName || "서버"} 관리`
: currentProject?.projectName ||
serverInfo?.projectName ||
"프로젝트"}
</h1>
// 채널 추가 버튼 - admin 페이지에서는 숨김
{!isAdminPage && (
<button
onClick={handleAddChannel}
className="w-8 h-8 bg-gray-600 rounded-full flex items-center justify-center text-white hover:bg-gray-500 transition-colors"
>
+
</button>
)}
3. 조건부 콘텐츠 렌더링
typescript{/* 채널 목록 또는 관리자 메뉴 */}
<div className="px-4 py-3 flex-1 overflow-y-auto">
{isAdminPage ? (
/* 관리자 메뉴 */
adminLoading ? (
<div className="text-white text-center py-4">
로딩 중...
</div>
) : (
<div className="space-y-1">
{adminMenuItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={`flex items-center justify-between px-3 py-2 rounded-md text-sm transition-colors ${
isActiveAdminLink(item.href)
? "bg-blue-600 text-white"
: "text-gray-300 hover:bg-gray-700 hover:text-white"
}`}
>
<div className="flex items-center space-x-3">
<span>{item.icon}</span>
<span>{item.label}</span>
</div>
{item.badge && (
<span className="bg-red-500 text-white text-xs rounded-full px-2 py-1 min-w-[20px] text-center">
{item.badge}
</span>
)}
</Link>
))}
</div>
)
) : loadingChannels ? (
<div className="text-white text-center py-4">
채널 로딩 중...
</div>
) : (
/* 기존 채널 목록 렌더링 */
<>
{/* 공지 채널, 채팅 채널, 음성 채널 */}
</>
)}
</div>
4. AdminLayout 단순화
typescript// frontend/src/app/(servers)/[server_id]/admin/layout.tsx
"use client";
import React from "react";
export default function AdminLayout({
children,
}: {
children: React.ReactNode;
}) {
return <>{children}</>;
}
5. 조건부 표시 로직 수정
typescript// isProjectSelected 조건 확장
{/* 중앙: 채널 목록 (프로젝트 선택 시) 또는 관리자 메뉴 (admin 페이지) */}
{(isProjectSelected || isAdminPage) && (
<div className="w-72 bg-gray-700 flex flex-col rounded-tl-lg rounded-tr-lg overflow-hidden">
{/* 프로젝트 헤더 */}
{/* 채널 목록 또는 관리자 메뉴 */}
</div>
)}
컴포넌트 아키텍처 개선
1. 통합된 사이드바 구조
plainBefore: ServersLayout: [ProjectSidebar] [AdminLayout] [UserSidebar] AdminLayout: [AdminSidebar] [Content] After: ServersLayout: [ProjectSidebar (통합)] [Content] [UserSidebar] ├── Projects (고정) ├── Channels/AdminMenu (조건부) └── UserInfo (고정)
2. 조건부 렌더링 흐름
typescriptpathname 감지
↓
isAdminPage = pathname.includes("/admin")
↓
┌─────────────────┬─────────────────┐
│ isAdminPage │ !isAdminPage │
│ true │ false │
├─────────────────┼─────────────────┤
│ 관리자 메뉴 │ 채널 목록 │
│ - 가입 요청 │ - 공지 채널 │
│ - 멤버 관리 │ - 채팅 채널 │
│ - 역할 관리 │ - 음성 채널 │
│ - 초대 관리 │ │
│ - 서버 설정 │ │
└─────────────────┴─────────────────┘
3. 삭제된 파일들
plain❌ Deleted: frontend/src/app/(servers)/[server_id]/admin/components/AdminSidebar.tsx ✅ 통합된 위치: frontend/src/app/(servers)/components/ProjectSidebar.tsx (관리자 메뉴 포함)
🎉 최종 결과
레이아웃 최적화 성과
| 개선 사항 | Before | After |
|---|---|---|
| 컴포넌트 수 | ProjectSidebar + AdminSidebar | ProjectSidebar (통합) |
| 레이아웃 중복 | AdminLayout + ServersLayout | ServersLayout만 사용 |
| 사이드바 여백 | 큰 여백 존재 | 여백 없음 |
| 조건부 렌더링 | 없음 | 경로 기반 동적 콘텐츠 |
기술적 성과
- ✅ 코드 중복 제거: AdminSidebar를 ProjectSidebar에 통합
- ✅ 조건부 렌더링: 경로 기반 동적 UI 변경
- ✅ 레이아웃 단순화: 불필요한 AdminLayout 로직 제거
- ✅ 일관된 UX: 하나의 사이드바에서 모든 기능 접근
- ✅ 성능 최적화: 컴포넌트 렌더링 최소화
UI/UX 개선
- ✅ 공간 효율성: 사이드바 간 여백 제거로 콘텐츠 영역 확대
- ✅ 직관적 네비게이션: 경로에 따른 적절한 메뉴 표시
- ✅ 시각적 일관성: 동일한 사이드바 스타일 유지
- ✅ 반응형 디자인: 모든 화면 크기에서 일관된 레이아웃
- ✅ 인터랙티브 요소: 호버 효과, 활성 상태 표시
관리자 페이지 구조 완성
plainProjectSidebar (통합 사이드바) ├── 프로젝트 목록 (고정) │ ├── 프로젝트 아이콘들 │ └── 프로젝트 추가 버튼 │ ├── 동적 콘텐츠 영역 │ ├── Admin 경로 (/admin/*): │ │ ├── 👥 서버 가입 요청 (배지) │ │ ├── 👤 사람과 사용자 │ │ ├── 🏷️ 역할 │ │ ├── 📨 초대 │ │ └── 🗑️ 서버 삭제 │ │ │ └── 일반 경로: │ ├── 📢 공지 채널 │ ├── # 채팅 채널 │ └── 🔊 음성 채널 │ └── UserInfo (고정) ├── 사용자 프로필 └── 온라인 상태
이제 하나의 통합된 사이드바에서 프로젝트 탐색과 서버 관리를 모두 효율적으로 수행할 수 있으며, 경로에 따라 적절한 메뉴가 자동으로 표시되는 직관적인 관리자 인터페이스가 완성되었다.
태그
#Next.js#aurora
