diff --git a/webapp/package-lock.json b/webapp/package-lock.json index f170363c..7be9d5d8 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -20,12 +20,13 @@ "chart.js": "^4.5.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "coordo": "github:dataforgoodfr/Coordonnees#master", + "coordo": "github:dataforgoodfr/Coordonnees#main", "lucide-react": "^0.562.0", "react": "^19.2.0", "react-chartjs-2": "^5.3.1", "react-dom": "^19.2.0", "react-resizable-panels": "^3.0.6", + "react-router-dom": "^7.13.0", "recharts": "^2.15.4" }, "devDependencies": { @@ -3734,6 +3735,19 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/coordo": { "version": "1.0.0", "resolved": "git+ssh://git@github.com/dataforgoodfr/Coordonnees.git#c688088b3dc6388c33cce812e2503f63171bc2fa", @@ -6468,6 +6482,44 @@ "react-dom": "^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, + "node_modules/react-router": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz", + "integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz", + "integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==", + "license": "MIT", + "dependencies": { + "react-router": "7.13.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/react-smooth": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", @@ -6753,6 +6805,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", diff --git a/webapp/package.json b/webapp/package.json index 71fa46cb..8e0cde34 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -31,6 +31,7 @@ "react-chartjs-2": "^5.3.1", "react-dom": "^19.2.0", "react-resizable-panels": "^3.0.6", + "react-router-dom": "^7.13.0", "recharts": "^2.15.4" }, "devDependencies": { diff --git a/webapp/src/app/routes/AppRouter.tsx b/webapp/src/app/routes/AppRouter.tsx index 535a9053..2695b8e2 100644 --- a/webapp/src/app/routes/AppRouter.tsx +++ b/webapp/src/app/routes/AppRouter.tsx @@ -1,5 +1,21 @@ -import { MainPage } from '@pages'; +import { MainPage } from "@/pages"; +import { lazy } from "react"; +import { BrowserRouter, Route, Routes } from "react-router-dom"; +import { AdminRoute } from "./lib/ProtectedRoute"; + +const AdminPage = lazy(() => import("@/pages/admin")); +const LoginPage = lazy(() => import("@/pages/login")); export function AppRouter() { - return ; + return ( + + + } /> + } /> + }> + } /> + + + + ); } diff --git a/webapp/src/app/routes/lib/ProtectedRoute.tsx b/webapp/src/app/routes/lib/ProtectedRoute.tsx new file mode 100644 index 00000000..28a77f60 --- /dev/null +++ b/webapp/src/app/routes/lib/ProtectedRoute.tsx @@ -0,0 +1,17 @@ +import { useAuth } from "@/app/providers/AuthProvider"; +import { Navigate, Outlet, useLocation } from "react-router-dom"; + +/** + * Route guard for admin routes. + * Redirect to login page if not authenticated. + */ +export function AdminRoute() { + const { isAuthenticated } = useAuth(); + const location = useLocation(); + + if (!isAuthenticated) { + return ; + } + + return ; +} diff --git a/webapp/src/pages/MainPage.tsx b/webapp/src/pages/MainPage.tsx index 09109800..b9378ac0 100644 --- a/webapp/src/pages/MainPage.tsx +++ b/webapp/src/pages/MainPage.tsx @@ -1,20 +1,22 @@ -import { useApi } from "@providers"; +import { DashboardPopover, Map, MapSidebar } from "@/widgets"; import { Header } from "@components"; +import { useApi } from "@providers"; import { SidebarProvider } from "@ui/sidebar"; -import { DashboardPopover, MapSidebar, Map } from "@/widgets"; import { useEffect, useState } from "react"; import { ResizableHandle, ResizablePanel, ResizablePanelGroup, -} from "@/components/ui/resizable" +} from "@/components/ui/resizable"; +import { useNavigate } from "react-router-dom"; export interface MainPageProps { userData?: unknown; } export function MainPage() { + const navigate = useNavigate(); const client = useApi(); const [data, setData] = useState(null); @@ -23,10 +25,11 @@ export function MainPage() { .then((json) => setData(json.data)) .catch((err) => console.error("fetchData error", err)); }, []); + return (
console.log("Login clicked")} + onLogin={() => navigate('/login')} onLogout={() => console.log("Logout clicked")} isLogin={false} /> diff --git a/webapp/src/pages/admin/AdminPage.tsx b/webapp/src/pages/admin/AdminPage.tsx new file mode 100644 index 00000000..4e6095e5 --- /dev/null +++ b/webapp/src/pages/admin/AdminPage.tsx @@ -0,0 +1,7 @@ +export function AdminPage() { + return ( +
+

Admin Page

+
+ ); +} diff --git a/webapp/src/pages/admin/index.tsx b/webapp/src/pages/admin/index.tsx new file mode 100644 index 00000000..6a93bf98 --- /dev/null +++ b/webapp/src/pages/admin/index.tsx @@ -0,0 +1 @@ +export { AdminPage as default } from "./AdminPage"; diff --git a/webapp/src/pages/index.ts b/webapp/src/pages/index.ts index 316470a0..1d145162 100644 --- a/webapp/src/pages/index.ts +++ b/webapp/src/pages/index.ts @@ -1,2 +1 @@ -export { LoginPage } from './LoginPage'; -export { MainPage } from './MainPage'; \ No newline at end of file +export { MainPage } from "./MainPage"; diff --git a/webapp/src/pages/LoginPage.tsx b/webapp/src/pages/login/LoginPage.tsx similarity index 51% rename from webapp/src/pages/LoginPage.tsx rename to webapp/src/pages/login/LoginPage.tsx index 8ec65b0a..a8d7d7a3 100644 --- a/webapp/src/pages/LoginPage.tsx +++ b/webapp/src/pages/login/LoginPage.tsx @@ -1,6 +1,6 @@ export function LoginPage() { return ( -
+

Login Page

); diff --git a/webapp/src/pages/login/index.ts b/webapp/src/pages/login/index.ts new file mode 100644 index 00000000..35fe74b2 --- /dev/null +++ b/webapp/src/pages/login/index.ts @@ -0,0 +1 @@ +export { LoginPage as default } from "./LoginPage";