Skip to content

Contact Page Closes #67 #72

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

Open
wants to merge 1 commit 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
52 changes: 52 additions & 0 deletions web/components/InputField/ContactInputField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import { Field } from 'formik';
import {
FormControl,
FormLabel,
FormErrorMessage,
Input,
Textarea,
IconButton,
} from '@chakra-ui/react';
import InputPopover from './InputPopover';
import { RiErrorWarningFill } from 'react-icons/ri';

function ContactInputField({ type, label, name, error, touched, tag }) {
return (
<Field type={type} name={name}>
{({ field }) => (
<FormControl isInvalid={error && touched}>
<FormLabel htmlFor={name}>
{label}
{error && touched ? (
<InputPopover
header="Error"
content={<FormErrorMessage>{error} </FormErrorMessage>}
trigger={
<IconButton fontSize="20px" size="sm" isRound="true">
<RiErrorWarningFill color="#F65656" />
</IconButton>
}
/>
) : (
''
)}
</FormLabel>
{tag === 'Input' ? (
<Input {...field} type={type} id={name} />
) : (
<Textarea
placeholder="Send us a message!"
{...field}
type={type}
id={name}
height="250px"
/>
)}
</FormControl>
)}
</Field>
);
}

export default ContactInputField;
29 changes: 29 additions & 0 deletions web/components/InputField/InputPopover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import {
Popover,
PopoverTrigger,
PopoverContent,
PopoverHeader,
PopoverBody,
PopoverArrow,
PopoverCloseButton,
Portal,
} from '@chakra-ui/react';

function InputPopover({ header, trigger, content, openOn }) {
return (
<Popover defaultIsOpen={openOn}>
<PopoverTrigger>{trigger}</PopoverTrigger>
<Portal>
<PopoverContent>
<PopoverArrow />
<PopoverHeader>{header}</PopoverHeader>
<PopoverCloseButton />
<PopoverBody>{content}</PopoverBody>
</PopoverContent>
</Portal>
</Popover>
);
}

export default InputPopover;
5 changes: 5 additions & 0 deletions web/config/db/migrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ const migrations = [
scriptDate: '2022-01-08',
sql: 'ALTER TABLE indeedjobs ADD fullDesc TEXT NOT NULL;',
},
{
scriptName: 'create-contacts-table',
scriptDate: '2022-02-08',
sql: 'CREATE TABLE contacts(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, email VARCHAR(128) NOT NULL, name VARCHAR(32) NOT NULL, description VARCHAR(1000) NOT NULL);',
},
];

module.exports = migrations;
18 changes: 18 additions & 0 deletions web/pages/api/contacts/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import nextConnect from 'next-connect';
import { query } from '../../../utils/query';

const handler = nextConnect().post(async (req, res) => {
const { email, name, description } = await req.body;
try {
await query(`INSERT INTO contacts(email, name, description) VALUES(?, ?, ?)`, [
email,
name,
description,
]);
return res.status(200).json({ message: 'Message sent!' });
} catch (e) {
res.status(500).json({ message: e.message });
}
});

export default handler;
140 changes: 140 additions & 0 deletions web/pages/contact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import React, { useState } from 'react';
import {
FormControl,
Button,
Flex,
Heading,
VStack,
Box,
Alert,
AlertIcon,
AlertDescription,
} from '@chakra-ui/react';
import { Formik, Form } from 'formik';
import * as Yup from 'yup';
import ContactInputField from '../components/InputField/ContactInputField';

const initialValues = {
email: '',
name: '',
description: '',
};

function Contact() {
const [response, setResponse] = useState();

const contactSchema = Yup.object().shape({
email: Yup.string().required('Required'),
name: Yup.string().min(2, 'Too short').required('Required'),
description: Yup.string().max(1000, 'Too long').required('Required'),
});

async function onContacts(values) {
const body = {
email: values.email,
name: values.name,
description: values.description,
};

let res = await fetch('./api/contacts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});

res = await res.json();
setResponse(res);
initialValues = { initialValues };
}
return (
<>
<Flex align="center" justify="center" maxH="auto" backgroundColor="gray.700">
<VStack
className="noselect"
background="#A0D8F0"
p="9.25rem"
align="center"
justify="center"
spacing="1.5rem"
color="black"
>
<Heading align="center">Contact Us</Heading>
{response && response.message && (
<Alert
status="success"
rounded="1.5rem"
p="0.75rem 1rem"
justify="center"
align="center"
width="fit-content"
maxWidth="100%"
>
<AlertIcon />
<AlertDescription>{response.message}</AlertDescription>
</Alert>
)}

<FormControl>
<Formik
initialValues={initialValues}
validationSchema={contactSchema}
onSubmit={async (values, actions) => {
await onContacts(values);
actions.setSubmitting(false);
actions.resetForm({ initialValues });
}}
>
{({ errors, touched, isSubmitting, isValid }) => (
<Form>
<VStack w="50rem" spacing="1.75rem">
<ContactInputField
name="email"
label="Email"
error={errors.email}
touched={touched.email}
tag="Input"
background="white"
/>
<ContactInputField
name="name"
type="text"
label="Name"
error={errors.name}
touched={touched.name}
tag="Input"
bg="white"
/>

<ContactInputField
name="description"
type="text"
label="Description"
error={errors.description}
touched={touched.description}
tag="Textarea"
bg="white"
/>

<Box style={{ marginLeft: 'auto', marginRight: '0' }}>
<Button
disabled={!isValid}
isLoading={isSubmitting}
type="submit"
colorScheme="teal"
size="lg"
>
Send Message
</Button>
</Box>
</VStack>
</Form>
)}
</Formik>
</FormControl>
</VStack>
</Flex>
</>
);
}

export default Contact;