Files
alva/felsokning/app/src/App.tsx
T
Claude 3b83fc94e9 Portalen är stängd på riktigt — m-9 stängd
Anmärkningen var att en inloggning som SER ut att autentisera ger
portalen bakom den en auktoritet den inte har. Rättelsen är inte att ta
bort skylten utan att göra spärren verklig där det finns något att
spärra mot.

Med plattformen konfigurerad autentiserar inloggningen mot
/api/auth/logga-in, varje portalväg går genom Portalvakt, och
fakturavyn läser organisationens egna fakturor ur GET /api/fakturor.
Misslyckas hämtningen visas felet — inte exemplet: data som ser äkta ut
men inte är det är värre än ett synligt fel. Utloggningen finns i
portalhuvudet och rensar sessionen på riktigt.

Utan konfigurerad plattform finns ingen session att kräva, och
demonstrationsmärkningen visas exakt i det läget.

---- Varför garantin inte är ett källkodstest ------------------------

Sviten kan bara läsa koden och se att vakten är inkopplad. Släpper den
igenom ändå — fel villkor, fel ordning, ett <Navigate> som aldrig hinner
rendera — ser koden likadan ut. Och en spärr som inte spärrar är precis
det m-9 handlade om.

e2e/portalsparr.mjs bygger därför med plattformen konfigurerad och
tittar var besökaren faktiskt hamnar: fem vägar spärrade utan session,
fem öppna med, utloggning som rensar token och stänger portalen igen.
Mutationstestad — att plocka bort vakten från en enda route fäller den.

Bevisad: 374 enhetstester, typkontroll, genomgången 4/4 ärenden,
portalspärren 14/14.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-06 12:08:18 +00:00

102 lines
5.0 KiB
TypeScript

import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, HashRouter, Routes, Route } from "react-router-dom";
import Index from "./pages/Index";
import NotFound from "./pages/NotFound";
import ResetPassword from "./pages/ResetPassword";
import Profile from "./pages/Profile";
import Account from "./pages/Account";
import AccountConfirmation from "./pages/AccountConfirmation";
import Contact from "./pages/Contact";
import Admin from "./pages/Admin";
import FAQ from "./pages/FAQ";
import OrderConfirmation from "./pages/OrderConfirmation";
import ChangeSubscription from "./pages/ChangeSubscription";
import Arendelista from "./pages/felsokning/Arendelista";
import NyttArende from "./pages/felsokning/NyttArende";
import ArendeSida from "./pages/felsokning/ArendeSida";
import DelatArende from "./pages/felsokning/DelatArende";
import PublikDelning from "./pages/felsokning/PublikDelning";
import Oversikt from "./pages/felsokning/Oversikt";
import Installningar from "./pages/felsokning/Installningar";
import AlvaStart from "./pages/alva/Start";
import AlvaAnsokan from "./pages/alva/Ansokan";
import AlvaLoggaIn from "./pages/alva/LoggaIn";
import AlvaPortal from "./pages/alva/Portal";
import AlvaKunskapskallor from "./pages/alva/Kunskapskallor";
import AlvaAnalys from "./pages/alva/Analys";
import AlvaFakturor from "./pages/alva/Fakturor";
import AlvaIntegration from "./pages/alva/Integration";
import { Portalvakt } from "./pages/alva/Portalvakt";
import { PaymentTestModeBanner } from "@/components/PaymentTestModeBanner";
const queryClient = new QueryClient();
// Hash-baserad routing för miljöer utan SPA-rewrites (t.ex. förhandsvisning
// på en statisk sida). Standard är vanlig historik-routing.
//
// Historik-routing kräver att sidan serveras från roten: ligger den under
// en sökväg matchar ingen route och besökaren får 404-sidan. I
// förhandsvisningsläge går routingen därför via hash — då spelar
// sökvägen ingen roll — och startsidan är Guidad Felsökning i stället för
// värdapplikationens startsida.
const forhandsvisning = !!import.meta.env.VITE_HASH_ROUTER;
const Router = forhandsvisning ? HashRouter : BrowserRouter;
function AppContent() {
return (
<Router>
<PaymentTestModeBanner />
<Routes>
<Route path="/" element={forhandsvisning ? <Arendelista /> : <Index />} />
<Route path="/contact" element={<Contact />} />
<Route path="/faq" element={<FAQ />} />
<Route path="/reset-password" element={<ResetPassword />} />
<Route path="/profile" element={<Profile />} />
<Route path="/account" element={<Account />} />
<Route path="/account/confirmation" element={<AccountConfirmation />} />
<Route path="/admin" element={<Admin />} />
<Route path="/order-confirmation" element={<OrderConfirmation />} />
<Route path="/account/change-subscription" element={<ChangeSubscription />} />
{/* ALVA — publik webbplats och kundportal. Samma system, samma
komponentbibliotek: besökaren lämnar aldrig marknadswebben
när den loggar in. */}
<Route path="/alva" element={<AlvaStart />} />
<Route path="/alva/ansokan" element={<AlvaAnsokan />} />
<Route path="/alva/logga-in" element={<AlvaLoggaIn />} />
{/* Portalen är stängd utan giltig plattformssession — se
Portalvakt. Utan konfigurerad plattform finns ingen session
att kräva, och vyerna är då märkta som demonstration. */}
<Route path="/alva/portal" element={<Portalvakt><AlvaPortal /></Portalvakt>} />
<Route path="/alva/portal/kunskapskallor" element={<Portalvakt><AlvaKunskapskallor /></Portalvakt>} />
<Route path="/alva/portal/analys" element={<Portalvakt><AlvaAnalys /></Portalvakt>} />
<Route path="/alva/portal/integration" element={<Portalvakt><AlvaIntegration /></Portalvakt>} />
<Route path="/alva/portal/fakturor" element={<Portalvakt><AlvaFakturor /></Portalvakt>} />
<Route path="/felsokning" element={<Arendelista />} />
<Route path="/felsokning/nytt" element={<NyttArende />} />
<Route path="/felsokning/arende/:id" element={<ArendeSida />} />
<Route path="/felsokning/dela/:id" element={<DelatArende />} />
<Route path="/felsokning/delad/:kod" element={<PublikDelning />} />
<Route path="/felsokning/oversikt" element={<Oversikt />} />
<Route path="/felsokning/installningar" element={<Installningar />} />
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
<Route path="*" element={<NotFound />} />
</Routes>
</Router>
);
}
const App = () => (
<QueryClientProvider client={queryClient}>
<TooltipProvider>
<Toaster />
<Sonner />
<AppContent />
</TooltipProvider>
</QueryClientProvider>
);
export default App;