myheats

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

Startlist.js (4448B)


      1 import { lazy, useEffect, useState } from 'react'
      2 import { useParams } from 'react-router-dom'
      3 import Select from 'react-select'
      4 import { supabase } from './supabaseClient'
      5 
      6 const Auth = lazy(() => import('./Auth'))
      7 
      8 async function addAthleteToHeat(e, selectedAthlete, heatId) {
      9   e.preventDefault()
     10 
     11   const { error } = await supabase.from('startlist').upsert({
     12     athlete: selectedAthlete.value,
     13     heat: heatId
     14   })
     15 
     16   if (error === null)
     17     window.location.reload()
     18 }
     19 
     20 async function removeAthleteFromHeat(e, startlistId, athleteFirstName, athleteLastName, heatName) {
     21   e.preventDefault()
     22   const athleteName = athleteFirstName + (athleteLastName ? ' ' + athleteLastName : '')
     23 
     24   if (window.confirm('Do you really want to remove athlete "' + athleteName + '" from heat "' + heatName + '"?')) {
     25     await supabase
     26       .from('startlist')
     27       .delete()
     28       .eq('id', startlistId)
     29     window.location.reload()
     30   }
     31 }
     32 
     33 function StartlistForm({heatId}) {
     34   const [heatName, setheatName] = useState("")
     35   const [heatLocation, setheatLocation] = useState("")
     36   const [heatStart, setheatStart] = useState("")
     37   const [startlist, setStartlist] = useState([])
     38   const [athleteOpts, setAthleteOpts] = useState([])
     39   const [selectedAthlete, setselectedAthlete] = useState({})
     40 
     41   const [loading, setLoading] = useState(false)
     42 
     43   useEffect(() => {
     44     (async () => {
     45       setLoading(true)
     46 
     47       const startlistData = await supabase
     48         .from('startlist')
     49         .select(`
     50           id,
     51           heat,
     52           athlete (
     53             id,
     54             nr,
     55             firstname,
     56             lastname,
     57             birthday,
     58             school
     59           )
     60         `)
     61       .eq('heat', heatId)
     62 
     63       if (startlistData.error === null)
     64         setStartlist(startlistData.data)
     65 
     66       const heatData = await supabase
     67         .from('heats')
     68         .select('name, location, planned_start')
     69         .eq('id', heatId)
     70         .single()
     71 
     72       if (heatData.error === null) {
     73         setheatName(heatData.data.name)
     74         setheatLocation(heatData.data.location)
     75         setheatStart(heatData.data.planned_start)
     76       }
     77 
     78       const athleteList = await supabase.from('athletes').select()
     79       if (athleteList.error === null) {
     80         let options = athleteList.data.map(a => {
     81           return {
     82             value: a.id,
     83             label: a.nr + " " + a.firstname + " " + (a.lastname ? a.lastname : "")
     84           }
     85         })
     86         setAthleteOpts(options)
     87       }
     88 
     89       setLoading(false)
     90     })();
     91   }, [heatId])
     92 
     93   return (
     94     <div>
     95       <h1>Startlist #{heatId} {heatName} <button disabled={!loading}>{loading ? '🔄 loading' : ''}</button></h1>
     96       <div className='heatInfo'>
     97         <ul>
     98           <li><b>Location:</b>&emsp;&emsp;&emsp;{heatLocation ? heatLocation : 'n/a'}</li>
     99           <li><b>Planned start:</b>&emsp;{heatStart ? heatStart : 'n/a'}</li>
    100         </ul>
    101       </div>
    102       <table>
    103         <thead>
    104           <tr>
    105             <th>Nr</th>
    106             <th>Firstname</th>
    107             <th>Lastname</th>
    108             <th>Birthday</th>
    109             <th>School</th>
    110             <th>Add/remove</th>
    111           </tr>
    112         </thead>
    113         <tbody>
    114         {startlist.map(i => (
    115             <tr key={i.id}>
    116               <td className='right'>{i.athlete.nr}</td>
    117               <td>{i.athlete.firstname}</td>
    118               <td>{i.athlete.lastname}</td>
    119               <td className='right'>{i.athlete.birthday}</td>
    120               <td>{i.athlete.school}</td>
    121               <td className='right'><button onClick={e => removeAthleteFromHeat(
    122                 e,
    123                 i.id,
    124                 i.athlete.firstname,
    125                 i.athlete.lastname,
    126                 heatName
    127               )}>🗑️ remove</button></td>
    128             </tr>
    129           ))}
    130           <tr>
    131             <td></td>
    132             <td colSpan={2}>
    133               <Select
    134                 options={athleteOpts}
    135                 onChange={(e) => setselectedAthlete(e)}
    136               />
    137             </td>
    138             <td colSpan={2}></td>
    139             <td className='right'>
    140               <button onClick={(e) => addAthleteToHeat(e, selectedAthlete, heatId)}>➕ add</button>
    141             </td>
    142           </tr>
    143         </tbody>
    144       </table>
    145     </div>
    146   )
    147 }
    148 
    149 function Startlist({session}) {
    150     const { heatId } = useParams();
    151 
    152     return (
    153       <div>
    154         {!session ? <Auth /> : <StartlistForm heatId={heatId} />}
    155       </div>
    156     )
    157   }
    158   
    159 export default Startlist