Merge pull request 'fix(mobile): lance la vérification de mise à jour à chaque ouverture (#106)' (#114) from fix/mobile-update-check-on-open into main
Some checks failed
Some checks failed
This commit is contained in:
commit
c17b5b0060
3 changed files with 124 additions and 105 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import { Navigate, Outlet, Route, Routes } from "react-router-dom";
|
||||
import { AdminAuthProvider } from "./features/admin/AdminAuthContext";
|
||||
import { RequireAdmin } from "./features/admin/RequireAdmin";
|
||||
import { UpdateBanner } from "./features/app-update/UpdateBanner";
|
||||
import { RedirectIfAuthenticated } from "./features/auth/RedirectIfAuthenticated";
|
||||
import { RequireAuth } from "./features/auth/RequireAuth";
|
||||
import { AdminLayout } from "./layouts/AdminLayout";
|
||||
|
|
@ -71,111 +72,120 @@ import { ShoppingListPage } from "./pages/shopping-list/ShoppingListPage";
|
|||
* never nested under `RequireAuth`. `/admin/login` is the only
|
||||
* unauthenticated admin route; everything else sits under `RequireAdmin` +
|
||||
* `AdminLayout`.
|
||||
*
|
||||
* {@link UpdateBanner} is mounted here, outside `<Routes>`, rather than in
|
||||
* `AppLayout` — the native app-update check (issue #66) must run on every
|
||||
* app start, session or not, and `AppLayout` only mounts once a visitor is
|
||||
* past `RequireAuth`. It's a `position: fixed` strip and renders nothing on
|
||||
* the web, so mounting it app-wide costs the routed pages no layout.
|
||||
*/
|
||||
export function App() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route
|
||||
element={
|
||||
<RequireAuth>
|
||||
<AppLayout />
|
||||
</RequireAuth>
|
||||
}
|
||||
>
|
||||
<Route path="/" element={<PlanningPage />} />
|
||||
{/* Same component for both — a master-detail layout, not a
|
||||
<>
|
||||
<UpdateBanner />
|
||||
<Routes>
|
||||
<Route
|
||||
element={
|
||||
<RequireAuth>
|
||||
<AppLayout />
|
||||
</RequireAuth>
|
||||
}
|
||||
>
|
||||
<Route path="/" element={<PlanningPage />} />
|
||||
{/* Same component for both — a master-detail layout, not a
|
||||
navigation to a separate page: the tab bar + table stay
|
||||
mounted, only RecipesPage's detail panel changes with `:id`
|
||||
(see RecipesPage.tsx). */}
|
||||
<Route path="/recettes" element={<RecipesPage />} />
|
||||
<Route path="/recettes/nouvelle" element={<RecipeFormPage />} />
|
||||
<Route path="/recettes/importer/:sourceKey/:externalId" element={<ImportRecipePage />} />
|
||||
<Route path="/recettes/sources/:sourceKey/:externalId" element={<RecipesPage />} />
|
||||
<Route path="/recettes/:id" element={<RecipesPage />} />
|
||||
<Route path="/recettes/:id/modifier" element={<RecipeFormPage />} />
|
||||
<Route path="/liste-de-courses" element={<ShoppingListPage />} />
|
||||
<Route path="/cuisiner" element={<CookingSessionPage />} />
|
||||
<Route path="/parametres/compte" element={<AccountSettingsPage />} />
|
||||
<Route path="/parametres/preferences" element={<PreferencesPage />} />
|
||||
<Route path="/parametres/foyer" element={<HouseholdSettingsPage />} />
|
||||
<Route path="/parametres/preferences-utilisateur" element={<UserPreferencesPage />} />
|
||||
<Route path="/parametres/application" element={<AppSettingsPage />} />
|
||||
<Route path="/parametres/credits" element={<CreditsPage />} />
|
||||
<Route path="/foyer" element={<Navigate to="/parametres/foyer" replace />} />
|
||||
</Route>
|
||||
<Route
|
||||
path="/onboarding/regime"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<OnboardingDietPage />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/onboarding/foyer"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<OnboardingHouseholdPage />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/onboarding/sources"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<OnboardingSourcesPage />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/onboarding/allergenes"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<OnboardingAllergensPage />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<RedirectIfAuthenticated>
|
||||
<LoginPage />
|
||||
</RedirectIfAuthenticated>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/signup"
|
||||
element={
|
||||
<RedirectIfAuthenticated>
|
||||
<SignupPage />
|
||||
</RedirectIfAuthenticated>
|
||||
}
|
||||
/>
|
||||
<Route path="/telecharger" element={<DownloadPage />} />
|
||||
<Route
|
||||
element={
|
||||
<AdminAuthProvider>
|
||||
<Outlet />
|
||||
</AdminAuthProvider>
|
||||
}
|
||||
>
|
||||
<Route path="/admin/login" element={<AdminLoginPage />} />
|
||||
<Route path="/recettes" element={<RecipesPage />} />
|
||||
<Route path="/recettes/nouvelle" element={<RecipeFormPage />} />
|
||||
<Route path="/recettes/importer/:sourceKey/:externalId" element={<ImportRecipePage />} />
|
||||
<Route path="/recettes/sources/:sourceKey/:externalId" element={<RecipesPage />} />
|
||||
<Route path="/recettes/:id" element={<RecipesPage />} />
|
||||
<Route path="/recettes/:id/modifier" element={<RecipeFormPage />} />
|
||||
<Route path="/liste-de-courses" element={<ShoppingListPage />} />
|
||||
<Route path="/cuisiner" element={<CookingSessionPage />} />
|
||||
<Route path="/parametres/compte" element={<AccountSettingsPage />} />
|
||||
<Route path="/parametres/preferences" element={<PreferencesPage />} />
|
||||
<Route path="/parametres/foyer" element={<HouseholdSettingsPage />} />
|
||||
<Route path="/parametres/preferences-utilisateur" element={<UserPreferencesPage />} />
|
||||
<Route path="/parametres/application" element={<AppSettingsPage />} />
|
||||
<Route path="/parametres/credits" element={<CreditsPage />} />
|
||||
<Route path="/foyer" element={<Navigate to="/parametres/foyer" replace />} />
|
||||
</Route>
|
||||
<Route
|
||||
path="/admin"
|
||||
path="/onboarding/regime"
|
||||
element={
|
||||
<RequireAdmin>
|
||||
<AdminLayout />
|
||||
</RequireAdmin>
|
||||
<RequireAuth>
|
||||
<OnboardingDietPage />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/onboarding/foyer"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<OnboardingHouseholdPage />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/onboarding/sources"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<OnboardingSourcesPage />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/onboarding/allergenes"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<OnboardingAllergensPage />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<RedirectIfAuthenticated>
|
||||
<LoginPage />
|
||||
</RedirectIfAuthenticated>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/signup"
|
||||
element={
|
||||
<RedirectIfAuthenticated>
|
||||
<SignupPage />
|
||||
</RedirectIfAuthenticated>
|
||||
}
|
||||
/>
|
||||
<Route path="/telecharger" element={<DownloadPage />} />
|
||||
<Route
|
||||
element={
|
||||
<AdminAuthProvider>
|
||||
<Outlet />
|
||||
</AdminAuthProvider>
|
||||
}
|
||||
>
|
||||
<Route index element={<AdminDashboardPage />} />
|
||||
<Route path="monitoring" element={<AdminMonitoringPage />} />
|
||||
<Route path="corrections" element={<AdminCorrectionsPage />} />
|
||||
<Route path="catalogue" element={<AdminCatalogPage />} />
|
||||
<Route path="didacticiels" element={<AdminToursPage />} />
|
||||
<Route path="/admin/login" element={<AdminLoginPage />} />
|
||||
<Route
|
||||
path="/admin"
|
||||
element={
|
||||
<RequireAdmin>
|
||||
<AdminLayout />
|
||||
</RequireAdmin>
|
||||
}
|
||||
>
|
||||
<Route index element={<AdminDashboardPage />} />
|
||||
<Route path="monitoring" element={<AdminMonitoringPage />} />
|
||||
<Route path="corrections" element={<AdminCorrectionsPage />} />
|
||||
<Route path="catalogue" element={<AdminCatalogPage />} />
|
||||
<Route path="didacticiels" element={<AdminToursPage />} />
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Routes>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,28 @@
|
|||
// Styles for UpdateBanner — a discreet, dismissible strip above the routed
|
||||
// page content (see AppLayout.tsx). Uses --color-warning the same way
|
||||
// source-item-preview__hint does elsewhere in the app: "worth noticing",
|
||||
// Styles for UpdateBanner — a discreet, dismissible strip pinned to the top
|
||||
// of the screen. Mounted app-wide in App.tsx (outside `<Routes>`) so the
|
||||
// native update check runs session or not, hence `position: fixed` rather
|
||||
// than the old in-flow placement inside `.app-content`: this way it never
|
||||
// enters any routed page's layout / height math (`.app-layout` is
|
||||
// `height: 100vh; overflow: hidden`), it just overlays. Native-only —
|
||||
// renders nothing on the web (see UpdateBanner.tsx). Uses --color-warning
|
||||
// the same way source-item-preview__hint does elsewhere: "worth noticing",
|
||||
// not an error.
|
||||
.update-banner {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-sm);
|
||||
margin-bottom: var(--space-md);
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
// Clears the Android status bar when the WebView draws under it.
|
||||
padding-top: calc(var(--space-sm) + env(safe-area-inset-top, 0px));
|
||||
background: color-mix(in srgb, var(--color-warning) 12%, var(--color-surface));
|
||||
border: 1px solid var(--color-warning);
|
||||
border-radius: var(--radius-base);
|
||||
border-bottom: 1px solid var(--color-warning);
|
||||
font-size: var(--font-size-sm);
|
||||
|
||||
&__text {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { useState } from "react";
|
|||
import { useTranslation } from "react-i18next";
|
||||
import { NavLink, Outlet, useLocation, useNavigate } from "react-router-dom";
|
||||
import { BottomSheet } from "../components/ui/BottomSheet";
|
||||
import { UpdateBanner } from "../features/app-update/UpdateBanner";
|
||||
import { useAuth } from "../features/auth/AuthContext";
|
||||
import { useIsMobileViewport } from "../lib/useIsMobileViewport";
|
||||
import "./AppLayout.scss";
|
||||
|
|
@ -148,9 +147,9 @@ export function AppLayout() {
|
|||
)}
|
||||
|
||||
<main className={isMobile ? "app-content app-content--with-bottom-nav" : "app-content"}>
|
||||
{/* Renders nothing on the web build (native-only check) or once no
|
||||
newer version is known — see UpdateBanner's own doc comment. */}
|
||||
<UpdateBanner />
|
||||
{/* `UpdateBanner` used to sit here, but the native update check
|
||||
(issue #66) must run session or not — it's mounted app-wide in
|
||||
`App.tsx` now, as a `position: fixed` strip. */}
|
||||
<Outlet />
|
||||
</main>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue