-
Notifications
You must be signed in to change notification settings - Fork 0
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
refactor : useMutation으로 api 호출 방식 통일 #299
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,12 +1,13 @@ | ||||||||||||
import { useMutation } from '@tanstack/react-query'; | ||||||||||||
import { AxiosError } from 'axios'; | ||||||||||||
|
||||||||||||
import { authClient } from '@/apis'; | ||||||||||||
import { STORAGE_KEYS } from '@/constants/storage.constant.ts'; | ||||||||||||
|
||||||||||||
import { | ||||||||||||
AuthErrorData, | ||||||||||||
GetAuthVerificationCheckResponse, | ||||||||||||
PostAuthVerificationEmailResponse, | ||||||||||||
Comment on lines
-8
to
-9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 확인해보니까 이 두 타입은 이제 사용하는 곳이 없던데, 한번 확인해보시고 이번 PR에서 멸종 ㄱㄱ 어때요 |
||||||||||||
GetAuthVerificationCheckData, | ||||||||||||
PostAuthVerificationEmailData, | ||||||||||||
} from '../types/Auth.type'; | ||||||||||||
|
||||||||||||
interface EmailVerificationParams { | ||||||||||||
|
@@ -20,31 +21,45 @@ interface VerificationCheckParams { | |||||||||||
|
||||||||||||
export const postAuthVerificationEmail = async ( | ||||||||||||
emailVerificationParams: EmailVerificationParams | ||||||||||||
): Promise<PostAuthVerificationEmailResponse> => { | ||||||||||||
try { | ||||||||||||
const res = await authClient.post(`/auth/verification/email`, emailVerificationParams); | ||||||||||||
if (res.data) { | ||||||||||||
sessionStorage.setItem(STORAGE_KEYS.EMAIL_AUTH_SESSION_TOKEN, res.data.sessionToken); | ||||||||||||
): Promise<PostAuthVerificationEmailData> => { | ||||||||||||
const res = await authClient.post(`/auth/verification/email`, emailVerificationParams); | ||||||||||||
return res.data; | ||||||||||||
}; | ||||||||||||
|
||||||||||||
export const usePostAuthVerificationEmail = () => { | ||||||||||||
return useMutation({ | ||||||||||||
mutationFn: postAuthVerificationEmail, | ||||||||||||
onSuccess: (data) => { | ||||||||||||
sessionStorage.setItem(STORAGE_KEYS.EMAIL_AUTH_SESSION_TOKEN, data.sessionToken); | ||||||||||||
sessionStorage.setItem( | ||||||||||||
STORAGE_KEYS.EMAIL_AUTH_SESSION_TOKEN_EXPIRED_IN, | ||||||||||||
res.data.sessionTokenExpiredIn.toString() | ||||||||||||
data.sessionTokenExpiredIn.toString() | ||||||||||||
); | ||||||||||||
} | ||||||||||||
return { data: res.data }; | ||||||||||||
} catch (error: unknown) { | ||||||||||||
return { error: error as AxiosError<AuthErrorData> }; | ||||||||||||
} | ||||||||||||
}, | ||||||||||||
throwOnError: (error: AxiosError<AuthErrorData>) => { | ||||||||||||
//이전과 같은 이메일일 경우 errorBoundary로 가지 않고 에러 처리 | ||||||||||||
if (error.response?.status === 400) return false; | ||||||||||||
// 나머지는 errorBoundary로 처리 | ||||||||||||
return true; | ||||||||||||
Comment on lines
+40
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
으로 줄일 수도 있을 것 같네요! |
||||||||||||
}, | ||||||||||||
}); | ||||||||||||
}; | ||||||||||||
|
||||||||||||
export const getAuthVerificationCheck = async ( | ||||||||||||
verificationCheckParams: VerificationCheckParams | ||||||||||||
): Promise<GetAuthVerificationCheckResponse> => { | ||||||||||||
try { | ||||||||||||
const res = await authClient.get('/auth/verification/check', { | ||||||||||||
params: verificationCheckParams, | ||||||||||||
}); | ||||||||||||
return { data: res.data }; | ||||||||||||
} catch (error: unknown) { | ||||||||||||
return { error: error as AxiosError<AuthErrorData> }; | ||||||||||||
} | ||||||||||||
): Promise<GetAuthVerificationCheckData> => { | ||||||||||||
const res = await authClient.get('/auth/verification/check', { | ||||||||||||
params: verificationCheckParams, | ||||||||||||
}); | ||||||||||||
return res.data; | ||||||||||||
}; | ||||||||||||
|
||||||||||||
export const useGetAuthVerificationCheck = () => { | ||||||||||||
return useMutation({ | ||||||||||||
mutationFn: getAuthVerificationCheck, | ||||||||||||
throwOnError: (error: AxiosError<AuthErrorData>) => { | ||||||||||||
if (error.response?.status === 401) return false; | ||||||||||||
return true; | ||||||||||||
}, | ||||||||||||
}); | ||||||||||||
}; |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,11 +1,14 @@ | ||||||||||||
import { useState } from 'react'; | ||||||||||||
|
||||||||||||
import { AxiosError } from 'axios'; | ||||||||||||
|
||||||||||||
import { STORAGE_KEYS } from '@/constants/storage.constant.ts'; | ||||||||||||
import { | ||||||||||||
getAuthVerificationCheck, | ||||||||||||
postAuthVerificationEmail, | ||||||||||||
useGetAuthVerificationCheck, | ||||||||||||
usePostAuthVerificationEmail, | ||||||||||||
} from '@/home/apis/authVerification.ts'; | ||||||||||||
import { EmailAuthProps } from '@/home/components/SignupContents/EmailAuth/EmailAuth.type.ts'; | ||||||||||||
import { AuthErrorData } from '@/home/types/Auth.type'; | ||||||||||||
import { useSecondTimer } from '@/hooks/useSecondTimer.ts'; | ||||||||||||
|
||||||||||||
export const useEmailAuth = ({ onConfirm, email }: EmailAuthProps) => { | ||||||||||||
|
@@ -14,27 +17,43 @@ export const useEmailAuth = ({ onConfirm, email }: EmailAuthProps) => { | |||||||||||
const [error, setError] = useState<string>(''); | ||||||||||||
const [emailSending, setEmailSending] = useState(false); | ||||||||||||
|
||||||||||||
const postAuthVerificationEmailMutation = usePostAuthVerificationEmail(); | ||||||||||||
const getAuthVerificationCheckMutation = useGetAuthVerificationCheck(); | ||||||||||||
|
||||||||||||
const sendAuthenticationMail = async () => { | ||||||||||||
setEmailSending(true); | ||||||||||||
const { data } = await postAuthVerificationEmail({ email: email, verificationType: 'SIGN_UP' }); | ||||||||||||
await postAuthVerificationEmailMutation.mutateAsync( | ||||||||||||
{ email: email, verificationType: 'SIGN_UP' }, | ||||||||||||
{ | ||||||||||||
onSuccess: () => { | ||||||||||||
setAuthed(true); | ||||||||||||
}, | ||||||||||||
onError: () => { | ||||||||||||
setAuthed(false); | ||||||||||||
setError('인증 메일 재전송에 실패했습니다.'); | ||||||||||||
}, | ||||||||||||
} | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
다른 콜백들과의 일관성을 위해 mutation이 성공하거나 실패했을 때 호출되는 추가적으로 |
||||||||||||
); | ||||||||||||
setEmailSending(false); | ||||||||||||
setAuthed(!!data); | ||||||||||||
setError(!data ? '인증 메일 재전송에 실패했습니다.' : ''); | ||||||||||||
resetTimer(); | ||||||||||||
}; | ||||||||||||
|
||||||||||||
const onClickNext = async () => { | ||||||||||||
const session = sessionStorage.getItem(STORAGE_KEYS.EMAIL_AUTH_SESSION_TOKEN); | ||||||||||||
if (!session) return; | ||||||||||||
|
||||||||||||
const res = await getAuthVerificationCheck({ session }); | ||||||||||||
|
||||||||||||
if (res.data) { | ||||||||||||
if (res.data.isVerified) onConfirm(); | ||||||||||||
else setError('이메일 인증을 완료해주세요.'); | ||||||||||||
} else if (res.error) { | ||||||||||||
setError(res.error.response?.data.message || '이메일 인증 확인에 실패했습니다.'); | ||||||||||||
} | ||||||||||||
await getAuthVerificationCheckMutation.mutateAsync( | ||||||||||||
{ session: session }, | ||||||||||||
{ | ||||||||||||
onSuccess: (data) => { | ||||||||||||
if (data.isVerified) onConfirm(); | ||||||||||||
else setError('이메일 인증을 완료해주세요.'); | ||||||||||||
}, | ||||||||||||
onError: (error: AxiosError<AuthErrorData>) => { | ||||||||||||
setError(error.response?.data.message || '인증에 실패했습니다.'); | ||||||||||||
}, | ||||||||||||
} | ||||||||||||
); | ||||||||||||
}; | ||||||||||||
|
||||||||||||
return { authed, leftTime, isTimerEnd, error, emailSending, sendAuthenticationMail, onClickNext }; | ||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
import { BoxButton, PlainButton, SuffixTextField } from '@yourssu/design-system-react'; | ||
import { useForm } from 'react-hook-form'; | ||
|
||
import { EMAIL_DOMAIN, MAIL_SEARCH_URL } from '@/constants/email.constant'; | ||
import { EmailFormProps } from '@/home/components/SignupContents/EmailForm/EmailForm.type.ts'; | ||
import { useEmailForm } from '@/home/components/SignupContents/EmailForm/useEmailForm.ts'; | ||
import { usePreventDuplicateClick } from '@/hooks/usePreventDuplicateClick.ts'; | ||
|
||
import { | ||
StyledSignupButtonText, | ||
|
@@ -21,10 +21,13 @@ import { | |
|
||
export const EmailForm = ({ onConfirm }: EmailFormProps) => { | ||
const { email, emailError, onEmailSubmit, onChange } = useEmailForm({ onConfirm }); | ||
const { disabled, handleClick } = usePreventDuplicateClick(); | ||
const { | ||
handleSubmit, | ||
formState: { isSubmitting }, | ||
} = useForm(); | ||
Comment on lines
+24
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. react-hook-form으로 form 제출 상태를 관리하는게 좋네요👍 email error도 react-hook-form으로 관리할 수 있을 것 같은데 나중에 해보는 걸루.. |
||
|
||
return ( | ||
<StyledSignupContentContainer> | ||
<StyledSignupContentContainer onSubmit={handleSubmit(onEmailSubmit)}> | ||
<StyledSignupContentTitle>회원가입</StyledSignupContentTitle> | ||
<div> | ||
<StyledTextFieldLabel>숭실대학교 메일을 입력해주세요.</StyledTextFieldLabel> | ||
|
@@ -55,11 +58,10 @@ export const EmailForm = ({ onConfirm }: EmailFormProps) => { | |
size="large" | ||
variant="filled" | ||
rounding={8} | ||
disabled={email === '' || disabled} | ||
onClick={() => handleClick(onEmailSubmit)} | ||
disabled={email === '' || isSubmitting} | ||
> | ||
<StyledSignupButtonText> | ||
{disabled ? '잠시만 기다려주세요...' : '인증 메일 받기'} | ||
{isSubmitting ? '잠시만 기다려주세요...' : '인증 메일 받기'} | ||
</StyledSignupButtonText> | ||
</BoxButton> | ||
</StyledButtonsContainer> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,37 @@ | ||
import { useState } from 'react'; | ||
|
||
import { postAuthVerificationEmail } from '@/home/apis/authVerification.ts'; | ||
import { AxiosError } from 'axios'; | ||
|
||
import { usePostAuthVerificationEmail } from '@/home/apis/authVerification.ts'; | ||
import { EmailFormProps } from '@/home/components/SignupContents/EmailForm/EmailForm.type.ts'; | ||
import { AuthErrorData } from '@/home/types/Auth.type'; | ||
import { useParseFullEmail } from '@/hooks/useParseFullEmail'; | ||
|
||
export const useEmailForm = ({ onConfirm }: EmailFormProps) => { | ||
const [email, setEmail] = useState(''); | ||
const [emailError, setEmailError] = useState<string | undefined>(undefined); | ||
const parseFullEmail = useParseFullEmail(); | ||
|
||
const postAuthVerificationEmailMutation = usePostAuthVerificationEmail(); | ||
|
||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
setEmail(e.target.value); | ||
}; | ||
|
||
const onEmailSubmit = async () => { | ||
const fullEmail = parseFullEmail(email); | ||
const res = await postAuthVerificationEmail({ email: fullEmail, verificationType: 'SIGN_UP' }); | ||
if (res.data) { | ||
onConfirm(fullEmail); | ||
} else { | ||
setEmailError(res.error?.response?.data.message || '이메일을 다시 확인해주세요.'); | ||
} | ||
|
||
await postAuthVerificationEmailMutation.mutateAsync( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
{ email: fullEmail, verificationType: 'SIGN_UP' }, | ||
{ | ||
onSuccess: () => { | ||
onConfirm(fullEmail); | ||
}, | ||
onError: (error: AxiosError<AuthErrorData>) => { | ||
setEmailError(error.response?.data.message || '이메일을 다시 확인해주세요.'); | ||
}, | ||
} | ||
); | ||
}; | ||
|
||
return { email, emailError, onChange, onEmailSubmit }; | ||
|
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.
tanstack query를 적용하면서
apis/authVerification
파일 내에 api 함수와 useMutation이 같이 위치하게 됐는데요.useMutation은
home/hooks
로 분리하는 게 폴더 구조상 적절해 보입니다!아니면 같은 파일 내에 위치시키신 이유가 따로 있을까요?
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.
저도 다른 API 호출 코드들과 통일성을 위해
apis
폴더 아래에는 axios를 이용한 API 호출 코드만 남기고useMutation()
을 반환하는 커스텀 훅은home/hooks
아래로 위치시키는게 좋을 것 같습니다!추가적으로
postAuthVerificationEmail()
,getAuthVerificationCheck()
함수도 별도의 파일로 분리하는게 좋을 것 같네요.