This repository has been archived by the owner on Feb 23, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 219
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move checkout state code into thunks and rename
CheckoutState
conte…
…xt to `CheckoutEvents` (#6455) * Add checkout data store * wip on checkout data store * CheckoutContext now uses the checkout store * Investigated and removed setting the redirectUrl on the default state * update extension and address hooks to use checkout data store * use checkout data store in checkout-processor and use-checkout-button * trim useCheckoutContext from use-payment-method-interface && use-store-cart-item-quantity * Remove useCheckoutContext from shipping provider * Remove isCalculating from state * Removed useCheckoutContext from lots of places * Remove useCheckoutContext from checkout-payment-block * Remove useCheckoutContext in checkout-shipping-methods-block and checkout-shipping-address-block * add isCart selector and action and update the checkoutstate context * Fixed redirectUrl bug by using thunks * Remove dispatchActions from checkout-state * Change SET_HAS_ERROR action to be neater * Thomas' feedback * Tidy up * Oops, deleted things I shouldn't have * Typescript * Fix types * Fix tests * Remove isCart * Update docs and remove unecessary getRedirectUrl() selector * validate event emitter button * Added thunks in a separate file * Call thunks from checkout-state * Checkout logic tested and working * Remove dependency injection as much as poss, tidy up and fix some TS errors * Fix types in thunks.ts * Fixed some ts errors * WIP * Fixed bug * Shift side effects from checkout-state to checkout-processor * Revert "Shift side effects from checkout-state to checkout-processor" This reverts commit 059533d. * Rename CheckoutState to CheckoutEvents * Move status check outside the thunk * remove duplicate EVENTS constant * remove temp buttons * Remove console logs * Augment @wordpress/data package with our new store types * Add correct type for CheckoutAction * Remove createErrorNotice arg from runCheckoutAfterProcessingWithErrorObservers * Remove createErrorNotice from emit event types * Use type keyword when importing types * Add correct types for dispatch and select in thunks * Update wordpress/data types * Replace store creation with new preferred method * Set correct action type on reducer * Remove unnecessary async from thunk * add CHECKOUT_ prefix to checkout events again * export EVENTS with eveything else in checkout0-events/event-emit * Remove duplicate SelectFromMap and TailParameters * Updated type for paymentStatus * TODO remove wp/data experimental thunks * Remove `setCustomerId` from events and `processCheckoutResponseHeaders` (#6586) * Prevent passing dispatch, instead get actions direct from store * Get setCustomerId from the store instead of passing it to processCheckoutResponseHeaders * Revert "Prevent passing dispatch, instead get actions direct from store" This reverts commit 4479a2e. * Auto stash before revert of "Prevent passing dispatch, instead get actions direct from store" * Remove duplicate dispatch * Fix unit tests Co-authored-by: Thomas Roberts <[email protected]> Co-authored-by: Thomas Roberts <[email protected]>
- Loading branch information
1 parent
f51dee2
commit 4117c83
Showing
31 changed files
with
51,549 additions
and
64,973 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
194 changes: 194 additions & 0 deletions
194
assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
|
||
import { | ||
createContext, | ||
useContext, | ||
useReducer, | ||
useRef, | ||
useMemo, | ||
useEffect, | ||
useCallback, | ||
} from '@wordpress/element'; | ||
import { usePrevious } from '@woocommerce/base-hooks'; | ||
import deprecated from '@wordpress/deprecated'; | ||
import { useDispatch, useSelect } from '@wordpress/data'; | ||
import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import type { CheckoutEventsContextType } from './types'; | ||
import { useEventEmitters, reducer as emitReducer } from './event-emit'; | ||
import { STATUS } from '../../../../../data/checkout/constants'; | ||
import { useValidationContext } from '../../validation'; | ||
import { useStoreEvents } from '../../../hooks/use-store-events'; | ||
import { useCheckoutNotices } from '../../../hooks/use-checkout-notices'; | ||
import { useEmitResponse } from '../../../hooks/use-emit-response'; | ||
import { CheckoutState } from '../../../../../data/checkout/default-state'; | ||
|
||
const CheckoutEventsContext = createContext( { | ||
onSubmit: () => void null, | ||
onCheckoutAfterProcessingWithSuccess: () => () => void null, | ||
onCheckoutAfterProcessingWithError: () => () => void null, | ||
onCheckoutBeforeProcessing: () => () => void null, // deprecated for onCheckoutValidationBeforeProcessing | ||
onCheckoutValidationBeforeProcessing: () => () => void null, | ||
} ); | ||
|
||
export const useCheckoutEventsContext = () => { | ||
return useContext( CheckoutEventsContext ); | ||
}; | ||
|
||
/** | ||
* Checkout Events provider | ||
* Emit Checkout events and provide access to Checkout event handlers | ||
* | ||
* @param {Object} props Incoming props for the provider. | ||
* @param {Object} props.children The children being wrapped. | ||
* @param {string} props.redirectUrl Initialize what the checkout will redirect to after successful submit. | ||
*/ | ||
export const CheckoutEventsProvider = ( { | ||
children, | ||
redirectUrl, | ||
}: { | ||
children: React.ReactChildren; | ||
redirectUrl: string; | ||
} ): JSX.Element => { | ||
const checkoutActions = useDispatch( CHECKOUT_STORE_KEY ); | ||
const checkoutState: CheckoutState = useSelect( ( select ) => | ||
select( CHECKOUT_STORE_KEY ).getCheckoutState() | ||
); | ||
|
||
if ( redirectUrl && redirectUrl !== checkoutState.redirectUrl ) { | ||
checkoutActions.setRedirectUrl( redirectUrl ); | ||
} | ||
|
||
const { setValidationErrors } = useValidationContext(); | ||
const { createErrorNotice } = useDispatch( 'core/notices' ); | ||
|
||
const { dispatchCheckoutEvent } = useStoreEvents(); | ||
const { | ||
isSuccessResponse, | ||
isErrorResponse, | ||
isFailResponse, | ||
shouldRetry, | ||
} = useEmitResponse(); | ||
const { | ||
checkoutNotices, | ||
paymentNotices, | ||
expressPaymentNotices, | ||
} = useCheckoutNotices(); | ||
|
||
const [ observers, observerDispatch ] = useReducer( emitReducer, {} ); | ||
const currentObservers = useRef( observers ); | ||
const { | ||
onCheckoutAfterProcessingWithSuccess, | ||
onCheckoutAfterProcessingWithError, | ||
onCheckoutValidationBeforeProcessing, | ||
} = useEventEmitters( observerDispatch ); | ||
|
||
// set observers on ref so it's always current. | ||
useEffect( () => { | ||
currentObservers.current = observers; | ||
}, [ observers ] ); | ||
|
||
/** | ||
* @deprecated use onCheckoutValidationBeforeProcessing instead | ||
* | ||
* To prevent the deprecation message being shown at render time | ||
* we need an extra function between useMemo and event emitters | ||
* so that the deprecated message gets shown only at invocation time. | ||
* (useMemo calls the passed function at render time) | ||
* See: https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/4039/commits/a502d1be8828848270993264c64220731b0ae181 | ||
*/ | ||
const onCheckoutBeforeProcessing = useMemo( () => { | ||
return function ( | ||
...args: Parameters< typeof onCheckoutValidationBeforeProcessing > | ||
) { | ||
deprecated( 'onCheckoutBeforeProcessing', { | ||
alternative: 'onCheckoutValidationBeforeProcessing', | ||
plugin: 'WooCommerce Blocks', | ||
} ); | ||
return onCheckoutValidationBeforeProcessing( ...args ); | ||
}; | ||
}, [ onCheckoutValidationBeforeProcessing ] ); | ||
|
||
// Emit CHECKOUT_VALIDATE event and set the error state based on the response of | ||
// the registered callbacks | ||
useEffect( () => { | ||
if ( checkoutState.status === STATUS.BEFORE_PROCESSING ) { | ||
checkoutActions.emitValidateEvent( { | ||
observers: currentObservers.current, | ||
setValidationErrors, | ||
} ); | ||
} | ||
}, [ | ||
checkoutState.status, | ||
setValidationErrors, | ||
createErrorNotice, | ||
checkoutActions, | ||
] ); | ||
|
||
const previousStatus = usePrevious( checkoutState.status ); | ||
const previousHasError = usePrevious( checkoutState.hasError ); | ||
|
||
// Emit CHECKOUT_AFTER_PROCESSING_WITH_SUCCESS and CHECKOUT_AFTER_PROCESSING_WITH_ERROR events | ||
// and set checkout errors according to the callback responses | ||
useEffect( () => { | ||
if ( | ||
checkoutState.status === previousStatus && | ||
checkoutState.hasError === previousHasError | ||
) { | ||
return; | ||
} | ||
|
||
if ( checkoutState.status === STATUS.AFTER_PROCESSING ) { | ||
checkoutActions.emitAfterProcessingEvents( { | ||
observers: currentObservers.current, | ||
notices: { | ||
checkoutNotices, | ||
paymentNotices, | ||
expressPaymentNotices, | ||
}, | ||
} ); | ||
} | ||
}, [ | ||
checkoutState.status, | ||
checkoutState.hasError, | ||
checkoutState.redirectUrl, | ||
checkoutState.orderId, | ||
checkoutState.customerId, | ||
checkoutState.orderNotes, | ||
checkoutState.processingResponse, | ||
previousStatus, | ||
previousHasError, | ||
createErrorNotice, | ||
isErrorResponse, | ||
isFailResponse, | ||
isSuccessResponse, | ||
shouldRetry, | ||
checkoutNotices, | ||
expressPaymentNotices, | ||
paymentNotices, | ||
checkoutActions, | ||
] ); | ||
|
||
const onSubmit = useCallback( () => { | ||
dispatchCheckoutEvent( 'submit' ); | ||
checkoutActions.setBeforeProcessing(); | ||
}, [ dispatchCheckoutEvent, checkoutActions ] ); | ||
|
||
const checkoutEventHandlers: CheckoutEventsContextType = { | ||
onSubmit, | ||
onCheckoutBeforeProcessing, | ||
onCheckoutValidationBeforeProcessing, | ||
onCheckoutAfterProcessingWithSuccess, | ||
onCheckoutAfterProcessingWithError, | ||
}; | ||
return ( | ||
<CheckoutEventsContext.Provider value={ checkoutEventHandlers }> | ||
{ children } | ||
</CheckoutEventsContext.Provider> | ||
); | ||
}; |
17 changes: 17 additions & 0 deletions
17
assets/js/base/context/providers/cart-checkout/checkout-events/types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import type { emitterCallback } from '../../../event-emit'; | ||
|
||
export type CheckoutEventsContextType = { | ||
// Submits the checkout and begins processing. | ||
onSubmit: () => void; | ||
// Used to register a callback that will fire after checkout has been processed and there are no errors. | ||
onCheckoutAfterProcessingWithSuccess: ReturnType< typeof emitterCallback >; | ||
// Used to register a callback that will fire when the checkout has been processed and has an error. | ||
onCheckoutAfterProcessingWithError: ReturnType< typeof emitterCallback >; | ||
// Deprecated in favour of onCheckoutValidationBeforeProcessing. | ||
onCheckoutBeforeProcessing: ReturnType< typeof emitterCallback >; | ||
// Used to register a callback that will fire when the checkout has been submitted before being sent off to the server. | ||
onCheckoutValidationBeforeProcessing: ReturnType< typeof emitterCallback >; | ||
}; |
Oops, something went wrong.