Skip to content

Conversation

@hyeeuncho
Copy link
Member

@hyeeuncho hyeeuncho commented Jul 10, 2025

전화번호 인증 - 회원가입, 마이페이지

스크린샷 2025-07-10 오후 6 19 15

Summary by CodeRabbit

  • 신규 기능

    • 회원가입 및 프로필 수정 시 휴대폰 번호 인증(문자 인증번호 발송 및 확인) 기능이 추가되었습니다.
    • 휴대폰 인증 시 3분 타이머와 인증번호 입력 UI가 제공됩니다.
    • 인증 성공 시만 정보 수정 또는 가입이 가능합니다.
  • 개선 및 변경

    • 버튼 스타일이 개선되어 정렬 및 레이아웃이 향상되었습니다.
    • 이벤트 티켓 목록에서 이벤트의 온라인/오프라인 유형이 표시됩니다.
  • 버그 수정

    • 인증 실패 시 상세 오류 메시지가 안내됩니다.
  • 기타

    • 내부 에러 처리 및 API 응답 구조가 개선되었습니다.
    • 휴대폰 인증 관련 API 호출 및 훅이 정비되고, 인증 로직이 커스텀 훅으로 통합되어 관리가 용이해졌습니다.

@hyeeuncho hyeeuncho linked an issue Jul 10, 2025 that may be closed by this pull request
3 tasks
@coderabbitai
Copy link

coderabbitai bot commented Jul 10, 2025

Walkthrough

이 변경사항은 전화번호 인증 기능을 회원가입 및 프로필 수정 페이지에 통합합니다. 인증 코드 전송 및 확인을 위한 API와 훅이 추가 및 개선되었으며, UI에 타이머와 인증 입력란이 구현되었습니다. 또한, 에러 응답 구조가 확장되어 상세 오류 메시지 처리가 가능해졌습니다.

Changes

파일(들) 변경 요약
design-system/ui/Button.tsx Button 컴포넌트의 클래스에 정렬 및 레이아웃 관련 유틸리티 클래스 추가, padding 클래스의 반응형 적용
design-system/ui/buttons/TertiaryButton.tsx 비활성화(disabled) 상태에서의 스타일을 별도로 분리하여 조건부로 적용
src/entities/user/ui/ProfileInfo.tsx, src/pages/join/InfoInputPage.tsx 전화번호 인증 UI 및 로직 추가, 타이머 및 인증 입력 필드 구현, 인증 성공 시 상태 반영 및 버튼 활성화 제어
src/features/join/api/user.ts 인증 코드 전송 및 확인 API 함수의 파라미터 구조를 객체로 변경, 반환값을 response data로 수정
src/features/join/hooks/useUserHook.ts 인증 관련 mutation 훅의 파라미터 구조 변경, AxiosError 타입 명시 및 상세 오류 메시지 처리 로직 추가
src/pages/menu/ui/MyTicketPage.tsx EventCard에 onlineType prop 전달 추가
src/shared/types/api/apiResponse.ts ApiErrorResponse 인터페이스에 result 속성(선택적, Record<string, string>) 추가
src/shared/types/api/http-client.ts 에러 인터셉터에서 error 전체 로그 추가 및 errorInfo에 result 속성 포함
src/shared/utils/phoneVerification.ts 전화번호 인증 관련 커스텀 훅 usePhoneVerification 추가, 인증 코드 요청 및 검증, 타이머 관리 기능 포함

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI
    participant useSendCertificationCode
    participant useVerifyCertificationCode
    participant API

    User->>UI: 전화번호 입력 및 "인증하기" 클릭
    UI->>useSendCertificationCode: 인증 코드 전송 요청
    useSendCertificationCode->>API: POST /send-certification-code
    API-->>useSendCertificationCode: 인증 코드 전송 결과 반환
    useSendCertificationCode-->>UI: 성공/실패 처리, 타이머 시작

    User->>UI: 인증 코드 입력 및 "확인" 클릭
    UI->>useVerifyCertificationCode: 인증 코드 확인 요청
    useVerifyCertificationCode->>API: POST /verify-certification-code
    API-->>useVerifyCertificationCode: 인증 결과 반환
    useVerifyCertificationCode-->>UI: 성공 시 인증 완료 처리, 실패 시 에러 메시지 표시
Loading

Suggested reviewers

  • Yejiin21

Poem

🐇
전화번호 인증이 왔어요,
토끼는 깡충, 폰을 들고
뾰로롱~ 코드가 도착하니
타이머가 똑딱똑딱,
인증 성공의 기쁨에
토끼 볼이 발그레!
오늘도 개발은 한 뼘 더!

✨ 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.

@hyeeuncho hyeeuncho self-assigned this Jul 10, 2025
@hyeeuncho hyeeuncho added 🔧 Feature 기능 구현 🖼️ Publishing 페이지 퍼블리싱 labels Jul 10, 2025
@github-actions
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (3)
src/shared/types/api/http-client.ts (1)

59-59: 프로덕션 환경에서 console.log 사용을 검토해주세요.

디버깅을 위한 console.log는 개발 중에는 유용하지만, 프로덕션 배포 시에는 제거하거나 적절한 로깅 라이브러리로 대체하는 것을 고려해주세요.

src/pages/join/InfoInputPage.tsx (1)

49-78: 인증 코드 로직 중복

이 컴포넌트와 ProfileInfo.tsx에 동일한 인증 로직이 중복되어 있습니다.

커스텀 훅으로 추출하여 재사용성을 높이는 것을 권장합니다. 인증 로직을 위한 커스텀 훅을 생성해드릴까요?

src/entities/user/ui/ProfileInfo.tsx (1)

207-214: 중복된 취소 로직

취소 버튼의 동작이 두 곳에서 중복되어 있습니다.

취소 로직을 함수로 추출:

const handleCancel = () => {
  setIsEditing(false);
  setValue('name', data?.name || '');
  setValue('phone', data?.phoneNumber || '');
  setIsVerified(false);
  setIsVerifyVisible(false);
  setVerificationCode('');
};

Also applies to: 226-232

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 15c9478 and 7f6068b.

📒 Files selected for processing (9)
  • design-system/ui/Button.tsx (1 hunks)
  • design-system/ui/buttons/TertiaryButton.tsx (1 hunks)
  • src/entities/user/ui/ProfileInfo.tsx (4 hunks)
  • src/features/join/api/user.ts (1 hunks)
  • src/features/join/hooks/useUserHook.ts (2 hunks)
  • src/pages/join/InfoInputPage.tsx (7 hunks)
  • src/pages/menu/ui/MyTicketPage.tsx (1 hunks)
  • src/shared/types/api/apiResponse.ts (1 hunks)
  • src/shared/types/api/http-client.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: xaexunxang
PR: GoTogether-Inc/frontend#106
File: src/entities/event/model/eventRequest.ts:26-30
Timestamp: 2025-04-29T10:26:21.217Z
Learning: GoTogether 프로젝트의 이벤트 API에서는 생성(EventCreate)과 수정(EventUpdate) 인터페이스에서 다른 필드명을 사용합니다:
- EventCreate: organizerEmail, organizerPhoneNumber (Swagger 스펙 기준)
- EventUpdate: hostEmail, hostPhoneNumber (Notion 스펙 기준)
이는 백엔드 API 명세의 불일치로 인한 의도적인 차이입니다.
🧬 Code Graph Analysis (2)
src/features/join/api/user.ts (1)
src/shared/types/api/http-client.ts (1)
  • axiosClient (15-22)
src/features/join/hooks/useUserHook.ts (1)
src/features/join/api/user.ts (2)
  • sendCertificationCode (27-32)
  • verifyCertificationCode (34-39)
🪛 ESLint
src/features/join/hooks/useUserHook.ts

[error] 40-40: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)


[error] 59-59: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)

🔇 Additional comments (7)
src/shared/types/api/apiResponse.ts (1)

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

ApiErrorResponse에 선택적 result 프로퍼티를 추가한 것은 상세한 오류 메시지 처리를 위한 좋은 개선사항입니다. Record<string, string> 타입은 키-값 쌍의 오류 세부사항을 담기에 적합합니다.

src/pages/menu/ui/MyTicketPage.tsx (1)

136-136: 이벤트 카드 프로퍼티 추가가 적절합니다.

EventCardonlineType 프로퍼티를 추가하여 이벤트의 온라인 유형 정보를 전달하는 것은 일관된 패턴을 따르고 있습니다.

src/shared/types/api/http-client.ts (1)

64-64: 오류 응답 구조 개선이 적절합니다.

errorInfo 객체에 result 프로퍼티를 추가하여 상세한 오류 정보를 포함하는 것은 ApiErrorResponse 인터페이스 변경과 일관성을 유지하고 있습니다.

design-system/ui/buttons/TertiaryButton.tsx (2)

27-27: 비활성화 상태 스타일링이 적절합니다.

disabledStyle 상수를 추가하여 비활성화된 버튼의 시각적 피드백을 제공하는 것은 사용자 경험을 개선하는 좋은 방법입니다.


33-33: 조건부 스타일 적용이 올바릅니다.

disabled 상태에 따라 조건부로 스타일을 적용하는 방식이 깔끔하고 유지보수하기 좋습니다.

design-system/ui/Button.tsx (1)

15-15: 버튼 스타일링 개선이 적절합니다.

레이아웃 유틸리티 클래스(inline-flex, items-center, justify-center)와 반응형 패딩을 추가하여 버튼의 일관성과 정렬을 개선한 것은 좋은 변경사항입니다.

src/entities/user/ui/ProfileInfo.tsx (1)

239-241: 조건부 버튼 비활성화 로직 개선 가능

전화번호가 변경되지 않았거나 인증이 완료된 경우에만 수정 가능하도록 설정되어 있습니다.

비즈니스 로직이 명확하고 적절합니다. 사용자가 전화번호를 변경할 때만 인증을 요구하는 것은 좋은 UX입니다.

@github-actions
Copy link

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

🧹 Nitpick comments (3)
src/shared/utils/phoneVerification.ts (3)

19-34: 사용자 경험 개선을 위한 alert 대안 검토가 필요합니다.

현재 alert()를 사용한 검증 메시지는 사용자 경험에 부정적인 영향을 줄 수 있습니다. 토스트 메시지나 인라인 에러 메시지를 고려해보세요.

또한, 전화번호 유효성 검증 로직을 추가하는 것을 고려해보세요:

  const requestVerificationCode = (phone: string) => {
    if (!phone) {
-     alert('연락처를 입력해주세요.');
+     // 토스트 메시지나 상태 기반 에러 처리 고려
      return;
    }
+   
+   // 전화번호 형식 검증 추가 고려
+   const phoneRegex = /^\d{3}-\d{3,4}-\d{4}$/;
+   if (!phoneRegex.test(phone)) {
+     // 형식 오류 처리
+     return;
+   }

37-52: 인증번호 검증 로직이 적절합니다.

6자리 인증번호 검증과 API 호출 로직이 올바르게 구현되어 있습니다.

다만 하드코딩된 6자리 제한을 상수로 분리하는 것을 고려해보세요:

+ const VERIFICATION_CODE_LENGTH = 6;
+
  const submitVerificationCode = (phone: string) => {
-   if (!verificationCode || verificationCode.length !== 6) {
+   if (!verificationCode || verificationCode.length !== VERIFICATION_CODE_LENGTH) {
-     alert('6자리 인증번호를 입력해주세요.');
+     alert(`${VERIFICATION_CODE_LENGTH}자리 인증번호를 입력해주세요.`);
      return;
    }

73-85: 반환 객체 구조가 적절합니다.

필요한 모든 상태와 핸들러를 적절히 노출하고 있습니다.

TypeScript 타입 안전성을 위해 반환 타입을 명시적으로 정의하는 것을 고려해보세요:

interface PhoneVerificationReturn {
  isVerified: boolean;
  isVerifyVisible: boolean;
  verificationCode: string;
  setVerificationCode: (code: string) => void;
  timer: number;
  formatTime: (seconds: number) => string;
  requestVerificationCode: (phone: string) => void;
  submitVerificationCode: (phone: string) => void;
  setIsVerified: (verified: boolean) => void;
  setIsVerifyVisible: (visible: boolean) => void;
  resetVerification: () => void;
}

export const usePhoneVerification = (): PhoneVerificationReturn => {
  // ... 기존 코드
};
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7f6068b and cf78ceb.

📒 Files selected for processing (5)
  • src/entities/user/ui/ProfileInfo.tsx (4 hunks)
  • src/features/join/api/user.ts (1 hunks)
  • src/pages/join/InfoInputPage.tsx (7 hunks)
  • src/shared/types/api/http-client.ts (1 hunks)
  • src/shared/utils/phoneVerification.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/shared/types/api/http-client.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/features/join/api/user.ts
  • src/pages/join/InfoInputPage.tsx
  • src/entities/user/ui/ProfileInfo.tsx
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: xaexunxang
PR: GoTogether-Inc/frontend#106
File: src/entities/event/model/eventRequest.ts:26-30
Timestamp: 2025-04-29T10:26:21.217Z
Learning: GoTogether 프로젝트의 이벤트 API에서는 생성(EventCreate)과 수정(EventUpdate) 인터페이스에서 다른 필드명을 사용합니다:
- EventCreate: organizerEmail, organizerPhoneNumber (Swagger 스펙 기준)
- EventUpdate: hostEmail, hostPhoneNumber (Notion 스펙 기준)
이는 백엔드 API 명세의 불일치로 인한 의도적인 차이입니다.
🔇 Additional comments (3)
src/shared/utils/phoneVerification.ts (3)

1-2: LGTM! 깔끔한 import 구조입니다.

필요한 React 훅과 사용자 정의 훅을 적절히 import하고 있습니다.


4-11: 상태 관리 구조가 적절합니다.

전화번호 인증에 필요한 모든 상태를 적절히 관리하고 있습니다.


67-71: 시간 포맷팅 함수가 올바르게 구현되었습니다.

MM:SS 형식으로 시간을 표시하는 로직이 정확합니다.

Comment on lines +55 to +65
useEffect(() => {
if (isVerifyVisible && timer > 0) {
const interval = setInterval(() => {
setTimer(prev => prev - 1);
}, 1000);
return () => clearInterval(interval);
} else if (isVerifyVisible && timer === 0) {
alert('인증 시간이 만료되었습니다. 다시 인증해주세요.');
setIsVerifyVisible(false);
}
}, [isVerifyVisible, timer]);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

타이머 로직에 메모리 누수 방지 개선이 필요합니다.

현재 타이머 로직은 올바르게 구현되어 있지만, 컴포넌트 언마운트 시 메모리 누수를 방지하기 위한 추가 처리가 필요합니다.

다음과 같이 개선해주세요:

  useEffect(() => {
+   let interval: NodeJS.Timeout;
+   
    if (isVerifyVisible && timer > 0) {
-     const interval = setInterval(() => {
+     interval = setInterval(() => {
        setTimer(prev => prev - 1);
      }, 1000);
-     return () => clearInterval(interval);
    } else if (isVerifyVisible && timer === 0) {
      alert('인증 시간이 만료되었습니다. 다시 인증해주세요.');
      setIsVerifyVisible(false);
    }
+   
+   return () => {
+     if (interval) {
+       clearInterval(interval);
+     }
+   };
  }, [isVerifyVisible, timer]);
📝 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
useEffect(() => {
if (isVerifyVisible && timer > 0) {
const interval = setInterval(() => {
setTimer(prev => prev - 1);
}, 1000);
return () => clearInterval(interval);
} else if (isVerifyVisible && timer === 0) {
alert('인증 시간이 만료되었습니다. 다시 인증해주세요.');
setIsVerifyVisible(false);
}
}, [isVerifyVisible, timer]);
useEffect(() => {
let interval: NodeJS.Timeout;
if (isVerifyVisible && timer > 0) {
interval = setInterval(() => {
setTimer(prev => prev - 1);
}, 1000);
} else if (isVerifyVisible && timer === 0) {
alert('인증 시간이 만료되었습니다. 다시 인증해주세요.');
setIsVerifyVisible(false);
}
return () => {
if (interval) {
clearInterval(interval);
}
};
}, [isVerifyVisible, timer]);
🤖 Prompt for AI Agents
In src/shared/utils/phoneVerification.ts around lines 55 to 65, the useEffect
hook sets up a timer interval but does not clear it when the component unmounts,
risking memory leaks. To fix this, add a cleanup function that clears the
interval regardless of the timer or visibility state when the component
unmounts. Ensure the interval is cleared both when the timer reaches zero and on
unmount by returning a cleanup function that calls clearInterval on the interval
ID.

Comment on lines +12 to +17
const resetVerification = () => {
setIsVerified(false);
setIsVerifyVisible(false);
setVerificationCode('');
setTimer(0);
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

함수 정의 위치 개선이 필요합니다.

resetVerification 함수가 상태 변수들보다 먼저 정의되어 있어 코드 가독성을 떨어뜨릴 수 있습니다.

다음과 같이 함수를 아래로 이동시켜 주세요:

  const [timer, setTimer] = useState(0);
-const resetVerification = () => {
-    setIsVerified(false);
-    setIsVerifyVisible(false);
-    setVerificationCode('');
-    setTimer(0);
-  };
  
  // 인증번호 발송
  const requestVerificationCode = (phone: string) => {
    // ... 기존 코드
  };
  
  // 인증번호 확인
  const submitVerificationCode = (phone: string) => {
    // ... 기존 코드
  };
  
+ const resetVerification = () => {
+   setIsVerified(false);
+   setIsVerifyVisible(false);
+   setVerificationCode('');
+   setTimer(0);
+ };
📝 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 resetVerification = () => {
setIsVerified(false);
setIsVerifyVisible(false);
setVerificationCode('');
setTimer(0);
};
const [timer, setTimer] = useState(0);
// 인증번호 발송
const requestVerificationCode = (phone: string) => {
// ... 기존 코드
};
// 인증번호 확인
const submitVerificationCode = (phone: string) => {
// ... 기존 코드
};
const resetVerification = () => {
setIsVerified(false);
setIsVerifyVisible(false);
setVerificationCode('');
setTimer(0);
};
🤖 Prompt for AI Agents
In src/shared/utils/phoneVerification.ts between lines 12 and 17, the
resetVerification function is defined before the state variables it uses, which
reduces code readability. Move the resetVerification function definition to
below the state variable declarations to improve the logical flow and
readability of the code.

@hyeeuncho hyeeuncho merged commit c52cf92 into develop Jul 10, 2025
2 checks passed
@hyeeuncho hyeeuncho deleted the feat/#235/sms-verify branch July 10, 2025 10:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔧 Feature 기능 구현 🖼️ Publishing 페이지 퍼블리싱

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 전화번호 인증

3 participants