Skip to content
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

♻️ 회원가입 페이지 sms 개선 #64

Merged
merged 1 commit into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/entities/signUp/api/getCheckSmsCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,11 @@ export const getCheckSmsCode = async (phoneNumber: string, code: string) => {
const response = await axios.get(
`/api/auth/sms?phoneNumber=${phoneNumber}&code=${code}`,
);
return response;
if (response.status === 200) {
toast.success('인증 번호 확인에 성공했습니다.');
return true;
} else {
toast.error('인증 번호 확인에 실패했습니다.');
return false;
}
};
14 changes: 12 additions & 2 deletions src/entities/signUp/model/useCheckSmsCode.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import { useQuery } from '@tanstack/react-query';
import { getCheckSmsCode } from '../api/getCheckSmsCode';

export const useCheckSmsCode = (phoneNumber: string, code: string) => {
export const useCheckSmsCode = (
phoneNumber: string,
code: string,
setIsSmsVerified: React.Dispatch<React.SetStateAction<boolean>>,
) => {
return useQuery({
queryKey: ['CheckSmsCode', phoneNumber, code],
queryFn: () => getCheckSmsCode(phoneNumber, code),
queryFn: async () => {
const result = await getCheckSmsCode(phoneNumber, code);
if (typeof result === 'boolean') {
setIsSmsVerified(result);
}
return result;
},
enabled: false,
});
};
4 changes: 2 additions & 2 deletions src/entities/signUp/model/useSendSms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { toast } from 'react-toastify';
import { postSendSms } from '../api/postSendSms';

export const useSendSms = (
setIsSmsSent: React.Dispatch<React.SetStateAction<boolean>>,
setTimer: React.Dispatch<React.SetStateAction<number>>,
setIsSmsSent: React.Dispatch<React.SetStateAction<boolean>>,
) => {
return useMutation({
mutationFn: (phoneNumber: string) => postSendSms(phoneNumber),
Expand All @@ -14,7 +14,7 @@ export const useSendSms = (
toast.success('문자 메시지 전송이 완료되었습니다.');
},
onError: () => {
toast.error('문제 매시지 전송에 실패했습니다.');
toast.error('문자 메시지 전송에 실패했습니다.');
},
});
};
10 changes: 6 additions & 4 deletions src/entities/signUp/model/useTimer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ import { useEffect } from 'react';
export const useTimer = (
timer: number,
setTimer: React.Dispatch<React.SetStateAction<number>>,
setIsSmsSent: React.Dispatch<React.SetStateAction<boolean>>, // 추가
setIsSmsSent: React.Dispatch<React.SetStateAction<boolean>>,
isSmsVerified: boolean,
) => {
useEffect(() => {
if (timer > 0) {
if (timer > 0 && !isSmsVerified) {
const intervalId = setInterval(() => {
setTimer((prev) => prev - 1);
}, 1000);

return () => clearInterval(intervalId);
} else if (timer === 0) {
} else if (timer === 0 || isSmsVerified) {
setIsSmsSent(false);
setTimer(0);
}
}, [timer, setTimer, setIsSmsSent]);
}, [timer, setTimer, isSmsVerified]);
};
32 changes: 23 additions & 9 deletions src/entities/signUp/ui/SignUpForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,20 @@ const SignUpForm = () => {
} = useForm<FormData>();
const [isSmsSent, setIsSmsSent] = useState(false);
const [timer, setTimer] = useState(0);
const [isSmsVerified, setIsSmsVerified] = useState(false);
const { mutate: signup } = useSignup();
const { mutate: sendSms } = useSendSms(setIsSmsSent, setTimer);
const { refetch: checkSmsCode } = useCheckSmsCode(
const { mutate: sendSms, isPending: isSendingSms } = useSendSms(
setTimer,
setIsSmsSent,
);

const { refetch: checkSmsCode, isPending: isCheckingCode } = useCheckSmsCode(
watch('phoneNumber'),
watch('code'),
setIsSmsVerified,
);

useTimer(timer, setTimer, setIsSmsSent);
useTimer(timer, setTimer, setIsSmsSent, isSmsVerified);

return (
<form
Expand Down Expand Up @@ -116,6 +122,7 @@ const SignUpForm = () => {
})}
type="tel"
placeholder="연락처는 - 빼고 입력해주세요"
disabled={isSmsVerified}
/>
<div className="flex space-x-3">
<Input
Expand All @@ -129,25 +136,32 @@ const SignUpForm = () => {
type="text"
placeholder="인증 번호 입력"
style={{ width: '80%' }}
disabled={!isSmsSent && watch('code') !== null}
disabled={!isSmsSent || isSmsVerified}
/>
<Button
onClick={() => checkSmsCode()}
text="확인"
width="20%"
disabled={!isSmsSent}
disabled={!watch('code') || isSmsVerified || !isCheckingCode}
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Let me analyze the code context we have. I can see that:

  1. isCheckingCode is isPending from useCheckSmsCode hook
  2. The button's disabled condition is !watch('code') || isSmsVerified || !isCheckingCode
  3. useCheckSmsCode is a query hook that verifies the SMS code

I can now provide the final response:

SMS 인증 버튼의 disabled 로직 수정 필요
현재 !isCheckingCode 조건으로 인해 로딩 상태가 아닐 때만 버튼이 활성화되는데, 이는 잘못된 로직입니다. 일반적인 UX 패턴에서는 오히려 인증 확인 중일 때(isCheckingCode === true) 버튼을 비활성화하는 것이 바람직합니다. disabled 조건을 다음과 같이 수정하는 것을 추천드립니다:

disabled={!watch('code') || isSmsVerified || isCheckingCode}
🔗 Analysis chain

확인 버튼 disabled 조건 재검토
현재 확인 버튼은 “코드 값 없음 || 이미 인증된 상태 || !isCheckingCode” 조건에서 비활성화됩니다. isCheckingCode는 ‘인증 확인 과정이 진행 중임’을 나타내므로, 로딩 상태일 때 버튼을 활성화해도 되는지 혹은 비활성화해야 하는지 사용성 측면을 한번 더 고민해 보시면 좋겠습니다.


Let me gather more information about the code context to better understand the verification flow and usage of isCheckingCode.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for the SignUpForm component implementation and related state management
ast-grep --pattern 'const SignUpForm = $_' -l typescript

# Find usages of isCheckingCode
rg "isCheckingCode" -A 3 -B 3

# Look for any verification or SMS-related state management
rg "isSmsVerified|setIsSmsVerified" -A 3 -B 3

Length of output: 6969

type="button"
/>
</div>
<button
type="button"
onClick={() => sendSms(watch('phoneNumber'))}
className="text-caption2 text-gray-300"
disabled={isSmsSent}
disabled={
!watch('phoneNumber') ||
isSendingSms ||
isSmsSent ||
isSmsVerified
}
>
{isSmsSent
? `인증번호 재발송 (${Math.floor(timer / 60)}:${String(timer % 60).padStart(2, '0')})`
: '인증번호 발송'}
{isSmsVerified
? '인증 완료'
: isSmsSent
? `인증번호 재발송 (${Math.floor(timer / 60)}:${String(timer % 60).padStart(2, '0')})`
: '인증번호 발송'}
</button>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/shared/ui/Loading/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default function Loading() {
}, []);

return (
<div className="flex h-screen items-center justify-center">
<div className="flex h-screen w-screen items-center justify-center">
<p className="text-h1 text-main-600">
로딩중{dots}
<span className="invisible">...</span>
Expand Down
Loading