Skip to content

Conversation

@YouD0313
Copy link
Collaborator

@YouD0313 YouD0313 commented May 28, 2025

구현내용

관리자 권한 판별 라우터, 사이드바 레이아웃

연관이슈

close #317

Summary by CodeRabbit

  • New Features

    • 관리자(Admin) 페이지를 위한 사이드바 및 라우팅 기능이 추가되었습니다.
    • 관리자 전용 라우트 보호 및 접근 제어 기능이 도입되었습니다.
    • 관리자용 메뉴 및 경로 상수가 새롭게 제공됩니다.
  • 개선 및 변경

    • 사용자 및 관리자 라우팅 구조가 통합되어 더욱 효율적으로 관리됩니다.
    • 로그아웃 시 인증 관련 상태와 로컬 스토리지가 보다 철저하게 정리됩니다.
    • 여러 컴포넌트에서 라우트 상수의 import 경로가 통일되어 경로 관련 오류 가능성이 줄어듭니다.

@YouD0313 YouD0313 requested a review from layout-SY May 28, 2025 15:06
@YouD0313 YouD0313 self-assigned this May 28, 2025
@YouD0313 YouD0313 linked an issue May 28, 2025 that may be closed by this pull request
2 tasks
@coderabbitai
Copy link

coderabbitai bot commented May 28, 2025

Caution

Review failed

The pull request is closed.

"""

Walkthrough

관리자 라우터 보호 기능과 사이드바 레이아웃이 새롭게 추가되었습니다. 기존의 라우팅 구조가 통합되고, 관리자 전용 라우트 보호 컴포넌트와 사이드바 관련 컴포넌트 및 상수들이 도입되었습니다. 또한, 여러 파일에서 ROUTES 상수의 import 경로가 통일되었습니다.

Changes

파일/경로 요약 변경 요약
src/routes/ProtectAdminRoute.tsx, src/routes/AdminRoutes.tsx, src/routes/MergeRoutes.tsx 관리자 보호 라우트, 관리자 라우트, 라우트 통합 컴포넌트 신규 추가
src/components/common/admin/sidebar/*, src/constants/admin/sidebar.ts 관리자 사이드바, 리스트, 스타일 컴포넌트 및 사이드바 상수 신규 추가
src/store/authStore.ts 인증 스토어에 redirectAdmin, replace 메서드 추가 및 logout 로직 개선
src/constants/routes.ts ADMIN_ROUTE 상수 신규 추가
src/routes/AppRoutes.tsx, src/App.tsx 라우팅 구조 변경 및 AppRoutes → MergeRoutes로 교체
src/components/common/header/Header.tsx, src/hooks/useAuth.ts 로그아웃 로직 개선 및 ROUTES import 경로 변경
src/constants/sidebarItems.tsx, src/constants/user/myPageFilter.ts, src/hooks/user/*, ... ROUTES import 경로를 constants/routes로 일괄 변경

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MergeRoutes
    participant ProtectAdminRoute
    participant AuthStore
    participant RouterProvider
    participant AdminSidebar

    User->>MergeRoutes: 앱 진입
    MergeRoutes->>AuthStore: isAdmin 확인
    alt 관리자
        MergeRoutes->>ProtectAdminRoute: 관리자 라우트 진입
        ProtectAdminRoute->>AuthStore: 로그인/관리자 여부 확인
        alt 인증/권한 있음
            ProtectAdminRoute->>AdminSidebar: 관리자 사이드바 렌더
        else 인증/권한 없음
            ProtectAdminRoute->>AuthStore: 로그아웃 및 상태 초기화
            ProtectAdminRoute->>RouterProvider: 메인 라우트로 이동
        end
    else 일반 사용자
        MergeRoutes->>RouterProvider: 일반 라우트 진입
    end
Loading

Assessment against linked issues

Objective (이슈 번호) Addressed Explanation
관리자 로그인 판별 라우터 (#317)
사이드바 레이아웃 (#317)

Possibly related PRs

Suggested labels

⛏기능, 🛠개선

Suggested reviewers

  • layout-SY

Poem

토끼가 뛰노는 관리자 땅,
사이드바가 반짝, 라우터가 빵!
권한을 지키는 문지기 등장,
경로는 하나로, 혼란은 없당!
로그인 판별도 이제는 완벽,
개발자 토끼는 오늘도 행복! 🐇✨
"""

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-05-29T10_28_06_955Z-debug-0.log


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47fe26c and 1a0039a.

📒 Files selected for processing (1)
  • src/components/common/admin/sidebar/AdminSidebar.tsx (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@YouD0313 YouD0313 marked this pull request as ready for review May 28, 2025 15:08
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (13)
src/constants/routes.ts (2)

34-44: ADMIN_ROUTE에 as const 타입 안전성 추가 제안
현재 ADMIN_ROUTEas const가 빠져 있어, 상수 객체의 값을 타입으로 고정하지 못하고 있습니다.
일관된 타입 안전성을 위해 export const ADMIN_ROUTE = { ... } as const; 형태로 변경을 권장드립니다.


34-44: 관리자용 라우트에 /admin 프리픽스 일관 적용 제안
지금은 ADMIN_ROUTE.admin + ADMIN_ROUTE.notice 형태로 조합해 사용해야 할 수 있어 실수 위험이 있습니다.
각 경로에 풀 패스로 /admin/notice, /admin/banner 등 프리픽스를 포함하거나,
devPals, notice, banner 등을 모두 /admin/*으로 변경해 주면 더 명확해집니다.

-export const ADMIN_ROUTE = {
+export const ADMIN_ROUTE = {
   admin: '/admin',
-  devPals: '/main',
+  devPals: '/admin/main',
   notice: '/notice',
   banner: '/banner',
   // ...
} as const;
src/constants/user/myPageFilter.ts (1)

9-22: 하드코딩된 linkUrl → ROUTES.projectDetail 상수 사용 제안
현재 linkUrl: '/project-detail'을 직접 입력하고 있는데, 중앙화된 ROUTES.projectDetail 상수를 사용하면 변경 시 유지보수가 더욱 용이해집니다.

-    linkUrl: `/project-detail`,
+    linkUrl: ROUTES.projectDetail,
src/pages/login/Login.tsx (1)

102-104: Link 컴포넌트 경로 상수 사용 제안
<Link to='/change-password'>, <Link to='/signup'> 등 리터럴 문자열 대신 ROUTES.changePw, ROUTES.signup 상수를 사용하면 유지보수가 더 쉬워집니다.

- <Link to='/change-password'>
+ <Link to={ROUTES.changePw}>
   <span>비밀번호 재설정</span>
- </Link>
+ </Link>
...
- <Link to='/signup'>
+ <Link to={ROUTES.signup}>
   <Button>회원가입</Button>
- </Link>
+ </Link>

Also applies to: 126-129

src/components/common/admin/sidebar/sidebarList/AdminSidebarList.styled.ts (2)

4-4: 빈 스타일 컴포넌트에 대한 검토가 필요합니다.

MovedListContainer가 빈 스타일로 정의되어 있습니다. 필요한 스타일이 누락되었거나 불필요한 컴포넌트일 수 있습니다.

만약 기본 nav 태그만 필요하다면 styled component 대신 일반 HTML 요소 사용을 고려해보세요:

-export const MovedListContainer = styled.nav``;
+// nav 태그를 직접 사용하거나 필요한 스타일을 추가하세요

30-30: 빈 래퍼 컴포넌트의 필요성을 검토해 주세요.

MovedListTitleWrapper 또한 빈 스타일로 정의되어 있습니다. 실제로 스타일링이 필요하지 않다면 컴포넌트를 제거하는 것을 고려해보세요.

src/components/common/admin/sidebar/AdminSidebar.tsx (1)

15-15: 빈 title을 전달하는 이유를 명확히 해주세요.

메인 사이드바 리스트에 빈 문자열('')이 title로 전달되고 있습니다. 이것이 의도된 동작인지 확인이 필요합니다.

더 명확한 의도 표현을 위해 다음과 같이 변경을 고려해보세요:

-<AdminSidebarList title='' list={SIDEBAR_LIST.main} />
+<AdminSidebarList title={null} list={SIDEBAR_LIST.main} />

또는 AdminSidebarList에서 title이 선택적 props가 되도록 수정할 수 있습니다.

src/routes/AdminRoutes.tsx (2)

11-28: 라우팅 구조를 개선할 수 있습니다.

현재 구현은 작동하지만, React Router의 모범 사례를 더 잘 따르도록 개선할 수 있습니다.

다음과 같은 개선을 고려해보세요:

-export const AdminRoutes = () => {
-  const routeList = [
-    {
-      path: ADMIN_ROUTE.admin,
-      element: (
-        <ProtectAdminRoute>
-          <Sidebar />
-        </ProtectAdminRoute>
-      ),
-    },
-  ];
-
-  const newAdminRoutes = routeList.map((items) => {
-    return { ...items, errorElement: <NotFoundPage /> };
-  });
-
-  return newAdminRoutes;
-};
+export const AdminRoutes = () => {
+  return [
+    {
+      path: ADMIN_ROUTE.admin,
+      element: (
+        <ProtectAdminRoute>
+          <Sidebar />
+        </ProtectAdminRoute>
+      ),
+      errorElement: <NotFoundPage />,
+    },
+  ];
+};

23-25: 에러 처리 로직의 효율성을 개선할 수 있습니다.

map 함수를 사용하여 errorElement를 추가하는 것보다 라우트 정의 시점에 직접 포함하는 것이 더 효율적입니다.

src/routes/AppRoutes.tsx (1)

386-398: 주석 처리된 코드를 제거하세요

이전 라우터 구현 코드가 주석으로 남아있습니다. 새로운 구조가 안정화되면 제거하는 것이 좋습니다.

- // const router = createBrowserRouter([
- //   {
- //     element: (
- //       <ToastProvider>
- //         <Outlet />
- //       </ToastProvider>
- //     ),
- //     children: [...newRouteList, { path: '*', element: <NotFoundPage /> }],
- //   },
- // ]);
src/components/common/admin/sidebar/sidebarList/AdminSidebarList.tsx (3)

1-1: 사용하지 않는 import를 제거하세요.

literal이 zod에서 import되었지만 코드에서 사용되지 않고 있습니다.

다음과 같이 수정하세요:

-import { literal } from 'zod';

49-49: target 속성 로직을 개선하세요.

현재 movedSite를 포함하는지 문자열 검사로 target을 결정하는데, 더 명시적이고 유지보수하기 쉬운 방법을 사용하는 것이 좋겠습니다.

다음과 같은 방법을 고려해보세요:

-          target={list.name.includes('movedSite') ? '_blank' : '_parent'}
+          target={item.name === 'movedSite' ? '_blank' : '_parent'}

또는 데이터 구조에 isExternal 속성을 추가하여 더 명확하게 관리할 수 있습니다.


52-52: 아이콘 접근성을 개선하세요.

아이콘에 적절한 aria-label이나 title 속성을 추가하여 접근성을 향상시키세요.

다음과 같이 수정할 수 있습니다:

-          <S.MovedListIcon>{iconMap[list.name]}</S.MovedListIcon>
+          <S.MovedListIcon aria-label={`${list.title} 아이콘`}>
+            {iconMap[list.name]}
+          </S.MovedListIcon>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a06231e and 482d1ec.

📒 Files selected for processing (47)
  • src/App.tsx (2 hunks)
  • src/components/common/admin/sidebar/AdminSidebar.styled.ts (1 hunks)
  • src/components/common/admin/sidebar/AdminSidebar.tsx (1 hunks)
  • src/components/common/admin/sidebar/sidebarList/AdminSidebarList.styled.ts (1 hunks)
  • src/components/common/admin/sidebar/sidebarList/AdminSidebarList.tsx (1 hunks)
  • src/components/common/header/Header.tsx (3 hunks)
  • src/components/common/header/Notification/Notification.tsx (1 hunks)
  • src/components/user/comment/commentComponent/commentComponent/CommentComponent.tsx (1 hunks)
  • src/components/user/comment/replyComponent/ReplyComponent.tsx (1 hunks)
  • src/components/user/customerService/MoveInquiredLink.tsx (1 hunks)
  • src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx (1 hunks)
  • src/components/user/customerService/noticeDetail/bottom/button/OtherNoticeButton.tsx (1 hunks)
  • src/components/user/home/projectCardLists/ProjectCardLists.tsx (1 hunks)
  • src/components/user/manageProjects/Card.tsx (1 hunks)
  • src/components/user/manageProjects/CardList.tsx (1 hunks)
  • src/components/user/mypage/ContentTab.tsx (1 hunks)
  • src/components/user/mypage/joinedProject/MyJoinProjects.tsx (1 hunks)
  • src/components/user/mypage/joinedProject/Project.tsx (1 hunks)
  • src/components/user/mypage/myProfile/MyProfile.tsx (1 hunks)
  • src/components/user/mypage/myProfile/editProfile/EditProfile.tsx (1 hunks)
  • src/components/user/mypage/myProfile/profile/Profile.tsx (1 hunks)
  • src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx (1 hunks)
  • src/components/user/userPage/userProjectList/UserProjectList.tsx (1 hunks)
  • src/constants/admin/sidebar.ts (1 hunks)
  • src/constants/routes.ts (1 hunks)
  • src/constants/sidebarItems.tsx (1 hunks)
  • src/constants/user/myPageFilter.ts (1 hunks)
  • src/hooks/useAuth.ts (2 hunks)
  • src/hooks/user/ProjectHooks/useApplyProject.ts (1 hunks)
  • src/hooks/user/ProjectHooks/useCreateProject.ts (1 hunks)
  • src/hooks/user/ProjectHooks/useUpdateProject.ts (1 hunks)
  • src/hooks/user/useMyInfo.ts (1 hunks)
  • src/pages/login/Login.tsx (1 hunks)
  • src/pages/login/LoginApi.tsx (1 hunks)
  • src/pages/login/LoginSuccess.tsx (1 hunks)
  • src/pages/user/changePassword/ChangePassword.tsx (1 hunks)
  • src/pages/user/customerService/notice/Notice.tsx (1 hunks)
  • src/pages/user/main/HeroSection.tsx (1 hunks)
  • src/pages/user/mypage/MyPage.tsx (1 hunks)
  • src/pages/user/projectDetail/ProjectDetail.tsx (1 hunks)
  • src/pages/user/register/Register.tsx (1 hunks)
  • src/pages/user/userpage/UserPage.tsx (1 hunks)
  • src/routes/AdminRoutes.tsx (1 hunks)
  • src/routes/AppRoutes.tsx (3 hunks)
  • src/routes/MergeRoutes.tsx (1 hunks)
  • src/routes/ProtectAdminRoute.tsx (1 hunks)
  • src/store/authStore.ts (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (8)
src/App.tsx (1)
src/routes/MergeRoutes.tsx (1)
  • MergeRoutes (9-33)
src/components/common/admin/sidebar/AdminSidebar.tsx (2)
src/components/common/admin/sidebar/sidebarList/AdminSidebarList.tsx (1)
  • AdminSidebarList (37-58)
src/constants/admin/sidebar.ts (1)
  • SIDEBAR_LIST (3-55)
src/hooks/useAuth.ts (1)
src/constants/user/modalMessage.ts (1)
  • MODAL_MESSAGE (1-30)
src/routes/AdminRoutes.tsx (2)
src/constants/routes.ts (1)
  • ADMIN_ROUTE (34-44)
src/routes/ProtectAdminRoute.tsx (1)
  • ProtectAdminRoute (13-58)
src/constants/admin/sidebar.ts (1)
src/constants/routes.ts (1)
  • ADMIN_ROUTE (34-44)
src/store/authStore.ts (1)
src/models/auth.ts (1)
  • UserData (18-23)
src/routes/MergeRoutes.tsx (4)
src/components/common/Toast/ToastProvider.tsx (1)
  • ToastProvider (6-31)
src/routes/ProtectAdminRoute.tsx (1)
  • ProtectAdminRoute (13-58)
src/routes/AdminRoutes.tsx (1)
  • AdminRoutes (11-28)
src/routes/AppRoutes.tsx (1)
  • AppRoutes (104-399)
src/routes/ProtectAdminRoute.tsx (3)
src/hooks/useModal.ts (1)
  • useModal (3-36)
src/constants/routes.ts (2)
  • ADMIN_ROUTE (34-44)
  • ROUTES (1-32)
src/constants/user/modalMessage.ts (1)
  • MODAL_MESSAGE (1-30)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: accessibility-test
🔇 Additional comments (57)
src/pages/login/LoginApi.tsx (1)

4-4: 라우트 상수 import 경로 중앙화 확인
import { ROUTES } from '../../constants/routes';로 모든 화면에서 동일한 ROUTES를 사용하도록 변경된 점이 적절합니다.

src/pages/login/LoginSuccess.tsx (1)

4-4: 라우트 상수 import 경로 중앙화 확인
import { ROUTES } from '../../constants/routes';로 변경되어 일관성이 확보되었습니다.

src/pages/login/Login.tsx (1)

15-15: 라우트 상수 import 경로 중앙화 확인
import { ROUTES } from '../../constants/routes';로 경로 상수를 통일한 변경이 잘 반영되었습니다.

src/pages/user/changePassword/ChangePassword.tsx (1)

12-12: 통합된 ROUTES 경로로 import 경로 업데이트 확인
user 관련 경로를 별도 모듈에서 가져오던 것을 ../../../constants/routes로 통합하여 유지보수성이 개선되었습니다.

src/components/user/manageProjects/Card.tsx (1)

5-5: 통합된 ROUTES 경로로 import 경로 업데이트 확인
route 상수를 중앙화된 constants/routes에서 가져오도록 변경해 일관성이 확보되었습니다.

src/components/user/manageProjects/CardList.tsx (1)

5-5: 통합된 ROUTES 경로로 import 경로 업데이트 확인
모든 사용자 프로젝트 관련 링크가 새로운 ROUTES 상수를 통해 올바르게 참조됩니다.

src/components/user/mypage/ContentTab.tsx (1)

4-4: 통합된 ROUTES 경로로 import 경로 업데이트 확인
탭 필터 링크 로직에서 사용되는 ROUTES 상수를 중앙화된 모듈 경로로 일원화했습니다.

src/pages/user/main/HeroSection.tsx (1)

5-5: 통합된 ROUTES 경로로 import 경로 업데이트 확인
HeroSection의 네비게이션 to 속성도 중앙화된 ROUTES 상수를 사용하여 일관성이 유지됩니다.

src/pages/user/customerService/notice/Notice.tsx (1)

8-8: 라우트 상수 임포트 경로 업데이트 확인
ROUTES 상수를 ../../../../constants/routes 경로에서 가져오도록 수정한 것이 프로젝트 전반 리팩토링 방향과 일치합니다.

src/constants/sidebarItems.tsx (1)

1-1: ROUTES 상수 중앙화된 모듈로 경로 통일
ROUTES./routes에서 가져오도록 변경하여 constants 디렉토리 내 중앙 모듈을 통해 일관된 라우트 참조가 가능해졌습니다.

src/components/user/mypage/myProfile/editProfile/EditProfile.tsx (1)

16-16:

✅ Verification successful

경로 상수 임포트 경로 정정 및 키 확인 요청
ROUTES../../../../../constants/routes에서 가져오는 수정이 올바릅니다. ROUTES.mypageconstants/routes.ts 내에 정의되어 있는지 아래 스크립트를 통해 확인 권장드립니다.


🏁 Script executed:

#!/bin/bash
# Ensure ROUTES.mypage key is defined
rg "mypage" src/constants/routes.ts

Length of output: 78


경로 상수 임포트 및 키 존재 여부 확인 완료

  • ROUTES../../../../../constants/routes에서 가져오는 경로 수정이 적절합니다.
  • src/constants/routes.ts에서 ROUTES.mypage가 정의된 것을 확인했습니다. 추가 변경은 필요하지 않습니다.
src/components/user/mypage/myProfile/profile/Profile.tsx (1)

9-9: 경로 상수 임포트 경로 수정 확인
ROUTES를 중앙화된 constants/routes에서 가져오도록 변경한 것이 의도한 리팩토링과 일치합니다.

src/components/user/comment/commentComponent/commentComponent/CommentComponent.tsx (1)

7-7: ROUTES 임포트 경로 일관화
ROUTES를 상위 5단계로 이동해 constants/routes에서 가져오도록 수정하여 프로젝트 전반 라우트 참조가 통일되었습니다.

src/components/user/customerService/noticeDetail/bottom/button/OtherNoticeButton.tsx (1)

1-1: ROUTES import 경로 중앙화 확인
constants/user/routes에서 constants/routes로 올바르게 갱신되어 경로 관리가 일관성 있게 중앙화되었습니다. 상대 경로도 정확합니다.

src/hooks/user/useMyInfo.ts (1)

15-15: useMyInfo 훅 내 ROUTES import 일관성 확보
../../constants/routes로 변경된 import가 navigate(ROUTES.mypage) 호출부와 잘 매칭되어 있으며, 불필요한 사용자 전용 경로 분기가 제거되어 깔끔합니다.

src/hooks/user/ProjectHooks/useApplyProject.ts (1)

7-7: useApplyProject 훅의 ROUTES 경로 갱신 확인
../../../constants/routes로 올바르게 수정되어 navigate(ROUTES.main) 호출이 의도대로 동작할 것입니다.

src/hooks/user/ProjectHooks/useCreateProject.ts (1)

6-6: useCreateProject 훅 ROUTES import 통일
../../../constants/routes로 변경된 import가 navigate(ROUTES.main) 경로 지정과 일치하며, 경로 구조가 간소화되었습니다.

src/pages/user/projectDetail/ProjectDetail.tsx (1)

11-11: ProjectDetail 컴포넌트 ROUTES 중앙화 반영
../../../constants/routes로 import 경로가 정확히 업데이트되어, navigate(${ROUTES.apply}/${id}) 및 기타 ROUTES 사용부가 문제없이 동작할 것으로 보입니다.

src/hooks/user/ProjectHooks/useUpdateProject.ts (1)

7-7: 경로 통합: ROUTES 상수 import 수정
경로 일관성을 위해 기존 ../../../constants/user/routes에서 ../../../constants/routes로 통합하였습니다. 기능적 변화는 없으며, 새로 추가된 관리자 라우트도 문제없이 참조할 수 있습니다.

src/components/user/customerService/MoveInquiredLink.tsx (1)

2-2: 경로 통합: ROUTES 상수 import 수정
공통 상수 파일(src/constants/routes)로 경로를 통합하여 유지보수성을 높였습니다. 기능에는 영향이 없습니다.

src/components/common/header/Notification/Notification.tsx (1)

8-8: 경로 통합: ROUTES 상수 import 수정
기존 유저 전용 경로에서 공통 경로(src/constants/routes)로 변경하여 코드 일관성을 확보했습니다. 로직 변화는 없습니다.

src/components/user/comment/replyComponent/ReplyComponent.tsx (1)

11-11: 경로 통합: ROUTES 상수 import 수정
라우트 상수를 중앙화된 파일(src/constants/routes)에서 가져오도록 수정하여 경로 관리가 통일되었습니다. 기능적 차이는 없습니다.

src/components/user/mypage/joinedProject/MyJoinProjects.tsx (1)

7-7: 경로 통합: ROUTES 상수 import 수정
모든 프로젝트 관련 컴포넌트가 같은 상수 파일(src/constants/routes)을 참조하도록 경로를 통일했습니다. 동작에는 영향이 없습니다.

src/components/user/mypage/notifications/appliedProjects/AppliedProjects.tsx (1)

7-7: 라우트 상수 중앙화 변경 승인

ROUTES 상수의 import 경로를 사용자별 경로에서 중앙화된 경로로 변경하는 것이 적절합니다. 이는 라우팅 구조 통합의 일환으로 코드 일관성을 향상시킵니다.

src/pages/user/userpage/UserPage.tsx (1)

5-5: 라우트 상수 import 경로 통일

다른 컴포넌트들과 일관되게 ROUTES 상수의 import 경로를 중앙화된 위치로 변경한 것이 좋습니다. 코드베이스 전반의 일관성을 유지합니다.

src/App.tsx (2)

7-7: 관리자 라우팅 통합을 위한 MergeRoutes 도입

AppRoutes를 MergeRoutes로 변경하여 관리자 권한 기반 라우팅을 구현하는 것이 적절합니다. 이는 PR 목표인 관리자 권한 판별 라우터 구현에 핵심적인 변경사항입니다.


25-25: 관리자/사용자 라우트 조건부 렌더링 적용

MergeRoutes 컴포넌트 사용으로 사용자의 관리자 상태에 따른 조건부 라우팅이 적용됩니다. 관리자 권한 검증과 적절한 라우트 보호가 구현됩니다.

src/pages/user/register/Register.tsx (1)

18-18: 회원가입 페이지의 라우트 상수 중앙화

Register 컴포넌트에서도 ROUTES 상수의 import 경로를 중앙화된 위치로 일관되게 변경하였습니다. 전체 코드베이스의 라우팅 구조 통합이 완료되었습니다.

src/components/user/customerService/noticeDetail/bottom/button/ListButton.tsx (1)

1-1: 라우트 상수 통합 변경사항 승인

ROUTES 상수의 import 경로를 통합된 위치로 변경한 것이 일관성 있고 적절합니다.

src/constants/admin/sidebar.ts (1)

3-55: 사이드바 구성 구조 승인

관리자 인터페이스의 사이드바 메뉴 구조가 잘 정리되어 있으며, as const를 사용하여 타입 안정성도 확보되었습니다.

src/components/common/header/Header.tsx (3)

20-20: 라우트 상수 통합 변경사항 승인

ROUTES 상수의 import 경로를 통합된 위치로 변경한 것이 일관성 있고 적절합니다.


29-34: 개선된 로그아웃 로직 승인

로그아웃 시 사용자 상태, 인증 스토리지, 로컬스토리지를 모두 정리하는 포괄적인 로그아웃 처리가 구현되어 보안성과 안정성이 향상되었습니다.


109-109: 로그아웃 핸들러 사용 승인

새로 구현된 handleClickLogout 함수를 사용하여 일관성 있는 로그아웃 처리가 적용되었습니다.

src/components/common/admin/sidebar/AdminSidebar.styled.ts (1)

3-20: 사이드바 스타일 구성 승인

관리자 사이드바의 레이아웃과 스타일링이 적절하게 구성되어 있습니다. 고정 너비(15rem)와 적절한 간격 설정, 그리드 레이아웃 사용이 사용자 경험을 고려한 좋은 설계입니다.

src/hooks/useAuth.ts (3)

10-10: 라우트 상수 import 경로 통합을 확인했습니다.

라우트 상수의 import 경로가 중앙화된 구조로 변경된 것을 확인했습니다. 이는 코드베이스 전반에 걸친 일관된 리팩토링으로 보입니다.


100-101: 로그아웃 순서 변경이 의도적인지 확인해 주세요.

로그아웃 플로우에서 logout() 호출이 모달 오픈 이후로 이동했습니다. 이로 인해 사용자 경험이나 상태 관리에 영향이 있는지 검토가 필요합니다.


99-99:

❌ Incorrect review comment

주석 처리된 스토리지 클리어 코드를 확인해 주세요.

useAuthStore.persist.clearStorage(); 코드가 주석 처리되어 있습니다. 이는 로그아웃 시 인증 상태가 완전히 클리어되지 않을 수 있습니다.

다음 스크립트를 실행하여 authStore의 logout 메서드에서 persist storage 클리어가 처리되고 있는지 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# authStore에서 logout 메서드 구현을 확인
ast-grep --pattern $'logout() {
  $$$
}'

Length of output: 41


아래 스크립트를 실행하여 useAuthStore 정의 위치, persist 설정, logout 메서드 및 clearStorage 호출 여부를 한 번에 확인해 주세요.


🏁 Script executed:

#!/bin/bash
# 1) useAuthStore 정의 파일 찾기
FILE=$(rg -l "const useAuthStore")

# 2) 해당 파일에서 persist 설정 확인
rg -n "persist" -n "$FILE"

# 3) logout 메서드 구현 위치 확인
rg -n "logout" -n "$FILE"

# 4) clearStorage 호출 여부 확인
rg -n "clearStorage" -n "$FILE"

Length of output: 427


주석 처리된 useAuthStore.persist.clearStorage() 호출은 불필요합니다.

src/store/authStore.tslogout 메서드(48행)에서 이미

useAuthStore.persist.clearStorage();

를 호출하고 있어, 훅(src/hooks/useAuth.ts)에서 주석 처리된 코드를 복원할 필요가 없습니다.

  • src/store/authStore.ts
    • 48행: logout: () => { … }
    • 55행: useAuthStore.persist.clearStorage(); 호출 확인

Likely an incorrect or invalid review comment.

src/components/common/admin/sidebar/sidebarList/AdminSidebarList.styled.ts (1)

6-15: 링크 스타일링이 잘 구현되었습니다.

hover 효과와 flexbox를 사용한 정렬이 적절하게 구현되어 있습니다.

src/components/common/admin/sidebar/AdminSidebar.tsx (2)

1-6: import 구조가 잘 정리되어 있습니다.

상수, 스타일, 에셋, 컴포넌트들이 적절한 순서로 import되어 있습니다.


7-21: 사이드바 컴포넌트 구조가 잘 설계되었습니다.

로고, 구분선, 그리고 세 개의 사이드바 리스트(메인, 서비스 관리, 사용자 관리)로 구성된 구조가 명확하고 직관적입니다.

src/routes/AdminRoutes.tsx (2)

7-9: Lazy loading 구현이 적절합니다.

Admin 사이드바 컴포넌트의 lazy loading이 올바르게 구현되어 성능 최적화에 도움이 됩니다.


16-18: ProtectAdminRoute로 보안이 잘 구현되었습니다.

관리자 라우트가 적절한 보안 래퍼로 보호되고 있어 권한 없는 접근을 방지할 수 있습니다.

src/routes/MergeRoutes.tsx (2)

1-7: 임포트 구성이 적절합니다

필요한 모든 의존성이 올바르게 임포트되어 있고, 라우팅 통합에 필요한 컴포넌트들이 포함되어 있습니다.


9-10: 관리자 상태 확인 로직이 안전합니다

nullable 값에 대한 적절한 fallback 처리가 되어 있습니다.

src/routes/AppRoutes.tsx (2)

14-14: 라우트 상수 경로 통일이 적절합니다

../constants/routes로 통일하여 일관성을 개선했습니다.


104-104: 함수 시그니처 변경이 적절합니다

named export로 변경하여 새로운 라우팅 구조에 맞게 조정했습니다.

src/routes/ProtectAdminRoute.tsx (1)

1-11: 임포트와 인터페이스 정의가 적절합니다

필요한 의존성들이 올바르게 임포트되고 props 인터페이스가 명확히 정의되어 있습니다.

src/store/authStore.ts (3)

7-7: 인터페이스 확장이 적절합니다

관리자 라우팅을 위한 redirectAdmin 필드와 replace 메서드가 명확하게 정의되어 있습니다.

Also applies to: 13-13


31-31: 새로운 상태와 메서드 구현이 올바릅니다

초기 상태 설정과 replace 메서드 구현이 의도한 대로 작동할 것으로 보입니다.

Also applies to: 36-40


48-56:

✅ Verification successful

logout 구현 변경에 대한 검증이 필요합니다

clearStorage() 사용으로 변경하는 것은 더 철저한 정리를 제공하지만, 다른 persisted 데이터에 영향을 줄 수 있습니다.

다음 스크립트로 다른 persist 스토어들이 영향받는지 확인하세요:

주석 처리된 코드도 제거를 고려해보세요:

- // set({
- //   redirectAdmin: false,
- //   isLoggedIn: false,
- //   accessToken: null,
- //   userData: null,
- // });

🏁 Script executed:

#!/bin/bash
# persist를 사용하는 다른 zustand 스토어들 확인
rg -A 5 -B 5 "persist.*create" --type ts --type tsx

# clearStorage 호출이 다른 곳에서도 사용되는지 확인  
rg "clearStorage|persist\.clear" --type ts --type tsx

Length of output: 165


다른 zustand persist 스토어와 clearStorage 호출 여부를 정확히 파악하기 위해 아래 스크립트를 실행해 주세요:


🏁 Script executed:

#!/bin/bash
# TS/TSX 파일에서 persist 미들웨어 사용 확인  
rg -A5 -B5 'persist(' --glob '*.ts' --glob '*.tsx'

# clearStorage 호출 확인  
rg -A5 -B5 'clearStorage' --glob '*.ts' --glob '*.tsx'

Length of output: 2480


아래 스크립트로 persist 미들웨어 사용 위치와 clearStorage 호출을 다시 확인해 주세요:


🏁 Script executed:

#!/bin/bash
# 1) persist 미들웨어 사용 위치 검색 (fixed-string)
rg -F 'persist(' -n --glob '*.ts' --glob '*.tsx'

# 2) .persist.clearStorage 호출 위치 검색
rg -F 'persist.clearStorage' -n --glob '*.ts' --glob '*.tsx'

# 3) AST 패턴으로 persist(create, options) 구조 확인
ast-grep --pattern $'persist($_, $_)'

Length of output: 441


logout 구현 검증 완료: clearStorage()는 auth-store 키만 삭제하며 다른 스토어엔 영향 없습니다

Zustand persist.clearStorage()는 옵션으로 지정한 name(여기선 auth-storage)에 대응하는 키만 제거하므로, 다른 persist 스토어의 데이터는 건드리지 않습니다. 주석 처리된 set({...}) 호출도 더 이상 사용되지 않으니 함께 삭제해주세요.

  • 파일: src/store/authStore.ts (라인 48–56)
    • 주석 처리된 set({ … }) 블록 제거
src/components/common/admin/sidebar/sidebarList/AdminSidebarList.tsx (2)

18-28: 아이콘 매핑 객체가 잘 구성되어 있습니다.

모든 아이콘이 heroicons에서 일관되게 가져와졌고, 키 네이밍도 명확합니다.


30-35: 타입 정의가 적절합니다.

IconKey 타입으로 아이콘 이름을 제한하고, props 인터페이스도 잘 정의되어 있습니다. readonly 배열 사용으로 불변성도 보장하고 있습니다.

src/pages/user/mypage/MyPage.tsx (1)

10-10: ROUTES 상수 중앙 경로로 일관되게 업데이트됨을 확인했습니다.
상대 경로(../../../constants/routes)가 올바르며, 프로젝트 전반의 경로 관리 일관성을 높여 줍니다.

src/components/user/home/projectCardLists/ProjectCardLists.tsx (1)

6-6: ROUTES 상수 중앙 경로로 일관되게 업데이트됨을 확인했습니다.
상대 경로(../../../../constants/routes)가 올바르며, 프로젝트 전반의 경로 관리 일관성을 높여 줍니다.

src/components/user/userPage/userProjectList/UserProjectList.tsx (1)

3-3: ROUTES 상수 중앙 경로로 일관되게 업데이트됨을 확인했습니다.
상대 경로(../../../../constants/routes)가 올바르며, 프로젝트 전반의 경로 관리 일관성을 높여 줍니다.

src/components/user/mypage/joinedProject/Project.tsx (1)

5-5: ROUTES 상수 중앙 경로로 일관되게 업데이트됨을 확인했습니다.
상대 경로(../../../../constants/routes)가 올바르며, 프로젝트 전반의 경로 관리 일관성을 높여 줍니다.

src/components/user/mypage/myProfile/MyProfile.tsx (1)

10-10: ROUTES 상수 중앙 경로로 일관되게 업데이트됨을 확인했습니다.
상대 경로(../../../../constants/routes)가 올바르며, 프로젝트 전반의 경로 관리 일관성을 높여 줍니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 482d1ec and 2323cad.

⛔ Files ignored due to path filters (1)
  • src/assets/logout.svg is excluded by !**/*.svg
📒 Files selected for processing (10)
  • src/api/http.api.ts (0 hunks)
  • src/components/common/admin/sidebar/AdminSidebar.styled.ts (1 hunks)
  • src/components/common/admin/sidebar/AdminSidebar.tsx (1 hunks)
  • src/components/common/admin/sidebar/sidebarList/AdminSidebarList.tsx (1 hunks)
  • src/constants/admin/sidebar.ts (1 hunks)
  • src/constants/routes.ts (1 hunks)
  • src/routes/AdminRoutes.tsx (1 hunks)
  • src/routes/MergeRoutes.tsx (1 hunks)
  • src/routes/ProtectAdminRoute.tsx (1 hunks)
  • src/store/authStore.ts (3 hunks)
💤 Files with no reviewable changes (1)
  • src/api/http.api.ts
✅ Files skipped from review due to trivial changes (2)
  • src/constants/routes.ts
  • src/constants/admin/sidebar.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/components/common/admin/sidebar/AdminSidebar.styled.ts
  • src/store/authStore.ts
  • src/routes/AdminRoutes.tsx
  • src/routes/ProtectAdminRoute.tsx
  • src/components/common/admin/sidebar/sidebarList/AdminSidebarList.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/components/common/admin/sidebar/AdminSidebar.tsx (2)
src/components/common/admin/sidebar/sidebarList/AdminSidebarList.tsx (1)
  • AdminSidebarList (33-54)
src/constants/admin/sidebar.ts (1)
  • SIDEBAR_LIST (3-55)
🔇 Additional comments (2)
src/components/common/admin/sidebar/AdminSidebar.tsx (2)

23-25: 사이드바 리스트 렌더링이 효율적으로 구현되었습니다.

각기 다른 카테고리의 사이드바 항목들을 명확하게 분리하여 렌더링하고 있으며, 상수를 통한 데이터 관리도 적절합니다.


10-10: 상태 관리 hook 사용이 적절합니다.

useAuthStore에서 logout 함수만 선택적으로 가져와 사용하는 것이 효율적이고 적절한 패턴입니다.

Comment on lines 16 to 19
<S.LogoutButton type='button' onClick={logout}>
<S.LogoutImg src={logoutIcon} alt='logout icon' />
<S.LogoutSpan>Logout</S.LogoutSpan>
</S.LogoutButton>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

로그아웃 버튼의 사용자 경험 개선이 필요합니다.

현재 로그아웃 버튼을 클릭하면 즉시 로그아웃이 실행됩니다. 사용자 확인 없이 중요한 작업이 실행되는 것은 좋지 않은 UX입니다.

확인 모달이나 확인 절차를 추가하는 것을 제안합니다:

+ import { useState } from 'react';

export default function AdminSidebar() {
  const logout = useAuthStore((state) => state.logout);
+ const [showLogoutModal, setShowLogoutModal] = useState(false);

+ const handleLogoutClick = () => {
+   setShowLogoutModal(true);
+ };

+ const handleConfirmLogout = () => {
+   logout();
+   setShowLogoutModal(false);
+ };

  return (
    <S.SidebarContainer>
      <S.SidebarLogoWrapper>
        <S.SidebarLogoImg src={logo} alt='logo' />
-       <S.LogoutButton type='button' onClick={logout}>
+       <S.LogoutButton type='button' onClick={handleLogoutClick}>
          <S.LogoutImg src={logoutIcon} alt='logout icon' />
          <S.LogoutSpan>Logout</S.LogoutSpan>
        </S.LogoutButton>
      </S.SidebarLogoWrapper>
+     {showLogoutModal && (
+       <LogoutConfirmModal
+         onConfirm={handleConfirmLogout}
+         onCancel={() => setShowLogoutModal(false)}
+       />
+     )}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/components/common/admin/sidebar/AdminSidebar.tsx around lines 16 to 19,
the logout button triggers immediate logout without user confirmation, which
harms UX. Modify the logout handler to first show a confirmation modal or dialog
asking the user to confirm the logout action. Only proceed with the actual
logout if the user confirms; otherwise, cancel the operation. Implement this
confirmation step to improve user experience and prevent accidental logouts.

Comment on lines 15 to 18
<S.SidebarLogoImg src={logo} alt='logo' />
<S.LogoutButton type='button' onClick={logout}>
<S.LogoutImg src={logoutIcon} alt='logout icon' />
<S.LogoutSpan>Logout</S.LogoutSpan>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

접근성 개선을 위한 속성 추가가 필요합니다.

로그아웃 버튼과 이미지에 적절한 접근성 속성이 누락되어 있습니다.

다음과 같이 접근성 속성을 추가하세요:

        <S.SidebarLogoImg src={logo} alt='logo' />
-       <S.LogoutButton type='button' onClick={logout}>
+       <S.LogoutButton 
+         type='button' 
+         onClick={logout}
+         aria-label='관리자 로그아웃'
+         title='로그아웃'
+       >
-         <S.LogoutImg src={logoutIcon} alt='logout icon' />
+         <S.LogoutImg src={logoutIcon} alt='' role='presentation' />
          <S.LogoutSpan>Logout</S.LogoutSpan>
        </S.LogoutButton>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<S.SidebarLogoImg src={logo} alt='logo' />
<S.LogoutButton type='button' onClick={logout}>
<S.LogoutImg src={logoutIcon} alt='logout icon' />
<S.LogoutSpan>Logout</S.LogoutSpan>
<S.SidebarLogoImg src={logo} alt='logo' />
<S.LogoutButton
type='button'
onClick={logout}
aria-label='관리자 로그아웃'
title='로그아웃'
>
<S.LogoutImg src={logoutIcon} alt='' role='presentation' />
<S.LogoutSpan>Logout</S.LogoutSpan>
</S.LogoutButton>
🤖 Prompt for AI Agents
In src/components/common/admin/sidebar/AdminSidebar.tsx around lines 15 to 18,
the logout button and its image lack proper accessibility attributes. Add an
aria-label to the logout button describing its action, and ensure the logout
image has an empty alt attribute (alt="") if it is decorative, or a descriptive
alt text if it conveys information. This will improve screen reader support and
overall accessibility.

@YouD0313 YouD0313 merged commit 72ff949 into develop May 29, 2025
3 checks passed
@YouD0313 YouD0313 deleted the feat/#317 branch May 29, 2025 10:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

관리자 로그인 판별 라우터, 사이드바 레이아웃

3 participants