Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

form submission with error handling, PR includes suggestionBox #339

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions src/components/Feeds/AllyFeed.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,7 @@ const AllyFeed = props => {
) : (
<NoResultsCard type="allies" />
)}
<ModalForm
isOpen={isOpen}
title="Sign up to be an Ally"
onClose={onClose}
/>
<ModalForm isOpen={isOpen} onClose={onClose} />
</Box>
</>
);
Expand Down
8 changes: 6 additions & 2 deletions src/components/Forms/AllySignUpForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ const AllySignUpForm = () => {
return;
}

submitAlly(infoToSubmit);
const possibleError = submitAlly(infoToSubmit);

setSubmitted(true);
if (possibleError) setValidationMessage(possibleError);
else setSubmitted(true);
};

//renders in place of form once it has been submitted
Expand All @@ -63,6 +64,9 @@ const AllySignUpForm = () => {
}
}}
>
<Text fontSize="xl" textAlign="center">
Sign up to be an Ally
</Text>
{/* renders when form is submitted with validation errors */}
{validationMessage && <Text>{validationMessage}</Text>}

Expand Down
8 changes: 6 additions & 2 deletions src/components/Forms/BusinessSignUpForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ const BusinessSignUpForm = ({ isFundraiser = false }) => {
return;
}

submitBusiness(infoToSubmit);
const possibleError = submitBusiness(infoToSubmit);

setSubmitted(true);
if (possibleError) setValidationMessage(possibleError);
else setSubmitted(true);
};

const handleLocationType = event => {
Expand Down Expand Up @@ -156,6 +157,9 @@ const BusinessSignUpForm = ({ isFundraiser = false }) => {
}
}}
>
<Text fontSize="xl" textAlign="center">
Register your business
</Text>
{/* renders when form is submitted with validation errors */}
{validationMessage && <Text>{validationMessage}</Text>}

Expand Down
214 changes: 214 additions & 0 deletions src/components/Forms/SuggestionBox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
import React, { useState } from 'react';
import {
FormControl,
Flex,
useTheme,
FormLabel,
Input,
Textarea,
Text,
NumberInput,
NumberInputField,
NumberInputStepper,
NumberIncrementStepper,
NumberDecrementStepper,
} from '@chakra-ui/core';

const encode = data => {
return Object.keys(data)
.map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
.join('&');
};

//how to intigrate with netlifys form handling
//https://www.netlify.com/blog/2017/07/20/how-to-integrate-netlifys-form-handling-in-a-react-app/#form-handling-with-static-site-generators

export default function SuggestionBox() {
const [topic, setTopic] = useState(null);
const [description, setDescription] = useState(null);
const [benefits, setBenefits] = useState(null);
const [urgency, setUrgency] = useState(5);
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [validationMessage, setValidationMessage] = useState(null);
const [submitted, setSubmitted] = useState(false);

const theme = useTheme();

const handleSubmit = event => {
event.preventDefault();

const toSubmit = {
topic,
description,
benefits,
urgency,
name,
email,
};

//Simple Custom Validation
const valuesToValidate = Object.values(toSubmit);
//Validates all required fields are filled (must be initiated with null).
if (valuesToValidate.includes(null)) {
setValidationMessage('All fields with * are required.');
return;
}

//posts to Netlify intigration
fetch('/', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: encode({ 'form-name': 'contact', toSubmit }),
})
.then(() => {
console.log('Success!');
setSubmitted(true);
})
.catch(error => {
console.log(error);
setValidationMessage(error);
});
};

if (submitted) {
return (
<Text fontSize="2xl" textAlign="center" margin="0 0 2rem 0">
Thank you for your suggestion!
</Text>
);
}

return (
<FormControl
width="100%"
maxWidth="1000px"
margin="0 auto 3rem"
padding="0 24px"
>
{/* netlify form handling */}
<form
netlify
method="POST"
data-netlify-honeypot="bot-field"
data-netlify="true"
name="suggestion-box"
onSubmit={handleSubmit}
>
<input type="hidden" name="bot-field" />
<input type="hidden" name="form-name" value="contact" />

<Text fontSize="xl" textAlign="center">
Suggestion Box
</Text>

{/* renders when form is submitted with validation errors */}
{validationMessage && (
<Text textAlign="center">{validationMessage}</Text>
)}

<Flex direction="column" margin={theme.spacing.base}>
<FormLabel isRequired htmlFor="topic">
Topic
</FormLabel>
<Input
value={topic}
id="topic"
name="topic"
type="text"
placeholder="e.g. Business, Functionality, New Feature"
onChange={event => setTopic(event.currentTarget.value)}
/>
</Flex>

<Flex direction="column" margin={theme.spacing.base}>
<FormLabel isRequired htmlFor="textField">
Description
</FormLabel>
<Textarea
value={description}
id="description"
name="description"
placeholder="Description"
onChange={event => setDescription(event.currentTarget.value)}
/>
</Flex>

<Flex direction="column" margin={theme.spacing.base}>
<FormLabel isRequired htmlFor="benefits">
Benefits
</FormLabel>
<Textarea
value={benefits}
id="benefits"
name="benefits"
placeholder="Benefits"
onChange={event => setBenefits(event.currentTarget.value)}
/>
</Flex>

<Flex direction="column" margin={theme.spacing.base}>
<FormLabel isRequired htmlFor="urgency">
Urgency: 1 (Most Urgent) - 5 (Not Urgent)
</FormLabel>
<NumberInput
id="urgency"
name="urgency"
type="number"
min={1}
max={5}
value={urgency}
onChange={value => setUrgency(value > 5 ? 5 : value)}
>
<NumberInputField />
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
</Flex>

<Flex width="100%" direction="column">
<Flex direction="column" margin={theme.spacing.base}>
<FormLabel htmlFor="name">Name</FormLabel>
<Input
value={name}
id="name"
name="name"
type="text"
placeholder="Name"
onChange={event => setName(event.currentTarget.value)}
/>
</Flex>
<Flex direction="column" margin={theme.spacing.base}>
<FormLabel htmlFor="email">Email</FormLabel>
<Input
value={email}
id="email"
name="email"
type="text"
placeholder="Email"
onChange={event => setEmail(event.currentTarget.value)}
/>
</Flex>

<Flex width="100%" justify="center">
<input
type="submit"
value="SUBMIT"
style={{
background: `${theme.buttons.primary.backgroundColor.default}`,
color: `${theme.buttons.primary.color.default}`,
borderRadius: '2rem',
fontFamily: `${theme.buttons.primary.fontFamily}`,
fontWeight: 'bold',
padding: `${theme.buttons.primary.padding}`,
textTransform: `${theme.buttons.primary.textTransform}`,
}}
/>
</Flex>
</Flex>
</form>
</FormControl>
);
}
7 changes: 4 additions & 3 deletions src/components/about/ContactCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import {
import React from 'react';
import Image from '../../components/Image.js';
import { VOLUNTEER_URL } from '../../constants/about';
import BusinessSignUpForm from '../Forms/BusinessSignUpForm.js';

import SuggestionBox from '../Forms/SuggestionBox.js';

const CardContent = ({ title, blurb, publicId, alt, transforms = {} }) => {
const theme = useTheme();
Expand Down Expand Up @@ -77,13 +78,13 @@ const CardImage = ({ publicId, transforms, alt }) => {
};

const ModalForm = ({ isOpen, onClose, title }) => (
<Modal isOpen={isOpen} onClose={onClose}>
<Modal isOpen={isOpen} onClose={onClose} closeOnOverlayClick={false}>
<ModalOverlay />
<ModalContent>
<ModalHeader>{title}</ModalHeader>
<ModalCloseButton />
<ModalBody>
<BusinessSignUpForm />
<SuggestionBox />
</ModalBody>
</ModalContent>
</Modal>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/about.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,11 @@ export default function About() {
>
<ContactCard
modalCard
title="Business Owners"
title="Suggestions"
publicId="assets/contact-left"
alt="business shop window"
transforms={{ width: 800, height: 450, crop: 'crop' }}
blurb="Add your business to our list"
blurb="How can we improve?"
/>
<ErrorBoundary>
<StaticQuery
Expand Down
32 changes: 20 additions & 12 deletions src/services/AirtableServices.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ export function submitAlly({
'Last Name': lastName,
};

let error = null;

base('Allies').create(AirtableData, function (err, record) {
if (err) {
console.error(err);
return;
}
console.log(record);
error = err;
} else console.log(record);
});

if (error) return error;
}

export function submitBusiness({
Expand Down Expand Up @@ -77,13 +80,14 @@ export function submitBusiness({
Bitcoin: bitcoin,
};

let error = null;
base('Businesses').create(AirtableData, function (err, record) {
if (err) {
console.error(err);
return;
}
console.log(record);
error = err;
} else console.log(record);
});
if (error) return error;
}

//Only fetches from first page of docs for performance concerns.
Expand Down Expand Up @@ -112,9 +116,11 @@ export function useAllySpecialities() {
console.error(err);
return;
}
records.forEach(record => {
setSpecialities(prev => [...prev, record.get('Speciality')]);
});
setSpecialities(
records.map(record => {
return record.get('Speciality');
})
);
});
}, []);

Expand All @@ -137,9 +143,11 @@ export function useBusinessCategories() {
console.error(err);
return;
}
records.forEach(record => {
setCategories(prev => [...prev, record.get('Category')]);
});
setCategories(
records.map(record => {
return record.get('Category');
})
);
});
}, []);

Expand Down