mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 12:31:14 -05:00
209 lines
9.8 KiB
TypeScript
209 lines
9.8 KiB
TypeScript
import * as React from "react";
|
|
import { lazy, Suspense } from "react";
|
|
import { Toaster } from "@/components/ui/toaster";
|
|
import { Toaster as Sonner } from "@/components/ui/sonner";
|
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
import { QueryClient, QueryClientProvider, QueryCache } from "@tanstack/react-query";
|
|
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
|
import { CacheMonitor } from "@/components/dev/CacheMonitor";
|
|
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
|
import { AuthProvider } from "@/hooks/useAuth";
|
|
import { AuthModalProvider } from "@/contexts/AuthModalContext";
|
|
import { LocationAutoDetectProvider } from "@/components/providers/LocationAutoDetectProvider";
|
|
import { Analytics } from "@vercel/analytics/react";
|
|
import { Footer } from "@/components/layout/Footer";
|
|
import { PageLoader } from "@/components/loading/PageSkeletons";
|
|
|
|
// Core routes (eager-loaded for best UX)
|
|
import Index from "./pages/Index";
|
|
import Parks from "./pages/Parks";
|
|
import Rides from "./pages/Rides";
|
|
import Search from "./pages/Search";
|
|
import Auth from "./pages/Auth";
|
|
|
|
// Detail routes (lazy-loaded)
|
|
const ParkDetail = lazy(() => import("./pages/ParkDetail"));
|
|
const RideDetail = lazy(() => import("./pages/RideDetail"));
|
|
const ParkRides = lazy(() => import("./pages/ParkRides"));
|
|
const Manufacturers = lazy(() => import("./pages/Manufacturers"));
|
|
const ManufacturerDetail = lazy(() => import("./pages/ManufacturerDetail"));
|
|
const ManufacturerRides = lazy(() => import("./pages/ManufacturerRides"));
|
|
const ManufacturerModels = lazy(() => import("./pages/ManufacturerModels"));
|
|
const RideModelDetail = lazy(() => import("./pages/RideModelDetail"));
|
|
const RideModelRides = lazy(() => import("./pages/RideModelRides"));
|
|
const Designers = lazy(() => import("./pages/Designers"));
|
|
const DesignerDetail = lazy(() => import("./pages/DesignerDetail"));
|
|
const DesignerRides = lazy(() => import("./pages/DesignerRides"));
|
|
const ParkOwners = lazy(() => import("./pages/ParkOwners"));
|
|
const PropertyOwnerDetail = lazy(() => import("./pages/PropertyOwnerDetail"));
|
|
const OwnerParks = lazy(() => import("./pages/OwnerParks"));
|
|
const Operators = lazy(() => import("./pages/Operators"));
|
|
const OperatorDetail = lazy(() => import("./pages/OperatorDetail"));
|
|
const OperatorParks = lazy(() => import("./pages/OperatorParks"));
|
|
const BlogIndex = lazy(() => import("./pages/BlogIndex"));
|
|
const BlogPost = lazy(() => import("./pages/BlogPost"));
|
|
const Terms = lazy(() => import("./pages/Terms"));
|
|
const Privacy = lazy(() => import("./pages/Privacy"));
|
|
const SubmissionGuidelines = lazy(() => import("./pages/SubmissionGuidelines"));
|
|
const Contact = lazy(() => import("./pages/Contact"));
|
|
|
|
// Admin routes (lazy-loaded - heavy bundle)
|
|
const AdminDashboard = lazy(() => import("./pages/AdminDashboard"));
|
|
const AdminModeration = lazy(() => import("./pages/AdminModeration"));
|
|
const AdminReports = lazy(() => import("./pages/AdminReports"));
|
|
const AdminSystemLog = lazy(() => import("./pages/AdminSystemLog"));
|
|
const AdminUsers = lazy(() => import("./pages/AdminUsers"));
|
|
const AdminBlog = lazy(() => import("./pages/AdminBlog"));
|
|
const AdminSettings = lazy(() => import("./pages/AdminSettings"));
|
|
const AdminContact = lazy(() => import("./pages/admin/AdminContact"));
|
|
const AdminEmailSettings = lazy(() => import("./pages/admin/AdminEmailSettings"));
|
|
|
|
// User routes (lazy-loaded)
|
|
const Profile = lazy(() => import("./pages/Profile"));
|
|
const UserSettings = lazy(() => import("./pages/UserSettings"));
|
|
const AuthCallback = lazy(() => import("./pages/AuthCallback"));
|
|
|
|
// Utility routes (lazy-loaded)
|
|
const NotFound = lazy(() => import("./pages/NotFound"));
|
|
const ForceLogout = lazy(() => import("./pages/ForceLogout"));
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
refetchOnWindowFocus: false, // Disable automatic refetch on tab focus
|
|
refetchOnMount: true, // Keep refetch on component mount
|
|
refetchOnReconnect: true, // Keep refetch on network reconnect
|
|
retry: 1, // Keep retry attempts
|
|
staleTime: 30000, // 30 seconds - queries stay fresh for 30s
|
|
gcTime: 5 * 60 * 1000, // 5 minutes - keep in cache for 5 mins
|
|
},
|
|
},
|
|
// Add cache size management
|
|
queryCache: new QueryCache({
|
|
onSuccess: () => {
|
|
// Monitor cache size in development
|
|
if (import.meta.env.DEV) {
|
|
const cacheSize = queryClient.getQueryCache().getAll().length;
|
|
if (cacheSize > 100) {
|
|
console.warn(`⚠️ Query cache size: ${cacheSize} queries`);
|
|
}
|
|
}
|
|
},
|
|
}),
|
|
});
|
|
|
|
// Add cache size monitoring and automatic cleanup (dev mode)
|
|
if (import.meta.env.DEV) {
|
|
setInterval(() => {
|
|
const cache = queryClient.getQueryCache();
|
|
const queries = cache.getAll();
|
|
|
|
// Remove oldest queries if cache exceeds 250 items (increased limit)
|
|
if (queries.length > 250) {
|
|
const sortedByLastUpdated = queries
|
|
.sort((a, b) => (a.state.dataUpdatedAt || 0) - (b.state.dataUpdatedAt || 0));
|
|
|
|
const toRemove = sortedByLastUpdated.slice(0, queries.length - 200);
|
|
toRemove.forEach(query => {
|
|
queryClient.removeQueries({ queryKey: query.queryKey });
|
|
});
|
|
|
|
console.log(`🧹 Removed ${toRemove.length} stale queries from cache`);
|
|
}
|
|
}, 60000); // Check every minute
|
|
}
|
|
|
|
function AppContent(): React.JSX.Element {
|
|
return (
|
|
<TooltipProvider>
|
|
<BrowserRouter>
|
|
<LocationAutoDetectProvider />
|
|
<Toaster />
|
|
<Sonner />
|
|
<div className="min-h-screen flex flex-col">
|
|
<div className="flex-1">
|
|
<Suspense fallback={<PageLoader />}>
|
|
<Routes>
|
|
{/* Core routes - eager loaded */}
|
|
<Route path="/" element={<Index />} />
|
|
<Route path="/parks" element={<Parks />} />
|
|
<Route path="/rides" element={<Rides />} />
|
|
<Route path="/search" element={<Search />} />
|
|
<Route path="/auth" element={<Auth />} />
|
|
|
|
{/* Detail routes - lazy loaded */}
|
|
<Route path="/parks/:slug" element={<ParkDetail />} />
|
|
<Route path="/parks/:parkSlug/rides" element={<ParkRides />} />
|
|
<Route path="/parks/:parkSlug/rides/:rideSlug" element={<RideDetail />} />
|
|
<Route path="/manufacturers" element={<Manufacturers />} />
|
|
<Route path="/manufacturers/:slug" element={<ManufacturerDetail />} />
|
|
<Route path="/manufacturers/:manufacturerSlug/rides" element={<ManufacturerRides />} />
|
|
<Route path="/manufacturers/:manufacturerSlug/models" element={<ManufacturerModels />} />
|
|
<Route path="/manufacturers/:manufacturerSlug/models/:modelSlug" element={<RideModelDetail />} />
|
|
<Route path="/manufacturers/:manufacturerSlug/models/:modelSlug/rides" element={<RideModelRides />} />
|
|
<Route path="/designers" element={<Designers />} />
|
|
<Route path="/designers/:slug" element={<DesignerDetail />} />
|
|
<Route path="/designers/:designerSlug/rides" element={<DesignerRides />} />
|
|
<Route path="/owners" element={<ParkOwners />} />
|
|
<Route path="/owners/:slug" element={<PropertyOwnerDetail />} />
|
|
<Route path="/owners/:ownerSlug/parks" element={<OwnerParks />} />
|
|
<Route path="/operators" element={<Operators />} />
|
|
<Route path="/operators/:slug" element={<OperatorDetail />} />
|
|
<Route path="/operators/:operatorSlug/parks" element={<OperatorParks />} />
|
|
<Route path="/blog" element={<BlogIndex />} />
|
|
<Route path="/blog/:slug" element={<BlogPost />} />
|
|
<Route path="/terms" element={<Terms />} />
|
|
<Route path="/privacy" element={<Privacy />} />
|
|
<Route path="/submission-guidelines" element={<SubmissionGuidelines />} />
|
|
<Route path="/contact" element={<Contact />} />
|
|
|
|
{/* User routes - lazy loaded */}
|
|
<Route path="/auth/callback" element={<AuthCallback />} />
|
|
<Route path="/profile" element={<Profile />} />
|
|
<Route path="/profile/:username" element={<Profile />} />
|
|
<Route path="/settings" element={<UserSettings />} />
|
|
|
|
{/* Admin routes - lazy loaded */}
|
|
<Route path="/admin" element={<AdminDashboard />} />
|
|
<Route path="/admin/moderation" element={<AdminModeration />} />
|
|
<Route path="/admin/reports" element={<AdminReports />} />
|
|
<Route path="/admin/system-log" element={<AdminSystemLog />} />
|
|
<Route path="/admin/users" element={<AdminUsers />} />
|
|
<Route path="/admin/blog" element={<AdminBlog />} />
|
|
<Route path="/admin/settings" element={<AdminSettings />} />
|
|
<Route path="/admin/contact" element={<AdminContact />} />
|
|
<Route path="/admin/email-settings" element={<AdminEmailSettings />} />
|
|
|
|
{/* Utility routes - lazy loaded */}
|
|
<Route path="/force-logout" element={<ForceLogout />} />
|
|
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
|
|
<Route path="*" element={<NotFound />} />
|
|
</Routes>
|
|
</Suspense>
|
|
</div>
|
|
<Footer />
|
|
</div>
|
|
</BrowserRouter>
|
|
</TooltipProvider>
|
|
);
|
|
}
|
|
|
|
const App = (): React.JSX.Element => (
|
|
<QueryClientProvider client={queryClient}>
|
|
<AuthProvider>
|
|
<AuthModalProvider>
|
|
<AppContent />
|
|
</AuthModalProvider>
|
|
</AuthProvider>
|
|
{import.meta.env.DEV && (
|
|
<>
|
|
<ReactQueryDevtools initialIsOpen={false} position="bottom" />
|
|
<CacheMonitor />
|
|
</>
|
|
)}
|
|
<Analytics />
|
|
</QueryClientProvider>
|
|
);
|
|
|
|
export default App;
|