App.jsx (5312B)
1 import { Suspense, lazy, useState, useEffect, Fragment } from 'react' 2 import { BrowserRouter as Router, Routes, Route, Outlet, Link, NavLink } from 'react-router-dom' 3 import { CookiesProvider, useCookies } from 'react-cookie' 4 5 import './css/App.css' 6 import './css/blue.css' 7 import './css/red.css' 8 import './css/yellow.css' 9 10 const Score = lazy(() => import('./Score')) 11 const Heats = lazy(() => import('./Heats')) 12 const Athletes = lazy(() => import('./Athletes')) 13 const Startlist = lazy(() => import('./Startlist')) 14 const Auth = lazy(() => import('./Auth')) 15 const AuthVerify = lazy(() => import('./AuthVerify')) 16 const Leaderboard = lazy(() => import('./Leaderboard')) 17 const Settings = lazy(() => import('./Settings')) 18 19 const api_uri = import.meta.env.VITE_API_URI 20 const api_port = import.meta.env.VITE_API_PORT 21 22 document.title = import.meta.env.VITE_APP_DOC_TITLE ? import.meta.env.VITE_APP_DOC_TITLE : 'My Heats' 23 24 function Layout() { 25 const [session, setSession, destroySession] = useCookies(['auth']) 26 const [settings, setSettings] = useState(new Map()) 27 28 // load stylesheet based on settings 29 const colors = ['red', 'blue', 'yellow']; 30 let theme = "" 31 let showLogo = "true" 32 let logoUrl = "/logo192.png" 33 let showVersion = "true" 34 35 if (settings.style && colors.includes(settings.style)) { 36 theme = settings.style 37 //console.info(`I see ${settings.style}. Try one of "style=${colors}" in ${window.location.origin}/settings`) 38 } 39 if (settings.showLogo) { 40 showLogo = settings.showLogo 41 } 42 if (settings.logoUrl) { 43 logoUrl = settings.logoUrl 44 } 45 if (settings.showVersion) { 46 showVersion = settings.showVersion 47 } 48 49 useEffect(() => { 50 (async () => { 51 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/allSettings`) 52 if (res.status !== 204) { 53 const { data, error } = await res.json() 54 if (error) { 55 console.error(error) 56 } else { 57 let s = new Map() 58 data.forEach(setting => { 59 s[setting.name] = setting.value 60 }) 61 setSettings(s) 62 } 63 } 64 })(); 65 }, []) 66 67 return ( 68 <Fragment> 69 <nav className={theme}> 70 <ul> 71 <li> 72 <NavLink 73 className={({ isActive, isPending }) => isPending ? "pending" : isActive ? `active ${theme}.active` : ""} 74 to="/"> 75 Leaderboard 76 </NavLink> 77 </li> 78 {session.auth ? <li> 79 <NavLink 80 className={({ isActive, isPending }) => isPending ? "pending" : isActive ? `active ${theme}.active}` : ""} 81 to="/score"> 82 Scoring 83 </NavLink> 84 </li> : ''} 85 {session.auth ? <li> 86 <NavLink 87 className={({ isActive, isPending }) => isPending ? "pending" : isActive ? `active ${theme}.active}` : ""} 88 to="/heats"> 89 Heats and Startlists 90 </NavLink> 91 </li> : ''} 92 {session.auth ? <li> 93 <NavLink 94 className={({ isActive, isPending }) => isPending ? "pending" : isActive ? `active ${theme}.active}` : ""} 95 to="/athletes"> 96 Athletes 97 </NavLink> 98 </li> : ''} 99 </ul> 100 </nav> 101 <main> 102 <Outlet /> 103 </main> 104 <footer> 105 <br /> 106 {showVersion === 'true' ? 107 <span>MyHeats <a href="https://code.in0rdr.ch/myheats/refs.html">v0.6-nightly</a></span> : '' } 108 {showLogo === 'true' ? 109 <span className="logo"><img src={logoUrl} alt="Logo" /></span> : '' } 110 <span> 111 {session.auth ? <button 112 onClick={() => location.href="/settings"}> 113 ⚙ 114 </button> : ''} 115 </span> 116 <span> 117 {session.auth ? <button onClick={() => destroySession('auth')}>➭</button> : 118 <NavLink 119 className={({ isActive, isPending }) => isPending ? "pending" : isActive ? "active" : ""} 120 to="/auth"> 121 Login 122 </NavLink> 123 } 124 </span> 125 </footer> 126 </Fragment> 127 ) 128 } 129 130 function NoMatch() { 131 return ( 132 <div className="NoMatch"> 133 Nothing to see here, <Link to="/">go to leaderboard</Link> 134 </div> 135 ) 136 } 137 138 function App() { 139 const [session] = useCookies(['auth']) 140 141 return ( 142 <Fragment> 143 <Router> 144 <Suspense fallback={<div>Loading...</div>}> 145 <Routes> 146 <Route path="/" element={<Layout session={session} />}> 147 <Route path="/" element={<Leaderboard session={session} />} /> 148 <Route path="/score" element={<Score session={session} />} /> 149 <Route path="/heats" element={<Heats session={session} />} /> 150 <Route path="/athletes" element={<Athletes session={session} />} /> 151 <Route path="/startlist/:heatId" element={<Startlist session={session} />} /> 152 <Route path="/auth" element={<Auth />} /> 153 <Route path="/authverify" element={<AuthVerify />} /> 154 <Route path="/settings" element={<Settings session={session} />} /> 155 <Route path="*" element={<NoMatch />} /> 156 </Route> 157 </Routes> 158 </Suspense> 159 </Router> 160 </Fragment> 161 ); 162 } 163 164 export default App;