Skip to content

Commit

Permalink
Merge pull request #144 from FinalDoubleTen/FE-13--feat/NewUser
Browse files Browse the repository at this point in the history
Feat: 카카오 로그인 구현 / 무한 로그아웃 문제 해결
  • Loading branch information
jseo9732 authored Jan 12, 2024
2 parents 2f455f9 + 70c8fa9 commit c068626
Show file tree
Hide file tree
Showing 22 changed files with 217 additions and 95 deletions.
1 change: 1 addition & 0 deletions src/@types/auth.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface EditPassword {

export interface EditPasswordProps {
password: string;
newPassword: string;
}

export interface AuthInputBoxProps {
Expand Down
18 changes: 9 additions & 9 deletions src/@types/member.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ interface MemberInfo {
nickname: string;
email: string;
profileImageUrl: string | null;
ageType:
| 'TEENAGER'
| 'TWENTIES'
| 'THIRTIES'
| 'FOURTIES'
| 'ABOVE_FIFTIES'
| 'DEFATULT'
| null;
genderType: 'MALE' | 'FEMALE' | 'NON_BINARY' | null;
ageType: string | null;
// | 'TEENAGER'
// | 'TWENTIES'
// | 'THIRTIES'
// | 'FOURTIES'
// | 'ABOVE_FIFTIES'
// | 'DEFATULT'
genderType: string | null;
// 'MALE' | 'FEMALE' | 'NON_BINARY' | 'DEFATULT';
survey: Survey | null;
}

Expand Down
11 changes: 4 additions & 7 deletions src/api/authClient.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { getItem, removeItem, setItem } from '@utils/localStorageFun';
import axios from 'axios';
import { postLogout } from './auth';

const authClient = axios.create({
baseURL: import.meta.env.VITE_SERVER_URL,
baseURL: `${import.meta.env.VITE_SERVER_URL}api/`,
headers: {
'Content-Type': 'application/json',
},
Expand Down Expand Up @@ -38,18 +37,16 @@ authClient.interceptors.response.use(
return res;
},
function (error) {
console.error(error);

if (error.response.status === 401) {
// 응답이 401으로 오는 경우
// 1. 엑세스 토큰이 없는 경우(엑세스 토큰이 없습니다.)
// 2. 리프레시 토큰이 만료된 경우(리프레시 토큰이 존재하지 않습니다.)
// 3. 리프레시 토큰이 없는 경우
// 전부 비로그인으로 처리합니다.
// TODO 서지수 | 로그아웃 요청
console.log('401에러 발생 로그인 페이지로 이동시키면 됩니다.');
postLogout();
removeItem('accessToken');
if (getItem('accessToken')) {
removeItem('accessToken');
}
}
return Promise.reject(error);
},
Expand Down
2 changes: 1 addition & 1 deletion src/api/client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios';

const client = axios.create({
baseURL: import.meta.env.VITE_SERVER_URL,
baseURL: `${import.meta.env.VITE_SERVER_URL}api/`,
headers: {
'Content-Type': 'application/json',
},
Expand Down
2 changes: 0 additions & 2 deletions src/components/Auth/AuthSurvey/AuthSurvey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,13 @@ const AuthSurvey = ({ path }: Props) => {
// newPrevUserInfo.survey = data;
// return newPrevUserInfo;
// });
alert('변경되었습니다.');
navigate(path);
}
} catch (err) {
console.error(err);
alert('오류가 발생했습니다. 다시 시도해주세요');
}
};
console.log(isDirty);

return (
<form className="mb-8" onSubmit={handleSubmit(onSaveSubmit)}>
Expand Down
8 changes: 2 additions & 6 deletions src/components/Auth/Login/AuthButtons/KakaoLoginButton.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { KakaoIcon } from '@components/common/icons/Icons';

const KakaoLoginButton = () => {
const VITE_KAKAO_LOGIN_TEST_API_KEY = import.meta.env
.VITE_KAKAO_LOGIN_TEST_API_KEY;
const REDIRECT_URI = `${window.location.href}/kakao`;
const KAKAO_LOGIN_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${VITE_KAKAO_LOGIN_TEST_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code`;

return (
<a
href={KAKAO_LOGIN_URL}
href={`${import.meta.env.VITE_SERVER_URL}oauth2/authorization/kakao`}
// href="http://localhost:8080/oauth2/authorization/kakao"
className="body3 mb-2 flex h-14 w-full items-center justify-center gap-2 rounded-lg bg-[#fee304] p-2 text-['#3B1E1E']">
<KakaoIcon />
카카오로 로그인
Expand Down
44 changes: 44 additions & 0 deletions src/components/Auth/Login/KakaoLogin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { UserInfoState } from '@recoil/Auth.atom';
import { setItem } from '@utils/localStorageFun';
import { useEffect } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';

const KakaoLogin = () => {
const setUserInfo = useSetRecoilState(UserInfoState);
const navigate = useNavigate();

const [searchParams, _] = useSearchParams();
const nickname = searchParams.get('nickname');
const email = searchParams.get('email');
const gender = searchParams.get('gender');
const age_range = searchParams.get('age_range');
const accessToken = searchParams.get('token');
const profile_image = searchParams.get('profile_image');
const signup = searchParams.get('signup');

useEffect(() => {
if (accessToken) {
setItem('accessToken', accessToken);
setUserInfo({
nickname: nickname!,
email: email!,
profileImageUrl: profile_image,
ageType: age_range,
genderType: gender,
survey: null,
});
if (signup) {
navigate('/signup/success');
} else {
navigate('/');
}
} else {
alert('로그인에 실패했습니다. 다시 시도해주세요.');
navigate('/login');
}
}, []);
return <>카카오 로그인 중입니다.</>;
};

export default KakaoLogin;
1 change: 0 additions & 1 deletion src/components/Auth/Login/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ const LoginForm = () => {
if (res.data.status === 200) {
setItem('accessToken', res.data.data.tokenInfo.accessToken);
// setUserInfo(res.data.data.memberDto);
// TODO 서지수 | 로그인 후 어디로 갈지 물어보고 수정
navigate('/');
}
} catch (err) {
Expand Down
3 changes: 2 additions & 1 deletion src/components/Auth/Login/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import LoginLogo from './LoginLogo';
import LoginForm from './LoginForm';
import AuthButtonsWrapper from './AuthButtons/AuthButtonsWrapper';
import KakaoLogin from './KakaoLogin';

export { LoginLogo, LoginForm, AuthButtonsWrapper };
export { LoginLogo, LoginForm, AuthButtonsWrapper, KakaoLogin };
37 changes: 23 additions & 14 deletions src/components/Mypage/DeleteMemberButton.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
import { deleteMember } from '@api/member';
import Alert from '@components/common/alert/Alert';
import { UserInfoState } from '@recoil/Auth.atom';
import { useNavigate } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';

const DeleteMemberButton = () => {
const setUserInfo = useSetRecoilState(UserInfoState);
const navigate = useNavigate();
const onDeleteClick = async () => {
if (confirm('정말 탈퇴 하시겠습니까?')) {
try {
const res = await deleteMember();
if (res.data.status === 200) {
setUserInfo(null);
navigate('/');
alert('회원 탈퇴되었습니다. 감사합니다.');
}
} catch (err) {
console.log(err);

const handleConfirm = async (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
try {
const res = await deleteMember();
if (res.data.status === 200) {
setUserInfo(null);
navigate('/');
alert('회원 탈퇴되었습니다. 감사합니다.');
}
} catch (err) {
console.log(err);
}
};

const handleCancel = (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
};
return (
<button onClick={onDeleteClick} className="body5 text-gray4">
회원 탈퇴
</button>
<Alert
title="회원 탈퇴"
message="정말 탈퇴하시겠어요?"
onConfirm={handleConfirm}
onCancel={handleCancel}>
<button className="body5 text-gray4">회원 탈퇴</button>
</Alert>
);
};

Expand Down
24 changes: 10 additions & 14 deletions src/components/Mypage/EditPassword/EditPwForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
AuthPwInputBox,
} from '@components/Auth';
import SubmitBtn from '@components/common/button/SubmitBtn';
import { AxiosError } from 'axios';
import { SubmitHandler, useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';

Expand All @@ -26,31 +27,26 @@ const EditPwForm = () => {
const navigate = useNavigate();

const onEditPwSubmit: SubmitHandler<EditPassword> = async (data) => {
const { password } = data;
const { currentPw, password } = data;

// 비밀번호 확인 로직
// try {
// const res = await getCheckPw(inputValue);
// if (res.status === 200) {
try {
const res = await putMemberPassword({
password,
password: currentPw,
newPassword: password,
});
if (res.status === 200) {
alert('비밀번호가 변경되었습니다.');
navigate('/mypage/info');
}
} catch (err) {
alert('오류가 발생했습니다. 다시 시도해주세요');
console.error('비밀번호 수정 요청 중 에러 발생', err);
if (err instanceof AxiosError) {
if (err.response?.data.status === 404) {
resetField('currentPw');
setError('currentPw', { message: '비밀번호가 올바르지 않습니다.' });
}
}
}
// if (isExist) {
// setError('currentPw', { message: '비밀번호가 올바르지 않습니다.' });
// }
// }
// } catch (err) {
// console.error(err);
// }
};
return (
<form
Expand Down
21 changes: 18 additions & 3 deletions src/components/Mypage/LogoutButton.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { postLogout } from '@api/auth';
import Alert from '@components/common/alert/Alert';
import { UserInfoState } from '@recoil/Auth.atom';
import { removeItem } from '@utils/localStorageFun';
import { useSetRecoilState } from 'recoil';
Expand All @@ -8,6 +9,10 @@ const LogoutButton = () => {

const onLogoutClick = async (e: any) => {
e.stopPropagation();
};

const handleConfirm = async (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
try {
const res = await postLogout();
if (res.data === 'LOGOUT!') {
Expand All @@ -19,10 +24,20 @@ const LogoutButton = () => {
}
};

const handleCancel = (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
};

return (
<button onClick={onLogoutClick} className="caption2 text-gray4">
로그아웃
</button>
<Alert
title="로그아웃"
message="로그아웃 하시겠어요?"
onConfirm={handleConfirm}
onCancel={handleCancel}>
<button onClick={onLogoutClick} className="caption2 text-gray4">
로그아웃
</button>
</Alert>
);
};

Expand Down
51 changes: 44 additions & 7 deletions src/components/Mypage/MypageItem.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,56 @@
import Alert from '@components/common/alert/Alert';
import { RightIcon } from '@components/common/icons/Icons';
import { Link } from 'react-router-dom';
import { getItem } from '@utils/localStorageFun';
import { Link, useNavigate } from 'react-router-dom';

interface Props {
link: string;
children: string;
}

const MypageItem = ({ link, children }: Props) => {
const navigate = useNavigate();
const isLogin = getItem('accessToken');

const handleConfirm = async (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
if (getItem('accessToken')) {
navigate(link);
}
};

const handleCancel = (e: React.MouseEvent<HTMLElement>) => {
e.stopPropagation();
};

return (
<Link
to={link}
className="flex h-14 w-full items-center justify-between py-2">
<span className="body3 text-black">{children}</span>
<RightIcon />
</Link>
<>
{isLogin ? (
<Link
to={link}
className="flex h-14 w-full items-center justify-between py-2">
<span className="body3 text-black">{children}</span>
<RightIcon />
</Link>
) : (
<Alert
title="로그인"
message={
<>
조회 시 로그인이 필요합니다.
<br />
로그인 하시겠습니까?
</>
}
onConfirm={handleConfirm}
onCancel={handleCancel}>
<button className="flex h-14 w-full items-center justify-between py-2">
<span className="body3 text-black">{children}</span>
<RightIcon />
</button>
</Alert>
)}
</>
);
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/Mypage/MypageList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const MypageList = () => {
<div>
<MypageItem link="/mytour">나의 여정</MypageItem>
<MypageItem link="/wishlist">나의 관심 여행지</MypageItem>
<MypageItem link="/myreview">나의 리뷰</MypageItem>
<MypageItem link="/myPageReview">나의 리뷰</MypageItem>
<MypageItem link="/mypage/survey">나의 여행 취향 설정</MypageItem>
</div>
);
Expand Down
Loading

0 comments on commit c068626

Please sign in to comment.