myheats

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

Heats.jsx (3617B)


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