Skip to content

Commit

Permalink
refactor: login(kakao) 코드 교체 & 훅 추가,
Browse files Browse the repository at this point in the history
access, refresh 토큰 처리 기능 정상화
로그인/로그아웃은 react-kakao-login 라이브러리의 함수/타입 가져오기로 재구현
  • Loading branch information
ptyoiy committed Jul 22, 2024
1 parent 2dd4c61 commit 29bb890
Show file tree
Hide file tree
Showing 23 changed files with 342 additions and 241 deletions.
64 changes: 40 additions & 24 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
/* eslint-disable react/jsx-props-no-spreading */
import { Modal } from '@mui/material';
import { useContext } from 'react';
import {
Navigate,
Route,
Routes,
useSearchParams
} from 'react-router-dom';
import { Navigate, Route, Routes, useSearchParams } from 'react-router-dom';
import Wrapper from './AppStyles';
import BottomNavbar from './components/BottomNavbar';
import HeaderLogo from './components/HeaderLogo';
import { ModalContext, userContext } from './context';
import { ModalContext } from './context';
import { useCheckAuthTokens } from './hooks/useKakaoAuth';
import { useUser } from './hooks/useUser';
import {
AlarmSettingPage,
LinktreePage,
Expand All @@ -21,20 +18,15 @@ import {
Signup,
TerracePage,
} from './pages';
import RegisterServiceWorker from './util/firebaseCloudMessage/RegisterSW';
import { useRegisterServiceWorker } from './util';
import { useInitKakaoLogin } from './util/kakaoAuth';

function App() {
console.log('APP rerender', import.meta.env);
const { userData } = useContext(userContext);
const { modal, modalDispatch } = useContext(ModalContext);
const [, setSearchParams] = useSearchParams();
const { Component, props } = modal;
const handleModalClose = () => {
setSearchParams({});
modalDispatch({ payload: 'close' });
};
const { major, isModalOpen, Component, props, handleModalClose, dispatchLogout } = useSystem();

RegisterServiceWorker();
useRegisterServiceWorker();
useInitKakaoLogin();
useCheckAuthTokens(dispatchLogout);

return (
<Wrapper>
Expand All @@ -53,14 +45,38 @@ function App() {
<Route path="alarm" element={<AlarmSettingPage />} />
</Route>
</Routes>
{userData?.major && <BottomNavbar />}
{!!Component && (
<Modal open={!!Component} onClose={handleModalClose}>
<Component {...props} />
</Modal>
)}
{major && <BottomNavbar />}
{/* TODO: useModal로 교체하고 컴포넌트 분리하기 */}
<Modal open={isModalOpen} onClose={handleModalClose}>
{isModalOpen ? <Component {...props} /> : <div>.</div>}
</Modal>
</Wrapper>
);
}

function useSystem() {
const {
userData,
dispatchActions: { dispatchLogout },
} = useUser();
console.log('APP rerender');
const { modal, modalDispatch } = useContext(ModalContext);
const [, setSearchParams] = useSearchParams();
const { Component, props } = modal;
const handleModalClose = () => {
setSearchParams({});
modalDispatch({ payload: 'close' });
};
const isModalOpen = Boolean(Component);

return {
major: userData.major,
isModalOpen,
Component,
props,
handleModalClose,
dispatchLogout,
};
}

export default App;
22 changes: 2 additions & 20 deletions src/api/axios/index.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,12 @@
import axios, { AxiosError } from 'axios';
import { getAccessToken } from './user';
import axios from 'axios';

axios.defaults.baseURL = '/api';
axios.defaults.withCredentials = true;
axios.interceptors.response.use(
(response) => response,
async (error: AxiosError) => {
const originalRequest = error.config;
switch (error.response.status) {
// access 없음
// access 만료시 갱신
case 401:
case 419: {
await getAccessToken();
return axios(originalRequest);
}
// skip default
}
return Promise.reject(error);
}
);

export * from './alarm';
export { default as getAlerts } from './alert';
export * from './event';
export { default as getLinks } from './link';
export * from './notice';
export * from './types.d';
export * from './user';

11 changes: 9 additions & 2 deletions src/api/axios/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,18 @@ export interface ResponseLinkType {
id: number;
src: string;
text: string;
major: '컴퓨터' | '소프트웨어';
major: '컴퓨터' | '소프트';
order: number;
}

export type ResponseLoginType = {
user: IUser;
user: {
id: number;
activated: boolean;
name: string;
createdDate: Date;
lastAccess: Date;
major: '컴퓨터' | '소프트' | null;
};
create: boolean;
};
43 changes: 22 additions & 21 deletions src/api/axios/user.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,42 @@
import { QueryClient } from '@tanstack/react-query';
import axios from 'axios';
import { Dispatch } from 'react';
import { NavigateFunction } from 'react-router-dom';
import { Action } from '../../context';
import { ResponseLoginType } from './types';

export function login(id: number, kakao_accessToken: string) {
console.log('login called');
return axios.post(
'/login',
{
id,
kakao_accessToken,
},
{ withCredentials: true },
).then(({ data }) => data as ResponseLoginType);
return axios
.post(
'/login',
{
id,
kakao_accessToken,
},
{ withCredentials: true }
)
.catch((error) => {
throw error;
})
.then(({ data }) => data as ResponseLoginType);
}

// eslint-disable-next-line max-len
export const kakaoLogout = async (client: QueryClient, navigate: NavigateFunction, dispatch: Dispatch<Action>) => {
export const logout = async () => {
console.log('logout called');
return axios.post('/logout').then((d) => {
if (d.data.status !== 1) return;
client.removeQueries({ queryKey: ['login'] });
client.removeQueries({ queryKey: ['userInfo'] });
client.removeQueries({ queryKey: ['getAlarms'] });
dispatch({ payload: 'logout' });
navigate('/my', { replace: true });
if (d.data.status !== 1) {
console.warn('로그아웃 오류');
}
});
};

export const getUserInfo = async (id: number) => {
console.log('get UserInfo called');
console.log('get UserInfo called', axios.interceptors.response);
return axios.get(`/users/info/${id}`).then((res) => res.data);
};

export const getAccessToken = async () => {
console.log('get accessToken called');
return axios.post('/getToken').then((res) => res.data);
return axios.post('/getToken').then((res) => {
console.log({ res });
return res.data;
});
};
28 changes: 16 additions & 12 deletions src/api/query/user.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,34 @@
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { User, UserData } from '../../context';
import { getUserInfo, login } from '../axios';
import { getUserInfo } from '../axios';

export const useLoginQuery = (id: number, kakao_accessToken: string) => {
const info = useQuery({
queryKey: ['login'],
queryFn: () => login(id, kakao_accessToken),
enabled: !!(id && kakao_accessToken),
retry: false,
staleTime: Infinity,
});
return info;
};
// export const useLoginQuery = (isAuthenticated: boolean) => {
// const id = sessionStorage.getItem('id');
// const kakaoAccessToken = sessionStorage.getItem('kakaoAccessToken');
// const info = useQuery({
// queryKey: ['login'],
// queryFn: () => login(+id, kakaoAccessToken),
// enabled: !isAuthenticated && Boolean(id && kakaoAccessToken),
// retry: false,
// staleTime: Infinity,
// });
// return info;
// };

export const useUserInfoQuery = (userData: UserData) => {
const { userId, isAuthenticated } = userData;
// const queryClient = useQueryClient();
const userInfo = useQuery({
queryKey: ['userInfo'],
queryFn: () => getUserInfo(userId),
enabled: isAuthenticated,
enabled: isAuthenticated && Boolean((axios.interceptors.response as any).handlers.length),
staleTime: Infinity,
select(data) {
const { bookmark, eventLike, noticeLike, noticeRead } = data;
return new User(userData, bookmark, noticeRead, noticeLike, eventLike);
},
retry: 1
});
return userInfo;
};
17 changes: 5 additions & 12 deletions src/components/Login/index.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
import { memo } from 'react';
import ChatYellow from '../../assets/Img/ChatYellow.png';
import useKakaoLogin from '../../hook/useKakaoLogin';
import { useKakaoAuth } from '../../hooks/useKakaoAuth';
import * as s from '../../pages/SignupPage/styles';

type LoginButtonProps = {
showLogin: boolean
showLogin: boolean;
};

const LoginButton = memo(({ showLogin }: LoginButtonProps) => {
const { kakaoLoginRef, KakaoLoginWrapper } = useKakaoLogin();
const { kakaoLogin } = useKakaoAuth();

const handleClick = () => {
if (kakaoLoginRef.current) {
kakaoLoginRef?.current.onButtonClick();
}
kakaoLogin();
};

return (
<>
<s.Member src={ChatYellow} show={showLogin} onClick={handleClick} />
<KakaoLoginWrapper />
</>
);
return <s.Member src={ChatYellow} show={showLogin} onClick={handleClick} />;
});

export default LoginButton;
4 changes: 2 additions & 2 deletions src/components/Modal/MainModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ import LikeOnIcon from '../../../assets/Icons/LikeOn.png';
import NoticeIcon from '../../../assets/Icons/NoticeIcon.png';
import ShareIcon from '../../../assets/Icons/ShareIcon.png';
import CloseBtnSrc from '../../../assets/Icons/modalCloseBtn.png';
import { userContext } from '../../../context';
import { formatDate } from '../../../util/dateUtil/postDateUtil';
import Toast from '../../Toast';
import ModalImage from '../ModalImage';
import Stepper from '../stepper';
import * as s from './styles';
// eslint-disable-next-line import/no-cycle
import { MainModalProps, ModalContext } from '../../../context/modal';
import { useUser } from '../../../hooks/useUser';
import { ModalViewType } from '../../../pages/NoticePage';

function useFetchDataByType(type: ModalViewType) {
Expand Down Expand Up @@ -57,7 +57,7 @@ const MainModal = forwardRef((_props, _ref) => {
const { modal, modalDispatch } = useContext(ModalContext);
const { type, postId: eventId } = (modal.props as MainModalProps);

const { userData } = useContext(userContext);
const { userData } = useUser();
const { userId } = userData;
const { data, isPending } = useFetchDataByType(type)(eventId.toString());
const { data: user } = useUserInfoQuery(userData);
Expand Down
Loading

0 comments on commit 29bb890

Please sign in to comment.