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