Open /Events without a Base44 login

Turns PUBLIC_ROUTES into a path -> component map and adds /Events, so the page
is reachable on our own domain without the login redirect.

This removes the redirect, not the auth requirement: Event, Staff and VendorRate
all still 403 for an anonymous visitor, so the page renders its shell with empty
lists. initialData on the events query keeps that an empty state rather than a
crash. Getting real data here needs the app made public on the Base44 side.

Match case-insensitively, the way React Router already matches the gated routes
— otherwise /events and /Events would disagree about whether login is required.

Rendered bare rather than through LayoutWrapper, so the nav chrome doesn't fire
its own authenticated queries on a page meant to work signed out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 20:47:03 +05:30
parent cbc9357c5c
commit 878ebca143

View File

@@ -50,17 +50,30 @@ const LayoutWrapper = ({ children, currentPageName }) => Layout ?
<Layout currentPageName={currentPageName}>{children}</Layout> <Layout currentPageName={currentPageName}>{children}</Layout>
: <>{children}</>; : <>{children}</>;
// Routes that render for anyone, signed in or not. LandingPage is pure marketing // Paths that render for anyone, signed in or not, skipping the auth gate below.
// 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 // LandingPage is genuinely public: pure marketing markup, no entity reads, so it
// could read what the product is. Its CTAs point at /Dashboard, which is still // needs nothing from Base44. Events is not — it lists Event, Staff and VendorRate,
// gated, so signing in stays one click away. // all of which stay behind Base44 auth. Opening the route only removes the login
const PUBLIC_ROUTES = new Set(['/LandingPage']); // 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) => { const getPublicPage = (pathname) => {
// Tolerate a trailing slash so /LandingPage/ isn't quietly sent to login. // Tolerate a trailing slash, and compare case-insensitively so /events lands on
const normalized = pathname.length > 1 ? pathname.replace(/\/+$/, '') : pathname; // the same page as /Events — that is how React Router already matches the gated
return PUBLIC_ROUTES.has(normalized); // 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 // 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 { isLoadingAuth, isLoadingPublicSettings, authError, isAuthenticated, navigateToLogin } = useAuth();
const location = useLocation(); const location = useLocation();
// Ahead of both gates below. The spinner would stall this page on a network // Ahead of both gates below. The spinner would stall these pages on a network
// round-trip it has no use for, and the auth gate would redirect away from it — // round-trip, and the auth gate would redirect away from them — either one
// either one defeats the point of a public page. // defeats the point of a public route. Rendered bare, without LayoutWrapper,
if (isPublicRoute(location.pathname)) { // so the nav chrome doesn't fire its own authenticated queries here.
return ( const PublicPage = getPublicPage(location.pathname);
<Routes> if (PublicPage) {
<Route path="/LandingPage" element={<LandingPage />} /> return <PublicPage />;
</Routes>
);
} }
// Decided on the token rather than on the resolved auth state, so it settles // Decided on the token rather than on the resolved auth state, so it settles