The primary cause of the white screen in the APK was BrowserRouter. Capacitor serves files via https://localhost/ and the HTML5 History API routing (BrowserRouter) fails to resolve routes in this context, resulting in a blank white page. Changes: - Switch BrowserRouter → HashRouter in AppRouter.tsx - Add DeepLinkHandler component (handles appUrlOpen for Amber callbacks and other deep links in native context) - Fix Amber callback URL builder to use org.skatespots.app:// custom scheme when running in Capacitor (so Android fires an intent back into the app instead of navigating a browser) - Fix getSearchParams() in amber.ts to extract query params from hash fragment (HashRouter URLs look like /#/amber-callback?event=XXX) - Fix captureAmberCallback in main.tsx to check hash fragment too - Remove debug error overlay (no longer needed) Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
130 lines
7.3 KiB
TypeScript
130 lines
7.3 KiB
TypeScript
import { lazy, Suspense } from "react";
|
|
import { HashRouter, Route, Routes } from "react-router-dom";
|
|
import { ScrollToTop } from "./components/ScrollToTop";
|
|
import { DeepLinkHandler } from "./components/DeepLinkHandler";
|
|
|
|
// Eagerly load only the most-visited pages
|
|
import Index from "./pages/Index";
|
|
|
|
// Lazy load everything else — each page becomes its own JS chunk
|
|
const MapPage = lazy(() => import("./pages/MapPage"));
|
|
const EventsPage = lazy(() => import("./pages/EventsPage"));
|
|
const LabPage = lazy(() => import("./pages/LabPage"));
|
|
const WalletPage = lazy(() => import("./pages/WalletPage"));
|
|
const SettingsPage = lazy(() => import("./pages/SettingsPage"));
|
|
const CreateSpotPage = lazy(() => import("./pages/CreateSpotPage"));
|
|
const CreateShopPage = lazy(() => import("./pages/CreateShopPage"));
|
|
const CreateEventPage = lazy(() => import("./pages/CreateEventPage"));
|
|
const CreateListingPage = lazy(() => import("./pages/CreateListingPage"));
|
|
const CreateTourPage = lazy(() => import("./pages/CreateTourPage"));
|
|
const EditSpotPage = lazy(() => import("./pages/EditSpotPage"));
|
|
const EditShopPage = lazy(() => import("./pages/EditShopPage"));
|
|
const EditEventPage = lazy(() => import("./pages/EditEventPage"));
|
|
const GearSwapPage = lazy(() => import("./pages/GearSwapPage"));
|
|
const SpotDetailPage = lazy(() => import("./pages/SpotDetailPage"));
|
|
const ShopDetailPage = lazy(() => import("./pages/ShopDetailPage"));
|
|
const EventDetailPage = lazy(() => import("./pages/EventDetailPage"));
|
|
const OnboardingPage = lazy(() => import("./pages/OnboardingPage"));
|
|
const PyramidPage = lazy(() => import("./pages/PyramidPage"));
|
|
const BecomeCoachPage = lazy(() => import("./pages/BecomeCoachPage"));
|
|
const BecomeFilmerPage = lazy(() => import("./pages/BecomeFilmerPage"));
|
|
const BecomeEditorPage = lazy(() => import("./pages/BecomeEditorPage"));
|
|
const CoachDetailPage = lazy(() => import("./pages/CoachDetailPage"));
|
|
const TourDetailPage = lazy(() => import("./pages/TourDetailPage"));
|
|
const AboutPage = lazy(() => import("./pages/AboutPage"));
|
|
const FAQPage = lazy(() => import("./pages/FAQPage"));
|
|
const FoodPage = lazy(() => import("./pages/FoodPage"));
|
|
const CommunityStatsPage = lazy(() => import("./pages/CommunityStatsPage"));
|
|
const SpotCollectionsPage = lazy(() => import("./pages/SpotCollectionsPage"));
|
|
const CollectionDetailPage = lazy(() => import("./pages/CollectionDetailPage"));
|
|
const DirectMessagesPage = lazy(() => import("./pages/DirectMessagesPage"));
|
|
const ConversationPage = lazy(() => import("./pages/ConversationPage"));
|
|
const BountyLeaderboardPage = lazy(() => import("./pages/BountyLeaderboardPage"));
|
|
const SignersPage = lazy(() => import("./pages/SignersPage"));
|
|
const StashPage = lazy(() => import("./pages/StashPage"));
|
|
const NIP19Page = lazy(() => import("./pages/NIP19Page").then(m => ({ default: m.NIP19Page })));
|
|
const LicensePage = lazy(() => import("./pages/LicensePage"));
|
|
const SupportersPage = lazy(() => import("./pages/SupportersPage"));
|
|
const RiderCardPage = lazy(() => import("./pages/RiderCardPage"));
|
|
const AmberCallbackPage = lazy(() => import("./pages/AmberCallbackPage"));
|
|
const MarketplacePage = lazy(() => import("./pages/MarketplacePage"));
|
|
const NewsletterPage = lazy(() => import("./pages/NewsletterPage"));
|
|
const NotFound = lazy(() => import("./pages/NotFound"));
|
|
|
|
// Minimal inline fallback — no extra component needed
|
|
function PageLoader() {
|
|
return (
|
|
<div className="min-h-screen bg-black flex items-center justify-center">
|
|
<div className="w-8 h-8 border-2 border-[#ff0040] border-t-transparent rounded-full animate-spin" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function AppRouter() {
|
|
return (
|
|
<HashRouter>
|
|
<DeepLinkHandler />
|
|
<ScrollToTop />
|
|
<Suspense fallback={<PageLoader />}>
|
|
<Routes>
|
|
<Route path="/" element={<Index />} />
|
|
<Route path="/map" element={<MapPage />} />
|
|
<Route path="/events" element={<EventsPage />} />
|
|
<Route path="/lab" element={<LabPage />} />
|
|
{/* Legacy route redirect */}
|
|
<Route path="/coaches" element={<LabPage />} />
|
|
<Route path="/become-coach" element={<BecomeCoachPage />} />
|
|
<Route path="/become-filmer" element={<BecomeFilmerPage />} />
|
|
<Route path="/become-editor" element={<BecomeEditorPage />} />
|
|
<Route path="/coach/:pubkey/:identifier" element={<CoachDetailPage />} />
|
|
<Route path="/onboarding" element={<OnboardingPage />} />
|
|
<Route path="/pyramid" element={<PyramidPage />} />
|
|
<Route path="/marketplace" element={<GearSwapPage />} />
|
|
<Route path="/stats" element={<CommunityStatsPage />} />
|
|
<Route path="/about" element={<AboutPage />} />
|
|
<Route path="/faq" element={<FAQPage />} />
|
|
<Route path="/food" element={<FoodPage />} />
|
|
<Route path="/wallet" element={<WalletPage />} />
|
|
<Route path="/settings" element={<SettingsPage />} />
|
|
<Route path="/create-spot" element={<CreateSpotPage />} />
|
|
<Route path="/create-shop" element={<CreateShopPage />} />
|
|
<Route path="/create-event" element={<CreateEventPage />} />
|
|
<Route path="/create-listing" element={<CreateListingPage />} />
|
|
<Route path="/create-tour" element={<CreateTourPage />} />
|
|
<Route path="/edit-spot/:pubkey/:identifier" element={<EditSpotPage />} />
|
|
<Route path="/edit-shop/:pubkey/:identifier" element={<EditShopPage />} />
|
|
<Route path="/edit-event/:pubkey/:identifier" element={<EditEventPage />} />
|
|
<Route path="/spot/:pubkey/:identifier" element={<SpotDetailPage />} />
|
|
<Route path="/shop/:pubkey/:identifier" element={<ShopDetailPage />} />
|
|
<Route path="/event/:pubkey/:identifier" element={<EventDetailPage />} />
|
|
<Route path="/tour/:pubkey/:identifier" element={<TourDetailPage />} />
|
|
<Route path="/collections" element={<SpotCollectionsPage />} />
|
|
<Route path="/collections/:pubkey/:identifier" element={<CollectionDetailPage />} />
|
|
<Route path="/messages" element={<DirectMessagesPage />} />
|
|
<Route path="/messages/:npub" element={<ConversationPage />} />
|
|
{/* Bounty System */}
|
|
<Route path="/bounties" element={<BountyLeaderboardPage />} />
|
|
{/* Security & Signers */}
|
|
<Route path="/signers" element={<SignersPage />} />
|
|
{/* Stash - Private Inventory */}
|
|
<Route path="/stash" element={<StashPage />} />
|
|
{/* Info pages */}
|
|
<Route path="/card" element={<RiderCardPage />} />
|
|
<Route path="/license" element={<LicensePage />} />
|
|
<Route path="/supporters" element={<SupportersPage />} />
|
|
{/* Amber NIP-55 callback — Amber redirects here after signing/login */}
|
|
<Route path="/amber-callback" element={<AmberCallbackPage />} />
|
|
{/* Marketplace */}
|
|
<Route path="/marketplace-listings" element={<MarketplacePage />} />
|
|
{/* Newsletter */}
|
|
<Route path="/newsletter" element={<NewsletterPage />} />
|
|
{/* NIP-19 route for npub1, note1, naddr1, nevent1, nprofile1 */}
|
|
<Route path="/:nip19" element={<NIP19Page />} />
|
|
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
|
|
<Route path="*" element={<NotFound />} />
|
|
</Routes>
|
|
</Suspense>
|
|
</HashRouter>
|
|
);
|
|
}
|
|
export default AppRouter;
|