diff --git a/src/app/(auth)/layout.tsx b/src/app/(auth)/layout.tsx index c8cc154..6d244fb 100644 --- a/src/app/(auth)/layout.tsx +++ b/src/app/(auth)/layout.tsx @@ -4,8 +4,8 @@ export default function DashboardLayout({ children: React.ReactNode }) { return ( -
-
+
+
{children}
diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index dbb675e..ccb79d1 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -1,16 +1,15 @@ 'use client' + +import { useMounted } from '@hooks/useMounted' import Link from 'next/link' -import { useEffect, useState } from 'react' import AuthLogo from '@/app/features/auth/components/AuthLogo' import LoginForm from '@/app/features/auth/components/LoginForm' export default function Login() { - const [mounted, setMounted] = useState(false) - useEffect(() => setMounted(true), []) - if (!mounted) { - return null - } + const mounted = useMounted() + if (!mounted) return null + return ( <> diff --git a/src/app/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx index 4cf052c..df6d848 100644 --- a/src/app/(auth)/signup/page.tsx +++ b/src/app/(auth)/signup/page.tsx @@ -1,10 +1,25 @@ 'use client' +import { useMounted } from '@hooks/useMounted' +import Link from 'next/link' + +import AuthLogo from '@/app/features/auth/components/AuthLogo' import SignupForm from '@/app/features/auth/components/SignupForm' + export default function Signup() { + const mounted = useMounted() + if (!mounted) return null + return ( <> + +

+ 이미 회원이신가요?{' '} + + 로그인 + +

) } diff --git a/src/app/features/auth/components/LoginForm.tsx b/src/app/features/auth/components/LoginForm.tsx index 4c178d3..ed93927 100644 --- a/src/app/features/auth/components/LoginForm.tsx +++ b/src/app/features/auth/components/LoginForm.tsx @@ -26,7 +26,7 @@ export default function LoginForm() { return (
await loginMutate(data))} + onSubmit={handleSubmit((data) => loginMutate(data))} > ({ mode: 'onChange', defaultValues: { @@ -28,7 +28,7 @@ export default function SignupForm() { }) const [isChecked, setIsChecked] = useState(false) - const { submit } = useSignupSubmit() + const { mutate: signupMtate, isPending } = useSignupMutation() const validation = useConfirmPasswordValidation(getValues) function handleAgree() { @@ -36,7 +36,12 @@ export default function SignupForm() { } return ( - + + signupMtate({ email, nickname, password }), + )} + > - 회원가입 + {isPending ? '처리 중..' : '회원가입'}
) diff --git a/src/app/features/auth/hooks/useAuth.ts b/src/app/features/auth/hooks/useAuth.ts index ecda0ec..18a0140 100644 --- a/src/app/features/auth/hooks/useAuth.ts +++ b/src/app/features/auth/hooks/useAuth.ts @@ -1,8 +1,6 @@ import { User } from '@/app/shared/types/user.type' -import { signup as signupApi } from '../api/authApi' import { useAuthStore } from '../store/useAuthStore' -import { SignupRequest } from '../types/auth.type' export function useAuth() { const { setAccessToken, setUser, clearAuthState } = useAuthStore() @@ -18,10 +16,6 @@ export function useAuth() { setUser(user) } - async function signup(data: SignupRequest) { - await signupApi(data) - } - function logout() { clearAuthState() useAuthStore.persist.clearStorage() @@ -29,7 +23,6 @@ export function useAuth() { return { updateAuthState, - signup, logout, } } diff --git a/src/app/features/auth/hooks/useSignupMutation.ts b/src/app/features/auth/hooks/useSignupMutation.ts new file mode 100644 index 0000000..039b4c5 --- /dev/null +++ b/src/app/features/auth/hooks/useSignupMutation.ts @@ -0,0 +1,34 @@ +import { showError, showSuccess } from '@lib/toast' +import { useMutation } from '@tanstack/react-query' +import type { AxiosError } from 'axios' +import axios from 'axios' +import { useRouter } from 'next/navigation' + +import { User } from '@/app/shared/types/user.type' + +import { signup } from '../api/authApi' +import { SignupRequest } from '../types/auth.type' + +export function useSignupMutation() { + const router = useRouter() + + return useMutation({ + mutationFn: signup, + onSuccess: async () => { + showSuccess('회원가입이 완료되었습니다!') + await new Promise((resolve) => setTimeout(resolve, 400)) + router.push('/login') + }, + onError: (error) => { + if (axios.isAxiosError(error)) { + const severMessage = ( + error.response?.data as { message?: string } | undefined + )?.message + const fallback = error.message || '로그인 실패' + showError(severMessage ?? fallback) + } else { + showError('알 수 없는 에러 발생') + } + }, + }) +} diff --git a/src/app/features/auth/hooks/useSignupSubmit.ts b/src/app/features/auth/hooks/useSignupSubmit.ts deleted file mode 100644 index 1a1a843..0000000 --- a/src/app/features/auth/hooks/useSignupSubmit.ts +++ /dev/null @@ -1,28 +0,0 @@ -import axios from 'axios' -import { useRouter } from 'next/navigation' -import { toast } from 'sonner' - -import { SignupRequest } from '../types/auth.type' -import { useAuth } from './useAuth' - -export function useSignupSubmit() { - const { signup } = useAuth() - const router = useRouter() - - async function submit(data: SignupRequest) { - try { - await signup(data) - toast.success('가입이 완료되었습니다!') - router.push('/login') - } catch (e: unknown) { - if (axios.isAxiosError(e)) { - const message = e.response?.data?.message - toast.error(message ?? '회원가입에 실패하였습니다.') - } else { - toast.error('알 수 없는 에러 발생') - } - } - } - - return { submit } -} diff --git a/src/app/globals.css b/src/app/globals.css index c024759..873af03 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -8,6 +8,11 @@ --font-sans: 'Pretendard', 'Noto Sans KR', sans-serif; } +html, +body { + height: 100%; +} + body { font-family: var(--font-sans); } diff --git a/src/app/shared/hooks/useMounted.ts b/src/app/shared/hooks/useMounted.ts new file mode 100644 index 0000000..aaa640a --- /dev/null +++ b/src/app/shared/hooks/useMounted.ts @@ -0,0 +1,11 @@ +import { useEffect, useState } from 'react' + +export function useMounted() { + const [mounted, setMounted] = useState(false) + + useEffect(() => { + setMounted(true) + }, []) + + return mounted +} diff --git a/src/app/shared/types/user.type.ts b/src/app/shared/types/user.type.ts index 75d83ed..368e4e4 100644 --- a/src/app/shared/types/user.type.ts +++ b/src/app/shared/types/user.type.ts @@ -3,6 +3,6 @@ export interface User { email: string nickname: string profileImageUrl: string | null - createdAt?: string - updatedAt?: string + createdAt: string + updatedAt: string }