Skip to content

Conversation

@YouD0313
Copy link
Collaborator

@YouD0313 YouD0313 commented Jun 9, 2025

구현내용

관리자 문의 페이지
관리자 문의 전체 조회, 상세 조회 api
관리자 답변 페이지
관리자 문의 답변, 수정, 삭제 api

연관이슈

close #335

Summary by CodeRabbit

  • 신규 기능

    • 관리자 문의 목록 조회, 상세 확인, 답변 작성·수정·삭제 기능이 추가되었습니다.
    • 문의 상세에서 이미지 썸네일 클릭 시 확대 모달로 확인할 수 있습니다.
    • 문의 관리 페이지에 리스트, 상세, 답변 작성 화면이 새롭게 제공됩니다.
  • 스타일

    • 관리자 문의 관련 컴포넌트에 전용 스타일이 적용되어 UI가 개선되었습니다.
  • 버그 수정

    • 로그인 성공 페이지에서 불필요한 콘솔 출력이 제거되었습니다.
  • 리팩터

    • 관리자 문의 페이지가 공통 레이아웃 컴포넌트를 사용하도록 구조가 개선되었습니다.
  • 기타

    • 내부 API 경로 및 타입 정리가 이루어져 유지보수가 용이해졌습니다.
    • React Query 키 경로 및 타입이 일관되게 정비되었습니다.

@YouD0313 YouD0313 requested a review from layout-SY June 9, 2025 12:06
@YouD0313 YouD0313 self-assigned this Jun 9, 2025
@YouD0313 YouD0313 linked an issue Jun 9, 2025 that may be closed by this pull request
4 tasks
@coderabbitai
Copy link

coderabbitai bot commented Jun 9, 2025

"""

Walkthrough

이 변경사항은 관리자 문의 기능을 전면적으로 도입하고, 관련 API, React 컴포넌트, 스타일 파일, 커스텀 훅, 라우팅 구조를 추가 및 리팩토링합니다. 문의 전체 조회, 상세 조회, 답변 작성/수정/삭제 등 관리자 문의의 CRUD를 지원하는 기능이 구현되었습니다. 기존 관련 API 함수의 위치도 변경되었습니다.

Changes

파일/그룹 변경 요약
src/api/activityLog.api.ts getAllInquiries 함수 제거
src/api/admin/customerService/Inquiry.api.ts 관리자 문의 관련 API 함수(전체 조회, 상세 조회, 답변 작성/수정/삭제) 신설
src/components/admin/adminInquiry/... 관리자 문의 리스트, 상세, 답변, 답변작성 등 UI 컴포넌트 및 스타일 파일 신설
src/hooks/admin/useAdminInquiry.ts 관리자 문의 상세/답변/삭제용 커스텀 훅 신설
src/hooks/admin/useGetAllInquiries.ts getAllInquiries API 경로 및 키 변경
src/hooks/queries/keys.ts CustomerService.inquiryDetail 키 추가
src/models/activityLog.ts, src/models/inquiry.ts 문의/관리자 문의 관련 타입, 인터페이스 확장 및 신설
src/pages/admin/adminInquiries/... 관리자 문의 리스트/상세/답변 작성 페이지 컴포넌트 신설 및 기존 스타일 파일 제거
src/routes/AdminRoutes.tsx 관리자 문의 관련 라우트 및 중첩 라우팅 추가, Suspense로 lazy loading 처리
src/hooks/... (여러 파일) 쿼리 키 import 경로를 '../queries/user/keys''../queries/keys'로 일괄 변경
src/pages/login/LoginSuccess.tsx 불필요한 콘솔 로그 제거

Sequence Diagram(s)

sequenceDiagram
  participant Admin as 관리자
  participant UI as AdminInquiryList/AdminInquiryDetail
  participant Hook as useAdminInquiry/useGetAllInquiries
  participant API as Inquiry.api.ts
  participant Server as 서버

  Admin->>UI: 문의 리스트 페이지 접근
  UI->>Hook: useGetAllInquiries 호출
  Hook->>API: getAllInquiries()
  API->>Server: GET /admin/inquiries
  Server-->>API: 문의 리스트 반환
  API-->>Hook: 데이터 반환
  Hook-->>UI: 데이터 전달
  UI-->>Admin: 문의 리스트 렌더링

  Admin->>UI: 문의 상세 클릭
  UI->>Hook: useAdminInquiry({id})
  Hook->>API: getInquiryDetail(id)
  API->>Server: GET /admin/inquiries/:id
  Server-->>API: 문의 상세 반환
  API-->>Hook: 데이터 반환
  Hook-->>UI: 데이터 전달
  UI-->>Admin: 문의 상세/답변 UI 렌더링

  Admin->>UI: 답변 작성/수정
  UI->>Hook: post/patchInquiryAnswerMutate({id, answer})
  Hook->>API: postInquiryAnswer/patchInquiryAnswer
  API->>Server: POST/PATCH /admin/inquiries/:id/answer
  Server-->>API: 성공/실패 응답
  API-->>Hook: 응답 반환
  Hook-->>UI: 모달 등 상태 업데이트
  UI-->>Admin: 결과 알림 및 UI 갱신
Loading

Assessment against linked issues

Objective Addressed Explanation
관리자 문의 페이지 구현 (#335)
관리자 문의 전체 조회, 상세 조회 API 구현 (#335)
관리자 답변 페이지 구현 (#335)
관리자 문의 답변, 수정, 삭제 API 구현 (#335)

Assessment against linked issues: Out-of-scope changes

해당 변경사항에서 요구사항과 무관한 기능적 코드 변경은 발견되지 않았습니다.

Possibly related PRs

Suggested labels

⛏기능, 🛠개선

Poem

🐇
문의가 쏟아지는 관리자 방,
답변도 척척, 삭제도 뚝딱!
새 API, 컴포넌트 줄줄이,
스타일도 예쁘게, 라우트도 깔끔히.
토끼도 감탄해,
"이제 문의 걱정 끝!"
📝✨
"""

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-09T12_48_36_568Z-debug-0.log

✨ 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: 12

🧹 Nitpick comments (21)
src/hooks/admin/useGetAllInquiries.ts (1)

2-3: 상대경로 최적화 고려 및 alias 적용 제안
새 API 모듈과 중앙화된 쿼리 키를 올바르게 import 했습니다. 다만 ../../api/admin/customerService/Inquiry.api와 같은 상대경로가 길어지므로, @/api/...@/hooks/... 같은 경로 alias 설정을 도입하면 가독성과 유지보수성이 향상됩니다.

src/components/admin/adminInquiry/AdminInquiryAnswer.tsx (1)

28-28: 조건문을 단순화하세요.

