aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/pages/FormPage.tsx48
1 files changed, 46 insertions, 2 deletions
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx
index 8852ac5..2022d43 100644
--- a/src/pages/FormPage.tsx
+++ b/src/pages/FormPage.tsx
@@ -2,7 +2,8 @@
import { jsx, css } from "@emotion/react";
import { Link } from "react-router-dom";
-import React, { SyntheticEvent, useEffect, useState, createRef } from "react";
+import HCaptcha from "@hcaptcha/react-hcaptcha";
+import React, {SyntheticEvent, useEffect, useState, createRef, useRef} from "react";
import { useParams } from "react-router";
import { PropagateLoader } from "react-spinners";
@@ -143,6 +144,12 @@ const closedHeaderStyles = css`
}
`;
+const captchaStyles = css`
+ text-align: center;
+
+ margin-bottom: 1.5rem;
+`;
+
function FormPage(): JSX.Element {
const { id } = useParams<PathParams>();
@@ -150,6 +157,9 @@ function FormPage(): JSX.Element {
const [sending, setSending] = useState<boolean>();
const [sent, setSent] = useState<boolean>();
+ let captchaToken: string | null = null;
+ const captchaRef = useRef<HCaptcha>(null);
+
useEffect(() => {
getForm(id).then(form => {
setForm(form);
@@ -197,6 +207,9 @@ function FormPage(): JSX.Element {
async function handleSubmit(event: SyntheticEvent) {
event.preventDefault();
+ // Make copy to avoid losing value on state change.
+ const submitCaptchaToken = captchaToken;
+
// Client-side required validation
const invalidFieldIDs: number[] = [];
questions.forEach((prop, i) => {
@@ -231,6 +244,11 @@ function FormPage(): JSX.Element {
return;
}
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ if (!(FormFeatures.DisableAntispam in form!.features) && !submitCaptchaToken && captchaRef && captchaRef.current) {
+ captchaRef.current.execute();
+ }
+
setSending(true);
const answers: { [key: string]: unknown } = {};
@@ -265,7 +283,13 @@ function FormPage(): JSX.Element {
}
});
- await ApiClient.post(`forms/submit/${id}`, {response: answers});
+ const data: { [key: string]: unknown } = {response: answers};
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ if (!(FormFeatures.DisableAntispam in form!.features)) {
+ data["captcha"] = submitCaptchaToken;
+ }
+
+ await ApiClient.post(`forms/submit/${id}`, data);
setSending(false);
setSent(true);
}
@@ -284,6 +308,25 @@ function FormPage(): JSX.Element {
closed_header = <div css={closedHeaderStyles}>This form is now closed. You will not be able to submit your response.</div>;
}
+ let captcha = null;
+ if (!(FormFeatures.DisableAntispam in form.features) && open) {
+ captcha = (
+ <div css={captchaStyles}>
+ <HCaptcha
+ sitekey={process.env.HCAPTCHA_SITEKEY ? process.env.HCAPTCHA_SITEKEY : ""}
+ theme="dark"
+ onVerify={token => {
+ captchaToken = token;
+ }}
+ onExpire={() => {
+ captchaToken = null;
+ }}
+ ref={captchaRef}
+ />
+ </div>
+ );
+ }
+
return (
<div>
<HeaderBar title={form.name} description={form.description}/>
@@ -293,6 +336,7 @@ function FormPage(): JSX.Element {
{ closed_header }
{ questions }
</form>
+ { captcha }
<Navigation form_state={open} scopes={scopes}/>
</div>