Skip to content
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

Merged
merged 63 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
93e357b
Feat: 모달 프레임 구현 및 인풋 컴포넌트 추가
minjeong9919 Jun 10, 2024
5a6b1e6
Refactor: 'develop' 브랜치 pull
minjeong9919 Jun 11, 2024
8e1e87c
Refactor: 'develop' 브랜치 pull
minjeong9919 Jun 11, 2024
a4eca4b
Feat: 로그인 버튼 및 Oauth 추가
minjeong9919 Jun 11, 2024
8e053d0
Feat: 회원가입 모달창 인풋창 삽입
minjeong9919 Jun 11, 2024
04d67a5
Feat: 체크 svg 추가 및 circle 추가하여 수정
minjeong9919 Jun 11, 2024
f261641
Feat: 체크박스 커스텀
minjeong9919 Jun 12, 2024
6632c24
Feat: 약관 동의 컴포넌트 구현
minjeong9919 Jun 12, 2024
11b4dc4
Feat: 약관 체크 유무에 따라 모두 동의 약관이 자동으로 변하도록 수정
minjeong9919 Jun 12, 2024
a685b2d
Refactor: 회원가입 모달에서 페이지로 변환
minjeong9919 Jun 12, 2024
70328ce
Fix: 속성 camelCase로 수정
minjeong9919 Jun 12, 2024
a4ee643
Design: 전체적인 css 수정
minjeong9919 Jun 12, 2024
5bf7491
Feat: 로그인 실패 시 에러메세지 출력
minjeong9919 Jun 12, 2024
05bef3a
Refactor: input들 컴포넌트로 분리
minjeong9919 Jun 12, 2024
8908c52
Refactor: develop 브랜치 pull
minjeong9919 Jun 12, 2024
24d04aa
Refactor: 'develop' 브랜치 pull
minjeong9919 Jun 12, 2024
21a39c1
Refactor: 'develop' 브랜치 pull
minjeong9919 Jun 13, 2024
3393d6c
Feat: 인풋 값 미입력 후 포커스 해제 시 에러 발생 구현
minjeong9919 Jun 13, 2024
c9dc34b
Feat: 이메일 중복, 닉네임 중복 api 연동
minjeong9919 Jun 13, 2024
aec20ed
Refactor: 생년월일, 휴대폰 번호 유효성 검사 추가
minjeong9919 Jun 13, 2024
396ca5f
Feat: 약관 동의 상태 유무 부모 컴포넌트에 전달
minjeong9919 Jun 13, 2024
41c71c6
Refactor: dependency 수정
minjeong9919 Jun 13, 2024
e811144
Test: 이메일 중복, 닉네임 중복 API 요청 결과 테스트 확인 완료
minjeong9919 Jun 13, 2024
1975237
Feat: 약관 동의 후, 버튼 클릭 시 회원가입 API 요청 기능 구현
minjeong9919 Jun 14, 2024
0b39b51
Feat: 로그인 react-hook-form 적용
minjeong9919 Jun 14, 2024
9ee1236
Fix: Radio 버튼 임시로 수정
minjeong9919 Jun 14, 2024
ec85ff5
Refactor: 'develop' 브랜치 pull
minjeong9919 Jun 14, 2024
5c29263
Fix: 충돌 파일 삭제
minjeong9919 Jun 14, 2024
5d67d4d
Fix: LikeButton 잘못 제거해서 다시 생성
minjeong9919 Jun 14, 2024
c248b01
Fix: 충돌 해결을 위해 임시 파일 이름 변경
minjeong9919 Jun 14, 2024
821059c
Fix: 충돌해결 중 test,,
minjeong9919 Jun 14, 2024
16b4c49
Refactor: 'develop' 브랜치 pull
minjeong9919 Jun 14, 2024
8699175
Test: 로그인, 회원가입 API 요청 시도
minjeong9919 Jun 15, 2024
0fb8ed2
Test: Oauth 로그인 시도
minjeong9919 Jun 16, 2024
6d4941d
Test: 회원가입 API 요청 테스트 완료
minjeong9919 Jun 16, 2024
49d375d
Refactor: 이메일 중복, 닉네임 중복 응답 관리 코드 수정
minjeong9919 Jun 17, 2024
5d46156
Refactor: 로그인 성공 시 화면 새로고침
minjeong9919 Jun 17, 2024
11b1294
Feat: 로그인, 회원가입 상태에 따른 리다이렉트 구현
minjeong9919 Jun 17, 2024
425a56b
Refactor: hook form 상태에 따른 회원가입 버튼 색 실시간으로 변동
minjeong9919 Jun 18, 2024
8d327dc
Refactor: 'develop' 브랜치 pull
minjeong9919 Jun 18, 2024
8221876
Style: 토스트 커스텀 완료
minjeong9919 Jun 18, 2024
1f0b183
Refactor: 머지된 폰 넘버 컴포넌트 삽입
minjeong9919 Jun 18, 2024
6cf4083
Fix: 토스트 띄우고 페이지 이동
minjeong9919 Jun 18, 2024
b15189d
Refactor: 로그인, 회원가입 파일 위치 변경
minjeong9919 Jun 18, 2024
994ade9
Refactor: 컨벤션에 맞게 전반적인 코드 수정
minjeong9919 Jun 18, 2024
024dedc
Refactor: api 네트워크 오류, 응답 상태 처리
minjeong9919 Jun 18, 2024
f54e8eb
Refactor: 피드백 반영
minjeong9919 Jun 19, 2024
8dd4f47
Fix: .env 파일 제거
minjeong9919 Jun 19, 2024
0105ab6
Refactor: 피드백 반영
minjeong9919 Jun 19, 2024
f457938
Refactor: 닉네임 글자 수 제한 및 이름 -> 닉네임 으로 수정
minjeong9919 Jun 19, 2024
6337a56
Fix: ignore 파일에서 .env 제거
minjeong9919 Jun 19, 2024
0221036
Refactor: 'develop' 브랜치 pull
minjeong9919 Jun 20, 2024
96d1862
Refactor: signInput과 SignForm 컴포넌트를 하나로 통합
minjeong9919 Jun 20, 2024
9161854
Refactor: 상수 분리 및 변수명 수정
minjeong9919 Jun 20, 2024
61a9dfe
Refactor: 약관 동의 컴포넌트 통합
minjeong9919 Jun 20, 2024
012e4fa
Refactor: 'develop' 브랜치 pull
minjeong9919 Jun 20, 2024
ee4df43
Fix: 충돌 해결 및 수정
minjeong9919 Jun 20, 2024
a7bbe70
Fix: 파일명 수정
minjeong9919 Jun 20, 2024
8ef5ca5
Refactor: 'develop' 브랜치 pull
minjeong9919 Jun 20, 2024
8b46755
Test: push 중 오류 해결 테스트 1
minjeong9919 Jun 20, 2024
75355d0
Refactor: 피드백 반영2
minjeong9919 Jun 20, 2024
c4f518f
Refactor: 피드백 반영3
minjeong9919 Jun 20, 2024
78a902c
Fix: 저장 안 된 파일 추가
minjeong9919 Jun 20, 2024
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
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 @@ -30,6 +30,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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고양이 뚫렸네여?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오모낫 혹시 뚫리면 문제가 될 수 있을까요,,,!?!??!?!

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.
62 changes: 62 additions & 0 deletions src/api/authAPI.ts
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) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호~ formData를 미리 stringify된 걸로 가져오네요~
뭔가 아래 postSignin 함수는 함수 내부에서 string처리하는데 여긴 string으로 처리된 값을 가져오는데, 이 부분 어떻게 생각하시나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
},
body: JSON.stringify(formData),
});
},
body: JSON.stringify(formData),
});

json으로 파싱해서 보내는거면 accept는 없어되지않아요?

const data = await response.json();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구조분해해서 data.data로 리턴하는 게 사용할 때 더 쉬울 것 같아요.
responseData.data.accessToken 이런 식으로 불러오는 것을 responseData.accessToken으로 더 쉽게 불러올 수 있을 것 같아요

Suggested change
const data = await response.json();
const { data } = await response.json();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

엇 그러면 SignInModal내에서 response의 안의 status하고 Message 확인이 어렵지 않을까요..?!

return data;
} catch (error) {
throw error;
}
};
111 changes: 111 additions & 0 deletions src/app/(auth)/sign-in/_component/SignInModal.tsx
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);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기는 console찍혀도 될랑가용?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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')}>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<Link href='/sign-up' className={cn('auth-section-text')}>
<Link href={ROUTER.AUTH.SUGN_UP} className={cn('auth-section-text')}>

Copy link
Contributor

Choose a reason for hiding this comment

The 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>
);
}
61 changes: 61 additions & 0 deletions src/app/(auth)/sign-in/_component/SigninModal.module.scss
Copy link
Contributor

Choose a reason for hiding this comment

The 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;
}
}
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);
};
Comment on lines +19 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

뭔가 이름이 살짝 아쉬운 느낌이네요. handleOpenSignin? handleOpenModal?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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>
);
}
Loading