Startlist.jsx (5887B)
1 import { lazy, useEffect, useState } from 'react' 2 import { useParams } from 'react-router-dom' 3 const Auth = lazy(() => import('./Auth')) 4 import { addAthleteToHeat } from './Leaderboard' 5 import Select from 'react-select' 6 7 const api_uri = import.meta.env.VITE_API_URI 8 const api_port = import.meta.env.VITE_API_PORT 9 const locale = import.meta.env.VITE_LOCALE 10 11 async function addtoHeat(e, athlete, heatId, session) { 12 e.preventDefault() 13 try { 14 await addAthleteToHeat(athlete.value, heatId, session) 15 window.location.reload() 16 } catch(error) { 17 console.error(error) 18 } 19 } 20 21 async function removeAthleteFromHeat(e, startlistId, athleteFirstName, athleteLastName, heatName, session) { 22 e.preventDefault() 23 const athleteName = athleteFirstName + (athleteLastName ? ' ' + athleteLastName : '') 24 25 if (window.confirm('Do you really want to remove athlete "' + athleteName + '" from heat "' + heatName + '"?')) { 26 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/removeAthleteFromHeat`, { 27 method: 'POST', 28 headers: { 29 'Content-Type': 'application/json', 30 'Authorization': `Bearer ${session.auth.token}`, 31 }, 32 body: JSON.stringify({ 33 "startlist_id": startlistId, 34 }), 35 }) 36 const { data, error } = await res.json() 37 if (error) { 38 console.error(error) 39 } 40 window.location.reload() 41 } 42 } 43 44 async function startlistWithAthletes(heatId, session) { 45 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/startlistWithAthletes`, { 46 method: 'POST', 47 headers: { 48 'Content-Type': 'application/json', 49 'Authorization': `Bearer ${session.auth.token}`, 50 }, 51 body: JSON.stringify({ 52 "heat_id": heatId, 53 }), 54 }) 55 const { data, error } = await res.json() 56 if (error) { 57 throw error 58 } 59 return data 60 } 61 62 async function getHeat(heatId, session) { 63 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/getHeat`, { 64 method: 'POST', 65 headers: { 66 'Content-Type': 'application/json', 67 'Authorization': `Bearer ${session.auth.token}`, 68 }, 69 body: JSON.stringify({ 70 "heat_id": heatId, 71 }), 72 }) 73 const { data, error } = await res.json() 74 if (error) { 75 throw error 76 } 77 return data 78 } 79 80 function StartlistForm({heatId, session}) { 81 const [loading, setLoading] = useState(false) 82 const [heatName, setheatName] = useState("") 83 const [heatLocation, setheatLocation] = useState("") 84 const [heatStart, setheatStart] = useState("") 85 const [startlist, setStartlist] = useState([]) 86 const [athleteOpts, setAthleteOpts] = useState([]) 87 const [selectedAthlete, setselectedAthlete] = useState({}) 88 89 const dateOptions = { 90 year: "numeric", 91 month: "2-digit", 92 day: "2-digit", 93 } 94 95 useEffect(() => { 96 (async () => { 97 setLoading(true) 98 99 try { 100 const startlist = await startlistWithAthletes(heatId, session) 101 setStartlist(startlist) 102 103 const heat = await getHeat(heatId, session) 104 setheatName(heat.name) 105 setheatLocation(heat.location) 106 setheatStart(heat.planned_start) 107 } catch (error) { 108 console.error(error) 109 } 110 111 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/allAthletes`, { 112 headers: { 113 'Content-Type': 'application/json', 114 'Authorization': `Bearer ${session.auth.token}`, 115 }, 116 }) 117 const { data, error } = await res.json() 118 if (error) { 119 console.error(error) 120 } else { 121 let options = data.map(a => { 122 return { 123 value: a.id, 124 label: a.nr + " " + a.firstname + " " + (a.lastname ? a.lastname : "") 125 } 126 }) 127 setAthleteOpts(options) 128 } 129 setLoading(false) 130 })(); 131 }, [heatId]) 132 133 return ( 134 <div className='StartlistForm'> 135 <button disabled={!loading} className='loading'>↺ loading</button> 136 <h1>Startlist #{heatId} {heatName}</h1> 137 <div className='heatInfo'> 138 <ul> 139 <li><b>Location:</b> {heatLocation ? heatLocation : 'n/a'}</li> 140 <li><b>Planned start:</b> {heatStart ? heatStart : 'n/a'}</li> 141 </ul> 142 </div> 143 <table> 144 <thead> 145 <tr> 146 <th>Start Nr.</th> 147 <th>Firstname</th> 148 <th>Lastname</th> 149 <th>Birthday</th> 150 <th>School</th> 151 <th>Add/Delete</th> 152 </tr> 153 </thead> 154 <tbody> 155 {startlist.map(i => ( 156 <tr key={i.startlist_id}> 157 <td data-title='Start Nr.' className='right'>{i.nr}</td> 158 <td data-title='Firstname'>{i.firstname}</td> 159 <td data-title='Lastname'>{i.lastname}</td> 160 <td data-title='Birthday'>{new Date(i.birthday).toLocaleDateString(locale, dateOptions)}</td> 161 <td data-title='School'>{i.school}</td> 162 <td><button onClick={e => removeAthleteFromHeat( 163 e, 164 i.startlist_id, 165 i.firstname, 166 i.lastname, 167 heatName, 168 session 169 )}>– del</button></td> 170 </tr> 171 ))} 172 <tr className='input'> 173 <td data-title='Athlete' colSpan={5}> 174 <Select 175 options={athleteOpts} 176 onChange={(e) => setselectedAthlete(e)} 177 /> 178 </td> 179 <td> 180 <button onClick={(e) => addtoHeat(e, selectedAthlete, heatId, session)}>+ add</button> 181 </td> 182 </tr> 183 </tbody> 184 </table> 185 </div> 186 ) 187 } 188 189 function Startlist({session}) { 190 const { heatId } = useParams(); 191 192 return ( 193 <div> 194 {!session.auth ? <Auth /> : <StartlistForm heatId={heatId} session={session} />} 195 </div> 196 ) 197 } 198 199 export default Startlist