From 2fc48ef5f4ecb1ff727b49668da864781054ab4b Mon Sep 17 00:00:00 2001 From: bega Date: Tue, 19 Nov 2024 09:05:04 +0800 Subject: [PATCH] added recaptcha to the contact form --- package-lock.json | 47 +++++++++++++++++++++++++++++-- package.json | 2 ++ src/app/layout.tsx | 1 + src/sections/form/FormSection.tsx | 36 ++++++++++++++++++++--- 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index f75aee0..b0e7f21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "next-themes": "0.3.0", "react": "18", "react-dom": "18", + "react-google-recaptcha": "3.1.0", "sonner": "1.5.0", "tailwind-merge": "2.5.3", "tailwindcss-animate": "1.0.7", @@ -38,6 +39,7 @@ "@types/node": "20", "@types/react": "18", "@types/react-dom": "18", + "@types/react-google-recaptcha": "2.1.9", "eslint": "8", "eslint-config-next": "14.2.15", "postcss": "8", @@ -1083,6 +1085,15 @@ "@types/react": "*" } }, + "node_modules/@types/react-google-recaptcha": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.9.tgz", + "integrity": "sha512-nT31LrBDuoSZJN4QuwtQSF3O89FVHC4jLhM+NtKEmVF5R1e8OY0Jo4//x2Yapn2aNHguwgX5doAq8Zo+Ehd0ug==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.8.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz", @@ -3144,6 +3155,14 @@ "node": ">= 0.4" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4472,7 +4491,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -4518,6 +4536,18 @@ "node": ">=0.10.0" } }, + "node_modules/react-async-script": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", + "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", + "dependencies": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -4530,11 +4560,22 @@ "react": "^18.3.1" } }, + "node_modules/react-google-recaptcha": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz", + "integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==", + "dependencies": { + "prop-types": "^15.5.0", + "react-async-script": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-remove-scroll": { "version": "2.6.0", diff --git a/package.json b/package.json index 9cab216..9a0f573 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "next-themes": "0.3.0", "react": "18", "react-dom": "18", + "react-google-recaptcha": "3.1.0", "sonner": "1.5.0", "tailwind-merge": "2.5.3", "tailwindcss-animate": "1.0.7", @@ -39,6 +40,7 @@ "@types/node": "20", "@types/react": "18", "@types/react-dom": "18", + "@types/react-google-recaptcha": "2.1.9", "eslint": "8", "eslint-config-next": "14.2.15", "postcss": "8", diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 2a185b0..b12537d 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -19,6 +19,7 @@ const RootLayout = (props: TProps) => { type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(structuredData) }} /> + ); diff --git a/src/sections/form/FormSection.tsx b/src/sections/form/FormSection.tsx index 518b175..3234114 100644 --- a/src/sections/form/FormSection.tsx +++ b/src/sections/form/FormSection.tsx @@ -10,6 +10,7 @@ import { cn } from '@/lib/utils'; import email from '@emailjs/browser'; import { Loader } from 'lucide-react'; import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react'; +import ReCAPTCHA from 'react-google-recaptcha'; const initialData = { name: '', @@ -23,6 +24,7 @@ const FormSection: React.FC = () => { // States const [loading, setLoading] = useState(false); const [data, setData] = useState(initialData); + const [recaptchaToken, setRecaptchaToken] = useState(null); // Hooks const { toast } = useToast(); @@ -57,6 +59,10 @@ const FormSection: React.FC = () => { setData(initialData); }; + const handleRecaptchaChange = (token: string | null) => { + setRecaptchaToken(token); + }; + const handleSubmit = async (event: FormEvent) => { event.preventDefault(); @@ -76,11 +82,20 @@ const FormSection: React.FC = () => { setLoading(true); try { - const { name: from_name, email: from_email, message } = data; - const formData = { from_name, from_email, message: message }; + const formData = { + from_name: data.name, + from_email: data.email, + message: data.message, + 'g-recaptcha-response': recaptchaToken, + }; + const res = await email.send(serviceId, templateId, formData); + handleResponse(res.status); - } catch (error) { + } catch (error: any) { + if (error?.status) { + handleResponse(error?.status); + } console.error(error); } @@ -155,7 +170,20 @@ const FormSection: React.FC = () => { -