Skip to content

Conversation

@YouD0313
Copy link
Collaborator

@YouD0313 YouD0313 commented Jun 5, 2025

구현내용

관리자 페이지 FAQ 구현
사이드바, admin title fixed 수정
FAQ 작성, 수정, 삭제 구현

연관이슈

close #333

Summary by CodeRabbit

  • 신규 기능
    • 관리자 페이지에 FAQ(자주 묻는 질문) 관리 기능이 추가되었습니다.
    • 관리자 사이드바에 FAQ 메뉴가 추가되어, FAQ 목록 조회, 검색, 작성, 수정, 삭제가 가능합니다.
    • FAQ 작성 및 수정 폼, 상세 정보 확인, 삭제 시 모달 안내 등 다양한 관리 UI가 제공됩니다.
  • 스타일
    • 관리자 FAQ 및 공지사항 레이아웃과 스타일이 개선되었습니다.
    • 검색바, 타이틀, 사이드바 등 주요 UI 요소의 위치와 고정 스타일이 업데이트되었습니다.
  • 버그 수정/리팩터
    • FAQ 목록 및 아이템 렌더링 구조가 개선되어, 사용자와 관리자가 각각 맞춤형 FAQ 목록을 볼 수 있습니다.
    • FAQ 관련 컴포넌트 및 스타일 분리가 이루어졌습니다.
  • 기타
    • 경로 및 import 구조가 일부 정리되었습니다.

@YouD0313 YouD0313 requested a review from layout-SY June 5, 2025 13:58
@YouD0313 YouD0313 self-assigned this Jun 5, 2025
@YouD0313 YouD0313 linked an issue Jun 5, 2025 that may be closed by this pull request
3 tasks
@coderabbitai
Copy link

coderabbitai bot commented Jun 5, 2025

"""

Walkthrough

이 변경사항은 관리자 FAQ 기능을 신규 도입합니다. 관리자 FAQ의 조회, 작성, 수정, 삭제를 위한 API와 커스텀 훅, UI 컴포넌트, 라우팅, 스타일링이 일괄적으로 추가되었습니다. 사이드바, 라우트, 페이지, 리스트, 작성/수정 폼, FAQ 아이템 관리 등 전체 관리 플로우가 구현되었습니다.

Changes

파일/경로 그룹 변경 요약
src/api/admin/customerService/FAQ.api.ts, src/hooks/admin/useAdminFAQ.ts, src/models/customerService.ts FAQ 상세, 작성, 수정, 삭제 API 및 관련 타입, 커스텀 훅 추가
src/constants/admin/sidebar.ts, src/constants/routes.ts 관리자 FAQ 사이드바 및 라우트 상수 추가
src/routes/AdminRoutes.tsx 관리자 FAQ 라우트 및 하위 라우트(목록, 작성, 수정) 추가
src/pages/admin/adminFAQ/AdminFAQ.tsx, .../adminFAQList/AdminFAQListPage.tsx, .../adminFAQWrite/AdminFAQWritePage.tsx 관리자 FAQ 페이지, 목록 페이지, 작성/수정 페이지 추가
src/components/admin/adminFAQ/AdminFAQList.tsx, .../AdminFAQList.styled.ts, .../AdminFAQWrite.tsx FAQ 리스트, 스타일, 작성/수정 폼 컴포넌트 추가
src/components/user/customerService/faq/FAQItem.tsx, .../FAQItem.styled.ts, .../faqContent/FAQContent.tsx, .../faqContent/FAQContent.styled.ts FAQ 아이템/내용 컴포넌트 및 스타일 분리 및 확장, 어드민 모드 대응
src/pages/user/customerService/faq/FAQ.tsx, .../FAQ.styled.ts, .../FAQContent.tsx FAQ 리스트 렌더링 구조 단순화, 스타일/컴포넌트 분리, 불필요 파일 제거
src/components/common/admin/sidebar/AdminSidebar.styled.ts, .../sidebarList/AdminSidebarList.tsx 어드민 사이드바 스타일 및 FAQ 아이콘 추가
src/components/common/admin/title/AdminTitle.styled.ts, .../searchBar/SearchBar.styled.ts 어드민 타이틀/검색바 고정 스타일 및 레이아웃 개선
src/pages/admin/CommonAdminPage.tsx, .../CommonAdminPage.styled.ts 어드민 페이지 타이틀/Outlet 래퍼 스타일 추가 및 구조 변경
src/components/admin/adminNotice/AdminNoticeList.tsx, .../AdminNoticeList.styled.ts, .../AdminNoticeList.styled.ts 노티스 관련 경로/마진 등 경미한 스타일 및 경로 변경
src/components/user/customerService/notice/noticeItem/NoticeItem.tsx, .../notice/Notice.tsx NoticeItem import 경로 단순화

Sequence Diagram(s)

sequenceDiagram
    participant Admin as Admin User
    participant UI as AdminFAQList/AdminFAQWrite
    participant Hook as useAdminFAQ
    participant API as FAQ.api.ts
    participant Server as Backend

    Admin->>UI: 페이지 접속/FAQ 작성/수정/삭제
    UI->>Hook: FAQ 데이터 요청/변경 요청
    Hook->>API: getFAQDetail/postFAQ/putFAQ/deleteFAQ 호출
    API->>Server: HTTP 요청 (GET/POST/PUT/DELETE)
    Server-->>API: 응답 반환
    API-->>Hook: 결과/에러 반환
    Hook-->>UI: 데이터/성공/실패 콜백
    UI-->>Admin: 결과 표시(리스트, 모달, 리다이렉트 등)
Loading

Assessment against linked issues

Objective Addressed Explanation
관리자 FAQ UI (#333)
관리자 FAQ 작성페이지 (#333)
FAQ 작성, 수정, 삭제 구현 (#333)

Assessment against linked issues: Out-of-scope changes

해당 변경사항에서 명확하게 범위를 벗어난 기능적 코드 변경은 발견되지 않았습니다.

Suggested labels

⛏기능, 🛠개선

Suggested reviewers

  • layout-SY

Poem

🐇
새로 온 FAQ, 어드민의 빛,
작성, 수정, 삭제까지 척척!
사이드바에 불이 켜지고,
리스트와 폼이 반짝반짝.
토끼도 궁금증 없이
깡총깡총 뛰어놀아요!
🌟
"""

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-06-06T01_32_39_811Z-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 a7a7d99 and a5a7055.

