mirror of
https://github.com/System-End/site.git
synced 2026-04-19 19:45:07 +00:00
Merge pull request #1401 from hackclub/garyhtou/hcb-apply-teenager-questions
[HCB] Add additional application questions for adult orgs
This commit is contained in:
commit
251a9b2bfb
8 changed files with 188 additions and 67 deletions
|
|
@ -13,6 +13,9 @@ const formContainer = forwardRef(({ children, ...props }, ref) => {
|
|||
minHeight: '100dvb',
|
||||
'&.has-errors div[aria-required="true"] input:placeholder-shown': {
|
||||
borderColor: 'primary'
|
||||
},
|
||||
'&.has-errors div[aria-required="true"] textarea:placeholder-shown': {
|
||||
borderColor: 'primary'
|
||||
}
|
||||
}}
|
||||
{...props}
|
||||
|
|
|
|||
92
components/fiscal-sponsorship/apply/org-adult-form.js
Normal file
92
components/fiscal-sponsorship/apply/org-adult-form.js
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { Input, Select, Textarea } from 'theme-ui'
|
||||
import Field from './field'
|
||||
import useOrganizationI18n from '../organizationI18n'
|
||||
|
||||
export default function OrganizationAdultForm({ requiredFields }) {
|
||||
const org = useOrganizationI18n()
|
||||
const [teenagerLed, setTeenagerLed] = useState('false')
|
||||
|
||||
const onTeenagerLedChange = e => {
|
||||
const newValue = e.target.value
|
||||
setTeenagerLed(newValue)
|
||||
|
||||
if (newValue === 'true') {
|
||||
// Clear cache of removed fields
|
||||
sessionStorage.removeItem('bank-signup-eventPoliticalActivity')
|
||||
sessionStorage.removeItem('bank-signup-eventAnnualBudget')
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// [@garyhtou] welp... this exists because the Field component will cache
|
||||
// input values and set them on page load. It does it by directly setting
|
||||
// `input.value` with JavaScript; bypassing React. Because of that, the
|
||||
// `teenagerLed` state may not be synced with the DOM input value. This code
|
||||
// syncs `teenagerLed` with the DOM input value.
|
||||
// NOTE: This depends on Field's useEffect hook to run first.
|
||||
const eventTeenagerLedElm = document.getElementById('eventTeenagerLed')
|
||||
setTeenagerLed(eventTeenagerLedElm.value)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Field
|
||||
name="eventTeenagerLed"
|
||||
label={`Is your ${org.toLowerCase()} led by teenagers?`}
|
||||
col={true}
|
||||
description={`This means your ${org.toLowerCase()} was founded and is being led exclusively by teenagers.`}
|
||||
requiredFields={requiredFields}
|
||||
>
|
||||
<Select
|
||||
name="eventTeenagerLed"
|
||||
id="eventTeenagerLed"
|
||||
onChange={onTeenagerLedChange}
|
||||
value={teenagerLed}
|
||||
>
|
||||
{Object.entries({ Yes: 'true', No: 'false' }).map(([name, value]) => (
|
||||
<option key={name} value={value}>
|
||||
{name}
|
||||
</option>
|
||||
))}
|
||||
</Select>
|
||||
</Field>
|
||||
|
||||
{teenagerLed !== 'true' && (
|
||||
<>
|
||||
<Field
|
||||
name="eventPoliticalActivity"
|
||||
label={`Please describe any political activity your ${org.toLowerCase()} is involved in`}
|
||||
description="This includes but is not limited to protests, public demonstrations, political education, and lobbying."
|
||||
requiredFields={requiredFields}
|
||||
>
|
||||
<Textarea
|
||||
name="eventPoliticalActivity"
|
||||
id="eventPoliticalActivity"
|
||||
placeholder="We are involved in..."
|
||||
rows={3}
|
||||
sx={{
|
||||
resize: 'vertical'
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field
|
||||
name="eventAnnualBudget"
|
||||
label="What is your estimated annual budget (USD) for this year?"
|
||||
requiredFields={requiredFields}
|
||||
>
|
||||
<Input
|
||||
name="eventAnnualBudget"
|
||||
id="eventAnnualBudget"
|
||||
type="number"
|
||||
min={0}
|
||||
step={1}
|
||||
placeholder="10,000"
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -4,13 +4,11 @@ import Checkbox from './checkbox'
|
|||
import Field from './field'
|
||||
// This is using country-list instead of country-list-js as it has a smaller bundle size
|
||||
import { getNames } from 'country-list'
|
||||
import useOrganizationI18n from '../organizationI18n'
|
||||
import OrganizationAdultForm from './org-adult-form'
|
||||
|
||||
export default function OrganizationInfoForm({ requiredFields }) {
|
||||
const [org, setOrg] = useState('Organization')
|
||||
|
||||
useEffect(() => {
|
||||
if (navigator.language === 'en-GB') setOrg('Organisation')
|
||||
}, [])
|
||||
const org = useOrganizationI18n()
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -95,6 +93,8 @@ export default function OrganizationInfoForm({ requiredFields }) {
|
|||
}}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<OrganizationAdultForm requiredFields={requiredFields} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,12 @@ export function onSubmit({
|
|||
if (!formError) {
|
||||
setIsSubmitting(true)
|
||||
sendApplication().then(() => {
|
||||
router.push('/fiscal-sponsorship/apply/success')
|
||||
const isAdult = formData.get('eventTeenagerLed') !== 'true'
|
||||
const acceptanceEta = isAdult
|
||||
? 'within two weeks'
|
||||
: 'within two business days'
|
||||
|
||||
router.push(`/fiscal-sponsorship/apply/success?eta=${acceptanceEta}`)
|
||||
})
|
||||
}
|
||||
return
|
||||
|
|
|
|||
11
components/fiscal-sponsorship/organizationI18n.js
Normal file
11
components/fiscal-sponsorship/organizationI18n.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { useState, useEffect } from 'react'
|
||||
|
||||
export default function useOrganizationI18n() {
|
||||
const [org, setOrg] = useState('Organization')
|
||||
|
||||
useEffect(() => {
|
||||
if (navigator.language === 'en-GB') setOrg('Organisation')
|
||||
}, [])
|
||||
|
||||
return org
|
||||
}
|
||||
|
|
@ -8,65 +8,69 @@ const applicationsTable = new AirtablePlus({
|
|||
})
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method === 'POST') {
|
||||
const data = req.body
|
||||
|
||||
await fetch('https://hcb.hackclub.com/api/v1/events/create_demo', {
|
||||
body: JSON.stringify({
|
||||
email: data.userEmail,
|
||||
name: data.eventName,
|
||||
country: getCode(data.eventLocation) || '',
|
||||
postal_code: data.eventPostalCode || '',
|
||||
transparent: data.transparent,
|
||||
}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${process.env.HCB_API_TOKEN || ''}`
|
||||
}
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(async r => {
|
||||
await applicationsTable.create({
|
||||
'First Name': data.firstName,
|
||||
'Last Name': data.lastName,
|
||||
'Email Address': data.userEmail,
|
||||
'Phone Number': data.userPhone,
|
||||
'Date of Birth': data.userBirthday,
|
||||
'Event Name': data.eventName,
|
||||
'Event Website': data.eventWebsite,
|
||||
'Zip Code': data.eventPostalCode,
|
||||
'Tell us about your event': data.eventDescription,
|
||||
'Mailing Address': data.userAddress,
|
||||
'Address Line 1': data.addressLine1,
|
||||
City: data.addressCity,
|
||||
State: data.addressState,
|
||||
'Address Country': data.addressCountry,
|
||||
'Address Country Code': data.addressCountryCode,
|
||||
'Event Location': data.eventLocation,
|
||||
'Event Country Code': data.eventCountryCode,
|
||||
'Have you used HCB for any previous events?':
|
||||
data.returningUser === 'true'
|
||||
? 'Yes, I have used HCB before'
|
||||
: 'No, first time!',
|
||||
'How did you hear about HCB?': data.referredBy,
|
||||
Transparent:
|
||||
data.transparent === 'true' ? 'Yes, please!' : 'No, thanks.',
|
||||
'HCB account URL': `https://hcb.hackclub.com/${r.slug}`,
|
||||
'Contact Option': data.contactOption,
|
||||
'Slack Username': data.slackUsername,
|
||||
Accommodations: data.accommodations,
|
||||
'HCB ID': r.id
|
||||
})
|
||||
res.writeHead(302, { Location: '/hcb/apply/success' }).end()
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
res.writeHead(500, {
|
||||
Location: `/hcb/apply?step=3&airtable-error=${error}`
|
||||
})
|
||||
})
|
||||
} else {
|
||||
if (req.method !== 'POST') {
|
||||
res.status(405).json({ status: 'error', error: 'Must send POST request' })
|
||||
return
|
||||
}
|
||||
|
||||
const data = req.body
|
||||
|
||||
await fetch('https://hcb.hackclub.com/api/v1/events/create_demo', {
|
||||
body: JSON.stringify({
|
||||
email: data.userEmail,
|
||||
name: data.eventName,
|
||||
country: getCode(data.eventLocation) || '',
|
||||
postal_code: data.eventPostalCode || '',
|
||||
transparent: data.transparent
|
||||
}),
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${process.env.HCB_API_TOKEN || ''}`
|
||||
}
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(async r => {
|
||||
await applicationsTable.create({
|
||||
'First Name': data.firstName,
|
||||
'Last Name': data.lastName,
|
||||
'Email Address': data.userEmail,
|
||||
'Phone Number': data.userPhone,
|
||||
'Date of Birth': data.userBirthday,
|
||||
'Event Name': data.eventName,
|
||||
'Event Website': data.eventWebsite,
|
||||
'Zip Code': data.eventPostalCode,
|
||||
'Tell us about your event': data.eventDescription,
|
||||
'Mailing Address': data.userAddress,
|
||||
'Address Line 1': data.addressLine1,
|
||||
City: data.addressCity,
|
||||
State: data.addressState,
|
||||
'Address Country': data.addressCountry,
|
||||
'Address Country Code': data.addressCountryCode,
|
||||
'Event Location': data.eventLocation,
|
||||
'Event Country Code': data.eventCountryCode,
|
||||
'Have you used HCB for any previous events?':
|
||||
data.returningUser === 'true'
|
||||
? 'Yes, I have used HCB before'
|
||||
: 'No, first time!',
|
||||
'How did you hear about HCB?': data.referredBy,
|
||||
Transparent:
|
||||
data.transparent === 'true' ? 'Yes, please!' : 'No, thanks.',
|
||||
'HCB account URL': `https://hcb.hackclub.com/${r.slug}`,
|
||||
'Contact Option': data.contactOption,
|
||||
'Slack Username': data.slackUsername,
|
||||
Accommodations: data.accommodations,
|
||||
'Teenager Led?': data.eventTeenagerLed === 'true',
|
||||
'(Adults) Political Activity': data.eventPoliticalActivity,
|
||||
'(Adults) Annual Budget': parseInt(data.eventAnnualBudget),
|
||||
'HCB ID': r.id
|
||||
})
|
||||
res.status(200).end();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error)
|
||||
res.writeHead(500, {
|
||||
Location: `/hcb/apply?step=3&airtable-error=${error}`
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ export default function Apply() {
|
|||
'eventLocation',
|
||||
'eventPostalCode',
|
||||
'eventDescription',
|
||||
'eventTeenagerLed',
|
||||
'eventPoliticalActivity',
|
||||
'eventAnnualBudget',
|
||||
'firstName',
|
||||
'lastName',
|
||||
'userEmail',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { useEffect } from 'react'
|
|||
import { Container, Text, Link, Image } from 'theme-ui'
|
||||
import JSConfetti from 'js-confetti'
|
||||
import { Balancer } from 'react-wrap-balancer'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
function fireConfetti() {
|
||||
const jsConfetti = new JSConfetti()
|
||||
|
|
@ -24,6 +25,9 @@ export default function ApplicationSuccess() {
|
|||
fireConfetti()
|
||||
}, [])
|
||||
|
||||
const router = useRouter()
|
||||
const eta = router.query["eta"] || "soon" // default value
|
||||
|
||||
return (
|
||||
<Container
|
||||
variant="narrow"
|
||||
|
|
@ -51,8 +55,7 @@ export default function ApplicationSuccess() {
|
|||
</Text>
|
||||
<Text as="p" variant="lead">
|
||||
<Balancer>
|
||||
We’ll review your application and get back to you within two
|
||||
business days.
|
||||
We’ll review your application and get back to you {eta}.
|
||||
</Balancer>
|
||||
</Text>
|
||||
</header>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue