myheats

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

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               )}>&ndash; 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)}>&#43; 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