Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use client'

import LoginForm from '@/app/features/auth/components/LoginForm'

export default function Login() {
return (
<>
<LoginForm />
</>
)
}
2 changes: 1 addition & 1 deletion src/app/auth/page.tsx → src/app/(auth)/signin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default function MyForm() {
hasError={touchedFields.password && !!errors.password}
errorMessage={touchedFields.password ? errors.password?.message : ''}
/>

<Input labelName="안녕" name="text" />
<button
type="submit"
className="mt-4 rounded bg-blue-500 py-2 text-white"
Expand Down
Empty file removed src/app/auth/.gitkeep
Empty file.
60 changes: 60 additions & 0 deletions src/app/features/auth/components/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use client'

import Input from '@components/Input'
import { cn } from '@lib/cn'
import { useForm } from 'react-hook-form'

import { useLoginSubmit } from '../hooks/useLoginSubmit'
import { loginValidation } from '../schemas/loginValidation'
import { LoginRequest } from '../types/auth.type'

export default function LoginForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting, isValid },
} = useForm<LoginRequest>({
mode: 'onChange',
defaultValues: {
email: '',
password: '',
},
})

const { submit } = useLoginSubmit()
const showEmailError = !!errors.email
const showPasswordError = !!errors.password

return (
<form className="flex flex-col gap-16" onSubmit={handleSubmit(submit)}>
<Input
labelName="이메일"
type="email"
placeholder="이메일 입력"
autoComplete="email"
{...register('email', loginValidation.email)}
hasError={showEmailError}
errorMessage={errors.email?.message}
/>
<Input
labelName="비밀번호"
type="password"
placeholder="비밀번호 입력"
autoComplete="off"
{...register('password', loginValidation.password)}
hasError={showPasswordError}
errorMessage={errors.password?.message}
/>
<button
type="submit"
className={cn(
'mt-8 h-50 w-full rounded-8 text-lg font-medium text-white',
isValid && !isSubmitting ? 'BG-blue' : 'BG-blue-disabled',
)}
disabled={!isValid || isSubmitting}
>
로그인
</button>
</form>
)
}
3 changes: 2 additions & 1 deletion src/app/features/auth/hooks/useAuth.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useAuthStore } from '../store/useAuthStore'
import { login as loginApi, signup as signupApi } from '../api/authApi'
import { useAuthStore } from '../store/useAuthStore'
import { LoginRequest, SignupRequest } from '../types/auth.type'

export function useAuth() {
Expand All @@ -23,6 +23,7 @@ export function useAuth() {

function logout() {
clearAuthState()
useAuthStore.persist.clearStorage()
}

return {
Expand Down
28 changes: 28 additions & 0 deletions src/app/features/auth/hooks/useLoginSubmit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
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 }
}
16 changes: 16 additions & 0 deletions src/app/features/auth/schemas/loginValidation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const loginValidation = {
email: {
required: '이메일을 입력해 주세요.',
pattern: {
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
message: '유효한 이메일 주소를 입력해주세요',
},
},
password: {
required: '비밀번호를 입력해 주세요.',
minLength: {
value: 8,
message: '비밀번호는 최소 8자 이상이어야 합니다.',
},
},
}
4 changes: 4 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ body {
.BG-blue {
@apply bg-[#83C8FA] hover:bg-[#5FBBFF] dark:bg-[#228DFF] dark:hover:bg-[#2172C9];
}
.BG-blue-disabled {
@apply cursor-not-allowed bg-[#9FA6B2];
}

.Text-black {
@apply text-[#333236] dark:text-[#FFFFFF];
}
Expand Down