Judges.jsx (4373B)
1 import { lazy, useEffect, useState } from 'react' 2 import { exportJudgesToCSV } 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 addJudge(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 judge 17 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/addJudge`, { 18 method: 'POST', 19 headers: { 20 'Content-Type': 'application/json', 21 'Authorization': `Bearer ${session.auth.token}`, 22 }, 23 body: JSON.stringify({ 24 "email": formJson.email, 25 "firstname": formJson.firstname, 26 "lastname": formJson.lastname 27 }), 28 }) 29 const { data, error } = await res.json() 30 if (error) { 31 alert('Failed to create new judge: ' + error.message) 32 } 33 window.location.reload() 34 } 35 36 async function deleteJudge(e, judgeId, email, session) { 37 e.preventDefault() 38 39 if (window.confirm(`Do you really want to delete judge ${email}?`)) { 40 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/removeJudge`, { 41 method: 'POST', 42 headers: { 43 'Content-Type': 'application/json', 44 'Authorization': `Bearer ${session.auth.token}`, 45 }, 46 body: JSON.stringify({ 47 "judge_id": judgeId, 48 }), 49 }) 50 const { data, error } = await res.json() 51 if (error) { 52 alert('Failed to delete judge: ' + error.message) 53 } 54 window.location.reload() 55 } 56 } 57 58 // export judges 59 function ExportForm(judges) { 60 return ( 61 <div className='exportForm'> 62 <form method='post' onSubmit={e => exportJudgesToCSV(e, judges)}> 63 <button type='submit'>▿ export</button> 64 </form> 65 </div> 66 ) 67 } 68 69 function JudgeForm({session}) { 70 const [loading, setLoading] = useState(false) 71 const [judges, setJudges] = useState([]) 72 const dateOptions = { 73 year: "numeric", 74 month: "2-digit", 75 day: "2-digit", 76 } 77 78 useEffect(() => { 79 (async () => { 80 setLoading(true) 81 const res = await fetch(`${api_uri}:${api_port}/v1/leaderboard/allJudges`, { 82 headers: { 83 'Content-Type': 'application/json', 84 'Authorization': `Bearer ${session.auth.token}`, 85 } 86 }) 87 const { data, error } = await res.json() 88 if (error) { 89 console.log(error) 90 } else { 91 setJudges(data) 92 } 93 setLoading(false) 94 })(); 95 }, []) 96 97 return ( 98 <div className='JudgeForm'> 99 <button disabled={!loading} className='loading'>↺ loading</button> 100 <form method='post' onSubmit={e => addJudge(e, session)}> 101 <table> 102 <thead> 103 <tr> 104 <th>Created at</th> 105 <th>Email *</th> 106 <th>Firstname</th> 107 <th>Lastname</th> 108 </tr> 109 </thead> 110 <tbody> 111 {judges.map(j => ( 112 <tr key={j.id}> 113 <td data-title='Created at' className='right'>{new Date(j.created_at).toLocaleDateString(locale, dateOptions)}</td> 114 <td data-title='Email'>{j.email}</td> 115 <td data-title='Firstname'>{j.firstname}</td> 116 <td data-title='Lastname'>{j.lastname}</td> 117 <td><button onClick={e => deleteJudge(e, j.id, j.email, session)}>– del</button></td> 118 </tr> 119 ))} 120 <tr className='input'> 121 <td className='right'><i>* required</i></td> 122 <td data-title='Email *'> 123 <input type='text' name='email' /> 124 </td> 125 <td data-title='Firstname'> 126 <input type='text' name='firstname' /> 127 </td> 128 <td data-title='Lastname'> 129 <input type='text' name='lastname' /> 130 </td> 131 <td> 132 <button type='submit'>+ new</button> 133 </td> 134 </tr> 135 </tbody> 136 </table> 137 </form> 138 <ExportForm judges={judges} /> 139 </div> 140 ) 141 } 142 143 function Judges({session}) { 144 return ( 145 <div> 146 {!session.auth ? <Auth /> : <JudgeForm session={session} />} 147 </div> 148 ) 149 } 150 151 export default Judges