diff --git a/src/app/(auth)/layout.tsx b/src/app/(auth)/layout.tsx new file mode 100644 index 0000000..c8cc154 --- /dev/null +++ b/src/app/(auth)/layout.tsx @@ -0,0 +1,13 @@ +export default function DashboardLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( +
+
+ {children} +
+
+ ) +} diff --git a/src/app/(auth)/login/page.tsx b/src/app/(auth)/login/page.tsx index 73a37b2..dbb675e 100644 --- a/src/app/(auth)/login/page.tsx +++ b/src/app/(auth)/login/page.tsx @@ -1,11 +1,26 @@ 'use client' +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 + } return ( <> + +

+ 회원이 아니신가요?{' '} + + 회원가입하기 + +

) } diff --git a/src/app/features/.gitkeep b/src/app/features/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/features/auth/api/authApi.ts b/src/app/features/auth/api/authApi.ts index 4902afa..b5203fc 100644 --- a/src/app/features/auth/api/authApi.ts +++ b/src/app/features/auth/api/authApi.ts @@ -1,8 +1,9 @@ import api from '@/app/shared/lib/axios' -import { AUTH_ENDPOINT } from './authEndpoint' -import { LoginRequest, SignupRequest, LoginResponse } from '../types/auth.type' import { User as SignupResponse } from '@/app/shared/types/user.type' +import { LoginRequest, LoginResponse, SignupRequest } from '../types/auth.type' +import { AUTH_ENDPOINT } from './authEndpoint' + export const login = async (data: LoginRequest): Promise => { const response = await api.post(AUTH_ENDPOINT.LOGIN, data) return response.data diff --git a/src/app/features/auth/components/LoginForm.tsx b/src/app/features/auth/components/LoginForm.tsx index 5b1fe8b..4c178d3 100644 --- a/src/app/features/auth/components/LoginForm.tsx +++ b/src/app/features/auth/components/LoginForm.tsx @@ -4,7 +4,7 @@ import Input from '@components/Input' import { cn } from '@lib/cn' import { useForm } from 'react-hook-form' -import { useLoginSubmit } from '../hooks/useLoginSubmit' +import { useLoginMutation } from '../hooks/useLoginMutation' import { loginValidation } from '../schemas/loginValidation' import { LoginRequest } from '../types/auth.type' @@ -12,7 +12,7 @@ export default function LoginForm() { const { register, handleSubmit, - formState: { errors, isSubmitting, isValid }, + formState: { errors, isValid }, } = useForm({ mode: 'onChange', defaultValues: { @@ -21,19 +21,20 @@ export default function LoginForm() { }, }) - const { submit } = useLoginSubmit() - const showEmailError = !!errors.email - const showPasswordError = !!errors.password + const { mutate: loginMutate, isPending } = useLoginMutation() return ( -
+ await loginMutate(data))} + >
) diff --git a/src/app/features/auth/hooks/useAuth.ts b/src/app/features/auth/hooks/useAuth.ts index d4d1c1e..ecda0ec 100644 --- a/src/app/features/auth/hooks/useAuth.ts +++ b/src/app/features/auth/hooks/useAuth.ts @@ -1,12 +1,13 @@ -import { login as loginApi, signup as signupApi } from '../api/authApi' +import { User } from '@/app/shared/types/user.type' + +import { signup as signupApi } from '../api/authApi' import { useAuthStore } from '../store/useAuthStore' -import { LoginRequest, SignupRequest } from '../types/auth.type' +import { SignupRequest } from '../types/auth.type' export function useAuth() { const { setAccessToken, setUser, clearAuthState } = useAuthStore() - async function login(data: LoginRequest) { - const response = await loginApi(data) + function updateAuthState(response: { accessToken: string; user: User }) { const { accessToken, user } = response if (!accessToken || !user) { @@ -27,7 +28,7 @@ export function useAuth() { } return { - login, + updateAuthState, signup, logout, } diff --git a/src/app/features/auth/hooks/useLoginMutation.ts b/src/app/features/auth/hooks/useLoginMutation.ts new file mode 100644 index 0000000..c7bfeee --- /dev/null +++ b/src/app/features/auth/hooks/useLoginMutation.ts @@ -0,0 +1,35 @@ +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 { login } from '../api/authApi' +import { LoginRequest, LoginResponse } from '../types/auth.type' +import { useAuth } from './useAuth' + +export function useLoginMutation() { + const router = useRouter() + const { updateAuthState } = useAuth() + + return useMutation({ + mutationFn: login, + onSuccess: async (response) => { + updateAuthState(response) + showSuccess('로그인에 성공하셨습니다!') + await new Promise((resolve) => setTimeout(resolve, 400)) + router.push('/mydashboard') + }, + 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/useLoginSubmit.ts b/src/app/features/auth/hooks/useLoginSubmit.ts deleted file mode 100644 index da476f9..0000000 --- a/src/app/features/auth/hooks/useLoginSubmit.ts +++ /dev/null @@ -1,28 +0,0 @@ -import axios from 'axios' -import { useRouter } from 'next/navigation' -import { toast } from 'sonner' - -import { LoginRequest } from '../types/auth.type' -import { useAuth } from './useAuth' - -export function useLoginSubmit() { - const { login } = useAuth() - const router = useRouter() - - async function submit(data: LoginRequest) { - try { - await login(data) - toast.success('로그인 성공') - router.push('/mydashboard') - } 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 f03d8e3..c024759 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -67,7 +67,9 @@ body { .BG-ThemeToggleButton { @apply bg-[#FFFFFF] dark:bg-[#D3D3D3]; } - +.Text-violet { + @apply text-[#228DFF]; +} .BG-drag-hovered { @apply bg-blue-100; }