createdAt이 존재하는지 확인하는 조건문이 불필요합니다.

-            {createdAt ? createdAt : ''}
+            {createdAt || ''}
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.styled.ts (1)

38-43: 컴포넌트 확장의 의미적 일관성을 확인하세요.

InquiryAnswerWriteInquiryContent(div)를 확장하면서 resize: none 속성을 사용하는 것으로 보아 textarea로 사용될 것 같습니다. 의미적으로 더 명확한 네이밍이나 적절한 기본 컴포넌트 확장을 고려해보세요.

-export const InquiryAnswerWrite = styled(InquiryContent)`
+export const InquiryAnswerWriteTextarea = styled.textarea`
+  font-size: 1.1rem;
+  width: 100%;
   resize: none;
   border: 1px solid ${({ theme }) => theme.color.placeholder};
   border-radius: ${({ theme }) => theme.borderRadius.primary};
   padding: 1rem;
 `;
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (2)

8-22: 인터페이스 정의가 불필요합니다.

AdminInquiryAnswerWriteProps 인터페이스가 정의되어 있지만 실제로는 useOutletContext에서 타입을 직접 사용하고 있습니다. 이 인터페이스는 제거하거나 outlet context의 타입 안전성을 위해 활용하는 것이 좋겠습니다.

-interface AdminInquiryAnswerWriteProps {
-  answerData: string;
-  isWrite: boolean;
-  id: string;
-  postInquiryAnswerMutate: UseMutationResult<
-    void,
-    AxiosError,
-    InquiryAnswerBody
-  >;
-  patchInquiryAnswerMutate: UseMutationResult<
-    void,
-    AxiosError,
-    InquiryAnswerBody
-  >;
-}

55-58: Optional chaining을 사용하여 코드를 간소화하세요.

정적 분석 도구에서 제안한 대로 optional chaining을 사용하면 더 안전하고 간결한 코드가 됩니다.

-    if (inputRef && inputRef.current) {
-      inputRef.current.style.height = 'auto';
-      inputRef.current.style.height = `${inputRef.current.scrollHeight}px`;
-    }
+    if (inputRef.current) {
+      inputRef.current.style.height = 'auto';
+      inputRef.current.style.height = `${inputRef.current.scrollHeight}px`;
+    }
🧰 Tools
🪛 Biome (1.9.4)

[error] 55-55: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/components/admin/adminInquiry/AdminInquiryDetail.tsx (1)

15-16: 빈 문자열 폴백 처리를 개선할 수 있습니다.

inquiryId가 undefined일 때 빈 문자열로 폴백하는 것보다 더 명시적인 처리를 고려해보세요.

- const { inquiryId } = useParams();
- const id = inquiryId || '';
+ const { inquiryId } = useParams();
+ const id = inquiryId ?? '';
+ 
+ if (!inquiryId) {
+   return <div>잘못된 문의 ID입니다.</div>;
+ }
src/api/admin/customerService/Inquiry.api.ts (2)

14-14: 에러 메시지가 일관성이 없습니다.

한국어 에러 메시지와 영어 console.error가 혼재되어 있습니다. 일관성을 위해 통일하는 것을 권장합니다.

- console.error('전체 문의 조회 에러', e);
+ console.error('getAllInquiries error:', e);

27-28: 에러 로깅에 컨텍스트 정보가 부족합니다.

어떤 함수에서 에러가 발생했는지 알기 어렵습니다. 에러 로깅에 함수명을 포함시키는 것을 권장합니다.

- console.error(e);
+ console.error('getInquiryDetail error:', e);

다른 함수들도 마찬가지로 수정해주세요:

  • postInquiryAnswer error:
  • patchInquiryAnswer error:
  • deleteInquiry error:

Also applies to: 38-39, 49-50, 58-59

src/components/admin/adminInquiry/AdminInquiryAnswer.styled.ts (2)

32-32: 빈 스타일드 컴포넌트가 불필요해 보입니다.

AnswerButtonSpan이 스타일링 없이 정의되어 있습니다. 실제로 사용되지 않는다면 제거하는 것을 고려해보세요.

- export const AnswerButtonSpan = styled.span``;

만약 향후 스타일링을 위해 유지한다면 주석을 추가해주세요:

+ // TODO: 향후 스타일링 추가 예정
export const AnswerButtonSpan = styled.span``;

17-20: 반응형 디자인을 고려한 스타일링이 필요할 수 있습니다.

고정된 gap: 3remfont-size 값들이 모바일 환경에서 적절한지 확인해보세요.

export const AnswerHeaderWrapper = styled(InquiryHeaderWrapper)`
  display: flex;
- gap: 3rem;
+ gap: clamp(1rem, 5vw, 3rem);
`;

Also applies to: 22-25, 27-30

src/components/admin/adminInquiry/AdminInquiry.styled.ts (4)

4-4: 불필요한 빈 스타일드 컴포넌트
styled(Link)\`;에 CSS가 정의되어 있지 않습니다. 사용 목적이 명확하지 않다면 직접 Link` 컴포넌트를 사용하거나 스타일을 추가하는 편이 좋습니다.


6-13: 그리드 정렬 속성 검토
justify-content: center;는 그리드 컨테이너를 부모 내에서 중앙으로 배치합니다. 아이템 간 중앙 정렬을 원한다면 justify-items: center;를 고려해 보세요.


15-15: 불필요한 빈 스타일드 컴포넌트
styled.div\`;에 스타일이 없으므로, 실제 스타일링이 필요 없으면 일반 div`로 대체하거나 스타일을 추가 검토해 주세요.


22-22: 불필요한 빈 스타일드 컴포넌트
styled.div\`;에 CSS가 없어 일반 div`로 대체 가능 여부를 검토해 주세요.

src/components/admin/adminInquiry/AdminInquiryDetailContent.styled.ts (7)

17-17: 빈 래퍼 컴포넌트
styled.div\`;`에 스타일이 없으므로, 불필요하다면 제거하거나 실제 스타일을 추가해 주세요.


50-50: 버튼 컴포넌트 이름 검토
InquiryFileImgBlowUpButton 명칭이 다소 직관적이지 않을 수 있습니다. ZoomButton 또는 EnlargeButton 등으로 네이밍을 간결하게 다듬는 것을 제안합니다.


52-54: 이미지 크기 고정 검토
width: 5rem로 고정되면 비율이 깨질 수 있습니다. max-widthheight: auto 조합을 고려해 보세요.


60-62: 과도한 z-index 사용
1000000000은 너무 큰 값입니다. 테마나 상수로 관리하거나, 적절한 범위(예: 9999)로 조정하는 것을 권장합니다.


