myheats

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

Heats.js (3780B)


      1 import { lazy, useEffect, useState } from 'react'
      2 import { useNavigate, generatePath } from 'react-router-dom'
      3 import { supabase } from './supabaseClient'
      4 
      5 const Auth = lazy(() => import('./Auth'))
      6 
      7 async function addHeat(e) {
      8   e.preventDefault()
      9 
     10   // Read the form data
     11   const formData = new FormData(e.target);
     12   const formJson = Object.fromEntries(formData.entries());
     13 
     14   if (defaultsSet(formJson)) {
     15     alert('Check data of the new heat, seems like the defaults')
     16     return
     17   }
     18 
     19   // create new heat
     20   const { error } = await supabase
     21     .from('heats')
     22     .insert({
     23       name: formJson.name,
     24       location: formJson.location,
     25       // planned_start is an empty string if unset
     26       // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/time
     27       planned_start: formJson.planned_start === '' ? null : formJson.planned_start
     28   })
     29 
     30   if (error === null) {
     31     window.location.reload()
     32   } else {
     33     alert('Failed to create new heat: ' + error.message)
     34   }
     35 }
     36 
     37 export function defaultsSet({name, location}) {
     38   return (name === 'Name' || location === 'Location')
     39 }
     40 
     41 function navigateToHeat(e, n, heatId) {
     42   e.preventDefault()
     43   n(generatePath('/startlist/:heatId', {heatId:heatId}))
     44 }
     45 
     46 async function deleteHeat(e, heatId, heatName) {
     47   e.preventDefault()
     48 
     49   if (window.confirm('Do you really want to delete heat "' + heatName + '"?')) {
     50     await supabase
     51       .from('heats')
     52       .delete()
     53       .eq('id', heatId)
     54     window.location.reload()
     55   }
     56 }
     57 
     58 function HeatForm({session}) {
     59   const [loading, setLoading] = useState(false)
     60   const [heats, setHeats] = useState([])
     61 
     62   const navigate = useNavigate()
     63 
     64   useEffect(() => {
     65     (async () => {
     66       setLoading(true)
     67       const heatList = await supabase.from('heats').select()
     68       if (heatList.error === null)
     69         setHeats(heatList.data)
     70       setLoading(false)
     71     })();
     72   }, [])
     73 
     74   return (
     75     <div>
     76       <h1>Heats and Startlists <button disabled={!loading}>{loading ? '🔄 loading' : ''}</button></h1>
     77       <form method='post' onSubmit={addHeat}>
     78         <table>
     79           <thead>
     80             <tr>
     81               <th>Created at</th>
     82               <th>Name</th>
     83               <th>Location</th>
     84               <th>Planned start</th>
     85               <th>Startlist</th>
     86               <th>New/delete</th>
     87             </tr>
     88           </thead>
     89           <tbody>
     90             {heats.map(h => (
     91               <tr key={h.id}>
     92                 <td className='right'>{new Date(h.created_at).toLocaleString()}</td>
     93                 <td>{h.name}</td>
     94                 <td>{h.location}</td>
     95                 <td className='right'>{h.planned_start}</td>
     96                 <td className='right'>
     97                   <button onClick={e => navigateToHeat(e, navigate, h.id)}>🏁 startlist</button>
     98                   </td>
     99                 <td className='right'><button onClick={e => deleteHeat(e, h.id, h.name)}>🗑️ delete</button></td>
    100               </tr>
    101             ))}
    102             <tr>
    103               <td className='right'><i>* required</i></td>
    104               <td>
    105                 <input type='text' name='name' defaultValue='Name' /> *
    106               </td>
    107               <td>
    108                 <input type='text' name='location' defaultValue='Location' />
    109               </td>
    110               <td className='right'>
    111                 <input
    112                   type='time'
    113                   name='planned_start' />
    114               </td>
    115               <td></td>
    116               <td className='right'>
    117                 <button type='submit'>➕ new</button>
    118               </td>
    119             </tr>
    120           </tbody>
    121         </table>
    122       </form>
    123     </div>
    124   )
    125 }
    126 
    127 function Heats({session}) {
    128     return (
    129       <div>
    130         {!session ? <Auth /> : <HeatForm session={session} />}
    131       </div>
    132     )
    133   }
    134   
    135 export default Heats;