Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

튜토리얼 페이지 & 404 에러 페이지 #73

Merged
merged 6 commits into from
Sep 24, 2024
169 changes: 149 additions & 20 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
createRoutesFromElements,
Route,
Navigate,
Routes,
} from 'react-router-dom';
import MainPage from './pages/MainPage';
import LoginPage from './pages/LoginPage';
Expand All @@ -20,6 +21,8 @@ import SidePage from './pages/SidePage';
import ChallengeCommunityPage from './pages/ChallengeCommunityPage';
import CreateChallengePage from './pages/CreateChallengePage';
import ChallengeDetailPage from './pages/ChallengeDetailPage';
import TutorialPage from './pages/TutorialPage';
import ErrorPage from './pages/ErrorPage';

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
Expand All @@ -30,6 +33,7 @@ import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import './App.css';
import { useSSE } from './hooks/useSSE';
import ProtectedRoute from './components/ProtectedRoute';

const queryClient = new QueryClient();

Expand Down Expand Up @@ -57,35 +61,160 @@ const router = (isLoggedIn: boolean) =>
createBrowserRouter(
createRoutesFromElements(
<Route>
<Route
{/* 기본 라우터를 로그인 페이지로 변경 */}
<Route path="/" element={<LoginPage />} />
{/* <Route
path="/"
element={
isLoggedIn ? (
<Navigate to={`/${localStorage.getItem('LatestBoard') ?? 1}`} replace />
<Navigate to={`/${localStorage.getItem('LatestBoard') ?? 'tutorial'}`} replace />
) : (
<Navigate to="/login" replace />
<LoginPage />
)
}
/>
<Route path="/:id" element={<MainPage />}>
/> */}

{/* 로그인 상관없이 접근 가능한 라우터. 보호되지 않는 라우터 */}
<Route path="/api/oauth2/callback/:provider" element={<OAuthRedirectHandler />} />
<Route path="*" element={<ErrorPage />} />

{/* 보호된 경로들에 ProtectedRoute 적용 */}
<Route
path="/:id"
element={
<ProtectedRoute>
<MainPage />
</ProtectedRoute>
}
>
<Route path="/:id/personalBlock/:blockId" element={<SidePage />} />
</Route>
<Route path="/login" element={<LoginPage />} />
<Route path="/api/oauth2/callback/:provider" element={<OAuthRedirectHandler />} />
<Route path="/createBoard" element={<CreateBoard />} />
<Route path="/createPersonalBoard" element={<CreatePersonalBoard />} />
<Route path="/createPersonalBoard/:id" element={<CreatePersonalBoard />} />
<Route path="/createTeamBoard" element={<CreateTeamBoard />} />
<Route path="/createTeamBoard/:id" element={<CreateTeamBoard />} />
<Route path="/mypage" element={<MyPage />} />
<Route path="/mypage/edit" element={<ProfileEdit />} />
<Route path="/:id/teamdocument" element={<TeamDocumentBoard />}>
<Route path=":documentId" element={<TeamDocument />} />

<Route
path="/createBoard"
element={
<ProtectedRoute>
<CreateBoard />
</ProtectedRoute>
}
/>

<Route
path="/createPersonalBoard"
element={
<ProtectedRoute>
<CreatePersonalBoard />
</ProtectedRoute>
}
/>

<Route
path="/createPersonalBoard/:id"
element={
<ProtectedRoute>
<CreatePersonalBoard />
</ProtectedRoute>
}
/>

<Route
path="/createTeamBoard"
element={
<ProtectedRoute>
<CreateTeamBoard />
</ProtectedRoute>
}
/>

<Route
path="/createTeamBoard/:id"
element={
<ProtectedRoute>
<CreateTeamBoard />
</ProtectedRoute>
}
/>

<Route
path="/mypage"
element={
<ProtectedRoute>
<MyPage />
</ProtectedRoute>
}
/>

<Route
path="/mypage/edit"
element={
<ProtectedRoute>
<ProfileEdit />
</ProtectedRoute>
}
/>

<Route
path="/:id/teamdocument"
element={
<ProtectedRoute>
<TeamDocumentBoard />
</ProtectedRoute>
}
>
<Route
path=":documentId"
element={
<ProtectedRoute>
<TeamDocument />
</ProtectedRoute>
}
/>
</Route>
<Route path="/challenge" element={<ChallengeCommunityPage />} />
<Route path="/challenge/create" element={<CreateChallengePage />} />
<Route path="/challenge/create/:id" element={<CreateChallengePage />} />
<Route path="/challenge/:id" element={<ChallengeDetailPage />} />

<Route
path="/challenge"
element={
<ProtectedRoute>
<ChallengeCommunityPage />
</ProtectedRoute>
}
/>

<Route
path="/challenge/create"
element={
<ProtectedRoute>
<CreateChallengePage />
</ProtectedRoute>
}
/>

<Route
path="/challenge/create/:id"
element={
<ProtectedRoute>
<CreateChallengePage />
</ProtectedRoute>
}
/>

<Route
path="/challenge/:id"
element={
<ProtectedRoute>
<ChallengeDetailPage />
</ProtectedRoute>
}
/>

<Route
path="/tutorial"
element={
<ProtectedRoute>
<TutorialPage />
</ProtectedRoute>
}
/>
</Route>
)
);
Expand Down
12 changes: 12 additions & 0 deletions src/components/ProtectedRoute.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Navigate } from 'react-router-dom';

// * 로그인되지 않았는데 url 조작으로 접근을 방지 (로컬 스토리지에 저장된 토큰 확인)
const ProtectedRoute = ({ children }: { children: JSX.Element }) => {
if (!localStorage.getItem('accessToken')) {
return <Navigate to="/" replace />;
}

return children;
};

export default ProtectedRoute;
2 changes: 1 addition & 1 deletion src/contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
const login = ({ accessToken, refreshToken }: { accessToken: string; refreshToken: string }) => {
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('refreshToken', refreshToken);
// fetchMemberInfo();
fetchMemberInfo();
};

const logout = async () => {
Expand Down
8 changes: 6 additions & 2 deletions src/contexts/OAuthRedirectHandler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface LoginToken {
}

const OAuthRedirectHandler = () => {
const { provider } = useParams(); // Get the provider from the route parameters
const { provider } = useParams();
const navigate = useNavigate();
const { login } = useAuth();
const [loginToken, setLoginToken] = useState<LoginToken>({
Expand All @@ -30,7 +30,10 @@ const OAuthRedirectHandler = () => {
useEffect(() => {
if (loginToken.accessToken) {
login(loginToken);
navigate('/'); // 기본 대시보드 불러올 라우터로 설정 (가장 마지막에 방문한 대시보드를 기준으로)

// * 마지막에 방문한 대시보드가 있다면 해당 대시보드로 이동, 없다면 튜토리얼 페이지로 이동
const latestBoard = localStorage.getItem('LatestBoard');
navigate(latestBoard ? `/${latestBoard}` : '/tutorial');
}
}, [loginToken, login, navigate]);

Expand All @@ -55,6 +58,7 @@ const OAuthRedirectHandler = () => {
}
};

// * 로그인 처리 중일때 보여질 로딩창
return <Loading />;
};

Expand Down
3 changes: 2 additions & 1 deletion src/hooks/usePersonalDashBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ const usePersonalDashBoard = (dashboardId: string | null) => {
const deleteDashboard = async () => {
if (dashboardId) {
await deletePersonalDashboard(dashboardId);
navigate('/');
navigate(`/tutorial`);
localStorage.removeItem('LatestBoard');
}
};

Expand Down
Binary file added src/img/personal_tutorial.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/img/team_tutorial.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions src/pages/CreateTeamBoardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ const CreateTeamBoard = () => {
const deleteDashboard = async () => {
if (dashboardId) {
await deleteTeamDashboard(dashboardId);
navigate('/');
navigate(`/tutorial`);
localStorage.removeItem('LatestBoard');
}
};

Expand All @@ -146,7 +147,8 @@ const CreateTeamBoard = () => {
const quitDashboard = async () => {
if (dashboardId) {
await quitTeamDashboard(dashboardId);
navigate('/');
navigate(`/tutorial`);
localStorage.removeItem('LatestBoard');
}
};

Expand Down
Loading