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:
49
src/App.jsx
49
src/App.jsx
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user