Skip to content

Commit

Permalink
Merge pull request #98 from Quad8/82-feat-로그인-회원가입-구현
Browse files Browse the repository at this point in the history
[Feat] 로그인 & 회원가입 구현
  • Loading branch information
minjeong9919 authored Jun 21, 2024
2 parents 2ab5aaa + 78a902c commit c036801
Show file tree
Hide file tree
Showing 22 changed files with 909 additions and 4 deletions.
Binary file added public/.index.ts.swp
Binary file not shown.
3 changes: 3 additions & 0 deletions public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ export { default as UpArrowIcon } from './svgs/upArrow.svg';
export { default as UserIcon } from './svgs/user.svg';
export { default as VerticalTripleDotIcon } from './svgs/verticalTripleDot.svg';
export { default as WarnCircleIcon } from './svgs/warnCircle.svg';
export { default as GitHubIcon } from '@/public/svgs/gitHub.svg';
export { default as GoogleIcon } from '@/public/svgs/google.svg';
export { default as KakaoIcon } from '@/public/svgs/kakaotalk.svg';

export { default as blackSwitchImg } from './images/blackSwitch.jpg';
export { default as blueSwitchImg } from './images/blueSwitch.jpg';
Expand Down
10 changes: 10 additions & 0 deletions public/svgs/gitHub.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions public/svgs/google.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions public/svgs/kakaotalk.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions src/api/authAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
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) => {
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',
},
body: JSON.stringify(formData),
});
const data = await response.json();
return data;
} catch (error) {
throw error;
}
};
112 changes: 112 additions & 0 deletions src/app/(auth)/sign-in/_component/SignInModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
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 { ROUTER } from '@/constants/route';

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) {
toast.error('로그인 중 오류가 발생했습니다. 잠시 후 다시 시도해주세요.');
}
};

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={ROUTER.AHTH.SIGN_UP} className={cn('auth-section-text')}>
{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>
);
}
63 changes: 63 additions & 0 deletions src/app/(auth)/sign-in/_component/SigninModal.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
.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 {
@include flex-column(4rem);

margin-bottom: 6.8rem;
}

.auth-section-wrapper {
@include flex-center;
@include pretendard-14-400;

margin-bottom: 6rem;
}

.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;
}
}
5 changes: 5 additions & 0 deletions src/app/(auth)/sign-in/page.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.container {
width: 100%;
height: 200rem;
@include flex-column(2rem);
}
32 changes: 32 additions & 0 deletions src/app/(auth)/sign-in/page.tsx
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);
};

return (
<div className={cn('container')}>
<Button onClick={handleSignin}> 로그인 모달창</Button>
<a href='/sign-up'> 회원가입 하러가기</a>
<Modal isOpen={isOpenModal} onClose={handleCloseModal}>
<SignInModal />
</Modal>
</div>
);
}
Loading

0 comments on commit c036801

Please sign in to comment.