64-65: 빈 스타일드 컴포넌트
확장된 ModalImgWrapper에 스타일이 없어 불필요할 수 있습니다. 실제 커스터마이징이 필요 없다면 제거를 검토해 주세요.


66-68: 빈 스타일드 컴포넌트
ModalImgMessageWrapper 상속 후 변경된 스타일이 없습니다. 제거 여부를 검토해 주세요.


70-70: 빈 스타일드 컴포넌트
ModalImg 상속 후 별도 스타일이 없으므로, 직접 사용 가능 여부를 확인해 보세요.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0e708cb and 671973e.

📒 Files selected for processing (66)
  • src/api/activityLog.api.ts (0 hunks)
  • src/api/admin/customerService/Inquiry.api.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiry.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiry.tsx (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryAnswer.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryAnswer.tsx (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryAnswerWrite.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryDetail.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryDetail.tsx (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryDetailContent.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryDetailContent.tsx (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryList.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryList.tsx (1 hunks)
  • src/hooks/admin/useAdminFAQ.ts (1 hunks)
  • src/hooks/admin/useAdminInquiry.ts (1 hunks)
  • src/hooks/admin/useAdminNotice.ts (1 hunks)
  • src/hooks/admin/useGetAllInquiries.ts (1 hunks)
  • src/hooks/admin/useGetAllReports.ts (1 hunks)
  • src/hooks/admin/useGetAllUsers.ts (1 hunks)
  • src/hooks/admin/useGetAllUsersPreview.ts (1 hunks)
  • src/hooks/queries/keys.ts (1 hunks)
  • src/hooks/useAuth.ts (1 hunks)
  • src/hooks/user/CommentHooks/useDeleteComment.ts (1 hunks)
  • src/hooks/user/CommentHooks/useDeleteReply.ts (1 hunks)
  • src/hooks/user/CommentHooks/useGetComment.ts (1 hunks)
  • src/hooks/user/CommentHooks/useGetReply.ts (1 hunks)
  • src/hooks/user/CommentHooks/usePatchReply.ts (1 hunks)
  • src/hooks/user/CommentHooks/usePostComment.ts (1 hunks)
  • src/hooks/user/CommentHooks/usePostReply.ts (1 hunks)
  • src/hooks/user/CommentHooks/usePutComment.ts (1 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/evaluationHooks/useGetEvaluation.ts (1 hunks)
  • src/hooks/user/evaluationHooks/usePostEvaluation.ts (1 hunks)
  • src/hooks/user/useAlarmDelete.ts (1 hunks)
  • src/hooks/user/useAlarmList.ts (1 hunks)
  • src/hooks/user/useAlarmPatch.ts (1 hunks)
  • src/hooks/user/useApllicantList.ts (1 hunks)
  • src/hooks/user/useApplicantInfo.ts (1 hunks)
  • src/hooks/user/useChartData.ts (1 hunks)
  • src/hooks/user/useGetFAQ.ts (1 hunks)
  • src/hooks/user/useGetMyComments.ts (1 hunks)
  • src/hooks/user/useGetMyInquiries.ts (1 hunks)
  • src/hooks/user/useGetNotice.ts (1 hunks)
  • src/hooks/user/useGetNoticeDetail.ts (1 hunks)
  • src/hooks/user/useGetProjectData.ts (1 hunks)
  • src/hooks/user/useGetUserProjectList.ts (1 hunks)
  • src/hooks/user/useManagedProjects.ts (1 hunks)
  • src/hooks/user/useMyInfo.ts (1 hunks)
  • src/hooks/user/useNotification.ts (1 hunks)
  • src/hooks/user/usePassNonPassList.ts (1 hunks)
  • src/hooks/user/usePassNonPassMutation.ts (1 hunks)
  • src/hooks/user/usePostInquiry.ts (1 hunks)
  • src/hooks/user/useSendResultMutation.ts (1 hunks)
  • src/hooks/user/useUserInfo.ts (1 hunks)
  • src/models/activityLog.ts (1 hunks)
  • src/models/inquiry.ts (1 hunks)
  • src/pages/admin/adminInquiries/AdminInquiries.styled.ts (0 hunks)
  • src/pages/admin/adminInquiries/AdminInquiries.tsx (1 hunks)
  • src/pages/admin/adminInquiries/adminInquiryDetail/AdminInquiryDetailPage.tsx (1 hunks)
  • src/pages/admin/adminInquiries/adminInquiryList/AdminInquiryListPage.tsx (1 hunks)
  • src/pages/admin/adminInquiries/adminInquiryWrite/AdminInquiryWritePage.tsx (1 hunks)
  • src/pages/login/LoginSuccess.tsx (0 hunks)
  • src/routes/AdminRoutes.tsx (3 hunks)
💤 Files with no reviewable changes (3)
  • src/pages/login/LoginSuccess.tsx
  • src/api/activityLog.api.ts
  • src/pages/admin/adminInquiries/AdminInquiries.styled.ts
🧰 Additional context used
🧬 Code Graph Analysis (16)
src/components/admin/adminInquiry/AdminInquiryList.styled.ts (2)
src/components/admin/adminInquiry/AdminInquiryDetail.styled.ts (1)
  • SpinnerWrapper (4-4)
src/components/user/mypage/Spinner.styled.ts (1)
  • SpinnerWrapperStyled (29-35)
src/components/admin/adminInquiry/AdminInquiry.tsx (2)
src/models/inquiry.ts (1)
  • AdminInquiry (10-17)
src/constants/routes.ts (1)
  • ADMIN_ROUTE (34-48)
src/pages/admin/adminInquiries/adminInquiryList/AdminInquiryListPage.tsx (1)
src/components/admin/adminInquiry/AdminInquiryList.tsx (1)
  • AdminInquiryList (6-26)
src/pages/admin/adminInquiries/adminInquiryDetail/AdminInquiryDetailPage.tsx (1)
src/components/admin/adminInquiry/AdminInquiryDetail.tsx (1)
  • AdminInquiryDetail (9-60)
src/pages/admin/adminInquiries/adminInquiryWrite/AdminInquiryWritePage.tsx (1)
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (1)
  • AdminInquiryAnswerWrite (24-80)
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.styled.ts (2)
src/components/admin/adminInquiry/AdminInquiryAnswer.styled.ts (4)
  • InquiryAnswerContentContainer (11-13)
  • AnswerHeaderWrapper (17-20)
  • InquiryAnswerInfo (22-25)
  • InquiryAnswerButton (27-30)
src/components/admin/adminInquiry/AdminInquiryDetailContent.styled.ts (3)
  • AdminInquiryContentContainer (10-15)
  • AdminInquiryContentWrapper (17-17)
  • InquiryContent (45-48)
src/components/admin/adminInquiry/AdminInquiryDetail.tsx (4)
src/hooks/useModal.ts (1)
  • useModal (3-36)
src/hooks/admin/useAdminInquiry.ts (1)
  • useAdminInquiry (15-114)
src/components/common/loadingSpinner/LoadingSpinner.styled.ts (1)
  • Spinner (21-28)
src/components/admin/adminInquiry/AdminInquiryDetailContent.tsx (1)
  • AdminInquiryDetailContent (10-64)
src/components/admin/adminInquiry/AdminInquiryDetail.styled.ts (2)
src/components/admin/adminInquiry/AdminInquiryList.styled.ts (1)
  • SpinnerWrapper (4-4)
src/components/user/mypage/Spinner.styled.ts (1)
  • SpinnerWrapperStyled (29-35)
src/components/admin/adminInquiry/AdminInquiryAnswer.styled.ts (2)
src/components/admin/adminInquiry/AdminInquiryDetailContent.styled.ts (5)
  • AdminInquiryContentContainer (10-15)
  • AdminInquiryContentWrapper (17-17)
  • InquiryHeaderWrapper (19-21)
  • InquiryInfo (35-38)
  • InquiryContent (45-48)
src/components/user/customerService/inquiry/Inquiry.styled.ts (1)
  • SendButton (205-222)
src/components/admin/adminInquiry/AdminInquiryAnswer.tsx (1)
src/constants/routes.ts (1)
  • ADMIN_ROUTE (34-48)
src/models/inquiry.ts (2)
src/models/apiCommon.ts (1)
  • ApiCommonType (1-4)
src/models/activityLog.ts (1)
  • MyInquiries (3-14)
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (1)
src/models/inquiry.ts (1)
  • InquiryAnswerBody (27-30)
src/components/admin/adminInquiry/AdminInquiryDetailContent.tsx (2)
src/models/activityLog.ts (1)
  • MyInquiries (3-14)
src/constants/user/customerService.ts (1)
  • My_INQUIRIES_MESSAGE (15-20)
src/api/admin/customerService/Inquiry.api.ts (3)
src/api/http.api.ts (1)
  • httpClient (80-80)
src/models/inquiry.ts (3)
  • ApiAdminInquiry (19-21)
  • ApiAdminInquiryDetail (23-25)
  • InquiryAnswerBody (27-30)
src/models/apiCommon.ts (1)
  • ApiCommonBasicType (6-8)
src/hooks/admin/useAdminInquiry.ts (5)
src/hooks/admin/useAdminFAQ.ts (1)
  • State (14-14)
src/constants/admin/adminModal.ts (1)
  • ADMIN_MODAL_MESSAGE (1-8)
src/hooks/queries/keys.ts (1)
  • CustomerService (56-61)
src/api/admin/customerService/Inquiry.api.ts (4)
  • getInquiryDetail (19-30)
  • postInquiryAnswer (32-41)
  • patchInquiryAnswer (43-52)
  • deleteInquiry (54-61)
src/models/inquiry.ts (1)
  • InquiryAnswerBody (27-30)
src/components/admin/adminInquiry/AdminInquiryDetailContent.styled.ts (2)
src/components/user/customerService/inquiry/Inquiry.styled.ts (1)
  • SendButton (205-222)
src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts (4)
  • ModalImgContainer (58-72)
  • ModalImgWrapper (74-84)
  • ModalImgMessageWrapper (86-92)
  • ModalImg (94-97)
🪛 Biome (1.9.4)
src/components/admin/adminInquiry/AdminInquiry.tsx

[error] 10-10: Shouldn't redeclare 'AdminInquiry'. Consider to delete it or rename it.

'AdminInquiry' is defined here:

(lint/suspicious/noRedeclare)

src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx

[error] 55-55: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: accessibility-test
🔇 Additional comments (78)
src/hooks/queries/keys.ts (1)

60-60: 관리자 문의 상세 조회용 inquiryDetail 키 추가 승인

CustomerService에 문의 상세 조회를 위한 inquiryDetail 키가 올바르게 추가되었습니다.

src/hooks/user/CommentHooks/usePostComment.ts (1)

3-3: 쿼리 키 경로 수정 승인

ProjectCommentList의 import 경로가 기존 사용자 경로에서 중앙 queries/keys 모듈로 정상적으로 변경되었습니다.

src/hooks/user/evaluationHooks/useGetEvaluation.ts (1)

3-3: 쿼리 키 경로 수정 승인

ProjectMemberListEval의 import 경로가 중앙 queries/keys 모듈로 일관되게 업데이트되었습니다.

src/hooks/user/evaluationHooks/usePostEvaluation.ts (1)

3-3: 쿼리 키 경로 수정 승인

ProjectMemberListEval import 경로가 ../../queries/keys로 맞춰져 경로 일관성이 확보되었습니다.

src/hooks/user/CommentHooks/useGetReply.ts (1)

2-2: 쿼리 키 경로 수정 승인

ProjectReplyList의 import 경로를 새 중앙 모듈(queries/keys)에서 가져오도록 변경하여 일관성을 유지했습니다.

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

6-6: 쿼리 키 경로 업데이트 확인
import 경로 변경이 전체 리팩토링 방침과 일치하며 올바르게 적용되었습니다.

src/hooks/user/CommentHooks/usePostReply.ts (1)

3-3: 쿼리 키 경로 일관성 확인
ProjectReplyList를 공통 queries/keys 모듈에서 가져오도록 경로가 정확히 갱신되었습니다.

src/hooks/user/CommentHooks/usePatchReply.ts (1)

3-3: 쿼리 키 경로 일관성 확인
ProjectReplyList의 import 경로가 중앙화된 queries/keys로 올바르게 변경되었습니다.

src/hooks/user/CommentHooks/usePutComment.ts (1)

3-3: 쿼리 키 경로 일관성 확인
ProjectCommentList의 import가 통합된 queries/keys 모듈로 적절히 이동되었습니다.

src/hooks/user/CommentHooks/useGetComment.ts (1)

3-3: 쿼리 키 경로 일관성 확인
ProjectCommentList import가 새 queries/keys 위치로 정확히 반영되었습니다.

src/hooks/user/CommentHooks/useDeleteReply.ts (1)

2-2: 경로 변경이 올바르게 적용되었습니다.
기존 ../../queries/user/keys에서 중앙 모듈인 ../../queries/keys로 리팩토링되어 일관성이 향상되었습니다. 로직에 영향이 없습니다.

src/hooks/user/CommentHooks/useDeleteComment.ts (1)

2-2: 쿼리 키 임포트 경로가 일관적으로 중앙화되었습니다.
../../queries/keys로 변경되어 다른 훅들과 동일한 구조로 통일되었습니다. 기능상 문제 없습니다.

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

2-2: 쿼리 키 경로 리팩토링이 적절히 반영되었습니다.
../../queries/keys로 이동해 유지보수성과 가독성이 개선되었습니다. 기존 동작에는 영향 없습니다.

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

3-3: 쿼리 키 임포트 경로가 중앙 모듈로 통합되었습니다.
../queries/keys로 변경되어 경로 일관성이 확보되었습니다. 기능 변경 없음.

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

3-3: AlarmList 키 임포트 경로가 표준화되었습니다.
../queries/keys로 리팩토링되어 다른 훅들과 동일한 구조를 유지합니다. 로직에는 영향 없습니다.

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

3-3: 쿼리 키 import 경로 통합
applicantKey를 중앙화된 ../queries/keys에서 참조하도록 변경한 것이 일관성에 부합합니다.

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

1-1: 쿼리 키 import 경로 통합
ActivityLog../queries/keys로 불러오는 변경이 기존 구조와 일관되며 적절합니다.

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

3-3: 쿼리 키 import 경로 통합
managedProjectKey를 중앙화된 ../queries/keys에서 불러오도록 한 것은 캐시 무효화 관리에 일관성을 제공합니다.

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

5-5: 쿼리 키 import 경로 통합
managedProjectKey../../queries/keys로 참조하도록 변경해 모듈 구조 일관성을 유지했습니다.

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

4-4: 쿼리 키 import 경로 통합
managedProjectKey를 중앙화된 ../../queries/keys에서 가져오도록 업데이트된 것이 적절합니다.

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

4-4: 쿼리 키 import 경로 중앙화 반영 확인
기존의 '../queries/user/keys'에서 '../queries/keys'로 올바르게 변경되었습니다.

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

4-4: 쿼리 키 import 경로 업데이트 확인
myInfoKeyProjectListKey'../queries/keys'로 일관성 있게 옮겨졌습니다.

src/hooks/useAuth.ts (1)

9-9: 쿼리 키 import 경로 업데이트 확인
myInfoKey'./queries/keys'로 중앙화된 경로로 올바르게 변경되었습니다.

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

2-2: 쿼리 키 import 경로 업데이트 확인
userInfoKey'../queries/keys'로 일관성 있게 중앙화되었습니다.

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

4-4: 쿼리 키 import 경로 업데이트 확인
CustomerService 키가 '../queries/keys'로 올바르게 업데이트되었습니다.

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

2-2: 쿼리 키 import 경로 업데이트 승인
applicantKeyqueries/keys로 중앙화된 경로로 가져오도록 변경한 것은 일관적이며 적절합니다.

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

2-2: 쿼리 키 import 경로 업데이트 승인
applicantKey의 import 경로를 queries/keys로 통일한 변경이 올바르게 반영되었습니다.

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

2-2: 쿼리 키 import 경로 업데이트 승인
UserData의 경로를 중앙화된 queries/keys 모듈로 수정한 것은 일관성을 높이는 적절한 리팩토링입니다.

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

2-2: 쿼리 키 import 경로 업데이트 승인
AlarmListqueries/keys에서 가져오도록 경로를 통합한 변경이 정확히 적용되었습니다.

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

2-2: 쿼리 키 import 경로 업데이트 승인
managedProjectKey를 중앙화된 경로로 옮긴 것은 코드베이스 전반의 일관성 유지에 도움이 됩니다.

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

4-4: ActivityLog 쿼리 키 경로가 중앙 모듈로 올바르게 업데이트되었습니다.
이 변경으로 다른 훅들과 쿼리 키 참조 경로가 일관화되었습니다.

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

3-3: CustomerService 쿼리 키 경로가 중앙 모듈로 올바르게 업데이트되었습니다.
다른 고객 서비스 훅들과 동일한 queries/keys 모듈을 사용하여 일관성을 유지합니다.

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

3-3: CustomerService 쿼리 키 경로가 중앙 모듈로 올바르게 업데이트되었습니다.
키 관리가 통합되어 유지보수성이 향상되었습니다.

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

2-2: managedProjectKey 쿼리 키 경로가 중앙 모듈로 올바르게 업데이트되었습니다.
다른 프로젝트 관련 훅들과 경로 구조가 일치합니다.

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

4-4: ActivityLog 쿼리 키 경로가 중앙 모듈로 올바르게 업데이트되었습니다.
기존 경로에서 통합된 queries/keys 모듈로의 전환이 적절히 반영되었습니다.

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

2-2:

Details

✅ Verification successful

쿼리 키 import 경로 통합을 승인합니다.

query key import를 중앙화하는 좋은 리팩토링입니다. 새로운 경로가 올바르게 작동하는지 확인해 주세요.

다음 스크립트로 새로운 import 경로가 유효한지 확인해 주세요:


🏁 Script executed:

#!/bin/bash
# Description: 새로운 query keys 파일이 존재하고 ReportData를 export하는지 확인

# 새로운 keys 파일 존재 확인
fd -t f "keys" src/hooks/queries

# ReportData export 확인
rg -A 3 "export.*ReportData" src/hooks/queries

Length of output: 273


쿼리 키 import 경로 통합 검증 완료

src/hooks/queries/keys.ts 파일이 존재하며 export const ReportData가 확인되어 새로운 import 경로가 올바르게 작동합니다. 변경 승인합니다.

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

2-2: 쿼리 키 import 경로 통합을 승인합니다.

일관된 리팩토링으로 코드 구조가 개선되었습니다.

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

3-3: 쿼리 키 import 경로 통합을 승인합니다.

알람 관련 쿼리 키 import가 성공적으로 중앙화되었습니다.

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

8-8: 쿼리 키 import 경로 통합을 승인합니다.

CustomerService 쿼리 키가 여러 곳에서 사용되고 있어 이 변경이 특히 중요합니다. 올바르게 리팩토링되었습니다.

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

3-3: 쿼리 키 import 경로 통합을 승인합니다.

import 경로 변경과 함께 코드 포맷팅도 개선되어 가독성이 향상되었습니다.

src/pages/admin/adminInquiries/adminInquiryList/AdminInquiryListPage.tsx (1)

1-2: Page 컴포넌트 단순 래퍼 구현 적절
AdminInquiryListPage가 단순히 AdminInquiryList를 렌더링하는 래퍼로서 역할을 명확히 분리하고 있습니다. 불필요한 로직 없이 구성 요소가 모듈화된 점을 승인합니다.

src/pages/admin/adminInquiries/adminInquiryWrite/AdminInquiryWritePage.tsx (1)

1-2: 작성 페이지 래퍼 컴포넌트 승인
AdminInquiryWritePageAdminInquiryAnswerWrite 컴포넌트를 직접 렌더링하는 단순 구조로, 명확하게 책임이 분리되어 있습니다.

src/pages/admin/adminInquiries/adminInquiryDetail/AdminInquiryDetailPage.tsx (1)

1-2: 상세 페이지 래퍼 컴포넌트 구조 확인
AdminInquiryDetailPageAdminInquiryDetail 컴포넌트를 단일 책임으로 처리하며, 추가 props 없이 작동하도록 설계되었습니다. 페이지 수준에서 캐싱, 로딩 상태 관리 등 추가 기능이 필요한지 검토했으며, 현재 구조는 적절합니다.

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

12-12: import 경로 변경이 올바르게 적용되었습니다.

쿼리 키 구조의 리팩토링에 맞춰 import 경로가 중앙집중화된 구조로 변경되었습니다.


14-14: 타입을 export로 변경한 것이 좋습니다.

State 타입을 export하여 다른 모듈에서 재사용 가능하도록 만든 것은 좋은 변경사항입니다.

src/pages/admin/adminInquiries/AdminInquiries.tsx (1)

1-5: CommonAdminPage 컴포넌트 사용으로 코드가 간소화되었습니다.

공통 컴포넌트를 활용하여 일관성을 높이고 코드 중복을 줄인 좋은 리팩토링입니다.

src/components/admin/adminInquiry/AdminInquiryList.tsx (1)

17-25: 문의 목록 렌더링 로직이 잘 구현되었습니다.

데이터 매핑과 컴포넌트 구조가 깔끔하게 작성되었습니다.

src/components/admin/adminInquiry/AdminInquiryDetail.styled.ts (2)

4-4: 기존 스피너 스타일 컴포넌트를 재사용하는 것이 좋습니다.

일관성을 유지하기 위해 기존의 SpinnerWrapperStyled를 재사용한 것은 좋은 접근입니다.


6-12: 컨테이너 스타일링이 적절합니다.

Flexbox를 사용한 레이아웃과 적절한 간격 설정으로 깔끔한 UI 구조를 제공합니다.

src/components/admin/adminInquiry/AdminInquiryList.styled.ts (1)

1-15: LGTM! 스타일 컴포넌트 구조가 깔끔합니다.

기존 스피너 컴포넌트를 재사용하고 새로운 레이아웃 컴포넌트들을 명확하게 정의했습니다. 컨테이너와 래퍼의 역할 분리도 적절합니다.

src/components/admin/adminInquiry/AdminInquiryAnswerWrite.styled.ts (1)

1-43: LGTM! 전반적인 스타일 구조가 잘 구성되어 있습니다.

기존 컴포넌트들을 적절히 확장하여 일관된 디자인 시스템을 유지하고 있습니다. 테마 변수 사용도 적절합니다.

src/routes/AdminRoutes.tsx (3)

64-69: Suspense wrapper 추가가 좋습니다.

Lazy loading을 위한 Suspense wrapper 추가로 성능이 개선되었습니다. 스피너 fallback도 적절하게 설정되어 있습니다.


36-56: 문의 관련 컴포넌트의 lazy loading 구현이 적절합니다.

새로운 문의 관련 컴포넌트들이 올바르게 lazy loading으로 설정되어 있고, 컴포넌트 명명도 일관성 있게 되어 있습니다.


125-142: 중첩 라우팅 구조가 잘 설계되었습니다.

문의 관련 라우팅이 기존 공지사항, FAQ와 유사한 패턴으로 일관성 있게 구현되어 있습니다. 답변 작성과 수정을 위한 중첩 라우트도 적절하게 설계되어 있습니다.

src/models/inquiry.ts (3)

10-17: AdminInquiry 인터페이스가 잘 설계되었습니다.

관리자 문의 목록에 필요한 핵심 필드들이 적절하게 정의되어 있고, 타입 안전성이 확보되어 있습니다.


19-25: API 응답 인터페이스가 일관성 있게 구현되었습니다.

ApiCommonType을 확장하여 기존 API 응답 패턴과 일관성을 유지하고 있으며, 제네릭 타입 활용도 적절합니다.


27-30: InquiryAnswerBody 인터페이스가 API 요구사항과 일치합니다.

답변 제출/수정 시 필요한 필드들이 정확하게 정의되어 있고, AdminInquiryAnswerWrite 컴포넌트에서 사용하는 구조와 일치합니다.

src/components/admin/adminInquiry/AdminInquiryDetailContent.tsx (4)

13-16: 이미지 모달 상태 관리가 적절합니다.

이미지 모달을 위한 상태 구조가 명확하고, 필요한 정보(열림 상태와 URL)를 효율적으로 관리하고 있습니다.


26-43: 이미지 표시 및 확대 기능이 잘 구현되었습니다.

이미지 배열을 적절하게 렌더링하고, 사용자 가이드 메시지도 조건부로 표시하여 UX가 우수합니다. 키 prop도 올바르게 설정되어 있습니다.


45-61: 이미지 모달 구현이 사용자 친화적입니다.

모달 클릭으로 닫기 기능과 사용자 안내 메시지가 잘 구현되어 있어 직관적인 사용자 경험을 제공합니다.


22-24: 문의 정보 표시가 적절합니다.

카테고리와 제목을 결합한 헤더 형식과 사용자 정보 및 생성일시 표시가 관리자 인터페이스에 적합하게 구성되어 있습니다.

src/components/admin/adminInquiry/AdminInquiryDetail.tsx (2)

1-7: 임포트 구문이 깔끔하게 정리되어 있습니다.

모든 필요한 의존성이 적절히 임포트되었고, 타입 안전성을 위한 TypeScript 사용이 잘 되어 있습니다.


41-50: Outlet context 데이터 구조가 잘 설계되었습니다.

중첩 라우팅을 통해 하위 컴포넌트에 필요한 데이터와 함수들을 효율적으로 전달하고 있습니다.

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

32-41: API 함수 구조가 일관성 있게 잘 구현되었습니다.

POST와 PATCH 함수 모두 동일한 InquiryAnswerBody 타입을 사용하고 적절한 HTTP 메서드를 사용하고 있습니다.

Also applies to: 43-52

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

57-61: useQuery 설정이 적절합니다.

ID가 있을 때만 쿼리를 활성화하는 enabled 조건과 적절한 쿼리 키 사용이 잘 구현되었습니다.

src/components/admin/adminInquiry/AdminInquiryAnswer.styled.ts (1)

11-15: 스타일 컴포넌트 확장이 효율적입니다.

기존 컴포넌트를 확장하여 코드 중복을 방지하고 일관성을 유지하는 좋은 접근법입니다.

src/components/admin/adminInquiry/AdminInquiry.styled.ts (3)

1-3: 라이브러리 import 구조 적절
react-router-dom과 styled-components import 순서가 가독성에 적합합니다.


17-20: 카테고리 스타일 적절
폰트 크기와 굵기 설정이 의도대로 적용되어 있으며, UI 일관성을 잘 유지하고 있습니다.


29-41: 답변 상태 스타일링 적절
$hasAnswer 프로퍼티를 기반으로 색상과 배경을 조건부로 적용한 구현이 명확합니다.

src/components/admin/adminInquiry/AdminInquiryDetailContent.styled.ts (9)

1-8: 라이브러리 및 내부 컴포넌트 import
외부 styled-components와 내부 버튼, 모달 이미지 컴포넌트를 잘 가져오고 있습니다.


10-15: 컨테이너 스타일 적절
width, padding, border, border-radius 설정이 문의 상세 컨텐츠 영역에 적합합니다.


19-21: 헤더 래퍼 스타일 적절
마진으로 하단 여백을 확보해 헤더와 본문을 구분한 점이 좋습니다.


23-27: 제목 스타일 적절
폰트 크기, 굵기, 여백 설정으로 시멘틱한 제목 강조가 잘 구현되었습니다.


29-33: 정보 래퍼 스타일 적절
Flexbox와 gap으로 정보 항목 간 간격을 일관되게 적용한 점이 인상적입니다.


35-38: 정보 텍스트 스타일 적절
플레이스홀더 색상을 활용해 부차적 정보임을 명확히 표현했습니다.


40-43: 삭제 버튼 스타일 상속
SendButton에서 상속받아 폰트 크기와 패딩만 조정한 것은 DRY 원칙에 부합합니다.


45-48: 본문 컨텐츠 스타일 적절
폰트 크기와 넓이 설정이 본문 가독성을 고려한 합리적인 선택입니다.


56-58: 메시지 래퍼 스타일 적절
폰트 크기로 부가 설명을 구분하는 방식이 명확합니다.

Comment on lines +16 to +17
const [answer, setAnswer] = useState<string>('');
const selectButton: LinkType = answer === null ? '작성하기' : '수정하기';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

버튼 선택 로직의 타입 불일치를 수정하세요.

answer 상태가 string으로 타입이 지정되어 있는데 null과 비교하고 있습니다. answerData가 없는 경우를 올바르게 처리해야 합니다.

-  const [answer, setAnswer] = useState<string>('');
-  const selectButton: LinkType = answer === null ? '작성하기' : '수정하기';
+  const [answer, setAnswer] = useState<string | null>(null);
+  const selectButton: LinkType = !answer || answer.trim() === '' ? '작성하기' : '수정하기';
🤖 Prompt for AI Agents
In src/components/admin/adminInquiry/AdminInquiryAnswer.tsx around lines 16 to
17, the code compares the string-typed state variable 'answer' to null, which is
a type mismatch. To fix this, adjust the condition to check if 'answer' is an
empty string instead of null, or modify the state type to include null if that
is intended. Ensure the button selection logic correctly reflects whether
'answer' has meaningful content by using a proper check like answer === '' or
answer.length === 0.

Comment on lines 41 to 49
const handleSubmitAnswer = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();

if (isWrite) {
postInquiryAnswerMutate.mutate({ id, answer: answer });
} else {
patchInquiryAnswerMutate.mutate({ id, answer: answer });
}
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

입력 검증과 로딩 상태 처리가 필요합니다.

답변 제출 시 빈 값 검증과 mutation 진행 중 로딩 상태 처리가 없습니다. 사용자 경험 개선을 위해 추가하는 것이 좋겠습니다.

  const handleSubmitAnswer = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
+   
+   if (!answer.trim()) {
+     return;
+   }

    if (isWrite) {
      postInquiryAnswerMutate.mutate({ id, answer: answer });
    } else {
      patchInquiryAnswerMutate.mutate({ id, answer: answer });
    }
  };

또한 버튼에 로딩 상태를 반영하는 것을 고려해보세요:

+ const isLoading = postInquiryAnswerMutate.isPending || patchInquiryAnswerMutate.isPending;

          <S.InquiryAnswerWriteButton type='submit'
+           disabled={isLoading}
          >
            <S.InquiryAnswerWriteButtonSpan>
-             답변하기
+             {isLoading ? '처리 중...' : '답변하기'}
            </S.InquiryAnswerWriteButtonSpan>
          </S.InquiryAnswerWriteButton>
📝 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
const handleSubmitAnswer = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (isWrite) {
postInquiryAnswerMutate.mutate({ id, answer: answer });
} else {
patchInquiryAnswerMutate.mutate({ id, answer: answer });
}
};
// --- handleSubmitAnswer with empty-string check ---
const handleSubmitAnswer = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// Prevent submitting empty or whitespace-only answers
if (!answer.trim()) {
return;
}
if (isWrite) {
postInquiryAnswerMutate.mutate({ id, answer: answer });
} else {
patchInquiryAnswerMutate.mutate({ id, answer: answer });
}
};
// --- derive a combined loading flag for both mutations ---
const isLoading =
postInquiryAnswerMutate.isPending ||
patchInquiryAnswerMutate.isPending;
{/* ...later in your JSX... */}
<S.InquiryAnswerWriteButton
type='submit'
disabled={isLoading}
>
<S.InquiryAnswerWriteButtonSpan>
{isLoading ? '처리 중...' : '답변하기'}
</S.InquiryAnswerWriteButtonSpan>
</S.InquiryAnswerWriteButton>
🤖 Prompt for AI Agents
In src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx around lines 41
to 49, the handleSubmitAnswer function lacks input validation for empty answers
and does not handle loading states during mutation. Add a check to prevent
submission if the answer is empty, and implement loading state management to
disable the submit button and show a loading indicator while the mutation is in
progress. Update the button component to reflect the loading state accordingly.

);
}

