diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/pages/FormPage.tsx | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/src/pages/FormPage.tsx b/src/pages/FormPage.tsx index 1e331b9..9bd90d3 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"; @@ -154,6 +155,14 @@ const closedHeaderStyles = css` } `; +const captchaStyles = css` + text-align: center; + + @media (max-width: 850px) { + padding: 1.2rem; + } +`; + function FormPage(): JSX.Element { const { id } = useParams<PathParams>(); @@ -161,6 +170,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); @@ -208,6 +220,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) => { @@ -242,6 +257,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 } = {}; @@ -276,7 +296,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); } @@ -288,6 +314,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)) { + 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}/> @@ -296,6 +341,7 @@ function FormPage(): JSX.Element { <form id="form" onSubmit={handleSubmit} css={[formStyles, unselectable]}> { closed_header } { questions } + { captcha } </form> <Navigation form_state={open}/> </div> |