background
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. 통합된 사이드바 구조

plain
Before:
ServersLayout: [ProjectSidebar] [AdminLayout] [UserSidebar]
AdminLayout:                   [AdminSidebar] [Content]

After:
ServersLayout: [ProjectSidebar (통합)] [Content] [UserSidebar]
               ├── Projects (고정)
               ├── Channels/AdminMenu (조건부)
               └── UserInfo (고정)

2. 조건부 렌더링 흐름

typescript
pathname 감지
    ↓
isAdminPage = pathname.includes("/admin")
    ↓
┌─────────────────┬─────────────────┐
│  isAdminPage    │  !isAdminPage   │
│     truefalse       │
├─────────────────┼─────────────────┤
│ 관리자 메뉴      │ 채널 목록        │
│ - 가입 요청     │ - 공지 채널      │
│ - 멤버 관리     │ - 채팅 채널      │
│ - 역할 관리     │ - 음성 채널      │
│ - 초대 관리     │                 │
│ - 서버 설정     │                 │
└─────────────────┴─────────────────┘

3. 삭제된 파일들

plain
❌ Deleted:
frontend/src/app/(servers)/[server_id]/admin/components/AdminSidebar.tsx

✅ 통합된 위치:
frontend/src/app/(servers)/components/ProjectSidebar.tsx (관리자 메뉴 포함)

🎉 최종 결과

레이아웃 최적화 성과

개선 사항BeforeAfter
컴포넌트 수ProjectSidebar + AdminSidebarProjectSidebar (통합)
레이아웃 중복AdminLayout + ServersLayoutServersLayout만 사용
사이드바 여백큰 여백 존재여백 없음
조건부 렌더링없음경로 기반 동적 콘텐츠

기술적 성과

  • 코드 중복 제거: AdminSidebar를 ProjectSidebar에 통합
  • 조건부 렌더링: 경로 기반 동적 UI 변경
  • 레이아웃 단순화: 불필요한 AdminLayout 로직 제거
  • 일관된 UX: 하나의 사이드바에서 모든 기능 접근
  • 성능 최적화: 컴포넌트 렌더링 최소화

UI/UX 개선

  • 공간 효율성: 사이드바 간 여백 제거로 콘텐츠 영역 확대
  • 직관적 네비게이션: 경로에 따른 적절한 메뉴 표시
  • 시각적 일관성: 동일한 사이드바 스타일 유지
  • 반응형 디자인: 모든 화면 크기에서 일관된 레이아웃
  • 인터랙티브 요소: 호버 효과, 활성 상태 표시

관리자 페이지 구조 완성

plain
ProjectSidebar (통합 사이드바)
├── 프로젝트 목록 (고정)
│   ├── 프로젝트 아이콘들
│   └── 프로젝트 추가 버튼
│
├── 동적 콘텐츠 영역
│   ├── Admin 경로 (/admin/*):
│   │   ├── 👥 서버 가입 요청 (배지)
│   │   ├── 👤 사람과 사용자
│   │   ├── 🏷️ 역할
│   │   ├── 📨 초대
│   │   └── 🗑️ 서버 삭제
│   │
│   └── 일반 경로:
│       ├── 📢 공지 채널
│       ├── # 채팅 채널
│       └── 🔊 음성 채널
│
└── UserInfo (고정)
    ├── 사용자 프로필
    └── 온라인 상태

이제 하나의 통합된 사이드바에서 프로젝트 탐색과 서버 관리를 모두 효율적으로 수행할 수 있으며, 경로에 따라 적절한 메뉴가 자동으로 표시되는 직관적인 관리자 인터페이스가 완성되었다.

태그

#Next.js#aurora