Skip to content

Conversation

@Insung-Jo
Copy link

@Insung-Jo Insung-Jo commented Jun 18, 2025

📌 변경 사항 개요

  • 비밀번호 변경 컴포넌트 구현

✨ 요약

  • useConfirmPasswordValidation, mypageEndPoint, useChangePasswordMutation, mypageValidation, useNewPasswordValidation, PasswordChangeForm 등이 변경 및 추가 되었습니다.
  • useConfirmPasswordValidation 공통 훅으로 분리 (다른 페이지에도 적용 완료)
  • 비밀번호 변경 컴포넌트 구현 및 페이지 적용
  • 비밀번호 변경 관련
    • 엔드 포인트 추가
    • 타입 추가 및 API 작성
    • mutation 작성
    • 비밀번호 중복 검증 훅 구현

📝 상세 내용

  • 비밀번호 변경과 관련해서는 다른 사이트를 참고해서 작성하게 되었습니다.

useConfirmPasswordValidation

  • 다른 페이지에서도 사용하게 되어 공통으로 분리하였습니다.
// 변경 전
import { SignupFormData } from '../types/auth.type'

export function useConfirmPasswordValidation(getValues: () => SignupFormData) {
  return {
    required: '비밀번호를 한번 더 입력해 주세요.',
    validate: (value: string) => {
      const password = getValues().password
      return value === password || '비밀번호가 일치하지 않습니다'
    },
  }
}


// 변경 후
export function useConfirmPasswordValidation(getPasswordValue: () => string) {
  return {
    required: '비밀번호를 한번 더 입력해 주세요.',
    validate: (value: string) =>
      value === getPasswordValue() || '비밀번호가 일치하지 않습니다',
  }
}

컴포넌트 관련

PasswordChangeForm

  • 현재 비밀번호는 유효성 검사를 진행하지 않고 오로지 값 추적에만 사용합니다. (비밀번호 유출 위험 존재)
  • react-query를 사용하여 응답 성공과 에러를 관리 하였습니다.
  • reset()을 사용하여 제출 후 필드 값을 초기화 하였습니다.
  function onSubmit(data: PasswordChangeFormData) {
    changePassword(
      {
        password: data.password,
        newPassword: data.newPassword,
      },
      {
        onSuccess: () => {
          reset()
          showSuccess('비밀번호가 성공적으로 변경되었습니다!')
        },
      },
    )
  }

//...

        <Input
          labelName="현재 비밀번호"
          type="password"
          placeholder="비밀번호 입력"
          autoComplete="current-password"
          {...register('password')}
        />

검증 관련

useNewPasswordValidation

  • 검증은 단순하게 현재 비밀번호 값이랑 일치한지만 비교하게 작성했습니다. (위와 동일한 이유)
import { mypageValidation } from '../schemas/mypageValidation'

export function useNewPasswordValidation(getPasswordValue: () => string) {
  return {
    ...mypageValidation.password,
    validate: (value: string) => {
      if (value === getPasswordValue()) {
        return '현재 비밀번호와 동일한 비밀번호입니다.'
      }
      return true
    },
  }
}

🔗 관련 이슈

#79

🖼️ 스크린샷

2025-06-19.06-29-58.mp4

✅ 체크리스트

  • 브랜치 네이밍 컨벤션을 준수했습니다
  • 커밋 컨벤션을 준수했습니다
  • 코드가 프로젝트의 스타일 가이드라인을 준수합니다

💡 참고 사항

  • 새벽 작업이라 다소 오타가 있을 수 있습니다 해당 부분 확인 부탁 드립니다.
  • 해당 작업 까지 머지 되면 페이지 구현 진행할 거 같습니다.
  • 팀 미팅 참석을 기원하며..

Summary by CodeRabbit

  • 신규 기능

    • 마이페이지에서 프로필 정보 수정, 프로필 이미지 업로드, 비밀번호 변경이 가능한 폼과 관련 컴포넌트가 추가되었습니다.
    • 프로필 이미지 업로드 및 미리보기 기능이 제공됩니다.
    • 신규 아이콘(플러스, 흰색 펜, 닫기 원형) 컴포넌트가 추가되었습니다.
  • 버그 수정

    • 로그인 및 회원가입 에러 메시지 변수 오타가 수정되었습니다.
  • 스타일

    • 텍스트에 파란색을 적용하는 .Text-blue CSS 클래스가 추가되었습니다.
    • 읽기 전용 인풋에 회색 텍스트 및 기본 커서 스타일이 적용됩니다.
  • 리팩터

    • 인증 및 대시보드 관련 API 호출에서 HTTP 클라이언트가 일관되게 변경되었습니다.
    • 마이페이지 컴포넌트가 폼 컴포넌트로 분리되어 구조가 개선되었습니다.
  • 문서화 및 검증

    • 마이페이지 폼 입력값에 대한 유효성 검증 규칙이 추가되었습니다.

