Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Disable "Place order" button in Checkout block if any errors are visible and add explicitDismiss option when throwing API errors #7783

Closed
wants to merge 34 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
01b73d3
Refactor Store Notices
mikejolley Nov 16, 2022
07bac08
Move new notice code to checkout package
mikejolley Nov 17, 2022
926976e
Combine store and snackbars
mikejolley Nov 18, 2022
5b0eb8d
Update noticeContexts imports
mikejolley Nov 18, 2022
1b9a205
Remove context provider
mikejolley Nov 18, 2022
98df34c
Update data store
mikejolley Nov 18, 2022
f3437f6
Fix 502
mikejolley Nov 18, 2022
d9c21d8
Add new error contexts
mikejolley Nov 18, 2022
23a0dbd
Force types
mikejolley Nov 18, 2022
59b8079
Unnecessary reorder of imports
mikejolley Nov 18, 2022
f89919b
Fix global handling
mikejolley Nov 18, 2022
7b07244
Document forceType
mikejolley Nov 21, 2022
7881fef
Optional props are undefined
mikejolley Nov 21, 2022
f384602
Remove function name
mikejolley Nov 21, 2022
ea0412d
Missing condition
mikejolley Nov 21, 2022
be6868d
Remove context prop
mikejolley Nov 21, 2022
b26e88c
Define ACTION_TYPES
mikejolley Nov 21, 2022
35d584e
Remove controls
mikejolley Nov 21, 2022
6ffc042
Update assets/js/base/context/event-emit/utils.ts
mikejolley Nov 21, 2022
c129e05
CONTACT_INFORMATION
mikejolley Nov 21, 2022
4718aab
Remove ref from registerContainer
mikejolley Nov 21, 2022
136763f
Abstract container locating methods
mikejolley Nov 21, 2022
4efa4af
pass context correctly when displaying notices
mikejolley Nov 21, 2022
e4a05f9
Remove debugging buttons
mikejolley Nov 21, 2022
39fa3af
Update filter usage - remove useMemo so filter can work inline
mikejolley Nov 21, 2022
3530786
Refactor existing error notices from the API (#7728)
mikejolley Nov 23, 2022
f1151f2
Prevent pressing the checkout button when any notices are visible
opr Nov 28, 2022
f63e347
Remove all notices *before* updating customer data
opr Nov 29, 2022
2905c15
Add explicitDismiss as a property on the ApiErrorResponse
opr Nov 29, 2022
f3eb177
Disable checkout button if there is an error in any wc reg'd context
opr Nov 29, 2022
96df881
Handle explicitDismiss from server errors
opr Nov 29, 2022
9e3c7cd
Ensure additional data from errors makes it into the API response
opr Nov 29, 2022
1064624
Add explicitDismiss to stock related errors
opr Nov 29, 2022
de4550a
Remove duplicate condition
opr Nov 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import { useCheckoutSubmit } from '@woocommerce/base-context/hooks';
import { Icon, check } from '@wordpress/icons';
import Button from '@woocommerce/base-components/button';
import { STORE_NOTICES_STORE_KEY } from '@woocommerce/block-data';
import { useSelect } from '@wordpress/data';

const PlaceOrderButton = (): JSX.Element => {
const {
Expand All @@ -15,13 +17,29 @@ const PlaceOrderButton = (): JSX.Element => {
waitingForRedirect,
} = useCheckoutSubmit();

const hasNoticesVisible = useSelect( ( select ) => {
const noticeContainers = select(
STORE_NOTICES_STORE_KEY
).getContainers();
const noticeStore = select( 'core/notices' );
return noticeContainers.some( ( container ) => {
return (
noticeStore
.getNotices( container )
.filter( ( notice ) => notice.status === 'error' ).length >
0
);
} );
} );

return (
<Button
className="wc-block-components-checkout-place-order-button"
onClick={ onSubmit }
disabled={
isCalculating ||
isDisabled ||
hasNoticesVisible ||
waitingForProcessing ||
waitingForRedirect
}
Expand Down
12 changes: 10 additions & 2 deletions assets/js/base/context/event-emit/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@ export enum responseTypes {
}

export enum noticeContexts {
PAYMENTS = 'wc/payment-area',
EXPRESS_PAYMENTS = 'wc/express-payment-area',
GLOBAL = 'wc/global',
CART = 'wc/cart',
CHECKOUT = 'wc/checkout',
PAYMENTS = 'wc/checkout/payments',
EXPRESS_PAYMENTS = 'wc/checkout/express-payments',
CONTACT_INFORMATION = 'wc/checkout/contact-information',
SHIPPING_ADDRESS = 'wc/checkout/shipping-address',
BILLING_ADDRESS = 'wc/checkout/billing-address',
SHIPPING_METHODS = 'wc/checkout/shipping-methods',
CHECKOUT_ACTIONS = 'wc/checkout/checkout-actions',
}

export interface ResponseType extends Record< string, unknown > {
Expand Down
54 changes: 23 additions & 31 deletions assets/js/base/context/hooks/cart/use-store-cart-coupons.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
/** @typedef { import('@woocommerce/type-defs/hooks').StoreCartCoupon } StoreCartCoupon */

/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import {
CART_STORE_KEY as storeKey,
VALIDATION_STORE_KEY,
} from '@woocommerce/block-data';
import { CART_STORE_KEY, VALIDATION_STORE_KEY } from '@woocommerce/block-data';
import { decodeEntities } from '@wordpress/html-entities';
import type { StoreCartCoupon } from '@woocommerce/types';
import { __experimentalApplyCheckoutFilter } from '@woocommerce/blocks-checkout';

/**
* Internal dependencies
Expand All @@ -21,39 +17,21 @@ import { useStoreCart } from './use-store-cart';
* This is a custom hook for loading the Store API /cart/coupons endpoint and an
* action for adding a coupon _to_ the cart.
* See also: https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/trunk/src/RestApi/StoreApi
*
* @return {StoreCartCoupon} An object exposing data and actions from/for the
* store api /cart/coupons endpoint.
*/
export const useStoreCartCoupons = ( context = '' ): StoreCartCoupon => {
const { cartCoupons, cartIsLoading } = useStoreCart();
const { createErrorNotice } = useDispatch( 'core/notices' );
const { createNotice } = useDispatch( 'core/notices' );
const { setValidationErrors } = useDispatch( VALIDATION_STORE_KEY );

const {
applyCoupon,
removeCoupon,
isApplyingCoupon,
isRemovingCoupon,
}: Pick<
StoreCartCoupon,
| 'applyCoupon'
| 'removeCoupon'
| 'isApplyingCoupon'
| 'isRemovingCoupon'
| 'receiveApplyingCoupon'
> = useSelect(
( select, { dispatch } ) => {
const store = select( storeKey );
const actions = dispatch( storeKey );

const { applyCoupon, removeCoupon, receiveApplyingCoupon } =
useDispatch( CART_STORE_KEY );
const { isApplyingCoupon, isRemovingCoupon } = useSelect(
( select ) => {
const store = select( CART_STORE_KEY );
return {
applyCoupon: actions.applyCoupon,
removeCoupon: actions.removeCoupon,
isApplyingCoupon: store.isApplyingCoupon(),
isRemovingCoupon: store.isRemovingCoupon(),
receiveApplyingCoupon: actions.receiveApplyingCoupon,
};
},
[ createErrorNotice, createNotice ]
Expand All @@ -62,7 +40,14 @@ export const useStoreCartCoupons = ( context = '' ): StoreCartCoupon => {
const applyCouponWithNotices = ( couponCode: string ) => {
applyCoupon( couponCode )
.then( ( result ) => {
if ( result === true ) {
if (
result === true &&
__experimentalApplyCheckoutFilter( {
filterName: 'showApplyCouponNotice',
defaultValue: true,
arg: { couponCode, context },
} )
) {
createNotice(
'info',
sprintf(
Expand Down Expand Up @@ -96,7 +81,14 @@ export const useStoreCartCoupons = ( context = '' ): StoreCartCoupon => {
const removeCouponWithNotices = ( couponCode: string ) => {
removeCoupon( couponCode )
.then( ( result ) => {
if ( result === true ) {
if (
result === true &&
__experimentalApplyCheckoutFilter( {
filterName: 'showRemoveCouponNotice',
defaultValue: true,
arg: { couponCode, context },
} )
) {
createNotice(
'info',
sprintf(
Expand Down
1 change: 0 additions & 1 deletion assets/js/base/context/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export * from './use-store-products';
export * from './use-store-add-to-cart';
export * from './use-customer-data';
export * from './use-checkout-address';
export * from './use-checkout-notices';
export * from './use-checkout-submit';
export * from './use-checkout-extension-data';
export * from './use-validation';
55 changes: 0 additions & 55 deletions assets/js/base/context/hooks/use-checkout-notices.js

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ import {
* Internal dependencies
*/
import { useEventEmitters, reducer as emitReducer } from './event-emit';
import type { emitterCallback } from '../../../event-emit';
import { emitterCallback, noticeContexts } from '../../../event-emit';
import { STATUS } from '../../../../../data/checkout/constants';
import { useStoreEvents } from '../../../hooks/use-store-events';
import { useCheckoutNotices } from '../../../hooks/use-checkout-notices';
import { CheckoutState } from '../../../../../data/checkout/default-state';
import {
getExpressPaymentMethods,
Expand Down Expand Up @@ -111,11 +110,29 @@ export const CheckoutEventsProvider = ( {
}

const { setValidationErrors } = useDispatch( VALIDATION_STORE_KEY );
const { createErrorNotice } = useDispatch( 'core/notices' );

const { dispatchCheckoutEvent } = useStoreEvents();
const { checkoutNotices, paymentNotices, expressPaymentNotices } =
useCheckoutNotices();
useSelect( ( select ) => {
const { getNotices } = select( 'core/notices' );
const checkoutContexts = Object.values( noticeContexts ).filter(
( context ) =>
context !== noticeContexts.PAYMENTS &&
context !== noticeContexts.EXPRESS_PAYMENTS
);
const allCheckoutNotices = checkoutContexts.reduce(
( acc, context ) => {
return [ ...acc, ...getNotices( context ) ];
},
[]
);
return {
checkoutNotices: allCheckoutNotices,
paymentNotices: getNotices( noticeContexts.PAYMENTS ),
expressPaymentNotices: getNotices(
noticeContexts.EXPRESS_PAYMENTS
),
};
}, [] );

const [ observers, observerDispatch ] = useReducer( emitReducer, {} );
const currentObservers = useRef( observers );
Expand Down Expand Up @@ -160,12 +177,7 @@ export const CheckoutEventsProvider = ( {
setValidationErrors,
} );
}
}, [
checkoutState.status,
setValidationErrors,
createErrorNotice,
checkoutActions,
] );
}, [ checkoutState.status, setValidationErrors, checkoutActions ] );

const previousStatus = usePrevious( checkoutState.status );
const previousHasError = usePrevious( checkoutState.hasError );
Expand Down Expand Up @@ -199,7 +211,6 @@ export const CheckoutEventsProvider = ( {
checkoutState.orderNotes,
previousStatus,
previousHasError,
createErrorNotice,
checkoutNotices,
expressPaymentNotices,
paymentNotices,
Expand Down
Loading