Added contact form to application. Sends requests through EmailJS.
This commit is contained in:
parent
17410d3eec
commit
60e1e5e31f
|
@ -4246,6 +4246,21 @@
|
||||||
"minimalistic-crypto-utils": "^1.0.0"
|
"minimalistic-crypto-utils": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"emailjs-com": {
|
||||||
|
"version": "2.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/emailjs-com/-/emailjs-com-2.2.4.tgz",
|
||||||
|
"integrity": "sha512-Pm29HoSxEIKLv7p6rxOPpKFqLnf2JaHTl6coql59r8MNRNW49Mim65s7yoWAqQhZ+Mk4GFmQsiPSFXD6Gnm4BQ==",
|
||||||
|
"requires": {
|
||||||
|
"promise-polyfill": "7.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"promise-polyfill": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-P6NJ2wU/8fac44ENORsuqT8TiolKGB2u0fEClPtXezn7w5cmLIjM/7mhPlTebke2EPr6tmqZbXvnX0TxwykGrg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"emoji-regex": {
|
"emoji-regex": {
|
||||||
"version": "6.5.1",
|
"version": "6.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz",
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"@material-ui/icons": "^3.0.1",
|
"@material-ui/icons": "^3.0.1",
|
||||||
"ajv": "^6.0.0",
|
"ajv": "^6.0.0",
|
||||||
"disqus-react": "^1.0.5",
|
"disqus-react": "^1.0.5",
|
||||||
|
"emailjs-com": "^2.2.4",
|
||||||
"firebase": "^5.5.2",
|
"firebase": "^5.5.2",
|
||||||
"firebase-admin": "^6.1.0",
|
"firebase-admin": "^6.1.0",
|
||||||
"flamelink": "^0.19.6",
|
"flamelink": "^0.19.6",
|
||||||
|
|
|
@ -42,6 +42,11 @@ body {
|
||||||
height: 300px !important;
|
height: 300px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contact-form {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 960px) {
|
@media (min-width: 960px) {
|
||||||
.sighting-detail-google-map-container > div {
|
.sighting-detail-google-map-container > div {
|
||||||
width: calc(100% - 50% - 120px) !important;
|
width: calc(100% - 50% - 120px) !important;
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Grid from '@material-ui/core/Grid';
|
||||||
|
import emailjs from '../emailjs.js'
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import TextField from '@material-ui/core/TextField';
|
||||||
|
import CheckCircleIcon from '@material-ui/icons/CheckCircle';
|
||||||
|
import Snackbar from '@material-ui/core/Snackbar';
|
||||||
|
import IconButton from '@material-ui/core/IconButton';
|
||||||
|
import CloseIcon from '@material-ui/icons/Close';
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
import { Typography } from '@material-ui/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Styles that the different
|
||||||
|
* Material UI components pull
|
||||||
|
* in. Mostly used for spacing.
|
||||||
|
*/
|
||||||
|
const styles = theme => ({
|
||||||
|
container: {
|
||||||
|
display: 'flex',
|
||||||
|
flexWrap: 'wrap'
|
||||||
|
},
|
||||||
|
textField: {
|
||||||
|
marginLeft: theme.spacing.unit,
|
||||||
|
marginRight: theme.spacing.unit,
|
||||||
|
marginTop: theme.spacing.unit,
|
||||||
|
flexBasis: 280,
|
||||||
|
width: '90%'
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
marginLeft: theme.spacing.unit,
|
||||||
|
marginRight: theme.spacing.unit,
|
||||||
|
marginTop: theme.spacing.unit,
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
padding: theme.spacing.unit / 2,
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
fontSize: 20,
|
||||||
|
marginRight: theme.spacing.unit,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
menu: {
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
paper: {
|
||||||
|
position: 'absolute',
|
||||||
|
width: theme.spacing.unit * 50,
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
|
boxShadow: theme.shadows[5],
|
||||||
|
padding: theme.spacing.unit * 4,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form component.
|
||||||
|
*/
|
||||||
|
class ContactForm extends React.Component {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State of form components.
|
||||||
|
*/
|
||||||
|
state = {
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
comments: "",
|
||||||
|
open: false
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles state change in form
|
||||||
|
* components.
|
||||||
|
*/
|
||||||
|
handleChange = name => event => {
|
||||||
|
this.setState({
|
||||||
|
[name]: event.target.value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles closing the toast.
|
||||||
|
*/
|
||||||
|
handleClose = (event, reason) => {
|
||||||
|
if (reason === 'clickaway') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ open: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener for form.
|
||||||
|
* When the form is submitted,
|
||||||
|
* this function passes the
|
||||||
|
* data along to EmailJS.
|
||||||
|
*/
|
||||||
|
handleSubmit = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const templateParams = {
|
||||||
|
from_name: this.state.name,
|
||||||
|
from_email: this.state.email,
|
||||||
|
message_html: this.state.comments
|
||||||
|
};
|
||||||
|
|
||||||
|
emailjs.send('default_service', 'template_XaKOJGSf', templateParams);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
comments: "",
|
||||||
|
open: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The render method for this component.
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
const { classes } = this.props;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The actual form.
|
||||||
|
*/
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Typography variant="headline" align="center">
|
||||||
|
{<br/>}
|
||||||
|
Send us an email!
|
||||||
|
|
||||||
|
<form className={classes.container} autoComplete="off" onSubmit={this.handleSubmit}>
|
||||||
|
<Grid container className="contact-form">
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Grid container spacing={8}>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<TextField
|
||||||
|
id="name"
|
||||||
|
required
|
||||||
|
label="Name"
|
||||||
|
name="message-name"
|
||||||
|
placeholder="John Doe"
|
||||||
|
value={this.state.name}
|
||||||
|
className={classes.textField}
|
||||||
|
onChange={this.handleChange('name')}
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="email"
|
||||||
|
required
|
||||||
|
label="Email"
|
||||||
|
name="message-email"
|
||||||
|
type="email"
|
||||||
|
autoComplete="email"
|
||||||
|
placeholder="example@mail.com"
|
||||||
|
value={this.state.email}
|
||||||
|
className={classes.textField}
|
||||||
|
onChange={this.handleChange('email')}
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="comments"
|
||||||
|
required
|
||||||
|
label="Comments"
|
||||||
|
name="message-comments"
|
||||||
|
multiline
|
||||||
|
rows="5"
|
||||||
|
placeholder="The message you would like to send us."
|
||||||
|
value={this.state.comments}
|
||||||
|
className={classes.textField}
|
||||||
|
onChange={this.handleChange('comments')}
|
||||||
|
margin="normal"
|
||||||
|
variant="outlined"
|
||||||
|
InputLabelProps={{
|
||||||
|
shrink: true,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Button variant="contained" type="submit" color="primary" className={classes.button}>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</form>
|
||||||
|
</Typography>
|
||||||
|
<Snackbar
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'bottom',
|
||||||
|
horizontal: 'left',
|
||||||
|
}}
|
||||||
|
open={this.state.open}
|
||||||
|
autoHideDuration={6000}
|
||||||
|
onClose={this.handleClose}
|
||||||
|
ContentProps={{
|
||||||
|
'aria-describedby': 'message-id',
|
||||||
|
}}
|
||||||
|
message={<span id="message-id" className={classes.message}><CheckCircleIcon className={classes.icon} />Message sent.</span>}
|
||||||
|
action={[
|
||||||
|
<IconButton
|
||||||
|
key="close"
|
||||||
|
aria-label="Close"
|
||||||
|
color="inherit"
|
||||||
|
className={classes.close}
|
||||||
|
onClick={this.handleClose}
|
||||||
|
>
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactForm.propTypes = {
|
||||||
|
classes: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withStyles(styles)(ContactForm);
|
|
@ -14,6 +14,7 @@ import Hidden from '@material-ui/core/Hidden';
|
||||||
import Divider from '@material-ui/core/Divider';
|
import Divider from '@material-ui/core/Divider';
|
||||||
import MenuIcon from '@material-ui/icons/Menu';
|
import MenuIcon from '@material-ui/icons/Menu';
|
||||||
import HomeIcon from '@material-ui/icons/Home';
|
import HomeIcon from '@material-ui/icons/Home';
|
||||||
|
import EmailIcon from '@material-ui/icons/Email';
|
||||||
import AssignmentIcon from '@material-ui/icons/Assignment';
|
import AssignmentIcon from '@material-ui/icons/Assignment';
|
||||||
import MapIcon from '@material-ui/icons/Map';
|
import MapIcon from '@material-ui/icons/Map';
|
||||||
import InfoIcon from '@material-ui/icons/Info';
|
import InfoIcon from '@material-ui/icons/Info';
|
||||||
|
@ -23,6 +24,7 @@ import Home from '../pages/Home';
|
||||||
import ViewMap from '../pages/ViewMap';
|
import ViewMap from '../pages/ViewMap';
|
||||||
import Info from '../pages/Info';
|
import Info from '../pages/Info';
|
||||||
import Quiz from '../pages/QuizPage';
|
import Quiz from '../pages/QuizPage';
|
||||||
|
import Contact from '../pages/Contact';
|
||||||
import SightingList from '../pages/SightingList';
|
import SightingList from '../pages/SightingList';
|
||||||
import Report from '../pages/Report';
|
import Report from '../pages/Report';
|
||||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||||
|
@ -112,10 +114,6 @@ class ResponsiveDrawer extends React.Component {
|
||||||
<ListItemIcon><ListIcon /></ListItemIcon>
|
<ListItemIcon><ListIcon /></ListItemIcon>
|
||||||
<ListItemText primary='List' />
|
<ListItemText primary='List' />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem button key='About' onClick={() => this.nav('About')}>
|
|
||||||
<ListItemIcon><InfoIcon /></ListItemIcon>
|
|
||||||
<ListItemText primary='About' />
|
|
||||||
</ListItem>
|
|
||||||
<ListItem button onClick={this.handleClick}>
|
<ListItem button onClick={this.handleClick}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<SlideshowIcon />
|
<SlideshowIcon />
|
||||||
|
@ -136,6 +134,14 @@ class ResponsiveDrawer extends React.Component {
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
<ListItem button key='Contact' onClick={() => this.nav('Contact')}>
|
||||||
|
<ListItemIcon><EmailIcon /></ListItemIcon>
|
||||||
|
<ListItemText primary='Contact' />
|
||||||
|
</ListItem>
|
||||||
|
<ListItem button key='About' onClick={() => this.nav('About')}>
|
||||||
|
<ListItemIcon><InfoIcon /></ListItemIcon>
|
||||||
|
<ListItemText primary='About' />
|
||||||
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
<Divider />
|
<Divider />
|
||||||
</div>
|
</div>
|
||||||
|
@ -196,6 +202,7 @@ class ResponsiveDrawer extends React.Component {
|
||||||
{this.state.key === 'Map' && <ViewMap />}
|
{this.state.key === 'Map' && <ViewMap />}
|
||||||
{this.state.key === 'List' && <SightingList />}
|
{this.state.key === 'List' && <SightingList />}
|
||||||
{this.state.key === 'About' && <Info />}
|
{this.state.key === 'About' && <Info />}
|
||||||
|
{this.state.key === 'Contact' && <Contact />}
|
||||||
{this.state.key === 'Easy-Quiz' && <Quiz difficulty='Easy'/>}
|
{this.state.key === 'Easy-Quiz' && <Quiz difficulty='Easy'/>}
|
||||||
{this.state.key === 'Medium-Quiz' && <Quiz difficulty='Medium'/>}
|
{this.state.key === 'Medium-Quiz' && <Quiz difficulty='Medium'/>}
|
||||||
{this.state.key === 'Hard-Quiz' && <Quiz difficulty='Hard'/>}
|
{this.state.key === 'Hard-Quiz' && <Quiz difficulty='Hard'/>}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import * as emailjs from 'emailjs-com'
|
||||||
|
|
||||||
|
emailjs.init("user_4d5R86dmu6vgeJP4euxSA");
|
||||||
|
|
||||||
|
export default emailjs;
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import ContactForm from '../components/ContactForm.js'
|
||||||
|
|
||||||
|
class Contact extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
document.title = 'Marten Tracker | Contact';
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <ContactForm />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Contact;
|
Loading…
Reference in New Issue