Insung-Jo added 30 commits June 18, 2025 16:02
@Insung-Jo Insung-Jo added this to the 2차 구현 기간 milestone Jun 18, 2025
@Insung-Jo Insung-Jo self-assigned this Jun 18, 2025
@Insung-Jo Insung-Jo added ✨Feat 기능 개발 🎨Style UI, 스타일 관련 수정 labels Jun 18, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jun 18, 2025

Walkthrough

마이페이지(프로필 수정/비밀번호 변경) 기능이 새롭게 도입되었습니다. 인증 및 대시보드 관련 HTTP 클라이언트가 authHttpClient로 통일되었고, 비밀번호 확인 및 유효성 검사 훅이 개선되었습니다. 기존 마이페이지 폼은 별도 컴포넌트로 분리되어 구조가 리팩토링되었습니다.

Changes

파일/그룹 변경 요약
src/app/features/auth/api/authApi.ts, src/app/shared/components/common/sidebar/modal/CreateDashboardModal.tsx, src/app/shared/hooks/useDashboard.ts, src/app/shared/lib/axios.ts 인증/대시보드 API에서 HTTP 클라이언트 명칭을 authHttpClient로 통일, 인증 토큰 부착 방식 단순화
src/app/features/auth/components/SignupForm.tsx, src/app/shared/hooks/useConfirmPasswordValidation.ts, src/app/features/auth/hooks/useConfirmPasswordValidation.ts 비밀번호 확인 훅 import 경로 변경 및 구현 위치 이동, 훅 파라미터 전달 방식 개선, 기존 훅 삭제 및 새로운 위치에 재정의
src/app/features/auth/hooks/useLoginMutation.ts, src/app/features/auth/hooks/useSignupMutation.ts 오타(severMessageserverMessage) 수정
src/app/features/mypage/api/mypageApi.ts, src/app/features/mypage/api/mypageEndPoint.ts, src/app/features/mypage/types/mypage.type.ts 마이페이지 API, 엔드포인트 상수, 타입 정의 파일 신설 및 함수/상수/타입 추가
src/app/features/mypage/components/ProfileEditForm.tsx, src/app/features/mypage/components/ProfileImageUpload.tsx, src/app/features/mypage/components/PasswordChangeForm.tsx 프로필 수정/이미지 업로드/비밀번호 변경 폼 컴포넌트 신설
src/app/features/mypage/hook/useChangePasswordMutation.ts, src/app/features/mypage/hook/useNewPasswordValidation.ts, src/app/features/mypage/hook/useUpdateMyProfileMutation.ts, src/app/features/mypage/hook/useUploadProfileImageMutation.ts, src/app/features/mypage/hook/useUserQurey.ts 마이페이지 관련 커스텀 훅(비밀번호 변경, 새 비밀번호 유효성, 프로필 수정, 이미지 업로드, 유저 정보 쿼리) 신설
src/app/features/mypage/schemas/mypageValidation.ts 닉네임/비밀번호 유효성 검사 스키마 신설
src/app/mypage/page.tsx 기존 인라인 폼 제거, ProfileEditForm/PasswordChangeForm 컴포넌트로 대체, 관련 import 정리
src/app/shared/components/Input.tsx readOnly일 때 입력창 스타일(Text-gray cursor-default) 추가
src/app/shared/components/common/CloseCircleIcon/CloseCircleIcon.tsx, src/app/shared/components/common/PlusIcon/PlusIcon.tsx, src/app/shared/components/common/WhitePenIcon/WhitePenIcon.tsx 공통 SVG 아이콘 컴포넌트(닫기, 플러스, 흰색 펜) 신설
src/app/globals.css .Text-blue 텍스트 색상 유틸리티 클래스 추가

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ProfileEditForm
  participant ProfileImageUpload
  participant useUploadProfileImageMutation
  participant useUpdateMyProfileMutation
  participant API

  User->>ProfileEditForm: 프로필 정보 입력 및 제출
  ProfileEditForm->>ProfileImageUpload: 이미지 선택
  ProfileEditForm->>useUploadProfileImageMutation: (이미지 변경 시) 이미지 업로드
  useUploadProfileImageMutation->>API: 이미지 업로드 요청
  API-->>useUploadProfileImageMutation: 업로드 결과(이미지 URL)
  ProfileEditForm->>useUpdateMyProfileMutation: 닉네임/이미지 URL로 프로필 수정
  useUpdateMyProfileMutation->>API: 프로필 수정 요청
  API-->>useUpdateMyProfileMutation: 수정 결과
  useUpdateMyProfileMutation-->>ProfileEditForm: 성공/실패 알림
  ProfileEditForm-->>User: 성공 토스트 및 페이지 새로고침
Loading
sequenceDiagram
  participant User
  participant PasswordChangeForm
  participant useChangePasswordMutation
  participant API

  User->>PasswordChangeForm: 현재/새 비밀번호 입력 및 제출
  PasswordChangeForm->>useChangePasswordMutation: 비밀번호 변경 요청
  useChangePasswordMutation->>API: 비밀번호 변경 API 호출
  API-->>useChangePasswordMutation: 성공/실패 응답
  useChangePasswordMutation-->>PasswordChangeForm: 성공/실패 알림
  PasswordChangeForm-->>User: 성공 토스트 및 폼 리셋
Loading

Possibly related issues

Possibly related PRs

Suggested labels

♻️Refactor

Suggested reviewers

  • dkslel1225

Poem

🐇
마이페이지 새단장, 폼이 쏙쏙 분리돼요
비밀번호 바꿀 때도, 프로필도 멋지게
파란 토끼가 춤추며,
"새로운 훅과 아이콘,
우리 팀의 봄이 왔어요!"
🖊️✨

Warning

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

🔧 ESLint

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

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

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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: 1

🧹 Nitpick comments (8)
src/app/features/mypage/hook/useUserQurey.ts (2)

1-11: 파일명 오타를 수정해주세요.

파일명에 오타가 있습니다: useUserQurey.tsuseUserQuery.ts로 수정이 필요합니다.

- // 파일명: useUserQurey.ts
+ // 파일명: useUserQuery.ts

7-7: 쿼리 키를 더 구체적으로 개선하는 것을 고려해보세요.

현재 ['loadUser'] 쿼리 키보다는 ['user', 'me']와 같이 더 구체적이고 계층적인 키를 사용하는 것이 쿼리 관리에 유리할 수 있습니다.

- queryKey: ['loadUser'],
+ queryKey: ['user', 'me'],
src/app/shared/components/common/WhitePenIcon/WhitePenIcon.tsx (1)

1-21: 아이콘 컴포넌트가 잘 구현되었습니다.

타입스크립트 타입 정의와 기본값 설정이 적절하며, SVG props 확장을 통한 유연성도 좋습니다.

다만 viewBox="0 0 24 24"가 고정되어 있어서 size가 24와 크게 다를 때 비례 조정이 어려울 수 있습니다. 큰 문제는 아니지만 향후 고려해볼 점입니다.

src/app/shared/components/common/CloseCircleIcon/CloseCircleIcon.tsx (1)

10-11: 불필요한 Fragment 래퍼를 제거하세요.

SVG 엘리먼트 하나만 반환하므로 Fragment가 필요하지 않습니다.

-    <>
       <svg
         width={size}
         height={size}
         viewBox="0 0 24 24"
         fill="none"
         {...props}
       >
         {/* ... SVG content ... */}
       </svg>
-    </>

Also applies to: 38-39

src/app/features/mypage/components/ProfileEditForm.tsx (2)

55-90: 폼 제출 로직이 복잡하지만 잘 구조화되어 있습니다.

이미지 업로드 후 프로필 업데이트 순서가 논리적이며, 에러 처리도 포괄적입니다. 다만 mutation hook과 컴포넌트에서 에러 처리 로직이 중복되는 부분이 있습니다.

에러 처리 로직을 공통 유틸리티로 추출하는 것을 고려해보세요:

+// utils/errorHandler.ts
+export const handleApiError = (error: unknown, fallbackMessage: string) => {
+  if (isAxiosError(error)) {
+    const serverMessage = (error.response?.data as { message?: string })?.message
+    const message = serverMessage ?? error.message ?? fallbackMessage
+    showError(message)
+  } else {
+    showError('알 수 없는 에러 발생')
+  }
+}

76-77: router.refresh() 사용에 대한 검토가 필요합니다.

React Query의 캐시 무효화를 사용하는 것이 더 효율적일 수 있습니다. 전체 페이지 새로고침보다는 쿼리 무효화를 고려해보세요.

-showSuccess('프로필 변경이 완료되었습니다.')
-router.refresh()
+showSuccess('프로필 변경이 완료되었습니다.')
+// React Query 캐시 무효화 사용 고려
+queryClient.invalidateQueries(['loadUser'])
src/app/features/mypage/components/ProfileImageUpload.tsx (2)

28-42: 파일 선택 로직이 잘 구현되었습니다. Optional chaining 사용을 고려해보세요.

파일 선택 및 미리보기 URL 생성, 상위 컴포넌트로의 파일 전달 로직이 모두 적절합니다. 같은 파일 재선택을 위한 input 값 초기화도 좋습니다.

다만 41번째 라인에서 optional chaining을 사용하면 더 간결해집니다:

-    if (inputRef.current) inputRef.current.value = ''
+    inputRef.current && (inputRef.current.value = '')

44-52: 메모리 누수 방지 로직이 훌륭합니다. Optional chaining 적용을 고려해보세요.

blob URL 확인 후 URL.revokeObjectURL 호출로 메모리 누수를 방지하는 로직이 잘 구현되어 있습니다. 상태 초기화도 적절합니다.

51번째 라인에서도 optional chaining을 사용할 수 있습니다:

-    if (inputRef.current) inputRef.current.value = ''
+    inputRef.current && (inputRef.current.value = '')
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b0156e8 and 254e3f3.

📒 Files selected for processing (27)
  • src/app/features/auth/api/authApi.ts (1 hunks)
  • src/app/features/auth/components/SignupForm.tsx (2 hunks)
  • src/app/features/auth/hooks/useConfirmPasswordValidation.ts (0 hunks)
  • src/app/features/auth/hooks/useLoginMutation.ts (1 hunks)
  • src/app/features/auth/hooks/useSignupMutation.ts (1 hunks)
  • src/app/features/mypage/api/mypageApi.ts (1 hunks)
  • src/app/features/mypage/api/mypageEndPoint.ts (1 hunks)
  • src/app/features/mypage/components/PasswordChangeForm.tsx (1 hunks)
  • src/app/features/mypage/components/ProfileEditForm.tsx (1 hunks)
  • src/app/features/mypage/components/ProfileImageUpload.tsx (1 hunks)
  • src/app/features/mypage/hook/useChangePasswordMutation.ts (1 hunks)
  • src/app/features/mypage/hook/useNewPasswordValidation.ts (1 hunks)
  • src/app/features/mypage/hook/useUpdateMyProfileMutation.ts (1 hunks)
  • src/app/features/mypage/hook/useUploadProfileImageMutation.ts (1 hunks)
  • src/app/features/mypage/hook/useUserQurey.ts (1 hunks)
  • src/app/features/mypage/schemas/mypageValidation.ts (1 hunks)
  • src/app/features/mypage/types/mypage.type.ts (1 hunks)
  • src/app/globals.css (1 hunks)
  • src/app/mypage/page.tsx (2 hunks)
  • src/app/shared/components/Input.tsx (2 hunks)
  • src/app/shared/components/common/CloseCircleIcon/CloseCircleIcon.tsx (1 hunks)
  • src/app/shared/components/common/PlusIcon/PlusIcon.tsx (1 hunks)
  • src/app/shared/components/common/WhitePenIcon/WhitePenIcon.tsx (1 hunks)
  • src/app/shared/components/common/sidebar/modal/CreateDashboardModal.tsx (2 hunks)
  • src/app/shared/hooks/useConfirmPasswordValidation.ts (1 hunks)
  • src/app/shared/hooks/useDashboard.ts (2 hunks)
  • src/app/shared/lib/axios.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/app/features/auth/hooks/useConfirmPasswordValidation.ts
🧰 Additional context used
🧠 Learnings (2)
src/app/features/auth/components/SignupForm.tsx (1)
Learnt from: Insung-Jo
PR: CoPlay-FE/coplan#57
File: src/app/features/auth/hooks/useSignupSubmit.ts:12-0
Timestamp: 2025-06-16T09:44:38.218Z
Learning: In src/app/features/auth/hooks/useSignupSubmit.ts, the developer intentionally uses SignupRequest type instead of SignupFormData for the submit function parameter to prevent sending unnecessary confirmPassword field to the API, aligning the function signature with server expectations.
src/app/shared/components/common/CloseCircleIcon/CloseCircleIcon.tsx (1)
Learnt from: Insung-Jo
PR: CoPlay-FE/coplan#78
File: src/app/shared/components/common/CloseCircleIcon/CloseCircleIcon.tsx:24-24
Timestamp: 2025-06-18T19:28:36.654Z
Learning: In the CloseCircleIcon component (src/app/shared/components/common/CloseCircleIcon/CloseCircleIcon.tsx), the stroke color for the X lines is intentionally hardcoded as "black" for contrast purposes, while the circle fill uses "currentColor" to adapt to themes. This is a deliberate design choice, not an oversight.
🧬 Code Graph Analysis (15)
src/app/shared/hooks/useDashboard.ts (1)
src/app/shared/types/dashboard.ts (1)
  • DashboardListResponse (13-17)
src/app/features/auth/hooks/useSignupMutation.ts (1)
src/app/shared/lib/toast.ts (1)
  • showError (4-4)
src/app/features/auth/api/authApi.ts (2)
src/app/features/auth/types/auth.type.ts (3)
  • LoginRequest (3-6)
  • LoginResponse (8-11)
  • SignupRequest (13-17)
src/app/features/auth/api/authEndpoint.ts (1)
  • AUTH_ENDPOINT (1-4)
src/app/features/auth/hooks/useLoginMutation.ts (1)
src/app/shared/lib/toast.ts (1)
  • showError (4-4)
src/app/features/auth/components/SignupForm.tsx (1)
src/app/shared/hooks/useConfirmPasswordValidation.ts (1)
  • useConfirmPasswordValidation (1-7)
src/app/features/mypage/hook/useNewPasswordValidation.ts (1)
src/app/features/mypage/schemas/mypageValidation.ts (1)
  • mypageValidation (1-15)
src/app/features/mypage/hook/useUserQurey.ts (1)
src/app/features/mypage/api/mypageApi.ts (1)
  • loadUser (12-15)
src/app/features/mypage/hook/useUpdateMyProfileMutation.ts (2)
src/app/features/mypage/types/mypage.type.ts (1)
  • UpdateProfileRequest (1-4)
src/app/features/mypage/api/mypageApi.ts (1)
  • updateMyProfile (17-25)
src/app/features/mypage/hook/useUploadProfileImageMutation.ts (2)
src/app/features/mypage/types/mypage.type.ts (1)
  • UploadProfileImageResponse (6-8)
src/app/features/mypage/api/mypageApi.ts (1)
  • uploadProfileImage (27-37)
src/app/features/mypage/hook/useChangePasswordMutation.ts (3)
src/app/features/mypage/types/mypage.type.ts (1)
  • PasswordChangeRequest (10-13)
src/app/features/mypage/api/mypageApi.ts (1)
  • changePassword (39-43)
src/app/shared/lib/toast.ts (1)
  • showError (4-4)
src/app/shared/lib/axios.ts (1)
src/app/features/auth/store/useAuthStore.ts (1)
  • useAuthStore (5-20)
src/app/features/mypage/components/PasswordChangeForm.tsx (7)
src/app/features/mypage/types/mypage.type.ts (1)
  • PasswordChangeRequest (10-13)
src/app/features/mypage/api/mypageApi.ts (1)
  • changePassword (39-43)
src/app/features/mypage/hook/useChangePasswordMutation.ts (1)
  • useChangePasswordMutation (10-25)
src/app/features/mypage/hook/useNewPasswordValidation.ts (1)
  • useNewPasswordValidation (3-13)
src/app/shared/hooks/useConfirmPasswordValidation.ts (1)
  • useConfirmPasswordValidation (1-7)
src/app/shared/lib/toast.ts (1)
  • showSuccess (3-3)
src/app/shared/lib/cn.ts (1)
  • cn (4-6)
src/app/features/mypage/api/mypageApi.ts (2)
src/app/features/mypage/api/mypageEndPoint.ts (1)
  • MYPAGE_ENDPOINT (1-5)
src/app/features/mypage/types/mypage.type.ts (3)
  • UpdateProfileRequest (1-4)
  • UploadProfileImageResponse (6-8)
  • PasswordChangeRequest (10-13)
src/app/features/mypage/components/ProfileEditForm.tsx (6)
src/app/features/mypage/hook/useUserQurey.ts (1)
  • useUserQuery (5-10)
src/app/features/mypage/hook/useUploadProfileImageMutation.ts (1)
  • useUploadProfileImageMutation (7-11)
src/app/features/mypage/hook/useUpdateMyProfileMutation.ts (1)
  • useUpdateMyProfileMutation (9-17)
src/app/shared/lib/toast.ts (2)
  • showSuccess (3-3)
  • showError (4-4)
src/app/features/mypage/components/ProfileImageUpload.tsx (1)
  • ProfileImageUpload (15-102)
src/app/features/mypage/schemas/mypageValidation.ts (1)
  • mypageValidation (1-15)
src/app/features/mypage/components/ProfileImageUpload.tsx (3)
src/app/shared/components/common/WhitePenIcon/WhitePenIcon.tsx (1)
  • WhitePenIcon (5-20)
src/app/shared/components/common/PlusIcon/PlusIcon.tsx (1)
  • PlusIcon (6-38)
src/app/shared/components/common/CloseCircleIcon/CloseCircleIcon.tsx (1)
  • CloseCircleIcon (5-40)
🪛 Biome (1.9.4)
src/app/features/mypage/components/ProfileImageUpload.tsx

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (37)
src/app/globals.css (1)

81-83: 새로운 텍스트 색상 유틸리티 클래스가 적절히 추가되었습니다.

다크/라이트 테마를 모두 지원하는 .Text-blue 클래스가 기존 패턴을 잘 따라 구현되었습니다.

src/app/shared/hooks/useDashboard.ts (2)

5-5: HTTP 클라이언트 import 업데이트가 적절합니다.

authHttpClient로의 import 변경이 전체 리팩토링과 일관성 있게 적용되었습니다.


24-26: 대시보드 API 호출이 올바르게 업데이트되었습니다.

authHttpClient.get을 사용하여 인증이 필요한 대시보드 데이터를 요청하는 것이 적절합니다.

src/app/shared/components/common/sidebar/modal/CreateDashboardModal.tsx (2)

7-7: HTTP 클라이언트 import 업데이트가 적절합니다.

authHttpClient로의 import 변경이 일관되게 적용되었습니다.


49-52: 대시보드 생성 API 호출이 올바르게 업데이트되었습니다.

인증이 필요한 대시보드 생성 요청에 authHttpClient.post를 사용하는 것이 적절합니다.

src/app/features/auth/api/authApi.ts (3)

8-11: 로그인 API 호출 검증 필요

authHttpClient를 사용하는 로그인 요청이 Authorization 헤더로 인해 실패할 수 있습니다.


16-19: 회원가입 API 호출 검증 필요

authHttpClient를 사용하는 회원가입 요청이 Authorization 헤더로 인해 실패할 수 있습니다.


1-1: ```shell
#!/usr/bin/env bash

Display the content of authApi.ts to verify login/signup implementation

file=$(rg -l "authApi.ts" . | head -n1)
echo "Found auth API file at: $file"
echo "---- authApi.ts content ----"
sed -n '1,200p' "$file"


</details>
<details>
<summary>src/app/features/auth/hooks/useLoginMutation.ts (1)</summary>

`25-29`: **타이포 수정이 정확합니다.**

`severMessage`를 `serverMessage`로 수정한 것이 올바릅니다. 변수명이 더 명확해졌습니다.

</details>
<details>
<summary>src/app/shared/hooks/useConfirmPasswordValidation.ts (1)</summary>

`1-7`: **재사용 가능한 훅 구현이 깔끔합니다.**

콜백 함수를 받아 비밀번호 확인 검증을 수행하는 구조가 잘 설계되었습니다. 이전 구현보다 더 간단하고 재사용성이 높아졌습니다.

</details>
<details>
<summary>src/app/shared/components/common/PlusIcon/PlusIcon.tsx (1)</summary>

`1-38`: **아이콘 컴포넌트 구현이 표준적입니다.**

SVG 프로퍼티를 적절히 확장하고 재사용 가능한 구조로 잘 작성되었습니다. `currentColor` 사용으로 테마 대응도 가능합니다.

</details>
<details>
<summary>src/app/features/mypage/schemas/mypageValidation.ts (1)</summary>

`1-15`: **검증 스키마가 적절하게 구성되었습니다.**

닉네임 정규식이 한글과 영문을 올바르게 검증하고, 비밀번호 최소 길이 요구사항도 적절합니다. 사용자 친화적인 한국어 에러 메시지도 좋습니다.

</details>
<details>
<summary>src/app/features/auth/hooks/useSignupMutation.ts (1)</summary>

`24-28`: **로그인 훅과 일관된 타이포 수정입니다.**

`severMessage`를 `serverMessage`로 수정하여 로그인 훅과 동일한 패턴으로 일관성을 유지했습니다.

</details>
<details>
<summary>src/app/shared/components/Input.tsx (1)</summary>

`48-48`: **읽기 전용 상태의 시각적 피드백이 잘 구현되었습니다.**

읽기 전용 입력 필드에 회색 텍스트와 기본 커서 스타일을 적용하여 사용자 경험을 개선했습니다. 비밀번호 입력과 일반 입력 모두에 일관되게 적용되어 좋습니다.



Also applies to: 76-76

</details>
<details>
<summary>src/app/features/auth/components/SignupForm.tsx (2)</summary>

`4-4`: **공통 훅으로 이동한 import 경로 변경이 적절합니다.**

`useConfirmPasswordValidation` 훅을 공통 위치로 이동하고 절대 경로로 import하는 것이 코드 재사용성과 유지보수성 측면에서 좋습니다.

---

`32-32`: **훅 사용법 개선이 보안성과 명확성을 향상시켰습니다.**

이전에 `getValues` 함수 전체를 전달하던 방식에서 `() => getValues('password')` 함수를 전달하는 방식으로 변경된 것이 더 명확하고 안전합니다. 필요한 값만 정확히 전달하는 방식이 좋습니다.

</details>
<details>
<summary>src/app/features/mypage/api/mypageEndPoint.ts (1)</summary>

`1-6`: **엔드포인트 정의가 깔끔하고 일관성 있게 구현되었습니다.**

환경 변수를 사용한 동적 엔드포인트 구성이 적절하며, REST 규칙을 잘 따르고 있습니다.


`NEXT_PUBLIC_TEAM_ID` 환경 변수가 undefined일 경우를 대비한 검증이 필요할 수 있습니다.


다음 스크립트로 환경 변수 사용을 확인해보겠습니다:

```shell
#!/bin/bash
# Description: Check if NEXT_PUBLIC_TEAM_ID is properly configured and used
# Expected: Find environment variable configuration and usage patterns

# Check for environment variable configuration
fd -e env -e local | xargs grep -l "NEXT_PUBLIC_TEAM_ID" 2>/dev/null || echo "No .env files found with NEXT_PUBLIC_TEAM_ID"

# Check for other usages of this environment variable
rg "NEXT_PUBLIC_TEAM_ID" -A 2 -B 2
src/app/features/mypage/hook/useUpdateMyProfileMutation.ts (1)

9-17: 잘 구현된 React Query 뮤테이션 훅입니다.

타입 정의가 명확하고 React Query의 모범 사례를 잘 따르고 있습니다. 에러 처리도 적절히 설정되어 있습니다.

src/app/features/mypage/hook/useUploadProfileImageMutation.ts (1)

7-11: 파일 업로드를 위한 뮤테이션 훅이 잘 구현되었습니다.

File 타입을 사용하여 이미지 업로드에 적합하게 구성되었고, 다른 뮤테이션 훅과 일관된 패턴을 따르고 있습니다.

src/app/features/mypage/hook/useNewPasswordValidation.ts (1)

3-13: 비밀번호 유효성 검사 훅이 잘 구현되었습니다.

콜백 함수를 사용하여 현재 비밀번호를 유연하게 가져올 수 있도록 설계되었고, 기존 validation을 확장하는 방식이 좋습니다. 다만 클라이언트 측 유효성 검사와 함께 서버 측에서도 동일한 검증이 이루어지는지 확인해 주세요.

src/app/shared/components/common/CloseCircleIcon/CloseCircleIcon.tsx (1)

1-40: 잘 구현된 아이콘 컴포넌트입니다.

TypeScript 인터페이스가 적절하게 정의되었고, props spreading과 기본값 설정이 잘 되어 있습니다. stroke 색상이 하드코딩된 것은 의도적인 디자인 선택임을 확인했습니다.

src/app/mypage/page.tsx (2)

6-7: 컴포넌트 분리를 통한 좋은 리팩토링입니다.

ProfileEditForm과 PasswordChangeForm으로 분리하여 관심사의 분리가 잘 되었고, 코드의 가독성과 유지보수성이 향상되었습니다.

Also applies to: 41-41, 43-43


36-38: 버튼 타입 명시가 잘 되었습니다.

type="button"을 명시적으로 지정하여 의도하지 않은 폼 제출을 방지할 수 있어 좋습니다.

src/app/features/mypage/hook/useChangePasswordMutation.ts (1)

13-23: 에러 처리 로직이 잘 구현되어 있습니다.

서버 메시지 추출과 폴백 메시지 처리가 적절하며, Axios 에러와 일반 에러를 구분해서 처리하는 점이 좋습니다.

src/app/features/mypage/types/mypage.type.ts (1)

1-13: 타입 정의가 명확하고 적절합니다.

인터페이스들이 각각의 용도에 맞게 잘 정의되어 있으며, profileImageUrl의 null 허용 등 실제 사용 시나리오를 잘 반영하고 있습니다.

src/app/features/mypage/components/PasswordChangeForm.tsx (3)

63-69: 현재 비밀번호 필드에 대한 설계 결정이 보안상 적절합니다.

현재 비밀번호에 유효성 검사를 하지 않는 것은 보안상 올바른 접근입니다. 서버에서 검증하도록 하는 것이 더 안전합니다.


76-84: 교차 필드 유효성 검사가 잘 구현되어 있습니다.

새 비밀번호와 확인 비밀번호 필드에서 서로를 트리거하는 로직이 사용자 경험을 향상시킵니다.


41-54: 폼 제출 로직과 성공 처리가 적절합니다.

성공 시 폼 리셋과 토스트 알림 표시가 좋은 사용자 경험을 제공합니다. mutation의 onSuccess 콜백 사용도 적절합니다.

src/app/features/mypage/api/mypageApi.ts (2)

27-37: 이미지 업로드 함수가 올바르게 구현되었습니다.

FormData를 사용한 파일 업로드 처리가 적절하며, 타입 안정성도 잘 유지되고 있습니다.


39-43: 비밀번호 변경 API 함수가 간결하고 명확합니다.

void 반환 타입과 PUT 메서드 사용이 적절하며, 타입 안정성이 보장되고 있습니다.

src/app/features/mypage/components/ProfileEditForm.tsx (1)

44-53: useEffect를 사용한 폼 초기화 로직이 적절합니다.

비동기 사용자 데이터 로딩에 대응하는 방식이 좋으며, SSR 도입 예정이라는 주석도 유용합니다.

src/app/features/mypage/components/ProfileImageUpload.tsx (6)

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

필요한 의존성들이 올바르게 import되었고, Props 인터페이스가 명확하게 정의되어 있습니다. 한국어 주석으로 각 prop의 역할이 잘 설명되어 있습니다.


15-26: 상태 관리 로직이 적절합니다.

useRef와 useState 훅을 올바르게 사용하고 있으며, useEffect를 통한 상위 컴포넌트의 value prop과 내부 preview 상태 동기화가 잘 구현되어 있습니다.


54-60: 컨테이너 구조와 접근성이 잘 구현되었습니다.

적절한 크기 설정과 접근성을 위한 label-input 연결이 올바르게 구현되어 있습니다. 스타일링도 적절합니다.

참고: 정적 분석 도구에서 55-56라인에 대해 optional chain 사용을 제안했지만, 해당 라인에는 체이닝 연산이 없으므로 거짓 양성으로 판단됩니다.


61-79: 이미지 미리보기 UI가 훌륭하게 구현되었습니다.

조건부 렌더링, hover 효과가 있는 연필 아이콘 오버레이, Next.js의 최적화된 Image 컴포넌트 사용 등이 모두 적절하게 구현되어 있습니다. z-index 설정으로 레이어 순서도 올바르게 관리되고 있습니다.


81-90: 삭제 버튼 구현이 적절합니다.

조건부 렌더링으로 미리보기가 있을 때만 삭제 버튼을 표시하고, 적절한 positioning과 hover 효과가 구현되어 있습니다. button 타입도 올바르게 설정되었습니다.


92-102: 파일 input 구현이 표준적이고 적절합니다.

숨겨진 파일 input, 이미지 파일만 허용하는 accept 속성, ref를 통한 프로그래매틱 접근 등이 모두 올바르게 구현되어 있습니다.

Comment on lines +5 to 21
const authHttpClient = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
})

api.interceptors.request.use(
authHttpClient.interceptors.request.use(
(config) => {
const token = useAuthStore.getState().accessToken
const publicPaths = [AUTH_ENDPOINT.LOGIN, AUTH_ENDPOINT.SIGNUP]
const isPulicPath = publicPaths.some((path) => config.url?.includes(path))

if (!isPulicPath && token) {
if (token) {
config.headers.Authorization = `Bearer ${token}`
}

return config
},
(error) => {
return Promise.reject(error)
},
)
Copy link

@coderabbitai coderabbitai bot Jun 18, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Verification correct

인증 엔드포인트에 Authorization 헤더가 추가되는 문제를 확인해야 합니다.

요청 인터셉터가 단순화되면서 모든 요청에 토큰이 있으면 Authorization 헤더를 추가하도록 변경되었습니다. 하지만 로그인/회원가입 엔드포인트는 일반적으로 Authorization 헤더가 없어야 합니다.

이 변경으로 인해 인증 API 호출이 실패할 수 있습니다.

다음 스크립트로 인증 엔드포인트 사용 현황을 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# 인증 엔드포인트에서 authHttpClient 사용을 확인하고 잠재적 문제점을 파악합니다.

echo "=== 인증 API 엔드포인트 확인 ==="
rg -A 3 "AUTH_ENDPOINT" --type ts

echo -e "\n=== authHttpClient를 사용하는 인증 관련 함수들 ==="
rg -A 10 "authHttpClient\.post.*login|authHttpClient\.post.*signup" --type ts

Length of output: 1279


인증 엔드포인트에 Authorization 헤더가 추가되는 문제를 확인해야 합니다.

요청 인터셉터가 단순화되면서 모든 요청에 토큰이 있으면 Authorization 헤더를 추가하도록 변경되었습니다. 하지만 로그인/회원가입 엔드포인트는 일반적으로 Authorization 헤더가 없어야 합니다.

이 변경으로 인해 인증 API 호출이 실패할 수 있습니다.

다음 스크립트로 인증 엔드포인트 사용 현황을 확인해보겠습니다:

#!/bin/bash
# 인증 엔드포인트에서 authHttpClient 사용을 확인하고 잠재적 문제점을 파악합니다.

echo "=== 인증 API 엔드포인트 확인 ==="
rg -A 3 "AUTH_ENDPOINT" --type ts

echo -e "\n=== authHttpClient를 사용하는 인증 관련 함수들 ==="
rg -A 10 "authHttpClient\.post.*login|authHttpClient\.post.*signup" --type ts
🤖 Prompt for AI Agents
In src/app/shared/lib/axios.ts between lines 5 and 21, the request interceptor
adds the Authorization header to all requests if a token exists, which causes
issues for authentication endpoints like login and signup that should not
include this header. To fix this, modify the interceptor to check the request
URL and exclude adding the Authorization header for authentication endpoints
before returning the config.

Copy link
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.

@Insung-Jo 네, 리다이렉트 기능 구현 시 인증 플로우가 개선될 예정이군요. 현재 상태를 이해했습니다. 감사합니다!

(・ω・) ✨


✏️ Learnings added
Learnt from: Insung-Jo
PR: CoPlay-FE/coplan#80
File: src/app/shared/lib/axios.ts:5-21
Timestamp: 2025-06-19T03:57:11.459Z
Learning: 프로젝트에서 axios 인터셉터의 인증 헤더 처리는 현재 모든 요청에 토큰을 추가하는 상태이며, 리다이렉트 기능 구현 시 적절히 개선될 예정입니다.

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
Contributor

@dkslel1225 dkslel1225 left a comment

Choose a reason for hiding this comment

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

비밀번호 변경 컴포넌트 구현 수고하셨습니다!

@Insung-Jo Insung-Jo merged commit 32cba40 into feature/mypage Jun 19, 2025
1 check passed
@coderabbitai coderabbitai bot mentioned this pull request Jun 22, 2025
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨Feat 기능 개발 🎨Style UI, 스타일 관련 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants