myheats

Live heats, scoring and leaderboard for sport events
git clone https://git.in0rdr.ch/myheats.git
Log | Files | Refs | Pull requests | README | LICENSE

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;