diff --git a/src/entities/signIn/api/postSignin.ts b/src/entities/signIn/api/postSignin.ts new file mode 100644 index 0000000..f29546f --- /dev/null +++ b/src/entities/signIn/api/postSignin.ts @@ -0,0 +1,11 @@ +import axios from 'axios'; + +interface SignInData { + nickname: string; + password: string; +} + +export const postSignin = async (data: SignInData) => { + const response = await axios.post('/api/auth/signin', data); + return response; +}; diff --git a/src/entities/signIn/model/useSignin.ts b/src/entities/signIn/model/useSignin.ts new file mode 100644 index 0000000..57f9e3d --- /dev/null +++ b/src/entities/signIn/model/useSignin.ts @@ -0,0 +1,24 @@ +import { useMutation } from '@tanstack/react-query'; +import { useRouter } from 'next/navigation'; +import { toast } from 'react-toastify'; +import { postSignin } from '../api/postSignin'; + +interface SignInData { + nickname: string; + password: string; +} + +export const useSignin = () => { + const router = useRouter(); + + return useMutation({ + mutationFn: (data: SignInData) => postSignin(data), + onSuccess: () => { + toast.success('로그인이 완료되었습니다.'); + router.push('/'); + }, + onError: () => { + toast.error('로그인에 실패했습니다.'); + }, + }); +}; diff --git a/src/entities/signIn/ui/SignInForm/index.tsx b/src/entities/signIn/ui/SignInForm/index.tsx index 290c96a..0d0b1e3 100644 --- a/src/entities/signIn/ui/SignInForm/index.tsx +++ b/src/entities/signIn/ui/SignInForm/index.tsx @@ -1,11 +1,10 @@ 'use client'; -import { useRouter } from 'next/navigation'; import { useForm } from 'react-hook-form'; import Button from '@/shared/ui/Button'; import Input from '@/shared/ui/Input'; -import { signIn } from '../../api/signin'; import { showError } from '../../model/showError'; +import { useSignin } from '../../model/useSignin'; type FormData = { nickname: string; @@ -19,12 +18,12 @@ const SignInForm = () => { formState: { isSubmitting }, } = useForm(); - const router = useRouter(); + const { mutate: signin } = useSignin(); return (
signIn(data, router), + (data) => signin(data), (errors) => { const firstError = Object.values(errors)[0]; if (firstError && firstError.message) { diff --git a/src/entities/signUp/api/checkSmsCode.ts b/src/entities/signUp/api/checkSmsCode.ts deleted file mode 100644 index f225a35..0000000 --- a/src/entities/signUp/api/checkSmsCode.ts +++ /dev/null @@ -1,21 +0,0 @@ -import axios from 'axios'; -import { toast } from 'react-toastify'; - -export const checkSmsCode = async (phoneNumber: string, code: string) => { - if (!phoneNumber || !code) { - toast.error('전화번호와 인증 번호를 입력해주세요.'); - return; - } - - try { - const response = await axios.get( - `/api/auth/sms?phoneNumber=${phoneNumber}&code=${code}`, - ); - if (response.status === 200) { - toast.success('인증번호가 확인되었습니다.'); - } - } catch (error) { - console.error('Code verification failed', error); - toast.error('인증번호 확인에 실패했습니다.'); - } -}; diff --git a/src/entities/signUp/api/getCheckSmsCode.ts b/src/entities/signUp/api/getCheckSmsCode.ts new file mode 100644 index 0000000..99d1363 --- /dev/null +++ b/src/entities/signUp/api/getCheckSmsCode.ts @@ -0,0 +1,14 @@ +import axios from 'axios'; +import { toast } from 'react-toastify'; + +export const getCheckSmsCode = async (phoneNumber: string, code: string) => { + if (!phoneNumber || !code) { + toast.error('전화번호와 인증 번호를 입력해주세요.'); + return; + } + + const response = await axios.get( + `/api/auth/sms?phoneNumber=${phoneNumber}&code=${code}`, + ); + return response; +}; diff --git a/src/entities/signUp/api/postSendSms.ts b/src/entities/signUp/api/postSendSms.ts new file mode 100644 index 0000000..5f28a99 --- /dev/null +++ b/src/entities/signUp/api/postSendSms.ts @@ -0,0 +1,12 @@ +import axios from 'axios'; +import { toast } from 'react-toastify'; + +export const postSendSms = async (phoneNumber: string) => { + if (!phoneNumber) { + toast.error('전화번호를 입력해주세요.'); + return; + } + + const response = await axios.post('/api/auth/sms', { phoneNumber }); + return response; +}; diff --git a/src/entities/signUp/api/postSignup.ts b/src/entities/signUp/api/postSignup.ts new file mode 100644 index 0000000..97330aa --- /dev/null +++ b/src/entities/signUp/api/postSignup.ts @@ -0,0 +1,14 @@ +import axios from 'axios'; + +interface SignUpData { + name: string; + nickname: string; + email: string; + password: string; + phoneNumber: string; +} + +export const postSignup = async (data: SignUpData) => { + const response = await axios.post('/api/auth/signup', data); + return response; +}; diff --git a/src/entities/signUp/api/sendSms.ts b/src/entities/signUp/api/sendSms.ts deleted file mode 100644 index 6186162..0000000 --- a/src/entities/signUp/api/sendSms.ts +++ /dev/null @@ -1,25 +0,0 @@ -import axios from 'axios'; -import { toast } from 'react-toastify'; - -export const sendSms = async ( - phoneNumber: string, - setIsSmsSent: React.Dispatch>, - setTimer: React.Dispatch>, -) => { - if (!phoneNumber) { - toast.error('전화번호를 입력해주세요.'); - return; - } - - try { - const response = await axios.post('/api/auth/sms', { phoneNumber }); - if (response.status === 200) { - setIsSmsSent(true); - setTimer(180); - toast.success('인증번호가 발송되었습니다.'); - } - } catch (error) { - console.error('SMS sending failed', error); - toast.error('인증번호 발송에 실패했습니다.'); - } -}; diff --git a/src/entities/signUp/api/signup.ts b/src/entities/signUp/api/signup.ts deleted file mode 100644 index 9c3bb71..0000000 --- a/src/entities/signUp/api/signup.ts +++ /dev/null @@ -1,33 +0,0 @@ -import axios from 'axios'; -import { useRouter } from 'next/navigation'; -import { toast } from 'react-toastify'; - -interface SignUpData { - name: string; - nickname: string; - email: string; - password: string; - phoneNumber: string; -} - -export const signUp = async ( - data: SignUpData, - router: ReturnType, -) => { - try { - const response = await axios.post('/api/auth/signup', { - name: data.name, - nickname: data.nickname, - email: data.email, - password: data.password, - phoneNumber: data.phoneNumber, - }); - if (response.status === 200) { - toast.success('회원가입이 완료되었습니다.'); - router.push('/signIn'); - } - } catch (error) { - console.error('Signup failed', error); - toast.error('회원가입에 실패했습니다.'); - } -}; diff --git a/src/entities/signUp/model/useCheckSmsCode.ts b/src/entities/signUp/model/useCheckSmsCode.ts new file mode 100644 index 0000000..7f83505 --- /dev/null +++ b/src/entities/signUp/model/useCheckSmsCode.ts @@ -0,0 +1,10 @@ +import { useQuery } from '@tanstack/react-query'; +import { getCheckSmsCode } from '../api/getCheckSmsCode'; + +export const useCheckSmsCode = (phoneNumber: string, code: string) => { + return useQuery({ + queryKey: ['CheckSmsCode', phoneNumber, code], + queryFn: () => getCheckSmsCode(phoneNumber, code), + enabled: false, + }); +}; diff --git a/src/entities/signUp/model/useSendSms.ts b/src/entities/signUp/model/useSendSms.ts new file mode 100644 index 0000000..d2302da --- /dev/null +++ b/src/entities/signUp/model/useSendSms.ts @@ -0,0 +1,20 @@ +import { useMutation } from '@tanstack/react-query'; +import { toast } from 'react-toastify'; +import { postSendSms } from '../api/postSendSms'; + +export const useSendSms = ( + setIsSmsSent: React.Dispatch>, + setTimer: React.Dispatch>, +) => { + return useMutation({ + mutationFn: (phoneNumber: string) => postSendSms(phoneNumber), + onSuccess: () => { + setIsSmsSent(true); + setTimer(180); + toast.success('문자 메시지 전송이 완료되었습니다.'); + }, + onError: () => { + toast.error('문제 매시지 전송에 실패했습니다.'); + }, + }); +}; diff --git a/src/entities/signUp/model/useSignup.ts b/src/entities/signUp/model/useSignup.ts new file mode 100644 index 0000000..ee9f707 --- /dev/null +++ b/src/entities/signUp/model/useSignup.ts @@ -0,0 +1,27 @@ +import { useMutation } from '@tanstack/react-query'; +import { useRouter } from 'next/navigation'; +import { toast } from 'react-toastify'; +import { postSignup } from '../api/postSignup'; + +interface SignUpData { + name: string; + nickname: string; + email: string; + password: string; + phoneNumber: string; +} + +export const useSignup = () => { + const router = useRouter(); + + return useMutation({ + mutationFn: (data: SignUpData) => postSignup(data), + onSuccess: () => { + toast.success('회원가입이 완료되었습니다.'); + router.push('/signIn'); + }, + onError: () => { + toast.error('회원가입에 실패했습니다.'); + }, + }); +}; diff --git a/src/entities/signUp/model/useTimer.ts b/src/entities/signUp/model/useTimer.ts index b72eb07..9785a9c 100644 --- a/src/entities/signUp/model/useTimer.ts +++ b/src/entities/signUp/model/useTimer.ts @@ -3,13 +3,17 @@ import { useEffect } from 'react'; export const useTimer = ( timer: number, setTimer: React.Dispatch>, + setIsSmsSent: React.Dispatch>, // 추가 ) => { useEffect(() => { if (timer > 0) { const intervalId = setInterval(() => { setTimer((prev) => prev - 1); }, 1000); + return () => clearInterval(intervalId); + } else if (timer === 0) { + setIsSmsSent(false); } - }, [timer, setTimer]); + }, [timer, setTimer, setIsSmsSent]); }; diff --git a/src/entities/signUp/ui/SignUpForm/index.tsx b/src/entities/signUp/ui/SignUpForm/index.tsx index 6b83b78..3af7396 100644 --- a/src/entities/signUp/ui/SignUpForm/index.tsx +++ b/src/entities/signUp/ui/SignUpForm/index.tsx @@ -1,13 +1,12 @@ 'use client'; -import { useRouter } from 'next/navigation'; import { useState } from 'react'; import { useForm } from 'react-hook-form'; import { Button, Input } from '@/shared/ui'; -import { checkSmsCode } from '../../api/checkSmsCode'; -import { sendSms } from '../../api/sendSms'; -import { signUp } from '../../api/signup'; import { showError } from '../../model/showError'; +import { useCheckSmsCode } from '../../model/useCheckSmsCode'; +import { useSendSms } from '../../model/useSendSms'; +import { useSignup } from '../../model/useSignup'; import { useTimer } from '../../model/useTimer'; type FormData = { @@ -29,15 +28,19 @@ const SignUpForm = () => { } = useForm(); const [isSmsSent, setIsSmsSent] = useState(false); const [timer, setTimer] = useState(0); + const { mutate: signup } = useSignup(); + const { mutate: sendSms } = useSendSms(setIsSmsSent, setTimer); + const { refetch: checkSmsCode } = useCheckSmsCode( + watch('phoneNumber'), + watch('code'), + ); - useTimer(timer, setTimer); - - const router = useRouter(); + useTimer(timer, setTimer, setIsSmsSent); return ( signUp(data, router), + (data) => signup(data), (errors) => { const firstError = Object.values(errors)[0]; if (firstError && firstError.message) { @@ -126,10 +129,10 @@ const SignUpForm = () => { type="text" placeholder="인증 번호 입력" style={{ width: '80%' }} - disabled={!isSmsSent} + disabled={!isSmsSent && watch('code') !== null} />