Athletes.jsx (5295B)
1 import { lazy, useEffect, useState } from 'react' 2 import { exportAthletesToCSV } from './utils' 3 const Auth = lazy(() => import('./Auth')) 4 5 const api_uri = import.meta.env.VITE_API_URI 6 const api_port = import.meta.env.VITE_API_PORT 7 const locale = import.meta.env.VITE_LOCALE 8 9 async function addAthlete(e, session) { 10 e.preventDefault() 11 12 // Read the form data 13 const formData = new FormData(e.target); 14 const formJson = Object.fromEntries(formData.entries()); 15 16 // create new athlete 17 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/addAthlete`, { 18 method: 'POST', 19 headers: { 20 'Content-Type': 'application/json', 21 'Authorization': `Bearer ${session.auth.token}`, 22 }, 23 body: JSON.stringify({ 24 "nr": formJson.nr, 25 "firstname": formJson.firstname, 26 "lastname": formJson.lastname, 27 "birthday": formJson.birthday ? formJson.birthday : null, 28 "school": formJson.school 29 }), 30 }) 31 const { data, error } = await res.json() 32 if (error) { 33 alert('Failed to create new athlete: ' + error.message) 34 } 35 window.location.reload() 36 } 37 38 async function deleteAthlete(e, athleteId, athleteFirstName, athleteLastName, session) { 39 e.preventDefault() 40 41 const athleteName = athleteFirstName + (athleteLastName ? ' ' + athleteLastName : '') 42 if (window.confirm('Do you really want to delete athlete "' + athleteName + '"?')) { 43 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/removeAthlete`, { 44 method: 'POST', 45 headers: { 46 'Content-Type': 'application/json', 47 'Authorization': `Bearer ${session.auth.token}`, 48 }, 49 body: JSON.stringify({ 50 "athlete_id": athleteId, 51 }), 52 }) 53 const { data, error } = await res.json() 54 if (error) { 55 alert('Failed to delete athlete: ' + error.message) 56 } 57 window.location.reload() 58 } 59 } 60 61 // export athletes 62 function ExportForm(athletes) { 63 return ( 64 <div className='exportForm'> 65 <form method='post' onSubmit={e => exportAthletesToCSV(e, athletes)}> 66 <button type='submit'>▿ export</button> 67 </form> 68 </div> 69 ) 70 } 71 72 function AthleteForm({session}) { 73 const [loading, setLoading] = useState(false) 74 const [athletes, setAthletes] = useState([]) 75 const dateOptions = { 76 year: "numeric", 77 month: "2-digit", 78 day: "2-digit", 79 } 80 81 useEffect(() => { 82 (async () => { 83 setLoading(true) 84 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/allAthletes`, { 85 headers: { 86 'Content-Type': 'application/json', 87 'Authorization': `Bearer ${session.auth.token}`, 88 } 89 }) 90 const { data, error } = await res.json() 91 if (error) { 92 console.log(error) 93 } else { 94 setAthletes(data) 95 } 96 setLoading(false) 97 })(); 98 }, []) 99 100 return ( 101 <div className='AthleteForm'> 102 <button disabled={!loading} className='loading'>↺ loading</button> 103 <form method='post' onSubmit={e => addAthlete(e, session)}> 104 <table> 105 <thead> 106 <tr> 107 <th>Created at</th> 108 <th className="right">Start Nr. *</th> 109 <th>Firstname *</th> 110 <th>Lastname</th> 111 <th>Birthday</th> 112 <th>School</th> 113 <th>New/delete</th> 114 </tr> 115 </thead> 116 <tbody> 117 {athletes.map(a => ( 118 <tr key={a.id}> 119 <td data-title='Created at' className='right'>{new Date(a.created_at).toLocaleDateString(locale, dateOptions)}</td> 120 <td data-title='Start Nr.' className='right'>{a.nr}</td> 121 <td data-title='Firstname'>{a.firstname}</td> 122 <td data-title='Lastname'>{a.lastname}</td> 123 <td data-title='Birthday'>{a.birthday ? new Date(a.birthday).toLocaleDateString(locale, dateOptions) : ''}</td> 124 <td data-title='School'>{a.school}</td> 125 <td><button onClick={e => deleteAthlete(e, a.id, a.firstname, a.lastname, session)}>– del</button></td> 126 </tr> 127 ))} 128 <tr className='input'> 129 <td className='right'><i>* required</i></td> 130 <td data-title='Start Nr. *' className='right'> 131 <input type='number' name='nr' /> 132 </td> 133 <td data-title='Firstname *'> 134 <input type='text' name='firstname' /> 135 </td> 136 <td data-title='Lastname'> 137 <input type='text' name='lastname' /> 138 </td> 139 <td data-title='Birthday' className='right'> 140 <input 141 type='date' 142 name='birthday' /> 143 </td> 144 <td data-title='School'> 145 <input type='text' name='school' /> 146 </td> 147 <td> 148 <button type='submit'>+ new</button> 149 </td> 150 </tr> 151 </tbody> 152 </table> 153 </form> 154 <ExportForm athletes={athletes} /> 155 </div> 156 ) 157 } 158 159 function Athletes({session}) { 160 return ( 161 <div> 162 {!session.auth ? <Auth /> : <AthleteForm session={session} />} 163 </div> 164 ) 165 } 166 167 export default Athletes