if (!data) return;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

데이터 없음 처리가 부족합니다.

데이터가 없을 때 아무것도 반환하지 않는 대신 사용자에게 명확한 메시지를 표시해야 합니다.

- if (!data) return;
+ if (!data) {
+   return (
+     <S.AdminInquiryDetailContainer>
+       <div>문의 데이터를 찾을 수 없습니다.</div>
+     </S.AdminInquiryDetailContainer>
+   );
+ }
📝 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
if (!data) return;
if (!data) {
return (
<S.AdminInquiryDetailContainer>
<div>문의 데이터를 찾을 수 없습니다.</div>
</S.AdminInquiryDetailContainer>
);
}
🤖 Prompt for AI Agents
In src/components/admin/adminInquiry/AdminInquiryDetail.tsx at line 36, the code
currently returns nothing when data is absent, which provides no feedback to the
user. Modify this to render a clear and user-friendly message indicating that no
data is available, ensuring the UI communicates this state effectively.

Comment on lines 36 to 42
setTimeout(() => {
if (id) {
return navigate(`/admin/inquiries/detail/${id}`);
} else {
return navigate(-1);
}
}, 1000);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

네비게이션 로직에 잠재적 문제가 있습니다.

setTimeout을 사용한 지연 네비게이션은 사용자가 페이지를 빠르게 떠날 경우 메모리 누수를 일으킬 수 있습니다.

