1
0
Fork 0

Chore: Added recaptcha to Apply form (#2619)

* Added recaptcha v2 to Apply form

* fix

* fix import

* add recaptcha data in request payload

---------

Co-authored-by: Vasco Bettencourt <vasco.bettencourt@algolia.com>
This commit is contained in:
Natan Yagudayev 2025-06-06 11:47:27 -04:00 committed by GitHub
parent 0fc01a5c14
commit 67fcc5e656
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 87 additions and 35 deletions

View file

@ -27,7 +27,8 @@
"postcss-preset-env": "10.1.3",
"prism-react-renderer": "2.4.1",
"react": "^18.0.0",
"react-dom": "^18.0.0"
"react-dom": "^18.0.0",
"react-google-recaptcha": "^3.1.0"
},
"devDependencies": {
"tailwindcss": "3.4.17"

View file

@ -1,6 +1,7 @@
import { Button, Card, Heading1, InlineLink, Input, LabelText, Text } from '@algolia/ui-library';
import { useBaseUrlUtils } from '@docusaurus/useBaseUrl';
import React, { useState } from 'react';
import React, { useState, useRef } from 'react';
import { ReCAPTCHA } from 'react-google-recaptcha';
function ApplyForm() {
const { withBaseUrl } = useBaseUrlUtils();
@ -8,6 +9,7 @@ function ApplyForm() {
const [url, setUrl] = useState('');
const [email, setEmail] = useState('');
const [repo, setRepo] = useState('');
const recaptchaRef = useRef(null);
const handleSetUrl = (event) => {
setUrl(event.target.value);
@ -18,50 +20,68 @@ function ApplyForm() {
const handleSetRepo = (event) => {
setRepo(event.target.value);
};
const onSubmit = (event) => {
const onSubmit = async (event) => {
event.preventDefault();
if (state.status === 'loading') {
return;
}
// Check if reCAPTCHA is completed
const recaptchaValue = recaptchaRef.current?.getValue?.();
if (!recaptchaValue) {
setState({
status: 'failed',
message: 'Please complete the reCAPTCHA verification.',
});
return;
}
setState({ status: 'loading' });
const applyForm = event.target;
const method = applyForm.getAttribute('method');
const action = applyForm.getAttribute('action');
const formData = new FormData(applyForm);
const data = {};
formData.forEach(function (value, key) {
data[key] = value;
});
if (!data.repoURL) {
data.repoURL = 'https://www.github.com/algolia/docsearch';
}
const body = JSON.stringify(data);
try {
const applyForm = event.target;
const method = applyForm.getAttribute('method');
const action = applyForm.getAttribute('action');
const formData = new FormData(applyForm);
const data = {};
formData.forEach(function (value, key) {
data[key] = value;
});
if (!data.repoURL) {
data.repoURL = 'https://www.github.com/algolia/docsearch';
}
fetch(action, {
method,
headers: { 'Content-Type': 'application/json' },
body,
})
.then((response) => response.json())
.then(({ success, message }) => {
if (!success) {
return setState({
status: 'failed',
message: 'Unable to submit your request.',
});
}
data['g-recaptcha-response'] = recaptchaValue;
return setState({ status: 'succeed', message });
})
.catch(() =>
const body = JSON.stringify(data);
const response = await fetch(action, {
method,
headers: { 'Content-Type': 'application/json' },
body,
});
const { success, message } = await response.json();
if (!success) {
recaptchaRef.current?.reset();
setState({
status: 'failed',
message: 'Unable to submit your request.',
}),
);
});
}
// Reset reCAPTCHA after successful submission
recaptchaRef.current?.reset();
setState({ status: 'succeed', message });
} catch {
recaptchaRef.current?.reset();
setState({
status: 'failed',
message: 'Unable to submit your request.',
});
}
};
if (state.status === 'succeed' && state.message) {
@ -201,6 +221,12 @@ function ApplyForm() {
.
</LabelText>
<div className="uil-mt-16 uil-mb-16 uil-d-flex uil-jc-center uil-ai-center">
<div style={{ display: 'inline-block' }}>
<ReCAPTCHA ref={recaptchaRef} sitekey="6LeE9VcrAAAAAJ-MxCRdgKI0lxJIJs2PIVWlw-0z" theme="light" />
</div>
</div>
<Button
primary={true}
disabled={state.status === 'loading'}

View file

@ -2248,6 +2248,7 @@ __metadata:
prism-react-renderer: "npm:2.4.1"
react: "npm:^18.0.0"
react-dom: "npm:^18.0.0"
react-google-recaptcha: "npm:^3.1.0"
tailwindcss: "npm:3.4.17"
languageName: unknown
linkType: soft
@ -12014,7 +12015,7 @@ __metadata:
languageName: node
linkType: hard
"hoist-non-react-statics@npm:^3.1.0, hoist-non-react-statics@npm:^3.3.1":
"hoist-non-react-statics@npm:^3.1.0, hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.1":
version: 3.3.2
resolution: "hoist-non-react-statics@npm:3.3.2"
dependencies:
@ -18872,7 +18873,7 @@ __metadata:
languageName: node
linkType: hard
"prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
"prop-types@npm:^15.5.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@ -19076,6 +19077,18 @@ __metadata:
languageName: node
linkType: hard
"react-async-script@npm:^1.2.0":
version: 1.2.0
resolution: "react-async-script@npm:1.2.0"
dependencies:
hoist-non-react-statics: "npm:^3.3.0"
prop-types: "npm:^15.5.0"
peerDependencies:
react: ">=16.4.1"
checksum: 10c0/89450912110c380abc08258ce17d2fb18d31d6b7179a74f6bc504c0761a4ca271edb671e402fa8e5ea4250b5c17fa953af80a9f1c4ebb26c9e81caee8476c903
languageName: node
linkType: hard
"react-dev-utils@npm:^12.0.1":
version: 12.0.1
resolution: "react-dev-utils@npm:12.0.1"
@ -19169,6 +19182,18 @@ __metadata:
languageName: node
linkType: hard
"react-google-recaptcha@npm:^3.1.0":
version: 3.1.0
resolution: "react-google-recaptcha@npm:3.1.0"
dependencies:
prop-types: "npm:^15.5.0"
react-async-script: "npm:^1.2.0"
peerDependencies:
react: ">=16.4.1"
checksum: 10c0/5ecaa6b88f238defd939012cb2671b4cbda59fe03f059158994b8c5215db482412e905eae6a67d23cef220d77cfe0430ab91ce7849d476515cda72f3a8a0a746
languageName: node
linkType: hard
"react-helmet-async@npm:@slorber/react-helmet-async@*, react-helmet-async@npm:@slorber/react-helmet-async@1.3.0":
version: 1.3.0
resolution: "@slorber/react-helmet-async@npm:1.3.0"