Skip to content

Commit 7081e2a

Browse files
ktx-krupaMonil-KTX
andauthored
feat: integrate reCAPTCHA for newsletter subscription form (#198)
* feat: integrate reCAPTCHA for newsletter subscription form * update toast message --------- Co-authored-by: ktx-monil <[email protected]>
1 parent 9c2afbc commit 7081e2a

File tree

1 file changed

+32
-86
lines changed

1 file changed

+32
-86
lines changed

overrides/partials/footer.html

Lines changed: 32 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
id="newsletter-error"
125125
class="tw-text-left tw-ml-2 tw-text-red-400 tw-text-sm tw-hidden"
126126
></div>
127+
127128
<!-- reCAPTCHA v2 Container - Hidden by default -->
128129
<div
129130
id="newsletter-recaptcha-container"
@@ -144,6 +145,7 @@
144145
</div>
145146
</div>
146147
</div>
148+
147149
<div
148150
class="tw-px-6 tw-py-2 tw-rounded-full tw-bg-[#7782FF] tw-text-white tw-text-sm tw-font-medium hover:tw-bg-[#6672fa]"
149151
>
@@ -179,8 +181,7 @@
179181
// Configuration
180182
const NEWSLETTER_CONFIG = window.NEWSLETTER_CONFIG || {
181183
RECAPTCHA_SITE_KEY: "6LdvUdMrAAAAAJksqV0YEwNBEBGL2SB90Gebun5n",
182-
NEWSLETTER_ENDPOINT:
183-
"https://5cciazu22tev222enhrbx6w3y40hscvu.lambda-url.us-east-2.on.aws",
184+
NEWSLETTER_ENDPOINT: "https://5cciazu22tev222enhrbx6w3y40hscvu.lambda-url.us-east-2.on.aws",
184185
FALLBACK_ENDPOINT:
185186
"https://5cciazu22tev222enhrbx6w3y40hscvu.lambda-url.us-east-2.on.aws",
186187
};
@@ -284,11 +285,11 @@
284285
) {
285286
recaptchaToken = token;
286287

287-
// // Hide loader immediately on success
288-
// const loader = document.getElementById("newsletter-captcha-loader");
289-
// if (loader) {
290-
// loader.style.display = "none";
291-
// }
288+
// Hide loader, show success state briefly
289+
const loader = document.getElementById("newsletter-captcha-loader");
290+
if (loader) {
291+
loader.style.display = "flex";
292+
}
292293

293294
// Auto-submit after reCAPTCHA completion (like Vue component)
294295
setTimeout(async () => {
@@ -305,10 +306,7 @@
305306
const recaptchaContainer = document.getElementById(
306307
"newsletter-recaptcha"
307308
);
308-
if (!recaptchaContainer) return;
309-
310-
// Clear any existing widget content first
311-
recaptchaContainer.innerHTML = "";
309+
if (!recaptchaContainer || recaptchaWidgetId !== null) return;
312310

313311
try {
314312
recaptchaWidgetId = window.grecaptcha.render(recaptchaContainer, {
@@ -318,8 +316,7 @@
318316
theme: "dark",
319317
});
320318
} catch (error) {
321-
// If render fails, reset the widget ID
322-
recaptchaWidgetId = null;
319+
// Silent error handling
323320
}
324321
}
325322

@@ -330,32 +327,15 @@
330327
"newsletter-recaptcha-container"
331328
);
332329
const recaptchaDiv = document.getElementById("newsletter-recaptcha");
333-
const loader = document.getElementById("newsletter-captcha-loader");
334330

335331
if (container) {
336332
container.classList.remove("tw-hidden");
337333
container.classList.add("tw-flex");
338334
}
339335

340-
// Ensure loader is hidden when showing reCAPTCHA
341-
if (loader) {
342-
loader.style.display = "none";
343-
}
344-
345-
// Always try to initialize reCAPTCHA, even if widget exists
336+
// Wait for DOM update, then render reCAPTCHA
346337
setTimeout(() => {
347-
if (recaptchaDiv && window.grecaptcha) {
348-
// Destroy existing widget if it exists
349-
if (recaptchaWidgetId !== null) {
350-
try {
351-
window.grecaptcha.reset(recaptchaWidgetId);
352-
} catch (error) {
353-
// If reset fails, clear the container
354-
recaptchaDiv.innerHTML = "";
355-
}
356-
recaptchaWidgetId = null;
357-
}
358-
// Always create a new widget
338+
if (recaptchaDiv && window.grecaptcha && !recaptchaWidgetId) {
359339
initializeRecaptcha();
360340
}
361341
}, 100);
@@ -372,20 +352,12 @@
372352
"Please complete the reCAPTCHA to proceed.",
373353
"error"
374354
);
375-
// Show submit button again
376-
const buttonContainer = subscribeBtn.parentElement;
377-
buttonContainer.style.display = "block";
355+
// Re-enable submit button
378356
subscribeBtn.disabled = false;
379357
subscribeBtn.textContent = "Subscribe";
380358
return;
381359
}
382360

383-
// Hide loader during processing
384-
const loader = document.getElementById("newsletter-captcha-loader");
385-
if (loader) {
386-
loader.style.display = "none";
387-
}
388-
389361
try {
390362
isSubmitting = true;
391363

@@ -401,9 +373,7 @@
401373
"Captcha validation failed. Please try again.",
402374
"error"
403375
);
404-
// Show submit button again
405-
const buttonContainer = subscribeBtn.parentElement;
406-
buttonContainer.style.display = "block";
376+
// Re-enable submit button
407377
subscribeBtn.disabled = false;
408378
subscribeBtn.textContent = "Subscribe";
409379
return;
@@ -432,23 +402,9 @@
432402
container.classList.remove("tw-flex");
433403
}
434404

435-
// Completely destroy and recreate reCAPTCHA widget
436-
if (window.grecaptcha && recaptchaWidgetId !== null) {
437-
try {
438-
window.grecaptcha.reset(recaptchaWidgetId);
439-
} catch (error) {
440-
// Silent error handling
441-
}
405+
if (window.grecaptcha && recaptchaWidgetId) {
406+
window.grecaptcha.reset(recaptchaWidgetId);
442407
}
443-
444-
// Clear the container and reset widget ID
445-
const recaptchaDiv = document.getElementById(
446-
"newsletter-recaptcha"
447-
);
448-
if (recaptchaDiv) {
449-
recaptchaDiv.innerHTML = "";
450-
}
451-
recaptchaWidgetId = null;
452408
recaptchaToken = "";
453409

454410
// Analytics tracking
@@ -487,23 +443,9 @@
487443
container.classList.remove("tw-flex");
488444
}
489445

490-
// Completely destroy and recreate reCAPTCHA widget on error
491-
if (window.grecaptcha && recaptchaWidgetId !== null) {
492-
try {
493-
window.grecaptcha.reset(recaptchaWidgetId);
494-
} catch (error) {
495-
// Silent error handling
496-
}
446+
if (window.grecaptcha && recaptchaWidgetId) {
447+
window.grecaptcha.reset(recaptchaWidgetId);
497448
}
498-
499-
// Clear the container and reset widget ID
500-
const recaptchaDiv = document.getElementById(
501-
"newsletter-recaptcha"
502-
);
503-
if (recaptchaDiv) {
504-
recaptchaDiv.innerHTML = "";
505-
}
506-
recaptchaWidgetId = null;
507449
recaptchaToken = "";
508450

509451
// GTM error tracking
@@ -517,9 +459,7 @@
517459
});
518460
} finally {
519461
isSubmitting = false;
520-
// Show submit button again
521-
const buttonContainer = subscribeBtn.parentElement;
522-
buttonContainer.style.display = "block";
462+
// Re-enable submit button
523463
subscribeBtn.disabled = false;
524464
subscribeBtn.textContent = "Subscribe";
525465
}
@@ -541,6 +481,7 @@
541481
setTimeout(() => toast.classList.add("tw-hidden"), 300);
542482
}, 4000);
543483
}
484+
544485
document.addEventListener("DOMContentLoaded", function () {
545486
const form = document.getElementById("newsletter-form");
546487
const emailInput = document.getElementById("newsletter-email");
@@ -550,37 +491,41 @@
550491
function validateEmail(email) {
551492
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
552493
}
553-
// Initialize reCAPTCHA when API is ready
554494

495+
// Initialize reCAPTCHA when API is ready
555496
if (window.grecaptcha && window.grecaptcha.render) {
556497
isRecaptchaLoaded = true;
557498
initializeRecaptcha();
558499
}
500+
559501
form.addEventListener("submit", async function (e) {
560502
e.preventDefault(); // Prevent form submission and URL changes
561503
e.stopPropagation(); // Stop event bubbling
504+
562505
emailError.classList.add("tw-hidden");
506+
563507
const email = emailInput.value.trim();
564508
if (!validateEmail(email)) {
565509
emailError.textContent = "Invalid email address";
566510
emailError.classList.remove("tw-hidden");
567511
return false; // Prevent further processing
568512
}
569513

570-
// Hide submit button after click
571-
const buttonContainer = subscribeBtn.parentElement;
572-
buttonContainer.style.display = "none";
514+
// Disable submit button to prevent multiple submissions
515+
subscribeBtn.disabled = true;
516+
subscribeBtn.textContent = "Processing...";
517+
573518
try {
574519
// Show reCAPTCHA (like Vue component submitForm)
575520
submitForm();
576521
} catch (error) {
577522
showToastMessage("An error occurred. Please try again.", "error");
578-
// Show submit button again on error
579-
const buttonContainer = subscribeBtn.parentElement;
580-
buttonContainer.style.display = "block";
523+
524+
// Re-enable submit button
581525
subscribeBtn.disabled = false;
582526
subscribeBtn.textContent = "Subscribe";
583527
}
528+
584529
return false; // Ensure no form submission happens
585530
});
586531
});
@@ -1136,6 +1081,7 @@
11361081
}
11371082
}
11381083
</style>
1084+
11391085
<!-- reCAPTCHA v2 Script -->
11401086
<script
11411087
src="https://www.google.com/recaptcha/api.js?onload=onRecaptchaLoad&render=explicit"

0 commit comments

Comments
 (0)