mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
✨ Replace isBusy with new activity-state manager
This commit is contained in:
parent
405c397331
commit
9786a18eb0
5 changed files with 77 additions and 16 deletions
|
@ -13,6 +13,10 @@ export default {
|
||||||
RESET: 'COMMON:RESET',
|
RESET: 'COMMON:RESET',
|
||||||
HYDRATE: 'COMMON:HYDRATE',
|
HYDRATE: 'COMMON:HYDRATE',
|
||||||
|
|
||||||
|
// Activity management (advanced solution that replaces the isBusy state).
|
||||||
|
START_ACTIVITY: 'COMMON:START_ACTIVITY',
|
||||||
|
STOP_ACTIVITY: 'COMMON:STOP_ACTIVITY',
|
||||||
|
|
||||||
// Controls - always start with "DO_".
|
// Controls - always start with "DO_".
|
||||||
DO_PERSIST_DATA: 'COMMON:DO_PERSIST_DATA',
|
DO_PERSIST_DATA: 'COMMON:DO_PERSIST_DATA',
|
||||||
DO_MANUAL_CONNECTION: 'COMMON:DO_MANUAL_CONNECTION',
|
DO_MANUAL_CONNECTION: 'COMMON:DO_MANUAL_CONNECTION',
|
||||||
|
|
|
@ -59,14 +59,35 @@ export const setIsSaving = ( isSaving ) => ( {
|
||||||
} );
|
} );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transient. Changes the "manual connection is busy" flag.
|
* Transient (Activity): Marks the start of an async activity
|
||||||
|
* Think of it as "setIsBusy(true)"
|
||||||
*
|
*
|
||||||
* @param {boolean} isBusy
|
* @param {string} id Internal ID/key of the action, used to stop it again.
|
||||||
|
* @param {?string} description Optional, description for logging/debugging
|
||||||
|
* @return {?Action} The action.
|
||||||
|
*/
|
||||||
|
export const startActivity = ( id, description = null ) => {
|
||||||
|
if ( ! id || 'string' !== typeof id ) {
|
||||||
|
console.warn( 'Activity ID must be a non-empty string' );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: ACTION_TYPES.START_ACTIVITY,
|
||||||
|
payload: { id, description },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transient (Activity): Marks the end of an async activity.
|
||||||
|
* Think of it as "setIsBusy(false)"
|
||||||
|
*
|
||||||
|
* @param {string} id Internal ID/key of the action, used to stop it again.
|
||||||
* @return {Action} The action.
|
* @return {Action} The action.
|
||||||
*/
|
*/
|
||||||
export const setIsBusy = ( isBusy ) => ( {
|
export const stopActivity = ( id ) => ( {
|
||||||
type: ACTION_TYPES.SET_TRANSIENT,
|
type: ACTION_TYPES.STOP_ACTIVITY,
|
||||||
payload: { isBusy },
|
payload: { id },
|
||||||
} );
|
} );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,10 +151,8 @@ export const persist = function* () {
|
||||||
* @return {Action} The action.
|
* @return {Action} The action.
|
||||||
*/
|
*/
|
||||||
export const connectToSandbox = function* () {
|
export const connectToSandbox = function* () {
|
||||||
yield setIsBusy( true );
|
|
||||||
|
|
||||||
const result = yield { type: ACTION_TYPES.DO_SANDBOX_LOGIN };
|
const result = yield { type: ACTION_TYPES.DO_SANDBOX_LOGIN };
|
||||||
yield setIsBusy( false );
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
@ -145,13 +164,11 @@ export const connectToSandbox = function* () {
|
||||||
* @return {Action} The action.
|
* @return {Action} The action.
|
||||||
*/
|
*/
|
||||||
export const connectToProduction = function* ( products = [] ) {
|
export const connectToProduction = function* ( products = [] ) {
|
||||||
yield setIsBusy( true );
|
|
||||||
|
|
||||||
const result = yield {
|
const result = yield {
|
||||||
type: ACTION_TYPES.DO_PRODUCTION_LOGIN,
|
type: ACTION_TYPES.DO_PRODUCTION_LOGIN,
|
||||||
products,
|
products,
|
||||||
};
|
};
|
||||||
yield setIsBusy( false );
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
@ -165,7 +182,6 @@ export const connectViaIdAndSecret = function* () {
|
||||||
const { clientId, clientSecret, useSandbox } =
|
const { clientId, clientSecret, useSandbox } =
|
||||||
yield select( STORE_NAME ).persistentData();
|
yield select( STORE_NAME ).persistentData();
|
||||||
|
|
||||||
yield setIsBusy( true );
|
|
||||||
|
|
||||||
const result = yield {
|
const result = yield {
|
||||||
type: ACTION_TYPES.DO_MANUAL_CONNECTION,
|
type: ACTION_TYPES.DO_MANUAL_CONNECTION,
|
||||||
|
@ -173,7 +189,6 @@ export const connectViaIdAndSecret = function* () {
|
||||||
clientSecret,
|
clientSecret,
|
||||||
useSandbox,
|
useSandbox,
|
||||||
};
|
};
|
||||||
yield setIsBusy( false );
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
|
@ -81,12 +81,34 @@ const useHooks = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useBusyState = () => {
|
export const useBusyState = () => {
|
||||||
const { setIsBusy } = useDispatch( STORE_NAME );
|
const { startActivity, stopActivity } = useDispatch( STORE_NAME );
|
||||||
const isBusy = useTransient( 'isBusy' );
|
|
||||||
|
// Resolved value (object), contains a list of all running actions.
|
||||||
|
const activities = useSelect(
|
||||||
|
( select ) => select( STORE_NAME ).getActivityList(),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Derive isBusy state from activities
|
||||||
|
const isBusy = Object.keys( activities ).length > 0;
|
||||||
|
|
||||||
|
// HOC that starts and stops an activity while the callback is executed.
|
||||||
|
const withActivity = useCallback(
|
||||||
|
async ( id, description, asyncFn ) => {
|
||||||
|
startActivity( id, description );
|
||||||
|
try {
|
||||||
|
return await asyncFn();
|
||||||
|
} finally {
|
||||||
|
stopActivity( id );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[ startActivity, stopActivity ]
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isBusy,
|
withActivity, // HOC
|
||||||
setIsBusy: useCallback( ( busy ) => setIsBusy( busy ), [ setIsBusy ] ),
|
isBusy, // Boolean.
|
||||||
|
activities, // Object.
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import ACTION_TYPES from './action-types';
|
||||||
|
|
||||||
const defaultTransient = {
|
const defaultTransient = {
|
||||||
isReady: false,
|
isReady: false,
|
||||||
isBusy: false,
|
activities: new Map(),
|
||||||
|
|
||||||
// Read only values, provided by the server via hydrate.
|
// Read only values, provided by the server via hydrate.
|
||||||
wooSettings: {
|
wooSettings: {
|
||||||
|
@ -57,6 +57,21 @@ const commonReducer = createReducer( defaultTransient, defaultPersistent, {
|
||||||
return cleanState;
|
return cleanState;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[ ACTION_TYPES.START_ACTIVITY ]: ( state, payload ) => {
|
||||||
|
return setTransient( state, {
|
||||||
|
activities: new Map( state.activities ).set(
|
||||||
|
payload.id,
|
||||||
|
payload.description
|
||||||
|
),
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
|
||||||
|
[ ACTION_TYPES.STOP_ACTIVITY ]: ( state, payload ) => {
|
||||||
|
const newActivities = new Map( state.activities );
|
||||||
|
newActivities.delete( payload.id );
|
||||||
|
return setTransient( state, { activities: newActivities } );
|
||||||
|
},
|
||||||
|
|
||||||
[ ACTION_TYPES.HYDRATE ]: ( state, payload ) => {
|
[ ACTION_TYPES.HYDRATE ]: ( state, payload ) => {
|
||||||
const newState = setPersistent( state, payload.data );
|
const newState = setPersistent( state, payload.data );
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,11 @@ export const transientData = ( state ) => {
|
||||||
return transientState || EMPTY_OBJ;
|
return transientState || EMPTY_OBJ;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getActivityList = ( state ) => {
|
||||||
|
const { activities = new Map() } = state;
|
||||||
|
return Object.fromEntries( activities );
|
||||||
|
};
|
||||||
|
|
||||||
export const wooSettings = ( state ) => {
|
export const wooSettings = ( state ) => {
|
||||||
return getState( state ).wooSettings || EMPTY_OBJ;
|
return getState( state ).wooSettings || EMPTY_OBJ;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue