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.
prelminary work on the checkout context
- Loading branch information
Showing
8 changed files
with
308 additions
and
97 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
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,43 @@ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import { TYPES } from './constants'; | ||
|
||
const { | ||
SET_PRISTINE, | ||
SET_REDIRECT_URL, | ||
SET_COMPLETE, | ||
SET_INCOMPLETE, | ||
SET_HAS_ERROR, | ||
SET_NO_ERROR, | ||
INCREMENT_CALCULATING, | ||
DECREMENT_CALCULATING, | ||
} = TYPES; | ||
|
||
export const actions = { | ||
setPristine: () => ( { | ||
type: SET_PRISTINE, | ||
} ), | ||
setRedirectUrl: ( url ) => ( { | ||
type: SET_REDIRECT_URL, | ||
url, | ||
} ), | ||
setComplete: () => ( { | ||
type: SET_COMPLETE, | ||
} ), | ||
setIncomplete: () => ( { | ||
type: SET_INCOMPLETE, | ||
} ), | ||
setHasError: () => ( { | ||
type: SET_HAS_ERROR, | ||
} ), | ||
clearError: () => ( { | ||
type: SET_NO_ERROR, | ||
} ), | ||
incrementCalculating: () => ( { | ||
type: INCREMENT_CALCULATING, | ||
} ), | ||
decrementCalculating: () => ( { | ||
type: DECREMENT_CALCULATING, | ||
} ), | ||
}; |
17 changes: 17 additions & 0 deletions
17
assets/js/base/context/cart-checkout/checkout/constants.js
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 @@ | ||
export const DEFAULT_STATE = { | ||
redirectUrl: '', | ||
isComplete: false, | ||
hasError: false, | ||
calculatingCount: 0, | ||
}; | ||
|
||
export const TYPES = { | ||
SET_PRISTINE: 'set_pristine', | ||
SET_REDIRECT_URL: 'set_redirect_url', | ||
SET_COMPLETE: 'set_checkout_complete', | ||
SET_INCOMPLETE: 'set_checkout_incomplete', | ||
SET_HAS_ERROR: 'set_checkout_has_error', | ||
SET_NO_ERROR: 'set_checkout_no_error', | ||
INCREMENT_CALCULATING: 'increment_calculating', | ||
DECREMENT_CALCULATING: 'decrement_calculating', | ||
}; |
41 changes: 41 additions & 0 deletions
41
assets/js/base/context/cart-checkout/checkout/event-emit.js
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,41 @@ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import { actions, reducer, emitEvent } from '../event_emit'; | ||
|
||
const EMIT_TYPES = { | ||
CHECKOUT_COMPLETE: 'checkout_complete', | ||
}; | ||
|
||
/** | ||
* Receives a reducer dispatcher and returns an object with the | ||
* onCheckoutComplete callback registration function for the checkout emit | ||
* events. | ||
* | ||
* Calling the event registration function with the callback will register it | ||
* for the event emitter and will return a dispatcher for removing the | ||
* registered callback (useful for implementation in `useEffect`). | ||
* | ||
* @param {Function} dispatcher The emitter reducer dispatcher. | ||
* | ||
* @return {Object} An object with the `onCheckoutComplete` emmitter registration | ||
*/ | ||
const emitterSubscribers = ( dispatcher ) => ( { | ||
onCheckoutComplete: ( callback ) => { | ||
const action = actions.addEventCallback( | ||
EMIT_TYPES.CHECKOUT_COMPLETE, | ||
callback | ||
); | ||
dispatcher( action ); | ||
return () => { | ||
dispatcher( | ||
actions.removeEventCallback( | ||
EMIT_TYPES.CHECKOUT_COMPLETE, | ||
action.id | ||
) | ||
); | ||
}; | ||
}, | ||
} ); | ||
|
||
export { EMIT_TYPES, emitterSubscribers, reducer, emitEvent }; |
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,136 @@ | ||
/** | ||
* Internal dependencies | ||
*/ | ||
import { PaymentMethodDataProvider } from '../payment-methods'; | ||
import { ShippingMethodDataProvider } from '../shipping'; | ||
import { actions } from './actions'; | ||
import { reducer } from './reducer'; | ||
import { TYPES, DEFAULT_STATE } from './constants'; | ||
import { | ||
EMIT_TYPES, | ||
emitterSubscribers, | ||
emitEvent, | ||
reducer as emitReducer, | ||
} from './event-emit'; | ||
|
||
/** | ||
* External dependencies | ||
*/ | ||
import { | ||
createContext, | ||
useContext, | ||
useReducer, | ||
useRef, | ||
useMemo, | ||
useEffect, | ||
} from '@wordpress/element'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
const CheckoutContext = createContext( {} ); | ||
|
||
export const useCheckoutContext = () => { | ||
return useContext( CheckoutContext ); | ||
}; | ||
|
||
// create context provider for coupons | ||
|
||
// create context provider for checkout validation errors. | ||
|
||
// checkout and cart provider context will be different context but implement | ||
// the above (in terms of finalization.). For example cart context will redirect | ||
// checkout for finalization. Checkout context handles pinging the server for | ||
// processing checkout, validation of existing fields, and redirecting on | ||
// success. | ||
|
||
// checkout context should have events (calculating, success, fail, pristine) | ||
// Also, extensions should be able to register callbacks that will be fired as | ||
// each event is triggered. So there should be a way to register and remove | ||
// callbacks. | ||
// for setCalculating dispatches... let's do this as an incremental thing, | ||
// anything that triggers total changes will increment the calculator by one and when its | ||
// done it triggers a decrement. That way `isCalculating` is actually a report | ||
// on all things currently in processing. | ||
|
||
// todo add onClick handler for checkout submit button and this will: | ||
// - run validation (via validation context) | ||
// - if active payment method is present, trigger the payment method processing. | ||
// - when payment payment status is set to success, trigger the server request | ||
// for finalizing the checkout (which should include all the payment data) | ||
// - on receiving the server response, trigger checkout complete. | ||
// - do redirect to redirectUrl if checkoutComplete and paymentMethodStatus is | ||
// is complete (to allow for final payment method processing after checkout | ||
// is complete) (NOTE: maybe we could just handle this by detecting if there are | ||
// any observers left to process?) | ||
// One way I might be able to do all the above is to pass through the onSubmit | ||
// handler that is enhanced through each provider (maybe). Otherwise I'm going | ||
// to have to figure out a way to connect the various providers. | ||
|
||
const CheckoutProvider = ( { | ||
children, | ||
activePaymentMethod: initialActivePaymentMethod, | ||
redirectUrl, | ||
submitLabel = __( 'Place Order', 'woo-gutenberg-product-block' ), | ||
} ) => { | ||
// note, this is done intentionally so that the default state now has | ||
// the redirectUrl for when checkout is reset to PRISTINE state. | ||
DEFAULT_STATE.redirectUrl = redirectUrl; | ||
const [ checkoutState, dispatch ] = useReducer( reducer, DEFAULT_STATE ); | ||
const [ observers, subscriber ] = useReducer( emitReducer ); | ||
const currentObservers = useRef( observers ); | ||
// set observers on ref so it's always current | ||
useEffect( () => { | ||
currentObservers.current = observers; | ||
}, [ observers ] ); | ||
const onCheckoutComplete = emitterSubscribers( subscriber ) | ||
.onCheckoutComplete; | ||
const dispatchActions = useMemo( | ||
() => ( { | ||
resetCheckout: () => void dispatch( actions.setPristine() ), | ||
setRedirectUrl: ( url ) => | ||
void dispatch( actions.setRedirectUrl( url ) ), | ||
setHasError: () => void dispatch( actions.setHasError() ), | ||
clearError: () => void dispatch( actions.clearError() ), | ||
incrementCalculating: () => | ||
void dispatch( actions.incrementCalculating() ), | ||
decrementCalculating: () => | ||
void dispatch( actions.decrementCalculating() ), | ||
} ), | ||
[] | ||
); | ||
const onSubmit = () => { | ||
// @todo this is where we do validation and checkout processing | ||
dispatch( actions.setComplete() ); | ||
}; | ||
// emit events | ||
useEffect( () => { | ||
if ( checkoutState.isComplete ) { | ||
emitEvent( | ||
currentObservers.current, | ||
EMIT_TYPES.CHECKOUT_COMPLETE, | ||
{} | ||
); | ||
} | ||
}, [ checkoutState.isComplete ] ); | ||
|
||
// do redirect! | ||
useEffect( () => { | ||
// @todo check for if payment status and checkout status are complete | ||
// and then redirect | ||
window.location = checkoutState.redirectUrl; | ||
}, [ checkoutState.isComplete ] ); | ||
|
||
//@todo setup the checkout data to pass on the checkout providers value. | ||
return ( | ||
<CheckoutContext.Provider value={ contextValue }> | ||
<PaymentMethodDataProvider | ||
activePaymentMethod={ initialActivePaymentMethod } | ||
> | ||
<ShippingMethodDataProvider> | ||
{ children } | ||
</ShippingMethodDataProvider> | ||
</PaymentMethodDataProvider> | ||
</CheckoutContext.Provider> | ||
); | ||
}; | ||
|
||
export default CheckoutProvider; |
Oops, something went wrong.