-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #40 from boostcampwm-2024/feature/connect/login-#4
[FE] 로그인 API 연동 #4
- Loading branch information
Showing
8 changed files
with
117 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,12 @@ | ||
import { HTMLInputTypeAttribute } from 'react'; | ||
import { ComponentProps } from 'react'; | ||
|
||
type LoginInputProps = { | ||
type: HTMLInputTypeAttribute; | ||
placeholder: string; | ||
}; | ||
type LoginInputProps = ComponentProps<'input'>; | ||
|
||
export default function Input({ type, placeholder }: LoginInputProps) { | ||
export default function Input({ ...props }: LoginInputProps) { | ||
return ( | ||
<input | ||
className='px-4 py-2 text-sm border-2 rounded-lg outline-none' | ||
type={type} | ||
placeholder={placeholder} | ||
{...props} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,72 @@ | ||
import useLoginModalStore from 'store/useLoginModalStore'; | ||
import Input from './Input'; | ||
import { ChatBubbleOvalLeftIcon } from '@heroicons/react/16/solid'; | ||
import { FormEvent, useEffect, useState } from 'react'; | ||
import { login } from 'service/auth'; | ||
import useAuthStore from 'store/authStore'; | ||
|
||
export default function Login() { | ||
const { isOpen, toggleModal } = useLoginModalStore(); | ||
const [email, setEmail] = useState(''); | ||
const [password, setPassword] = useState(''); | ||
const { setAccessToken } = useAuthStore(); | ||
|
||
useEffect(() => { | ||
setEmail(''); | ||
setPassword(''); | ||
}, [isOpen]); | ||
|
||
if (!isOpen) return; | ||
|
||
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
const res = await login(email, password); | ||
|
||
if ('error' in res) { | ||
return; | ||
} | ||
|
||
setAccessToken(res.accessToken); | ||
toggleModal(); | ||
}; | ||
|
||
return ( | ||
<> | ||
<Overay onClick={() => toggleModal()} /> | ||
<section className='fixed left-1/2 top-1/2 flex w-[500px] -translate-x-1/2 -translate-y-1/2 flex-col rounded-2xl bg-white p-20 shadow-lg'> | ||
<h2 className='text-3xl font-bold'>JuGa</h2> | ||
<div className='flex flex-col gap-2 my-10'> | ||
<Input type='text' placeholder='아이디' /> | ||
<Input type='password' placeholder='비밀번호' /> | ||
</div> | ||
<div className='flex flex-col gap-2'> | ||
<form className='flex flex-col mb-2' onSubmit={handleSubmit}> | ||
<div className='flex flex-col gap-2 my-10'> | ||
<Input | ||
type='text' | ||
placeholder='아이디' | ||
value={email} | ||
onChange={(e) => setEmail(e.target.value)} | ||
autoComplete='username' | ||
/> | ||
<Input | ||
type='password' | ||
placeholder='비밀번호' | ||
value={password} | ||
onChange={(e) => setPassword(e.target.value)} | ||
autoComplete='current-password' | ||
/> | ||
</div> | ||
<button className='py-2 text-white transition rounded-3xl bg-juga-blue-40 hover:bg-juga-blue-50'> | ||
로그인 | ||
</button> | ||
<button className='flex items-center justify-center gap-2 rounded-3xl bg-yellow-300 px-3.5 py-2 transition hover:bg-yellow-400'> | ||
<ChatBubbleOvalLeftIcon className='size-5' /> | ||
<p>카카오 계정으로 로그인</p> | ||
</button> | ||
</div> | ||
</form> | ||
<button className='flex items-center justify-center gap-2 rounded-3xl bg-yellow-300 px-3.5 py-2 transition hover:bg-yellow-400'> | ||
<ChatBubbleOvalLeftIcon className='size-5' /> | ||
<p>카카오 계정으로 로그인</p> | ||
</button> | ||
</section> | ||
</> | ||
); | ||
} | ||
|
||
function Overay({ onClick }: { onClick: () => void }) { | ||
return ( | ||
<div className='fixed inset-0 bg-black opacity-5' onClick={onClick}></div> | ||
<div className='fixed inset-0 bg-black opacity-30' onClick={onClick}></div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { LoginFailResponse, LoginSuccessResponse } from 'types'; | ||
|
||
export async function login( | ||
email: string, | ||
password: string, | ||
): Promise<LoginSuccessResponse | LoginFailResponse> { | ||
return fetch('http://223.130.151.42:3000/auth/login', { | ||
method: 'POST', | ||
headers: { 'Content-Type': 'application/json' }, | ||
body: JSON.stringify({ | ||
email, | ||
password, | ||
}), | ||
}).then((res) => res.json()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { create } from 'zustand'; | ||
|
||
type AuthStore = { | ||
accessToken: string | null; | ||
isLogin: boolean; | ||
setAccessToken: (token: string) => void; | ||
resetToken: () => void; | ||
}; | ||
|
||
const useAuthStore = create<AuthStore>((set) => ({ | ||
accessToken: null, | ||
isLogin: false, | ||
setAccessToken: (token: string) => { | ||
set({ accessToken: token, isLogin: token !== null }); | ||
}, | ||
resetToken: () => { | ||
set({ accessToken: null, isLogin: false }); | ||
}, | ||
})); | ||
|
||
export default useAuthStore; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export type LoginSuccessResponse = { | ||
accessToken: string; | ||
}; | ||
|
||
export type LoginFailResponse = { | ||
error: string; | ||
message: string[]; | ||
statusCode: number; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters