From 45c8152888c50bedb7f594804239b4bde10a97a0 Mon Sep 17 00:00:00 2001 From: Rasmy Nguyen Date: Mon, 16 Dec 2024 12:18:54 -0500 Subject: [PATCH] fix(recaptcha): replace alerts with generic errors (#3627) This PR replaces the default recaptcha failure alert behavior with generic errors appended to the relevant forms. --- src/other-scripts/recaptcha/index.js | 52 ++++++++++++++++++++++---- src/other-scripts/recaptcha/style.scss | 6 +++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/other-scripts/recaptcha/index.js b/src/other-scripts/recaptcha/index.js index 427efccc98..a7f7a61904 100644 --- a/src/other-scripts/recaptcha/index.js +++ b/src/other-scripts/recaptcha/index.js @@ -95,6 +95,39 @@ function addHiddenField( form ) { } } +/** + * Append a generic error message above the given form. + * + * @param {HTMLElement} form The form element. + * @param {string} message The error message to display. + */ +function addErrorMessage( form, message ) { + const errorText = document.createElement( 'p' ); + errorText.textContent = message; + const container = document.createElement( 'div' ); + container.classList.add( 'newspack-recaptcha-error' ); + container.appendChild( errorText ); + // Newsletters block errors render below the form. + if ( form.parentElement.classList.contains( 'newspack-newsletters-subscribe' ) ) { + form.append( container ); + } else { + container.classList.add( 'newspack-ui__notice', 'newspack-ui__notice--error' ); + form.insertBefore( container, form.firstChild ); + } +} + +/** + * Remove generic error messages from form if present. + * + * @param {HTMLElement} form The form element. + */ +function removeErrorMessages( form ) { + const errors = form.querySelectorAll( '.newspack-recaptcha-error' ); + for ( const error of errors ) { + error.parentElement.removeChild( error ); + } +} + /** * Remove the hidden reCAPTCHA v3 token field from the given form. * @@ -168,6 +201,14 @@ function renderWidget( form, onSuccess = null, onError = null ) { refreshWidget( button ); }; + const errorCallback = ( message ) => { + if ( onError ) { + onError( message ); + } else { + addErrorMessage( form, message ); + } + } + // Render reCAPTCHA widget. See https://developers.google.com/recaptcha/docs/invisible#js_api for API reference. const widgetId = grecaptcha.render( button, { ...options, @@ -179,17 +220,12 @@ function renderWidget( form, onSuccess = null, onError = null ) { refreshWidget( button ); } else { clearInterval( refreshIntervalId ); + button.disabled = true; } const message = retryCount < 3 ? wp.i18n.__( 'There was an error connecting with reCAPTCHA. Please try submitting again.', 'newspack-plugin' ) : wp.i18n.__( 'There was an error connecting with reCAPTCHA. Please reload the page and try again.', 'newspack-plugin' ); - if ( onError ) { - onError( message ); - } else { - // Recaptcha's default error behavior is to alert with the above message. - // eslint-disable-next-line no-alert - alert( message ); - } + errorCallback( message ); }, 'expired-callback': () => { refreshWidget( button ); @@ -202,6 +238,8 @@ function renderWidget( form, onSuccess = null, onError = null ) { button.addEventListener( 'click', e => { e.preventDefault(); e.stopImmediatePropagation(); + // Empty error messages if present. + removeErrorMessages( form ); // Skip reCAPTCHA verification if the button has a data-skip-recaptcha attribute. if ( button.hasAttribute( 'data-skip-recaptcha' ) ) { successCallback(); diff --git a/src/other-scripts/recaptcha/style.scss b/src/other-scripts/recaptcha/style.scss index 52fdd4451e..b6bfb43f17 100644 --- a/src/other-scripts/recaptcha/style.scss +++ b/src/other-scripts/recaptcha/style.scss @@ -13,3 +13,9 @@ inset: 0 !important; // Prevents an odd side-scroll issue in the registration modal & block. visibility: hidden !important; } + +.newspack-recaptcha-error { + &.newspack-ui__notice--error { + margin-top: 0 !important; + } +}