From 89aaa3d754bed099b5576eb11da9ae5e7251384f Mon Sep 17 00:00:00 2001 From: selvi Date: Tue, 11 Aug 2026 10:53:22 +0530 Subject: [PATCH] recaptcha updated --- package-lock.json | 51 ++++++++++++++++++++++++++++++++---- package.json | 2 ++ src/app/contact/page.tsx | 31 +++++++++++++++++++++- src/app/reservation/page.tsx | 32 +++++++++++++++++++++- 4 files changed, 109 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7818574..6a0aab1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@react-three/drei": "^10.7.7", "@react-three/fiber": "^9.6.1", + "@types/react-google-recaptcha": "^2.1.9", "axios": "^1.19.0", "framer-motion": "^12.42.2", "gsap": "^3.15.0", @@ -19,6 +20,7 @@ "next": "16.2.10", "react": "19.2.4", "react-dom": "19.2.4", + "react-google-recaptcha": "^3.1.0", "selenium-webdriver": "^4.46.0", "three": "^0.185.1", "xml2js": "^0.6.2" @@ -1814,6 +1816,15 @@ "@types/react": "^19.2.0" } }, + "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==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-reconciler": { "version": "0.28.9", "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz", @@ -4517,6 +4528,15 @@ "integrity": "sha512-VSIRpLfRwlAAdGL4wiTucx2ScRipo0ed1FBatWkyt832jC4CReKstga6yIhYVwGu9LOBjuX9wzmRMeQdBJtzEA==", "license": "Apache-2.0" }, + "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==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -5108,7 +5128,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -5581,7 +5600,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -6437,7 +6455,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6763,7 +6780,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, "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -6820,6 +6836,19 @@ "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==", + "license": "MIT", + "dependencies": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, "node_modules/react-dom": { "version": "19.2.4", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", @@ -6832,11 +6861,23 @@ "react": "^19.2.4" } }, + "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==", + "license": "MIT", + "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, "license": "MIT" }, "node_modules/react-use-measure": { diff --git a/package.json b/package.json index 8578d13..aa4d573 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "dependencies": { "@react-three/drei": "^10.7.7", "@react-three/fiber": "^9.6.1", + "@types/react-google-recaptcha": "^2.1.9", "axios": "^1.19.0", "framer-motion": "^12.42.2", "gsap": "^3.15.0", @@ -22,6 +23,7 @@ "next": "16.2.10", "react": "19.2.4", "react-dom": "19.2.4", + "react-google-recaptcha": "^3.1.0", "selenium-webdriver": "^4.46.0", "three": "^0.185.1", "xml2js": "^0.6.2" diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx index c358bac..895f4fa 100644 --- a/src/app/contact/page.tsx +++ b/src/app/contact/page.tsx @@ -1,8 +1,9 @@ "use client"; -import { useState } from "react"; +import { useState, useRef } from "react"; import axios from "axios"; import Image from "next/image"; +import ReCAPTCHA from "react-google-recaptcha"; import { Phone, Mail, MapPin, Clock, UtensilsCrossed, ShoppingBag, Truck, ChefHat } from "lucide-react"; import SubpageLayout from "@/components/SubpageLayout"; import InnerBanner from "@/components/InnerBanner"; @@ -28,9 +29,16 @@ const CornerOrnaments = () => ( export default function ContactPage() { const [formData, setFormData] = useState({ name: "", email: "", phone: "", subject: "", msg: "" }); const [submitted, setSubmitted] = useState(false); + const [recaptchaToken, setRecaptchaToken] = useState(null); + const [recaptchaError, setRecaptchaError] = useState(false); + const recaptchaRef = useRef(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); + if (!recaptchaToken) { + setRecaptchaError(true); + return; + } if (formData.name && formData.email && formData.msg) { const emailData = { name: formData.name, @@ -49,12 +57,16 @@ export default function ContactPage() { { headers: { "Content-Type": "application/json" } } ); setSubmitted(true); + setRecaptchaToken(null); + recaptchaRef.current?.reset(); setTimeout(() => { setSubmitted(false); setFormData({ name: "", email: "", phone: "", subject: "", msg: "" }); }, 5000); } catch (error) { console.error("Failed to send message", error); + recaptchaRef.current?.reset(); + setRecaptchaToken(null); } } }; @@ -302,6 +314,23 @@ export default function ContactPage() { /> + {/* reCAPTCHA */} +
+ { + setRecaptchaToken(token); + setRecaptchaError(false); + }} + onExpired={() => setRecaptchaToken(null)} + /> + {recaptchaError && ( +

Please complete the reCAPTCHA verification.

+ )} +
+