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;