diff --git a/apps/client/src/layout/Layout.tsx b/apps/client/src/layout/Layout.tsx index a5d2d08a..055102fd 100644 --- a/apps/client/src/layout/Layout.tsx +++ b/apps/client/src/layout/Layout.tsx @@ -1,14 +1,15 @@ -import { Outlet,useLocation } from 'react-router-dom'; +import { Outlet, useLocation } from 'react-router-dom'; import { Sidebar } from '@shared/components/sidebar/Sidebar'; const Layout = () => { const location = useLocation(); const isOnboarding = location.pathname.startsWith('/onboarding'); + const isLogin = location.pathname.startsWith('/login'); return ( <>
- {!isOnboarding && } + {!isOnboarding && !isLogin && }
diff --git a/apps/client/src/pages/login/Login.tsx b/apps/client/src/pages/login/Login.tsx new file mode 100644 index 00000000..1c15e771 --- /dev/null +++ b/apps/client/src/pages/login/Login.tsx @@ -0,0 +1,73 @@ +import onBoardingBg from '/assets/onBoarding/background/onBoardingBg.webp'; +import Header from '@pages/onBoarding/components/header/Header'; +import Footer from '@pages/onBoarding/components/footer/Footer'; +import { Icon } from '@pinback/design-system/icons'; +import { handleGoogleLogin } from '@shared/utils/handleGoogleLogin'; +import { Link } from 'react-router-dom'; +import Chippi from '@assets/chippi_extension_popup.svg'; +import GoogleLogo from '/assets/onBoarding/icons/googleLogo.svg'; + +const Login = () => { + return ( +
+
+ +
+
+ 치삐 이미지 + + + +

+ 가장 재미있게 북마크를 활용하는 방법 +

+ +

+ 내가 저장해둔 영감을 pinback과 함께 열어볼까요? +

+ + + +

+ 가입 시 pinback의{' '} + + 이용 약관 + {' '} + 및{' '} + + 개인정보처리방침 + + 에 동의한 것으로 간주됩니다. +

+
+
+ +
+
+ ); +}; + +export default Login; diff --git a/apps/client/src/pages/onBoarding/components/funnel/step/SocialLoginStep.tsx b/apps/client/src/pages/onBoarding/components/funnel/step/SocialLoginStep.tsx index 9ab9a800..1bfba6ed 100644 --- a/apps/client/src/pages/onBoarding/components/funnel/step/SocialLoginStep.tsx +++ b/apps/client/src/pages/onBoarding/components/funnel/step/SocialLoginStep.tsx @@ -1,30 +1,11 @@ import Chippi from '@assets/chippi_extension_popup.svg'; import GoogleLogo from '/assets/onBoarding/icons/googleLogo.svg'; +import { Link } from 'react-router-dom'; +import { handleGoogleLogin } from '@shared/utils/handleGoogleLogin'; const SocialLoginStep = () => { - const handleGoogleLogin = () => { - const clientId = import.meta.env.VITE_GOOGLE_CLIENT_ID; - - const redirectUri = import.meta.env.PROD - ? import.meta.env.VITE_GOOGLE_REDIRECT_URI_PROD - : import.meta.env.VITE_GOOGLE_REDIRECT_URI_DEV; - - if (!clientId || !redirectUri) { - alert('Google OAuth 설정이 누락되었습니다.'); - return; - } - const googleAuthUrl = - `https://accounts.google.com/o/oauth2/v2/auth?` + - `client_id=${clientId}` + - `&redirect_uri=${redirectUri}` + - `&response_type=code` + - `&scope=email profile`; - - window.location.href = googleAuthUrl; - }; - return ( -
+
치삐 이미지 { /> 구글 계정으로 로그인 + {/*TODO: 개인정보처리방침 추가되면 링크 수정*/} +

+ 가입 시 pinback의{' '} + + 이용 약관 + {' '} + 및{' '} + + 개인정보처리방침 + + 에 동의한 것으로 간주됩니다. +

); }; diff --git a/apps/client/src/routes/router.tsx b/apps/client/src/routes/router.tsx index bd8c08ab..4dcc2427 100644 --- a/apps/client/src/routes/router.tsx +++ b/apps/client/src/routes/router.tsx @@ -1,5 +1,6 @@ import Category from '@pages/category/Category'; import Level from '@pages/level/Level'; +import Login from '@pages/login/Login'; import MyBookmark from '@pages/myBookmark/MyBookmark'; import GoogleCallback from '@pages/onBoarding/GoogleCallback'; import OnBoarding from '@pages/onBoarding/OnBoarding'; @@ -37,6 +38,10 @@ export const router = createBrowserRouter([ path: ROUTES_CONFIG.onBoardingCallback.path, element: , }, + { + path: ROUTES_CONFIG.login.path, + element: , + }, ], }, ]); diff --git a/apps/client/src/routes/routesConfig.ts b/apps/client/src/routes/routesConfig.ts index 7934fb5a..ebe13e73 100644 --- a/apps/client/src/routes/routesConfig.ts +++ b/apps/client/src/routes/routesConfig.ts @@ -23,4 +23,8 @@ export const ROUTES_CONFIG = { title: '구글 OAuth 콜백', path: '/onboarding/callback', }, + login: { + title: '로그인', + path: '/login', + }, }; diff --git a/apps/client/src/shared/apis/setting/axiosInstance.ts b/apps/client/src/shared/apis/setting/axiosInstance.ts index 91cf0317..8e38f241 100644 --- a/apps/client/src/shared/apis/setting/axiosInstance.ts +++ b/apps/client/src/shared/apis/setting/axiosInstance.ts @@ -35,11 +35,14 @@ apiRequest.interceptors.response.use( originalRequest.url?.includes(url) ); + const isLoginPage = window.location.pathname.startsWith('/login'); + if ( error.response && (error.response.status === 401 || error.response.status === 403) && !originalRequest._retry && - !isNoAuth + !isNoAuth && + !isLoginPage ) { originalRequest._retry = true; diff --git a/apps/client/src/shared/components/profilePopup/ProfilePopup.tsx b/apps/client/src/shared/components/profilePopup/ProfilePopup.tsx index 61ad37a2..52b91fce 100644 --- a/apps/client/src/shared/components/profilePopup/ProfilePopup.tsx +++ b/apps/client/src/shared/components/profilePopup/ProfilePopup.tsx @@ -42,7 +42,7 @@ export default function ProfilePopup({ const handleLogout = () => { localStorage.removeItem('token'); localStorage.removeItem('email'); - navigate('/onboarding'); + navigate('/login'); }; return ( diff --git a/apps/client/src/shared/utils/handleGoogleLogin.ts b/apps/client/src/shared/utils/handleGoogleLogin.ts new file mode 100644 index 00000000..8b0ff14b --- /dev/null +++ b/apps/client/src/shared/utils/handleGoogleLogin.ts @@ -0,0 +1,20 @@ +export const handleGoogleLogin = () => { + const clientId = import.meta.env.VITE_GOOGLE_CLIENT_ID; + + const redirectUri = import.meta.env.PROD + ? import.meta.env.VITE_GOOGLE_REDIRECT_URI_PROD + : import.meta.env.VITE_GOOGLE_REDIRECT_URI_DEV; + + if (!clientId || !redirectUri) { + alert('Google OAuth 설정이 누락되었습니다.'); + return; + } + const googleAuthUrl = + `https://accounts.google.com/o/oauth2/v2/auth?` + + `client_id=${clientId}` + + `&redirect_uri=${redirectUri}` + + `&response_type=code` + + `&scope=email profile`; + + window.location.href = googleAuthUrl; +};