Skip to content

Commit

Permalink
feat: auth routing (#146)
Browse files Browse the repository at this point in the history
* feat: add loading view

* feat: add auth routing

* feat: set accessToken to localStorage

* fix: remove /auth paths

* feat: handle token access
  • Loading branch information
Jinho1011 authored Jan 24, 2024
1 parent f4b1215 commit 3f31712
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 80 deletions.
3 changes: 3 additions & 0 deletions src/apis/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ACCESS_TOKEN } from 'src/constants/localStorage';

import { ErrorResponse } from '@interfaces/api/error';

export class ResponseError extends Error {
Expand Down Expand Up @@ -76,6 +78,7 @@ class Fetch {

setAccessToken(token: string) {
this.accessToken = token;
localStorage.setItem(ACCESS_TOKEN, token);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/constants/localStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const ACCESS_TOKEN = 'access_token';
4 changes: 1 addition & 3 deletions src/interfaces/models/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export interface User {
memberId: number;
nickname?: string;
accessToken?: string;
refrehToken?: string;
nickname: string;
}
33 changes: 30 additions & 3 deletions src/routes/Auth/kakao/KakaoLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,23 @@ import { useNavigate } from 'react-router';
import { useAuthStore } from 'src/store/auth';

import { kakaoLogin } from '@apis/oauth/kakao';
import { Row } from '@components/commons/Flex/Flex';

import { ResponseError } from '@apis/fetch';
import { colors, zIndex } from '@styles/theme';

import { ALogoIcon, BLogoIcon } from '@icons/index';

import client, { ResponseError } from '@apis/fetch';

import Login from '../login/Login';

import { Container } from './KakaoLogin.styles';

const KakaoLogin = () => {
const setUser = useAuthStore((state) => state.setUser);
const kakaoCode = new URL(window.location.href).searchParams.get('code');

const navigate = useNavigate();
const login = useAuthStore((state) => state.login);

const handleKakaoLogin = async () => {
if (kakaoCode) {
Expand All @@ -26,7 +31,8 @@ const KakaoLogin = () => {
state: { memberId: response.memberId },
});
} else {
setUser({ memberId: response.memberId, accessToken: response.accessToken });
client.setAccessToken(response.accessToken);
login();
navigate('/');
}
}
Expand All @@ -51,6 +57,27 @@ const KakaoLogin = () => {

return (
<Container>
<div
className="loading"
style={{
position: 'fixed',
overflow: 'hidden',
height: '100vh',
width: '100vw',
zIndex: zIndex.modal,
backgroundColor: colors.navy_60,
}}
>
<Row
justifyContent={'center'}
alignItems={'center'}
gap={7.5}
style={{ width: '100%', height: '100%' }}
>
<ALogoIcon width={65} />
<BLogoIcon width={66} />
</Row>
</div>
<Login />
</Container>
);
Expand Down
2 changes: 1 addition & 1 deletion src/routes/Auth/login/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { colors, theme } from '@styles/theme';

import { ABLogoIcon, AppleIcon, GoogleIcon, KakaoIcon } from '@icons/index';

import { Container, Divider, LoginButtonContainer, LogoContainer } from './Login.styles';
import { Container, Divider, LoginButtonContainer } from './Login.styles';

const Login = () => {
const KakaoRestApiKey = import.meta.env.VITE_KAKAO_OAUTH_KEY;
Expand Down
6 changes: 0 additions & 6 deletions src/routes/Auth/signup/Terms.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { ChangeEvent, useState } from 'react';
import { useAuthStore } from 'src/store/auth';

import { useTerms } from '@apis/oauth/signup';
import Checkbox from '@components/commons/CheckBox/CheckBox';
Expand All @@ -16,7 +15,6 @@ interface TermsProps {

const Terms = ({ memberId }: TermsProps) => {
const consentToTermMutation = useTerms();
const setUser = useAuthStore((state) => state.setUser);
const [all, setAll] = useState(false);
const [consentToTerm, setConsentToTerm] = useState(false);
const [consentToCollectAndUseInfo, setConsentToCollectAndUseInfo] = useState(false);
Expand Down Expand Up @@ -45,10 +43,6 @@ const Terms = ({ memberId }: TermsProps) => {
memberId,
listen_marketing: consetToMarketing,
});
setUser({
memberId: response.memberId,
accessToken: response.accessToken,
});
};

return (
Expand Down
92 changes: 35 additions & 57 deletions src/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import React from 'react';
import { RouteObject, RouterProvider, createBrowserRouter } from 'react-router-dom';
import {
Navigate,
Outlet,
Route,
RouterProvider,
createBrowserRouter,
createRoutesFromElements,
} from 'react-router-dom';
import { useAuthStore } from 'src/store/auth';

import GoogleLogin from './Auth/google/GoogleLogin';
Expand All @@ -11,65 +18,36 @@ import Notification from './Notification/Notification';
import TopicCreate from './Topic/TopicCreate';
import TopicSideSelection from './Topic/TopicSideSelection';

const Router = () => {
const user = useAuthStore((state) => state.user);
const isAuthorized = user !== null;

const authorizedRoutes: RouteObject[] = [
{
path: '/',
children: [
{
index: true,
element: <Home />,
},
{
path: 'topics/create',
element: <TopicSideSelection />,
},
{
path: 'topics/create/:topicSide',
element: <TopicCreate />,
},
{
path: 'notifications',
element: <Notification />,
},
],
},
];
const ProtectedRoute = () => {
const isLoggedIn = useAuthStore((store) => store.isLoggedIn);

const publicRoutes: RouteObject[] = [
{
path: '/',
children: [
{
path: 'signup',
element: <Signup />,
},
{
path: 'login',
element: <Login />,
},
{
path: 'login/kakao',
element: <KakaoLogin />,
},
{
path: 'login/google',
element: <GoogleLogin />,
},
],
},
];
if (!isLoggedIn) {
return <Navigate to={'/login'} replace />;
}

const routes = import.meta.env.DEV
? [...authorizedRoutes, ...publicRoutes]
: isAuthorized
? authorizedRoutes
: publicRoutes;
return <Outlet />;
};

const router = createBrowserRouter(routes);
const Router = () => {
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" errorElement={<div>Error...</div>}>
<Route path="*" element={<ProtectedRoute />}>
<Route index element={<Home />} />
<Route path="topics">
<Route path="create" element={<TopicSideSelection />} />
<Route path="create/:topicSide" element={<TopicCreate />} />
</Route>
<Route path="notifications" element={<Notification />} />
</Route>

<Route path="login" element={<Login />} />
<Route path="login/kakao" element={<KakaoLogin />} />
<Route path="login/google" element={<GoogleLogin />} />
<Route path="signup" element={<Signup />} />
</Route>
)
);

return <RouterProvider router={router} />;
};
Expand Down
38 changes: 28 additions & 10 deletions src/store/auth.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
import { ACCESS_TOKEN } from 'src/constants/localStorage';
import { create } from 'zustand';

import { User } from '@interfaces/models/user';
import { persist } from 'zustand/middleware';

interface AuthState {
user: User | null;
isLoggedIn: boolean;
}

interface AuthAction {
setUser: (user: User) => void;
login: () => boolean;
logout: () => void;
}

export const useAuthStore = create<AuthState & AuthAction>((set) => ({
user: null,
setUser: (user: User) => {
set({ user: user });
},
}));
export const useAuthStore = create(
persist<AuthState & AuthAction>(
(set) => ({
isLoggedIn: false,
login: () => {
const userLocalStorage = localStorage.getItem(ACCESS_TOKEN);
if (userLocalStorage) {
set({ isLoggedIn: true });
return true;
} else {
return false;
}
},
logout: () => {
set({ isLoggedIn: false });
localStorage.clear();
},
}),
{
name: 'userLoginStatus',
}
)
);

0 comments on commit 3f31712

Please sign in to comment.