📒 Files selected for processing (1)
  • src/components/common/admin/searchBar/SearchBar.styled.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/common/admin/searchBar/SearchBar.styled.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: accessibility-test
✨ 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.

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/components/common/admin/searchBar/SearchBar.styled.ts (1)

64-71: 고정 위치 컴포넌트 구현이 적절하나 개선사항을 제안합니다.

고정 위치 검색바 래퍼의 구현이 적절하지만, 다음 개선사항을 고려해보세요:

  1. 20rem과 같은 마법 숫자를 상수로 분리하여 관리하세요.
  2. z-index: 10 값이 다른 고정 요소들과 충돌하지 않는지 확인하세요.

개선된 구현 예시:

+// 상수 정의 (별도 파일에서 관리 권장)
+const SIDEBAR_WIDTH = '20rem';
+const SEARCH_BAR_Z_INDEX = 10;

 export const SearchBarFixedWrapperStyled = styled.div`
-  width: calc(100vw - 20rem);
+  width: calc(100vw - ${SIDEBAR_WIDTH});
   position: fixed;
   top: 0;
   padding-top: 9rem;
   background: ${({ theme }) => theme.color.white};
-  z-index: 10;
+  z-index: ${SEARCH_BAR_Z_INDEX};
 `;
src/pages/admin/CommonAdminPage.styled.ts (1)

8-8: 빈 스타일드 컴포넌트는 제거하는 것이 좋습니다.

현재 FixedTitle은 스타일이 정의되지 않은 빈 컴포넌트입니다. 실제로 사용되지 않거나 향후 스타일이 추가될 예정이 아니라면 제거하는 것이 좋습니다.

-export const FixedTitle = styled.div``;
src/components/user/customerService/notice/noticeItem/NoticeItem.tsx (1)

2-2: 상대경로 간소화 고려
ContentBorderNoResult 임포트에 여전히 깊은 상대경로(../../../../)가 사용되고 있습니다. 가능한 경우 tsconfig 경로 별칭(alias)을 도입하여 절대/간단한 경로로 변경하는 것을 권장합니다.

Also applies to: 5-5

src/components/admin/adminFAQ/AdminFAQList.tsx (1)

8-14: 상태 관리 개선 제안

현재 keyword 상태를 string으로 관리하고 있는데, 사용자 FAQ 페이지에서는 SearchKeyword 타입을 사용합니다. 타입 일관성을 위해 동일한 타입을 사용하는 것을 권장합니다.

-  const [keyword, setKeyword] = useState<string>('');
+  const [keyword, setKeyword] = useState<SearchKeyword>({ keyword: '' });
   const { faqData, isLoading } = useGetFAQ(keyword);

   const handleGetKeyword = (keyword: string) => {
-    setKeyword(keyword);
+    setKeyword({ keyword });
   };
src/components/user/customerService/faq/faqContent/FAQContent.tsx (2)

24-24: 타입 안전성 개선 제안

list.id를 문자열로 변환할 때 더 안전한 처리를 권장합니다.

-  const id = String(list.id) || '';
+  const id = list.id?.toString() ?? '';

65-65: 삭제 액션 보안 강화 제안

삭제 액션을 # 링크로 처리하는 것보다 버튼을 사용하는 것이 더 적절할 수 있습니다.

