feat: centralize routes and navigation guards

This commit is contained in:
donghyeon-ka
2026-07-25 21:03:57 +09:00
parent bfc642875c
commit b221453c15
8 changed files with 317 additions and 11 deletions
+79
View File
@@ -0,0 +1,79 @@
import {
BrowserRouter,
Link,
Route,
Routes,
} from "react-router-dom";
import { routePath } from "../../contracts/routes.js";
import { decideRouteAccess } from "./navigation-policy.js";
function HomePage() {
return (
<main>
<h1>Clean Architecture Frontend</h1>
<p>런타임 계약이 검증되었습니다.</p>
<Link to={routePath("SAMPLE_RESOURCE_LIST")}>샘플 리소스</Link>
</main>
);
}
function SamplePlaceholder() {
return (
<main>
<h1>샘플 리소스</h1>
<p>계약 fixture를 준비하고 있습니다.</p>
</main>
);
}
function NotFoundPage() {
return (
<main>
<h1>페이지를 찾을 없습니다.</h1>
<Link to={routePath("APP_HOME")}>홈으로 이동</Link>
</main>
);
}
/**
* @param {{
* authSession: import("../../application/ports/auth-session-port.js").AuthSessionPort
* }} props
*/
function GuardedSampleRoute({ authSession }) {
const decision = decideRouteAccess(
"SAMPLE_RESOURCE_LIST",
authSession.getState(),
);
if (!decision.allowed) {
return (
<main>
<h1>세션이 필요합니다.</h1>
<button type="button">로그인</button>
</main>
);
}
return <SamplePlaceholder />;
}
/**
* @param {{
* authSession: import("../../application/ports/auth-session-port.js").AuthSessionPort,
* basename?: string
* }} props
*/
export function AppRouter({ authSession, basename = "/" }) {
return (
<BrowserRouter basename={basename}>
<Routes>
<Route path={routePath("APP_HOME")} element={<HomePage />} />
<Route
path={routePath("SAMPLE_RESOURCE_LIST")}
element={<GuardedSampleRoute authSession={authSession} />}
/>
<Route path={routePath("NOT_FOUND")} element={<NotFoundPage />} />
</Routes>
</BrowserRouter>
);
}