mirror of
https://github.com/System-End/site.git
synced 2026-04-19 22:05:11 +00:00
Redesign Apply page
This commit is contained in:
parent
6dec10a43e
commit
4e1a96e84a
10 changed files with 234 additions and 315 deletions
|
|
@ -1,8 +1,11 @@
|
|||
import { useEffect, useRef, useState, useCallback } from 'react'
|
||||
import { Box, Flex, Input, Text } from 'theme-ui'
|
||||
import { Box, Card, Flex, Input, Text } from 'theme-ui'
|
||||
import FlexCol from '../../flex-col'
|
||||
import AutofillColourFix from './autofill-colour-fix'
|
||||
import { geocode, search } from '../../../lib/fiscal-sponsorship/apply/address-validation'
|
||||
import {
|
||||
geocode,
|
||||
search
|
||||
} from '../../../lib/fiscal-sponsorship/apply/address-validation'
|
||||
import Icon from '../../icon'
|
||||
|
||||
const approvedCountries = [
|
||||
|
|
@ -127,13 +130,10 @@ export default function AutoComplete({ name, isPersonalAddressInput }) {
|
|||
</Box>
|
||||
</FlexCol>
|
||||
{predictions && predictions.length > 0 && (
|
||||
<Box
|
||||
<Card
|
||||
sx={{
|
||||
background: '#47454f',
|
||||
border: '1px solid #696675',
|
||||
p: [3, 3],
|
||||
width: '100%',
|
||||
p: 3,
|
||||
borderRadius: '4px',
|
||||
position: 'absolute',
|
||||
bottom: 'calc(100% + 0.5em)'
|
||||
}}
|
||||
|
|
@ -148,9 +148,8 @@ export default function AutoComplete({ name, isPersonalAddressInput }) {
|
|||
cursor: 'pointer',
|
||||
border: 'none',
|
||||
background: 'none',
|
||||
color: '#d1cbe7',
|
||||
'&:hover': {
|
||||
color: 'white'
|
||||
color: 'blue'
|
||||
},
|
||||
fontFamily: 'inherit',
|
||||
fontSize: 'inherit',
|
||||
|
|
@ -172,7 +171,7 @@ export default function AutoComplete({ name, isPersonalAddressInput }) {
|
|||
</>
|
||||
))}
|
||||
</FlexCol>
|
||||
</Box>
|
||||
</Card>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import { Box, Flex, Label, Text } from 'theme-ui'
|
||||
import { Badge, Box, Flex, Label, Text } from 'theme-ui'
|
||||
import FlexCol from '../../flex-col'
|
||||
|
||||
export default function Field({
|
||||
|
|
@ -12,8 +12,7 @@ export default function Field({
|
|||
children
|
||||
}) {
|
||||
const router = useRouter()
|
||||
const isRequired =
|
||||
requiredFields[parseInt(router.query.step) - 1].includes(name)
|
||||
const isRequired = requiredFields.includes(name)
|
||||
|
||||
/* Fill in the field input element with the value from sessionStorage.
|
||||
Note: the custom checkbox component does this in its own useEffect hook. */
|
||||
|
|
@ -27,43 +26,47 @@ export default function Field({
|
|||
}, [router.query, name])
|
||||
|
||||
return (
|
||||
<FlexCol gap={2} width={'100%'}>
|
||||
<Flex
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: col ? 'column' : 'row',
|
||||
alignItems: col ? 'flex-start' : 'center',
|
||||
gap: 1,
|
||||
width: '100%',
|
||||
'input, textarea': {
|
||||
border: '1px solid',
|
||||
borderColor: 'smoke',
|
||||
outlineColor: 'blue'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Label
|
||||
htmlFor={name}
|
||||
sx={{
|
||||
flexDirection: col ? 'column' : 'row',
|
||||
alignItems: col ? 'flex-start' : 'center',
|
||||
gap: 2
|
||||
fontSize: 2,
|
||||
flexDirection: 'row'
|
||||
}}
|
||||
>
|
||||
<Flex sx={{ alignItems: 'center', gap: 2 }}>
|
||||
<Label
|
||||
htmlFor={name}
|
||||
{label}
|
||||
{isRequired && (
|
||||
<Text
|
||||
as="span"
|
||||
sx={{
|
||||
fontSize: 3,
|
||||
width: 'fit-content'
|
||||
color: 'red',
|
||||
fontWeight: 'bold',
|
||||
ml: 1
|
||||
}}
|
||||
title="Required"
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
{isRequired && (
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: 'muted',
|
||||
padding: '4px 6px',
|
||||
borderRadius: '999px',
|
||||
lineHeight: '1',
|
||||
fontSize: 14
|
||||
}}
|
||||
>
|
||||
Required
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
{children}
|
||||
</Flex>
|
||||
*
|
||||
</Text>
|
||||
)}
|
||||
</Label>
|
||||
{children}
|
||||
{description && (
|
||||
<Text sx={{ color: 'muted', fontSize: 1 }}>{description}</Text>
|
||||
<Text as="p" variant="caption">
|
||||
{description}
|
||||
</Text>
|
||||
)}
|
||||
</FlexCol>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { forwardRef } from 'react'
|
||||
import { Box } from 'theme-ui'
|
||||
import { Box, Container } from 'theme-ui'
|
||||
|
||||
const formContainer = forwardRef(({ children }, ref) => {
|
||||
return (
|
||||
|
|
@ -7,19 +7,25 @@ const formContainer = forwardRef(({ children }, ref) => {
|
|||
ref={ref}
|
||||
as="form"
|
||||
sx={{
|
||||
height: '100%',
|
||||
width: ['100%', null, null, '50ch'],
|
||||
flex: '1',
|
||||
overflowY: ['none', null, null, 'auto'],
|
||||
pr: [0, null, '2ch'],
|
||||
pl: [0, null, 1],
|
||||
pb: [0, null, 3],
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 4
|
||||
bg: 'snow',
|
||||
px: [3, 5],
|
||||
py: 5,
|
||||
minHeight: '100dvb'
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<Container
|
||||
variant="copy"
|
||||
sx={{
|
||||
ml: 0,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
columnGap: 4,
|
||||
rowGap: 3,
|
||||
px: 0
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Container>
|
||||
</Box>
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,89 +1,63 @@
|
|||
import { Box, Flex, Link, Text } from 'theme-ui'
|
||||
import { Box, Flex, Link, Text, Heading, Grid } from 'theme-ui'
|
||||
import Icon from '../../icon'
|
||||
import FlexCol from '../../flex-col'
|
||||
|
||||
export default function HCBInfo() {
|
||||
return (
|
||||
<Box>
|
||||
<FlexCol gap={4}>
|
||||
<FlexCol gap={4}>
|
||||
<Text sx={{ fontSize: 36 }}>
|
||||
What HCB <i>is</i>
|
||||
</Text>
|
||||
<FlexCol gap={3} ml={3}>
|
||||
<FlexCol gap={2}>
|
||||
<Flex sx={{ alignItems: 'center', gap: 2 }}>
|
||||
<Link
|
||||
color="white"
|
||||
href="/fiscal-sponsorship/about"
|
||||
target="_blank"
|
||||
sx={{
|
||||
fontSize: 3,
|
||||
display: 'inline-flex',
|
||||
alignItems: 'flex-end',
|
||||
gap: 1
|
||||
}}
|
||||
>
|
||||
A fiscal sponsor
|
||||
<Icon glyph="external" />
|
||||
</Link>
|
||||
</Flex>
|
||||
<Text sx={{ color: 'muted' }}>
|
||||
<ul>
|
||||
<li>Nonprofit status.</li>
|
||||
<li>Tax-deductable donations.</li>
|
||||
</ul>
|
||||
</Text>
|
||||
</FlexCol>
|
||||
<FlexCol gap={2}>
|
||||
<Text sx={{ fontSize: 3 }}>A financial platform</Text>
|
||||
<Text sx={{ color: 'muted' }}>
|
||||
<ul>
|
||||
<li>A donations page and invoicing system.</li>
|
||||
<li>Transfer money electronically.</li>
|
||||
<li>Order cards for you and your team to make purchases.</li>
|
||||
</ul>
|
||||
</Text>
|
||||
</FlexCol>
|
||||
</FlexCol>
|
||||
</FlexCol>
|
||||
<FlexCol gap={4}>
|
||||
<Text sx={{ fontSize: 36 }}>
|
||||
What HCB <i>is not</i>
|
||||
</Text>
|
||||
<FlexCol gap={3} ml={3}>
|
||||
<FlexCol gap={2}>
|
||||
<Text sx={{ fontSize: 3 }}>
|
||||
A bank!{' '}
|
||||
<Text sx={{ color: 'muted', fontSize: 2 }}>(we're better)</Text>
|
||||
</Text>
|
||||
<Text sx={{ color: 'muted' }}>
|
||||
<ul>
|
||||
<li>
|
||||
Rather than setting up a standard bank account, you'll get a
|
||||
restricted fund within Hack Club accounts.
|
||||
</li>
|
||||
<li>
|
||||
You can't deposit or withdraw cash. But you can receive any
|
||||
kind of electronic payment!
|
||||
</li>
|
||||
</ul>
|
||||
</Text>
|
||||
</FlexCol>
|
||||
<FlexCol gap={2}>
|
||||
<Text sx={{ fontSize: 3 }}>For-profit</Text>
|
||||
<Text sx={{ color: 'muted' }}>
|
||||
<ul>
|
||||
<li>
|
||||
If you’re a for-profit entity, then HCB is not for you.
|
||||
Consider setting up a business.
|
||||
</li>
|
||||
</ul>
|
||||
</Text>
|
||||
</FlexCol>
|
||||
</FlexCol>
|
||||
</FlexCol>
|
||||
</FlexCol>
|
||||
<Box
|
||||
sx={{
|
||||
gridArea: 'info',
|
||||
alignItems: 'start',
|
||||
mark: { color: '#ec555c', bg: 'inherit' },
|
||||
'ul, p': { pl: 0, color: 'muted', mb: 4 }
|
||||
}}
|
||||
>
|
||||
<Heading variant="subheadline">
|
||||
HCB is a{' '}
|
||||
<Link
|
||||
href="/fiscal-sponsorship/about"
|
||||
target="_blank"
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'flex-end',
|
||||
gap: 1
|
||||
}}
|
||||
>
|
||||
fiscal sponsor
|
||||
<Icon glyph="external" size={24} />
|
||||
</Link>
|
||||
</Heading>
|
||||
<ul>
|
||||
<li>Nonprofit status.</li>
|
||||
<li>Tax-deductable donations.</li>
|
||||
</ul>
|
||||
<Heading variant="subheadline">
|
||||
HCB provides a financial platform.
|
||||
</Heading>
|
||||
<ul>
|
||||
<li>A donations page and invoicing system.</li>
|
||||
<li>Transfer money electronically.</li>
|
||||
<li>Order cards for you and your team to make purchases.</li>
|
||||
</ul>
|
||||
<Heading variant="subheadline">
|
||||
HCB is not a bank.{' '}
|
||||
<Text sx={{ color: 'muted', fontWeight: 'body' }}>(we’re better)</Text>
|
||||
</Heading>
|
||||
<ul>
|
||||
<li>
|
||||
Rather than setting up a standard bank account, you’ll get a
|
||||
restricted fund within Hack Club accounts.
|
||||
</li>
|
||||
<li>
|
||||
You can't deposit or withdraw cash. But you can receive any kind of
|
||||
electronic payment!
|
||||
</li>
|
||||
</ul>
|
||||
<Heading variant="subheadline">HCB is not for for-profits.</Heading>
|
||||
<p>
|
||||
If you’re a for-profit entity, HCB is not for you. Consider setting up a
|
||||
business.
|
||||
</p>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Button, Flex, Text, Spinner } from 'theme-ui'
|
||||
import { Button, Spinner } from 'theme-ui'
|
||||
|
||||
async function sendApplication() {
|
||||
// Get the form data from sessionStorage
|
||||
|
|
@ -26,31 +26,7 @@ async function sendApplication() {
|
|||
}
|
||||
}
|
||||
|
||||
function NavIcon({ isBack }) {
|
||||
const style = {
|
||||
height: '1em',
|
||||
fill: 'white',
|
||||
margin: 0,
|
||||
flexShrink: 0
|
||||
}
|
||||
|
||||
return isBack ? (
|
||||
<svg style={style} viewBox="10.73 7.72 9.27 16.53">
|
||||
<g>
|
||||
<path d="M19.768,23.89c0.354,-0.424 0.296,-1.055 -0.128,-1.408c-1.645,-1.377 -5.465,-4.762 -6.774,-6.482c1.331,-1.749 5.1,-5.085 6.774,-6.482c0.424,-0.353 0.482,-0.984 0.128,-1.408c-0.353,-0.425 -0.984,-0.482 -1.409,-0.128c-1.839,1.532 -5.799,4.993 -7.2,6.964c-0.219,0.312 -0.409,0.664 -0.409,1.054c0,0.39 0.19,0.742 0.409,1.053c1.373,1.932 5.399,5.462 7.2,6.964l0.001,0.001c0.424,0.354 1.055,0.296 1.408,-0.128Z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
) : (
|
||||
<svg style={style} viewBox="12.75 7.72 9.25 16.53">
|
||||
<g>
|
||||
<path d="M12.982,23.89c-0.354,-0.424 -0.296,-1.055 0.128,-1.408c1.645,-1.377 5.465,-4.762 6.774,-6.482c-1.331,-1.749 -5.1,-5.085 -6.774,-6.482c-0.424,-0.353 -0.482,-0.984 -0.128,-1.408c0.353,-0.425 0.984,-0.482 1.409,-0.128c1.839,1.532 5.799,4.993 7.2,6.964c0.219,0.312 0.409,0.664 0.409,1.054c0,0.39 -0.19,0.742 -0.409,1.053c-1.373,1.932 -5.399,5.462 -7.2,6.964l-0.001,0.001c-0.424,0.354 -1.055,0.296 -1.408,-0.128Z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default function NavButton({
|
||||
isBack,
|
||||
form,
|
||||
clickHandler,
|
||||
requiredFields,
|
||||
|
|
@ -63,37 +39,10 @@ export default function NavButton({
|
|||
setSpinner(false)
|
||||
}, [router.query.step])
|
||||
|
||||
const minStep = 1
|
||||
const maxStep = 3
|
||||
|
||||
const click = async () => {
|
||||
setSpinner(true)
|
||||
|
||||
let step = parseInt(router.query.step)
|
||||
|
||||
async function setStep(s) {
|
||||
await router.push(
|
||||
{
|
||||
pathname: router.pathname,
|
||||
query: { ...router.query, step: s }
|
||||
},
|
||||
undefined,
|
||||
{}
|
||||
)
|
||||
}
|
||||
|
||||
if (!step) {
|
||||
// Set the step query param to minStep if it's not there.
|
||||
await setStep(minStep)
|
||||
} else if (step === minStep && isBack) {
|
||||
await router.push('/hcb')
|
||||
return
|
||||
} else if (step < minStep) {
|
||||
// Set the step query param to minStep if it's lower than that.
|
||||
await setStep(minStep)
|
||||
}
|
||||
|
||||
/* Don't return from inside the loop since
|
||||
/* Don't return from inside the loop since
|
||||
we want all input values to be saved every time */
|
||||
let wasError = false
|
||||
|
||||
|
|
@ -105,11 +54,9 @@ export default function NavButton({
|
|||
|
||||
// Check if there are empty required fields.
|
||||
if (
|
||||
(!isBack &&
|
||||
(!value || value.trim() === '') &&
|
||||
((!value || value.trim() === '') &&
|
||||
requiredFields[step - 1].includes(key)) ||
|
||||
(!isBack &&
|
||||
formData.get('contactOption') === 'slack' &&
|
||||
(formData.get('contactOption') === 'slack' &&
|
||||
!formData.get('slackUsername')) // I'm so sorry for this
|
||||
) {
|
||||
setFormError('Please fill all required fields')
|
||||
|
|
@ -122,47 +69,15 @@ export default function NavButton({
|
|||
// Run the parent's click handler for this button.
|
||||
if (clickHandler) await clickHandler()
|
||||
|
||||
if (step >= maxStep && !isBack) {
|
||||
await sendApplication()
|
||||
await router.push('/fiscal-sponsorship/apply/success')
|
||||
return
|
||||
} else {
|
||||
step += isBack ? -1 : 1
|
||||
}
|
||||
await setStep(step)
|
||||
await sendApplication()
|
||||
await router.push('/fiscal-sponsorship/apply/success')
|
||||
return
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant={isBack ? 'outline' : 'ctaLg'}
|
||||
sx={{
|
||||
color: 'white',
|
||||
width: '100%',
|
||||
maxWidth: isBack ? '8rem' : '10rem',
|
||||
position: 'relative'
|
||||
}}
|
||||
onClick={click}
|
||||
>
|
||||
<Flex
|
||||
sx={{
|
||||
flexDirection: isBack ? 'row' : 'row-reverse',
|
||||
justifyContent: 'center',
|
||||
placeItems: 'center',
|
||||
fontSize: isBack ? 2 : 4,
|
||||
gap: [2, null, null, 3]
|
||||
}}
|
||||
>
|
||||
<NavIcon isBack={isBack} />
|
||||
<Text
|
||||
sx={{
|
||||
textTransform: 'none',
|
||||
fontWeight: 'bold'
|
||||
}}
|
||||
>
|
||||
{isBack ? 'Back' : 'Next'}
|
||||
</Text>
|
||||
</Flex>
|
||||
{!isBack && spinner && (
|
||||
<Button variant="ctaLg" sx={{ width: 'fit-content' }} onClick={click}>
|
||||
Submit
|
||||
{spinner && (
|
||||
<Spinner
|
||||
sx={{
|
||||
height: '32px',
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export default function OrganizationInfoForm({ requiredFields }) {
|
|||
<Textarea
|
||||
name="eventDescription"
|
||||
id="eventDescription"
|
||||
rows={3}
|
||||
rows={2}
|
||||
sx={{
|
||||
resize: 'vertical',
|
||||
width: '100%',
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
import { Input, Flex, Label, Radio } from 'theme-ui'
|
||||
import { Input, Flex, Label, Radio, Box, Grid } from 'theme-ui'
|
||||
import Checkbox from './checkbox'
|
||||
import AddressInput from './address-input'
|
||||
import Field from './field'
|
||||
import AutofillColourFix from './autofill-colour-fix'
|
||||
import { useState } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export default function PersonalInfoForm({
|
||||
setValidationResult,
|
||||
requiredFields
|
||||
}) {
|
||||
const [selectedContactOption, setSelectedContactOption] = useState('Email')
|
||||
const [email, setEmail] = useState(
|
||||
window.sessionStorage.getItem('bank-signup-userEmail')
|
||||
) // For display only, is not used for data submission.
|
||||
const [email, setEmail] = useState('') // For display only, is not used for data submission.
|
||||
|
||||
useEffect(() => {
|
||||
setEmail(window.sessionStorage.getItem('bank-signup-userEmail'))
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -78,7 +80,7 @@ export default function PersonalInfoForm({
|
|||
sx={{ ...AutofillColourFix }}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
{/* <Field
|
||||
name="referredBy"
|
||||
label="Who were you referred by?"
|
||||
requiredFields={requiredFields}
|
||||
|
|
@ -111,13 +113,21 @@ export default function PersonalInfoForm({
|
|||
/>
|
||||
</Field>
|
||||
|
||||
*/}
|
||||
|
||||
<Field
|
||||
name="contactOption"
|
||||
label="Preferred contact channel"
|
||||
description="So we know where to message you about your application!"
|
||||
requiredFields={requiredFields}
|
||||
>
|
||||
<Flex sx={{ gap: 4 }}>
|
||||
<Grid
|
||||
columns={[null, 2]}
|
||||
sx={{
|
||||
rowGap: 2,
|
||||
columnGap: 4,
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
<Label
|
||||
sx={{
|
||||
display: 'flex',
|
||||
|
|
@ -132,34 +142,45 @@ export default function PersonalInfoForm({
|
|||
/>
|
||||
Email
|
||||
</Label>
|
||||
<Label
|
||||
<Grid
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row'
|
||||
columnGap: 1,
|
||||
rowGap: 2,
|
||||
gridTemplateColumns: 'auto 1fr'
|
||||
}}
|
||||
>
|
||||
<Radio
|
||||
name="contactOption"
|
||||
value="Slack"
|
||||
onInput={() => setSelectedContactOption('Slack')}
|
||||
/>
|
||||
Slack
|
||||
</Label>
|
||||
</Flex>
|
||||
{selectedContactOption === 'Slack' ? (
|
||||
<Field name="slackUsername" requiredFields={requiredFields}>
|
||||
<Input
|
||||
name="slackUsername"
|
||||
id="slackUsername"
|
||||
placeholder="Your name in the Hack Club Slack"
|
||||
sx={{ ...AutofillColourFix }}
|
||||
/>
|
||||
</Field>
|
||||
) : selectedContactOption === 'Email' ? (
|
||||
<div>
|
||||
We'll use {email ?? 'whatever you put for your email above!'}
|
||||
</div>
|
||||
) : null}
|
||||
<Label
|
||||
sx={{
|
||||
display: 'contents',
|
||||
'~ div > label': { fontSize: 1 }
|
||||
}}
|
||||
>
|
||||
<Radio
|
||||
name="contactOption"
|
||||
value="Slack"
|
||||
onInput={() => setSelectedContactOption('Slack')}
|
||||
/>
|
||||
Hack Club Slack
|
||||
</Label>
|
||||
{selectedContactOption === 'Slack' ? (
|
||||
<>
|
||||
<div />
|
||||
<Field
|
||||
label="Your Hack Club Slack username"
|
||||
name="slackUsername"
|
||||
requiredFields={requiredFields}
|
||||
>
|
||||
<Input
|
||||
name="slackUsername"
|
||||
id="slackUsername"
|
||||
autoFocus
|
||||
sx={{ ...AutofillColourFix }}
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
) : null}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Field>
|
||||
<Field
|
||||
name="accommodations"
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export default function Watermark() {
|
|||
position: 'absolute',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: '#1d181f',
|
||||
backgroundColor: 'snow',
|
||||
clipPath: 'url(#my-clip-path)'
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ export default function Features() {
|
|||
name="Receive foundation grants"
|
||||
body="with tax-deductible 501(c)(3) status."
|
||||
/>
|
||||
{/* Send money & reimburse via check, ACH, bank wire, PayPal, & more.
|
||||
Operate globally with a US Entity.
|
||||
Issue physical & virtual debit cards to your team.
|
||||
Get 24 hour support on weekdays.
|
||||
Pay team members with built-in payroll.
|
||||
Embed a custom donation form on your website.
|
||||
We file all your taxes automatically, including form 990. " */}
|
||||
<Module
|
||||
icon="card"
|
||||
name="Issue physical & virtual debit cards"
|
||||
|
|
@ -69,7 +76,6 @@ export default function Features() {
|
|||
<Laptop
|
||||
href="https://hcb.hackclub.com/reboot"
|
||||
title="See Reboot’s finances in public"
|
||||
sx={{}}
|
||||
/>
|
||||
</Container>
|
||||
</Box>
|
||||
|
|
@ -90,7 +96,6 @@ function Module({ icon, name, body }) {
|
|||
color: 'slate',
|
||||
lineHeight: '1.375',
|
||||
fontSize: 20,
|
||||
alignSelf: 'center',
|
||||
m: 0
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import { useEffect, useState, useRef } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Box, Flex, Text } from 'theme-ui'
|
||||
import { Box, Flex, Heading, Grid } from 'theme-ui'
|
||||
import ForceTheme from '../../../components/force-theme'
|
||||
import Head from 'next/head'
|
||||
import Meta from '@hackclub/meta'
|
||||
import FlexCol from '../../../components/flex-col'
|
||||
import Progress from '../../../components/fiscal-sponsorship/apply/progress'
|
||||
import NavButton from '../../../components/fiscal-sponsorship/apply/nav-button'
|
||||
import Watermark from '../../../components/fiscal-sponsorship/apply/watermark'
|
||||
import FormContainer from '../../../components/fiscal-sponsorship/apply/form-container'
|
||||
|
|
@ -15,7 +13,7 @@ import PersonalInfoForm from '../../../components/fiscal-sponsorship/apply/perso
|
|||
import AlertModal from '../../../components/fiscal-sponsorship/apply/alert-modal'
|
||||
import { geocode } from '../../../lib/fiscal-sponsorship/apply/address-validation'
|
||||
|
||||
const valiadateAddress = async step => {
|
||||
const validateAddress = async step => {
|
||||
// Validate the address
|
||||
if (step === 3) {
|
||||
// Get the raw personal address input
|
||||
|
|
@ -55,9 +53,12 @@ export default function Apply() {
|
|||
const [formError, setFormError] = useState(null)
|
||||
|
||||
const requiredFields = [
|
||||
[],
|
||||
['eventName', 'eventLocation'],
|
||||
['firstName', 'lastName', 'userEmail', 'userBirthday', 'contactOption']
|
||||
'eventName',
|
||||
'eventLocation',
|
||||
'firstName',
|
||||
'lastName',
|
||||
'userEmail',
|
||||
'userBirthday'
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -81,59 +82,54 @@ export default function Apply() {
|
|||
return (
|
||||
<>
|
||||
<Meta as={Head} title="Apply for HCB" />
|
||||
<ForceTheme theme="dark" />
|
||||
<ForceTheme theme="light" />
|
||||
|
||||
<Box
|
||||
<Grid
|
||||
columns={[null, null, 2]}
|
||||
sx={{
|
||||
display: 'grid',
|
||||
gap: 5,
|
||||
gridTemplateAreas: [
|
||||
'"title" "form" "form" "nav"',
|
||||
null,
|
||||
null,
|
||||
'"title form" "title form" "nav form"'
|
||||
],
|
||||
height: ['auto', null, null, '100vh'],
|
||||
p: [4, 5]
|
||||
gap: 0,
|
||||
width: '100%',
|
||||
minHeight: '100vh',
|
||||
alignItems: 'start'
|
||||
}}
|
||||
>
|
||||
<Box sx={{ gridArea: 'title' }}>
|
||||
<FlexCol gap={[4, null, null, '20vh']}>
|
||||
<Text variant="title">
|
||||
Let’s get you
|
||||
<br />
|
||||
set up on HCB.
|
||||
</Text>
|
||||
<Progress />
|
||||
</FlexCol>
|
||||
</Box>
|
||||
<Box sx={{ gridArea: 'form', overflowY: 'auto' }}>
|
||||
<FormContainer ref={formContainer}>
|
||||
{step === 1 && <HCBInfo />}
|
||||
{step === 2 && (
|
||||
<OrganizationInfoForm requiredFields={requiredFields} />
|
||||
)}
|
||||
{step === 3 && <PersonalInfoForm requiredFields={requiredFields} />}
|
||||
</FormContainer>
|
||||
</Box>
|
||||
<Flex
|
||||
sx={{
|
||||
gridArea: 'nav',
|
||||
alignSelf: 'end',
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'space-between'
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
px: [3, 5],
|
||||
py: 5,
|
||||
gap: [3, 5],
|
||||
height: [null, '100dvh'],
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
overflowY: 'auto'
|
||||
}}
|
||||
>
|
||||
<NavButton isBack={true} form={formContainer} />
|
||||
<Heading as="h1" variant="title">
|
||||
Let’s get you
|
||||
<br />
|
||||
set up on HCB.
|
||||
</Heading>
|
||||
<HCBInfo />
|
||||
</Flex>
|
||||
<FormContainer ref={formContainer}>
|
||||
<Heading as="h2" variant="headline" sx={{ mb: -2 }}>
|
||||
Your organization
|
||||
</Heading>
|
||||
<OrganizationInfoForm requiredFields={requiredFields} />
|
||||
<Heading as="h2" variant="headline" sx={{ mb: -2 }}>
|
||||
Personal details
|
||||
</Heading>
|
||||
<PersonalInfoForm requiredFields={requiredFields} />
|
||||
<NavButton
|
||||
isBack={false}
|
||||
form={formContainer}
|
||||
setFormError={setFormError}
|
||||
requiredFields={requiredFields}
|
||||
clickHandler={() => valiadateAddress(step)}
|
||||
clickHandler={() => validateAddress(step)}
|
||||
/>
|
||||
</Flex>
|
||||
</Box>
|
||||
</FormContainer>
|
||||
</Grid>
|
||||
<AlertModal formError={formError} setFormError={setFormError} />
|
||||
<Watermark />
|
||||
</>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue