diff --git a/src/App.jsx b/src/App.jsx index 8aa384e..b0a8df4 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -50,17 +50,30 @@ const LayoutWrapper = ({ children, currentPageName }) => Layout ? {children} : <>{children}; -// Routes that render for anyone, signed in or not. LandingPage is pure marketing -// markup — it reads no entities and never touches useAuth — so the only thing the -// auth gate ever did for it was bounce visitors to a Google login before they -// could read what the product is. Its CTAs point at /Dashboard, which is still -// gated, so signing in stays one click away. -const PUBLIC_ROUTES = new Set(['/LandingPage']); +// Paths that render for anyone, signed in or not, skipping the auth gate below. +// +// LandingPage is genuinely public: pure marketing markup, no entity reads, so it +// needs nothing from Base44. Events is not — it lists Event, Staff and VendorRate, +// all of which stay behind Base44 auth. Opening the route only removes the login +// redirect; a signed-out visitor gets the page shell with empty lists, because +// skipping the gate cannot grant data the backend still refuses to serve. +const PUBLIC_ROUTES = new Map([ + ['/LandingPage', LandingPage], + ['/Events', Pages['Events']], +]); -const isPublicRoute = (pathname) => { - // Tolerate a trailing slash so /LandingPage/ isn't quietly sent to login. - const normalized = pathname.length > 1 ? pathname.replace(/\/+$/, '') : pathname; - return PUBLIC_ROUTES.has(normalized); +const getPublicPage = (pathname) => { + // Tolerate a trailing slash, and compare case-insensitively so /events lands on + // the same page as /Events — that is how React Router already matches the gated + // routes, and a mismatch here would send one casing to login and not the other. + const trimmed = pathname.length > 1 ? pathname.replace(/\/+$/, '') : pathname; + const normalized = trimmed.toLowerCase(); + for (const [path, Page] of PUBLIC_ROUTES) { + if (path.toLowerCase() === normalized) { + return Page; + } + } + return null; }; // The bare domain is the front door, so it can't be allowed to bounce anonymous @@ -72,15 +85,13 @@ const AuthenticatedApp = () => { const { isLoadingAuth, isLoadingPublicSettings, authError, isAuthenticated, navigateToLogin } = useAuth(); const location = useLocation(); - // Ahead of both gates below. The spinner would stall this page on a network - // round-trip it has no use for, and the auth gate would redirect away from it — - // either one defeats the point of a public page. - if (isPublicRoute(location.pathname)) { - return ( - - } /> - - ); + // Ahead of both gates below. The spinner would stall these pages on a network + // round-trip, and the auth gate would redirect away from them — either one + // defeats the point of a public route. Rendered bare, without LayoutWrapper, + // so the nav chrome doesn't fire its own authenticated queries here. + const PublicPage = getPublicPage(location.pathname); + if (PublicPage) { + return ; } // Decided on the token rather than on the resolved auth state, so it settles