-                <S.AdminFAQLink to='#' onClick={handleClickDeleteFAQ}>
+                <S.AdminFAQButton type="button" onClick={handleClickDeleteFAQ}>
                   삭제
-                </S.AdminFAQLink>
+                </S.AdminFAQButton>
src/components/user/customerService/faq/FAQItem.tsx (1)

11-11: props 명명 규칙을 확인해주세요

$isAdmin prop에서 $ 접두사는 React props에서 일반적이지 않습니다. styled-components의 transient props 패턴과 혼동될 수 있습니다.

-  $isAdmin?: boolean;
+  isAdmin?: boolean;

그리고 사용부에서도 수정:

-export default function FAQItem({ faqData, $isAdmin = false }: FAQItemProps) {
+export default function FAQItem({ faqData, isAdmin = false }: FAQItemProps) {
src/api/admin/customerService/FAQ.api.ts (2)

7-7: URL 패턴 일관성을 확인해주세요

getFAQDetail에서는 /faq/${id}로 시작하는 반면, 다른 함수들에서는 faq/로 시작합니다. 일관성을 위해 모든 엔드포인트에서 동일한 패턴을 사용하는 것이 좋습니다.

-    const response = await httpClient.get<ApiFAQDetail>(`/faq/${id}`);
+    const response = await httpClient.get<ApiFAQDetail>(`faq/${id}`);

또는 다른 함수들을 /로 시작하도록 수정:

-    await httpClient.post<ApiCommonBasicType>(`faq`, formData);
+    await httpClient.post<ApiCommonBasicType>(`/faq`, formData);

10-13: 에러 처리 개선을 고려해보세요

현재 에러 처리가 console.error와 재던짐만 수행하고 있습니다. 더 구체적인 에러 정보나 사용자 친화적인 에러 메시지 제공을 고려해보세요.

  } catch (e) {
-    console.error(e);
+    console.error('FAQ 상세 정보 조회 실패:', e);
    throw e;
  }
src/components/admin/adminFAQ/AdminFAQWrite.tsx (1)

61-72: 폼 데이터 처리 중복을 개선해보세요

controlled 상태와 FormData 추출을 모두 사용하고 있어 중복이 발생합니다. 일관성을 위해 하나의 방식을 선택하는 것이 좋습니다.

controlled 상태만 사용하는 방식:

-    const formData = new FormData(e.currentTarget as HTMLFormElement);
-
-    const formDataObj: WriteBody = {
-      title: formData.get('title') as string,
-      content: formData.get('content') as string,
-    };
+    const formDataObj: WriteBody = {
+      title: form.title.trim(),
+      content: form.content.trim(),
+    };
src/hooks/admin/useAdminFAQ.ts (1)

39-45: 네비게이션 타이밍 개선을 고려해보세요

고정된 1초 지연은 사용자 경험에 부정적일 수 있습니다. 모달 확인 후 즉시 이동하거나, 더 짧은 지연을 사용하는 것을 고려해보세요.

-        setTimeout(() => {
+        setTimeout(() => {
           if (pathname) {
             return navigate(pathname);
           } else {
             return navigate(-1);
           }
-        }, 1000);
+        }, 500);
src/components/user/customerService/faq/FAQItem.styled.ts (2)

24-39: 버튼 기본 스타일 보완 제안
기본 브라우저 버튼 스타일을 초기화(border: none; background: none; cursor: pointer;)하고, 호버 시 커서 변경을 추가하면 사용자 경험이 향상됩니다.

 export const ShowMoreFAQ = styled.button`
   width: 100%;
   display: flex;
   justify-content: center;
   align-items: center;
   font-weight: bold;
   font-size: 1rem;
+  border: none;
+  background: none;
+  cursor: pointer;

   svg {
     width: 1rem;
   }

   &:hover {
     background: ${({ theme }) => theme.color.lightgrey};
   }
 `;

41-62: 애니메이션 구현 리팩터링 제안
@keyframes를 컴포넌트 내부가 아닌 styled-componentskeyframes 헬퍼로 분리하여 중복을 줄이고 가독성을 높일 수 있습니다.

import styled, { keyframes } from 'styled-components';

const bounce = keyframes`
  0% { transform: translateY(0); }
  50% { transform: translateY(-3px); }
  100% { transform: translateY(0); }
`;

export const ShowMoreSpan = styled.span`
  width: 100%;
  padding: 1.2rem 0;
  display: flex;
  justify-content: center;
  gap: 0.5rem;
+ cursor: pointer;

  &:hover {
    animation: ${bounce} 0.4s infinite;
  }
`;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ab68b7d and da63bd6.

📒 Files selected for processing (30)
  • src/api/admin/customerService/FAQ.api.ts (1 hunks)
  • src/components/admin/adminFAQ/AdminFAQList.styled.ts (1 hunks)
  • src/components/admin/adminFAQ/AdminFAQList.tsx (1 hunks)
  • src/components/admin/adminFAQ/AdminFAQWrite.tsx (1 hunks)
  • src/components/admin/adminNotice/AdminNoticeList.styled.ts (1 hunks)
  • src/components/admin/adminNotice/AdminNoticeList.tsx (1 hunks)
  • src/components/common/admin/searchBar/SearchBar.styled.ts (2 hunks)
  • src/components/common/admin/sidebar/AdminSidebar.styled.ts (1 hunks)
  • src/components/common/admin/sidebar/sidebarList/AdminSidebarList.tsx (2 hunks)
  • src/components/common/admin/title/AdminTitle.styled.ts (1 hunks)
  • src/components/user/customerService/faq/FAQContent.tsx (0 hunks)
  • src/components/user/customerService/faq/FAQItem.styled.ts (1 hunks)
  • src/components/user/customerService/faq/FAQItem.tsx (1 hunks)
  • src/components/user/customerService/faq/faqContent/FAQContent.styled.ts (3 hunks)
  • src/components/user/customerService/faq/faqContent/FAQContent.tsx (1 hunks)
  • src/components/user/customerService/notice/noticeItem/NoticeItem.tsx (1 hunks)
  • src/constants/admin/sidebar.ts (1 hunks)
  • src/constants/routes.ts (1 hunks)
  • src/hooks/admin/useAdminFAQ.ts (1 hunks)
  • src/models/customerService.ts (1 hunks)
  • src/pages/admin/CommonAdminPage.styled.ts (1 hunks)
  • src/pages/admin/CommonAdminPage.tsx (1 hunks)
  • src/pages/admin/adminFAQ/AdminFAQ.tsx (1 hunks)
  • src/pages/admin/adminFAQ/adminFAQList/AdminFAQListPage.tsx (1 hunks)
  • src/pages/admin/adminFAQ/adminFAQWrite/AdminFAQWritePage.tsx (1 hunks)
  • src/pages/admin/adminNotice/AdminNotice.tsx (1 hunks)
  • src/pages/user/customerService/faq/FAQ.styled.ts (0 hunks)
  • src/pages/user/customerService/faq/FAQ.tsx (2 hunks)
  • src/pages/user/customerService/notice/Notice.tsx (1 hunks)
  • src/routes/AdminRoutes.tsx (2 hunks)
💤 Files with no reviewable changes (2)
  • src/pages/user/customerService/faq/FAQ.styled.ts
  • src/components/user/customerService/faq/FAQContent.tsx
🧰 Additional context used
🧬 Code Graph Analysis (13)
src/pages/admin/adminFAQ/adminFAQWrite/AdminFAQWritePage.tsx (1)
src/components/admin/adminFAQ/AdminFAQWrite.tsx (1)
  • AdminFAQWrite (11-124)
src/pages/admin/adminFAQ/adminFAQList/AdminFAQListPage.tsx (1)
src/components/admin/adminFAQ/AdminFAQList.tsx (1)
  • AdminFAQList (8-36)
src/constants/admin/sidebar.ts (1)
src/constants/routes.ts (1)
  • ADMIN_ROUTE (34-48)
src/pages/admin/CommonAdminPage.tsx (1)
src/components/common/admin/title/AdminTitle.tsx (1)
  • AdminTitle (8-17)
src/pages/admin/adminFAQ/AdminFAQ.tsx (1)
src/pages/admin/CommonAdminPage.tsx (1)
  • CommonAdminPage (9-20)
src/models/customerService.ts (1)
src/models/apiCommon.ts (1)
  • ApiCommonType (1-4)
src/pages/user/customerService/faq/FAQ.tsx (1)
src/components/user/customerService/faq/FAQItem.tsx (1)
  • FAQItem (14-49)
src/routes/AdminRoutes.tsx (2)
src/models/customerService.ts (1)
  • FAQ (3-7)
src/constants/routes.ts (1)
  • ADMIN_ROUTE (34-48)
src/api/admin/customerService/FAQ.api.ts (3)
src/api/http.api.ts (1)
  • httpClient (80-80)
src/models/customerService.ts (2)
  • ApiFAQDetail (17-19)
  • WriteBody (59-62)
src/models/apiCommon.ts (1)
  • ApiCommonBasicType (6-8)
src/components/user/customerService/faq/FAQItem.tsx (3)
src/models/customerService.ts (1)
  • FAQ (3-7)
src/components/user/customerService/faq/faqContent/FAQContent.tsx (1)
  • FAQContent (21-78)
src/components/common/noResult/NoResult.tsx (1)
  • NoResult (8-17)
src/hooks/admin/useAdminFAQ.ts (4)
src/constants/admin/adminModal.ts (1)
  • ADMIN_MODAL_MESSAGE (1-7)
src/hooks/queries/user/keys.ts (1)
  • CustomerService (56-60)
src/api/admin/customerService/FAQ.api.ts (4)
  • getFAQDetail (5-14)
  • postFAQ (16-23)
  • putFAQ (25-38)
  • deleteFAQ (40-47)
src/models/customerService.ts (1)
  • WriteBody (59-62)
src/components/user/customerService/faq/FAQItem.styled.ts (4)
src/components/admin/adminFAQ/AdminFAQList.styled.ts (1)
  • SpinnerWrapper (5-5)
src/pages/user/customerService/faq/FAQ.styled.ts (1)
  • SpinnerWrapper (4-4)
src/components/user/mypage/Spinner.styled.ts (1)
  • SpinnerWrapperStyled (29-35)
src/components/user/customerService/notice/noticeItem/NoticeItem.styled.ts (1)
  • Wrapper (4-8)
src/components/user/customerService/faq/faqContent/FAQContent.styled.ts (1)
src/components/user/customerService/noticeDetail/content/NoticeDetailContent.styled.ts (3)
  • AdminDropdownWrapper (54-56)
  • AdminLinkWrapper (58-69)
  • AdminLink (71-81)
🔇 Additional comments (42)
src/components/admin/adminNotice/AdminNoticeList.styled.ts (1)

11-11: 레이아웃 일관성을 위한 여백 추가가 적절합니다.

관리자 인터페이스의 고정 헤더 및 전체적인 레이아웃 개선에 따른 여백 조정이 적절해 보입니다.

src/components/common/admin/searchBar/SearchBar.styled.ts (1)

8-8: 여백 감소가 적절합니다.

고정 레이아웃으로 변경되면서 여백을 줄인 것이 전체적인 레이아웃 개선에 부합합니다.

src/models/customerService.ts (2)

13-15: FAQ 상세 타입 정의가 적절합니다.

FAQDetailWriteBody를 확장하여 id를 추가한 구조가 적절합니다. 기존 코드의 일관성을 유지하고 있습니다.


17-19: API 응답 타입 정의가 적절합니다.

ApiFAQDetailApiCommonType을 확장하여 FAQ 상세 데이터를 포함하는 구조가 기존 패턴과 일치합니다. 다른 API 응답 타입들(ApiFAQ, ApiNoticeDetail)과 일관성을 유지하고 있습니다.

src/pages/admin/adminNotice/AdminNotice.tsx (1)

1-1: 정상: CommonAdminPage import 경로 대소문자 일치
import 경로가 대소문자를 정확히 반영하도록 수정되어, case-sensitive 파일 시스템에서도 문제없이 모듈을 로드할 수 있습니다.

src/constants/routes.ts (1)

38-38: 새 관리자 라우트 faq 추가
ADMIN_ROUTE에 FAQ 관리용 faq 경로가 정상적으로 추가되었습니다. 이후 사이드바 및 라우팅 설정에서도 일관되게 사용되었는지 확인하세요.

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

9-9: 확인: NoticeItem 컴포넌트 재사용 경로 변경
페이지 내 개별 구현 대신 공통 components 폴더의 NoticeItem을 참조하도록 경로를 잘 조정하였습니다.

src/components/admin/adminNotice/AdminNoticeList.tsx (1)

9-9: 확인: NoticeItem import 경로 일관성 확보
관리자 리스트에서도 공통 컴포넌트를 재사용하도록 import 경로가 올바르게 조정되었습니다.

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

22-26: FAQ 사이드바 항목 추가 확인
새로운 FAQ 메뉴 항목이 SIDEBAR_LIST.service에 올바르게 추가되었습니다. ADMIN_ROUTE.faq 경로도 정의되어 있어 정상적으로 작동할 것으로 보입니다.

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

8-8: FAQ 아이콘 import 추가
LightBulbIcon이 heroicons에서 잘 임포트되었으며, 사이드바 아이콘 맵에 사용할 준비가 되었습니다.


19-19: FAQ 아이콘 매핑 등록
iconMapfaq: <LightBulbIcon /> 항목을 추가하여 사이드바에 FAQ 아이콘이 올바르게 표시됩니다.

src/components/user/customerService/notice/noticeItem/NoticeItem.tsx (1)

4-4: NoticeList import 경로 검증
NoticeList를 상위 디렉터리에서 정상적으로 import하고 있습니다. 경로와 컴포넌트 이름이 일치하는지 확인되었습니다.

src/pages/admin/adminFAQ/adminFAQList/AdminFAQListPage.tsx (1)

1-5: AdminFAQListPage 페이지 래퍼 컴포넌트
AdminFAQList를 간단히 래핑하여 페이지로 제공하는 구조가 적절합니다. 추가 로직이 없기 때문에 유지보수가 용이합니다.

src/pages/admin/adminFAQ/adminFAQWrite/AdminFAQWritePage.tsx (1)

1-5: AdminFAQWritePage 페이지 래퍼 컴포넌트
AdminFAQWrite 컴포넌트를 단순히 렌더링하는 페이지 구조가 명확하며, 별도의 로직 없이 역할이 분리되어 좋습니다.

src/pages/admin/CommonAdminPage.tsx (1)

12-17: 고정 레이아웃을 위한 래퍼 구조가 올바르게 구현되었습니다.

AdminTitle과 Outlet을 각각 FixedTitle과 OutletWrapper로 감싸는 구조가 깔끔하게 적용되어 고정 헤더/사이드바 레이아웃을 지원합니다.

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

11-13: 고정 사이드바를 위한 레이아웃 조정이 적절합니다.

ContainerArea에 margin-left: 15rem을 추가하여 고정 사이드바를 위한 공간을 확보했습니다.

src/components/admin/adminFAQ/AdminFAQList.styled.ts (1)

1-11: 기존 스타일 컴포넌트를 적절히 재사용하고 있습니다.

SpinnerWrapper와 SearchBarFixedWrapper를 재내보내는 방식으로 일관성을 유지하고 있습니다.

src/pages/user/customerService/faq/FAQ.tsx (2)

7-7: 리팩토링이 잘 구현되었습니다

FAQItem 컴포넌트로 분리하여 관심사의 분리 원칙을 잘 따르고 있습니다. 기존 FAQ 목록 렌더링 로직을 캡슐화하여 코드의 재사용성과 유지보수성이 향상되었습니다.


36-36: 깔끔한 컴포넌트 사용

FAQItem 컴포넌트에 faqData를 직접 전달하는 방식으로 단순화되어 가독성이 좋습니다.

src/components/admin/adminFAQ/AdminFAQList.tsx (3)

1-6: Import 구조가 잘 정리되었습니다

필요한 컴포넌트들을 적절히 import하고 있으며, 기존 useGetFAQ 훅을 재사용하여 일관성을 유지하고 있습니다.


16-22: 로딩 상태 처리가 적절합니다

스피너를 사용한 로딩 상태 처리가 잘 구현되어 있습니다.


32-32: Admin 플래그 전달이 정확합니다

$isAdmin={true} 플래그를 통해 관리자용 기능을 활성화하는 방식이 깔끔합니다.

src/routes/AdminRoutes.tsx (2)

21-27: Lazy loading 구현이 적절합니다

FAQ 관련 컴포넌트들을 lazy loading으로 구현하여 초기 번들 크기를 최적화했습니다. import 경로와 컴포넌트 명명이 일관성 있게 구성되어 있습니다.


70-81: 라우트 구조가 잘 설계되었습니다

기존 Notice 섹션과 동일한 패턴으로 FAQ 라우트를 구성하여 일관성을 유지하고 있습니다. 중첩 라우트 구조도 직관적이고 RESTful한 방식으로 잘 구현되었습니다.

src/components/user/customerService/faq/faqContent/FAQContent.tsx (6)

1-15: Import 구조가 체계적으로 구성되었습니다

필요한 아이콘, 타입, 훅들을 적절히 import하고 있으며, 의존성이 명확히 구분되어 있습니다.


16-20: 타입 정의가 명확합니다

FAQContentProps 인터페이스가 명확하게 정의되어 있어 컴포넌트의 계약이 분명합니다.


21-27: 상태 관리와 훅 사용이 적절합니다

컴포넌트의 상태 관리와 커스텀 훅 사용이 잘 구성되어 있습니다. 모달 처리와 FAQ 관리 기능이 적절히 분리되어 있습니다.


29-31: 삭제 기능 구현이 적절합니다

FAQ 삭제 기능이 mutation을 통해 적절히 구현되어 있습니다.


49-71: 관리자 권한 체크와 UI가 잘 구현되었습니다

조건부 렌더링을 통한 관리자 전용 기능이 적절히 구현되어 있습니다. 드롭다운 메뉴와 수정/삭제 링크가 잘 구성되어 있습니다.


73-75: 모달 피드백 구현이 우수합니다

사용자 액션에 대한 피드백을 모달로 제공하는 방식이 UX 관점에서 좋습니다.

src/components/user/customerService/faq/FAQItem.tsx (1)

14-48: 점진적 로딩 구현이 잘 되어 있습니다

FAQ 항목의 점진적 로딩 로직이 올바르게 구현되어 있고, 빈 데이터에 대한 처리도 적절합니다. 코드 구조가 명확하고 읽기 쉽습니다.

src/api/admin/customerService/FAQ.api.ts (1)

16-47: API 함수 구조가 일관되고 타입 안전합니다

모든 CRUD 함수가 일관된 패턴을 따르고 있으며, TypeScript 타입 정의도 적절히 사용되고 있습니다.

src/components/admin/adminFAQ/AdminFAQWrite.tsx (1)

84-123: 컴포넌트 구조와 로직이 잘 구성되어 있습니다

폼 유효성 검사, 로딩 상태 처리, 모달 피드백 등이 적절히 구현되어 있습니다. 생성/수정 모드 분기 처리도 올바릅니다.

src/hooks/admin/useAdminFAQ.ts (1)

60-94: React Query 패턴이 올바르게 구현되어 있습니다

useQuery와 useMutation의 사용법이 적절하고, 캐시 무효화 로직도 올바릅니다. 타입 안전성도 잘 보장되고 있습니다.

src/components/user/customerService/faq/faqContent/FAQContent.styled.ts (3)

2-6: 임포트 경로 확인
NoticeDetailContent.styled에서 AdminDropdownWrapper, AdminLink, AdminLinkWrapper를 가져오는 상대 경로가 올바르게 설정되어 있습니다.


40-44: 부모 요소에 position: relative 추가
관리자 드롭다운(AdminFAQDropdownWrapper)의 절대 위치 지정이 이 컨테이너를 기준으로 동작하도록 ListContentWrapperposition: relative를 추가한 것이 적절합니다.


83-107: 관리자 FAQ 컨트롤용 스타일 컴포넌트 추가
AdminDropdownWrapper 확장, 인증 버튼, 링크 래퍼, 링크 컴포넌트 등 관리자 전용 UI 요소가 일관된 위치와 크기로 잘 정의되어 있습니다.

src/components/user/customerService/faq/FAQItem.styled.ts (5)

1-3: SpinnerWrapperStyled 임포트 경로 확인
SpinnerWrapperStyled를 사용하는 경로(../../../../components/user/mypage/Spinner.styled)가 정확하며, 재사용을 위한 래퍼를 잘 설정했습니다.


4-4: 스피너 래퍼 재정의
공통 SpinnerWrapperStyled를 감싸는 SpinnerWrapper를 생성하여 일관된 스타일 적용이 가능합니다.


6-11: Container 레이아웃 스타일
section 태그를 중앙 정렬하고 상단 여백을 부여해 콘텐츠 배치가 명확합니다.


13-18: 반응형 너비 설정
$isAdmin 플래그에 따라 너비를 달리 지정해 관리자인지 여부에 따른 레이아웃 차별화가 적절합니다.


20-23: 빈 styled 컴포넌트
ToggleWrapperShowMoreFAQWrapper는 현재 스타일이 없어도 구조적 목적에 부합하지만, 추후 스타일 추가 시 편리합니다.

Comment on lines +4 to 10
width: calc(100vw - 20rem);
position: fixed;
top: 0;
padding: 2.5rem 0 0 0;
background: ${({ theme }) => theme.color.white};
z-index: 100;
`;
Copy link

@coderabbitai coderabbitai bot Jun 5, 2025

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

고정 헤더로의 레이아웃 변경이 적절하게 구현되었습니다.

TitleContainer가 고정 위치로 변경되어 관리자 페이지의 헤더 역할을 합니다. width 계산식이 사이드바 너비를 적절히 고려하고 있습니다.

사이드바 너비와의 일관성을 확인해주세요:


🏁 Script executed:

#!/bin/bash
# 사이드바 너비 설정과 헤더 width 계산의 일관성 확인
echo "=== 사이드바 너비 확인 ==="
rg -A 2 -B 2 "width.*15rem|width.*20rem" --type tsx --type ts

echo "=== 헤더 width 계산 확인 ==="
rg -A 2 -B 2 "calc.*100vw" --type tsx --type ts

Length of output: 271


아래 스크립트로 사이드바 너비 정의와 헤더 calc(100vw…) 사용 위치를 전역 검색해 일관성을 확인해보겠습니다.


🏁 Script executed:

#!/bin/bash
echo "=== 사이드바 너비(rem) 사용 위치 ==="
rg -n "rem" -g "*.ts*"

echo "=== 헤더 width calc(100vw…) 사용 위치 ==="
rg -n "calc(100vw" -g "*.ts*"

Length of output: 56479


AdminTitle 헤더 너비와 사이드바 너비 불일치 확인 및 z-index 관리 제안

  • src/components/common/admin/sidebar/AdminSidebar.styled.ts에서는 사이드바 너비가 width: 15rem;로 정의되어 있습니다.
  • src/components/common/admin/title/AdminTitle.styled.ts에서는 헤더 너비를 width: calc(100vw - 20rem);으로 설정해, 사이드바 너비(15rem)보다 5rem 더 크게 빼고 있습니다.

▶ 사이드바 실제 너비가 20rem인지 재확인하거나, 공통 CSS 변수(--sidebar-width)를 도입하여 양쪽에 동일한 값을 사용하도록 통일해주세요.
▶ 또한 z-index: 100;을 하드코딩하기보다는 --stack-header 같은 CSS 커스텀 프로퍼티로 관리하는 방안을 고려해보세요.

🤖 Prompt for AI Agents
In src/components/common/admin/title/AdminTitle.styled.ts around lines 4 to 10,
the header width calculation subtracts 20rem while the sidebar width in
src/components/common/admin/sidebar/AdminSidebar.styled.ts is set to 15rem,
causing inconsistency. To fix this, verify the actual sidebar width and unify
both components by either using the same fixed rem value or, preferably, define
a CSS custom property like --sidebar-width and use it in both places for width
calculations. Additionally, replace the hardcoded z-index: 100 with a CSS
variable such as --stack-header to manage stacking context consistently.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

position fixed라 어쩔 수 없었는데?

Copy link

Choose a reason for hiding this comment

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

@YouD0313 맞습니다! position: fixed를 사용하면 뷰포트 기준으로 위치가 결정되어서 calc(100vw - 20rem) 같은 계산이 필요하죠.

다만 제가 지적한 부분은 position: fixed 사용 자체가 아니라, 실제 사이드바 너비(15rem)와 계산에서 빼는 값(20rem)이 다르다는 점이었습니다. position: fixed를 유지하면서도 정확한 사이드바 너비를 사용하거나 CSS 변수로 통일하면 더 일관성 있는 코드가 될 것 같아요.

현재 구현으로도 동작에는 문제없어 보이니, 나중에 리팩토링 시 고려해보시면 될 것 같습니다! 👍


✏️ Learnings added
Learnt from: YouD0313
PR: devpalsPlus/frontend#334
File: src/components/common/admin/title/AdminTitle.styled.ts:4-10
Timestamp: 2025-06-05T15:59:56.203Z
Learning: YouD0313 prefers using position: fixed for admin headers due to layout requirements, even if it requires viewport-relative width calculations like calc(100vw - 20rem).

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

컴포넌트 내부에 패딩 2rem이 있고 fixed라 적용이 안돼서 더 빼준거라고

Copy link

Choose a reason for hiding this comment

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

@YouD0313 아하! 그렇다면 완전히 이해됩니다. position: fixed를 사용할 때 내부 패딩이 제대로 적용되지 않아서 뷰포트 계산에서 추가로 빼주신 거군요.

사이드바 너비(15rem) + 내부 패딩 보정(5rem) = 20rem으로 계산하신 것이 맞네요. position: fixed의 레이아웃 특성상 이런 조정이 필요한 경우가 있죠. 명확한 설명 감사합니다! 👍


✏️ Learnings added
Learnt from: YouD0313
PR: devpalsPlus/frontend#334
File: src/components/common/admin/title/AdminTitle.styled.ts:4-10
Timestamp: 2025-06-05T16:04:56.880Z
Learning: YouD0313가 AdminTitle 컴포넌트에서 calc(100vw - 20rem)을 사용하는 이유: position: fixed 사용 시 내부 패딩 2rem이 제대로 적용되지 않아, 사이드바 너비(15rem)에 추가로 5rem을 더 빼서 총 20rem을 차감하여 레이아웃 문제를 해결함.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: YouD0313
PR: devpalsPlus/frontend#334
File: src/components/common/admin/title/AdminTitle.styled.ts:4-10
Timestamp: 2025-06-05T15:59:56.203Z
Learning: YouD0313 prefers using position: fixed for admin headers due to layout requirements, even if it requires viewport-relative width calculations like calc(100vw - 20rem).

`;

export const SidebarContainer = styled.section`
position: fixed;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

사이드바와 헤더 너비 불일치 문제가 있습니다.

사이드바 너비는 15rem인데 AdminTitle.styled.ts에서는 20rem을 가정하고 있습니다 (calc(100vw - 20rem)). 이로 인해 레이아웃 불일치가 발생할 수 있습니다.

다음 중 하나로 수정해주세요:

# 옵션 1: AdminTitle.styled.ts 수정
-  width: calc(100vw - 20rem);
+  width: calc(100vw - 15rem);

또는

# 옵션 2: 사이드바 너비를 20rem으로 변경
-  width: 15rem;
+  width: 20rem;
-  margin-left: 15rem;
+  margin-left: 20rem;

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

🤖 Prompt for AI Agents
In src/components/common/admin/sidebar/AdminSidebar.styled.ts at line 17, the
sidebar width is set to 15rem, but AdminTitle.styled.ts assumes 20rem width,
causing layout mismatch. To fix this, either update the sidebar width to 20rem
to match AdminTitle.styled.ts or adjust AdminTitle.styled.ts to use 15rem
consistently. Ensure both files use the same width value to maintain layout
alignment.

import Spinner from '../../user/mypage/Spinner';

export default function AdminFAQList() {
const [keyword, setKeyword] = useState<string>('');
Copy link
Collaborator

Choose a reason for hiding this comment

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

useSearchBar로 searchBar 공용화 한 걸로 하셔도 돼요

@YouD0313 YouD0313 merged commit 0e708cb into develop Jun 6, 2025
4 checks passed
@YouD0313 YouD0313 deleted the feat/#333 branch June 6, 2025 01:34
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.

관리자 FAQ

3 participants