import { useEffect, Suspense, lazy } from "react";
import { Switch, Route, useLocation } from "wouter";
import { queryClient } from "./lib/queryClient";
import { QueryClientProvider } from "@tanstack/react-query";
import { Toaster } from "@/components/ui/toaster";
import { PageLoader } from "@/components/page-loader";
import { useAuth } from "@/hooks/use-auth";
import { isSafeInvitePath, readPendingInvitePath } from "@/lib/invite-return";
import { mayRenderMarketingHomepage } from "@/lib/root-surface";
import { usePersistBrowserTimezone } from "@/hooks/use-persist-browser-timezone";
import { PostHogIdentify, usePostHogIdentify } from "@/hooks/use-posthog-identify";
import { FinanceCacheGuard } from "@/components/finance-cache-guard";
import { BandProvider } from "@/contexts/BandContext";
import { initGA } from "./lib/analytics";
import { useAnalytics } from "./hooks/use-analytics";
// Critical pages loaded immediately (landing, login, not-found)
import Landing from "@/pages/landing";
import Login from "@/pages/login";
import NotFound from "@/pages/not-found";
// Lazy load the authenticated app shell (keeps it out of the public landing bundle)
const AppLayout = lazy(() =>
import("@/components/layout/app-layout").then((m) => ({ default: m.AppLayout }))
);
// Lazy load authenticated pages (loaded only when needed)
const Dashboard = lazy(() => import("@/pages/dashboard"));
const GettingStarted = lazy(() => import("@/pages/getting-started"));
const OnboardingRedirect = lazy(() => import("@/components/onboarding-redirect"));
const Calendar = lazy(() => import("@/pages/calendar"));
const Setlists = lazy(() => import("@/pages/setlists"));
const SetlistEditor = lazy(() => import("@/pages/setlist-editor"));
const Rehearsal = lazy(() => import("@/pages/rehearsal"));
const AiSetlistCoach = lazy(() => import("@/pages/ai-setlist-coach"));
const Songs = lazy(() => import("@/pages/songs"));
const SongDetails = lazy(() => import("@/pages/song-details"));
const Members = lazy(() => import("@/pages/members"));
const Finances = lazy(() => import("@/pages/finances"));
const Settings = lazy(() => import("@/pages/settings"));
const SettingsDeleteAccount = lazy(
() => import("@/pages/settings-delete-account"),
);
const DeleteAccountPublic = lazy(
() => import("@/pages/delete-account-public"),
);
const Subscription = lazy(() => import("@/pages/subscription"));
const EventDetails = lazy(() => import("@/pages/event-details"));
const Venues = lazy(() => import("@/pages/venues"));
const VenueDetail = lazy(() => import("@/pages/venue-detail"));
const Todos = lazy(() => import("@/pages/todos"));
// Lazy load admin pages (heavy components)
const AdminDashboard = lazy(() => import("@/pages/admin"));
const AdminUserManagement = lazy(() => import("@/pages/admin-user-management"));
// Lazy load public content pages
const ResetPassword = lazy(() => import("@/pages/reset-password"));
const PrivacyPolicy = lazy(() => import("@/pages/privacy-policy"));
const VerificationPending = lazy(() => import("@/pages/verification-pending"));
const AcceptInvitation = lazy(() => import("@/pages/accept-invitation"));
const SmartSongAnalytics = lazy(() => import("@/pages/smart-song-analytics"));
const GreatCoverBandSetlist = lazy(() => import("@/pages/great-cover-band-setlist"));
const WhyEveryBandShouldUseBandMGT = lazy(() => import("@/pages/why-every-band-should-use-bandmgt"));
const Resources = lazy(() => import("@/pages/resources"));
const ResourcesTopicPage = lazy(() => import("@/pages/resources-topic"));
const ResourcesTypeRoute = lazy(() => import("@/pages/resources-type"));
const PreGigChecklistPage = lazy(() => import("@/pages/resources-pre-gig-checklist"));
const GigFeeCalculatorPage = lazy(() => import("@/pages/resources-gig-fee-calculator"));
const PerformanceContractUkPage = lazy(() => import("@/pages/resources-performance-contract-uk"));
const PerformanceContractUsPage = lazy(() => import("@/pages/resources-performance-contract-us"));
const WeddingPlaybookPage = lazy(() => import("@/pages/resources-wedding-playbook"));
const SetlistEnergyPlannerPage = lazy(() => import("@/pages/resources-setlist-energy-planner"));
const AiSetlistCoachGuidePage = lazy(() => import("@/pages/resources-ai-setlist-coach"));
const AiSetlistComparePage = lazy(() => import("@/pages/resources-ai-setlist-compare"));
const VenueFollowUpPackPage = lazy(() => import("@/pages/resources-venue-follow-up"));
const About = lazy(() => import("@/pages/about"));
// Blog pages (accessible to all users)
const Blog = lazy(() => import("@/pages/blog"));
const BlogArticle = lazy(() => import("@/pages/blog-article"));
const WhatsNew = lazy(() => import("@/pages/whats-new"));
// In-app changelog (authenticated only)
const Changelog = lazy(() => import("@/pages/changelog"));
function InviteReturnGate() {
const [, navigate] = useLocation();
useEffect(() => {
const path = readPendingInvitePath();
if (path) navigate(path, { replace: true });
}, [navigate]);
return ;
}
function Router() {
const { authStatus } = useAuth();
const [location] = useLocation();
const pathname = location.split("?")[0] || "/";
usePersistBrowserTimezone();
// Identify users in PostHog when authenticated
usePostHogIdentify();
// Track page views when routes change
useAnalytics();
if (isSafeInvitePath(pathname)) {
return (
}>
);
}
if (authStatus === "pending") {
return ;
}
const pendingInvite = readPendingInvitePath();
if (!mayRenderMarketingHomepage({
authStatus,
pathname,
pendingInvitePath: pendingInvite,
}) && pathname === "/" && authStatus === "anonymous") {
return ;
}
if (authStatus !== "authenticated") {
return (
}>
{ window.location.href = '/resources/analytics/smart-song-analytics'; return null; }} />
{ window.location.href = '/resources/setlist-strategy/great-cover-band-setlist'; return null; }} />
);
}
return (
}>
{/* Full-screen routes — no app layout */}
{/* All other routes get the app layout */}
}>
{
const [, setLocation] = useLocation();
useEffect(() => {
setLocation("/settings/delete-account");
}, [setLocation]);
return null;
}}
/>
{ const [, setLocation] = useLocation(); useEffect(() => setLocation('/dashboard'), []); return null; }} />
);
}
function App() {
// Defer Google Analytics initialization to improve initial page load
useEffect(() => {
// Defer GA loading until after critical content is rendered
const timeoutId = setTimeout(() => {
if (!import.meta.env.VITE_GA_MEASUREMENT_ID) {
console.warn('Missing required Google Analytics key: VITE_GA_MEASUREMENT_ID');
} else {
initGA();
}
}, 2000); // Load after 2 seconds to prioritize critical content
return () => clearTimeout(timeoutId);
}, []);
return (
);
}
export default App;