diff --git a/src/app/pages/LoginPage/LoginPage.tsx b/src/app/pages/LoginPage/LoginPage.tsx index 439dfe78..55645946 100644 --- a/src/app/pages/LoginPage/LoginPage.tsx +++ b/src/app/pages/LoginPage/LoginPage.tsx @@ -1,6 +1,9 @@ import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; +import loginTimerURL from '@/shared/assets/svgs/login/ic_login_timer.svg'; +import logoURL from '@/shared/assets/svgs/login/ic_logo.svg'; + import { ROUTES_CONFIG } from '@/router/routesConfig'; import { authConfig } from '@/shared/config/auth'; @@ -69,11 +72,7 @@ const LoginPage = () => { const navigateToLogin = () => { setIsExiting(true); setTimeout(() => { - if (window.electron) { - window.open(authConfig.authUrl.electron, '_blank'); - } else { - window.location.href = authConfig.authUrl.react; - } + authConfig.redirectToMoribAuth(); }, 700); }; @@ -100,7 +99,7 @@ const LoginPage = () => { className={`relative z-10 flex h-full w-full items-center transition-all duration-700 ${isExiting ? 'translate-y-12 opacity-0' : ''}`} >
- Morib 로고 + Morib 로고 {/* 제목 - 피그마 기준 72px 폰트, 줄간격 1.3 */}
@@ -123,7 +122,7 @@ const LoginPage = () => {
- 몰입 타이머 시각화 + 몰입 타이머 시각화
diff --git a/src/app/shared/apisV2/client.ts b/src/app/shared/apisV2/client.ts index 3dd2d432..31edb5a3 100644 --- a/src/app/shared/apisV2/client.ts +++ b/src/app/shared/apisV2/client.ts @@ -1,9 +1,11 @@ import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; -import { getAccessToken, reloginWithoutLogout, setAccessToken, setRefreshToken } from '@/shared/utils/auth'; +import { getAccessToken, setAccessToken, setRefreshToken } from '@/shared/utils/auth'; import { postReissueToken } from '@/shared/apisV2/auth/auth.api'; +import { authConfig } from '../config/auth'; + export const API_URL = `${import.meta.env.VITE_BASE_URL}`; const defaultConfig: AxiosRequestConfig = { @@ -48,7 +50,7 @@ const addAuthInterceptor = (axiosClient: AxiosInstance) => { return axiosClient(prevRequest); } catch (reissueError) { - reloginWithoutLogout(); + authConfig.redirectToLogin(); } } return Promise.reject(e); diff --git a/src/app/shared/apisV2/setting/setting.mutations.ts b/src/app/shared/apisV2/setting/setting.mutations.ts index 6bdb1a76..64914768 100644 --- a/src/app/shared/apisV2/setting/setting.mutations.ts +++ b/src/app/shared/apisV2/setting/setting.mutations.ts @@ -1,7 +1,5 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { useLogout } from '@/shared/hooks/useLogout'; - import { deleteAccount, putChangeProfile } from './setting.api'; import { settingKeys } from './setting.keys'; @@ -18,13 +16,11 @@ export const usePutChangeProfile = () => { export const useDeleteAccount = () => { const queryClient = useQueryClient(); - const { handleLogout } = useLogout(); return useMutation({ mutationFn: deleteAccount, onSuccess: () => { queryClient.invalidateQueries(); - handleLogout(); }, }); }; diff --git a/public/timer.svg b/src/app/shared/assets/svgs/login/ic_login_timer.svg similarity index 100% rename from public/timer.svg rename to src/app/shared/assets/svgs/login/ic_login_timer.svg diff --git a/public/logo.svg b/src/app/shared/assets/svgs/login/ic_logo.svg similarity index 100% rename from public/logo.svg rename to src/app/shared/assets/svgs/login/ic_logo.svg diff --git a/src/app/shared/config/auth.ts b/src/app/shared/config/auth.ts index ce40571f..57c38a91 100644 --- a/src/app/shared/config/auth.ts +++ b/src/app/shared/config/auth.ts @@ -1,8 +1,6 @@ -import { redirect } from 'react-router-dom'; - import { ROUTES_CONFIG } from '@/router/routesConfig'; -import { getAccessToken, getIsOnboardingCompleted } from '../utils/auth'; +import { getAccessToken, getIsOnboardingCompleted, removeAllTokens } from '../utils/auth'; export const authConfig = { authUrl: { @@ -21,6 +19,20 @@ export const authConfig = { }, redirectToLogin: () => { - redirect(ROUTES_CONFIG.login.path); + removeAllTokens(); + if (window.electron) { + // pathname은 프로토콜·호스트(scheme, host)와 쿼리(?...), **해시(#...)**를 제외한 경로 + // 일렉트론은 해쉬 라우터를 사용하고 있기 때문에 루트 패스로 이동이 가능함. + window.location.replace(window.location.pathname); + } else { + window.location.replace(ROUTES_CONFIG.login.path); + } + }, + redirectToMoribAuth: () => { + if (window.electron) { + window.open(authConfig.authUrl.electron, '_blank'); + } else { + window.location.href = authConfig.authUrl.react; + } }, }; diff --git a/src/app/shared/hooks/useLogout.ts b/src/app/shared/hooks/useLogout.ts deleted file mode 100644 index 8ac706bb..00000000 --- a/src/app/shared/hooks/useLogout.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { useNavigate } from 'react-router-dom'; - -import { ROUTES_CONFIG } from '@/router/routesConfig'; - -import { removeAllTokens } from '../utils/auth'; - -export const useLogout = () => { - const navigate = useNavigate(); - - const handleLogout = () => { - removeAllTokens(); - navigate(ROUTES_CONFIG.login.path, { replace: true }); - }; - - return { handleLogout }; -}; diff --git a/src/app/shared/layout/Sidebar/ModalContentsSetting/AccountContent/AccountContent.tsx b/src/app/shared/layout/Sidebar/ModalContentsSetting/AccountContent/AccountContent.tsx index eb51c6e5..08a8de5b 100644 --- a/src/app/shared/layout/Sidebar/ModalContentsSetting/AccountContent/AccountContent.tsx +++ b/src/app/shared/layout/Sidebar/ModalContentsSetting/AccountContent/AccountContent.tsx @@ -3,8 +3,6 @@ import React, { useState } from 'react'; import ButtonRadius8 from '@/shared/components/ButtonRadius8/ButtonRadius8'; import ButtonStatusToggle from '@/shared/components/ButtonStatusToggle/ButtonStatusToggle'; -import { useLogout } from '@/shared/hooks/useLogout'; - import { overlay } from '@/shared/utils/overlay'; import { UserProfileType } from '@/shared/types/profile'; @@ -14,6 +12,7 @@ import MailIcon from '@/shared/assets/svgs/mail.svg?react'; import ModalContentsAlert from '@/pages/HomePage/ModalContentsAlert/ModalContentsAlert'; import { useDeleteAccount, usePutChangeProfile } from '@/shared/apisV2/setting/setting.mutations'; +import { authConfig } from '@/shared/config/auth'; type AccountContentProps = UserProfileType; @@ -24,8 +23,6 @@ const AccountContent = ({ ...props }: AccountContentProps) => { const [isToggleOn, setIsToggleOn] = useState(props.isPushEnabled); const [userName, setUserName] = useState(props.name); - const { handleLogout } = useLogout(); - const handleToggle = () => setIsToggleOn((prev) => !prev); const handleNameChange = (e: React.ChangeEvent) => { @@ -40,7 +37,11 @@ const AccountContent = ({ ...props }: AccountContentProps) => { overlay({ backdrop: true, content: ({ close }) => ( - + ), }); }; @@ -59,7 +60,7 @@ const AccountContent = ({ ...props }: AccountContentProps) => { }; const handleDeleteAccount = () => { - deleteAccount(undefined, { onSuccess: handleLogout }); + deleteAccount(undefined, { onSuccess: authConfig.redirectToLogin }); }; return ( diff --git a/src/app/shared/utils/auth.ts b/src/app/shared/utils/auth.ts index b9e43455..1369454c 100644 --- a/src/app/shared/utils/auth.ts +++ b/src/app/shared/utils/auth.ts @@ -1,5 +1,3 @@ -import { ROUTES_CONFIG } from '@/router/routesConfig'; - export const getAccessToken = () => { const accessToken = localStorage.getItem('accessToken'); return accessToken; @@ -9,21 +7,6 @@ export const setAccessToken = (accessToken: string) => { localStorage.setItem('accessToken', accessToken); }; -export const reloginWithoutLogout = () => { - localStorage.removeItem('accessToken'); - localStorage.removeItem('refreshToken'); - localStorage.removeItem('isOnboardingCompleted'); - - // electron 환경인지 확인 - if (window.electron?.auth) { - // electron IPC 통신을 통해 메인 프로세스에 메시지 전송 - window.electron.auth.relogin(); - } else { - // 일반 브라우저 환경인 경우 기존 방식대로 처리 - location.href = ROUTES_CONFIG.login.path; - } -}; - export const getRefreshToken = () => { const refreshToken = localStorage.getItem('refreshToken'); return refreshToken;