Skip to content

Commit d42029b

Browse files
committed
add reCaptcha
1 parent d78d6d9 commit d42029b

File tree

5 files changed

+234
-95
lines changed

5 files changed

+234
-95
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2121
- decoration components
2222
- nav component styling and intersection api
2323
- CardsColumns.js and Card.js
24+
- reCAPTCHA
2425

2526
### Fixed
2627

components/mailchimp/NewsletterForm.js

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,48 @@
1-
import { useState } from 'react';
1+
import { createRef, useState } from 'react';
22
import { decode } from 'html-entities';
33
import Container from '../Container';
44
import newsletterStyles from '../../styles/Newsletter.module.scss';
5+
import ReCAPTCHA from 'react-google-recaptcha';
6+
7+
const SITE_KEY = process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY;
58

69
const NewsletterForm = ({ status, message, onValidated }) => {
710
const [error, setError] = useState(null);
8-
const [email, setEmail] = useState(null);
11+
const [name, setName] = useState('');
12+
const [email, setEmail] = useState('');
13+
const recaptchaRef = createRef();
14+
15+
const onReCAPTCHAChange = async captchaCode => {
16+
// If the reCAPTCHA code is null or undefined indicating that
17+
// the reCAPTCHA was expired then return early
18+
if (!captchaCode) {
19+
return;
20+
}
21+
try {
22+
const response = await fetch('/api/register', {
23+
method: 'POST',
24+
body: JSON.stringify({ email, name, captcha: captchaCode }),
25+
headers: {
26+
'Content-Type': 'application/json',
27+
},
28+
});
29+
if (response.ok) {
30+
// If the response is ok than show the success console.log
31+
console.log('Email registered successfully');
32+
} else {
33+
// Else throw an error with the message returned
34+
const error = await response.json();
35+
throw new Error(error.message);
36+
}
37+
} catch (error) {
38+
console.log(error?.message || 'Something went wrong');
39+
} finally {
40+
// Reset the reCAPTCHA when the request has failed or succeeded
41+
recaptchaRef.current.reset();
42+
setEmail('');
43+
setName('');
44+
}
45+
};
946

1047
/**
1148
* Handle form submit.
@@ -17,17 +54,24 @@ const NewsletterForm = ({ status, message, onValidated }) => {
1754

1855
setError(null);
1956

57+
if (!name) {
58+
setError('Please enter a name');
59+
return null;
60+
}
61+
2062
if (!email) {
2163
setError('Please enter a valid email address');
2264
return null;
2365
}
2466

67+
recaptchaRef.current.execute();
68+
2569
const isFormValidated = onValidated({ EMAIL: email });
2670

2771
event.target.reset();
2872

2973
// On success return true
30-
return email && email.indexOf('@') > -1 && isFormValidated;
74+
return name && email && email.indexOf('@') > -1 && isFormValidated;
3175
};
3276

3377
/**
@@ -77,22 +121,36 @@ const NewsletterForm = ({ status, message, onValidated }) => {
77121
>
78122
<input
79123
className={`${newsletterStyles.newsletter__input} ${newsletterStyles.newsletter__name}`}
124+
onChange={event => setName(event?.target?.value ?? '')}
80125
type="text"
81126
name="name"
127+
value={name}
82128
placeholder="name"
83129
/>
84130
<input
85131
className={`${newsletterStyles.newsletter__input} ${newsletterStyles.newsletter__email}`}
86132
onChange={event => setEmail(event?.target?.value ?? '')}
87133
type="email"
88134
name="email"
135+
value={email}
89136
placeholder="email"
90137
onKeyUp={event => handleInputKeyEvent(event)}
91138
/>
92-
<button className={newsletterStyles.newsletter__button}>
139+
<button
140+
className={newsletterStyles.newsletter__button}
141+
type="submit"
142+
>
93143
Subscribe
94144
</button>
145+
146+
<ReCAPTCHA
147+
ref={recaptchaRef}
148+
size="invisible"
149+
sitekey={SITE_KEY}
150+
onChange={onReCAPTCHAChange}
151+
/>
95152
</form>
153+
96154
<div className={newsletterStyles.newsletterFormInfo}>
97155
{status === 'sending' && (
98156
<div className={newsletterStyles.newsletterFormSending}>

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"next": "^12.0.10",
1616
"react": "17.0.1",
1717
"react-dom": "17.0.1",
18+
"react-google-recaptcha": "^2.1.0",
1819
"react-mailchimp-subscribe": "^2.1.3",
1920
"sass": "^1.35.1"
2021
}

pages/api/register.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
const sleep = () =>
2+
new Promise(resolve => {
3+
setTimeout(() => {
4+
resolve();
5+
}, 350);
6+
});
7+
8+
export default async function handler(req, res) {
9+
const SECRET_KEY = process.env.RECAPTCHA_SECRET_KEY;
10+
11+
const { body, method } = req;
12+
13+
// Extract the email, name, and captcha code from the request body
14+
const { email, name, captcha } = body;
15+
16+
if (method === 'POST') {
17+
// If email or captcha are missing return an error
18+
if (!email || !name || !captcha) {
19+
return res.status(422).json({
20+
message: 'Unprocessable request, please provide the required fields',
21+
});
22+
}
23+
24+
try {
25+
// Ping the google recaptcha verify API to verify the captcha code you received
26+
const response = await fetch(
27+
`https://www.google.com/recaptcha/api/siteverify?secret=${SECRET_KEY}&response=${captcha}`,
28+
{
29+
headers: {
30+
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
31+
},
32+
method: 'POST',
33+
}
34+
);
35+
const captchaValidation = await response.json();
36+
37+
if (captchaValidation.success) {
38+
// Replace this with the API that will save the data received
39+
// to your backend
40+
await sleep();
41+
// Return 200 if everything is successful
42+
return res.status(200).send('OK');
43+
}
44+
45+
return res.status(422).json({
46+
message: 'Unprocessable request, Invalid captcha code',
47+
});
48+
} catch (error) {
49+
console.log(error);
50+
return res.status(422).json({ message: 'Something went wrong' });
51+
}
52+
}
53+
// Return 404 if someone pings the API with a method other than
54+
// POST
55+
return res.status(404).send('Not found');
56+
}

0 commit comments

Comments
 (0)