import { createRoot } from 'react-dom/client'; // Import polyfills first import './lib/polyfills.ts'; import { ErrorBoundary } from '@/components/ErrorBoundary'; import App from './App.tsx'; import './index.css'; // Hide Capacitor splash screen once JS is ready // Uses the global Capacitor object to avoid a hard dependency on the package if (typeof window !== 'undefined') { const cap = (window as unknown as { Capacitor?: { Plugins?: { SplashScreen?: { hide: () => Promise } } } }).Capacitor; if (cap?.Plugins?.SplashScreen) { cap.Plugins.SplashScreen.hide().catch(() => {}); } } // Outfit font for body text import '@fontsource-variable/outfit'; // Bebas Neue — bold condensed display font for headlines import '@fontsource/bebas-neue'; // Barlow Condensed — tight condensed font for subheadings and UI labels import '@fontsource/barlow-condensed/400.css'; import '@fontsource/barlow-condensed/600.css'; import '@fontsource/barlow-condensed/700.css'; // Leaflet CSS is loaded via CDN in index.html /** * AMBER CALLBACK PRE-CHECK + REDIRECT * * Amber opens the callbackUrl in a browser tab. Because we use HashRouter, * the callbackUrl has no # fragment — it's a plain path: * https://skate-spots.org/amber-callback?event= * * This IIFE runs before React mounts and: * 1. Captures ?event= from the URL into sessionStorage * 2. If we're on /amber-callback (non-hash path), redirects to /#/amber-callback * so HashRouter can match the route and render AmberCallbackPage */ (function captureAmberCallback() { // Try normal query string first (Amber callback: /amber-callback?event=XXX) let eventParam = new URLSearchParams(window.location.search).get('event'); // Try hash fragment (Capacitor deep link: #/amber-callback?event=XXX) if (!eventParam) { const hash = window.location.hash; const qIdx = hash.indexOf('?'); if (qIdx !== -1) { eventParam = new URLSearchParams(hash.slice(qIdx)).get('event'); } } if (eventParam) { console.log('[Amber Pre-Check] Detected Amber callback, event:', eventParam.substring(0, 16) + '...'); try { sessionStorage.setItem('amber_callback_event', eventParam); sessionStorage.setItem('amber_callback_url', window.location.href); sessionStorage.setItem('amber_callback_timestamp', Date.now().toString()); } catch (e) { console.error('[Amber Pre-Check] Failed to store callback:', e); } // If we landed on /amber-callback (non-hash path), redirect into HashRouter // so React Router can match the route and render AmberCallbackPage. // The event is already saved in sessionStorage above so it survives the redirect. const isHashRoute = window.location.hash.startsWith('#/'); if (!isHashRoute && window.location.pathname.includes('amber-callback')) { console.log('[Amber Pre-Check] Redirecting to HashRouter route: /#/amber-callback'); window.location.replace(window.location.origin + '/#/amber-callback'); // Stop — the page will reload at the correct hash route return; } } })(); createRoot(document.getElementById("root")!).render( ); // Tell the boot crash guard (in index.html) that the app mounted successfully, // so its "did not render" timeout doesn't fire. try { (window as unknown as { __SKATESPOTS_BOOTED__?: () => void }).__SKATESPOTS_BOOTED__?.(); } catch { /* no-op */ }