+ const [timeoutId, setTimeoutId] = useState<NodeJS.Timeout | null>(null);
+
+ useEffect(() => {
+   return () => {
+     if (timeoutId) {
+       clearTimeout(timeoutId);
+     }
+   };
+ }, [timeoutId]);

  const handleButtonState = (state: State, isDeleteApi: boolean = false) => {
    switch (state) {
      case 'success':
        // ... existing code ...
-       setTimeout(() => {
+       const id = setTimeout(() => {
          if (id) {
            return navigate(`/admin/inquiries/detail/${id}`);
          } else {
            return navigate(-1);
          }
        }, 1000);
+       setTimeoutId(id);
        break;

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

🤖 Prompt for AI Agents
In src/hooks/admin/useAdminInquiry.ts around lines 36 to 42, the use of
setTimeout for delayed navigation can cause memory leaks if the user leaves the
page quickly. To fix this, replace setTimeout with a safer approach such as
using a cleanup mechanism like clearTimeout in a useEffect cleanup function or
switching to a promise-based delay that can be cancelled on component unmount to
prevent the navigation callback from executing after the component is gone.

@YouD0313 YouD0313 added ⛏기능 기능 구현에 대한 라벨 🛠개선 성능 개선/리팩토링에 대한 라벨 labels Jun 9, 2025
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: 1

♻️ Duplicate comments (1)
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (1)

81-85: 🛠️ Refactor suggestion

로딩 상태를 버튼 UI에 반영하세요.

로딩 상태가 정의되어 있지만 버튼의 disabled 속성이나 텍스트에 반영되지 않아 사용자가 로딩 상태를 인지하기 어렵습니다.

- <S.InquiryAnswerWriteButton type='submit'>
+ <S.InquiryAnswerWriteButton type='submit' disabled={isLoading}>
    <S.InquiryAnswerWriteButtonSpan>
-     답변하기
+     {isLoading ? '처리 중...' : '답변하기'}
    </S.InquiryAnswerWriteButtonSpan>
  </S.InquiryAnswerWriteButton>
🧹 Nitpick comments (1)
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (1)

67-67: 옵셔널 체이닝을 사용하여 코드를 간소화할 수 있습니다.

현재의 조건문을 옵셔널 체이닝으로 간소화하면 더 읽기 쉬운 코드가 됩니다.

- if (inputRef && inputRef.current) {
+ if (inputRef.current) {
    inputRef.current.style.height = 'auto';
    inputRef.current.style.height = `${inputRef.current.scrollHeight}px`;
  }
🧰 Tools
🪛 Biome (1.9.4)

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 671973e and 7bfdc0c.

📒 Files selected for processing (7)
  • src/components/admin/adminInquiry/AdminInquiry.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiry.tsx (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryAnswer.tsx (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryList.tsx (1 hunks)
  • src/hooks/admin/useAdminInquiry.ts (1 hunks)
  • src/models/activityLog.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/models/activityLog.ts
  • src/components/admin/adminInquiry/AdminInquiryList.tsx
  • src/components/admin/adminInquiry/AdminInquiry.tsx
  • src/components/admin/adminInquiry/AdminInquiry.styled.ts
  • src/components/admin/adminInquiry/AdminInquiryAnswer.tsx
  • src/hooks/admin/useAdminInquiry.ts
🧰 Additional context used
🪛 Biome (1.9.4)
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx

[error] 67-67: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: accessibility-test
🔇 Additional comments (2)
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (2)

88-93: 이전 리뷰에서 지적된 ref 할당 문제가 해결되었습니다.

textarea 요소에 ref={inputRef}가 추가되어 auto-resize 기능이 정상적으로 작동할 것입니다.


55-57: 이전 리뷰에서 제안된 입력 검증이 추가되었습니다.

빈 답변 검증이 추가되어 사용자 경험이 개선되었습니다.

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: 0

🧹 Nitpick comments (2)
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (2)

71-74: Optional chaining을 사용하여 코드를 개선하세요.

Static analysis 도구에서 제안한 대로 optional chaining을 사용하면 더 간결하고 안전한 코드가 됩니다.

-    if (inputRef && inputRef.current) {
+    if (inputRef?.current) {
       inputRef.current.style.height = 'auto';
       inputRef.current.style.height = `${inputRef.current.scrollHeight}px`;
     }
🧰 Tools
🪛 Biome (1.9.4)

[error] 71-71: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


92-97: 접근성 개선을 위해 aria 속성을 추가하는 것을 고려해보세요.

textarea에 적절한 aria 속성을 추가하면 스크린 리더 사용자들에게 더 나은 경험을 제공할 수 있습니다.

         <S.InquiryAnswerWrite
           as='textarea'
           value={answer}
           ref={inputRef}
           onChange={handleChangeAnswer}
+          aria-label="문의 답변 내용"
+          placeholder="답변을 입력해주세요"
         ></S.InquiryAnswerWrite>
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7bfdc0c and 59f6af4.

📒 Files selected for processing (3)
  • src/components/admin/adminInquiry/AdminInquiryAnswer.tsx (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryAnswerWrite.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/admin/adminInquiry/AdminInquiryAnswerWrite.styled.ts
  • src/components/admin/adminInquiry/AdminInquiryAnswer.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx

[error] 71-71: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: accessibility-test
🔇 Additional comments (1)
src/components/admin/adminInquiry/AdminInquiryAnswerWrite.tsx (1)

1-104: 전반적으로 잘 구현된 컴포넌트입니다.

과거 리뷰에서 지적되었던 ref 할당, 로딩 상태 처리, 입력 검증 등의 이슈들이 모두 적절히 해결되었습니다. 관리자 문의 답변 작성/수정 기능이 깔끔하게 구현되어 있습니다.

🧰 Tools
🪛 Biome (1.9.4)

[error] 71-71: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

@YouD0313 YouD0313 merged commit 9b9ba14 into develop Jun 9, 2025
4 checks passed
@YouD0313 YouD0313 deleted the feat/#335 branch June 9, 2025 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⛏기능 기능 구현에 대한 라벨 🛠개선 성능 개선/리팩토링에 대한 라벨

Projects

None yet

Development

Successfully merging this pull request may close these issues.

관리자 문의

3 participants