From 990954d7d463b84b240af8dc3601ba0cce679ae6 Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 14:12:10 +0900 Subject: [PATCH 01/13] =?UTF-8?q?=F0=9F=97=91=EF=B8=8Fremove:=20gitkeep=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/features/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/app/features/.gitkeep diff --git a/src/app/features/.gitkeep b/src/app/features/.gitkeep deleted file mode 100644 index e69de29..0000000 From 06e6a2e648dc73af05b406027b1fc8d950f72348 Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 14:13:15 +0900 Subject: [PATCH 02/13] =?UTF-8?q?=F0=9F=8E=A8style:=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/globals.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/globals.css b/src/app/globals.css index 4a53a73..d68ca28 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -67,3 +67,6 @@ body { .BG-ThemeToggleButton { @apply bg-[#FFFFFF] dark:bg-[#D3D3D3]; } +.Text-violet { + @apply text-[#228DFF]; +} From 33bbfcf73b812809736284497443addf8d44588d Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 14:24:11 +0900 Subject: [PATCH 03/13] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor:=20useAuth=20?= =?UTF-8?q?=EB=82=B4=EB=B6=80=20=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EC=83=81=ED=83=9C=20=EA=B4=80=EB=A6=AC=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/features/auth/hooks/useAuth.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/app/features/auth/hooks/useAuth.ts b/src/app/features/auth/hooks/useAuth.ts index d4d1c1e..0011363 100644 --- a/src/app/features/auth/hooks/useAuth.ts +++ b/src/app/features/auth/hooks/useAuth.ts @@ -1,12 +1,16 @@ -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) + async function updateAuthState(response: { + accessToken: string + user: User + }) { const { accessToken, user } = response if (!accessToken || !user) { @@ -27,7 +31,7 @@ export function useAuth() { } return { - login, + updateAuthState, signup, logout, } From edc091eb727eaf72f8cd5b38279cf5ed0e7ee890 Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 14:54:30 +0900 Subject: [PATCH 04/13] =?UTF-8?q?=E2=9C=A8feat:=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20react-query=20useMutation?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=A0=84=ED=99=98=20=EB=B0=8F=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/auth/components/LoginForm.tsx | 11 ++++--- .../features/auth/hooks/useLoginMutaion.ts | 30 +++++++++++++++++++ src/app/features/auth/hooks/useLoginSubmit.ts | 28 ----------------- 3 files changed, 37 insertions(+), 32 deletions(-) create mode 100644 src/app/features/auth/hooks/useLoginMutaion.ts delete mode 100644 src/app/features/auth/hooks/useLoginSubmit.ts diff --git a/src/app/features/auth/components/LoginForm.tsx b/src/app/features/auth/components/LoginForm.tsx index 5b1fe8b..8e03e13 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 { useLoginMutaion } from '../hooks/useLoginMutaion' import { loginValidation } from '../schemas/loginValidation' import { LoginRequest } from '../types/auth.type' @@ -21,12 +21,15 @@ export default function LoginForm() { }, }) - const { submit } = useLoginSubmit() + const { mutate: loginMutate, isPending } = useLoginMutaion() const showEmailError = !!errors.email const showPasswordError = !!errors.password return ( -
+ loginMutate(data))} + > - 로그인 + {isPending ? '로그인 중..' : '로그인'}
) diff --git a/src/app/features/auth/hooks/useLoginMutaion.ts b/src/app/features/auth/hooks/useLoginMutaion.ts new file mode 100644 index 0000000..6328127 --- /dev/null +++ b/src/app/features/auth/hooks/useLoginMutaion.ts @@ -0,0 +1,30 @@ +import { useMutation } from '@tanstack/react-query' +import axios from 'axios' +import { useRouter } from 'next/navigation' +import { toast } from 'sonner' + +import { login } from '../api/authApi' +import { useAuth } from './useAuth' + +export function useLoginMutaion() { + const router = useRouter() + const { updateAuthState } = useAuth() + + return useMutation({ + mutationFn: login, + onSuccess: async (response) => { + updateAuthState(response) + toast.success('로그인 성공') + await new Promise((resolve) => setTimeout(resolve, 400)) + router.push('/mydashboard') + }, + onError: (error: unknown) => { + if (axios.isAxiosError(error)) { + const message = error.response?.data?.message + toast.error(message ?? '로그인 실패') + } else { + toast.error('알 수 없는 에러 발생') + } + }, + }) +} 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 } -} From 54b57bab13bc92fa0bb74388d9aaad2eece54c0c Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 14:55:21 +0900 Subject: [PATCH 05/13] =?UTF-8?q?=F0=9F=AB=A7modify:=20import=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/features/auth/api/authApi.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 From 9d0aa932877ed8d6e04bc8a22c6c935c2adccade Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 14:55:52 +0900 Subject: [PATCH 06/13] =?UTF-8?q?=F0=9F=8E=A8style:=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(auth)/layout.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/app/(auth)/layout.tsx 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} +
+
+ ) +} From 3874b83efce38b10929c7ab10f0998836aac8be4 Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 14:56:11 +0900 Subject: [PATCH 07/13] =?UTF-8?q?=E2=9C=A8feat:=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(auth)/login/page.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 ( <> + +

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

) } From e1810b06a30943a16914b5bf0168096414f455bf Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 15:27:16 +0900 Subject: [PATCH 08/13] =?UTF-8?q?=F0=9F=AB=A7modify:=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=20=EB=B3=80=EC=88=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/features/auth/components/LoginForm.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/app/features/auth/components/LoginForm.tsx b/src/app/features/auth/components/LoginForm.tsx index 8e03e13..6002495 100644 --- a/src/app/features/auth/components/LoginForm.tsx +++ b/src/app/features/auth/components/LoginForm.tsx @@ -22,8 +22,6 @@ export default function LoginForm() { }) const { mutate: loginMutate, isPending } = useLoginMutaion() - const showEmailError = !!errors.email - const showPasswordError = !!errors.password return (
From adbba5526f9dca8c7fe830a82fe2b828f98afc55 Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 15:45:35 +0900 Subject: [PATCH 10/13] =?UTF-8?q?=F0=9F=AB=A7modify:=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=20=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/features/auth/hooks/useAuth.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/app/features/auth/hooks/useAuth.ts b/src/app/features/auth/hooks/useAuth.ts index 0011363..ecda0ec 100644 --- a/src/app/features/auth/hooks/useAuth.ts +++ b/src/app/features/auth/hooks/useAuth.ts @@ -7,10 +7,7 @@ import { SignupRequest } from '../types/auth.type' export function useAuth() { const { setAccessToken, setUser, clearAuthState } = useAuthStore() - async function updateAuthState(response: { - accessToken: string - user: User - }) { + function updateAuthState(response: { accessToken: string; user: User }) { const { accessToken, user } = response if (!accessToken || !user) { From fdbd6c98ceda71ee0e4b60ee8400f0e1fd65ad31 Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 17:08:47 +0900 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=90=9Bfix:=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=9E=98=EB=B9=97=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/features/auth/components/LoginForm.tsx | 14 ++++++-------- .../{useLoginMutaion.ts => useLoginMutation.ts} | 7 ++++--- 2 files changed, 10 insertions(+), 11 deletions(-) rename src/app/features/auth/hooks/{useLoginMutaion.ts => useLoginMutation.ts} (80%) diff --git a/src/app/features/auth/components/LoginForm.tsx b/src/app/features/auth/components/LoginForm.tsx index 5deba10..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 { useLoginMutaion } from '../hooks/useLoginMutaion' +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,12 +21,12 @@ export default function LoginForm() { }, }) - const { mutate: loginMutate, isPending } = useLoginMutaion() + const { mutate: loginMutate, isPending } = useLoginMutation() return ( loginMutate(data))} + onSubmit={handleSubmit(async (data) => await loginMutate(data))} > {isPending ? '로그인 중..' : '로그인'} diff --git a/src/app/features/auth/hooks/useLoginMutaion.ts b/src/app/features/auth/hooks/useLoginMutation.ts similarity index 80% rename from src/app/features/auth/hooks/useLoginMutaion.ts rename to src/app/features/auth/hooks/useLoginMutation.ts index 6328127..7c9a814 100644 --- a/src/app/features/auth/hooks/useLoginMutaion.ts +++ b/src/app/features/auth/hooks/useLoginMutation.ts @@ -4,13 +4,14 @@ import { useRouter } from 'next/navigation' import { toast } from 'sonner' import { login } from '../api/authApi' +import { LoginRequest, LoginResponse } from '../types/auth.type' import { useAuth } from './useAuth' -export function useLoginMutaion() { +export function useLoginMutation() { const router = useRouter() const { updateAuthState } = useAuth() - return useMutation({ + return useMutation({ mutationFn: login, onSuccess: async (response) => { updateAuthState(response) @@ -18,7 +19,7 @@ export function useLoginMutaion() { await new Promise((resolve) => setTimeout(resolve, 400)) router.push('/mydashboard') }, - onError: (error: unknown) => { + onError: (error) => { if (axios.isAxiosError(error)) { const message = error.response?.data?.message toast.error(message ?? '로그인 실패') From 47bf3d6afa1c7b0b5d30ea8b00a5d3be73e5f059 Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 17:18:59 +0900 Subject: [PATCH 12/13] =?UTF-8?q?=E2=9C=A8feat:=20=ED=86=A0=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/features/auth/hooks/useLoginMutation.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/features/auth/hooks/useLoginMutation.ts b/src/app/features/auth/hooks/useLoginMutation.ts index 7c9a814..95cd393 100644 --- a/src/app/features/auth/hooks/useLoginMutation.ts +++ b/src/app/features/auth/hooks/useLoginMutation.ts @@ -1,7 +1,7 @@ +import { showError, showSuccess } from '@lib/toast' import { useMutation } from '@tanstack/react-query' import axios from 'axios' import { useRouter } from 'next/navigation' -import { toast } from 'sonner' import { login } from '../api/authApi' import { LoginRequest, LoginResponse } from '../types/auth.type' @@ -15,16 +15,16 @@ export function useLoginMutation() { mutationFn: login, onSuccess: async (response) => { updateAuthState(response) - toast.success('로그인 성공') + showSuccess('로그인에 성공하셨습니다!') await new Promise((resolve) => setTimeout(resolve, 400)) router.push('/mydashboard') }, onError: (error) => { if (axios.isAxiosError(error)) { const message = error.response?.data?.message - toast.error(message ?? '로그인 실패') + showError(message ?? '로그인에 실패하셨습니다.') } else { - toast.error('알 수 없는 에러 발생') + showError('알 수 없는 에러 발생') } }, }) From f4bdea9c4d03a15d5e1540472dc784aa62f93202 Mon Sep 17 00:00:00 2001 From: Joinsung Date: Tue, 17 Jun 2025 17:32:13 +0900 Subject: [PATCH 13/13] =?UTF-8?q?=F0=9F=90=9Bfix:=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=9E=98=EB=B9=97=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/features/auth/hooks/useLoginMutation.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/features/auth/hooks/useLoginMutation.ts b/src/app/features/auth/hooks/useLoginMutation.ts index 95cd393..c7bfeee 100644 --- a/src/app/features/auth/hooks/useLoginMutation.ts +++ b/src/app/features/auth/hooks/useLoginMutation.ts @@ -1,5 +1,6 @@ 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' @@ -11,7 +12,7 @@ export function useLoginMutation() { const router = useRouter() const { updateAuthState } = useAuth() - return useMutation({ + return useMutation({ mutationFn: login, onSuccess: async (response) => { updateAuthState(response) @@ -21,8 +22,11 @@ export function useLoginMutation() { }, onError: (error) => { if (axios.isAxiosError(error)) { - const message = error.response?.data?.message - showError(message ?? '로그인에 실패하셨습니다.') + const severMessage = ( + error.response?.data as { message?: string } | undefined + )?.message + const fallback = error.message || '로그인 실패' + showError(severMessage ?? fallback) } else { showError('알 수 없는 에러 발생') }