React Comments is a Disqus-like comment feature for Drupal 8. It is a much more beautiful alternative to the Ajax Comments module, which we had migrated to Drupal 8 as an initial solution. The only thing missing in React Comments for our purposes was ReCaptcha integration.
There are various ReCaptcha components for React. We tried a few and decided on react-recaptcha-google. We added that package to the project (yarn add react-recaptcha-google
) and added an implementation of that component:
cd react_comments/js/src/
cat src/components/CommentReacaptcha.js
import React, { Component } from "react";
import "./CommentReacaptcha.css";
import { ReCaptcha } from "react-recaptcha-google";
class CommentReacaptcha extends Component {
constructor(props, context) {
super(props, context);
this.onLoadRecaptcha = this.onLoadRecaptcha.bind(this);
this.verifyCallback = this.verifyCallback.bind(this);
}
componentDidMount() {
if (this.captchaDemo) {
this.captchaDemo.reset();
}
}
resetCaptcha() {
this.captchaDemo.reset();
}
onLoadRecaptcha() {
if (this.captchaDemo) {
this.captchaDemo.reset();
}
}
verifyCallback(recaptchaToken) {
this.props.verified(recaptchaToken);
}
render() {
let containerClasses = ["rc_comment-recap-container"];
return (
<div className={containerClasses}>
<ReCaptcha
ref={(el) => {
this.captchaDemo = el;
}}
size="normal"
render="explicit"
sitekey="<our-site-key>"
onloadCallback={this.onLoadRecaptcha}
verifyCallback={this.verifyCallback}
/>
</div>
);
}
}
export default CommentReacaptcha;
We imported the component to App.js:
cat src/App.js | awk 'NR >= 9 && NR <= 10'
import { loadReCaptcha } from "react-recaptcha-google";
import CommentReacaptcha from "./components/CommentReacaptcha";
We added state variable that will indicate whether captcha is verified or not:
cat src/App.js | awk 'NR >= 12 && NR <= 22'
class App extends Component {
state = {
currentUser: {
hasPermission: () => false
},
comments: null,
settings: null,
loading: true,
openMenu: null,
captchaVerified: false,
};
We added a callback method that will update the state variable:
cat src/App.js | awk 'NR >= 180 && NR <= 182'
captchaVerified(token) {
this.setState({captchaVerified: !!token})
}
Added component to render:
cat src/App.js | awk 'NR >= 203 && NR <= 203'
<CommentReacaptcha verified={this.captchaVerified.bind(this)} />
Finally, added an attribute in CommentBox component to disable comment button if captcha is not verified:
cat src/components/CommentBox.js | awk 'NR >= 209 && NR <= 209'
{
type === "comment" && user && userCanPostComments && (
<button
disabled={!this.props.captchaVerified}
onClick={this.handlePost.bind(this)}
className="rc_add-comment"
>
Post your comment{user.name && ` as ${user.name}`}
</button>
);
}
One last issue:
Once in a while, the browser would throw an error complaining something about grecaptcha.render
not being a function. The fix is to check for that in the module. We first tried to patch the module with npm but there is a mismatch betweeen the version of react-recaptcha-google
in npmjs.com and that in GitHub. So we forked the repo and added our own patch to it:
git clone git@github.com:henokmikre/react-recaptcha-google.git
cd react-recaptcha-google/
git checkout 2718b3675098a6b9856aaf1af4df57ed10df6011 -b v2
vi src/ReCaptcha.js
yarn install
yarn build
git commit -am "Added error handling for grecaptcha.render."
Here is the exact change (which was actually taken from another npm package appleboy/react-recaptcha
):
diff --git a/src/ReCaptcha.js b/src/ReCaptcha.js
index 674e746..8df8a7a 100644
--- a/src/ReCaptcha.js
+++ b/src/ReCaptcha.js
@@ -37,7 +37,11 @@ const defaultProps = {
badge: 'bottomright',
};
-const isReady = () => typeof window !== 'undefined' && typeof window.grecaptcha !== 'undefined';
+const isReady = () =>
+ typeof window !== "undefined"
+ && typeof window.grecaptcha !== 'undefined'
+ // need to check for presence of render, because reCaptcha creates { ready } first
+ && !!window.grecaptcha.render;
git push origin v2
We then added the forked version of react-recaptcha-google
in react_comments
yarn.lock. A better approach would be to use a component based on ReCaptcha v3.
Last step was to rebuild the React. But we first need to make sure we have the build tools:
# Install nodejs
curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -
sudo yum install -y nodejs
# Install yarn
curl --silent --location https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
sudo yum install -y yarn
# Install packages
yum install
Now we can build:
./build.php
That's all!