mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 14:57:26 +08:00
Merge remote-tracking branch 'origin/PCP-4210-features-refactor-to-use-rest-endpoints' into PCP-4210-features-refactor-to-use-rest-endpoints
# Conflicts: # modules/ppcp-settings/resources/js/data/debug.js
This commit is contained in:
commit
c902f24010
26 changed files with 599 additions and 276 deletions
|
@ -11,8 +11,8 @@ import { getQuery } from '../utils/navigation';
|
|||
const SettingsApp = () => {
|
||||
const { isReady: onboardingIsReady, completed: onboardingCompleted } =
|
||||
OnboardingHooks.useSteps();
|
||||
const { isReady: merchantIsReady } = CommonHooks.useStore();
|
||||
const {
|
||||
isReady: merchantIsReady,
|
||||
merchant: { isSendOnlyCountry },
|
||||
} = CommonHooks.useMerchantInfo();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { __ } from '@wordpress/i18n';
|
|||
import { useCallback, useEffect, useRef, useState } from '@wordpress/element';
|
||||
|
||||
import TopNavigation from '../../../ReusableComponents/TopNavigation';
|
||||
import { useSaveSettings } from '../../../../hooks/useSaveSettings';
|
||||
import { useStoreManager } from '../../../../hooks/useStoreManager';
|
||||
import { CommonHooks } from '../../../../data';
|
||||
import TabBar from '../../../ReusableComponents/TabBar';
|
||||
import classNames from 'classnames';
|
||||
|
@ -20,7 +20,7 @@ const SettingsNavigation = ( {
|
|||
activePanel,
|
||||
setActivePanel,
|
||||
} ) => {
|
||||
const { persistAll } = useSaveSettings();
|
||||
const { persistAll } = useStoreManager();
|
||||
|
||||
const title = __( 'PayPal Payments', 'woocommerce-paypal-payments' );
|
||||
|
||||
|
|
|
@ -12,11 +12,12 @@ import {
|
|||
import { Content, ContentWrapper } from '../../../ReusableComponents/Elements';
|
||||
import SettingsCard from '../../../ReusableComponents/SettingsCard';
|
||||
import { TITLE_BADGE_POSITIVE } from '../../../ReusableComponents/TitleBadge';
|
||||
import { useTodos } from '../../../../data/todos/hooks';
|
||||
import { useMerchantInfo } from '../../../../data/common/hooks';
|
||||
import { STORE_NAME as COMMON_STORE_NAME } from '../../../../data/common';
|
||||
import { STORE_NAME as TODOS_STORE_NAME } from '../../../../data/todos';
|
||||
import { CommonHooks, TodosHooks } from '../../../../data';
|
||||
import {
|
||||
CommonStoreName,
|
||||
TodosStoreName,
|
||||
CommonHooks,
|
||||
TodosHooks,
|
||||
} from '../../../../data';
|
||||
|
||||
import {
|
||||
NOTIFICATION_ERROR,
|
||||
|
@ -28,8 +29,8 @@ import { selectTab, TAB_IDS } from '../../../../utils/tabSelector';
|
|||
import { setActiveModal } from '../../../../data/common/actions';
|
||||
|
||||
const TabOverview = () => {
|
||||
const { isReady: areTodosReady } = TodosHooks.useTodos();
|
||||
const { isReady: merchantIsReady } = CommonHooks.useMerchantInfo();
|
||||
const { isReady: areTodosReady } = TodosHooks.useStore();
|
||||
const { isReady: merchantIsReady } = CommonHooks.useStore();
|
||||
|
||||
if ( ! areTodosReady || ! merchantIsReady ) {
|
||||
return <SpinnerOverlay asModal={ true } />;
|
||||
|
@ -48,12 +49,12 @@ export default TabOverview;
|
|||
|
||||
const OverviewTodos = () => {
|
||||
const [ isResetting, setIsResetting ] = useState( false );
|
||||
const { todos, isReady: areTodosReady, dismissTodo } = useTodos();
|
||||
// eslint-disable-next-line no-shadow
|
||||
const { todos, dismissTodo } = TodosHooks.useTodos();
|
||||
const { isReady: areTodosReady } = TodosHooks.useStore();
|
||||
const { setActiveModal, setActiveHighlight } =
|
||||
useDispatch( COMMON_STORE_NAME );
|
||||
useDispatch( CommonStoreName );
|
||||
const { resetDismissedTodos, setDismissedTodos } =
|
||||
useDispatch( TODOS_STORE_NAME );
|
||||
useDispatch( TodosStoreName );
|
||||
const { createSuccessNotice } = useDispatch( noticesStore );
|
||||
|
||||
const showTodos = areTodosReady && todos.length > 0;
|
||||
|
@ -120,8 +121,8 @@ const OverviewTodos = () => {
|
|||
|
||||
const OverviewFeatures = () => {
|
||||
const [ isRefreshing, setIsRefreshing ] = useState( false );
|
||||
const { merchant } = useMerchantInfo();
|
||||
const { refreshFeatureStatuses } = useDispatch( COMMON_STORE_NAME );
|
||||
const { merchant } = CommonHooks.useMerchantInfo();
|
||||
const { refreshFeatureStatuses } = useDispatch( CommonStoreName );
|
||||
const { createSuccessNotice, createErrorNotice } =
|
||||
useDispatch( noticesStore );
|
||||
const { features, fetchFeatures } = useFeatures();
|
||||
|
|
|
@ -82,3 +82,16 @@ export function persist() {
|
|||
} );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk action creator. Forces a data refresh from the REST API, replacing the current Redux values.
|
||||
*
|
||||
* @return {Function} The thunk function.
|
||||
*/
|
||||
export function refresh() {
|
||||
return ( { dispatch, select } ) => {
|
||||
dispatch.invalidateResolutionForStore();
|
||||
|
||||
select.persistentData();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -38,10 +38,16 @@ const useStoreData = () => {
|
|||
};
|
||||
|
||||
export const useStore = () => {
|
||||
const { dispatch, useTransient } = useStoreData();
|
||||
const { select, dispatch, useTransient } = useStoreData();
|
||||
const { persist, refresh } = dispatch;
|
||||
const [ isReady ] = useTransient( 'isReady' );
|
||||
|
||||
return { persist: dispatch.persist, isReady };
|
||||
// Load persistent data from REST if not done yet.
|
||||
if ( ! isReady ) {
|
||||
select.persistentData();
|
||||
}
|
||||
|
||||
return { persist, refresh, isReady };
|
||||
};
|
||||
|
||||
// TODO: Replace with real hook.
|
||||
|
|
|
@ -27,6 +27,19 @@ export function persist() {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk action creator. Forces a data refresh from the REST API, replacing the current Redux values.
|
||||
*
|
||||
* @return {Function} The thunk function.
|
||||
*/
|
||||
export function refresh() {
|
||||
return ( { dispatch, select } ) => {
|
||||
dispatch.invalidateResolutionForStore();
|
||||
|
||||
select.persistentData();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Side effect. Fetches the ISU-login URL for a sandbox account.
|
||||
*
|
||||
|
|
|
@ -13,8 +13,32 @@ import { useCallback, useEffect, useMemo, useState } from '@wordpress/element';
|
|||
import { createHooksForStore } from '../utils';
|
||||
import { STORE_NAME } from './constants';
|
||||
|
||||
const useHooks = () => {
|
||||
/**
|
||||
* Single source of truth for access Redux details.
|
||||
*
|
||||
* This hook returns a stable API to access actions, selectors and special hooks to generate
|
||||
* getter- and setters for transient or persistent properties.
|
||||
*
|
||||
* @return {{select, dispatch, useTransient, usePersistent}} Store data API.
|
||||
*/
|
||||
const useStoreData = () => {
|
||||
const select = useSelect( ( selectors ) => selectors( STORE_NAME ), [] );
|
||||
const dispatch = useDispatch( STORE_NAME );
|
||||
const { useTransient, usePersistent } = createHooksForStore( STORE_NAME );
|
||||
|
||||
return useMemo(
|
||||
() => ( {
|
||||
select,
|
||||
dispatch,
|
||||
useTransient,
|
||||
usePersistent,
|
||||
} ),
|
||||
[ select, dispatch, useTransient, usePersistent ]
|
||||
);
|
||||
};
|
||||
|
||||
const useHooks = () => {
|
||||
const { useTransient, usePersistent, dispatch, select } = useStoreData();
|
||||
const {
|
||||
persist,
|
||||
sandboxOnboardingUrl,
|
||||
|
@ -23,10 +47,9 @@ const useHooks = () => {
|
|||
authenticateWithOAuth,
|
||||
startWebhookSimulation,
|
||||
checkWebhookSimulationState,
|
||||
} = useDispatch( STORE_NAME );
|
||||
} = dispatch;
|
||||
|
||||
// Transient accessors.
|
||||
const [ isReady ] = useTransient( 'isReady' );
|
||||
const [ activeModal, setActiveModal ] = useTransient( 'activeModal' );
|
||||
const [ activeHighlight, setActiveHighlight ] =
|
||||
useTransient( 'activeHighlight' );
|
||||
|
@ -38,18 +61,9 @@ const useHooks = () => {
|
|||
);
|
||||
|
||||
// Read-only properties.
|
||||
const wooSettings = useSelect(
|
||||
( select ) => select( STORE_NAME ).wooSettings(),
|
||||
[]
|
||||
);
|
||||
const features = useSelect(
|
||||
( select ) => select( STORE_NAME ).features(),
|
||||
[]
|
||||
);
|
||||
const webhooks = useSelect(
|
||||
( select ) => select( STORE_NAME ).webhooks(),
|
||||
[]
|
||||
);
|
||||
const wooSettings = select.wooSettings();
|
||||
const features = select.features();
|
||||
const webhooks = select.webhooks();
|
||||
|
||||
const savePersistent = async ( setter, value ) => {
|
||||
setter( value );
|
||||
|
@ -57,7 +71,6 @@ const useHooks = () => {
|
|||
};
|
||||
|
||||
return {
|
||||
isReady,
|
||||
activeModal,
|
||||
setActiveModal,
|
||||
activeHighlight,
|
||||
|
@ -82,6 +95,19 @@ const useHooks = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const useStore = () => {
|
||||
const { select, dispatch, useTransient } = useStoreData();
|
||||
const { persist, refresh } = dispatch;
|
||||
const [ isReady ] = useTransient( 'isReady' );
|
||||
|
||||
// Load persistent data from REST if not done yet.
|
||||
if ( ! isReady ) {
|
||||
select.persistentData();
|
||||
}
|
||||
|
||||
return { persist, refresh, isReady };
|
||||
};
|
||||
|
||||
export const useSandbox = () => {
|
||||
const { isSandboxMode, setSandboxMode, sandboxOnboardingUrl } = useHooks();
|
||||
|
||||
|
@ -139,7 +165,7 @@ export const useWebhooks = () => {
|
|||
};
|
||||
|
||||
export const useMerchantInfo = () => {
|
||||
const { isReady, features } = useHooks();
|
||||
const { features } = useHooks();
|
||||
const merchant = useMerchant();
|
||||
const { refreshMerchantData, setMerchant } = useDispatch( STORE_NAME );
|
||||
|
||||
|
@ -164,7 +190,6 @@ export const useMerchantInfo = () => {
|
|||
}, [ refreshMerchantData, setMerchant ] );
|
||||
|
||||
return {
|
||||
isReady,
|
||||
merchant, // Merchant details
|
||||
features, // Eligible merchant features
|
||||
verifyLoginStatus, // Callback
|
||||
|
@ -204,7 +229,9 @@ export const useActiveHighlight = () => {
|
|||
return { activeHighlight, setActiveHighlight };
|
||||
};
|
||||
|
||||
// -- Not using the `useHooks()` data provider --
|
||||
/*
|
||||
* Busy state management hooks
|
||||
*/
|
||||
|
||||
export const useBusyState = () => {
|
||||
const { startActivity, stopActivity } = useDispatch( STORE_NAME );
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
SettingsStoreName,
|
||||
StylingStoreName,
|
||||
TodosStoreName,
|
||||
FeaturesStoreName,
|
||||
} from './index';
|
||||
|
||||
export const addDebugTools = ( context, modules ) => {
|
||||
|
@ -18,10 +19,15 @@ export const addDebugTools = ( context, modules ) => {
|
|||
if ( ! context.debug ) { return }
|
||||
*/
|
||||
|
||||
const describe = ( fnName, fnInfo ) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log( `\n%c${ fnName }:`, 'font-weight:bold', fnInfo, '\n\n' );
|
||||
};
|
||||
|
||||
const debugApi = ( window.ppcpDebugger = window.ppcpDebugger || {} );
|
||||
|
||||
// Dump the current state of all our Redux stores.
|
||||
debugApi.dumpStore = async () => {
|
||||
debugApi.dumpStore = async ( cbFilter = null ) => {
|
||||
/* eslint-disable no-console */
|
||||
if ( ! console?.groupCollapsed ) {
|
||||
console.error( 'console.groupCollapsed is not supported.' );
|
||||
|
@ -34,11 +40,19 @@ export const addDebugTools = ( context, modules ) => {
|
|||
console.group( `[STORE] ${ storeSelector }` );
|
||||
|
||||
const dumpStore = ( selector ) => {
|
||||
const contents = wp.data.select( storeName )[ selector ]();
|
||||
let contents = wp.data.select( storeName )[ selector ]();
|
||||
|
||||
console.groupCollapsed( `.${ selector }()` );
|
||||
console.table( contents );
|
||||
console.groupEnd();
|
||||
if ( cbFilter ) {
|
||||
contents = cbFilter( contents, selector, storeName );
|
||||
|
||||
if ( undefined !== contents && null !== contents ) {
|
||||
console.log( `.${ selector }() [filtered]`, contents );
|
||||
}
|
||||
} else {
|
||||
console.groupCollapsed( `.${ selector }()` );
|
||||
console.table( contents );
|
||||
console.groupEnd();
|
||||
}
|
||||
};
|
||||
|
||||
Object.keys( module.selectors ).forEach( dumpStore );
|
||||
|
@ -51,45 +65,90 @@ export const addDebugTools = ( context, modules ) => {
|
|||
// Reset all Redux stores to their initial state.
|
||||
debugApi.resetStore = () => {
|
||||
const stores = [];
|
||||
const { isConnected } = wp.data.select( CommonStoreName ).merchant();
|
||||
|
||||
if ( isConnected ) {
|
||||
// Make sure the Onboarding wizard is "completed".
|
||||
const onboarding = wp.data.dispatch( OnboardingStoreName );
|
||||
onboarding.setPersistent( 'completed', true );
|
||||
onboarding.persist();
|
||||
describe(
|
||||
'resetStore',
|
||||
'Reset all Redux stores to their DEFAULT state, without changing any server-side data. The default state is defined in the JS code.'
|
||||
);
|
||||
|
||||
// Reset all stores, except for the onboarding store.
|
||||
stores.push( CommonStoreName );
|
||||
stores.push( PaymentStoreName );
|
||||
stores.push( SettingsStoreName );
|
||||
stores.push( StylingStoreName );
|
||||
stores.push( TodosStoreName );
|
||||
} else {
|
||||
// Only reset the common & onboarding stores to restart the onboarding wizard.
|
||||
stores.push( CommonStoreName );
|
||||
const { completed } = wp.data
|
||||
.select( OnboardingStoreName )
|
||||
.persistentData();
|
||||
|
||||
// Reset all stores, except for the onboarding store.
|
||||
stores.push( CommonStoreName );
|
||||
stores.push( PaymentStoreName );
|
||||
stores.push( SettingsStoreName );
|
||||
stores.push( StylingStoreName );
|
||||
stores.push( TodosStoreName );
|
||||
|
||||
// Only reset the onboarding store when the wizard is not completed.
|
||||
if ( ! completed ) {
|
||||
stores.push( OnboardingStoreName );
|
||||
}
|
||||
|
||||
stores.forEach( ( storeName ) => {
|
||||
const store = wp.data.dispatch( storeName );
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log( `Reset store: ${ storeName }...` );
|
||||
|
||||
try {
|
||||
store.reset();
|
||||
store.persist();
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log( `Done: Store '${ storeName }' reset` );
|
||||
} catch ( error ) {
|
||||
console.error( ' ... Reset failed, skipping this store' );
|
||||
console.error(
|
||||
`Failed: Could not reset store '${ storeName }'`
|
||||
);
|
||||
}
|
||||
} );
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log( '---- Complete ----\n\n' );
|
||||
};
|
||||
|
||||
debugApi.refreshStore = () => {
|
||||
const stores = [];
|
||||
|
||||
describe(
|
||||
'refreshStore',
|
||||
'Refreshes all Redux details with details provided by the server. This has a similar effect as reloading the page without saving'
|
||||
);
|
||||
|
||||
stores.push( CommonStoreName );
|
||||
stores.push( PaymentStoreName );
|
||||
stores.push( SettingsStoreName );
|
||||
stores.push( StylingStoreName );
|
||||
stores.push( TodosStoreName );
|
||||
stores.push( FeaturesStoreName );
|
||||
stores.push( OnboardingStoreName );
|
||||
|
||||
stores.forEach( ( storeName ) => {
|
||||
const store = wp.data.dispatch( storeName );
|
||||
|
||||
try {
|
||||
store.refresh();
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(
|
||||
`Done: Store '${ storeName }' refreshed from REST`
|
||||
);
|
||||
} catch ( error ) {
|
||||
console.error(
|
||||
`Failed: Could not refresh store '${ storeName }' from REST`
|
||||
);
|
||||
}
|
||||
} );
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log( '---- Complete ----\n\n' );
|
||||
};
|
||||
|
||||
// Disconnect the merchant and display the onboarding wizard.
|
||||
debugApi.disconnect = () => {
|
||||
const common = wp.data.dispatch( CommonStoreName );
|
||||
|
||||
describe();
|
||||
|
||||
common.disconnectMerchant();
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -102,6 +161,11 @@ export const addDebugTools = ( context, modules ) => {
|
|||
debugApi.onboardingMode = ( state ) => {
|
||||
const onboarding = wp.data.dispatch( OnboardingStoreName );
|
||||
|
||||
describe(
|
||||
'onboardingMode',
|
||||
'Toggle between onboarding wizard and the settings screen.'
|
||||
);
|
||||
|
||||
onboarding.setPersistent( 'completed', ! state );
|
||||
onboarding.persist();
|
||||
};
|
||||
|
|
|
@ -87,3 +87,16 @@ export function persist() {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk action creator. Forces a data refresh from the REST API, replacing the current Redux values.
|
||||
*
|
||||
* @return {Function} The thunk function.
|
||||
*/
|
||||
export function refresh() {
|
||||
return ( { dispatch, select } ) => {
|
||||
dispatch.invalidateResolutionForStore();
|
||||
|
||||
select.persistentData();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -82,3 +82,16 @@ export function persist() {
|
|||
} );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk action creator. Forces a data refresh from the REST API, replacing the current Redux values.
|
||||
*
|
||||
* @return {Function} The thunk function.
|
||||
*/
|
||||
export function refresh() {
|
||||
return ( { dispatch, select } ) => {
|
||||
dispatch.invalidateResolutionForStore();
|
||||
|
||||
select.persistentData();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -94,3 +94,16 @@ export function persist() {
|
|||
} );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk action creator. Forces a data refresh from the REST API, replacing the current Redux values.
|
||||
*
|
||||
* @return {Function} The thunk function.
|
||||
*/
|
||||
export function refresh() {
|
||||
return ( { dispatch, select } ) => {
|
||||
dispatch.invalidateResolutionForStore();
|
||||
|
||||
select.persistentData();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,22 +7,58 @@
|
|||
* @file
|
||||
*/
|
||||
|
||||
import { useDispatch } from '@wordpress/data';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
|
||||
import { STORE_NAME } from './constants';
|
||||
import { createHooksForStore } from '../utils';
|
||||
import { useMemo } from '@wordpress/element';
|
||||
|
||||
const useHooks = () => {
|
||||
/**
|
||||
* Single source of truth for access Redux details.
|
||||
*
|
||||
* This hook returns a stable API to access actions, selectors and special hooks to generate
|
||||
* getter- and setters for transient or persistent properties.
|
||||
*
|
||||
* @return {{select, dispatch, useTransient, usePersistent}} Store data API.
|
||||
*/
|
||||
const useStoreData = () => {
|
||||
const select = useSelect( ( selectors ) => selectors( STORE_NAME ), [] );
|
||||
const dispatch = useDispatch( STORE_NAME );
|
||||
const { useTransient, usePersistent } = createHooksForStore( STORE_NAME );
|
||||
const { persist, setPersistent, changePaymentSettings } =
|
||||
useDispatch( STORE_NAME );
|
||||
|
||||
// Read-only flags and derived state.
|
||||
// Nothing here yet.
|
||||
return useMemo(
|
||||
() => ( {
|
||||
select,
|
||||
dispatch,
|
||||
useTransient,
|
||||
usePersistent,
|
||||
} ),
|
||||
[ select, dispatch, useTransient, usePersistent ]
|
||||
);
|
||||
};
|
||||
|
||||
// Transient accessors.
|
||||
export const useStore = () => {
|
||||
const { select, useTransient, dispatch } = useStoreData();
|
||||
const { persist, refresh, setPersistent, changePaymentSettings } = dispatch;
|
||||
const [ isReady ] = useTransient( 'isReady' );
|
||||
|
||||
// Load persistent data from REST if not done yet.
|
||||
if ( ! isReady ) {
|
||||
select.persistentData();
|
||||
}
|
||||
|
||||
return {
|
||||
persist,
|
||||
refresh,
|
||||
setPersistent,
|
||||
changePaymentSettings,
|
||||
isReady,
|
||||
};
|
||||
};
|
||||
|
||||
export const usePaymentMethods = () => {
|
||||
const { usePersistent } = useStoreData();
|
||||
|
||||
// PayPal checkout.
|
||||
const [ paypal ] = usePersistent( 'ppcp-gateway' );
|
||||
const [ venmo ] = usePersistent( 'venmo' );
|
||||
|
@ -47,79 +83,6 @@ const useHooks = () => {
|
|||
const [ pui ] = usePersistent( 'ppcp-pay-upon-invoice-gateway' );
|
||||
const [ oxxo ] = usePersistent( 'ppcp-oxxo-gateway' );
|
||||
|
||||
// Custom modal data.
|
||||
const [ paypalShowLogo ] = usePersistent( 'paypalShowLogo' );
|
||||
const [ threeDSecure ] = usePersistent( 'threeDSecure' );
|
||||
const [ fastlaneCardholderName ] = usePersistent(
|
||||
'fastlaneCardholderName'
|
||||
);
|
||||
const [ fastlaneDisplayWatermark ] = usePersistent(
|
||||
'fastlaneDisplayWatermark'
|
||||
);
|
||||
|
||||
return {
|
||||
persist,
|
||||
isReady,
|
||||
setPersistent,
|
||||
changePaymentSettings,
|
||||
paypal,
|
||||
venmo,
|
||||
payLater,
|
||||
creditCard,
|
||||
advancedCreditCard,
|
||||
fastlane,
|
||||
applePay,
|
||||
googlePay,
|
||||
bancontact,
|
||||
blik,
|
||||
eps,
|
||||
ideal,
|
||||
mybank,
|
||||
p24,
|
||||
trustly,
|
||||
multibanco,
|
||||
pui,
|
||||
oxxo,
|
||||
paypalShowLogo,
|
||||
threeDSecure,
|
||||
fastlaneCardholderName,
|
||||
fastlaneDisplayWatermark,
|
||||
};
|
||||
};
|
||||
|
||||
export const useStore = () => {
|
||||
const { persist, isReady, setPersistent, changePaymentSettings } =
|
||||
useHooks();
|
||||
return { persist, isReady, setPersistent, changePaymentSettings };
|
||||
};
|
||||
|
||||
export const usePaymentMethods = () => {
|
||||
const {
|
||||
// PayPal Checkout.
|
||||
paypal,
|
||||
venmo,
|
||||
payLater,
|
||||
creditCard,
|
||||
|
||||
// Online card payments.
|
||||
advancedCreditCard,
|
||||
fastlane,
|
||||
applePay,
|
||||
googlePay,
|
||||
|
||||
// Local APMs.
|
||||
bancontact,
|
||||
blik,
|
||||
eps,
|
||||
ideal,
|
||||
mybank,
|
||||
p24,
|
||||
trustly,
|
||||
multibanco,
|
||||
pui,
|
||||
oxxo,
|
||||
} = useHooks();
|
||||
|
||||
const payPalCheckout = [ paypal, venmo, payLater, creditCard ];
|
||||
const onlineCardPayments = [
|
||||
advancedCreditCard,
|
||||
|
@ -169,12 +132,16 @@ export const usePaymentMethods = () => {
|
|||
};
|
||||
|
||||
export const usePaymentMethodsModal = () => {
|
||||
const {
|
||||
paypalShowLogo,
|
||||
threeDSecure,
|
||||
fastlaneCardholderName,
|
||||
fastlaneDisplayWatermark,
|
||||
} = useHooks();
|
||||
const { usePersistent } = useStoreData();
|
||||
|
||||
const [ paypalShowLogo ] = usePersistent( 'paypalShowLogo' );
|
||||
const [ threeDSecure ] = usePersistent( 'threeDSecure' );
|
||||
const [ fastlaneCardholderName ] = usePersistent(
|
||||
'fastlaneCardholderName'
|
||||
);
|
||||
const [ fastlaneDisplayWatermark ] = usePersistent(
|
||||
'fastlaneDisplayWatermark'
|
||||
);
|
||||
|
||||
return {
|
||||
paypalShowLogo,
|
||||
|
|
|
@ -19,6 +19,7 @@ const defaultTransient = Object.freeze( {
|
|||
|
||||
// Persistent: Values that are loaded from the DB.
|
||||
const defaultPersistent = Object.freeze( {
|
||||
// Payment methods.
|
||||
'ppcp-gateway': {},
|
||||
venmo: {},
|
||||
'pay-later': {},
|
||||
|
@ -37,6 +38,8 @@ const defaultPersistent = Object.freeze( {
|
|||
'ppcp-multibanco': {},
|
||||
'ppcp-pay-upon-invoice-gateway': {},
|
||||
'ppcp-oxxo-gateway': {},
|
||||
|
||||
// Custom payment method properties.
|
||||
paypalShowLogo: false,
|
||||
threeDSecure: 'no-3d-secure',
|
||||
fastlaneCardholderName: false,
|
||||
|
|
|
@ -84,3 +84,16 @@ export function persist() {
|
|||
} );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk action creator. Forces a data refresh from the REST API, replacing the current Redux values.
|
||||
*
|
||||
* @return {Function} The thunk function.
|
||||
*/
|
||||
export function refresh() {
|
||||
return ( { dispatch, select } ) => {
|
||||
dispatch.invalidateResolutionForStore();
|
||||
|
||||
select.persistentData();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,17 +6,38 @@
|
|||
*
|
||||
* @file
|
||||
*/
|
||||
import { useDispatch } from '@wordpress/data';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
|
||||
import { STORE_NAME } from './constants';
|
||||
import { createHooksForStore } from '../utils';
|
||||
import { useMemo } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Single source of truth for access Redux details.
|
||||
*
|
||||
* This hook returns a stable API to access actions, selectors and special hooks to generate
|
||||
* getter- and setters for transient or persistent properties.
|
||||
*
|
||||
* @return {{select, dispatch, useTransient, usePersistent}} Store data API.
|
||||
*/
|
||||
const useStoreData = () => {
|
||||
const select = useSelect( ( selectors ) => selectors( STORE_NAME ), [] );
|
||||
const dispatch = useDispatch( STORE_NAME );
|
||||
const { useTransient, usePersistent } = createHooksForStore( STORE_NAME );
|
||||
|
||||
return useMemo(
|
||||
() => ( {
|
||||
select,
|
||||
dispatch,
|
||||
useTransient,
|
||||
usePersistent,
|
||||
} ),
|
||||
[ select, dispatch, useTransient, usePersistent ]
|
||||
);
|
||||
};
|
||||
|
||||
const useHooks = () => {
|
||||
const { useTransient, usePersistent } = createHooksForStore( STORE_NAME );
|
||||
const { persist } = useDispatch( STORE_NAME );
|
||||
|
||||
// Read-only flags and derived state.
|
||||
const [ isReady ] = useTransient( 'isReady' );
|
||||
const { usePersistent } = useStoreData();
|
||||
|
||||
// Persistent accessors.
|
||||
const [ invoicePrefix, setInvoicePrefix ] =
|
||||
|
@ -47,8 +68,6 @@ const useHooks = () => {
|
|||
usePersistent( 'disabledCards' );
|
||||
|
||||
return {
|
||||
persist,
|
||||
isReady,
|
||||
invoicePrefix,
|
||||
setInvoicePrefix,
|
||||
authorizeOnly,
|
||||
|
@ -79,8 +98,16 @@ const useHooks = () => {
|
|||
};
|
||||
|
||||
export const useStore = () => {
|
||||
const { persist, isReady } = useHooks();
|
||||
return { persist, isReady };
|
||||
const { select, dispatch, useTransient } = useStoreData();
|
||||
const { persist, refresh } = dispatch;
|
||||
const [ isReady ] = useTransient( 'isReady' );
|
||||
|
||||
// Load persistent data from REST if not done yet.
|
||||
if ( ! isReady ) {
|
||||
select.persistentData();
|
||||
}
|
||||
|
||||
return { persist, refresh, isReady };
|
||||
};
|
||||
|
||||
export const useSettings = () => {
|
||||
|
|
|
@ -82,3 +82,16 @@ export function persist() {
|
|||
} );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk action creator. Forces a data refresh from the REST API, replacing the current Redux values.
|
||||
*
|
||||
* @return {Function} The thunk function.
|
||||
*/
|
||||
export function refresh() {
|
||||
return ( { dispatch, select } ) => {
|
||||
dispatch.invalidateResolutionForStore();
|
||||
|
||||
select.persistentData();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @file
|
||||
*/
|
||||
|
||||
import { useCallback } from '@wordpress/element';
|
||||
import { useCallback, useMemo } from '@wordpress/element';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
|
||||
import { createHooksForStore } from '../utils';
|
||||
|
@ -20,13 +20,37 @@ import {
|
|||
STYLING_PAYMENT_METHODS,
|
||||
STYLING_SHAPES,
|
||||
} from './configuration';
|
||||
import { persistentData } from './selectors';
|
||||
|
||||
/**
|
||||
* Single source of truth for access Redux details.
|
||||
*
|
||||
* This hook returns a stable API to access actions, selectors and special hooks to generate
|
||||
* getter- and setters for transient or persistent properties.
|
||||
*
|
||||
* @return {{select, dispatch, useTransient, usePersistent}} Store data API.
|
||||
*/
|
||||
const useStoreData = () => {
|
||||
const select = useSelect( ( selectors ) => selectors( STORE_NAME ), [] );
|
||||
const dispatch = useDispatch( STORE_NAME );
|
||||
const { useTransient, usePersistent } = createHooksForStore( STORE_NAME );
|
||||
|
||||
return useMemo(
|
||||
() => ( {
|
||||
select,
|
||||
dispatch,
|
||||
useTransient,
|
||||
usePersistent,
|
||||
} ),
|
||||
[ select, dispatch, useTransient, usePersistent ]
|
||||
);
|
||||
};
|
||||
|
||||
const useHooks = () => {
|
||||
const { useTransient } = createHooksForStore( STORE_NAME );
|
||||
const { persist, setPersistent } = useDispatch( STORE_NAME );
|
||||
const { useTransient, dispatch } = useStoreData();
|
||||
const { setPersistent } = dispatch;
|
||||
|
||||
// Transient accessors.
|
||||
const [ isReady ] = useTransient( 'isReady' );
|
||||
const [ location, setLocation ] = useTransient( 'location' );
|
||||
|
||||
// Persistent accessors.
|
||||
|
@ -61,8 +85,6 @@ const useHooks = () => {
|
|||
);
|
||||
|
||||
return {
|
||||
persist,
|
||||
isReady,
|
||||
location,
|
||||
setLocation,
|
||||
getLocationProp,
|
||||
|
@ -71,8 +93,16 @@ const useHooks = () => {
|
|||
};
|
||||
|
||||
export const useStore = () => {
|
||||
const { persist, isReady } = useHooks();
|
||||
return { persist, isReady };
|
||||
const { select, dispatch, useTransient } = useStoreData();
|
||||
const { persist, refresh } = dispatch;
|
||||
const [ isReady ] = useTransient( 'isReady' );
|
||||
|
||||
// Load persistent data from REST if not done yet.
|
||||
if ( ! isReady ) {
|
||||
select.persistentData();
|
||||
}
|
||||
|
||||
return { persist, refresh, isReady };
|
||||
};
|
||||
|
||||
export const useStylingLocation = () => {
|
||||
|
|
|
@ -5,6 +5,12 @@
|
|||
*/
|
||||
|
||||
export default {
|
||||
/**
|
||||
* Resets the store state to its initial values.
|
||||
* Used when needing to clear all store data.
|
||||
*/
|
||||
RESET: 'ppcp/todos/RESET',
|
||||
|
||||
// Transient data
|
||||
SET_TRANSIENT: 'ppcp/todos/SET_TRANSIENT',
|
||||
SET_COMPLETED_TODOS: 'ppcp/todos/SET_COMPLETED_TODOS',
|
||||
|
|
|
@ -17,11 +17,47 @@ import {
|
|||
REST_RESET_DISMISSED_TODOS_PATH,
|
||||
} from './constants';
|
||||
|
||||
export const setIsReady = ( isReady ) => ( {
|
||||
type: ACTION_TYPES.SET_TRANSIENT,
|
||||
payload: { isReady },
|
||||
/**
|
||||
* Special. Resets all values in the store to initial defaults.
|
||||
*
|
||||
* @return {Object} The action.
|
||||
*/
|
||||
export const reset = () => ( {
|
||||
type: ACTION_TYPES.RESET,
|
||||
} );
|
||||
|
||||
/**
|
||||
* Generic transient-data updater.
|
||||
*
|
||||
* @param {string} prop Name of the property to update.
|
||||
* @param {any} value The new value of the property.
|
||||
* @return {Object} The action.
|
||||
*/
|
||||
export const setTransient = ( prop, value ) => ( {
|
||||
type: ACTION_TYPES.SET_TRANSIENT,
|
||||
payload: { [ prop ]: value },
|
||||
} );
|
||||
|
||||
/**
|
||||
* Generic persistent-data updater.
|
||||
*
|
||||
* @param {string} prop Name of the property to update.
|
||||
* @param {any} value The new value of the property.
|
||||
* @return {Object} The action.
|
||||
*/
|
||||
export const setPersistent = ( prop, value ) => ( {
|
||||
type: ACTION_TYPES.SET_PERSISTENT,
|
||||
payload: { [ prop ]: value },
|
||||
} );
|
||||
|
||||
/**
|
||||
* Transient. Marks the store as "ready", i.e., fully initialized.
|
||||
*
|
||||
* @param {boolean} isReady Whether the store is ready
|
||||
* @return {Object} The action.
|
||||
*/
|
||||
export const setIsReady = ( isReady ) => setTransient( 'isReady', isReady );
|
||||
|
||||
export const setTodos = ( todos ) => ( {
|
||||
type: ACTION_TYPES.SET_TODOS,
|
||||
payload: todos,
|
||||
|
@ -39,6 +75,7 @@ export const setCompletedTodos = ( completedTodos ) => ( {
|
|||
|
||||
// Thunks
|
||||
|
||||
// TODO: Possibly, this should be a resolver?
|
||||
export function fetchTodos() {
|
||||
return async () => {
|
||||
const response = await apiFetch( { path: REST_PATH } );
|
||||
|
@ -46,9 +83,14 @@ export function fetchTodos() {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk action creator. Triggers the persistence of store data to the server.
|
||||
*
|
||||
* @return {Function} The thunk function.
|
||||
*/
|
||||
export function persist() {
|
||||
return async ( { select } ) => {
|
||||
return await apiFetch( {
|
||||
await apiFetch( {
|
||||
path: REST_PERSIST_PATH,
|
||||
method: 'POST',
|
||||
data: select.persistentData(),
|
||||
|
@ -56,6 +98,19 @@ export function persist() {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Thunk action creator. Forces a data refresh from the REST API, replacing the current Redux values.
|
||||
*
|
||||
* @return {Function} The thunk function.
|
||||
*/
|
||||
export function refresh() {
|
||||
return ( { dispatch, select } ) => {
|
||||
dispatch.invalidateResolutionForStore();
|
||||
|
||||
select.persistentData();
|
||||
};
|
||||
}
|
||||
|
||||
export function resetDismissedTodos() {
|
||||
return async ( { dispatch } ) => {
|
||||
try {
|
||||
|
|
|
@ -10,31 +10,40 @@
|
|||
import { useSelect, useDispatch } from '@wordpress/data';
|
||||
import { STORE_NAME } from './constants';
|
||||
import { createHooksForStore } from '../utils';
|
||||
import { useMemo } from '@wordpress/element';
|
||||
|
||||
const ensureArray = ( value ) => {
|
||||
if ( ! value ) {
|
||||
return [];
|
||||
}
|
||||
return Array.isArray( value ) ? value : Object.values( value );
|
||||
/**
|
||||
* Single source of truth for access Redux details.
|
||||
*
|
||||
* This hook returns a stable API to access actions, selectors and special hooks to generate
|
||||
* getter- and setters for transient or persistent properties.
|
||||
*
|
||||
* @return {{select, dispatch, useTransient, usePersistent}} Store data API.
|
||||
*/
|
||||
const useStoreData = () => {
|
||||
const select = useSelect( ( selectors ) => selectors( STORE_NAME ), [] );
|
||||
const dispatch = useDispatch( STORE_NAME );
|
||||
const { useTransient, usePersistent } = createHooksForStore( STORE_NAME );
|
||||
|
||||
return useMemo(
|
||||
() => ( {
|
||||
select,
|
||||
dispatch,
|
||||
useTransient,
|
||||
usePersistent,
|
||||
} ),
|
||||
[ select, dispatch, useTransient, usePersistent ]
|
||||
);
|
||||
};
|
||||
|
||||
const useHooks = () => {
|
||||
const { useTransient } = createHooksForStore( STORE_NAME );
|
||||
const { fetchTodos, setDismissedTodos, setCompletedTodos, persist } =
|
||||
useDispatch( STORE_NAME );
|
||||
|
||||
// Read-only flags and derived state.
|
||||
const [ isReady ] = useTransient( 'isReady' );
|
||||
const { dispatch, select } = useStoreData();
|
||||
const { fetchTodos, setDismissedTodos, setCompletedTodos } = dispatch;
|
||||
|
||||
// Get todos data from store
|
||||
const { todos, dismissedTodos, completedTodos } = useSelect( ( select ) => {
|
||||
const store = select( STORE_NAME );
|
||||
return {
|
||||
todos: ensureArray( store.getTodos() ),
|
||||
dismissedTodos: ensureArray( store.getDismissedTodos() ),
|
||||
completedTodos: ensureArray( store.getCompletedTodos() ),
|
||||
};
|
||||
}, [] );
|
||||
const todos = select.getTodos();
|
||||
const dismissedTodos = select.getDismissedTodos();
|
||||
const completedTodos = select.getCompletedTodos();
|
||||
|
||||
const dismissedSet = new Set( dismissedTodos );
|
||||
|
||||
|
@ -62,8 +71,6 @@ const useHooks = () => {
|
|||
);
|
||||
|
||||
return {
|
||||
persist,
|
||||
isReady,
|
||||
todos: filteredTodos,
|
||||
dismissedTodos,
|
||||
completedTodos,
|
||||
|
@ -74,14 +81,21 @@ const useHooks = () => {
|
|||
};
|
||||
|
||||
export const useStore = () => {
|
||||
const { persist, isReady } = useHooks();
|
||||
return { persist, isReady };
|
||||
const { select, dispatch, useTransient } = useStoreData();
|
||||
const { persist, refresh } = dispatch;
|
||||
const [ isReady ] = useTransient( 'isReady' );
|
||||
|
||||
// Load persistent data from REST if not done yet.
|
||||
if ( ! isReady ) {
|
||||
select.getTodos();
|
||||
}
|
||||
|
||||
return { persist, refresh, isReady };
|
||||
};
|
||||
|
||||
export const useTodos = () => {
|
||||
const { todos, fetchTodos, dismissTodo, setTodoCompleted, isReady } =
|
||||
useHooks();
|
||||
return { todos, fetchTodos, dismissTodo, setTodoCompleted, isReady };
|
||||
const { todos, fetchTodos, dismissTodo, setTodoCompleted } = useHooks();
|
||||
return { todos, fetchTodos, dismissTodo, setTodoCompleted };
|
||||
};
|
||||
|
||||
export const useDismissedTodos = () => {
|
||||
|
|
|
@ -52,6 +52,21 @@ const reducer = createReducer( defaultTransient, defaultPersistent, {
|
|||
[ ACTION_TYPES.SET_TRANSIENT ]: ( state, payload ) =>
|
||||
changeTransient( state, payload ),
|
||||
|
||||
/**
|
||||
* Resets state to defaults while maintaining initialization status
|
||||
*
|
||||
* @param {Object} state Current state
|
||||
* @return {Object} Reset state
|
||||
*/
|
||||
[ ACTION_TYPES.RESET ]: ( state ) => {
|
||||
const cleanState = changeTransient(
|
||||
changePersistent( state, defaultPersistent ),
|
||||
defaultTransient
|
||||
);
|
||||
cleanState.isReady = true; // Keep initialization flag
|
||||
return cleanState;
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates todos list
|
||||
*
|
||||
|
@ -99,6 +114,7 @@ const reducer = createReducer( defaultTransient, defaultPersistent, {
|
|||
},
|
||||
|
||||
/**
|
||||
* TODO: This is not used anywhere. Remove "SET_TODOS" and use this resolver instead.
|
||||
* Initializes persistent state with data from the server
|
||||
*
|
||||
* @param {Object} state Current state
|
||||
|
|
|
@ -11,7 +11,17 @@ const EMPTY_OBJ = Object.freeze( {} );
|
|||
const EMPTY_ARR = Object.freeze( [] );
|
||||
|
||||
const getState = ( state ) => state || EMPTY_OBJ;
|
||||
const getArray = ( value ) => {
|
||||
if ( Array.isArray( value ) ) {
|
||||
return value;
|
||||
}
|
||||
if ( value ) {
|
||||
return Object.values( value );
|
||||
}
|
||||
return EMPTY_ARR;
|
||||
};
|
||||
|
||||
// TODO: Implement a persistentData resolver!
|
||||
export const persistentData = ( state ) => {
|
||||
return getState( state ).data || EMPTY_OBJ;
|
||||
};
|
||||
|
@ -23,15 +33,15 @@ export const transientData = ( state ) => {
|
|||
|
||||
export const getTodos = ( state ) => {
|
||||
const todos = state?.todos || persistentData( state ).todos;
|
||||
return todos || EMPTY_ARR;
|
||||
return getArray( todos );
|
||||
};
|
||||
|
||||
export const getDismissedTodos = ( state ) => {
|
||||
const dismissed =
|
||||
state?.dismissedTodos || persistentData( state ).dismissedTodos;
|
||||
return dismissed || EMPTY_ARR;
|
||||
return getArray( dismissed );
|
||||
};
|
||||
|
||||
export const getCompletedTodos = ( state ) => {
|
||||
return state?.completedTodos || EMPTY_ARR; // Only look at root state, not persistent data
|
||||
return getArray( state?.completedTodos ); // Only look at root state, not persistent data
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@ import { useState, useEffect, useCallback, useRef } from '@wordpress/element';
|
|||
import { store as noticesStore } from '@wordpress/notices';
|
||||
|
||||
import { CommonHooks, OnboardingHooks } from '../data';
|
||||
import { useStoreManager } from './useStoreManager';
|
||||
|
||||
const PAYPAL_PARTNER_SDK_URL =
|
||||
'https://www.paypal.com/webapps/merchantboarding/js/lib/lightbox/partner.js';
|
||||
|
@ -30,7 +31,7 @@ export const useHandleOnboardingButton = ( isSandbox ) => {
|
|||
const { sandboxOnboardingUrl } = CommonHooks.useSandbox();
|
||||
const { productionOnboardingUrl } = CommonHooks.useProduction();
|
||||
const products = OnboardingHooks.useDetermineProducts();
|
||||
const { withActivity, startActivity } = CommonHooks.useBusyState();
|
||||
const { startActivity } = CommonHooks.useBusyState();
|
||||
const { authenticateWithOAuth } = CommonHooks.useAuthentication();
|
||||
const [ onboardingUrl, setOnboardingUrl ] = useState( '' );
|
||||
const [ scriptLoaded, setScriptLoaded ] = useState( false );
|
||||
|
@ -134,7 +135,7 @@ export const useHandleOnboardingButton = ( isSandbox ) => {
|
|||
// Ensure the onComplete handler is not removed by a PayPal init script.
|
||||
timerRef.current = setInterval( addHandler, 250 );
|
||||
},
|
||||
[ authenticateWithOAuth, withActivity ]
|
||||
[ authenticateWithOAuth, startActivity ]
|
||||
);
|
||||
|
||||
const removeCompleteHandler = useCallback( () => {
|
||||
|
@ -161,6 +162,7 @@ const useConnectionBase = () => {
|
|||
useDispatch( noticesStore );
|
||||
const { verifyLoginStatus } = CommonHooks.useMerchantInfo();
|
||||
const { withActivity } = CommonHooks.useBusyState();
|
||||
const { refreshAll } = useStoreManager();
|
||||
|
||||
return {
|
||||
handleFailed: ( res, genericMessage ) => {
|
||||
|
@ -178,6 +180,7 @@ const useConnectionBase = () => {
|
|||
if ( loginSuccessful ) {
|
||||
createSuccessNotice( MESSAGES.CONNECTED );
|
||||
await setCompleted( true );
|
||||
refreshAll();
|
||||
} else {
|
||||
createErrorNotice( MESSAGES.LOGIN_FAILED );
|
||||
}
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
import { useCallback, useMemo } from '@wordpress/element';
|
||||
|
||||
import {
|
||||
CommonHooks,
|
||||
PayLaterMessagingHooks,
|
||||
PaymentHooks,
|
||||
SettingsHooks,
|
||||
StylingHooks,
|
||||
TodosHooks,
|
||||
} from '../data';
|
||||
|
||||
export const useSaveSettings = () => {
|
||||
const { withActivity } = CommonHooks.useBusyState();
|
||||
|
||||
const { persist: persistPayment } = PaymentHooks.useStore();
|
||||
const { persist: persistSettings } = SettingsHooks.useStore();
|
||||
const { persist: persistStyling } = StylingHooks.useStore();
|
||||
const { persist: persistTodos } = TodosHooks.useStore();
|
||||
const { persist: persistPayLaterMessaging } =
|
||||
PayLaterMessagingHooks.useStore();
|
||||
|
||||
const persistActions = useMemo(
|
||||
() => [
|
||||
{
|
||||
key: 'persist-methods',
|
||||
message: 'Save payment methods',
|
||||
action: persistPayment,
|
||||
},
|
||||
{
|
||||
key: 'persist-settings',
|
||||
message: 'Save the settings',
|
||||
action: persistSettings,
|
||||
},
|
||||
{
|
||||
key: 'persist-styling',
|
||||
message: 'Save styling details',
|
||||
action: persistStyling,
|
||||
},
|
||||
{
|
||||
key: 'persist-todos',
|
||||
message: 'Save todos state',
|
||||
action: persistTodos,
|
||||
},
|
||||
{
|
||||
key: 'persist-pay-later-messaging',
|
||||
message: 'Save pay later messaging details',
|
||||
action: persistPayLaterMessaging,
|
||||
},
|
||||
],
|
||||
[
|
||||
persistPayLaterMessaging,
|
||||
persistPayment,
|
||||
persistSettings,
|
||||
persistStyling,
|
||||
persistTodos,
|
||||
]
|
||||
);
|
||||
|
||||
const persistAll = useCallback( () => {
|
||||
/**
|
||||
* Executes onSave on TabPayLaterMessaging component.
|
||||
*
|
||||
* Todo: find a better way for this, because it's highly unreliable
|
||||
* (it only works when the user is still on the "Pay Later Messaging" tab)
|
||||
*/
|
||||
document.getElementById( 'configurator-publishButton' )?.click();
|
||||
|
||||
persistActions.forEach( ( { key, message, action } ) => {
|
||||
withActivity( key, message, action );
|
||||
} );
|
||||
}, [ persistActions, withActivity ] );
|
||||
|
||||
return { persistAll };
|
||||
};
|
76
modules/ppcp-settings/resources/js/hooks/useStoreManager.js
Normal file
76
modules/ppcp-settings/resources/js/hooks/useStoreManager.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
import { useCallback, useMemo } from '@wordpress/element';
|
||||
|
||||
import {
|
||||
CommonHooks,
|
||||
PayLaterMessagingHooks,
|
||||
PaymentHooks,
|
||||
SettingsHooks,
|
||||
StylingHooks,
|
||||
TodosHooks,
|
||||
} from '../data';
|
||||
|
||||
export const useStoreManager = () => {
|
||||
const { withActivity } = CommonHooks.useBusyState();
|
||||
|
||||
const paymentStore = PaymentHooks.useStore();
|
||||
const settingsStore = SettingsHooks.useStore();
|
||||
const stylingStore = StylingHooks.useStore();
|
||||
const todosStore = TodosHooks.useStore();
|
||||
const payLaterStore = PayLaterMessagingHooks.useStore();
|
||||
|
||||
const storeActions = useMemo(
|
||||
() => [
|
||||
{
|
||||
key: 'methods',
|
||||
message: 'Process payment methods',
|
||||
store: paymentStore,
|
||||
},
|
||||
{
|
||||
key: 'settings',
|
||||
message: 'Process the settings',
|
||||
store: settingsStore,
|
||||
},
|
||||
{
|
||||
key: 'styling',
|
||||
message: 'Process styling details',
|
||||
store: stylingStore,
|
||||
},
|
||||
{
|
||||
key: 'todos',
|
||||
message: 'Process todos state',
|
||||
store: todosStore,
|
||||
},
|
||||
{
|
||||
key: 'pay-later-messaging',
|
||||
message: 'Process pay later messaging details',
|
||||
store: payLaterStore,
|
||||
},
|
||||
],
|
||||
[ payLaterStore, paymentStore, settingsStore, stylingStore, todosStore ]
|
||||
);
|
||||
|
||||
const persistAll = useCallback( () => {
|
||||
/**
|
||||
* Executes onSave on TabPayLaterMessaging component.
|
||||
*
|
||||
* Todo: find a better way for this, because it's highly unreliable
|
||||
* (it only works when the user is still on the "Pay Later Messaging" tab)
|
||||
*/
|
||||
document.getElementById( 'configurator-publishButton' )?.click();
|
||||
|
||||
storeActions.forEach( ( { key, message, store } ) => {
|
||||
withActivity( `persist-${ key }`, message, store.persist );
|
||||
} );
|
||||
}, [ storeActions, withActivity ] );
|
||||
|
||||
const refreshAll = useCallback( () => {
|
||||
storeActions.forEach( ( { key, message, store } ) => {
|
||||
withActivity( `refresh-${ key }`, message, store.refresh );
|
||||
} );
|
||||
}, [ storeActions, withActivity ] );
|
||||
|
||||
return {
|
||||
persistAll,
|
||||
refreshAll,
|
||||
};
|
||||
};
|
|
@ -211,7 +211,8 @@ class SettingsDataManager {
|
|||
$this->payment_methods->toggle_method_state( $method['id'], false );
|
||||
}
|
||||
|
||||
// Always enable Venmo and Pay Later.
|
||||
// Always enable PayPal, Venmo and Pay Later.
|
||||
$this->payment_methods->toggle_method_state( PayPalGateway::ID, true );
|
||||
$this->payment_methods->toggle_method_state( 'venmo', true );
|
||||
$this->payment_methods->toggle_method_state( 'pay-later', true );
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue