-
Notifications
You must be signed in to change notification settings - Fork 0
feat: 전화번호 인증 #236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 전화번호 인증 #236
Conversation
Walkthrough이 변경사항은 전화번호 인증 기능을 회원가입 및 프로필 수정 페이지에 통합합니다. 인증 코드 전송 및 확인을 위한 API와 훅이 추가 및 개선되었으며, UI에 타이머와 인증 입력란이 구현되었습니다. 또한, 에러 응답 구조가 확장되어 상세 오류 메시지 처리가 가능해졌습니다. Changes
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: 성공 시 인증 완료 처리, 실패 시 에러 메시지 표시
Suggested reviewers
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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
📒 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: 이벤트 카드 프로퍼티 추가가 적절합니다.
EventCard에onlineType프로퍼티를 추가하여 이벤트의 온라인 유형 정보를 전달하는 것은 일관된 패턴을 따르고 있습니다.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입니다.
There was a problem hiding this 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
📒 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 형식으로 시간을 표시하는 로직이 정확합니다.
| 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]); |
There was a problem hiding this comment.
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.
| 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.
| const resetVerification = () => { | ||
| setIsVerified(false); | ||
| setIsVerifyVisible(false); | ||
| setVerificationCode(''); | ||
| setTimer(0); | ||
| }; |
There was a problem hiding this comment.
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.
| 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.
전화번호 인증 - 회원가입, 마이페이지
Summary by CodeRabbit
신규 기능
개선 및 변경
버그 수정
기타