Web: wire AppLayout into routing + stub section pages (step 3/5)
- App.tsx: every authenticated route now nests under one
RequireAuth + AppLayout parent route (react-router nested
routes/<Outlet />) instead of each page wrapping its own guard.
- New routes/pages: /recettes, /liste-de-courses, /foyer, each a thin
wrapper around a shared ComingSoonPage ("cette section arrive
bientôt.") — no backend behind them yet, matches the "pages stub
dédiées" choice discussed in chat.
- locales/fr/translation.json: nav labels + stub copy.
HomePage still shows its own greeting/logout card here (unchanged,
now nested inside AppLayout's <Outlet /> — briefly duplicating the
sidebar's greeting/logout) — replaced by the actual planning view in
the next commit.
This commit is contained in:
parent
f4ab482b52
commit
c07f8ad82e
7 changed files with 90 additions and 7 deletions
|
|
@ -1,27 +1,37 @@
|
||||||
import { Navigate, Route, Routes } from "react-router-dom";
|
import { Navigate, Route, Routes } from "react-router-dom";
|
||||||
import { RedirectIfAuthenticated } from "./features/auth/RedirectIfAuthenticated";
|
import { RedirectIfAuthenticated } from "./features/auth/RedirectIfAuthenticated";
|
||||||
import { RequireAuth } from "./features/auth/RequireAuth";
|
import { RequireAuth } from "./features/auth/RequireAuth";
|
||||||
|
import { AppLayout } from "./layouts/AppLayout";
|
||||||
import { HomePage } from "./pages/HomePage";
|
import { HomePage } from "./pages/HomePage";
|
||||||
|
import { HouseholdPage } from "./pages/HouseholdPage";
|
||||||
import { LoginPage } from "./pages/LoginPage";
|
import { LoginPage } from "./pages/LoginPage";
|
||||||
|
import { RecipesPage } from "./pages/RecipesPage";
|
||||||
|
import { ShoppingListPage } from "./pages/ShoppingListPage";
|
||||||
import { SignupPage } from "./pages/SignupPage";
|
import { SignupPage } from "./pages/SignupPage";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Top-level route table. `/` requires an authenticated session (see
|
* Top-level route table. Every authenticated section is nested under one
|
||||||
* {@link RequireAuth}); `/login` and `/signup` redirect an already-logged-in
|
* `RequireAuth` + `AppLayout` parent route (sidebar chrome + `/auth`
|
||||||
* visitor to `/` instead (see {@link RedirectIfAuthenticated}). Anything
|
* guard applied once, not per-page — see {@link AppLayout}); `/login` and
|
||||||
* else falls back to `/`, which itself redirects to `/login` if needed.
|
* `/signup` redirect an already-logged-in visitor to `/` instead (see
|
||||||
|
* {@link RedirectIfAuthenticated}). Anything else falls back to `/`, which
|
||||||
|
* itself redirects to `/login` if needed.
|
||||||
*/
|
*/
|
||||||
export function App() {
|
export function App() {
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
path="/"
|
|
||||||
element={
|
element={
|
||||||
<RequireAuth>
|
<RequireAuth>
|
||||||
<HomePage />
|
<AppLayout />
|
||||||
</RequireAuth>
|
</RequireAuth>
|
||||||
}
|
}
|
||||||
/>
|
>
|
||||||
|
<Route path="/" element={<HomePage />} />
|
||||||
|
<Route path="/recettes" element={<RecipesPage />} />
|
||||||
|
<Route path="/liste-de-courses" element={<ShoppingListPage />} />
|
||||||
|
<Route path="/foyer" element={<HouseholdPage />} />
|
||||||
|
</Route>
|
||||||
<Route
|
<Route
|
||||||
path="/login"
|
path="/login"
|
||||||
element={
|
element={
|
||||||
|
|
|
||||||
|
|
@ -42,5 +42,17 @@
|
||||||
"home": {
|
"home": {
|
||||||
"greeting": "Bonjour {{firstName}} {{lastName}} 👋",
|
"greeting": "Bonjour {{firstName}} {{lastName}} 👋",
|
||||||
"logout": "Se déconnecter"
|
"logout": "Se déconnecter"
|
||||||
|
},
|
||||||
|
"recipes": {
|
||||||
|
"title": "Recettes",
|
||||||
|
"comingSoon": "Cette section arrive bientôt."
|
||||||
|
},
|
||||||
|
"shoppingList": {
|
||||||
|
"title": "Liste de courses",
|
||||||
|
"comingSoon": "Cette section arrive bientôt."
|
||||||
|
},
|
||||||
|
"household": {
|
||||||
|
"title": "Foyer & profil",
|
||||||
|
"comingSoon": "Cette section arrive bientôt."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
apps/web/src/pages/ComingSoonPage.scss
Normal file
12
apps/web/src/pages/ComingSoonPage.scss
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Styles for ComingSoonPage — shared by every stub section page.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
.coming-soon-page {
|
||||||
|
max-width: 40rem;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
font-size: var(--font-size-md);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
apps/web/src/pages/ComingSoonPage.tsx
Normal file
23
apps/web/src/pages/ComingSoonPage.tsx
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import "./ComingSoonPage.scss";
|
||||||
|
|
||||||
|
interface ComingSoonPageProps {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder rendered by every section that has a route/sidebar entry but
|
||||||
|
* no real feature behind it yet (Recettes, Liste de courses, Foyer &
|
||||||
|
* profil — see `RecipesPage.tsx` etc.). One shared component instead of
|
||||||
|
* three near-identical markup blocks; each page still gets its own file
|
||||||
|
* (and its own copy, via i18n) so building out a real feature later means
|
||||||
|
* rewriting one dedicated file, not splitting a generic route.
|
||||||
|
*/
|
||||||
|
export function ComingSoonPage({ title, description }: ComingSoonPageProps) {
|
||||||
|
return (
|
||||||
|
<div className="coming-soon-page">
|
||||||
|
<h1>{title}</h1>
|
||||||
|
<p>{description}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
8
apps/web/src/pages/HouseholdPage.tsx
Normal file
8
apps/web/src/pages/HouseholdPage.tsx
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ComingSoonPage } from "./ComingSoonPage";
|
||||||
|
|
||||||
|
/** Household & profile section — routed at `/foyer`. No backend yet beyond auth, stub for now. */
|
||||||
|
export function HouseholdPage() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return <ComingSoonPage title={t("household.title")} description={t("household.comingSoon")} />;
|
||||||
|
}
|
||||||
8
apps/web/src/pages/RecipesPage.tsx
Normal file
8
apps/web/src/pages/RecipesPage.tsx
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ComingSoonPage } from "./ComingSoonPage";
|
||||||
|
|
||||||
|
/** Recipes section — routed at `/recettes`. No backend yet (see README's "Planning" section), stub for now. */
|
||||||
|
export function RecipesPage() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return <ComingSoonPage title={t("recipes.title")} description={t("recipes.comingSoon")} />;
|
||||||
|
}
|
||||||
10
apps/web/src/pages/ShoppingListPage.tsx
Normal file
10
apps/web/src/pages/ShoppingListPage.tsx
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { ComingSoonPage } from "./ComingSoonPage";
|
||||||
|
|
||||||
|
/** Shopping list section — routed at `/liste-de-courses`. No backend yet, stub for now. */
|
||||||
|
export function ShoppingListPage() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<ComingSoonPage title={t("shoppingList.title")} description={t("shoppingList.comingSoon")} />
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue