- Order cards for you and your team to
- make purchases.
-
+
A donations page and invoicing system.
+
Transfer money electronically.
+
Order cards for you and your team to make purchases.
@@ -64,22 +53,23 @@ export default function BankInfo() {
- A bank! (we're better)
-
+
+ A bank!{' '}
+ (we're better)
+
+
- Rather than setting up a standard bank account,
- you'll get a restricted fund within Hack Club accounts.
-
-
- You can't deposit or withdraw money.
+ Rather than setting up a standard bank account, you'll get a
+ restricted fund within Hack Club accounts.
+
You can't deposit or withdraw money.
For-profit
-
+
If you’re a for-profit entity, then Bank is not for you.
@@ -92,5 +82,5 @@ export default function BankInfo() {
- );
+ )
}
diff --git a/components/bank/apply/checkbox.js b/components/bank/apply/checkbox.js
index 0b4fac64..0442d343 100644
--- a/components/bank/apply/checkbox.js
+++ b/components/bank/apply/checkbox.js
@@ -1,39 +1,35 @@
import { useEffect, useState } from 'react'
import Icon from '../../icon'
-export default function Checkbox({ name, defaultChecked=false, size=38 }) {
- const [checked, setChecked] = useState(defaultChecked)
- const toggle = () => setChecked(!checked)
+export default function Checkbox({ name, defaultChecked = false, size = 38 }) {
+ const [checked, setChecked] = useState(defaultChecked)
+ const toggle = () => setChecked(!checked)
- /* Fill in the field with the value from sessionStorage.
+ /* Fill in the field with the value from sessionStorage.
For other input elements, the value is set in the Field component,
but these checkboxes hold their state in useState rather than in the DOM. */
- useEffect(() => {
- const value = sessionStorage.getItem('bank-signup-' + name)
- if (value) {
- const input = document.getElementById(name)
- input && setChecked(value === 'true')
- }
- }, [name])
+ useEffect(() => {
+ const value = sessionStorage.getItem('bank-signup-' + name)
+ if (value) {
+ const input = document.getElementById(name)
+ input && setChecked(value === 'true')
+ }
+ }, [name])
- return (<>
-
- toggle()}
- onKeyDown={(e) => e.key === 'Enter' && toggle()}
- />
+ return (
+ <>
+
+ toggle()}
+ onKeyDown={e => e.key === 'Enter' && toggle()}
+ />
>
- )
-}
\ No newline at end of file
+ )
+}
diff --git a/components/bank/apply/field.js b/components/bank/apply/field.js
index 50a41ab4..4b942e1f 100644
--- a/components/bank/apply/field.js
+++ b/components/bank/apply/field.js
@@ -3,50 +3,67 @@ import { useEffect } from 'react'
import { Box, Flex, Label, Text } from 'theme-ui'
import FlexCol from '../../flex-col'
-export default function Field({ name, label, description, col = true, requiredFields, children }) {
- const router = useRouter()
- const isRequired = requiredFields[parseInt(router.query.step) - 1].includes(name)
+export default function Field({
+ name,
+ label,
+ description,
+ col = true,
+ requiredFields,
+ children
+}) {
+ const router = useRouter()
+ const isRequired =
+ requiredFields[parseInt(router.query.step) - 1].includes(name)
- /* Fill in the field input element with the value from sessionStorage.
+ /* Fill in the field input element with the value from sessionStorage.
Note: the custom checkbox component does this in its own useEffect hook. */
- useEffect(() => {
- const value = sessionStorage.getItem('bank-signup-' + name)
- if (value) {
- const input = document.getElementById(name)
- if (input) input.value = value
- }
- }, [name])
-
- return (
-
-
-
-
- { isRequired &&
- Required
- }
-
- { children }
-
- { description &&
- { description }
- }
-
- )
+ useEffect(() => {
+ const value = sessionStorage.getItem('bank-signup-' + name)
+ if (value) {
+ const input = document.getElementById(name)
+ if (input) input.value = value
+ }
+ }, [name])
+
+ return (
+
+
+
+
+ {isRequired && (
+
+ Required
+
+ )}
+
+ {children}
+
+ {description && (
+ {description}
+ )}
+
+ )
}
diff --git a/components/bank/apply/form-container.js b/components/bank/apply/form-container.js
index 78f67471..2eadc9e5 100644
--- a/components/bank/apply/form-container.js
+++ b/components/bank/apply/form-container.js
@@ -1,29 +1,29 @@
import { forwardRef } from 'react'
import { Box } from 'theme-ui'
-const formContainer = forwardRef(({ children }, ref) => {
- return (
-
- { children }
-
- )
+const formContainer = forwardRef(({ children }, ref) => {
+ return (
+
+ {children}
+
+ )
})
-https://stackoverflow.com/a/67993106/10652680
-formContainer.displayName = 'formContainer'
-export default formContainer
\ No newline at end of file
+//stackoverflow.com/a/67993106/10652680
+https: formContainer.displayName = 'formContainer'
+export default formContainer
diff --git a/components/bank/apply/nav-button.js b/components/bank/apply/nav-button.js
index d529bfd5..6df3c92b 100644
--- a/components/bank/apply/nav-button.js
+++ b/components/bank/apply/nav-button.js
@@ -3,156 +3,171 @@ import { useEffect, useState } from 'react'
import { Button, Flex, Text, Spinner } from 'theme-ui'
async function sendApplication() {
- // Get the form data from sessionStorage
- const data = {}
- for (let i = 0; i < sessionStorage.length; i++) {
- const key = sessionStorage.key(i)
- if (key.startsWith('bank-signup-')) {
- data[key.replace('bank-signup-', '')] = sessionStorage.getItem(key)
- }
+ // Get the form data from sessionStorage
+ const data = {}
+ for (let i = 0; i < sessionStorage.length; i++) {
+ const key = sessionStorage.key(i)
+ if (key.startsWith('bank-signup-')) {
+ data[key.replace('bank-signup-', '')] = sessionStorage.getItem(key)
}
- console.dir('Sending data:', data)
+ }
+ console.dir('Sending data:', data)
- // Send the data
- try {
- const res = await fetch('/api/bank/apply', {
- method: 'POST',
- cors: 'no-cors',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(data),
- })
- } catch (error) {
- console.error(error);
- }
-}
-
-function NavIcon({ isBack }) {
- const style = {
- height: '1em',
- fill: 'white',
- margin: 0,
- flexShrink: 0,
- }
-
- return isBack ?
-
- :
-
+ // Send the data
+ try {
+ const res = await fetch('/api/bank/apply', {
+ method: 'POST',
+ cors: 'no-cors',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data)
+ })
+ } catch (error) {
+ console.error(error)
+ }
}
-export default function NavButton({ isBack, form, clickHandler, requiredFields, setFormError }) {
- const router = useRouter()
- const [spinner, setSpinner] = useState(false)
+function NavIcon({ isBack }) {
+ const style = {
+ height: '1em',
+ fill: 'white',
+ margin: 0,
+ flexShrink: 0
+ }
- useEffect(() => {
- setSpinner(false)
- }, [router.query.step])
+ return isBack ? (
+
+ ) : (
+
+ )
+}
- const minStep = 1
- const maxStep = 3
+export default function NavButton({
+ isBack,
+ form,
+ clickHandler,
+ requiredFields,
+ setFormError
+}) {
+ const router = useRouter()
+ const [spinner, setSpinner] = useState(false)
- const click = async () => {
- setSpinner(true)
+ useEffect(() => {
+ setSpinner(false)
+ }, [router.query.step])
- let step = parseInt(router.query.step)
+ const minStep = 1
+ const maxStep = 3
- async function setStep(s) {
- await router.push({
- pathname: router.pathname,
- query: { ...router.query, step: s } },
- undefined,
- {}
- )
- }
+ const click = async () => {
+ setSpinner(true)
- 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('/bank')
- return
- } else if (step < minStep) {
- // Set the step query param to minStep if it's lower than that.
- await setStep(minStep)
- }
+ let step = parseInt(router.query.step)
- /* Don't return from inside the loop since
- we want all input values to be saved every time */
- let wasError = false;
-
- // Save form data
- new FormData(form.current).forEach((value, key) => {
- sessionStorage.setItem('bank-signup-' + key, value)
-
- // Check if there are empty required fields.
- if (
- !isBack &&
- (!value || value.trim() === "")
- && requiredFields[step - 1].includes(key)
- ) {
- setFormError("Please fill all required fields")
- wasError = true
- setSpinner(false)
- }
- })
- if (wasError) return
-
- // Run the parent's click handler for this button.
- if (clickHandler) await clickHandler()
-
- if (step >= maxStep && !isBack) {
- await sendApplication()
- await router.push('/bank/apply/success')
- return
- } else {
- step += isBack ? -1 : 1
- }
- await setStep(step)
+ async function setStep(s) {
+ await router.push(
+ {
+ pathname: router.pathname,
+ query: { ...router.query, step: s }
+ },
+ undefined,
+ {}
+ )
}
- return (
-
+ )
+}
diff --git a/components/bank/apply/org-form.js b/components/bank/apply/org-form.js
index a174b8d8..3bb3c484 100644
--- a/components/bank/apply/org-form.js
+++ b/components/bank/apply/org-form.js
@@ -6,70 +6,78 @@ import Field from './field'
import AutofillColourFix from './autofill-colour-fix'
export default function OrganizationInfoForm({ requiredFields }) {
- const [org, setOrg] = useState('organization')
+ const [org, setOrg] = useState('organization')
- useEffect(() => {
- if (navigator.language === 'en-GB') setOrg('organisation')
- }, [])
+ useEffect(() => {
+ if (navigator.language === 'en-GB') setOrg('organisation')
+ }, [])
- return (
- <>
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
- >
- )
-}
\ No newline at end of file
+ requiredFields={requiredFields}
+ >
+
+
+
+
+
+ >
+ )
+}
diff --git a/components/bank/apply/personal-form.js b/components/bank/apply/personal-form.js
index e3f3445f..b320706e 100644
--- a/components/bank/apply/personal-form.js
+++ b/components/bank/apply/personal-form.js
@@ -4,87 +4,105 @@ import AddressInput from './address-input'
import Field from './field'
import AutofillColourFix from './autofill-colour-fix'
-export default function PersonalInfoForm({ setValidationResult, requiredFields }) {
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- )
-}
\ No newline at end of file
+export default function PersonalInfoForm({
+ setValidationResult,
+ requiredFields
+}) {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/components/bank/apply/progress.js b/components/bank/apply/progress.js
index 092d38f8..a82976f9 100644
--- a/components/bank/apply/progress.js
+++ b/components/bank/apply/progress.js
@@ -31,16 +31,16 @@ function StepIcon({ completed, number }) {
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
- inset: '0',
+ inset: '0'
}}
>
- { number }
+ {number}
@@ -51,10 +51,14 @@ function Step({ number, label, completed }) {
return (
- {label}
+
+ {label}
+
)
}
@@ -63,11 +67,7 @@ export default function Progress() {
const router = useRouter()
const step = parseInt(router.query.step)
- const labels = [
- 'Intro',
- 'Organization info',
- 'Personal info'
- ]
+ const labels = ['Intro', 'Organization info', 'Personal info']
return (
)
-}
\ No newline at end of file
+}
diff --git a/components/bank/apply/watermark.js b/components/bank/apply/watermark.js
index 94ad2670..a6b6323c 100644
--- a/components/bank/apply/watermark.js
+++ b/components/bank/apply/watermark.js
@@ -2,81 +2,81 @@ import React, { useRef, useEffect } from 'react'
import { Box } from 'theme-ui'
export default function Watermark() {
- /* This is going to come back to haunt me one day.
+ /* This is going to come back to haunt me one day.
It's an abomination but it works ... for now */
- const shineRef = useRef()
- const svgRef = useRef()
+ const shineRef = useRef()
+ const svgRef = useRef()
- // Mouse move event
- const handleMouseMove = ({ clientX, clientY }) => {
- if (!shineRef.current || !svgRef.current) return
-
- const svgWidth = svgRef.current.clientWidth / 100
- const svgFromTop = svgRef.current.getBoundingClientRect().top
- const svgFromLeft = svgRef.current.getBoundingClientRect().left
+ // Mouse move event
+ const handleMouseMove = ({ clientX, clientY }) => {
+ if (!shineRef.current || !svgRef.current) return
- shineRef.current.style.top = `${clientY / svgWidth + 6.2}px`
- shineRef.current.style.left = `${clientX / svgWidth + 9.2}px`
- }
+ const svgWidth = svgRef.current.clientWidth / 100
+ const svgFromTop = svgRef.current.getBoundingClientRect().top
+ const svgFromLeft = svgRef.current.getBoundingClientRect().left
- // Bind event
- useEffect(() => {
- window.addEventListener('mousemove', handleMouseMove)
- return () => window.removeEventListener('mousemove', handleMouseMove)
- }, [])
+ shineRef.current.style.top = `${clientY / svgWidth + 6.2}px`
+ shineRef.current.style.left = `${clientX / svgWidth + 9.2}px`
+ }
- return (
- {
+ window.addEventListener('mousemove', handleMouseMove)
+ return () => window.removeEventListener('mousemove', handleMouseMove)
+ }, [])
+
+ return (
+
+
+
+
+
+
+ )
+}
diff --git a/components/bank/features.js b/components/bank/features.js
index 9156245d..6fd44b12 100644
--- a/components/bank/features.js
+++ b/components/bank/features.js
@@ -27,7 +27,8 @@ export default function Features({ partner = false }) {
name="Bank account"
body={
<>
- Bank account under the hood with a custom, beautiful dashboard.
+ Bank account under the hood with a custom, beautiful
+ dashboard.
>
}
/>
diff --git a/components/bank/start.js b/components/bank/start.js
index d9915927..f0e27c08 100644
--- a/components/bank/start.js
+++ b/components/bank/start.js
@@ -18,30 +18,33 @@ export default function Start() {
return (
<>
-
+
Sign up for Hack Club Bank.
-
- Open to Hack Clubs, hackathons, and charitable organizations in the US and Canada.
+
+ Open to Hack Clubs, hackathons, and charitable organizations in
+ the US and Canada.
-
+
- We run Hack Club HQ on Bank!{' '}
-
+
+ We run Hack Club HQ on Bank!{' '}
+
See our finances.
diff --git a/components/bank/stats.js b/components/bank/stats.js
index 37895fe7..8bec17a4 100644
--- a/components/bank/stats.js
+++ b/components/bank/stats.js
@@ -1,35 +1,40 @@
import { Text, Box, Flex } from 'theme-ui'
import { useEffect, useState } from 'react'
-const easeInOutExpo = (x) =>
+const easeInOutExpo = x =>
x === 0
? 0
: x === 1
? 1
: x < 0.5
? Math.pow(2, 20 * x - 10) / 2
- : (2 - Math.pow(2, -20 * x + 10)) / 2;
-
-function startMoneyAnimation(setBalance, amount, duration = 2_000, moneyFormatter) {
- const startTime = performance.now();
+ : (2 - Math.pow(2, -20 * x + 10)) / 2
+
+function startMoneyAnimation(
+ setBalance,
+ amount,
+ duration = 2_000,
+ moneyFormatter
+) {
+ const startTime = performance.now()
function animate() {
- const time = performance.now() - startTime;
- const progress = time / duration;
- const easedProgress = easeInOutExpo(progress);
+ const time = performance.now() - startTime
+ const progress = time / duration
+ const easedProgress = easeInOutExpo(progress)
setBalance(moneyFormatter(amount * easedProgress))
if (progress < 1) {
- requestAnimationFrame(animate);
+ requestAnimationFrame(animate)
} else {
setBalance(moneyFormatter(amount))
}
}
- requestAnimationFrame(animate);
+ requestAnimationFrame(animate)
}
-
+
function formatMoney(amount) {
const normalisedAmount = amount / 100
return normalisedAmount
@@ -39,7 +44,7 @@ function formatMoney(amount) {
const Stats = () => {
const [transactedRaw, setTransactedRaw] = useState() // The raw amount transacted (in cents).
- const [balance, setBalance] = useState(0) // A formatted balance string, split by decimal
+ const [balance, setBalance] = useState(0) // A formatted balance string, split by decimal
useEffect(() => {
if (!transactedRaw) {
@@ -53,42 +58,49 @@ const Stats = () => {
}
let observer = new IntersectionObserver(
- (e) => {
+ e => {
if (e[0].isIntersecting) {
console.info('intersecting')
startMoneyAnimation(setBalance, transactedRaw, 2_500, formatMoney)
}
},
{ threshold: 1.0 }
- );
- observer.observe(document.querySelector("#parent"));
+ )
+ observer.observe(document.querySelector('#parent'))
- return () => observer.disconnect();
+ return () => observer.disconnect()
}, [transactedRaw])
return (
-
+
-
- So far we have enabled
-
- { transactedRaw ?
+ So far we have enabled
+ {transactedRaw ? (
<>
-
- { balance[0] }
- .{ balance[1] }
+ {balance[0]}
+ .{balance[1]}
>
- :
- ...
- }
+ ) : (
+
+ ...
+
+ )}
in transactions
diff --git a/components/bank/timeline.js b/components/bank/timeline.js
index a221cca3..cff5fc5b 100644
--- a/components/bank/timeline.js
+++ b/components/bank/timeline.js
@@ -3,22 +3,29 @@ import Slide from 'react-reveal'
function Step({ stepIndex, label }) {
return (
-
+
- {label}
+
+ {label}
+
)
}
@@ -30,29 +37,35 @@ export default function Timeline() {
'Hop on an intro call with the Bank team',
'Start fundraising!'
]
- const stepSideLength = 64;
+ const stepSideLength = 64
return (
-
- {labels.map((label, idx) => )}
-
+
+ {labels.map((label, idx) => (
+
+ ))}
+
)
diff --git a/components/dot.js b/components/dot.js
index 6385c7e6..d6028452 100644
--- a/components/dot.js
+++ b/components/dot.js
@@ -7,7 +7,7 @@ const flashing = keyframes({
to: { opacity: 0 }
})
-export default function Dot({hideOnMobile}) {
+export default function Dot({ hideOnMobile }) {
return (
- { children }
-
- )
-}
\ No newline at end of file
+ return {children}
+}
diff --git a/components/hackathons/features/money.js b/components/hackathons/features/money.js
index 3738fa47..b18fe402 100644
--- a/components/hackathons/features/money.js
+++ b/components/hackathons/features/money.js
@@ -21,10 +21,7 @@ const Content = () => (
Hack Club Bank
-
+
Grants, waived fees, and more!
@@ -39,8 +36,8 @@ const Content = () => (
}
body={
<>
- Running on Bank? Get a $500 grant once you have a venue,
- provided by Hack Club with the help of{' '}
+ Running on Bank? Get a $500 grant once you have a venue, provided
+ by Hack Club with the help of{' '}
The best way to learn is by building.
- A hackathon is a space that helps give makers everything they
- need to start building–mentors, collaborators, inspiration, and
- a goal to work towards. Hackers will leave a hackathon with a
- project of their own, ready and excited to keep hacking once
- they get home.
+ A hackathon is a space that helps give makers everything they need
+ to start building–mentors, collaborators, inspiration, and a goal
+ to work towards. Hackers will leave a hackathon with a project of
+ their own, ready and excited to keep hacking once they get home.
@@ -35,13 +34,29 @@ export default function Overview() {
Hack Club is a global community of thousands of high school
makers. We're organizers, coders, hackers, painters, engineers,
- musicians, writers, volunteers. We make things. We want others
- to make things too.
+ musicians, writers, volunteers. We make things. We want others to
+ make things too.
-
-
+
+
@@ -53,7 +68,13 @@ function Highlight({ children }) {
return (
{children}
diff --git a/components/hackathons/scrolling-hackathons.js b/components/hackathons/scrolling-hackathons.js
index 7fcf3f32..f61caf69 100644
--- a/components/hackathons/scrolling-hackathons.js
+++ b/components/hackathons/scrolling-hackathons.js
@@ -43,9 +43,23 @@ export default function ScrollingHackathons({
>
Join other high-schoolers at an upcoming hackathon.
-
-
-
+
+
+
+
+
from{' '}
diff --git a/components/index/cards/button.js b/components/index/cards/button.js
index 259daa78..7b3b2eb4 100644
--- a/components/index/cards/button.js
+++ b/components/index/cards/button.js
@@ -33,16 +33,15 @@ export default function Buttons({
alignItems: 'center',
color: 'inherit',
px: '3',
- py: primary ? '12px' : 2,
+ py: primary ? '12px' : 2,
width: 'fit-content',
textTransform: 'none',
fontWeight: '400',
- fontSize:
- primary ? ['18px', '20px', '22px'] : [1, '16px', '18px'],
+ fontSize: primary ? ['18px', '20px', '22px'] : [1, '16px', '18px'],
backdropFilter: 'blur(2px)',
fontWeight: fontWeight
}}
- as='a'
+ as="a"
href={link || '/'}
target="_blank"
rel="noreferrer"
diff --git a/components/index/cards/card-model.js b/components/index/cards/card-model.js
index e94661a4..f1e202b3 100644
--- a/components/index/cards/card-model.js
+++ b/components/index/cards/card-model.js
@@ -148,7 +148,7 @@ const CardModel = ({
mt: ['-24px', '-32px', '-32px', '-32px'],
zIndex: 0
}}
- alt=''
+ alt=""
/>
)}
{children}
diff --git a/components/index/cards/epoch.js b/components/index/cards/epoch.js
index 4ddbb876..788c886e 100644
--- a/components/index/cards/epoch.js
+++ b/components/index/cards/epoch.js
@@ -129,7 +129,7 @@ export default function Epoch() {
ml: ['-24px', '-32px', '-32px', '-32px'],
mt: ['-24px', '-32px', '-32px', '-32px']
}}
- alt='Hack Club Presents Epoch background'
+ alt="Hack Club Presents Epoch background"
/>
@@ -140,7 +140,7 @@ export default function Epoch() {
position: 'relative',
zIndex: 2
}}
- alt='Hack Club Presents Epoch header'
+ alt="Hack Club Presents Epoch header"
/>
{timer.length ? (
diff --git a/components/index/cards/slack.js b/components/index/cards/slack.js
index 8c96d9b6..03fdb32a 100644
--- a/components/index/cards/slack.js
+++ b/components/index/cards/slack.js
@@ -64,7 +64,7 @@ export default function Slack({ data, slackKey, events }) {
ml: ['-24px', '-32px', '-32px', '-32px'],
mt: ['-24px', '-32px', '-32px', '-32px']
}}
- alt='Slack AMA'
+ alt="Slack AMA"
/>
diff --git a/components/index/cards/sprig-console.js b/components/index/cards/sprig-console.js
index 7a40781b..3e5455ae 100644
--- a/components/index/cards/sprig-console.js
+++ b/components/index/cards/sprig-console.js
@@ -5,7 +5,6 @@ import Tilt from '../../tilt'
/** @jsxImportSource theme-ui */
-
export default function SprigConsole({ stars, consoleCount }) {
return (
@@ -34,7 +33,7 @@ export default function SprigConsole({ stars, consoleCount }) {
mt: '-24px',
zIndex: 0
}}
- alt='Printed circuit board'
+ alt="Printed circuit board"
/>
{user}
@@ -65,8 +60,8 @@ export default function GitHub({
maxWidth: '100%',
display: 'inline-block',
overflow: 'hidden',
- whiteSpace: 'nowrap',
- flexShrink: 1,
+ whiteSpace: 'nowrap',
+ flexShrink: 1
}}
>
{message}
@@ -78,7 +73,7 @@ export default function GitHub({
color: 'inherit',
mx: 2,
flexShrink: 0,
- ml: 'auto',
+ ml: 'auto'
}}
>
diff --git a/components/secret.js b/components/secret.js
index 85f7b48e..bb19dc03 100644
--- a/components/secret.js
+++ b/components/secret.js
@@ -123,7 +123,7 @@ export default function Secret({ reveal, ...props }) {
src={img}
width="30%"
sx={{ margin: 'auto' }}
- alt='a secret dino!'
+ alt="a secret dino!"
/>
print kc
diff --git a/components/tilt.js b/components/tilt.js
index 20f0b5ae..30862a74 100644
--- a/components/tilt.js
+++ b/components/tilt.js
@@ -4,7 +4,7 @@ import VanillaTilt from 'vanilla-tilt'
// NOTE(@lachlanjc): only pass one child!
const Tilt = ({ options = {}, children, ...props }) => {
const root = useRef(null)
-
+
useEffect(() => {
VanillaTilt.init(root.current, {
max: 7.5,
diff --git a/lib/bank/apply/address-validation.js b/lib/bank/apply/address-validation.js
index f4bbdb86..6166f7b3 100644
--- a/lib/bank/apply/address-validation.js
+++ b/lib/bank/apply/address-validation.js
@@ -1,81 +1,83 @@
async function getOrRefreshToken() {
- // Get the token from localStorage
- const token = JSON.parse(localStorage.getItem('mapkit-token'))
- if (token) {
- // If the token is still valid, return it
- if (Date.now() < token.refreshBefore) return token.accessToken
- } else {
- // The token is invalid or doesn't exist, so get a new one
+ // Get the token from localStorage
+ const token = JSON.parse(localStorage.getItem('mapkit-token'))
+ if (token) {
+ // If the token is still valid, return it
+ if (Date.now() < token.refreshBefore) return token.accessToken
+ } else {
+ // The token is invalid or doesn't exist, so get a new one
- // This is a MapKit master token, restricted to https://hackclub.com
- const master = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkNSQkg2S1VLTEIifQ.eyJpc3MiOiJQNlBWMlI5NDQzIiwiaWF0IjoxNjc5NjY3NjIyLCJleHAiOjE3MTEyMzg0MDB9.E6g9QPdbEWLgF6tdcL0YfX8NescYnwKhQpXdiyRitNm7-Oot-3VH0ze9xUd8xkOzuS_-7KeWy4bfYTD-2yX7Sg';
-
- // Get a MapKit server token
- const res = await fetch('https://maps-api.apple.com/v1/token', {
- headers: { Authorization: `Bearer ${master}` },
- })
- const resJson = await res.json()
-
- // Set the token's expiration time to 10 seconds before the actual expiration time
- resJson.refreshBefore = Date.now() + (resJson.expiresInSeconds * 1_000) - 10_000
+ // This is a MapKit master token, restricted to https://hackclub.com
+ const master =
+ 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkNSQkg2S1VLTEIifQ.eyJpc3MiOiJQNlBWMlI5NDQzIiwiaWF0IjoxNjc5NjY3NjIyLCJleHAiOjE3MTEyMzg0MDB9.E6g9QPdbEWLgF6tdcL0YfX8NescYnwKhQpXdiyRitNm7-Oot-3VH0ze9xUd8xkOzuS_-7KeWy4bfYTD-2yX7Sg'
- // Save the token to localStorage
- localStorage.setItem('mapkit-token', JSON.stringify(resJson))
+ // Get a MapKit server token
+ const res = await fetch('https://maps-api.apple.com/v1/token', {
+ headers: { Authorization: `Bearer ${master}` }
+ })
+ const resJson = await res.json()
- return resJson.accessToken
- }
+ // Set the token's expiration time to 10 seconds before the actual expiration time
+ resJson.refreshBefore =
+ Date.now() + resJson.expiresInSeconds * 1_000 - 10_000
+
+ // Save the token to localStorage
+ localStorage.setItem('mapkit-token', JSON.stringify(resJson))
+
+ return resJson.accessToken
+ }
}
//TODO: Limit the number of retries
export async function search(query) {
- if (!query.trim()) return
-
- const token = await getOrRefreshToken()
+ if (!query.trim()) return
- const res = await fetch(`https://maps-api.apple.com/v1/search?q=${query}`, {
- headers: { Authorization: `Bearer ${token}` },
- })
- const resJson = await res.json()
-
- if (resJson.error) {
- if (resJson.error.message === 'Not Authorized') {
- // The token is invalid, so remove it from localStorage
- localStorage.removeItem('mapkit-token')
+ const token = await getOrRefreshToken()
- // Try again
- console.warn('MapKit token expired, refreshing')
- return search(query)
- } else {
- throw new Error(resJson.error.message)
- }
+ const res = await fetch(`https://maps-api.apple.com/v1/search?q=${query}`, {
+ headers: { Authorization: `Bearer ${token}` }
+ })
+ const resJson = await res.json()
+
+ if (resJson.error) {
+ if (resJson.error.message === 'Not Authorized') {
+ // The token is invalid, so remove it from localStorage
+ localStorage.removeItem('mapkit-token')
+
+ // Try again
+ console.warn('MapKit token expired, refreshing')
+ return search(query)
+ } else {
+ throw new Error(resJson.error.message)
}
+ }
- return resJson
+ return resJson
}
export async function geocode(query) {
- if (!query.trim()) return
+ if (!query.trim()) return
- const token = await getOrRefreshToken()
+ const token = await getOrRefreshToken()
- const res = await fetch(`https://maps-api.apple.com/v1/geocode?q=${query}`, {
- headers: { Authorization: `Bearer ${token}` },
- })
- const resJson = await res.json()
-
- if (resJson.error) {
- if (resJson.error.message === 'Not Authorized') {
- // The token is invalid, so remove it from localStorage
- localStorage.removeItem('mapkit-token')
+ const res = await fetch(`https://maps-api.apple.com/v1/geocode?q=${query}`, {
+ headers: { Authorization: `Bearer ${token}` }
+ })
+ const resJson = await res.json()
- // Try again
- console.warn('MapKit token expired, refreshing')
- return geocode(query)
- } else {
- throw new Error(resJson.error.message)
- }
+ if (resJson.error) {
+ if (resJson.error.message === 'Not Authorized') {
+ // The token is invalid, so remove it from localStorage
+ localStorage.removeItem('mapkit-token')
+
+ // Try again
+ console.warn('MapKit token expired, refreshing')
+ return geocode(query)
+ } else {
+ throw new Error(resJson.error.message)
}
+ }
- return resJson
-}
\ No newline at end of file
+ return resJson
+}
diff --git a/pages/api/bank/apply.js b/pages/api/bank/apply.js
index bcb05afc..da5679ba 100644
--- a/pages/api/bank/apply.js
+++ b/pages/api/bank/apply.js
@@ -18,7 +18,7 @@ export default async function handler(req, res) {
method: 'POST',
headers: {
'Content-Type': 'application/json',
- Authorization: `Bearer ${process.env.HCB_API_TOKEN || ""}`
+ Authorization: `Bearer ${process.env.HCB_API_TOKEN || ''}`
}
})
.then(r => r.json())
@@ -35,15 +35,16 @@ export default async function handler(req, res) {
'Mailing Address': data.mailingAddress,
'Address Line 1': data.addressLine1,
'Address Line 2': data.addressLine2,
- 'City': data.addressCity,
- 'State': data.addressState,
+ City: data.addressCity,
+ State: data.addressState,
'Zip Code': data.addressZip,
'Address Country': data.addressCountry,
- 'Country': data.eventCountry,
+ Country: data.eventCountry,
'Event Location': data.eventLocation,
- 'Have you used Hack Club Bank for any previous events?': data.returningUser,
+ 'Have you used Hack Club Bank for any previous events?':
+ data.returningUser,
'How did you hear about HCB?': data.referredBy,
- 'Transparent': data.transparent,
+ Transparent: data.transparent,
'HCB account URL': `https://bank.hackclub.com/${r.slug}`
})
res.writeHead(302, { Location: '/bank/apply/success' }).end()
diff --git a/pages/bank/apply.js b/pages/bank/apply.js
index a6593fe2..beca604d 100644
--- a/pages/bank/apply.js
+++ b/pages/bank/apply.js
@@ -34,10 +34,12 @@ export default function Apply() {
// Set the query url parameter to 1 if it's not present
if (!step || step < 1) {
- router.push({
- pathname: router.pathname,
- query: { ...router.query, step: 1 } },
- undefined,
+ router.push(
+ {
+ pathname: router.pathname,
+ query: { ...router.query, step: 1 }
+ },
+ undefined,
{}
)
}
@@ -47,9 +49,9 @@ export default function Apply() {
<>
-
+
@@ -61,7 +63,7 @@ export default function Apply() {
'"title" "form" "form" "nav"',
null,
null,
- '"title form" "title form" "nav form"',
+ '"title form" "title form" "nav form"'
],
height: ['auto', null, null, '100vh'],
p: [4, 5]
@@ -69,15 +71,21 @@ export default function Apply() {
>
- Let's get you set up on bank.
+
+ Let's get you
+
+ set up on bank.
+
- { step === 1 && }
- { step === 2 && }
- { step === 3 && }
+ {step === 1 && }
+ {step === 2 && (
+
+ )}
+ {step === 3 && }
@@ -100,14 +108,16 @@ export default function Apply() {
// Validate the address
if (step === 3) {
// Get the raw personal address input
- const userAddress = sessionStorage.getItem('bank-signup-userAddressRaw')
+ const userAddress = sessionStorage.getItem(
+ 'bank-signup-userAddressRaw'
+ )
if (!userAddress) return
-
+
const result = await geocode(userAddress)
- const addrComp = (type) =>
+ const addrComp = type =>
result.results[0].structuredAddress[type]
-
+
const thoroughfare = addrComp('fullThoroughfare')
const city = addrComp('locality')
const state = addrComp('administrativeArea')
@@ -118,9 +128,18 @@ export default function Apply() {
sessionStorage.setItem('bank-signup-addressLine1', thoroughfare)
sessionStorage.setItem('bank-signup-addressCity', city ?? '')
sessionStorage.setItem('bank-signup-addressState', state ?? '')
- sessionStorage.setItem('bank-signup-addressZip', postalCode ?? '')
- sessionStorage.setItem('bank-signup-addressCountry', country ?? '')
- sessionStorage.setItem('bank-signup-addressCountryCode', countryCode ?? '')
+ sessionStorage.setItem(
+ 'bank-signup-addressZip',
+ postalCode ?? ''
+ )
+ sessionStorage.setItem(
+ 'bank-signup-addressCountry',
+ country ?? ''
+ )
+ sessionStorage.setItem(
+ 'bank-signup-addressCountryCode',
+ countryCode ?? ''
+ )
}
}}
/>
diff --git a/pages/bank/fiscal-sponsorship.js b/pages/bank/fiscal-sponsorship.js
index 7c7d6823..dc2337a1 100644
--- a/pages/bank/fiscal-sponsorship.js
+++ b/pages/bank/fiscal-sponsorship.js
@@ -10,467 +10,476 @@ import Footer from '../../components/footer'
import Icon from '../../components/icon'
import Tilt from '../../components/tilt'
-function Bullet({ glow=true, icon, href, children }) {
- let effectColours = [
- '#ec3750',
- '#ff8c37',
- '#f1c40f',
- '#33d6a6',
- '#5bc0de',
- '#338eda',
- '#a633d6',
- ]
+function Bullet({ glow = true, icon, href, children }) {
+ let effectColours = [
+ '#ec3750',
+ '#ff8c37',
+ '#f1c40f',
+ '#33d6a6',
+ '#5bc0de',
+ '#338eda',
+ '#a633d6'
+ ]
- // Raw doggen this trig, no AI this is natty
- function keyframeGenerator(spread, blur, colours, opacity = 0.5) {
- let hexOpacity =
- Math.max(Math.min(Math.round(opacity * 255), 255), 0).toString(16).padStart(2, '0');
+ // Raw doggen this trig, no AI this is natty
+ function keyframeGenerator(spread, blur, colours, opacity = 0.5) {
+ let hexOpacity = Math.max(Math.min(Math.round(opacity * 255), 255), 0)
+ .toString(16)
+ .padStart(2, '0')
- let final = {}
- for (let i = 0; i <= 100; i++) {
- let baseX = Math.sin(i * Math.PI / 50) // 50 keyframes for each pi radians
- let baseY = -Math.cos(i * Math.PI / 50)
+ let final = {}
+ for (let i = 0; i <= 100; i++) {
+ let baseX = Math.sin((i * Math.PI) / 50) // 50 keyframes for each pi radians
+ let baseY = -Math.cos((i * Math.PI) / 50)
- // Ensure no scientific notation
- const roundFactor = 1_000_000
- baseX = Math.round(baseX * roundFactor) / roundFactor
- baseY = Math.round(baseY * roundFactor) / roundFactor
+ // Ensure no scientific notation
+ const roundFactor = 1_000_000
+ baseX = Math.round(baseX * roundFactor) / roundFactor
+ baseY = Math.round(baseY * roundFactor) / roundFactor
- let boxShadow = ''
- for (let c = 0; c < colours.length; c++) {
- // Rotate by 2pi / colours.length * c radians
- let x = baseX * Math.cos(2 * Math.PI * c / colours.length) - baseY * Math.sin(2 * Math.PI * c / colours.length)
- let y = baseX * Math.sin(2 * Math.PI * c / colours.length) + baseY * Math.cos(2 * Math.PI * c / colours.length)
+ let boxShadow = ''
+ for (let c = 0; c < colours.length; c++) {
+ // Rotate by 2pi / colours.length * c radians
+ let x =
+ baseX * Math.cos((2 * Math.PI * c) / colours.length) -
+ baseY * Math.sin((2 * Math.PI * c) / colours.length)
+ let y =
+ baseX * Math.sin((2 * Math.PI * c) / colours.length) +
+ baseY * Math.cos((2 * Math.PI * c) / colours.length)
- boxShadow += `${x * spread}px ${y * spread}px ${blur}px ${colours[c]}${hexOpacity},`
- }
+ boxShadow += `${x * spread}px ${y * spread}px ${blur}px ${
+ colours[c]
+ }${hexOpacity},`
+ }
- // Remove trailing comma
- boxShadow = boxShadow.slice(0, -1)
+ // Remove trailing comma
+ boxShadow = boxShadow.slice(0, -1)
- final[i + '%'] = { boxShadow }
- }
-
- return final
+ final[i + '%'] = { boxShadow }
}
- const shadowSpread = glow ? 5 : 0
- const shadowBlur = glow ? 10 : 0
- const animatedBoxShadow = keyframes(keyframeGenerator(shadowSpread, shadowBlur, effectColours))
+ return final
+ }
- const borderWidth = '2px'
+ const shadowSpread = glow ? 5 : 0
+ const shadowBlur = glow ? 10 : 0
+ const animatedBoxShadow = keyframes(
+ keyframeGenerator(shadowSpread, shadowBlur, effectColours)
+ )
- return (
-
-
+
-
- {children}
- { href &&
-
- }
-
-
- )
+ textDecoration: 'none',
+ color: 'inherit',
+
+ backgroundColor: 'var(--theme-ui-colors-darkless)',
+
+ '&:hover::after': {
+ content: '""',
+ position: 'absolute',
+ inset: 0,
+ boxShadow: `linear-gradient(60deg, ${effectColours[0]}, ${effectColours[1]}, ${effectColours[2]}, ${effectColours[3]}, ${effectColours[4]})`,
+ borderRadius: 'inherit',
+ zIndex: -1,
+ animation: `${animatedBoxShadow} 5s ease infinite`
+ }
+ }}
+ >
+
+ {children}
+ {href && (
+
+ )}
+
+
+ )
}
-function BulletBox({ padding='2rem', children }) {
- return (
-
- { children }
-
- )
+function BulletBox({ padding = '2rem', children }) {
+ return (
+
+ {children}
+
+ )
}
function Section({ id, children }) {
- return (
-
- { children }
-
- )
+ return (
+
+ {children}
+
+ )
}
export default function FiscalSponsorship() {
- const gridRef = useRef()
- const glowRef = useRef()
+ const gridRef = useRef()
+ const glowRef = useRef()
- const scrollPos = useRef(0)
- const mousePos = useRef([0, 0])
+ const scrollPos = useRef(0)
+ const mousePos = useRef([0, 0])
- const setGlowMaskPosition = () => {
- const finalPos = [-mousePos.current[0], -mousePos.current[1] + scrollPos.current]
- glowRef.current.style.maskPosition = `${finalPos[0]}px ${finalPos[1]}px`;
- glowRef.current.style.WebkitMaskPosition = `${finalPos[0]}px ${finalPos[1]}px`;
+ const setGlowMaskPosition = () => {
+ const finalPos = [
+ -mousePos.current[0],
+ -mousePos.current[1] + scrollPos.current
+ ]
+ glowRef.current.style.maskPosition = `${finalPos[0]}px ${finalPos[1]}px`
+ glowRef.current.style.WebkitMaskPosition = `${finalPos[0]}px ${finalPos[1]}px`
+ }
+
+ useEffect(() => {
+ const handleScroll = e => {
+ scrollPos.current = -window.scrollY / 10
+
+ gridRef.current.style.transform = `translateY(${scrollPos.current}px)`
+
+ setGlowMaskPosition()
}
- useEffect(() => {
- const handleScroll = (e) => {
- scrollPos.current = -window.scrollY / 10
+ const handleMouseMove = e => {
+ const x = e.clientX
+ const y = e.clientY
+ glowRef.current.style.left = x + 'px'
+ glowRef.current.style.top = y + 'px'
- gridRef.current.style.transform = `translateY(${scrollPos.current}px)`
+ mousePos.current = [x, y]
+ setGlowMaskPosition()
+ }
- setGlowMaskPosition()
- }
+ window.addEventListener('scroll', handleScroll)
+ window.addEventListener('mousemove', handleMouseMove)
+ return () => {
+ window.removeEventListener('scroll', handleScroll)
+ window.removeEventListener('mousemove', handleMouseMove)
+ }
+ }, [])
- const handleMouseMove = (e) => {
- const x = e.clientX
- const y = e.clientY
- glowRef.current.style.left = x + 'px'
- glowRef.current.style.top = y + 'px'
-
- mousePos.current = [x, y]
- setGlowMaskPosition()
- }
-
- window.addEventListener('scroll', handleScroll)
- window.addEventListener('mousemove', handleMouseMove)
- return () => {
- window.removeEventListener('scroll', handleScroll)
- window.removeEventListener('mousemove', handleMouseMove)
- }
- }, [])
-
- return (
-
-
-
+
-
+
+
+
+
+ Fiscal Sponsorship — Hack Club Bank
+
+
+
+
+
+ Fiscal sponsorship
+
+ The fast track to{' '}
+
-
-
-
- Fiscal Sponsorship — Hack Club Bank
-
-
-
-
-
- Fiscal sponsorship
-
- The fast track to 501(c)(3) nonprofit
- status for your startup
-
-
-
- Building a project, event, or organization on a
- mission to serve the public good or your community?
- Obtaining 501(c)(3) public charity status in the U.S.
- just got easier through fiscal sponsorship.
-
+ >
+ 501(c)(3) nonprofit{' '}
+
+ status for your startup
+
+
+
+ Building a project, event, or organization on a mission to serve the
+ public good or your community? Obtaining 501(c)(3) public charity
+ status in the U.S. just got easier through fiscal sponsorship.
+
-
- Jump to:
-
- What’s Fiscal Sponsorship?
- Requirements for Fiscal Sponsorship
- Partner with Hack Club Bank
-
-
- <>
-
- Every year, thousands of organizations from around
- the world apply through the IRS to become a U.S. 501(c)(3)
- for charitable recognition and tax exemptions.
- The process for obtaining legal status can take anywhere
- from 2-12 months, and as a nonprofit organizer,
- it’s important to know that this can mean:
-
-
-
- $3,000 in up-front costs, from filing different
- applications and forms to support from legal counsel.
-
-
- The potential for the IRS to reject an application
- (and not return your money).
-
-
- An annual filing fee of $2,500.
-
-
- Hiring bookkeepers and accountants to prepare
- taxes and provide upkeep to stay in good standing.
-
-
- Up to $5,000 to close down shop if you lose or terminate status.
-
-
- >
-
- Unfortunately, between the price and time needed to
- organize a nonprofit, these barriers prevent many
- charitable initiatives from exiting an idea phase
- to go on to making a valuable impact throughout the world.
-
-
- So 501(c)(3) status is cool and all,
- but why go through the hassle of applying
- when it’s so expensive and time consuming?
-
+
+ Jump to:
+
+
+ What’s Fiscal Sponsorship?
+
+
+ Requirements for Fiscal Sponsorship
+
+
+ Partner with Hack Club Bank
+
+
+
+ <>
+
+ Every year, thousands of organizations from around the world apply
+ through the IRS to become a U.S. 501(c)(3) for charitable
+ recognition and tax exemptions. The process for obtaining legal
+ status can take anywhere from 2-12 months, and as a nonprofit
+ organizer, it’s important to know that this can mean:
+
+
+
+ $3,000 in up-front costs, from filing different applications and
+ forms to support from legal counsel.
+
+
+ The potential for the IRS to reject an application (and not
+ return your money).
+
+
+ An annual filing fee of $2,500.
+
+
+ Hiring bookkeepers and accountants to prepare taxes and provide
+ upkeep to stay in good standing.
+
+
+ Up to $5,000 to close down shop if you lose or terminate status.
+
+
+ >
+
+ Unfortunately, between the price and time needed to organize a
+ nonprofit, these barriers prevent many charitable initiatives from
+ exiting an idea phase to go on to making a valuable impact
+ throughout the world.
+
+
+ So 501(c)(3) status is cool and all, but why go through the hassle
+ of applying when it’s so expensive and time consuming?
+
-
- As a legally recognized 501(c)(3) nonprofit
- in the U.S., there are loads of legal tax
- benefits that make the status worth it, like:
-
-
-
- The ability to receive tax deductible
- donations from sponsors.
-
-
- Reduced taxable income for your U.S.
- supporters, which incentivizes giving.
-
-
- Exemption from U.S. federal
- income tax and unemployment tax.
-
-
- Potential exemption from state
- income, sales, and employment taxes.
-
-
- Potential for reduced rates on postage,
- marketing, advertising, legal counsel, and more.
-
-
-
- As it turns out, there’s an alternative route
- for startups, student-led initiatives,
- or anyone looking to avoid a headache
- with the IRS to obtain all the benefits of
- 501(c)(3) status. To avoid the traditional
- filing route, go for fiscal sponsorship.
-
+
+ As a legally recognized 501(c)(3) nonprofit in the U.S., there are
+ loads of legal tax benefits that make the status worth it, like:
+
+
+
+ The ability to receive tax deductible donations from
+ sponsors.
+
+
+ Reduced taxable income for your U.S. supporters, which{' '}
+ incentivizes giving.
+
+
+ Exemption from U.S. federal income tax and unemployment
+ tax.
+
+
+ Potential exemption from state income, sales, and employment
+ taxes.
+
+
+ Potential for reduced rates on postage, marketing, advertising,
+ legal counsel, and more.
+
+
+
+ As it turns out, there’s an alternative route for startups,
+ student-led initiatives, or anyone looking to avoid a headache with
+ the IRS to obtain all the benefits of 501(c)(3) status. To avoid the
+ traditional filing route, go for fiscal sponsorship.
+
-
-
- What’s Fiscal Sponsorship?
-
-
- By legally partnering with an existing
- nonprofit offering fiscal sponsorship,
- projects and events can claim all the
- legal benefits of individual 501(c)(3)
- status. Piggy-backing off this existing
- status, organizations also gain access
- to resources from their fiscal sponsor like:
-
-
-
- Bookkeeping and administration ensuring
- that all paperwork and taxes are filed.
-
-
- Fully established HR and benefits,
- which can vary by the fiscal sponsor.
-
-
- A board of directors - you
- don’t have to organize your own!
-
-
- Fully transparent operational fees,
- typically ranging from 7-12% that
- prevent you from paying operating costs.
-
-
- The ability to terminate your fiscal
- sponsorship agreement and file for
- separate tax-exempt status at any point.
-
-
-
- If you’re brand new to nonprofit organizing
- or unsure where your project will take you,
- fiscal sponsorship is a great tool to help
- manage your finances and gauge whether becoming
- an independent nonprofit down the line is
- practical or financially feasible.
-
-
- Fiscal sponsorship makes it so that hacks
- aren’t just for folding that stubborn fitted
- sheet or sending an email to hundreds of
- people in seconds; they’re also for obtaining
- nonprofit status.
-
-
-
-
-
- Requirements for Fiscal Sponsorship
-
-
- Depending on the fiscal sponsor you choose,
- requirements for working together can vary.
- Fiscal sponsors generally ask that your
- nonprofit’s goals be similar to theirs.
- They usually also ask that your organization
- or event commits to remaining charitable in
- nature and refrains from activites that may
- result in loss of 501(c)(3) status.
-
-
+
+ What’s Fiscal Sponsorship?
+
+ By legally partnering with an existing nonprofit offering fiscal
+ sponsorship, projects and events can claim all the legal benefits
+ of individual 501(c)(3) status. Piggy-backing off this existing
+ status, organizations also gain access to resources from their
+ fiscal sponsor like:
+
+
+
+ Bookkeeping and administration ensuring that all paperwork and
+ taxes are filed.
+
+
+ Fully established HR and benefits, which can vary by the fiscal
+ sponsor.
+
+
+ A board of directors - you don’t have to organize your own!
+
+
+ Fully transparent operational fees, typically ranging from 7-12%
+ that prevent you from paying operating costs.
+
+
+ The ability to terminate your fiscal sponsorship agreement and
+ file for separate tax-exempt status at any point.
+
+
+
+ If you’re brand new to nonprofit organizing or unsure where your
+ project will take you, fiscal sponsorship is a great tool to help
+ manage your finances and gauge whether becoming an independent
+ nonprofit down the line is practical or financially feasible.
+
+
+ Fiscal sponsorship makes it so that hacks aren’t just for folding
+ that stubborn fitted sheet or sending an email to hundreds of
+ people in seconds; they’re also for obtaining nonprofit status.
+
+
-
-
- Partner with Hack Club Bank
-
-
- While many fiscal sponsors require that their
- partners relate to their mission in similar ways,
- at Hack Club Bank, we’ve built our infrastructure
- to support hundreds of causes in all areas of
- charitability. Check out some of the resources
- we’ve built our fiscal sponsorship foundation on:
-
-
-
- A web interface that looks and operates
- just like a bank account
-
-
- Fee-free invoicing, ACH or check
- transfers, and reimbursements
-
-
- A customizable and embeddable
- donations URL
-
-
- Perks like Google Workspace,
- PVSA certification, and 1Password credits
-
-
- Optional transparency mode to show
- off finances to donors and the public
-
-
- 24 hour weekday turnaround time from a
- full-time support team for all queries
-
-
- ...and more!
-
-
-
- Looking for nonprofit status and not a religious or
- political organization? We’d love to meet you and
- chat about working together. Feel free to apply
- here or email our team if you have more questions
- about fiscal sponsorship!
-
-
-
-
- At its core, Hack Club is a nonprofit encouraging
- students to learn how to code by building and making
- cool things. Hack Club Bank was built out by teenagers
- at Hack Club and continues to be a real-world space
- that teens can hack on every day.
-
-
-
-
+ Requirements for Fiscal Sponsorship
+
+ Depending on the fiscal sponsor you choose, requirements for
+ working together can vary. Fiscal sponsors generally ask that your
+ nonprofit’s goals be similar to theirs. They usually also ask that
+ your organization or event commits to remaining charitable in
+ nature and refrains from activites that may result in loss of
+ 501(c)(3) status.
+
+
- '&::after': {
- content: '""',
- width: '500%',
- height: '100%',
+
+ Partner with Hack Club Bank
+
+ While many fiscal sponsors require that their partners relate to
+ their mission in similar ways, at Hack Club Bank, we’ve
+ built our infrastructure to support hundreds of causes in all
+ areas of charitability. Check out some of the resources we’ve
+ built our fiscal sponsorship foundation on:
+
+
+
+ A web interface that looks and operates just like a bank account
+
+
+ Fee-free invoicing, ACH or check transfers, and reimbursements
+
+
+ A customizable and embeddable donations URL
+
+
+ Perks like Google Workspace, PVSA certification, and 1Password
+ credits
+
+
+ Optional transparency mode to show off finances to donors and
+ the public
+
+
+ 24 hour weekday turnaround time from a full-time support team
+ for all queries
+
+
+ ...and more!
+
+
+
+ Looking for nonprofit status and not a religious or political
+ organization? We’d love to meet you and chat about working
+ together. Feel free to apply here or email our team if you have
+ more questions about fiscal sponsorship!
+
+
- position: 'absolute',
- translate: '-50% 100%',
- boxShadow: '0 -64px 64px #17171d',
- }
- }}/>
-
-
- )
-}
\ No newline at end of file
+
+ At its core, Hack Club is a nonprofit encouraging students to learn
+ how to code by building and making cool things.
+ Hack Club Bank was built out by teenagers at Hack Club and
+ continues to be a real-world space that teens can hack on every day.
+
+
+
+
+
+
+ )
+}
diff --git a/pages/bank/success.js b/pages/bank/success.js
index fdd64683..ee5abaf3 100644
--- a/pages/bank/success.js
+++ b/pages/bank/success.js
@@ -1,6 +1,16 @@
import { useRouter } from 'next/router'
import { useEffect } from 'react'
-import { Box, Button, Card, Container, Divider, Text, Link, Flex, Image } from 'theme-ui'
+import {
+ Box,
+ Button,
+ Card,
+ Container,
+ Divider,
+ Text,
+ Link,
+ Flex,
+ Image
+} from 'theme-ui'
import ForceTheme from '../../components/force-theme'
import JSConfetti from 'js-confetti'
import Icon from '../../components/icon'
@@ -8,12 +18,12 @@ import FlexCol from '../../components/flex-col'
function Option({ icon, label, link }) {
const color =
- icon === 'email' ? '#338eda' : icon === 'slack' ? '#a633d6' : '#ec3750';
-
+ icon === 'email' ? '#338eda' : icon === 'slack' ? '#a633d6' : '#ec3750'
+
return (
-
- { label }
+
+ {label}
)
@@ -38,15 +51,16 @@ export default function ApplicationSuccess() {
useEffect(() => {
const jsConfetti = new JSConfetti()
jsConfetti.addConfetti({
- confettiColors: [ // Hack Club colours!
+ confettiColors: [
+ // Hack Club colours!
'#ec3750',
'#ff8c37',
'#f1c40f',
'#33d6a6',
'#5bc0de',
'#338eda',
- '#a633d6',
- ],
+ '#a633d6'
+ ]
})
}, [router])
@@ -65,7 +79,7 @@ export default function ApplicationSuccess() {
Thanks for applying!
@@ -81,10 +95,10 @@ export default function ApplicationSuccess() {
)}
diff --git a/pages/philanthropy/index.js b/pages/philanthropy/index.js
index 14b7a154..5f44a713 100644
--- a/pages/philanthropy/index.js
+++ b/pages/philanthropy/index.js
@@ -38,13 +38,7 @@ import WindyCity from '../../public/donate/6screenshot_2021-10-03_at_3.29.29_pm.
import ZephyrFun from '../../public/donate/0screenshot_2021-10-03_at_3.59.34_pm.png'
import GoldenTrain from '../../public/home/golden-train.png'
-import {
- BarChart,
- Bar,
- XAxis,
- YAxis,
- ResponsiveContainer
-} from 'recharts'
+import { BarChart, Bar, XAxis, YAxis, ResponsiveContainer } from 'recharts'
const Header = styled(Box)`
background: url('/pattern.svg');
@@ -748,7 +742,7 @@ const Philanthropy = ({ posts = [] }) => {
width="20"
height="20"
sx={{ borderRadius: '100%' }}
- alt='belle'
+ alt="belle"
/>
Belle, 17, Malaysia
@@ -783,7 +777,7 @@ const Philanthropy = ({ posts = [] }) => {
src="/philanthropy/insider-logo.svg"
width={530}
height={150}
- alt='insider logo'
+ alt="insider logo"
/>
{
src="/philanthropy/wsj-logo.svg"
width={270}
height={100}
- alt='wsj logo'
+ alt="wsj logo"
/>
{
src="/philanthropy/forbes-logo.svg"
width={500}
height={100}
- alt='forbes logo'
+ alt="forbes logo"
/>
{
src="/philanthropy/cop.png"
width={750}
height={250}
- alt='cop logo'
+ alt="cop logo"
/>
@@ -1337,7 +1331,7 @@ const Philanthropy = ({ posts = [] }) => {
src="/philanthropy/christina-s.png"
width={250}
height={100}
- alt='christina'
+ alt="christina"
/>
Christina Asquith, Co-founder and COO
@@ -1348,7 +1342,7 @@ const Philanthropy = ({ posts = [] }) => {
src="/philanthropy/zach-s.png"
width={150}
height={100}
- alt='zach'
+ alt="zach"
/>
Zach Latta, Founder and Executive Director