diff --git a/components/bio.js b/components/bio.js index 00e822f7..7daa1f9d 100644 --- a/components/bio.js +++ b/components/bio.js @@ -25,7 +25,7 @@ export default function Bio({ popup = true, spanTwo = false, ...props }) { overflowY: 'hidden', overscrollBehavior: 'contain', gridColumn: !spanTwo ? null : [null, null, `1 / span 2`], - position: 'relative', + position: 'relative' }} as={href && !text ? 'a' : 'div'} href={href} diff --git a/components/footer.js b/components/footer.js index eb437af3..76afb92a 100644 --- a/components/footer.js +++ b/components/footer.js @@ -19,8 +19,6 @@ const Base = styled(Box)` } ` - - const Logo = props => ( ( ) -const Footer = ({ dark = false, children, ...props }) => ( +const Footer = ({ + dark = false, + email = 'team@hackclub.com', + children, + ...props +}) => ( ( icon="instagram" name="Instagram" /> - + 1-855-625-HACK diff --git a/components/hackathons/features/money.js b/components/hackathons/features/money.js index f1af372d..d4950b27 100644 --- a/components/hackathons/features/money.js +++ b/components/hackathons/features/money.js @@ -29,11 +29,7 @@ const Content = () => ( - $500 grants. - - } + leadText={<>$500 grants.} body={ <> Running on HCB? Get a $500 grant once you have a venue, provided diff --git a/components/hackathons/recap.js b/components/hackathons/recap.js index a924c381..19a559b0 100644 --- a/components/hackathons/recap.js +++ b/components/hackathons/recap.js @@ -81,7 +81,8 @@ export default function Recap() { name="$500 grants" desc={ <> - Join HCB to receive a $500 grant for your hackathon and a suite of financial tools. + Join HCB to receive a $500 grant for your hackathon and a suite + of financial tools. } /> diff --git a/components/hcb/apply-button.js b/components/hcb/apply-button.js index 29006859..73afa54e 100644 --- a/components/hcb/apply-button.js +++ b/components/hcb/apply-button.js @@ -1,30 +1,32 @@ import { Button, Text, Image, Flex } from 'theme-ui' import Icon from '../icon' +import Link from 'next/link' export default function ApplyButton() { return ( - + + + Apply now + + + + + ) } diff --git a/components/hcb/apply/address-input.js b/components/hcb/apply/address-input.js index e4b40cd6..af2b9df0 100644 --- a/components/hcb/apply/address-input.js +++ b/components/hcb/apply/address-input.js @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react' +import { useEffect, useRef, useState, useCallback } from 'react' import { Box, Flex, Input, Text } from 'theme-ui' import FlexCol from '../../flex-col' import AutofillColourFix from './autofill-colour-fix' @@ -31,13 +31,13 @@ const approvedCountries = [ export default function AutoComplete({ name, isPersonalAddressInput }) { const input = useRef() - const base = useRef() const [predictions, setPredictions] = useState(null) const [countryCode, setCountryCode] = useState(null) const optionClicked = async prediction => { input.current.value = prediction.name - await onInput(prediction.name) + // Needs to match the shape of the event object because onInput takes an event object. + await onInput({ target: { value: prediction.name } }) setPredictions(null) } const clickOutside = e => { @@ -46,26 +46,28 @@ export default function AutoComplete({ name, isPersonalAddressInput }) { } } - const onInput = async value => { - setPredictions(value ? (await search(value)).results : null) + const onInput = useCallback( + async e => { + if (!e.target.value) return + const value = e.target.value - if (isPersonalAddressInput) return - geocode(value) - .then(res => { - const country = res?.results[0]?.country - const countryCode = res?.results[0]?.countryCode + setPredictions(value ? (await search(value)).results : null) - setCountryCode(countryCode) + if (isPersonalAddressInput) return + geocode(value) + .then(res => { + const country = res?.results[0]?.country + const countryCode = res?.results[0]?.countryCode - sessionStorage.setItem('bank-signup-eventCountry', country) - sessionStorage.setItem('bank-signup-eventCountryCode', countryCode) - }) - .catch(err => console.error(err)) - } + setCountryCode(countryCode) - const onInputWrapper = async e => { - if (e.target.value) await onInput(e.target.value) - } + sessionStorage.setItem('bank-signup-eventCountry', country) + sessionStorage.setItem('bank-signup-eventCountryCode', countryCode) + }) + .catch(err => console.error(err)) + }, + [isPersonalAddressInput] + ) //TODO: Close suggestions view when focus is lost via tabbing. //TODO: Navigate suggestions with arrow keys. @@ -75,15 +77,15 @@ export default function AutoComplete({ name, isPersonalAddressInput }) { if (!inputEl) return document.addEventListener('click', clickOutside) - inputEl.addEventListener('input', onInputWrapper) - inputEl.addEventListener('focus', onInputWrapper) + inputEl.addEventListener('input', onInput) + inputEl.addEventListener('focus', onInput) return () => { document.removeEventListener('click', clickOutside) - inputEl.removeEventListener('input', onInputWrapper) - inputEl.removeEventListener('focus', onInputWrapper) + inputEl.removeEventListener('input', onInput) + inputEl.removeEventListener('focus', onInput) } - }, []) + }, [onInput]) return ( @@ -116,7 +118,7 @@ export default function AutoComplete({ name, isPersonalAddressInput }) { Currently, we only have first-class support for organizations in select countries.
- If you're somewhere else, you can still use bank! + If you're somewhere else, you can still use HCB!
Please contact us at hcb@hackclub.com diff --git a/components/hcb/apply/checkbox.js b/components/hcb/apply/checkbox.js index 0442d343..5ec96ed8 100644 --- a/components/hcb/apply/checkbox.js +++ b/components/hcb/apply/checkbox.js @@ -1,20 +1,22 @@ import { useEffect, useState } from 'react' import Icon from '../../icon' +import { useRouter } from 'next/router' export default function Checkbox({ name, defaultChecked = false, size = 38 }) { const [checked, setChecked] = useState(defaultChecked) const toggle = () => setChecked(!checked) + const router = useRouter() /* 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) + const value = router.query[name] || sessionStorage.getItem('bank-signup-' + name) if (value) { const input = document.getElementById(name) - input && setChecked(value === 'true') + input && setChecked(!!value) } - }, [name]) + }, [router.query, name]) return ( <> diff --git a/components/hcb/apply/field.js b/components/hcb/apply/field.js index 4b942e1f..8a06d083 100644 --- a/components/hcb/apply/field.js +++ b/components/hcb/apply/field.js @@ -18,12 +18,12 @@ export default function Field({ /* 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) + const value = router.query[name] || sessionStorage.getItem('bank-signup-' + name) if (value) { const input = document.getElementById(name) if (input) input.value = value } - }, [name]) + }, [router.query, name]) return ( diff --git a/components/hcb/apply/hcb-info.js b/components/hcb/apply/hcb-info.js index ed34e993..fcae4646 100644 --- a/components/hcb/apply/hcb-info.js +++ b/components/hcb/apply/hcb-info.js @@ -63,7 +63,10 @@ export default function HCBInfo() { Rather than setting up a standard bank account, you'll get a restricted fund within Hack Club accounts. -
  • You can't deposit or withdraw cash. But you can receive any kind of electronic payment!
  • +
  • + You can't deposit or withdraw cash. But you can receive any + kind of electronic payment! +
  • diff --git a/components/hcb/apply/personal-form.js b/components/hcb/apply/personal-form.js index 43b8f264..0c48fe77 100644 --- a/components/hcb/apply/personal-form.js +++ b/components/hcb/apply/personal-form.js @@ -164,13 +164,13 @@ export default function PersonalInfoForm({ diff --git a/components/hcb/everything.js b/components/hcb/everything.js index 1474a82f..83f74fbf 100644 --- a/components/hcb/everything.js +++ b/components/hcb/everything.js @@ -52,12 +52,12 @@ export default function Everything({ fee, partner = false }) { item.includes('signup') ? 'bolt' : item.includes('card') - ? 'card' - : item.includes('Transparency') - ? 'explore' - : item.includes('Physical') - ? 'email' - : 'enter' + ? 'card' + : item.includes('Transparency') + ? 'explore' + : item.includes('Physical') + ? 'email' + : 'enter' } > {item} @@ -73,8 +73,8 @@ export default function Everything({ fee, partner = false }) { item.startsWith('Instant') ? 'bolt' : item.includes('form') - ? 'link' - : 'enter' + ? 'link' + : 'enter' } > {item} diff --git a/components/hcb/stats.js b/components/hcb/stats.js index 4b2524a2..163e1119 100644 --- a/components/hcb/stats.js +++ b/components/hcb/stats.js @@ -5,10 +5,10 @@ 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 + ? 1 + : x < 0.5 + ? Math.pow(2, 20 * x - 10) / 2 + : (2 - Math.pow(2, -20 * x + 10)) / 2 function startMoneyAnimation( setBalance, diff --git a/components/index/cards/hackathons.js b/components/index/cards/hackathons.js index 6c00be83..2e94da24 100644 --- a/components/index/cards/hackathons.js +++ b/components/index/cards/hackathons.js @@ -1,8 +1,8 @@ import CardModel from './card-model' -import {Box, Flex, Grid, Image, Link, Text} from 'theme-ui' +import { Box, Flex, Grid, Image, Link, Text } from 'theme-ui' import Buttons from './button' import Dot from '../../dot' -import {formatDate} from '../../../lib/dates' +import { formatDate } from '../../../lib/dates' /** @jsxImportSource theme-ui */ const Cover = () => ( diff --git a/components/index/cards/haunted.js b/components/index/cards/haunted.js index a4eecd24..3379646b 100644 --- a/components/index/cards/haunted.js +++ b/components/index/cards/haunted.js @@ -1,6 +1,6 @@ -import CardModel from "./card-model"; -import { Box, Flex, Grid, Image, Text, Link } from "theme-ui"; -import Buttons from "./button"; +import CardModel from './card-model' +import { Box, Flex, Grid, Image, Text, Link } from 'theme-ui' +import Buttons from './button' /** @jsxImportSource theme-ui */ @@ -10,47 +10,52 @@ export default function Haunted() { github_link="https://github.com/hackclub/www-hauntedhouse" color="white" sx={{ - backgroundSize: "cover", - backgroundColor: "#95C9E5", - border: "2px solid #EB6424", + backgroundSize: 'cover', + backgroundColor: '#95C9E5', + border: '2px solid #EB6424' }} - position={[null, "bottom", "bottom"]} + position={[null, 'bottom', 'bottom']} highlight="#cc5600" image="/haunted/bg.webp" filter="brightness(0.7)" > - + Haunted - - Haunted House is a Chicago-based event full of sites and frights! Join us from October 28-29 - for a weekend of coding pushing the bounds of creativity, where fright meets byte! + Haunted House is a Chicago-based event full of sites and frights! Join + us from October 28-29 for a weekend of coding pushing the bounds of + creativity, where fright meets byte! - - Sign Up - + + Sign Up + - ); + ) } diff --git a/components/index/cards/haxidraw.js b/components/index/cards/haxidraw.js index be372328..5af1d22d 100644 --- a/components/index/cards/haxidraw.js +++ b/components/index/cards/haxidraw.js @@ -29,8 +29,8 @@ export default function Haxidraw({ stars }) { variant="subtitle" sx={{ zIndex: 2, position: 'relative' }} > - Blot is an open source drawing machine and online editor, - designed to be a fun and beginner friendly introduction to digital + Blot is an open source drawing machine and online editor, designed + to be a fun and beginner friendly introduction to digital fabrication and generative art. diff --git a/components/index/cards/mailing-list.js b/components/index/cards/mailing-list.js index ddbe5166..a81d9bff 100644 --- a/components/index/cards/mailing-list.js +++ b/components/index/cards/mailing-list.js @@ -23,8 +23,8 @@ const Loading = () => ( mr: '5px', '@keyframes spin': { '0%': { transform: 'rotate(0deg)' }, - '100%': { transform: 'rotate(360deg)' }, - }, + '100%': { transform: 'rotate(360deg)' } + } }} > ) @@ -35,19 +35,19 @@ const MailingList = () => { const [data, setData] = useState({ finalHtml: [], names: [] }) const formRef = useRef(null) - const handleSubmit = async (e) => { + const handleSubmit = async e => { e.preventDefault() setSubmitting(true) let res = await fetch('/api/mailing-list', { method: 'POST', headers: { - 'Content-Type': 'application/json', + 'Content-Type': 'application/json' }, body: JSON.stringify({ name: e.target.name.value, - email: e.target.email.value, - }), + email: e.target.email.value + }) }) formRef.current.reset() @@ -66,22 +66,33 @@ const MailingList = () => { useEffect(() => { Promise.all([ - fetch('https://api.github.com/repos/hackclub/leaders-newsletter/contents/updates') + fetch( + 'https://api.github.com/repos/hackclub/leaders-newsletter/contents/updates' + ) .then(response => response.json()) .then(data => data.sort((a, b) => b.name.localeCompare(a.name))) // Makes sure we only get the latest two newsletters .then(data => data.slice(0, 2)) .then(data => Promise.all(data.map(item => fetch(item.download_url)))) // Makes a separate fetch request for the content of each newsletter - .then(responses => Promise.all(responses.map(response => response.text()))) - .then(markdown => Promise.all(markdown.map(markdown => markdownToHtml(markdown)))) - .then(html => html.map(html => html.replace(/<[^>]*>/g, '').replace(/The Hackening/g, ''))), // Chucks out all html tags + 'The Hackening' - - fetch('https://api.github.com/repos/hackclub/leaders-newsletter/contents/updates') + .then(responses => + Promise.all(responses.map(response => response.text())) + ) + .then(markdown => + Promise.all(markdown.map(markdown => markdownToHtml(markdown))) + ) + .then(html => + html.map(html => + html.replace(/<[^>]*>/g, '').replace(/The Hackening/g, '') + ) + ), // Chucks out all html tags + 'The Hackening' + + fetch( + 'https://api.github.com/repos/hackclub/leaders-newsletter/contents/updates' + ) .then(response => response.json()) .then(data => data.sort((a, b) => b.name.localeCompare(a.name))) .then(data => data.map(item => item.name.split('.')[0])) // Grabs the name and gets rid of the file extension - ]) - .then(([finalHtml, names]) => setData({ finalHtml, names })) - }, []) + ]).then(([finalHtml, names]) => setData({ finalHtml, names })) + }, []) return ( @@ -93,10 +104,12 @@ const MailingList = () => { background: 'rgb(255,255,255, 0.45)', position: 'relative', zIndex: 2, - backdropFilter: 'blur(8px)', + backdropFilter: 'blur(8px)' }} > - + { alignItems: ['left', 'left', 'center'], flexDirection: 'column', gap: '10px', - width: ['100%', '100%', '75%'], + width: ['100%', '100%', '75%'] }} > Join the newsletter @@ -123,23 +136,24 @@ const MailingList = () => { color: 'darkless', mt: 2, fontSize: 3, - textAlign: 'left', + textAlign: 'left' }} - as='p' + as="p" > - We'll send you an email no more than once a month, when we work - on something cool for you. Check out our{' '} + We'll send you an email no more than once a month, when we + work on something cool for you. Check out our{' '} previous issues - . + + . { textAlign: 'center', alignItems: 'end', input: { bg: 'sunken' }, - width: '100%', + width: '100%' }} >
    - -
    diff --git a/pages/hcb/index.js b/pages/hcb/index.js index 7cc34281..e1742b9a 100644 --- a/pages/hcb/index.js +++ b/pages/hcb/index.js @@ -53,7 +53,7 @@ export default function Bank({ stats }) { -