-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feat] 로그인 & 회원가입 구현 #98
The head ref may contain hidden characters: "82-feat-\uB85C\uADF8\uC778-\uD68C\uC6D0\uAC00\uC785-\uAD6C\uD604"
Changes from 59 commits
93e357b
5a6b1e6
8e1e87c
a4eca4b
8e053d0
04d67a5
f261641
6632c24
11b4dc4
a685b2d
70328ce
a4ee643
5bf7491
05bef3a
8908c52
24d04aa
21a39c1
3393d6c
c9dc34b
aec20ed
396ca5f
41c71c6
e811144
1975237
0b39b51
9ee1236
ec85ff5
5c29263
5d67d4d
c248b01
821059c
16b4c49
8699175
0fb8ed2
6d4941d
49d375d
5d46156
11b1294
425a56b
8d327dc
8221876
1f0b183
6cf4083
b15189d
994ade9
024dedc
f54e8eb
8dd4f47
0105ab6
f457938
6337a56
0221036
96d1862
9161854
61a9dfe
012e4fa
ee4df43
a7bbe70
8ef5ca5
8b46755
75355d0
c4f518f
78a902c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,62 @@ | ||||||||||||||
import type { FetchSignInInfoTypes } from '@/types/authTypes'; | ||||||||||||||
|
||||||||||||||
const BASE_URL = process.env.NEXT_PUBLIC_KEYDEUK_API_BASE_URL; | ||||||||||||||
|
||||||||||||||
export const getCheckEmailDuplication = async (emailValue: string) => { | ||||||||||||||
const url = `${BASE_URL}/api/v1/users/check/email?email=${emailValue}`; | ||||||||||||||
try { | ||||||||||||||
const response = await fetch(url); | ||||||||||||||
const data = await response.json(); | ||||||||||||||
return data; | ||||||||||||||
} catch (error) { | ||||||||||||||
throw error; | ||||||||||||||
} | ||||||||||||||
}; | ||||||||||||||
|
||||||||||||||
export const getCheckNicknameDuplication = async (nickname: string) => { | ||||||||||||||
const url = `${BASE_URL}/api/v1/users/check/nickname?nickname=${nickname}`; | ||||||||||||||
try { | ||||||||||||||
const response = await fetch(url); | ||||||||||||||
const data = await response.json(); | ||||||||||||||
return data; | ||||||||||||||
} catch (error) { | ||||||||||||||
throw error; | ||||||||||||||
} | ||||||||||||||
}; | ||||||||||||||
|
||||||||||||||
export const postSignup = async (formData: FormData) => { | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오호~ formData를 미리 stringify된 걸로 가져오네요~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. postSignin이랑 postSignup의 보내주는 데이터 형식이 다릅니다!! signup은 formdata 형식으로 보내주고, signin은 json 형식이라서요,, |
||||||||||||||
const url = `${BASE_URL}/api/v1/users`; | ||||||||||||||
|
||||||||||||||
try { | ||||||||||||||
const response = await fetch(url, { | ||||||||||||||
method: 'POST', | ||||||||||||||
headers: { | ||||||||||||||
accept: 'application/json', | ||||||||||||||
}, | ||||||||||||||
body: formData, | ||||||||||||||
}); | ||||||||||||||
const data = await response.json(); | ||||||||||||||
return data; | ||||||||||||||
} catch (error) { | ||||||||||||||
throw error; | ||||||||||||||
} | ||||||||||||||
}; | ||||||||||||||
|
||||||||||||||
export const postSignin = async (formData: FetchSignInInfoTypes) => { | ||||||||||||||
const url = `${BASE_URL}/login`; | ||||||||||||||
|
||||||||||||||
try { | ||||||||||||||
const response = await fetch(url, { | ||||||||||||||
method: 'POST', | ||||||||||||||
headers: { | ||||||||||||||
'Content-Type': 'application/json', | ||||||||||||||
Accept: 'application/json', | ||||||||||||||
}, | ||||||||||||||
body: JSON.stringify(formData), | ||||||||||||||
}); | ||||||||||||||
Comment on lines
+53
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
json으로 파싱해서 보내는거면 accept는 없어되지않아요? |
||||||||||||||
const data = await response.json(); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 구조분해해서 data.data로 리턴하는 게 사용할 때 더 쉬울 것 같아요.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 엇 그러면 SignInModal내에서 response의 안의 status하고 Message 확인이 어렵지 않을까요..?! |
||||||||||||||
return data; | ||||||||||||||
} catch (error) { | ||||||||||||||
throw error; | ||||||||||||||
} | ||||||||||||||
}; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,111 @@ | ||||||
import classNames from 'classnames/bind'; | ||||||
import { FieldValues, SubmitHandler, useForm } from 'react-hook-form'; | ||||||
import Link from 'next/link'; | ||||||
import { toast } from 'react-toastify'; | ||||||
|
||||||
import { InputField, Button } from '@/components'; | ||||||
import { GitHubIcon, GoogleIcon, KakaoIcon } from '@/public/index'; | ||||||
import { postSignin } from '@/api/authAPI'; | ||||||
import { setCookie } from '@/libs/manageCookie'; | ||||||
import type { FetchSignInInfoTypes } from '@/types/authTypes'; | ||||||
|
||||||
import styles from './SigninModal.module.scss'; | ||||||
|
||||||
const cn = classNames.bind(styles); | ||||||
|
||||||
const AUTH_SECTION = ['아이디 찾기', '비밀번호 찾기', '회원가입']; | ||||||
const BASE_URL = process.env.NEXT_PUBLIC_KEYDEUK_API_BASE_URL; | ||||||
|
||||||
export default function SignInModal() { | ||||||
const { | ||||||
register, | ||||||
formState: { errors }, | ||||||
handleSubmit, | ||||||
} = useForm({ | ||||||
mode: 'onBlur', | ||||||
defaultValues: { | ||||||
email: '', | ||||||
password: '', | ||||||
}, | ||||||
}); | ||||||
|
||||||
const registers = { | ||||||
email: register('email', { | ||||||
required: '이메일을 입력해주세요.', | ||||||
}), | ||||||
password: register('password', { | ||||||
required: '비밀번호를 입력해주세요.', | ||||||
}), | ||||||
}; | ||||||
|
||||||
const onSubmit: SubmitHandler<FieldValues> = async (formData) => { | ||||||
try { | ||||||
const responseData = await postSignin(formData as FetchSignInInfoTypes); | ||||||
|
||||||
if (responseData.status === 'SUCCESS') { | ||||||
setCookie('accessToken', responseData.data.accessToken); | ||||||
setCookie('refreshToken', responseData.data.refreshToken); | ||||||
toast.success('로그인이 성공적으로 완료되었습니다.'); | ||||||
setTimeout(() => { | ||||||
window.location.reload(); | ||||||
}, 2000); | ||||||
} else if (responseData.status === 'FAIL') { | ||||||
toast.error(responseData.message); | ||||||
} | ||||||
} catch (error) { | ||||||
console.error('로그인 요청 실패', error); | ||||||
} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기는 console찍혀도 될랑가용? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 어머머머 센스쟁이 바아로 수정 갑니닷 |
||||||
}; | ||||||
|
||||||
const handleKakaoOauth = async (provider: string) => { | ||||||
window.location.href = `${BASE_URL}/oauth2/authorization/${provider}`; | ||||||
}; | ||||||
|
||||||
return ( | ||||||
<form className={cn('container')} onSubmit={handleSubmit(onSubmit)}> | ||||||
<h1 className={cn('title')}>로그인</h1> | ||||||
<div className={cn('input-wrapper')}> | ||||||
<InputField | ||||||
label='이메일' | ||||||
placeholder='이메일을 입력해주세요' | ||||||
sizeVariant='md' | ||||||
labelSize='sm' | ||||||
errorMessage={errors.email?.message} | ||||||
{...registers.email} | ||||||
/> | ||||||
<InputField | ||||||
label='비밀번호' | ||||||
placeholder='비밀번호를 입력해주세요' | ||||||
sizeVariant='md' | ||||||
labelSize='sm' | ||||||
type='password' | ||||||
suffixIcon='eye' | ||||||
errorMessage={errors.password?.message} | ||||||
{...registers.password} | ||||||
/> | ||||||
</div> | ||||||
<div className={cn('auth-section-wrapper')}> | ||||||
{AUTH_SECTION.map((text, i) => ( | ||||||
<div key={text} className={cn('auth-section')}> | ||||||
<Link href='/sign-up' className={cn('auth-section-text')}> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 상수로 쓰면 좋을거같아요 |
||||||
{text} | ||||||
</Link> | ||||||
{i === 2 || <div className={cn('bar')}>|</div>} | ||||||
</div> | ||||||
))} | ||||||
</div> | ||||||
<Button className={cn('button')} fontSize={24} type='submit'> | ||||||
로그인 | ||||||
</Button> | ||||||
|
||||||
<div className={cn('o-auth-wrapper')}> | ||||||
<p>간편 로그인 하기</p> | ||||||
<div className={cn('icons')}> | ||||||
<GitHubIcon onClick={() => handleKakaoOauth('github')} /> | ||||||
<GoogleIcon onClick={() => handleKakaoOauth('google')} /> | ||||||
<KakaoIcon onClick={() => handleKakaoOauth('kakao')} /> | ||||||
</div> | ||||||
</div> | ||||||
</form> | ||||||
); | ||||||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. include 순서 일치하면 좋을 것 같습니다! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
.container { | ||
width: 56.2rem; | ||
padding: 4rem; | ||
border-radius: 2.4rem; | ||
background-color: $white; | ||
} | ||
|
||
.title { | ||
margin-bottom: 8rem; | ||
font-size: 3rem; | ||
font-weight: bold; | ||
text-align: center; | ||
} | ||
|
||
.input-wrapper { | ||
margin-bottom: 6.8rem; | ||
@include flex-column(4rem); | ||
} | ||
|
||
.auth-section-wrapper { | ||
margin-bottom: 6rem; | ||
@include flex-center; | ||
@include pretendard-14-400; | ||
} | ||
|
||
.auth-section { | ||
display: flex; | ||
|
||
& > .auth-section-text { | ||
color: $gray-50; | ||
cursor: pointer; | ||
} | ||
|
||
& > .bar { | ||
margin: 0 1.2rem; | ||
color: $gray-20; | ||
cursor: default; | ||
} | ||
} | ||
|
||
.button { | ||
margin-bottom: 4rem; | ||
} | ||
|
||
.o-auth-wrapper { | ||
@include pretendard-14-400; | ||
@include flex-column(2rem); | ||
|
||
color: $gray-50; | ||
text-align: center; | ||
} | ||
|
||
.icons { | ||
display: flex; | ||
gap: 3.6rem; | ||
justify-content: center; | ||
|
||
& > * { | ||
cursor: pointer; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.container { | ||
width: 100%; | ||
height: 200rem; | ||
@include flex-column(2rem); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
'use client'; | ||
|
||
// 테스트 페이지 입니다. | ||
import classNames from 'classnames/bind'; | ||
import { useState } from 'react'; | ||
import { Modal, Button } from '@/components'; | ||
import styles from './page.module.scss'; | ||
import SignInModal from './_component/SignInModal'; | ||
|
||
const cn = classNames.bind(styles); | ||
|
||
export default function Page() { | ||
const [isOpenModal, setIsOpenModal] = useState(false); | ||
|
||
const handleCloseModal = () => { | ||
setIsOpenModal(false); | ||
}; | ||
|
||
const handleSignin = () => { | ||
setIsOpenModal(true); | ||
}; | ||
Comment on lines
+19
to
+21
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 뭔가 이름이 살짝 아쉬운 느낌이네요. handleOpenSignin? handleOpenModal? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여긴 저스트 테스트 페이지라서 임의로 지어봤답니당 😆 로그인은 모달창이라 아마 이 페이지는 삭제될 거예요!! |
||
|
||
return ( | ||
<div className={cn('container')}> | ||
<Button onClick={handleSignin}> 로그인 모달창</Button> | ||
<a href='/sign-up'> 회원가입 하러가기</a> | ||
<Modal isOpen={isOpenModal} onClose={handleCloseModal}> | ||
<SignInModal /> | ||
</Modal> | ||
</div> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고양이 뚫렸네여?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오모낫 혹시 뚫리면 문제가 될 수 있을까요,,,!?!??!?!