Skip to content

Conversation

@YouD0313
Copy link
Collaborator

@YouD0313 YouD0313 commented Jun 30, 2025

구현내용

관리자 문의 조회 기능 구현

연관이슈

close #346

Summary by CodeRabbit

  • 신규 기능

    • 관리자 문의 목록에 닉네임 및 날짜 범위로 필터링할 수 있는 검색/조회 UI가 추가되었습니다.
    • 문의 목록 필터링 시 URL 쿼리 파라미터를 통해 조건이 동기화됩니다.
    • 프로필에서 깃허브 링크를 수정할 수 있는 기능이 추가되었습니다.
    • 깃허브 링크 수정 후 성공 및 실패 모달이 구현되었습니다.
  • 버그 수정

    • 날짜 입력 시 유효성 검사 및 오류 메시지 모달이 추가되어 잘못된 입력에 대한 안내가 제공됩니다.
  • 스타일

    • 관리자 문의 목록 및 조회 UI의 스타일이 개선되었습니다.
    • 사용자 닉네임 클릭 시 드롭다운 및 인터랙션 효과가 적용되었습니다.
  • 문서화

    • 날짜 입력 오류에 대한 안내 메시지가 추가되었습니다.

@YouD0313 YouD0313 self-assigned this Jun 30, 2025
@YouD0313 YouD0313 added the ⛏기능 기능 구현에 대한 라벨 label Jun 30, 2025
@YouD0313 YouD0313 linked an issue Jun 30, 2025 that may be closed by this pull request
1 task
@YouD0313 YouD0313 added the 🛠개선 성능 개선/리팩토링에 대한 라벨 label Jun 30, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jun 30, 2025

"""

Walkthrough

관리자 문의하기 조회 기능이 추가 및 확장되었습니다. 검색 파라미터(유저 ID, 시작일, 종료일)를 통한 필터링, 관련 UI 컴포넌트, 스타일 및 API/훅 구조가 도입 및 변경되었습니다. 깃허브 링크 업데이트 기능도 추가되어 사용자 프로필 정보 갱신이 가능해졌습니다.

Changes

파일/경로 요약 변경 내용 요약
src/api/admin/customerService/inquiry.api.ts, src/hooks/admin/useGetAllInquiries.ts, src/models/inquiry.ts 문의 조회 API 및 훅에 검색 파라미터 타입(AdminInquiryChangeSearchParams) 도입, 함수 시그니처 변경
src/components/admin/adminInquiry/AdminInquiryList.tsx, src/components/admin/adminInquiry/AdminInquiry.tsx URL 쿼리 파라미터 기반 문의 리스트 필터링 및 클릭 이벤트로 파라미터 조작 추가
src/components/admin/adminInquiry/AdminInquiryListLookup.styled.ts, src/components/admin/adminInquiry/AdminInquiryListLookup.tsx 문의 리스트 필터/검색 UI 및 스타일 신규 추가, 날짜/닉네임 필터, 유효성 검사, 모달 처리
src/components/admin/adminInquiry/AdminInquiry.styled.ts, src/components/admin/adminInquiry/AdminInquiryList.styled.ts 문의 리스트/유저 관련 스타일 개선 및 구조 변경(버튼, 드롭다운 등)
src/components/admin/previewComponent/inquiresPreview/InquiresPreview.tsx 문의 미리보기 훅에 검색 파라미터 적용 방식 변경
src/constants/user/modalMessage.ts 날짜 필터 유효성 검사용 모달 메시지 상수 4종 추가
src/api/mypage.api.ts, src/hooks/user/useMyInfo.ts, src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx 깃허브 링크 PATCH API, 관련 커스텀 훅 및 성공 처리 로직 추가

Sequence Diagram(s)

sequenceDiagram
    participant Admin as Admin UI
    participant Lookup as AdminInquiryListLookup
    participant Router as react-router-dom
    participant Hook as useGetAllInquiries
    participant API as getAllInquiries API

    Admin->>Lookup: 필터 입력/제출
    Lookup->>Router: URL 쿼리 파라미터 set
    Router->>Hook: 파라미터 변경 감지
    Hook->>API: getAllInquiries(childSearchParams)
    API-->>Hook: 필터링된 문의 리스트 반환
    Hook-->>Admin: 문의 리스트 렌더링
Loading
sequenceDiagram
    participant User as 사용자
    participant Profile as ProfileGithubSuccess
    participant Hook as useGithubLink
    participant API as patchGithubLink

    User->>Profile: 깃허브 인증 성공 후 리다이렉트
    Profile->>Hook: patchGithubLinkMutate(githubUrl)
    Hook->>API: PATCH /user/github?githubUrl=
    API-->>Hook: 응답
    Hook-->>Profile: 성공/실패 모달 표시, 페이지 이동
Loading

Assessment against linked issues

Objective Addressed Explanation
관리자 문의하기 조회 기능 추가 (#346)
문의 조회 시 검색/필터(유저ID, 날짜) 기능 포함 (#346)
UI에서 필터 입력, 유효성 검사 및 결과 반영 (#346)
관련 API, 모델, 훅, 스타일 등 전반적 연동 (#346)

Suggested reviewers

  • layout-SY

Poem

문의를 찾아 hop hop hop,
필터와 모달이 깡총깡총,
날짜와 닉네임도 척척척,
관리자는 이제 걱정 뚝!
깃허브 링크도 쏙쏙쏙,
토끼 개발자, 오늘도 뿌듯! 🐰✨
"""

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-07-01T08_02_18_753Z-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 b475e93 and bbe20ec.

📒 Files selected for processing (2)
  • src/api/mypage.api.ts (2 hunks)
  • src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx
  • src/api/mypage.api.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: 5

🧹 Nitpick comments (6)
src/models/inquiry.ts (1)

10-14: 인터페이스 정의가 명확하고 적절합니다.

검색 파라미터를 위한 인터페이스가 잘 정의되어 있습니다. 다만 검색 조건이 선택적일 수 있으므로 옵셔널 프로퍼티를 고려해볼 수 있습니다.

선택적 개선사항으로 다음과 같이 옵셔널 프로퍼티를 사용할 수 있습니다:

export interface AdminInquiryChangeSearchParams {
-  userId: string;
-  startDate: string;
-  endDate: string;
+  userId?: string;
+  startDate?: string;
+  endDate?: string;
}
src/components/admin/previewComponent/inquiresPreview/InquiresPreview.tsx (1)

10-16: 빈 검색 파라미터 객체 생성이 적절합니다.

프리뷰 컴포넌트에서는 필터링이 필요하지 않으므로 빈 문자열로 초기화한 것이 적절합니다. 다만 hook의 시그니처 변경으로 인한 결합도 증가를 고려해볼 필요가 있습니다.

선택적 개선사항으로 hook에서 기본값을 제공하여 결합도를 줄일 수 있습니다:

// useGetAllInquiries에서 기본값 제공
export const useGetAllInquiries = (
  childSearchParams: AdminInquiryChangeSearchParams = {
    userId: '',
    startDate: '',
    endDate: ''
  }
) => {
  // ...
};
src/api/admin/customerService/inquiry.api.ts (1)

10-16: API 함수가 검색 파라미터를 지원하도록 올바르게 업데이트되었습니다.

함수가 검색 파라미터를 받아 쿼리 파라미터로 전달하는 구조가 RESTful 패턴에 맞게 구현되었습니다.

매개변수 명명에 대한 개선 제안:

export const getAllInquiries = async (
-  childSearchParams: AdminInquiryChangeSearchParams
+  searchParams: AdminInquiryChangeSearchParams
) => {
  try {
    const response = await httpClient.get<ApiAdminInquiry>(`/inquiry`, {
-      params: childSearchParams,
+      params: searchParams,
    });
    return response.data.data;
  } catch (e) {
    console.error('전체 문의 조회 에러', e);
    throw e;
  }
};

childSearchParams보다는 searchParams가 더 명확한 의미를 전달합니다.

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

26-34: 상호작용 요소 중첩을 피하는 것을 고려해보세요.

button 요소를 Link 내부에 중첩하는 것은 접근성 측면에서 문제가 될 수 있습니다. 이전 학습에서도 언급되었듯이 이런 경우 div를 사용하는 것이 더 의미적으로 올바릅니다.

-export const AdminInquiryUser = styled.button`
+export const AdminInquiryUser = styled.div`
   width: fit-content;
   font-size: 1.1rem;
   z-index: 1;
+  cursor: pointer;
   transition: color 0.1s ease-in-out;
   &:hover {
     color: ${({ theme }) => theme.color.lightnavy};
   }
 `;
src/components/admin/adminInquiry/AdminInquiryListLookup.tsx (2)

47-74: 성능 최적화 및 중복 검증 로직

handleChangeDate 함수가 매 렌더링마다 재생성되고 있으며, 날짜 검증 로직이 실시간 입력과 폼 제출 시 중복되어 있습니다.

useCallback을 사용하여 성능을 최적화하고 검증 로직을 통합하세요:

+import React, { useState, useCallback } from 'react';

+  const validateDateRange = useCallback((start: string, end: string) => {
+    if (start && end && start > end) {
+      return false;
+    }
+    return true;
+  }, []);

+  const handleChangeDate = useCallback((
     e: React.ChangeEvent<HTMLInputElement>,
     key: SearchParamsInquiryKeyType
-  ) => {
+  ) => {
     const value = e.currentTarget.value;
     
     setSearchFilters((prev) => {
       const newFilters = { ...prev, [key]: value };
+      
+      if (!validateDateRange(newFilters.startDate, newFilters.endDate)) {
+        handleModalOpen(
+          key === 'startDate' ? MODAL_MESSAGE.startDateInvalid : MODAL_MESSAGE.endDateInvalid
+        );
+        return prev;
+      }
+      
+      return newFilters;
     });
-  };
+  }, [validateDateRange, handleModalOpen]);

84-89: 사용자 경험 개선 제안

닉네임 입력 필드가 읽기 전용이지만 사용자에게 명확한 안내가 부족합니다. placeholder 텍스트만으로는 상호작용 방법이 명확하지 않을 수 있습니다.

사용자 가이드를 위한 시각적 힌트를 추가하는 것을 고려해보세요:

         <S.LookupUser
           type='text'
           value={nickname}
-          placeholder='닉네임을 클릭하세요.'
+          placeholder='문의 목록에서 닉네임을 클릭하여 선택하세요.'
           readOnly
+          style={{ cursor: 'default', backgroundColor: '#f5f5f5' }}
         />
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 453a09e and 1107d10.

📒 Files selected for processing (14)
  • src/api/admin/customerService/inquiry.api.ts (1 hunks)
  • src/api/mypage.api.ts (2 hunks)
  • src/components/admin/adminInquiry/AdminInquiry.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiry.tsx (2 hunks)
  • src/components/admin/adminInquiry/AdminInquiryList.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryList.tsx (2 hunks)
  • src/components/admin/adminInquiry/AdminInquiryListLookup.styled.ts (1 hunks)
  • src/components/admin/adminInquiry/AdminInquiryListLookup.tsx (1 hunks)
  • src/components/admin/previewComponent/inquiresPreview/InquiresPreview.tsx (1 hunks)
  • src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx (2 hunks)
  • src/constants/user/modalMessage.ts (1 hunks)
  • src/hooks/admin/useGetAllInquiries.ts (1 hunks)
  • src/hooks/user/useMyInfo.ts (2 hunks)
  • src/models/inquiry.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: YouD0313
PR: devpalsPlus/frontend#334
File: src/components/common/admin/title/AdminTitle.styled.ts:4-10
Timestamp: 2025-06-05T15:59:56.230Z
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).
src/components/admin/adminInquiry/AdminInquiryList.styled.ts (3)
Learnt from: YouD0313
PR: devpalsPlus/frontend#342
File: src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts:82-88
Timestamp: 2025-06-09T14:42:43.454Z
Learning: InquiryAnswerIconWrapper는 단일 ChevronRightIcon만 포함하며, 부모 InquiryAnswerContentWrapper가 이미 display: flex로 레이아웃을 제어하고 있어서 align-items: start 속성이 불필요할 수 있음
Learnt from: YouD0313
PR: devpalsPlus/frontend#334
File: src/components/common/admin/title/AdminTitle.styled.ts:4-10
Timestamp: 2025-06-05T15:59:56.230Z
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).
Learnt from: YouD0313
PR: devpalsPlus/frontend#334
File: src/components/common/admin/title/AdminTitle.styled.ts:4-10
Timestamp: 2025-06-05T16:04:56.917Z
Learning: YouD0313가 AdminTitle 컴포넌트에서 calc(100vw - 20rem)을 사용하는 이유: position: fixed 사용 시 내부 패딩 2rem이 제대로 적용되지 않아, 사이드바 너비(15rem)에 추가로 5rem을 더 빼서 총 20rem을 차감하여 레이아웃 문제를 해결함.
src/hooks/admin/useGetAllInquiries.ts (2)
Learnt from: layout-SY
PR: devpalsPlus/frontend#246
File: src/hooks/useAlarmList.ts:1-21
Timestamp: 2025-04-23T13:39:08.960Z
Learning: React Query의 useQuery 훅에서 queryFn으로 Promise를 반환하는 함수를 사용할 때는 불필요한 async/await을 사용하지 않는 것이 좋습니다. 예를 들어 `queryFn: async () => await getAlarmList()` 대신에 `queryFn: () => getAlarmList()`와 같이 직접 Promise를 반환하는 형태로 작성하는 것이 더 효율적입니다.
Learnt from: layout-SY
PR: devpalsPlus/frontend#246
File: src/hooks/useAlarmList.ts:1-21
Timestamp: 2025-04-23T13:39:08.960Z
Learning: React Query의 useQuery 훅에서 queryFn으로 Promise를 반환하는 함수를 사용할 때는 불필요한 async/await을 사용하지 않는 것이 좋습니다. 예를 들어 `queryFn: async () => await getAlarmList()` 대신에 `queryFn: () => getAlarmList()`와 같이 직접 Promise를 반환하는 형태로 작성하는 것이 더 효율적입니다.
src/components/admin/adminInquiry/AdminInquiry.styled.ts (2)
Learnt from: YouD0313
PR: devpalsPlus/frontend#255
File: src/components/common/customerService/CustomerServiceHeader.styled.ts:45-62
Timestamp: 2025-04-26T17:24:42.853Z
Learning: Interactive elements like buttons should not be nested inside other interactive elements like links (a tags). When creating a clickable UI inside a Link component, using a div instead of a button is more semantically correct.
Learnt from: YouD0313
PR: devpalsPlus/frontend#342
File: src/components/user/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts:82-88
Timestamp: 2025-06-09T14:42:43.454Z
Learning: InquiryAnswerIconWrapper는 단일 ChevronRightIcon만 포함하며, 부모 InquiryAnswerContentWrapper가 이미 display: flex로 레이아웃을 제어하고 있어서 align-items: start 속성이 불필요할 수 있음
src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx (4)
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
src/components/admin/adminInquiry/AdminInquiryList.tsx (4)
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
src/components/admin/adminInquiry/AdminInquiry.tsx (4)
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
src/components/admin/adminInquiry/AdminInquiryListLookup.tsx (4)
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.
🧬 Code Graph Analysis (8)
src/components/admin/previewComponent/inquiresPreview/InquiresPreview.tsx (2)
src/models/inquiry.ts (1)
  • AdminInquiryChangeSearchParams (10-14)
src/hooks/admin/useGetAllInquiries.ts (1)
  • useGetAllInquiries (6-19)
src/api/admin/customerService/inquiry.api.ts (1)
src/models/inquiry.ts (1)
  • AdminInquiryChangeSearchParams (10-14)
src/hooks/admin/useGetAllInquiries.ts (3)
src/models/inquiry.ts (1)
  • AdminInquiryChangeSearchParams (10-14)
src/hooks/queries/keys.ts (1)
  • Inquiries (52-54)
src/api/admin/customerService/inquiry.api.ts (1)
  • getAllInquiries (10-22)
src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx (2)
src/hooks/useModal.ts (1)
  • useModal (3-36)
src/hooks/user/useMyInfo.ts (1)
  • useGithubLink (92-108)
src/api/mypage.api.ts (2)
src/api/http.api.ts (1)
  • httpClient (80-80)
src/models/apiCommon.ts (1)
  • ApiCommonBasicType (6-8)
src/components/admin/adminInquiry/AdminInquiry.tsx (1)
src/constants/routes.ts (1)
  • ADMIN_ROUTE (35-58)
src/hooks/user/useMyInfo.ts (2)
src/api/mypage.api.ts (1)
  • patchGithubLink (57-66)
src/hooks/queries/keys.ts (1)
  • myInfoKey (12-14)
src/components/admin/adminInquiry/AdminInquiryListLookup.tsx (4)
src/hooks/useModal.ts (1)
  • useModal (3-36)
src/models/inquiry.ts (1)
  • AdminInquiryChangeSearchParams (10-14)
src/constants/user/modalMessage.ts (1)
  • MODAL_MESSAGE (1-39)
src/components/admin/adminInquiry/AdminInquiryList.tsx (1)
  • SearchParamsInquiryKeyType (9-9)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: accessibility-test
🔇 Additional comments (23)
src/api/mypage.api.ts (1)

1-1: Import 추가 확인됨

새로운 ApiCommonBasicType import가 적절히 추가되었습니다.

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

11-11: Import 추가 확인됨

새로운 patchGithubLink API 함수 import가 적절히 추가되었습니다.


92-108: 잘 구현된 커스텀 훅

useGithubLink 훅이 React Query 패턴을 올바르게 따르고 있습니다:

  • useMutation 사용이 적절함
  • 성공 시 캐시 무효화로 데이터 일관성 보장
  • 필요한 상태와 함수들을 적절히 반환

구현이 기존 패턴과 일치하며 재사용 가능한 구조입니다.

src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx (3)

7-7: Import 추가 확인됨

새로운 useGithubLink 훅 import가 적절히 추가되었습니다.


13-13: 훅 사용법 확인됨

useGithubLink 훅에서 필요한 mutation 함수를 적절히 추출하고 있습니다.


34-34: 의존성 배열 올바르게 업데이트됨

useEffect에서 사용하는 모든 외부 변수들이 의존성 배열에 포함되어 있습니다. 이전 학습 내용에 따라 올바르게 구현되었습니다.

src/constants/user/modalMessage.ts (1)

35-38: 날짜 유효성 검사를 위한 메시지가 적절히 추가되었습니다.

날짜 범위 입력 검증을 위한 사용자 친화적인 메시지들이 기존 패턴과 일관성 있게 추가되었습니다.

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

9-10: 레이아웃 변경이 새로운 조회 기능에 적합합니다.

수평 중앙 정렬에서 수직 컬럼 레이아웃으로 변경하여 문의 조회 필터 컴포넌트를 상단에 배치할 수 있도록 개선되었습니다.

src/components/admin/previewComponent/inquiresPreview/InquiresPreview.tsx (1)

7-7: 필요한 인터페이스 임포트가 추가되었습니다.

업데이트된 hook과의 호환성을 위해 적절히 임포트되었습니다.

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

3-3: 필요한 타입 임포트가 추가되었습니다.

새로운 검색 파라미터 인터페이스가 적절히 임포트되었습니다.

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

6-8: 매개변수 타입 정의가 잘 구현되었습니다.

AdminInquiryChangeSearchParams 타입을 받아서 필터링 기능을 지원하도록 적절히 구현되었습니다.


14-15: React Query queryKey와 queryFn 구현이 적절합니다.

검색 매개변수를 queryKey에 포함시켜서 매개변수 변경 시 자동으로 재요청이 발생하도록 올바르게 구현되었습니다. 이전 학습에서 언급된 불필요한 async/await도 사용하지 않아 효율적입니다.

src/components/admin/adminInquiry/AdminInquiry.tsx (3)

12-12: URL 매개변수 관리를 위한 훅 추가가 적절합니다.

사용자 필터링 기능을 위해 useSearchParams 훅을 추가한 것이 적절합니다.


14-27: 클릭 이벤트 처리가 올바르게 구현되었습니다.

preventDefaultstopPropagation을 사용하여 링크 내부의 버튼 클릭이 부모 링크를 트리거하지 않도록 적절히 처리되었습니다. URL 매개변수 업데이트 로직도 정확합니다.


34-38: 사용자 상호작용 요소가 적절히 구현되었습니다.

사용자 닉네임을 클릭 가능한 요소로 만들어 필터링 기능을 제공하는 것이 좋은 UX 개선입니다.

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

22-24: wrapper 컴포넌트 추가가 적절합니다.

상대 위치 지정을 위한 wrapper 컴포넌트 추가가 적절합니다.


36-48: 드롭다운 스타일이 잘 구현되었습니다.

드롭다운 컴포넌트의 절대 위치 지정과 스타일링이 적절히 구현되었습니다.

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

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

SearchParamsInquiryKeyType 타입 정의가 재사용성을 위해 적절히 추가되었습니다.


11-19: URL 매개변수 처리가 올바르게 구현되었습니다.

useSearchParams를 사용하여 필터링 매개변수를 추출하고 훅에 전달하는 로직이 적절히 구현되었습니다.


33-33: 조회 컴포넌트 추가가 적절합니다.

문의 목록 위에 AdminInquiryListLookup 컴포넌트를 추가하여 필터링 UI를 제공하는 것이 좋은 UX 개선입니다.

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

3-28: 날짜 입력 필드 스타일링이 잘 구현되었습니다.

날짜 입력 필드와 캘린더 피커에 대한 커스터마이징이 적절히 구현되었습니다. 특히 webkit 캘린더 피커 인디케이터를 투명하게 만든 것이 좋은 접근법입니다.


30-33: 폼 레이아웃이 적절합니다.

flexbox를 사용한 레이아웃이 조회 UI에 적합하게 구현되었습니다.


51-67: 아이콘 버튼 스타일링이 일관성 있게 구현되었습니다.

아이콘 wrapper와 버튼들의 스타일링이 테마 색상을 사용하여 일관성 있게 구현되었습니다.

Comment on lines 57 to 66
export const patchGithubLink = async (githubUrl: string) => {
try {
await httpClient.patch<ApiCommonBasicType>('/user/github', {
params: { githubUrl },
});
} catch (error) {
console.error('프로필 깃허브 업데이트: ', error);
throw error;
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

API 요청 구조 및 반환값 처리 개선 필요

현재 구현에서 몇 가지 문제점이 발견됩니다:

  1. params 속성 사용이 부적절할 수 있습니다 - PATCH 요청에서는 일반적으로 request body 또는 query parameter로 데이터를 전송합니다
  2. 응답 데이터를 반환하지 않아 호출부에서 성공 여부를 확인하기 어렵습니다

다음과 같이 수정을 권장합니다:

-export const patchGithubLink = async (githubUrl: string) => {
-  try {
-    await httpClient.patch<ApiCommonBasicType>('/user/github', {
-      params: { githubUrl },
-    });
-  } catch (error) {
-    console.error('프로필 깃허브 업데이트: ', error);
-    throw error;
-  }
-};
+export const patchGithubLink = async (githubUrl: string) => {
+  try {
+    const response = await httpClient.patch<ApiCommonBasicType>(
+      '/user/github',
+      { githubUrl }
+    );
+    return response.data;
+  } catch (error) {
+    console.error('프로필 깃허브 업데이트: ', error);
+    throw error;
+  }
+};

또는 query parameter로 전송하려면:

-    await httpClient.patch<ApiCommonBasicType>('/user/github', {
-      params: { githubUrl },
-    });
+    const response = await httpClient.patch<ApiCommonBasicType>(
+      `/user/github?githubUrl=${encodeURIComponent(githubUrl)}`
+    );
+    return response.data;
📝 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
export const patchGithubLink = async (githubUrl: string) => {
try {
await httpClient.patch<ApiCommonBasicType>('/user/github', {
params: { githubUrl },
});
} catch (error) {
console.error('프로필 깃허브 업데이트: ', error);
throw error;
}
};
export const patchGithubLink = async (githubUrl: string) => {
try {
const response = await httpClient.patch<ApiCommonBasicType>(
'/user/github',
{ githubUrl }
);
return response.data;
} catch (error) {
console.error('프로필 깃허브 업데이트: ', error);
throw error;
}
};
🤖 Prompt for AI Agents
In src/api/mypage.api.ts lines 57 to 66, the patchGithubLink function
incorrectly uses the 'params' property to send data in a PATCH request, which
should instead send the githubUrl in the request body or as query parameters.
Also, the function does not return the response, making it hard for callers to
verify success. Fix this by moving githubUrl into the request body (e.g., {
githubUrl }) and returning the awaited response from httpClient.patch so the
caller can handle the result.

Comment on lines 18 to 20

if (githubUrl) {
patchGithubLinkMutate(githubUrl);
Copy link

@coderabbitai coderabbitai bot Jun 30, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

비동기 처리 및 에러 핸들링 개선 필요

현재 구현에서 몇 가지 개선이 필요합니다:

  1. patchGithubLinkMutate는 비동기 함수이지만 await 없이 호출되고 있습니다
  2. mutation의 성공/실패 상태를 처리하지 않아 실제 API 호출 결과와 관계없이 성공 모달이 표시됩니다

다음과 같이 수정을 권장합니다:

-      if (githubUrl) {
-        patchGithubLinkMutate(githubUrl);
-        handleModalOpen(MODAL_MESSAGE.githubProfileSuccess);
-        setTimeout(() => {
-          navigate(`${ROUTES.mypage}/${ROUTES.mypageEdit}`, {
-            state: { githubUrl },
-          });
-        }, 1000);
-      }
+      if (githubUrl) {
+        patchGithubLinkMutate(githubUrl, {
+          onSuccess: () => {
+            handleModalOpen(MODAL_MESSAGE.githubProfileSuccess);
+            setTimeout(() => {
+              navigate(`${ROUTES.mypage}/${ROUTES.mypageEdit}`, {
+                state: { githubUrl },
+              });
+            }, 1000);
+          },
+          onError: () => {
+            handleModalOpen(MODAL_MESSAGE.githubProfileFail);
+            setTimeout(() => {
+              navigate(`${ROUTES.mypage}/${ROUTES.mypageEdit}`);
+            }, 1000);
+          }
+        });
+      }
📝 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 (githubUrl) {
patchGithubLinkMutate(githubUrl);
if (githubUrl) {
patchGithubLinkMutate(githubUrl, {
onSuccess: () => {
handleModalOpen(MODAL_MESSAGE.githubProfileSuccess);
setTimeout(() => {
navigate(`${ROUTES.mypage}/${ROUTES.mypageEdit}`, {
state: { githubUrl },
});
}, 1000);
},
onError: () => {
handleModalOpen(MODAL_MESSAGE.githubProfileFail);
setTimeout(() => {
navigate(`${ROUTES.mypage}/${ROUTES.mypageEdit}`);
}, 1000);
},
});
}
🤖 Prompt for AI Agents
In src/components/user/mypage/myProfile/editProfile/ProfileGithubSuccess.tsx
around lines 18 to 20, the patchGithubLinkMutate function is called without
awaiting its asynchronous result and lacks error handling. Modify the code to
await the patchGithubLinkMutate call and handle its promise properly by adding
try-catch or using then-catch to manage success and failure states, ensuring the
success modal only shows on successful mutation and errors are handled
gracefully.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

ProfileGithubSuccess.tsx에서 useEffect를 불러올 때 async를 사용중인데 문제가 되니?

Copy link

Choose a reason for hiding this comment

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

@YouD0313 useEffect에서 async를 사용하는 현재 패턴은 전혀 문제가 되지 않습니다!

useEffect(() => {
  (async () => {
    // 비동기 코드
  })();
}, []);

이런 즉시 실행 함수 표현식(IIFE) 패턴은 useEffect 내에서 비동기 코드를 사용할 때 매우 일반적이고 권장되는 방법입니다. useEffect 자체는 async 함수를 직접 받을 수 없기 때문에 이런 패턴을 사용하는 것이 정상입니다.

제가 이전 코멘트에서 지적한 문제는 async 사용이 아니라 patchGithubLinkMutate의 에러 핸들링 부족이었습니다. 현재 코드는 API 호출의 성공/실패 여부와 관계없이 항상 성공 모달을 표시하고 있어서, 실제로 API 호출이 실패하더라도 사용자에게는 성공했다고 잘못된 피드백을 주게 됩니다.

async 패턴 자체는 완전히 올바르게 사용하고 계십니다! 👍


🧠 Learnings used
Learnt from: layout-SY
PR: devpalsPlus/frontend#246
File: src/hooks/useAlarmList.ts:1-21
Timestamp: 2025-04-23T13:39:08.960Z
Learning: React Query의 useQuery 훅에서 queryFn으로 Promise를 반환하는 함수를 사용할 때는 불필요한 async/await을 사용하지 않는 것이 좋습니다. 예를 들어 `queryFn: async () => await getAlarmList()` 대신에 `queryFn: () => getAlarmList()`와 같이 직접 Promise를 반환하는 형태로 작성하는 것이 더 효율적입니다.

Learnt from: layout-SY
PR: devpalsPlus/frontend#246
File: src/hooks/useAlarmList.ts:1-21
Timestamp: 2025-04-23T13:39:08.960Z
Learning: React Query의 useQuery 훅에서 queryFn으로 Promise를 반환하는 함수를 사용할 때는 불필요한 async/await을 사용하지 않는 것이 좋습니다. 예를 들어 `queryFn: async () => await getAlarmList()` 대신에 `queryFn: () => getAlarmList()`와 같이 직접 Promise를 반환하는 형태로 작성하는 것이 더 효율적입니다.

Learnt from: layout-SY
PR: devpalsPlus/frontend#260
File: src/components/common/header/Header.tsx:30-32
Timestamp: 2025-04-30T06:28:07.990Z
Learning: testLiveAlarm 함수는 이미 내부적으로 에러 처리를 하고 Promise를 반환하므로, 컴포넌트에서 호출할 때 async/await과 try-catch 구문 없이 직접 호출해도 충분하다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#334
File: src/components/common/admin/title/AdminTitle.styled.ts:4-10
Timestamp: 2025-06-05T15:59:56.230Z
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).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

그럼 githubUrl 조건문처리와 다르다고 생각하는거니? 커스텀훅에서 처리하는게 맞다고 얘기하는거야?

Copy link

Choose a reason for hiding this comment

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

@YouD0313 좋은 질문입니다! 두 가지는 서로 다른 레벨의 검증이라고 생각합니다.

현재 상황 분석

1. githubUrl 조건문 처리 (클라이언트 사이드 검증)

  • URL 파라미터가 존재하는지 확인
  • 사용자가 올바른 경로로 왔는지 검증

2. API 호출 성공/실패 처리 (서버 통신 검증)

  • 실제 서버와의 통신 결과 확인
  • 네트워크 오류, 서버 오류 등을 처리

둘 다 필요한 이유

// 현재: githubUrl이 있어도 API 실패시 성공 모달이 표시됨
if (githubUrl) {
  patchGithubLinkMutate(githubUrl); // API 실패해도
  handleModalOpen(MODAL_MESSAGE.githubProfileSuccess); // 성공 모달 표시
}

처리 위치에 대한 견해

컴포넌트에서 처리하는 것이 더 적절하다고 생각합니다:

  • ✅ 각 컴포넌트마다 다른 성공/실패 UI 로직 구현 가능
  • ✅ 현재 Modal과 Navigation 로직이 컴포넌트에 종속됨
  • ✅ React Query의 onSuccess/onError 패턴과 일치

커스텀훅에서 처리하면 모든 컴포넌트가 동일한 에러 처리를 강제받게 되어 유연성이 떨어집니다.

결론: githubUrl 체크와 API 에러 처리는 모두 필요하며, 현재 구조에서는 컴포넌트의 onSuccess/onError 콜백 사용이 적절합니다.


🧠 Learnings used
Learnt from: layout-SY
PR: devpalsPlus/frontend#246
File: src/hooks/useAlarmList.ts:1-21
Timestamp: 2025-04-23T13:39:08.960Z
Learning: React Query의 useQuery 훅에서 queryFn으로 Promise를 반환하는 함수를 사용할 때는 불필요한 async/await을 사용하지 않는 것이 좋습니다. 예를 들어 `queryFn: async () => await getAlarmList()` 대신에 `queryFn: () => getAlarmList()`와 같이 직접 Promise를 반환하는 형태로 작성하는 것이 더 효율적입니다.

Learnt from: layout-SY
PR: devpalsPlus/frontend#246
File: src/hooks/useAlarmList.ts:1-21
Timestamp: 2025-04-23T13:39:08.960Z
Learning: React Query의 useQuery 훅에서 queryFn으로 Promise를 반환하는 함수를 사용할 때는 불필요한 async/await을 사용하지 않는 것이 좋습니다. 예를 들어 `queryFn: async () => await getAlarmList()` 대신에 `queryFn: () => getAlarmList()`와 같이 직접 Promise를 반환하는 형태로 작성하는 것이 더 효율적입니다.

Learnt from: layout-SY
PR: devpalsPlus/frontend#260
File: src/components/common/header/Header.tsx:30-32
Timestamp: 2025-04-30T06:28:07.990Z
Learning: testLiveAlarm 함수는 이미 내부적으로 에러 처리를 하고 Promise를 반환하므로, 컴포넌트에서 호출할 때 async/await과 try-catch 구문 없이 직접 호출해도 충분하다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#278
File: src/pages/login/LoginSuccess.tsx:13-24
Timestamp: 2025-05-11T09:39:02.041Z
Learning: useEffect 내에서 사용하는 모든 외부 변수(예: searchParams, storeLogin, navigate)는 의존성 배열에 포함되어야 합니다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#334
File: src/components/common/admin/title/AdminTitle.styled.ts:4-10
Timestamp: 2025-06-05T15:59:56.230Z
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).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

커스텀훅에서 처리된다면 컴포넌트에서 조건문이 필요할까?

Copy link

Choose a reason for hiding this comment

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

@YouD0313 정말 좋은 지적입니다! 맞습니다. 커스텀훅에서 전체 플로우를 처리한다면 컴포넌트의 조건문이 불필요해집니다.

현재 구조의 문제점

// 컴포넌트가 너무 많은 책임을 가짐
if (githubUrl) {
  patchGithubLinkMutate(githubUrl);
  handleModalOpen(MODAL_MESSAGE.githubProfileSuccess);
  // navigation logic...
} else {
  handleModalOpen(MODAL_MESSAGE.githubProfileFail);
  // navigation logic...
}

개선된 구조 제안

커스텀훅에서 전체 처리:

// useGithubProcess.ts
export const useGithubProcess = (onModalOpen, navigate) => {
  const { patchGithubLinkMutate } = useGithubLink();
  
  const handleGithubProcess = useCallback((githubUrl) => {
    if (!githubUrl) {
      onModalOpen(MODAL_MESSAGE.githubProfileFail);
      setTimeout(() => navigate(`${ROUTES.mypage}/${ROUTES.mypageEdit}`), 1000);
      return;
    }
    
    patchGithubLinkMutate(githubUrl, {
      onSuccess: () => {
        onModalOpen(MODAL_MESSAGE.githubProfileSuccess);
        setTimeout(() => navigate(`${ROUTES.mypage}/${ROUTES.mypageEdit}`, { state: { githubUrl } }), 1000);
      },
      onError: () => {
        onModalOpen(MODAL_MESSAGE.githubProfileFail);
        setTimeout(() => navigate(`${ROUTES.mypage}/${ROUTES.mypageEdit}`), 1000);
      }
    });
  }, []);
  
  return { handleGithubProcess };
};

컴포넌트는 단순해짐:

// ProfileGithubSuccess.tsx
export default function ProfileGithubSuccess() {
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const { isOpen, message, handleModalOpen, handleModalClose } = useModal();
  const { handleGithubProcess } = useGithubProcess(handleModalOpen, navigate);

  useEffect(() => {
    const githubUrl = searchParams.get('githubUrl');
    handleGithubProcess(githubUrl);
  }, [searchParams, handleGithubProcess]);

  return <Modal isOpen={isOpen} onClose={handleModalClose}>{message}</Modal>;
}

장점:

  • ✅ 관심사의 분리: 훅은 비즈니스 로직, 컴포넌트는 UI
  • ✅ 테스트 용이성: 각각 독립적으로 테스트 가능
  • ✅ 재사용성: 다른 컴포넌트에서도 동일한 로직 사용 가능
  • ✅ 컴포넌트 단순화: 조건문 제거

훌륭한 아키텍처 인사이트입니다! 👍


🧠 Learnings used
Learnt from: layout-SY
PR: devpalsPlus/frontend#260
File: src/components/common/header/Header.tsx:30-32
Timestamp: 2025-04-30T06:28:07.990Z
Learning: testLiveAlarm 함수는 이미 내부적으로 에러 처리를 하고 Promise를 반환하므로, 컴포넌트에서 호출할 때 async/await과 try-catch 구문 없이 직접 호출해도 충분하다.

Learnt from: YouD0313
PR: devpalsPlus/frontend#334
File: src/components/common/admin/title/AdminTitle.styled.ts:4-10
Timestamp: 2025-06-05T15:59:56.230Z
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).

@@ -1,3 +1,4 @@
import { ApiCommonBasicType } from '../models/apiCommon';
Copy link
Collaborator

Choose a reason for hiding this comment

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

type

@YouD0313 YouD0313 merged commit 1c3ea1b into develop Jul 1, 2025
4 checks passed
@YouD0313 YouD0313 deleted the feat/#346 branch July 1, 2025 12:59
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