Prefill team name on FIRST page

This commit is contained in:
Caleb Denio 2022-11-10 12:15:15 -05:00 committed by Ella
parent b11e3f1fba
commit c0a888fd07
4 changed files with 145 additions and 47 deletions

View file

@ -1,14 +1,20 @@
import { Box, Input, Label, Button, Select, Text } from 'theme-ui'
import { useState } from 'react'
import { useEffect, useRef, useState } from 'react'
import theme from '@hackclub/theme'
import Icon from '../../icon'
import { keyframes } from '@emotion/react'
import debounce from 'lodash/debounce'
const hideAnimation = keyframes({
from: { display: 'flex' },
to: { display: 'none', opacity: 0, padding: 0, position: 'absolute' }
})
const spinAnimation = keyframes({
from: { transform: 'rotate(0deg)' },
to: { transform: 'rotate(360deg)' }
})
function Base({ children, action, target, method, onSubmit, id }) {
return (
<Box
@ -32,25 +38,43 @@ function Field({
type,
value,
onChange,
required = true
required = true,
loading = false
}) {
return (
<Box sx={{ my: 2 }}>
<Label htmlFor={name} sx={{ color: 'muted', fontSize: 18 }}>
{label}
</Label>
<Input
id={name}
placeholder={placeholder}
name={name}
type={type}
sx={{
bg: 'dark'
}}
onChange={onChange}
value={value}
required={required}
/>
<Box sx={{ position: 'relative' }}>
{loading && (
<Box
sx={{
position: 'absolute',
top: 10,
right: 10,
width: 20,
height: 20,
border: '1px solid white',
borderRightStyle: 'none',
animation: `${spinAnimation} 1s linear infinite`,
borderRadius: '50%'
}}
></Box>
)}
<Input
id={name}
placeholder={placeholder}
name={name}
type={type}
sx={{
bg: 'dark'
}}
onChange={onChange}
value={value}
required={required}
/>
</Box>
</Box>
)
}
@ -58,34 +82,60 @@ function Field({
export default function Signup() {
const [submitted, setSubmitted] = useState(false)
const [values, setValues] = useState({
locationState: '',
locationCountry: '',
teamName: '',
teamType: '',
teamNumber: '',
userEmail: ''
})
const [eventName, setEventName] = useState('')
const [teamType, setTeamType] = useState('')
const [teamNumber, setTeamNumber] = useState('')
const [userEmail, setUserEmail] = useState('')
const [teamNameLoading, setTeamNameLoading] = useState(false)
const debouncedTeamNameUpdate = useRef(
debounce(async teamNumber => {
try {
const data = await fetch(
`/api/first-team?teamNumber=${teamNumber}`
).then(res => res.json())
setTeamNameLoading(false)
if (data.ok !== false) {
setEventName(data.nickname)
} else {
setEventName('')
}
} catch (e) {}
}, 200)
)
useEffect(() => {
if (teamNumber && teamType === 'FRC') {
setTeamNameLoading(true)
debouncedTeamNameUpdate.current(teamNumber)
} else {
setEventName('')
}
}, [teamType, teamNumber])
const handleSubmit = async e => {
e.preventDefault()
await fetch('/api/bank/demo', {
method: 'POST',
body: JSON.stringify(values)
body: JSON.stringify({
eventName,
teamType,
teamNumber,
userEmail
})
})
setSubmitted(true)
// clear form
setValues({
locationState: '',
locationCountry: '',
eventName: '',
teamType: '',
teamNumber: '',
userEmail: ''
})
setEventName('')
setTeamType('')
setTeamNumber('')
setUserEmail('')
}
return (
@ -96,13 +146,6 @@ export default function Signup() {
action="/api/bank/demo"
onSubmit={handleSubmit}
>
<Field
label="Team Name"
name="eventName"
placeholder="Poseidon Robotics"
value={values.eventName}
onChange={e => setValues({ ...values, eventName: e.target.value })}
/>
<Box sx={{ display: 'flex', flexDirection: 'row', gap: 2, w: '100%' }}>
<Box sx={{ my: 2 }}>
<Label htmlFor="teamType" sx={{ color: 'muted', fontSize: 18 }}>
@ -111,11 +154,9 @@ export default function Signup() {
name="teamType"
defaultValue="Select"
sx={{ bg: 'dark' }}
onChange={e =>
setValues({ ...values, teamType: e.target.value })
}
onChange={e => setTeamType(e.target.value)}
>
<option value="Select" selected disabled>
<option value="Select" disabled>
Select
</option>
<option value="FLL">FLL</option>
@ -129,18 +170,26 @@ export default function Signup() {
label="Team number (optional)"
name="teamNumber"
placeholder="12345"
value={values.teamNumber}
onChange={e => setValues({ ...values, teamNumber: e.target.value })}
value={teamNumber}
loading={teamNameLoading}
onChange={e => setTeamNumber(e.target.value)}
required={false}
/>
</Box>
<Field
label="Team name"
name="eventName"
placeholder="Poseidon Robotics"
value={eventName}
onChange={e => setEventName(e.target.value)}
/>
<Field
label="Email address"
name="userEmail"
placeholder="fiona@hackclub.com"
type="email"
value={values.userEmail}
onChange={e => setValues({ ...values, userEmail: e.target.value })}
value={userEmail}
onChange={e => setUserEmail(e.target.value)}
/>
<Button
sx={{

View file

@ -24,6 +24,7 @@
"airtable-plus": "^1.0.4",
"animated-value": "^0.2.4",
"animejs": "^3.2.1",
"axios": "^1.1.3",
"country-list-js": "^3.1.7",
"globby": "^11.0.4",
"jquery": "^3.6.1",

20
pages/api/first-team.js Normal file
View file

@ -0,0 +1,20 @@
import axios from 'axios'
export default async function handler(req, res) {
try {
const { data } = await axios(
`https://thebluealliance.com/api/v3/team/frc${encodeURIComponent(
req.query.teamNumber
)}`,
{
headers: {
'X-TBA-Auth-Key': process.env.TBA_API_KEY
}
}
)
res.json(data)
} catch (e) {
res.status(404).json({ ok: false })
}
}

View file

@ -1351,6 +1351,15 @@ axe-core@^4.3.5:
resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz"
integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==
axios@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35"
integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz"
@ -1576,7 +1585,7 @@ color-name@~1.1.4:
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
combined-stream@^1.0.6, combined-stream@~1.0.6:
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@ -2301,11 +2310,25 @@ flatted@^3.1.0:
resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz"
integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==
follow-redirects@^1.15.0:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz"
@ -3589,6 +3612,11 @@ property-information@^5.0.0, property-information@^5.3.0:
dependencies:
xtend "^4.0.0"
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
psl@^1.1.24:
version "1.8.0"
resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz"