recaptcha updated
This commit is contained in:
parent
961758847d
commit
89aaa3d754
51
package-lock.json
generated
51
package-lock.json
generated
@ -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": {
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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<string | null>(null);
|
||||
const [recaptchaError, setRecaptchaError] = useState(false);
|
||||
const recaptchaRef = useRef<ReCAPTCHA>(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() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* reCAPTCHA */}
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<ReCAPTCHA
|
||||
ref={recaptchaRef}
|
||||
sitekey="6Lckq9MrAAAAABjBD9rQYm19BMGFFWiwb9mPiw2K"
|
||||
theme="dark"
|
||||
onChange={(token) => {
|
||||
setRecaptchaToken(token);
|
||||
setRecaptchaError(false);
|
||||
}}
|
||||
onExpired={() => setRecaptchaToken(null)}
|
||||
/>
|
||||
{recaptchaError && (
|
||||
<p className="text-red-400 text-xs font-sans tracking-wider mt-1">Please complete the reCAPTCHA verification.</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="group relative flex items-center justify-center w-full py-4 mt-6 bg-gradient-to-r from-[#c5a975] via-[#d9b876] to-[#c5a975] hover:from-[#e8dcb5] hover:via-[#c5a975] hover:to-[#e8dcb5] text-[#1a3a25] font-serif tracking-widest uppercase transition-all duration-500 rounded shadow-[0_5px_15px_rgba(0,0,0,0.3)] overflow-hidden"
|
||||
|
||||
@ -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 { User, Mail, Phone, Calendar, Clock, Users, MapPin } from "lucide-react";
|
||||
import SubpageLayout from "@/components/SubpageLayout";
|
||||
import AnimatedSection from "@/components/AnimatedSection";
|
||||
@ -19,10 +20,18 @@ export default function ReservationPage() {
|
||||
area: "Heritage Dining Court"
|
||||
});
|
||||
const [reserved, setReserved] = useState(false);
|
||||
const [recaptchaToken, setRecaptchaToken] = useState<string | null>(null);
|
||||
const [recaptchaError, setRecaptchaError] = useState(false);
|
||||
const recaptchaRef = useRef<ReCAPTCHA>(null);
|
||||
|
||||
const handleReserve = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!recaptchaToken) {
|
||||
setRecaptchaError(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const emailData = {
|
||||
name: formData.name,
|
||||
phone: formData.phone,
|
||||
@ -40,12 +49,16 @@ export default function ReservationPage() {
|
||||
{ headers: { "Content-Type": "application/json" } }
|
||||
);
|
||||
setReserved(true);
|
||||
setRecaptchaToken(null);
|
||||
recaptchaRef.current?.reset();
|
||||
setTimeout(() => {
|
||||
setReserved(false);
|
||||
setFormData({ ...formData, name: "", email: "", phone: "", date: "" });
|
||||
}, 6000);
|
||||
} catch (error) {
|
||||
console.error("Failed to send reservation", error);
|
||||
recaptchaRef.current?.reset();
|
||||
setRecaptchaToken(null);
|
||||
}
|
||||
};
|
||||
|
||||
@ -301,6 +314,23 @@ export default function ReservationPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* reCAPTCHA */}
|
||||
<div className="flex flex-col items-center gap-1 mt-3">
|
||||
<ReCAPTCHA
|
||||
ref={recaptchaRef}
|
||||
sitekey="6Lckq9MrAAAAABjBD9rQYm19BMGFFWiwb9mPiw2K"
|
||||
theme="dark"
|
||||
onChange={(token) => {
|
||||
setRecaptchaToken(token);
|
||||
setRecaptchaError(false);
|
||||
}}
|
||||
onExpired={() => setRecaptchaToken(null)}
|
||||
/>
|
||||
{recaptchaError && (
|
||||
<p className="text-red-400 text-xs font-sans tracking-wider mt-1">Please complete the reCAPTCHA verification.</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="group relative flex items-center justify-center w-full py-4 mt-8 bg-gradient-to-r from-[#c5a975] via-[#d9b876] to-[#c5a975] hover:from-[#e8dcb5] hover:via-[#c5a975] hover:to-[#e8dcb5] text-[#1a3a25] font-serif tracking-widest uppercase transition-all duration-500 rounded shadow-[0_5px_15px_rgba(0,0,0,0.3)] overflow-hidden"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user