diff --git a/.env.example b/.env.example index f6ca95d..2207ec5 100644 --- a/.env.example +++ b/.env.example @@ -4,4 +4,7 @@ NEXT_PUBLIC_SHOW_LOGGER="false" GRAPHQL_URL=https://some-url.com/graphql -SENDGRID_API_KEY=Abcde \ No newline at end of file +SENDGRID_API_KEY=Abcde + +RECAPTCHA_SITE_KEY=6LcXXX +RECAPTCHA_SECRET_KEY=6LcYYY \ No newline at end of file diff --git a/next.config.js b/next.config.js index 074b341..071fe6b 100644 --- a/next.config.js +++ b/next.config.js @@ -48,6 +48,10 @@ const nextConfig = { }, ]; }, + + experimental: { + serverActions: true, + }, }; module.exports = nextConfig; diff --git a/package.json b/package.json index 05c7e9c..c918e18 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@heroicons/react": "^2.0.18", "@mui/material": "^5.13.5", "@sendgrid/mail": "^7.7.0", + "@types/react-google-recaptcha": "^2.1.5", "@types/styled-components": "^5.1.0", "classnames": "^2.3.2", "clsx": "^2.0.0", @@ -43,6 +44,7 @@ "plop": "^3.1.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-google-recaptcha": "^3.1.0", "react-headroom": "^3.2.1", "react-i18next": "^13.2.0", "react-icons": "^4.10.1", diff --git a/src/components/molecules/ContactForm/ContactForm.tsx b/src/components/molecules/ContactForm/ContactForm.tsx index 6aaf15b..f22c39f 100644 --- a/src/components/molecules/ContactForm/ContactForm.tsx +++ b/src/components/molecules/ContactForm/ContactForm.tsx @@ -1,10 +1,13 @@ 'use client'; import { Form, Formik } from 'formik'; -import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; +import { useEffect, useRef, useState } from 'react'; +import ReCAPTCHA from 'react-google-recaptcha'; +import { Trans, useTranslation } from 'react-i18next'; import * as Yup from 'yup'; +import { verifyCaptcha } from '@/lib/verifyCaptcha'; + import { Input } from '@/components/atoms/Input/Input'; import { Select } from '@/components/atoms/select/Select'; import { TextArea } from '@/components/atoms/TextArea/TextArea'; @@ -23,6 +26,25 @@ const ContactForm = () => { const [success, setSuccess] = useState(false); const [error, setError] = useState(false); + const recaptchaRef = useRef(null); + const [isVerified, setIsVerified] = useState(false); + + const reCaptchaSiteKey = '6LcSyzAoAAAAAC7JTJ6gtOWW3cjTK_vKRm2WjEtC'; + + async function handleCaptchaSubmission(token: string | null) { + // Server function to verify captcha + await verifyCaptcha(token) + .then(() => { + setIsVerified(true); + }) + .catch(() => { + setIsVerified(false); + setError(true); + }); + } + + useEffect(() => {}, [isVerified]); + const { t } = useTranslation(); const subjects = [ @@ -78,6 +100,7 @@ const ContactForm = () => { setSubmitting(false); setSuccess(true); resetForm(); + recaptchaRef.current?.reset(); }; return ( @@ -104,7 +127,10 @@ const ContactForm = () => { )} {error && (
- {t('contacts.error')} + + + info@martacodes.it +
)} @@ -139,7 +165,19 @@ const ContactForm = () => { />
-
+ +
+