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',
|
||||
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_".
|
||||
DO_PERSIST_DATA: 'COMMON:DO_PERSIST_DATA',
|
||||
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.
|
||||
*/
|
||||
export const setIsBusy = ( isBusy ) => ( {
|
||||
type: ACTION_TYPES.SET_TRANSIENT,
|
||||
payload: { isBusy },
|
||||
export const stopActivity = ( id ) => ( {
|
||||
type: ACTION_TYPES.STOP_ACTIVITY,
|
||||
payload: { id },
|
||||
} );
|
||||
|
||||
/**
|
||||
|
@ -130,10 +151,8 @@ export const persist = function* () {
|
|||
* @return {Action} The action.
|
||||
*/
|
||||
export const connectToSandbox = function* () {
|
||||
yield setIsBusy( true );
|
||||
|
||||
const result = yield { type: ACTION_TYPES.DO_SANDBOX_LOGIN };
|
||||
yield setIsBusy( false );
|
||||
|
||||
return result;
|
||||
};
|
||||
|
@ -145,13 +164,11 @@ export const connectToSandbox = function* () {
|
|||
* @return {Action} The action.
|
||||
*/
|
||||
export const connectToProduction = function* ( products = [] ) {
|
||||
yield setIsBusy( true );
|
||||
|
||||
const result = yield {
|
||||
type: ACTION_TYPES.DO_PRODUCTION_LOGIN,
|
||||
products,
|
||||
};
|
||||
yield setIsBusy( false );
|
||||
|
||||
return result;
|
||||
};
|
||||
|
@ -165,7 +182,6 @@ export const connectViaIdAndSecret = function* () {
|
|||
const { clientId, clientSecret, useSandbox } =
|
||||
yield select( STORE_NAME ).persistentData();
|
||||
|
||||
yield setIsBusy( true );
|
||||
|
||||
const result = yield {
|
||||
type: ACTION_TYPES.DO_MANUAL_CONNECTION,
|
||||
|
@ -173,7 +189,6 @@ export const connectViaIdAndSecret = function* () {
|
|||
clientSecret,
|
||||
useSandbox,
|
||||
};
|
||||
yield setIsBusy( false );
|
||||
|
||||
return result;
|
||||
};
|
||||
|
|
|
@ -81,12 +81,34 @@ const useHooks = () => {
|
|||
};
|
||||
|
||||
export const useBusyState = () => {
|
||||
const { setIsBusy } = useDispatch( STORE_NAME );
|
||||
const isBusy = useTransient( 'isBusy' );
|
||||
const { startActivity, stopActivity } = useDispatch( STORE_NAME );
|
||||
|
||||
// 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 {
|
||||
isBusy,
|
||||
setIsBusy: useCallback( ( busy ) => setIsBusy( busy ), [ setIsBusy ] ),
|
||||
withActivity, // HOC
|
||||
isBusy, // Boolean.
|
||||
activities, // Object.
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import ACTION_TYPES from './action-types';
|
|||
|
||||
const defaultTransient = {
|
||||
isReady: false,
|
||||
isBusy: false,
|
||||
activities: new Map(),
|
||||
|
||||
// Read only values, provided by the server via hydrate.
|
||||
wooSettings: {
|
||||
|
@ -57,6 +57,21 @@ const commonReducer = createReducer( defaultTransient, defaultPersistent, {
|
|||
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 ) => {
|
||||
const newState = setPersistent( state, payload.data );
|
||||
|
||||
|
|
|
@ -20,6 +20,11 @@ export const transientData = ( state ) => {
|
|||
return transientState || EMPTY_OBJ;
|
||||
};
|
||||
|
||||
export const getActivityList = ( state ) => {
|
||||
const { activities = new Map() } = state;
|
||||
return Object.fromEntries( activities );
|
||||
};
|
||||
|
||||
export const wooSettings = ( state ) => {
|
||||
return getState( state ).wooSettings || EMPTY_OBJ;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue