[Accessibility] Focus coupon input if it has an error (#48738)

* Focus cupon input if it has errors

* Add changelog file

* Add styles to coupon field with error on cart page

* Make coupon errors accessible on the cart page

* Add styles to coupon field with error on checkout page

* Rename coupon variables on cart

* Focus coupon field with error before updating live region on cart page

* Focus coupon field with error before updating live region on checkout page

* Remove incorrect early return

* Update coupon error notice test

* Improve coupon error message semantics

* Fix coupon errors for block based themes

* Update tests to not look for coupon errors on the notice block

* Rename coupon-error-message to coupon-error-notice

* Fix notice if coupon doesn't exist on tests

* FIx invalid coupon notice on classic theme test

* Update test for coupon inline notice

* Fix code formatting

Co-authored-by: Darin Kotter <darin.kotter@gmail.com>

* Fix code formatting

Co-authored-by: Darin Kotter <darin.kotter@gmail.com>

* Fix code formatting

Co-authored-by: Darin Kotter <darin.kotter@gmail.com>

* Fix code formatting

Co-authored-by: Darin Kotter <darin.kotter@gmail.com>

* Don't clear coupon input if code doesn't exist

* Create coupon error notice mixin

* Update coupon error notice styles

* Coupon error notice T19 compatibility

* Coupon error notice T17 compatibility

* Coupon error notice TT1 compatibility

* Coupon error notice TT compatibility

* Coupon error notice TT2 compatibility

* Coupon error notice TT3 compatibility

* Add spaces around paramenters

Co-authored-by: Darin Kotter <darin.kotter@gmail.com>

* Add spaces around paramenters

Co-authored-by: Darin Kotter <darin.kotter@gmail.com>

* Replace $red SCSS variable with a CSS one

* Keep input with the invalid coupon code after notice appears

* Fix typo in comment

Co-authored-by: Mike Jolley <mike.jolley@me.com>

* Fix typo in comment

Co-authored-by: Mike Jolley <mike.jolley@me.com>

* Break notice message into two lines

* Break if statement into two lines

---------

Co-authored-by: Darin Kotter <darin.kotter@gmail.com>
Co-authored-by: Mike Jolley <mike.jolley@me.com>
This commit is contained in:
Gabriel Manussakis 2024-08-23 15:22:28 -03:00 committed by GitHub
parent b4fd419f74
commit d773bb483a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 388 additions and 36 deletions

View File

@ -2,13 +2,14 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { useState, useRef } from '@wordpress/element';
import Button from '@woocommerce/base-components/button';
import LoadingMask from '@woocommerce/base-components/loading-mask';
import { withInstanceId } from '@wordpress/compose';
import {
ValidatedTextInput,
ValidationInputError,
ValidatedTextInputHandle,
Panel,
} from '@woocommerce/blocks-components';
import { useSelect } from '@wordpress/data';
@ -55,6 +56,7 @@ export const TotalsCoupon = ( {
validationErrorId: store.getValidationErrorId( textInputId ),
};
} );
const inputRef = useRef< ValidatedTextInputHandle >( null );
const handleCouponSubmit: MouseEventHandler< HTMLButtonElement > = (
e: MouseEvent< HTMLButtonElement >
@ -65,6 +67,8 @@ export const TotalsCoupon = ( {
if ( result ) {
setCouponValue( '' );
setIsCouponFormVisible( false );
} else if ( inputRef.current?.focus ) {
inputRef.current.focus();
}
} );
} else {
@ -104,6 +108,7 @@ export const TotalsCoupon = ( {
focusOnMount={ true }
validateOnMount={ false }
showError={ false }
ref={ inputRef }
/>
<Button
className="wc-block-components-totals-coupon__button"

View File

@ -26,6 +26,7 @@ import { getValidityMessageForInput } from '../../checkout/utils';
import { ValidatedTextInputProps } from './types';
export type ValidatedTextInputHandle = {
focus?: () => void;
revalidate: () => void;
};
@ -147,6 +148,9 @@ const ValidatedTextInput = forwardRef<
forwardedRef,
function () {
return {
focus() {
inputRef.current?.focus();
},
revalidate() {
validateInput( ! value );
},

View File

@ -15,7 +15,10 @@ import {
* Internal dependencies
*/
import { CheckoutPage } from '../checkout/checkout.page';
import { REGULAR_PRICED_PRODUCT_NAME } from '../checkout/constants';
import {
REGULAR_PRICED_PRODUCT_NAME,
INVALID_COUPON,
} from '../checkout/constants';
const test = base.extend< { checkoutPageObject: CheckoutPage } >( {
checkoutPageObject: async ( { page }, use ) => {
@ -41,7 +44,7 @@ test.describe( 'Shopper → Notice Templates', () => {
await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
} );
test( 'default block notice templates are visible', async ( {
test( 'default block notice templates, except for coupon errors, are visible', async ( {
frontendUtils,
page,
} ) => {
@ -70,10 +73,10 @@ test.describe( 'Shopper → Notice Templates', () => {
} )
).toBeVisible();
// We're explicitly checking the CSS classes of the block notices, and that the SVG is visible.
// We're explicitly checking the CSS classes of the block notices, and that the SVG is hidden.
await expect(
page.locator( '.wc-block-components-notice-banner.is-error svg' )
).toBeVisible();
).toBeHidden();
await page.getByLabel( 'Remove Polo from cart' ).click();
@ -89,7 +92,7 @@ test.describe( 'Shopper → Notice Templates', () => {
).toBeVisible();
} );
test( 'custom block notice templates are visible by template overwrite', async ( {
test( 'custom block notice templates, except for coupon errors, are visible by template overwrite', async ( {
requestUtils,
frontendUtils,
page,
@ -121,10 +124,10 @@ test.describe( 'Shopper → Notice Templates', () => {
page.getByText( 'BLOCK ERROR NOTICE: Coupon code already applied!' )
).toBeVisible();
// We're explicitly checking the CSS classes of the block notices, and that the SVG is visible.
// We're explicitly checking the CSS classes of the block notices, and that the SVG is hidden.
await expect(
page.locator( '.wc-block-components-notice-banner.is-error svg' )
).toBeVisible();
).toBeHidden();
await page.getByLabel( 'Remove Polo from cart' ).click();
@ -140,7 +143,7 @@ test.describe( 'Shopper → Notice Templates', () => {
await requestUtils.activateTheme( BLOCK_THEME_SLUG );
} );
test( 'classic notice templates are visible by template overwrite', async ( {
test( 'classic notice templates, except for coupon errors, are visible by template overwrite', async ( {
requestUtils,
frontendUtils,
page,
@ -177,7 +180,7 @@ test.describe( 'Shopper → Notice Templates', () => {
// We're explicitly checking the CSS classes of the classic notices.
await expect(
page.locator( '.woocommerce-notices-wrapper .woocommerce-error' )
).toBeVisible();
).toBeHidden();
await page.getByLabel( 'Remove Polo from cart' ).click();
@ -229,10 +232,10 @@ test.describe( 'Shopper → Notice Templates', () => {
} )
).toBeVisible();
// We're explicitly checking the CSS classes and that the SVG is visible.
// We're explicitly checking the CSS classes and that the SVG is hidden.
await expect(
page.locator( '.wc-block-components-notice-banner.is-error svg' )
).toBeVisible();
).toBeHidden();
await page.getByLabel( 'Remove Polo from cart' ).click();
@ -249,4 +252,26 @@ test.describe( 'Shopper → Notice Templates', () => {
await requestUtils.activateTheme( BLOCK_THEME_SLUG );
} );
test( 'coupon inline notice is visible', async ( {
frontendUtils,
page,
} ) => {
await frontendUtils.goToCartShortcode();
await page.getByPlaceholder( 'Coupon code' ).fill( INVALID_COUPON );
await page.getByRole( 'button', { name: 'Apply coupon' } ).click();
await expect(
page.getByText( `Coupon "${ INVALID_COUPON }" does not exist!`, {
exact: true,
} )
).toBeVisible();
// We're explicitly checking the CSS classes of the block notices, and that the SVG is hidden.
await expect(
page.locator( '.wc-block-components-notice-banner.is-error svg' )
).toBeHidden();
await expect( page.locator( '.coupon-error-notice' ) ).toBeVisible();
} );
} );

View File

@ -15,7 +15,10 @@ import {
* Internal dependencies
*/
import { CheckoutPage } from '../checkout/checkout.page';
import { REGULAR_PRICED_PRODUCT_NAME } from '../checkout/constants';
import {
REGULAR_PRICED_PRODUCT_NAME,
INVALID_COUPON,
} from '../checkout/constants';
const test = base.extend< { checkoutPageObject: CheckoutPage } >( {
checkoutPageObject: async ( { page }, use ) => {
@ -43,7 +46,7 @@ test.describe( 'Shopper → Notice Templates', () => {
await frontendUtils.addToCart( REGULAR_PRICED_PRODUCT_NAME );
} );
test( 'default classic notice templates are visible', async ( {
test( 'default classic notice templates, except for coupon errors, are visible', async ( {
frontendUtils,
page,
} ) => {
@ -73,7 +76,7 @@ test.describe( 'Shopper → Notice Templates', () => {
// We're explicitly checking the CSS classes of the classic notices.
await expect(
page.locator( '.woocommerce-notices-wrapper .woocommerce-error' )
).toBeVisible();
).toBeHidden();
await page.getByLabel( 'Remove Polo from cart' ).click();
@ -87,7 +90,7 @@ test.describe( 'Shopper → Notice Templates', () => {
).toBeVisible();
} );
test( 'custom classic notice templates are visible by template overwrite', async ( {
test( 'custom classic notice templates, except for coupon errors, are visible by template overwrite', async ( {
requestUtils,
frontendUtils,
page,
@ -124,7 +127,7 @@ test.describe( 'Shopper → Notice Templates', () => {
// We're explicitly checking the CSS classes of the classic notices.
await expect(
page.locator( '.woocommerce-notices-wrapper .woocommerce-error' )
).toBeVisible();
).toBeHidden();
await page.getByLabel( 'Remove Polo from cart' ).click();
@ -142,7 +145,7 @@ test.describe( 'Shopper → Notice Templates', () => {
await requestUtils.activateTheme( CLASSIC_THEME_SLUG );
} );
test( 'custom block notice templates are visible by template overwrite', async ( {
test( 'custom block notice templates, except for coupon errors, are visible by template overwrite', async ( {
requestUtils,
frontendUtils,
page,
@ -174,10 +177,10 @@ test.describe( 'Shopper → Notice Templates', () => {
page.getByText( 'BLOCK ERROR NOTICE: Coupon code already applied!' )
).toBeVisible();
// We're explicitly checking the CSS classes of the block notices, and that the SVG is visible.
// We're explicitly checking the CSS classes of the block notices, and that the SVG is hidden.
await expect(
page.locator( '.wc-block-components-notice-banner.is-error svg' )
).toBeVisible();
).toBeHidden();
await page.getByLabel( 'Remove Polo from cart' ).click();
@ -193,7 +196,7 @@ test.describe( 'Shopper → Notice Templates', () => {
await requestUtils.activateTheme( CLASSIC_THEME_SLUG );
} );
test( 'default block notice templates are visible by filter', async ( {
test( 'default block notice templates, except for coupon errors, are visible by filter', async ( {
requestUtils,
frontendUtils,
page,
@ -223,10 +226,10 @@ test.describe( 'Shopper → Notice Templates', () => {
page.getByText( 'Coupon code already applied!' )
).toBeVisible();
// We're explicitly checking the CSS classes and that the SVG is visible.
// We're explicitly checking the CSS classes and that the SVG is hidden.
await expect(
page.locator( '.wc-block-components-notice-banner.is-error svg' )
).toBeVisible();
).toBeHidden();
await page.getByLabel( 'Remove Polo from cart' ).click();
@ -241,4 +244,26 @@ test.describe( 'Shopper → Notice Templates', () => {
await requestUtils.activateTheme( CLASSIC_THEME_SLUG );
} );
test( 'coupon inline notice is visible', async ( {
frontendUtils,
page,
} ) => {
await frontendUtils.goToCartShortcode();
await page.getByPlaceholder( 'Coupon code' ).fill( INVALID_COUPON );
await page.getByRole( 'button', { name: 'Apply coupon' } ).click();
await expect(
page.getByText( `Coupon "${ INVALID_COUPON }" does not exist!`, {
exact: true,
} )
).toBeVisible();
// We're explicitly checking the CSS classes of the block notices, and that the SVG is hidden.
await expect(
page.locator( '.wc-block-components-notice-banner.is-error svg' )
).toBeHidden();
await expect( page.locator( '.coupon-error-notice' ) ).toBeVisible();
} );
} );

View File

@ -6,3 +6,4 @@ export const FLAT_RATE_SHIPPING_NAME = 'Flat rate shipping';
export const FLAT_RATE_SHIPPING_PRICE = '$10.00';
export const DISCOUNTED_PRODUCT_NAME = 'Cap';
export const REGULAR_PRICED_PRODUCT_NAME = 'Polo';
export const INVALID_COUPON = 'invalidcoupon';

View File

@ -0,0 +1,4 @@
Significance: patch
Type: enhancement
Move focus into coupon input if there is an error

View File

@ -300,3 +300,22 @@
color: #999;
}
}
@mixin coupon-error-notice-cart() {
clear: left;
color: var(--wc-red);
flex-basis: 100%;
float: none;
font-size: 0.75em;
margin-bottom: 0;
margin-top: 8px;
text-align: left;
width: auto;
}
@mixin coupon-error-notice-checkout() {
color: var(--wc-red);
display: block;
font-size: 0.75em;
margin-top: 8px;
}

View File

@ -1353,3 +1353,22 @@ table.variations {
color: #fff;
}
}
/**
* Coupon error notice
*/
.woocommerce-cart {
td.actions .coupon .coupon-error-notice {
@include coupon-error-notice-cart();
}
}
form.checkout_coupon {
.coupon-error-notice {
@include coupon-error-notice-checkout();
}
.input-text.has-error:focus {
border-color: var(--wc-red);
}
}

View File

@ -1257,3 +1257,22 @@ table.variations {
color: #fff;
}
}
/**
* Coupon error notice
*/
.woocommerce-cart {
td.actions .coupon .coupon-error-notice {
@include coupon-error-notice-cart();
}
}
form.checkout_coupon {
.coupon-error-notice {
@include coupon-error-notice-checkout();
}
.input-text.has-error:focus {
border-color: var(--wc-red);
}
}

View File

@ -3085,3 +3085,22 @@ a.reset_variations {
color: #000;
}
}
/**
* Coupon error notice
*/
.woocommerce-cart {
td.actions .coupon .coupon-error-notice {
@include coupon-error-notice-cart();
}
}
form.checkout_coupon {
.coupon-error-notice {
@include coupon-error-notice-checkout();
}
.input-text.has-error:focus {
border-color: var(--wc-red);
}
}

View File

@ -630,7 +630,6 @@ ul.wc-tabs {
#coupon_code {
float: left;
margin-bottom: 1rem;
}
}
}
@ -1152,3 +1151,23 @@ Notice messages (like 'Added to cart', 'Billing address needs to be filled in',
content: '\2713';
}
}
/**
* Coupon error notice
*/
.woocommerce-cart {
td.actions .coupon .coupon-error-notice {
@include coupon-error-notice-cart();
margin-top: 0;
}
}
form.checkout_coupon {
.coupon-error-notice {
@include coupon-error-notice-checkout();
}
.input-text.has-error:focus {
border-color: var(--wc-red);
}
}

View File

@ -1197,3 +1197,22 @@ ul.wc-tabs {
content: "\2713";
}
}
/**
* Coupon error notice
*/
.woocommerce-cart {
td.actions .coupon .coupon-error-notice {
@include coupon-error-notice-cart();
}
}
form.checkout_coupon {
.coupon-error-notice {
@include coupon-error-notice-checkout();
}
.input-text.has-error:focus {
border-color: var(--wc-red);
}
}

View File

@ -2412,3 +2412,22 @@ a.reset_variations {
color: #000;
}
}
/**
* Coupon error notice
*/
.woocommerce-cart {
td.actions .coupon .coupon-error-notice {
@include coupon-error-notice-cart();
}
}
form.checkout_coupon {
.coupon-error-notice {
@include coupon-error-notice-checkout();
}
.input-text.has-error:focus {
border-color: var(--wc-red);
}
}

View File

@ -310,6 +310,7 @@ a.added_to_cart {
.coupon {
display: flex;
align-items: center;
flex-wrap: wrap;
}
#coupon_code {

View File

@ -152,6 +152,16 @@
.button.alt {
float: right;
}
.coupon-error-notice {
clear: left;
color: var(--wc-red);
float: left;
font-size: 0.75em;
margin-bottom: 0;
text-align: left;
width: 48%;
}
}
.button {

View File

@ -1306,6 +1306,16 @@ p.demo_store,
border-radius: 5px;
}
form.checkout_coupon {
.coupon-error-notice {
@include coupon-error-notice-checkout();
}
.input-text.has-error:focus {
border-color: var(--wc-red);
}
}
ul#shipping_method {
list-style: none outside;
margin: 0;
@ -1971,6 +1981,14 @@ p.demo_store,
padding: 6px 6px 5px;
margin: 0 4px 0 0;
outline: 0;
&.has-error:focus {
border-color: var(--wc-red);
}
}
td.actions .coupon .coupon-error-notice {
@include coupon-error-notice-cart();
}
input {

View File

@ -104,7 +104,7 @@ jQuery( function ( $ ) {
// Remove errors
if ( ! preserve_notices ) {
$(
'.woocommerce-error, .woocommerce-message, .woocommerce-info, .is-error, .is-info, .is-success'
'.woocommerce-error, .woocommerce-message, .woocommerce-info, .is-error, .is-info, .is-success, .coupon-error-notice'
).remove();
}
@ -135,12 +135,30 @@ jQuery( function ( $ ) {
if ( $( '.woocommerce-checkout' ).length ) {
$( document.body ).trigger( 'update_checkout' );
}
// Store the old coupon error message and value before the
// .woocommerce-cart-form is replaced with the new form.
var $old_coupon_field_val = $( '#coupon_code' ).val();
var $old_coupon_error_msg = $( '#coupon_code' )
.closest( '.coupon' )
.find( '.coupon-error-notice' );
$( '.woocommerce-cart-form' ).replaceWith( $new_form );
$( '.woocommerce-cart-form' )
.find( ':input[name="update_cart"]' )
.prop( 'disabled', true );
if ( preserve_notices && $old_coupon_error_msg.length > 0 ) {
var $new_coupon_field = $( '.woocommerce-cart-form' ).find( '#coupon_code' );
var $new_coupon_field_wrapper = $new_coupon_field.closest( '.coupon' );
$new_coupon_field.val( $old_coupon_field_val );
// The coupon input with error needs to be focused before adding the live region
// with the error message, otherwise the screen reader won't read it.
$new_coupon_field.focus();
show_coupon_error( $old_coupon_error_msg, $new_coupon_field_wrapper, true );
}
if ( $notices.length > 0 ) {
show_notice( $notices );
}
@ -176,6 +194,43 @@ jQuery( function ( $ ) {
$target.prepend( html_element );
};
/**
* Shows coupon form errors.
*
* @param {string|object} html_element The HTML string response after applying an invalid coupon or a jQuery element.
* @param {Object} $target Coupon field wrapper jQuery element.
* @param {boolean} is_live_region Whether role="alert" should be added or not.
*/
var show_coupon_error = function ( html_element, $target, is_live_region ) {
if ( $target.length === 0 ) {
return;
}
var $coupon_error_el = '';
if ( typeof html_element === 'string' ) {
var msg = $( $.parseHTML( html_element ) ).text().trim();
if ( msg === '' ) {
return;
}
$coupon_error_el = $( '<p class="coupon-error-notice" id="coupon-error-notice">' + msg + '</p>' );
} else {
$coupon_error_el = html_element;
}
if ( is_live_region ) {
$coupon_error_el.attr( 'role', 'alert' );
}
$target.find( '#coupon_code' )
.addClass( 'has-error' )
.attr( 'aria-invalid', 'true' )
.attr( 'aria-describedby', 'coupon-error-notice' );
$target.append( $coupon_error_el );
};
/**
* Object to handle AJAX calls for cart shipping changes.
*/
@ -315,6 +370,7 @@ jQuery( function ( $ ) {
this.apply_coupon = this.apply_coupon.bind( this );
this.remove_coupon_clicked =
this.remove_coupon_clicked.bind( this );
this.remove_coupon_error = this.remove_coupon_error.bind( this );
this.quantity_update = this.quantity_update.bind( this );
this.item_remove_clicked = this.item_remove_clicked.bind( this );
this.item_restore_clicked = this.item_restore_clicked.bind( this );
@ -358,6 +414,11 @@ jQuery( function ( $ ) {
'.woocommerce-cart-form .cart_item :input',
this.input_changed
);
$( document ).on(
'blur change input',
'#coupon_code',
this.remove_coupon_error
);
$( '.woocommerce-cart-form :input[name="update_cart"]' ).prop(
'disabled',
@ -525,16 +586,28 @@ jQuery( function ( $ ) {
dataType: 'html',
success: function ( response ) {
$(
'.woocommerce-error, .woocommerce-message, .woocommerce-info, .is-error, .is-info, .is-success'
'.woocommerce-error, .woocommerce-message, .woocommerce-info, ' +
'.is-error, .is-info, .is-success, .coupon-error-notice'
).remove();
show_notice( response );
// We only want to show coupon notices if they are not errors.
// Coupon errors are shown under the input.
if ( response.indexOf( 'woocommerce-error' ) === -1 && response.indexOf( 'is-error' ) === -1 ) {
show_notice( response );
} else {
var $coupon_wrapper = $text_field.closest( '.coupon' );
if ( $coupon_wrapper.length > 0 ) {
show_coupon_error( response, $coupon_wrapper, false );
}
}
$( document.body ).trigger( 'applied_coupon', [
coupon_code,
] );
},
complete: function () {
unblock( $form );
$text_field.val( '' );
cart.update_cart( true );
},
} );
@ -578,6 +651,21 @@ jQuery( function ( $ ) {
} );
},
/**
* Handle when the coupon input loses focus.
*
* @param {Object} evt The JQuery event
*/
remove_coupon_error: function ( evt ) {
$( evt.currentTarget )
.removeClass( 'has-error' )
.removeAttr( 'aria-invalid' )
.removeAttr( 'aria-describedby' )
.closest( '.coupon' )
.find( '.coupon-error-notice' )
.remove();
},
/**
* Handle a cart Quantity Update
*

View File

@ -535,7 +535,8 @@ jQuery( function( $ ) {
wc_checkout_form.detachUnloadEventsOnSubmit();
try {
if ( 'success' === result.result && $form.triggerHandler( 'checkout_place_order_success', [ result, wc_checkout_form ] ) !== false ) {
if ( 'success' === result.result &&
$form.triggerHandler( 'checkout_place_order_success', [ result, wc_checkout_form ] ) !== false ) {
if ( -1 === result.redirect.indexOf( 'https://' ) || -1 === result.redirect.indexOf( 'http://' ) ) {
window.location = result.redirect;
} else {
@ -614,7 +615,8 @@ jQuery( function( $ ) {
init: function() {
$( document.body ).on( 'click', 'a.showcoupon', this.show_coupon_form );
$( document.body ).on( 'click', '.woocommerce-remove-coupon', this.remove_coupon );
$( 'form.checkout_coupon' ).hide().on( 'submit', this.submit );
$( document.body ).on( 'blur change input', '#coupon_code', this.remove_coupon_error );
$( 'form.checkout_coupon' ).hide().on( 'submit', this.submit.bind( this ) );
},
show_coupon_form: function() {
$( '.checkout_coupon' ).slideToggle( 400, function() {
@ -622,8 +624,36 @@ jQuery( function( $ ) {
});
return false;
},
submit: function() {
var $form = $( this );
show_coupon_error: function( html_element, $target ) {
if ( $target.length === 0 ) {
return;
}
var msg = $( $.parseHTML( html_element ) ).text().trim();
if ( msg === '' ) {
return;
}
$target.find( '#coupon_code' )
.focus()
.addClass( 'has-error' )
.attr( 'aria-invalid', 'true' )
.attr( 'aria-describedby', 'coupon-error-notice' );
$target.append( '<span class="coupon-error-notice" id="coupon-error-notice" role="alert">' + msg + '</span>' );
},
remove_coupon_error: function( evt ) {
$( evt.currentTarget )
.removeClass( 'has-error' )
.removeAttr( 'aria-invalid' )
.removeAttr( 'aria-describedby' )
.next( '.coupon-error-notice' )
.remove();
},
submit: function( evt ) {
var $form = $( evt.currentTarget );
var $coupon_field = $form.find( '#coupon_code' );
var self = this;
if ( $form.is( '.processing' ) ) {
return false;
@ -647,13 +677,20 @@ jQuery( function( $ ) {
type: 'POST',
url: wc_checkout_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'apply_coupon' ),
data: data,
success: function( code ) {
success: function( response ) {
$( '.woocommerce-error, .woocommerce-message, .is-error, .is-success' ).remove();
$form.removeClass( 'processing' ).unblock();
if ( code ) {
$form.before( code );
$form.slideUp();
if ( response ) {
// We only want to show coupon notices if they are no errors.
// Coupon errors are shown under the input.
if ( response.indexOf( 'woocommerce-error' ) === -1 && response.indexOf( 'is-error' ) === -1 ) {
$form.slideUp( 400, function() {
$form.before( response );
} );
} else {
self.show_coupon_error( response, $coupon_field.parent() );
}
$( document.body ).trigger( 'applied_coupon_in_checkout', [ data.coupon_code ] );
$( document.body ).trigger( 'update_checkout', { update_shipping_method: false } );
@ -699,6 +736,7 @@ jQuery( function( $ ) {
// Remove coupon code from coupon field
$( 'form.checkout_coupon' ).find( 'input[name="coupon_code"]' ).val( '' );
$( 'form.checkout_coupon' ).slideUp();
}
},
error: function ( jqXHR ) {