App.jsx (3621B)
1 import './App.css' 2 import { Suspense, lazy, useState, useEffect, Fragment } from 'react' 3 import { BrowserRouter as Router, Routes, Route, Outlet, Link, NavLink } from 'react-router-dom' 4 import { supabase } from './supabaseClient' 5 6 7 const Score = lazy(() => import('./Score')) 8 const Heats = lazy(() => import('./Heats')) 9 const Athletes = lazy(() => import('./Athletes')) 10 const Startlist = lazy(() => import('./Startlist')) 11 const Auth = lazy(() => import('./Auth')) 12 const Leaderboard = lazy(() => import('./Leaderboard')) 13 14 document.title = import.meta.env.VITE_APP_DOC_TITLE ? import.meta.env.VITE_APP_DOC_TITLE : 'My Heats' 15 16 function Layout({session}) { 17 return ( 18 <Fragment> 19 <nav> 20 <ul> 21 <li> 22 <NavLink 23 className={({ isActive, isPending }) => isPending ? "pending" : isActive ? "active" : ""} 24 to="/"> 25 Leaderboard 26 </NavLink> 27 </li> 28 {session ? <li> 29 <NavLink 30 className={({ isActive, isPending }) => isPending ? "pending" : isActive ? "active" : ""} 31 to="/score"> 32 Scoring 33 </NavLink> 34 </li> : ''} 35 {session ? <li> 36 <NavLink 37 className={({ isActive, isPending }) => isPending ? "pending" : isActive ? "active" : ""} 38 to="/heats"> 39 Heats and Startlists 40 </NavLink> 41 </li> : ''} 42 {session ? <li> 43 <NavLink 44 className={({ isActive, isPending }) => isPending ? "pending" : isActive ? "active" : ""} 45 to="/athletes"> 46 Athletes 47 </NavLink> 48 </li> : ''} 49 </ul> 50 </nav> 51 <main> 52 <Outlet /> 53 </main> 54 <footer> 55 <br /> 56 <span className='version'>MyHeats <a href="https://code.in0rdr.ch/myheats/refs.html">v0.5-nightly</a></span> 57 <span className='login'> 58 {session ? <button onClick={() => supabase.auth.signOut()}> Sign out {session.user.email} </button> : 59 <NavLink 60 className={({ isActive, isPending }) => isPending ? "pending" : isActive ? "active" : ""} 61 to="/auth"> 62 Login 63 </NavLink> 64 } 65 </span> 66 </footer> 67 </Fragment> 68 ) 69 } 70 71 function NoMatch() { 72 return ( 73 <div className="NoMatch"> 74 Nothing to see here, <Link to="/">go to leaderboard</Link> 75 </div> 76 ) 77 } 78 79 function App() { 80 const [session, setSession] = useState(null) 81 82 useEffect(() => { 83 // Returns the session, refreshing it if necessary 84 supabase.auth.getSession().then(({ data: { session } }) => { 85 setSession(session) 86 }) 87 88 supabase.auth.onAuthStateChange((_event, session) => { 89 setSession(session) 90 }) 91 }, []) 92 93 return ( 94 <Fragment> 95 <Router> 96 <Suspense fallback={<div>Loading...</div>}> 97 <Routes> 98 <Route path="/" element={<Layout session={session} />}> 99 <Route path="/" element={<Leaderboard session={session} />} /> 100 <Route path="/score" element={<Score session={session} />} /> 101 <Route path="/heats" element={<Heats session={session} />} /> 102 <Route path="/athletes" element={<Athletes session={session} />} /> 103 <Route path="/startlist/:heatId" element={<Startlist session={session} />} /> 104 <Route path="/auth" element={<Auth />} /> 105 <Route path="*" element={<NoMatch />} /> 106 </Route> 107 </Routes> 108 </Suspense> 109 </Router> 110 </Fragment> 111 ); 112 } 113 114 export default App;