Skip to content

Commit d40b25d

Browse files
authored
Merge pull request #167 from ASAP-Lettering/feat/#165
[Feat] 네이버 로그인
2 parents f02c0f5 + 73b1139 commit d40b25d

File tree

15 files changed

+303
-292
lines changed

15 files changed

+303
-292
lines changed

src/api/login/oauth.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { Provider } from '@/types/login';
2+
import client from '../client';
3+
4+
export const getOauthAccessToken = async (
5+
provider: Provider,
6+
code: string,
7+
state: string
8+
) => {
9+
const response = await client.post(`/api/v1/auth/token/${provider}`, {
10+
code: code,
11+
state: state
12+
});
13+
const { accessToken } = response.data;
14+
return accessToken;
15+
};

src/api/login/user.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { RegisterDataType } from '@/types/user';
22
import client, { authClient } from '../client';
33
import { getRefreshToken, setTokens } from '@/utils/storage';
4+
import { Provider } from '@/types/login';
45

56
// 로그인
6-
export const login = async (loginType: string, accessToken: string) => {
7+
export const login = async (loginType: Provider, accessToken: string) => {
78
return await client.post(`/api/v1/auth/login/${loginType}`, {
89
accessToken: accessToken
910
});

src/app/login/auth/page.tsx

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
'use client';
22

3+
import { getOauthAccessToken } from '@/api/login/oauth';
34
import { login } from '@/api/login/user';
45
import Loader from '@/components/common/Loader';
56
import { signupState } from '@/recoil/signupStore';
6-
import { clearLetterUrl, setOnboarding, setTokens } from '@/utils/storage';
7+
import { Provider } from '@/types/login';
8+
import {
9+
clearLetterUrl,
10+
setOnboarding,
11+
setRecentLogin,
12+
setTokens
13+
} from '@/utils/storage';
714
import axios from 'axios';
815
import { useRouter } from 'next/navigation';
916
import { useEffect, useState } from 'react';
@@ -13,12 +20,10 @@ import styled from 'styled-components';
1320
const Auth = () => {
1421
const [registerToken, setRegisterToken] = useRecoilState(signupState);
1522
const router = useRouter();
16-
const REST_API_KEY = process.env.NEXT_PUBLIC_REST_API_KEY;
1723
const [absoluteUrl, setAbsoluteUrl] = useState('');
1824
const [storeUrl, setstoreUrl] = useState('');
1925
const [type, setType] = useState('');
2026
const [oauthAccessToken, setOauthAccessToken] = useState('');
21-
const [provider, setProvider] = useState('');
2227

2328
useEffect(() => {
2429
if (typeof window !== 'undefined') {
@@ -39,6 +44,7 @@ const Auth = () => {
3944
const AUTHORIZATION_CODE = new URL(window.location.href).searchParams.get(
4045
'code'
4146
);
47+
const STATE = new URL(window.location.href).searchParams.get('state');
4248

4349
const TYPE = new URL(window.location.href).searchParams.get('type');
4450

@@ -50,13 +56,12 @@ const Auth = () => {
5056
//type에 따라 다른 토큰 url 지정
5157
switch (TYPE) {
5258
case 'kakao':
53-
setProvider('KAKAO');
5459
try {
5560
const response = await axios.post(
5661
'https://kauth.kakao.com/oauth/token',
5762
new URLSearchParams({
5863
grant_type: 'authorization_code',
59-
client_id: REST_API_KEY,
64+
client_id: process.env.NEXT_PUBLIC_KAKAO_REST_API_KEY,
6065
redirect_uri: absoluteUrl,
6166
code: AUTHORIZATION_CODE
6267
}),
@@ -73,7 +78,6 @@ const Auth = () => {
7378

7479
break;
7580
case 'google':
76-
setProvider('GOOGLE');
7781
try {
7882
const body = new URLSearchParams({
7983
grant_type: 'authorization_code',
@@ -100,6 +104,18 @@ const Auth = () => {
100104
}
101105
break;
102106
case 'naver':
107+
try {
108+
const response = await getOauthAccessToken(
109+
'NAVER' as Provider,
110+
AUTHORIZATION_CODE,
111+
STATE
112+
);
113+
setOauthAccessToken(response);
114+
} catch (error) {
115+
console.error('Unsupported OAuth type:', type);
116+
clearLetterUrl();
117+
return;
118+
}
103119
break;
104120
default:
105121
console.error('Unknown OAuth type:', TYPE);
@@ -112,12 +128,14 @@ const Auth = () => {
112128
useEffect(() => {
113129
try {
114130
if (oauthAccessToken) {
115-
login(provider, oauthAccessToken)
131+
login(type?.toUpperCase() as Provider, oauthAccessToken)
116132
.then((res) => {
117133
console.log('accessToken', res.data.accessToken);
118134
setTokens(res.data.accessToken, res.data.refreshToken);
119135
/* 온보딩 여부 저장 */
120136
setOnboarding(res.data.isProcessedOnboarding);
137+
/* 최근 로그인 정보 저장 */
138+
setRecentLogin(type);
121139
if (storeUrl) {
122140
router.push(`/verify/letter?url=${storeUrl}`);
123141
clearLetterUrl();

src/app/login/page.tsx

Lines changed: 22 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,17 @@
11
'use client';
22

3-
import SocialKakao from '@/components/signup/SocialKakao';
4-
import SocialGoogle from '@/components/signup/SocialGoogle';
3+
import Loader, { LoaderContainer } from '@/components/common/Loader';
4+
import OauthButton from '@/components/signup/OauthButton';
5+
import { OAUTH } from '@/constants/oauth';
56
import { theme } from '@/styles/theme';
7+
import { OAuthType } from '@/types/login';
8+
import { Suspense } from 'react';
69
import styled from 'styled-components';
7-
import Image from 'next/image';
8-
9-
interface OauthButtonProps {
10-
bgColor: string;
11-
}
1210

1311
const notReady = () => {
1412
alert('준비 중입니다.');
1513
};
1614

17-
const oauthButtons = [
18-
{
19-
key: 'naver',
20-
bgColor: '#03CF5D',
21-
component: (
22-
<Image
23-
src="/assets/icons/ic_naver.svg"
24-
alt="Naver"
25-
width={26}
26-
height={26}
27-
onClick={() => alert('준비 중입니다.')}
28-
/>
29-
)
30-
},
31-
{
32-
key: 'google',
33-
bgColor: '#FFFFFF',
34-
component: <SocialGoogle />
35-
},
36-
{
37-
key: 'kakao',
38-
bgColor: '#FEE500',
39-
component: <SocialKakao />
40-
}
41-
];
42-
4315
export default function Login() {
4416
return (
4517
<Container>
@@ -48,11 +20,23 @@ export default function Login() {
4820
<LogoText>편지로 수놓는 나의 스페이스</LogoText>
4921
<LogoImage src="/assets/login/login_logo.png" />
5022
<OauthWrapper>
51-
{oauthButtons.map(({ key, bgColor, component }) => (
52-
<OauthButton key={key} bgColor={bgColor}>
53-
{component}
54-
</OauthButton>
55-
))}
23+
<Suspense
24+
fallback={
25+
<LoaderContainer>
26+
<Loader />
27+
</LoaderContainer>
28+
}
29+
>
30+
{OAUTH.map((item) => (
31+
<OauthButton
32+
key={item.key}
33+
loginType={item.key as OAuthType}
34+
bgColor={item.bgColor}
35+
icon={item.icon}
36+
size={item.size}
37+
/>
38+
))}
39+
</Suspense>
5640
</OauthWrapper>
5741
<LetterBtnText onClick={notReady}>
5842
로그인 없이 편지 작성해보기
@@ -157,20 +141,6 @@ const OauthWrapper = styled.div`
157141
justify-content: center;
158142
`;
159143

160-
const OauthButton = styled.button<OauthButtonProps>`
161-
width: 69px;
162-
height: 69px;
163-
border-radius: 50%;
164-
border: none;
165-
background-color: ${({ bgColor }) => bgColor};
166-
display: flex;
167-
align-items: center;
168-
overflow: hidden;
169-
justify-content: center;
170-
cursor: pointer;
171-
transition: background-color 0.3s;
172-
`;
173-
174144
const LetterBtnText = styled.div`
175145
${(props) => props.theme.fonts.caption02};
176146
color: ${theme.colors.gray400};

src/app/mypage/page.tsx

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
import { getLetterCount } from '@/api/letter/letter';
44
import { getUserInfo, logout } from '@/api/mypage/user';
5-
import Button from '@/components/common/Button';
65
import Loader, { LoaderContainer } from '@/components/common/Loader';
76
import NavigatorBar from '@/components/common/NavigatorBar';
7+
import { OAUTH } from '@/constants/oauth';
88
import { theme } from '@/styles/theme';
99
import { clearOnboarding, clearTokens, getRefreshToken } from '@/utils/storage';
1010
import { useRouter } from 'next/navigation';
@@ -65,7 +65,6 @@ const MyPage = () => {
6565
setName(response.data.name);
6666
setEmail(response.data.email);
6767
setPlatform(response.data.socialPlatform);
68-
// console.log('회원정보 조회 성공:', response.data);
6968
} catch (error) {
7069
console.error('회원정보 조회 실패:', error);
7170
}
@@ -81,18 +80,9 @@ const MyPage = () => {
8180
}
8281
};
8382

84-
const EmailType = (platform): string => {
85-
switch (platform) {
86-
case 'GOOGLE':
87-
return '/assets/icons/ic_google.svg';
88-
case 'KAKAO':
89-
return '/assets/icons/ic_kakao_profile.svg';
90-
case 'NAVER':
91-
return '/assets/icons/ic_naver.svg';
92-
default:
93-
return '';
94-
}
95-
};
83+
const profileSrc = OAUTH.find(
84+
(oauth) => oauth.key === platform.toLowerCase()
85+
)?.profile;
9686

9787
return (
9888
<Container>
@@ -112,11 +102,7 @@ const MyPage = () => {
112102
<ProfileInfo>
113103
<ProfileName>{name}님의 스페이스</ProfileName>
114104
<ProfileEmail>
115-
<StyledIcon
116-
src={EmailType(platform)}
117-
alt="emailIcon"
118-
platform={platform as keyof typeof iconSizes}
119-
/>
105+
<StyledIcon src={profileSrc} alt={platform} />
120106
<div>{email}</div>
121107
</ProfileEmail>
122108
<CountRaw>
@@ -258,15 +244,9 @@ const ProfileImage = styled.img`
258244
}
259245
`;
260246

261-
const iconSizes = {
262-
GOOGLE: 20,
263-
KAKAO: 20,
264-
NAVER: 20
265-
} as const;
266-
267-
const StyledIcon = styled.img<{ platform: keyof typeof iconSizes }>`
268-
width: ${({ platform }) => iconSizes[platform]}px;
269-
height: ${({ platform }) => iconSizes[platform]}px;
247+
const StyledIcon = styled.img`
248+
width: 20px;
249+
height: 20px;
270250
`;
271251

272252
const ProfileInfo = styled.div`

src/app/signup/complete/page.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,7 @@ const Container = styled.div`
6868
width: 100%;
6969
max-width: 393px;
7070
height: 100%;
71-
max-height: 853px;
7271
flex-direction: column;
73-
//overflow: scroll;
7472
justify-content: space-between;
7573
background-image: url('/assets/signup/signup_bg.png');
7674
background-size: cover;

0 commit comments

Comments
 (0)