Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
131 changes: 86 additions & 45 deletions src/app/login/auth/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ const Auth = () => {
const [absoluteUrl, setAbsoluteUrl] = useState('');
const [storeUrl, setstoreUrl] = useState('');
const [type, setType] = useState('');
const [oauthAccessToken, setOauthAccessToken] = useState('');
const [provider, setProvider] = useState('');

useEffect(() => {
if (typeof window !== 'undefined') {
//oauth 타입을 state에 저장
const params = new URL(window.location.href).searchParams;
const typeParam = params.get('type');
setType(typeParam);
Expand All @@ -31,79 +34,117 @@ const Auth = () => {
}, []);

useEffect(() => {
if (!absoluteUrl) {
return;
}
if (!absoluteUrl || !type) return;
const getToken = async () => {
const AUTHORIZATION_CODE = new URL(window.location.href).searchParams.get(
'code'
);
const TYPE = new URL(window.location.href).searchParams.get('type');

let tokenUrl = '';
let provider: 'KAKAO' | 'GOOGLE' | 'NAVER';
const TYPE = new URL(window.location.href).searchParams.get('type');

if (!AUTHORIZATION_CODE || !TYPE) {
console.error('Authorization Code or Type is missing');
return;
}

//type에 따라 다른 토큰 url 지정
switch (TYPE) {
case 'kakao':
tokenUrl = `https://kauth.kakao.com/oauth/token?grant_type=authorization_code&client_id=${REST_API_KEY}&redirect_uri=${absoluteUrl}&code=${AUTHORIZATION_CODE}`;
provider = 'KAKAO';
setProvider('KAKAO');
try {
const response = await axios.post(
'https://kauth.kakao.com/oauth/token',
new URLSearchParams({
grant_type: 'authorization_code',
client_id: REST_API_KEY,
redirect_uri: absoluteUrl,
code: AUTHORIZATION_CODE
}),
{
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}
);
setOauthAccessToken(response.data.access_token);
} catch (error) {
console.error(error);
clearLetterUrl();
return;
}

break;
case 'google':
setProvider('GOOGLE');
try {
const body = new URLSearchParams({
grant_type: 'authorization_code',
client_id: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!,
client_secret: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_SECRET!,
redirect_uri: absoluteUrl,
code: AUTHORIZATION_CODE
});

const response = await axios.post(
'https://oauth2.googleapis.com/token',
body.toString(),
{
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
);
setOauthAccessToken(response.data.access_token);
} catch (error) {
console.error('Unsupported OAuth type:', type);
clearLetterUrl();
return;
}
break;
case 'naver':
break;
default:
console.error('Unknown OAuth type:', TYPE);
return;
}
};
getToken();
}, [absoluteUrl, type]);

try {
const response = await axios.post(tokenUrl, {
headers: { 'Content-Type': 'application/json' }
});

const oauthAccessToken = response.data.access_token;

if (oauthAccessToken) {
login(provider, oauthAccessToken)
.then((res) => {
console.log('accessToken', res.data.accessToken);
setTokens(res.data.accessToken, res.data.refreshToken);
/* 온보딩 여부 저장 */
setOnboarding(res.data.isProcessedOnboarding);
useEffect(() => {
try {
if (oauthAccessToken) {
login(provider, oauthAccessToken)
.then((res) => {
console.log('accessToken', res.data.accessToken);
setTokens(res.data.accessToken, res.data.refreshToken);
/* 온보딩 여부 저장 */
setOnboarding(res.data.isProcessedOnboarding);
if (storeUrl) {
router.push(`/verify/letter?url=${storeUrl}`);
clearLetterUrl();
} else {
router.push('/planet');
}
})
.catch((error) => {
if (error.response && error.response.status === 401) {
console.log('registerToken', error.response.data.registerToken);
setRegisterToken(error.response.data.registerToken);
if (storeUrl) {
router.push(`/verify/letter?url=${storeUrl}`);
router.push(`/signup/step1?url=${storeUrl}`);
clearLetterUrl();
} else {
router.push('/planet');
router.push('/signup/step1');
}
})
.catch((error) => {
if (error.response && error.response.status === 401) {
console.log('registerToken', error.response.data.registerToken);
setRegisterToken(error.response.data.registerToken);
if (storeUrl) {
router.push(`/signup/step1?url=${storeUrl}`);
clearLetterUrl();
} else {
router.push('/signup/step1');
}
}
});
}
} catch (error) {
console.error(error);
clearLetterUrl();
return;
}
});
}
};
getToken();
}, [absoluteUrl]);
} catch (error) {
console.log('oauth token 에러');
console.error(error);
clearLetterUrl();
return;
}
}, [oauthAccessToken]);

return (
<Container>
Expand Down
53 changes: 38 additions & 15 deletions src/app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,36 @@ interface OauthButtonProps {
bgColor: string;
}

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

const oauthButtons = [
{
key: 'naver',
bgColor: '#03CF5D',
component: (
<Image
src="/assets/icons/ic_naver.svg"
alt="Naver"
width={26}
height={26}
onClick={() => alert('준비 중입니다.')}
/>
)
},
{
key: 'google',
bgColor: '#FFFFFF',
component: <SocialGoogle />
},
{
key: 'kakao',
bgColor: '#FEE500',
component: <SocialKakao />
}
];

export default function Login() {
return (
<Container>
Expand All @@ -18,22 +48,15 @@ export default function Login() {
<LogoText>편지로 수놓는 나의 스페이스</LogoText>
<LogoImage src="/assets/login/login_logo.png" />
<OauthWrapper>
<OauthButton bgColor="#03CF5D">
<Image
src="/assets/icons/ic_naver.svg"
alt="Naver"
width={26}
height={26}
/>
</OauthButton>
<OauthButton bgColor="#FFFFFF">
<SocialGoogle />
</OauthButton>
<OauthButton bgColor="#FEE500">
<SocialKakao />
</OauthButton>
{oauthButtons.map(({ key, bgColor, component }) => (
<OauthButton key={key} bgColor={bgColor}>
{component}
</OauthButton>
))}
</OauthWrapper>
<LetterBtnText>로그인 없이 편지 작성해보기</LetterBtnText>
<LetterBtnText onClick={notReady}>
로그인 없이 편지 작성해보기
</LetterBtnText>
</ImageWrapper>
</Container>
);
Expand Down
35 changes: 33 additions & 2 deletions src/app/mypage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const MyPage = () => {
const [email, setEmail] = useState('');
const [planetCount, setPlanetCount] = useState(0);
const [letterCount, setLetterCount] = useState(0);
const [platform, setPlatform] = useState('');

const [loading, setLoading] = useState(true);

useEffect(() => {
Expand Down Expand Up @@ -62,7 +64,8 @@ const MyPage = () => {
const response = await getUserInfo();
setName(response.data.name);
setEmail(response.data.email);
console.log('회원정보 조회 성공:', response.data);
setPlatform(response.data.socialPlatform);
// console.log('회원정보 조회 성공:', response.data);
} catch (error) {
console.error('회원정보 조회 실패:', error);
}
Expand All @@ -78,6 +81,19 @@ const MyPage = () => {
}
};

const EmailType = (platform): string => {
switch (platform) {
case 'GOOGLE':
return '/assets/icons/ic_google.svg';
case 'KAKAO':
return '/assets/icons/ic_kakao_profile.svg';
case 'NAVER':
return '/assets/icons/ic_naver.svg';
default:
return '';
}
};

return (
<Container>
{loading ? (
Expand All @@ -96,7 +112,11 @@ const MyPage = () => {
<ProfileInfo>
<ProfileName>{name}님의 스페이스</ProfileName>
<ProfileEmail>
<img src="/assets/icons/ic_kakao_profile.svg" />
<StyledIcon
src={EmailType(platform)}
alt="emailIcon"
platform={platform as keyof typeof iconSizes}
/>
<div>{email}</div>
</ProfileEmail>
<CountRaw>
Expand Down Expand Up @@ -242,6 +262,17 @@ const ProfileImage = styled.img`
}
`;

const iconSizes = {
GOOGLE: 20,
KAKAO: 20,
NAVER: 20
} as const;

const StyledIcon = styled.img<{ platform: keyof typeof iconSizes }>`
width: ${({ platform }) => iconSizes[platform]}px;
height: ${({ platform }) => iconSizes[platform]}px;
`;

const ProfileInfo = styled.div`
display: flex;
flex-direction: column;
Expand Down
31 changes: 17 additions & 14 deletions src/components/signup/SocialGoogle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,36 @@ import Loader, { LoaderContainer } from '../common/Loader';
const SocialGoogle = () => {
const searchParams = useSearchParams();
const url = searchParams.get('url');
const REST_API_KEY = process.env.NEXT_PUBLIC_REST_API_KEY;
const GOOGLE_URL = '/login/google';
const [absoluteUrl, setabsoluteUrl] = useState('');

useEffect(() => {
if (typeof window !== 'undefined') {
setabsoluteUrl(
window.location.protocol + '//' + window.location.host + '/login/kakao'
window.location.protocol +
'//' +
window.location.host +
'/login/auth?type=google'
);
}
}, []);

const handleLogin = () => {
//이때 localStorage에 저장된 accessToken이 만료되었는지 확인해야함.
// if (accessToken) {
// if (url) {
// router.push(`/verify?url=${url}`);
// } else {
// router.push("/");
// }
// setAccessToken(accessToken);
// } else {
//받은 편지를 통해 들어올 경우 url를 저장한다.
if (url) {
setLetterUrl(url);
}
window.location.href = GOOGLE_URL;
const GOOGLE_CLIENT_ID = process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID;
const scope = 'openid profile email';

const authUrl = [
'https://accounts.google.com/o/oauth2/v2/auth',
`?client_id=${GOOGLE_CLIENT_ID}`,
`&redirect_uri=${encodeURIComponent(absoluteUrl)}`,
`&response_type=code`,
`&scope=${encodeURIComponent(scope)}`,
`&access_type=offline`,
`&prompt=consent`
].join('');
window.location.href = authUrl;
};

return (
Expand Down