diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Features/FeatureDescription.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Features/FeatureDescription.js new file mode 100644 index 000000000..9bf754d13 --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Features/FeatureDescription.js @@ -0,0 +1,36 @@ +import { __ } from '@wordpress/i18n'; +import { Button, Icon } from '@wordpress/components'; +import { reusableBlock } from '@wordpress/icons'; + +const FeatureDescription = ( { refreshHandler, isRefreshing } ) => { + const buttonLabel = isRefreshing + ? __( 'Refreshing…', 'woocommerce-paypal-payments' ) + : __( 'Refresh', 'woocommerce-paypal-payments' ); + + return ( + <> +

+ { __( + 'Enable additional features and capabilities on your WooCommerce store.', + 'woocommerce-paypal-payments' + ) } +

+

+ { __( + 'Click Refresh to update your current features after making changes.', + 'woocommerce-paypal-payments' + ) } +

+ + + ); +}; + +export default FeatureDescription; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Features/FeatureItem.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Features/FeatureItem.js new file mode 100644 index 000000000..1659f961f --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Features/FeatureItem.js @@ -0,0 +1,70 @@ +import { __ } from '@wordpress/i18n'; +import { FeatureSettingsBlock } from '../../../../../ReusableComponents/SettingsBlocks'; +import { Content } from '../../../../../ReusableComponents/Elements'; +import { TITLE_BADGE_POSITIVE } from '../../../../../ReusableComponents/TitleBadge'; +import { selectTab, TAB_IDS } from '../../../../../../utils/tabSelector'; +import { setActiveModal } from '../../../../../../data/common/actions'; + +const FeatureItem = ( { + isBusy, + isSandbox, + title, + description, + buttons, + enabled, + notes, +} ) => { + const getButtonUrl = ( button ) => { + if ( button.urls ) { + return isSandbox ? button.urls.sandbox : button.urls.live; + } + + return button.url; + }; + + const visibleButtons = buttons.filter( + ( button ) => + ! button.showWhen || // Learn more buttons + ( enabled && button.showWhen === 'enabled' ) || + ( ! enabled && button.showWhen === 'disabled' ) + ); + const handleClick = async ( feature ) => { + if ( feature.action?.type === 'tab' ) { + const tabId = TAB_IDS[ feature.action.tab.toUpperCase() ]; + await selectTab( tabId, feature.action.section ); + } + if ( feature.action?.modal ) { + setActiveModal( feature.action.modal ); + } + }; + + const actionProps = { + isBusy, + enabled, + notes, + buttons: visibleButtons.map( ( button ) => ( { + ...button, + url: getButtonUrl( button ), + onClick: () => handleClick( button ), + } ) ), + }; + + if ( enabled ) { + actionProps.badge = { + text: __( 'Active', 'woocommerce-paypal-payments' ), + type: TITLE_BADGE_POSITIVE, + }; + } + + return ( + + + + ); +}; + +export default FeatureItem; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Features/Features.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Features/Features.js new file mode 100644 index 000000000..c8997979a --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Features/Features.js @@ -0,0 +1,95 @@ +import { __, sprintf } from '@wordpress/i18n'; +import { useState } from '@wordpress/element'; +import { useDispatch } from '@wordpress/data'; +import { store as noticesStore } from '@wordpress/notices'; +import FeatureItem from './FeatureItem'; +import FeatureDescription from './FeatureDescription'; +import { ContentWrapper } from '../../../../../ReusableComponents/Elements'; +import SettingsCard from '../../../../../ReusableComponents/SettingsCard'; +import { useMerchantInfo } from '../../../../../../data/common/hooks'; +import { STORE_NAME as COMMON_STORE_NAME } from '../../../../../../data/common'; +import { + NOTIFICATION_ERROR, + NOTIFICATION_SUCCESS, +} from '../../../../../ReusableComponents/Icons'; +import { useFeatures } from '../../../../../../data/features/hooks'; + +const Features = () => { + const [ isRefreshing, setIsRefreshing ] = useState( false ); + const { merchant } = useMerchantInfo(); + const { features, fetchFeatures } = useFeatures(); + const { refreshFeatureStatuses } = useDispatch( COMMON_STORE_NAME ); + const { createSuccessNotice, createErrorNotice } = + useDispatch( noticesStore ); + + if ( ! features || features.length === 0 ) { + return null; + } + + const refreshHandler = async () => { + setIsRefreshing( true ); + try { + const statusResult = await refreshFeatureStatuses(); + if ( ! statusResult?.success ) { + throw new Error( + statusResult?.message || 'Failed to refresh status' + ); + } + + const featuresResult = await fetchFeatures(); + if ( featuresResult.success ) { + createSuccessNotice( + __( + 'Features refreshed successfully.', + 'woocommerce-paypal-payments' + ), + { icon: NOTIFICATION_SUCCESS } + ); + } else { + throw new Error( + featuresResult?.message || 'Failed to fetch features' + ); + } + } catch ( error ) { + createErrorNotice( + sprintf( + /* translators: %s: error message */ + __( 'Operation failed: %s', 'woocommerce-paypal-payments' ), + error.message || + __( 'Unknown error', 'woocommerce-paypal-payments' ) + ), + { icon: NOTIFICATION_ERROR } + ); + } finally { + setIsRefreshing( false ); + } + }; + + return ( + + } + contentContainer={ false } + > + + { features.map( ( { id, isEligible, ...feature } ) => ( + + ) ) } + + + ); +}; + +export default Features; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Help/Help.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Help/Help.js new file mode 100644 index 000000000..afb1cc1f2 --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Help/Help.js @@ -0,0 +1,72 @@ +import { __ } from '@wordpress/i18n'; +import { FeatureSettingsBlock } from '../../../../../ReusableComponents/SettingsBlocks'; +import { + Content, + ContentWrapper, +} from '../../../../../ReusableComponents/Elements'; +import SettingsCard from '../../../../../ReusableComponents/SettingsCard'; + +const Help = () => { + return ( + + + + + + + + + + + + ); +}; + +export default Help; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Todos/Todos.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Todos/Todos.js new file mode 100644 index 000000000..e7ff5fb4b --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/Todos/Todos.js @@ -0,0 +1,86 @@ +import { __ } from '@wordpress/i18n'; +import { useState } from '@wordpress/element'; +import { Button, Icon } from '@wordpress/components'; +import { useDispatch } from '@wordpress/data'; +import { reusableBlock } from '@wordpress/icons'; +import { store as noticesStore } from '@wordpress/notices'; +import { TodoSettingsBlock } from '../../../../../ReusableComponents/SettingsBlocks'; +import SettingsCard from '../../../../../ReusableComponents/SettingsCard'; +import { useTodos } from '../../../../../../data/todos/hooks'; +import { STORE_NAME as COMMON_STORE_NAME } from '../../../../../../data/common'; +import { STORE_NAME as TODOS_STORE_NAME } from '../../../../../../data/todos'; +import { NOTIFICATION_SUCCESS } from '../../../../../ReusableComponents/Icons'; + +const Todos = () => { + const [ isResetting, setIsResetting ] = useState( false ); + const { todos, isReady: areTodosReady, dismissTodo } = useTodos(); + // eslint-disable-next-line no-shadow + const { setActiveModal, setActiveHighlight } = + useDispatch( COMMON_STORE_NAME ); + const { resetDismissedTodos, setDismissedTodos } = + useDispatch( TODOS_STORE_NAME ); + const { createSuccessNotice } = useDispatch( noticesStore ); + + const showTodos = areTodosReady && todos.length > 0; + + const resetHandler = async () => { + setIsResetting( true ); + try { + await setDismissedTodos( [] ); + await resetDismissedTodos(); + + createSuccessNotice( + __( + 'Dismissed items restored successfully.', + 'woocommerce-paypal-payments' + ), + { icon: NOTIFICATION_SUCCESS } + ); + } finally { + setIsResetting( false ); + } + }; + + if ( ! showTodos ) { + return null; + } + + return ( + +

+ { __( + 'Complete these tasks to keep your store updated with the latest products and services.', + 'woocommerce-paypal-payments' + ) } +

+ + + } + > + +
+ ); +}; + +export default Todos; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/features-config.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/features-config.js deleted file mode 100644 index 3a01b436f..000000000 --- a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Overview/features-config.js +++ /dev/null @@ -1,278 +0,0 @@ -import { __ } from '@wordpress/i18n'; -import { TAB_IDS, selectTab } from '../../../../../utils/tabSelector'; -import { payLaterMessaging } from './pay-later-messaging'; - -export const getFeatures = ( setActiveModal ) => { - const storeCountry = ppcpSettings?.storeCountry; - const features = [ - { - id: 'save_paypal_and_venmo', - title: __( 'Save PayPal and Venmo', 'woocommerce-paypal-payments' ), - description: __( - 'Securely save PayPal and Venmo payment methods for subscriptions or return buyers.', - 'woocommerce-paypal-payments' - ), - buttons: [ - { - type: 'secondary', - text: __( 'Configure', 'woocommerce-paypal-payments' ), - onClick: () => { - selectTab( - TAB_IDS.SETTINGS, - 'ppcp--save-payment-methods' - ); - }, - showWhen: 'enabled', - class: 'small-button', - }, - { - type: 'secondary', - text: __( 'Sign up', 'woocommerce-paypal-payments' ), - urls: { - sandbox: - 'https://www.sandbox.paypal.com/bizsignup/entry?product=ADVANCED_VAULTING', - live: 'https://www.paypal.com/bizsignup/entry?product=ADVANCED_VAULTING', - }, - showWhen: 'disabled', - class: 'small-button', - }, - { - type: 'tertiary', - text: __( 'Learn more', 'woocommerce-paypal-payments' ), - url: 'https://www.paypal.com/us/enterprise/payment-processing/accept-venmo', - class: 'small-button', - }, - ], - }, - { - id: 'advanced_credit_and_debit_cards', - title: __( - 'Advanced Credit and Debit Cards', - 'woocommerce-paypal-payments' - ), - description: __( - 'Process major credit and debit cards including Visa, Mastercard, American Express and Discover.', - 'woocommerce-paypal-payments' - ), - buttons: [ - { - type: 'secondary', - text: __( 'Configure', 'woocommerce-paypal-payments' ), - onClick: () => { - selectTab( - TAB_IDS.PAYMENT_METHODS, - 'ppcp-card-payments-card' - ).then( () => { - setActiveModal( 'ppcp-credit-card-gateway' ); - } ); - }, - showWhen: 'enabled', - class: 'small-button', - }, - { - type: 'secondary', - text: __( 'Sign up', 'woocommerce-paypal-payments' ), - urls: { - sandbox: - 'https://www.sandbox.paypal.com/bizsignup/entry?product=ppcp', - live: 'https://www.paypal.com/bizsignup/entry?product=ppcp', - }, - showWhen: 'disabled', - class: 'small-button', - }, - { - type: 'tertiary', - text: __( 'Learn more', 'woocommerce-paypal-payments' ), - url: 'https://developer.paypal.com/studio/checkout/advanced', - class: 'small-button', - }, - ], - }, - { - id: 'alternative_payment_methods', - title: __( - 'Alternative Payment Methods', - 'woocommerce-paypal-payments' - ), - description: __( - 'Offer global, country-specific payment options for your customers.', - 'woocommerce-paypal-payments' - ), - buttons: [ - { - type: 'secondary', - text: __( 'Configure', 'woocommerce-paypal-payments' ), - onClick: () => { - selectTab( - TAB_IDS.PAYMENT_METHODS, - 'ppcp-alternative-payments-card' - ); - }, - showWhen: 'enabled', - class: 'small-button', - }, - { - type: 'secondary', - text: __( 'Sign up', 'woocommerce-paypal-payments' ), - url: 'https://developer.paypal.com/docs/checkout/apm/', - showWhen: 'disabled', - class: 'small-button', - }, - { - type: 'tertiary', - text: __( 'Learn more', 'woocommerce-paypal-payments' ), - url: 'https://developer.paypal.com/docs/checkout/apm/', - class: 'small-button', - }, - ], - }, - { - id: 'google_pay', - title: __( 'Google Pay', 'woocommerce-paypal-payments' ), - description: __( - 'Let customers pay using their Google Pay wallet.', - 'woocommerce-paypal-payments' - ), - buttons: [ - { - type: 'secondary', - text: __( 'Configure', 'woocommerce-paypal-payments' ), - onClick: () => { - selectTab( - TAB_IDS.PAYMENT_METHODS, - 'ppcp-card-payments-card' - ).then( () => { - setActiveModal( 'ppcp-googlepay' ); - } ); - }, - showWhen: 'enabled', - class: 'small-button', - }, - { - type: 'secondary', - text: __( 'Sign up', 'woocommerce-paypal-payments' ), - urls: { - sandbox: - 'https://www.sandbox.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=GOOGLE_PAY', - live: 'https://www.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=GOOGLE_PAY', - }, - showWhen: 'disabled', - class: 'small-button', - }, - { - type: 'tertiary', - text: __( 'Learn more', 'woocommerce-paypal-payments' ), - url: 'https://developer.paypal.com/docs/checkout/apm/google-pay/', - class: 'small-button', - }, - ], - notes: [ - __( - '¹PayPal Q2 Earnings-2021.', - 'woocommerce-paypal-payments' - ), - ], - }, - { - id: 'apple_pay', - title: __( 'Apple Pay', 'woocommerce-paypal-payments' ), - description: __( - 'Let customers pay using their Apple Pay wallet.', - 'woocommerce-paypal-payments' - ), - buttons: [ - { - type: 'secondary', - text: __( 'Configure', 'woocommerce-paypal-payments' ), - onClick: () => { - selectTab( - TAB_IDS.PAYMENT_METHODS, - 'ppcp-card-payments-card' - ).then( () => { - setActiveModal( 'ppcp-applepay' ); - } ); - }, - showWhen: 'enabled', - class: 'small-button', - }, - { - type: 'secondary', - text: __( - 'Domain registration', - 'woocommerce-paypal-payments' - ), - urls: { - sandbox: - 'https://www.sandbox.paypal.com/uccservicing/apm/applepay', - live: 'https://www.paypal.com/uccservicing/apm/applepay', - }, - showWhen: 'enabled', - class: 'small-button', - }, - { - type: 'secondary', - text: __( 'Sign up', 'woocommerce-paypal-payments' ), - urls: { - sandbox: - 'https://www.sandbox.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=APPLE_PAY', - live: 'https://www.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=APPLE_PAY', - }, - showWhen: 'disabled', - class: 'small-button', - }, - { - type: 'tertiary', - text: __( 'Learn more', 'woocommerce-paypal-payments' ), - url: 'https://developer.paypal.com/docs/checkout/apm/apple-pay/', - class: 'small-button', - }, - ], - }, - ]; - - const countryData = payLaterMessaging[ storeCountry ] || {}; - - if ( - !! window.ppcpSettings?.isPayLaterConfiguratorAvailable && - countryData - ) { - const countryLocation = [ - 'UK', - 'ES', - 'IT', - 'FR', - 'US', - 'DE', - 'AU', - ].includes( storeCountry ) - ? storeCountry.toLowerCase() - : 'us'; - features.push( { - id: 'pay_later_messaging', - title: __( 'Pay Later Messaging', 'woocommerce-paypal-payments' ), - description: __( - 'Let customers know they can buy now and pay later with PayPal. Adding this messaging can boost conversion rates and increase cart sizes by 39%¹, with no extra cost to you—plus, you get paid up front.', - 'woocommerce-paypal-payments' - ), - buttons: [ - { - type: 'secondary', - text: __( 'Configure', 'woocommerce-paypal-payments' ), - onClick: () => { - selectTab( TAB_IDS.PAY_LATER_MESSAGING ); - }, - showWhen: 'enabled', - class: 'small-button', - }, - { - type: 'tertiary', - text: __( 'Learn more', 'woocommerce-paypal-payments' ), - url: `https://www.paypal.com/${ countryLocation }/business/accept-payments/checkout/installments`, - class: 'small-button', - }, - ], - } ); - } - - return features; -}; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Tabs/TabOverview.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Tabs/TabOverview.js index 089ad7150..e8cd2cd1b 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Tabs/TabOverview.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Tabs/TabOverview.js @@ -1,356 +1,25 @@ -import { __, sprintf } from '@wordpress/i18n'; -import { useState, useEffect } from '@wordpress/element'; -import { Button, Icon } from '@wordpress/components'; -import { useDispatch } from '@wordpress/data'; -import { reusableBlock } from '@wordpress/icons'; -import { store as noticesStore } from '@wordpress/notices'; - -import { - TodoSettingsBlock, - FeatureSettingsBlock, -} from '../../../ReusableComponents/SettingsBlocks'; -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 { - NOTIFICATION_ERROR, - NOTIFICATION_SUCCESS, -} from '../../../ReusableComponents/Icons'; +import Todos from '../Components/Overview/Todos/Todos'; +import Features from '../Components/Overview/Features/Features'; +import Help from '../Components/Overview/Help/Help'; +import { TodosHooks, CommonHooks, FeaturesHooks } from '../../../../data'; import SpinnerOverlay from '../../../ReusableComponents/SpinnerOverlay'; -import { useFeatures } from '../../../../data/features/hooks'; -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: featuresIsReady } = FeaturesHooks.useFeatures(); - if ( ! areTodosReady || ! merchantIsReady ) { + if ( ! areTodosReady || ! merchantIsReady || ! featuresIsReady ) { return ; } return (
- - - + + +
); }; export default TabOverview; - -const OverviewTodos = () => { - const [ isResetting, setIsResetting ] = useState( false ); - const { todos, isReady: areTodosReady, dismissTodo } = useTodos(); - // eslint-disable-next-line no-shadow - const { setActiveModal, setActiveHighlight } = - useDispatch( COMMON_STORE_NAME ); - const { resetDismissedTodos, setDismissedTodos } = - useDispatch( TODOS_STORE_NAME ); - const { createSuccessNotice } = useDispatch( noticesStore ); - - const showTodos = areTodosReady && todos.length > 0; - - const resetHandler = async () => { - setIsResetting( true ); - try { - await setDismissedTodos( [] ); - await resetDismissedTodos(); - - createSuccessNotice( - __( - 'Dismissed items restored successfully.', - 'woocommerce-paypal-payments' - ), - { icon: NOTIFICATION_SUCCESS } - ); - } finally { - setIsResetting( false ); - } - }; - - if ( ! showTodos ) { - return null; - } - - return ( - -

- { __( - 'Complete these tasks to keep your store updated with the latest products and services.', - 'woocommerce-paypal-payments' - ) } -

- - - } - > - -
- ); -}; - -const OverviewFeatures = () => { - const [ isRefreshing, setIsRefreshing ] = useState( false ); - const { merchant } = useMerchantInfo(); - const { refreshFeatureStatuses } = useDispatch( COMMON_STORE_NAME ); - const { createSuccessNotice, createErrorNotice } = - useDispatch( noticesStore ); - const { features, fetchFeatures } = useFeatures(); - - useEffect( () => { - fetchFeatures(); - }, [ fetchFeatures ] ); - - const refreshHandler = async () => { - setIsRefreshing( true ); - - try { - const result = await refreshFeatureStatuses(); - if ( result && ! result.success ) { - const errorMessage = sprintf( - /* translators: %s: error message */ - __( - 'Operation failed: %s Check WooCommerce logs for more details.', - 'woocommerce-paypal-payments' - ), - result.message || - __( 'Unknown error', 'woocommerce-paypal-payments' ) - ); - - createErrorNotice( errorMessage, { - icon: NOTIFICATION_ERROR, - } ); - console.error( - 'Failed to refresh features:', - result.message || 'Unknown error' - ); - } else { - createSuccessNotice( - __( - 'Features refreshed successfully.', - 'woocommerce-paypal-payments' - ), - { - icon: NOTIFICATION_SUCCESS, - } - ); - } - } finally { - setIsRefreshing( false ); - } - }; - - return ( - - } - contentContainer={ false } - > - - { features.map( ( { id, ...feature } ) => ( - - ) ) } - - - ); -}; - -const OverviewFeatureItem = ( { - isBusy, - isSandbox, - title, - description, - buttons, - enabled, - notes, -} ) => { - const getButtonUrl = ( button ) => { - if ( button.urls ) { - return isSandbox ? button.urls.sandbox : button.urls.live; - } - - return button.url; - }; - - const visibleButtons = buttons.filter( - ( button ) => - ! button.showWhen || // Learn more buttons - ( enabled && button.showWhen === 'enabled' ) || - ( ! enabled && button.showWhen === 'disabled' ) - ); - const handleClick = async ( feature ) => { - if ( feature.action?.type === 'tab' ) { - const tabId = TAB_IDS[ feature.action.tab.toUpperCase() ]; - await selectTab( tabId, feature.action.section ); - } - if ( feature.action?.modal ) { - setActiveModal( feature.action.modal ); - } - }; - - const actionProps = { - isBusy, - enabled, - notes, - buttons: visibleButtons.map( ( button ) => ( { - ...button, - url: getButtonUrl( button ), - onClick: () => handleClick( button ), - } ) ), - }; - - if ( enabled ) { - actionProps.badge = { - text: __( 'Active', 'woocommerce-paypal-payments' ), - type: TITLE_BADGE_POSITIVE, - }; - } - - return ( - - - - ); -}; - -const OverviewFeatureDescription = ( { refreshHandler, isRefreshing } ) => { - const buttonLabel = isRefreshing - ? __( 'Refreshing…', 'woocommerce-paypal-payments' ) - : __( 'Refresh', 'woocommerce-paypal-payments' ); - - return ( - <> -

- { __( - 'Enable additional features and capabilities on your WooCommerce store.', - 'woocommerce-paypal-payments' - ) } -

-

- { __( - 'Click Refresh to update your current features after making changes.', - 'woocommerce-paypal-payments' - ) } -

- - - ); -}; - -const OverviewHelp = () => { - return ( - - - - - - - - - - - - ); -}; diff --git a/modules/ppcp-settings/resources/js/data/features/action-types.js b/modules/ppcp-settings/resources/js/data/features/action-types.js index 309037f18..dc21c5110 100644 --- a/modules/ppcp-settings/resources/js/data/features/action-types.js +++ b/modules/ppcp-settings/resources/js/data/features/action-types.js @@ -8,8 +8,7 @@ export default { // Transient data SET_TRANSIENT: 'ppcp/features/SET_TRANSIENT', - // Persistent data - SET_PERSISTENT: 'ppcp/features/SET_PERSISTENT', - RESET: 'ppcp/features/RESET', + // Persistant data + SET_FEATURES: 'ppcp/features/SET_FEATURES', HYDRATE: 'ppcp/features/HYDRATE', }; diff --git a/modules/ppcp-settings/resources/js/data/features/actions.js b/modules/ppcp-settings/resources/js/data/features/actions.js index 664e7cbae..6dc43653f 100644 --- a/modules/ppcp-settings/resources/js/data/features/actions.js +++ b/modules/ppcp-settings/resources/js/data/features/actions.js @@ -2,16 +2,14 @@ * Action Creators: Define functions to create action objects. * * These functions update state or trigger side effects (e.g., async operations). - * Actions are categorized as Transient, Persistent, or Side effect. + * Actions are categorized as Transient or Side effect. * * @file */ import apiFetch from '@wordpress/api-fetch'; - import ACTION_TYPES from './action-types'; -import { REST_PERSIST_PATH } from './constants'; -import { dispatch } from '@wordpress/data'; +import { REST_PATH } from './constants'; /** * @typedef {Object} Action An action object that is handled by a reducer or control. @@ -20,14 +18,7 @@ import { dispatch } from '@wordpress/data'; */ /** - * Special. Resets all values in the store to initial defaults. - * - * @return {Action} The action. - */ -export const reset = () => ( { type: ACTION_TYPES.RESET } ); - -/** - * Persistent. Set the full store details during app initialization. + * Set the full store details during app initialization. * * @param {{data: {}, flags?: {}}} payload * @return {Action} The action. @@ -49,18 +40,6 @@ export const setTransient = ( prop, value ) => ( { 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 {Action} 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. * @@ -70,24 +49,39 @@ export const setPersistent = ( prop, value ) => ( { export const setIsReady = ( isReady ) => setTransient( 'isReady', isReady ); /** - * Thunk action creator. Triggers the persistence of store data to the server. + * Sets the features in the store. * - * @return {Function} The thunk function. + * @param {Array} features The features to set. + * @return {Action} The action. */ -export function persist() { - return async ( { select } ) => { - await apiFetch( { - path: REST_PERSIST_PATH, - method: 'POST', - data: select.persistentData(), - } ); - }; -} +export const setFeatures = ( features ) => ( { + type: ACTION_TYPES.SET_FEATURES, + payload: features, +} ); -export function fetchFeatures() { - return async () => { - const response = await apiFetch( { path: REST_PERSIST_PATH } ); - const features = response?.data || []; - dispatch( setFeatures( features ) ); - }; -} +/** + * Fetches features from the server. + * + * @return {Promise} The features data. + */ +export const fetchFeatures = async () => { + try { + const response = await apiFetch( { path: REST_PATH } ); + if ( response?.data ) { + return { + success: true, + features: response.data.features, + }; + } + return { + success: false, + features: [], + }; + } catch ( e ) { + return { + success: false, + error: e, + message: e.message, + }; + } +}; diff --git a/modules/ppcp-settings/resources/js/data/features/constants.js b/modules/ppcp-settings/resources/js/data/features/constants.js index 64b1b5251..88961407a 100644 --- a/modules/ppcp-settings/resources/js/data/features/constants.js +++ b/modules/ppcp-settings/resources/js/data/features/constants.js @@ -5,23 +5,4 @@ */ export const STORE_NAME = 'wc/paypal/features'; - -/** - * REST path to hydrate data of this module by loading data from the WP DB. - * - * Used by: Resolvers - * See: .php - * - * @type {string} - */ -export const REST_HYDRATE_PATH = '/wc/v3/wc_paypal/features'; - -/** - * REST path to persist data of this module to the WP DB. - * - * Used by: Controls - * See: .php - * - * @type {string} - */ -export const REST_PERSIST_PATH = '/wc/v3/wc_paypal/features'; +export const REST_PATH = '/wc/v3/wc_paypal/features'; diff --git a/modules/ppcp-settings/resources/js/data/features/hooks.js b/modules/ppcp-settings/resources/js/data/features/hooks.js index 286d31518..476aab163 100644 --- a/modules/ppcp-settings/resources/js/data/features/hooks.js +++ b/modules/ppcp-settings/resources/js/data/features/hooks.js @@ -1,5 +1,5 @@ /** - * Hooks: Provide the main API for components to interact with the store. + * Hooks: Provide the main API for components to interact with the features store. * * These encapsulate store interactions, offering a consistent interface. * Hooks simplify data access and manipulation for components. @@ -7,49 +7,61 @@ * @file */ -import { useMemo } from '@wordpress/element'; -import { useDispatch, useSelect } from '@wordpress/data'; - -import { createHooksForStore } from '../utils'; -import { STORE_NAME } from './constants'; - -/** - * 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 ] - ); -}; - -export const useStore = () => { - const { dispatch, useTransient } = useStoreData(); - const [ isReady ] = useTransient( 'isReady' ); - - return { persist: dispatch.persist, isReady }; -}; +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect } from '@wordpress/element'; +import apiFetch from '@wordpress/api-fetch'; +import { STORE_NAME, REST_PATH } from './constants'; export const useFeatures = () => { - const { usePersistent } = useStoreData(); - const [ features, fetchFeatures ] = usePersistent( 'features' ); + const { features, isReady } = useSelect( ( select ) => { + const store = select( STORE_NAME ); + + return { + features: store.getFeatures() || [], + isReady: select( STORE_NAME ).transientData()?.isReady || false, + }; + }, [] ); + + const { setFeatures, setIsReady } = useDispatch( STORE_NAME ); + + useEffect( () => { + const loadInitialFeatures = async () => { + try { + const response = await apiFetch( { path: REST_PATH } ); + + if ( response?.data?.features ) { + const featuresData = response.data.features; + + if ( featuresData.length > 0 ) { + await setFeatures( featuresData ); + await setIsReady( true ); + } + } + } catch ( error ) {} + }; + + if ( ! isReady ) { + loadInitialFeatures(); + } + }, [ isReady, setFeatures, setIsReady ] ); return { features, - fetchFeatures, + isReady, + fetchFeatures: async () => { + try { + const response = await apiFetch( { path: REST_PATH } ); + const featuresData = response.data?.features || []; + + if ( featuresData.length > 0 ) { + await setFeatures( featuresData ); + await setIsReady( true ); + return { success: true, features: featuresData }; + } + return { success: false, features: [] }; + } catch ( error ) { + return { success: false, error, message: error.message }; + } + }, }; }; diff --git a/modules/ppcp-settings/resources/js/data/features/reducer.js b/modules/ppcp-settings/resources/js/data/features/reducer.js index 11e261ebe..d3932fca4 100644 --- a/modules/ppcp-settings/resources/js/data/features/reducer.js +++ b/modules/ppcp-settings/resources/js/data/features/reducer.js @@ -22,7 +22,7 @@ const defaultTransient = Object.freeze( { /** * Persistent: Values that are loaded from and saved to the DB. - * These represent the core todos configuration. + * These represent the core features configuration. */ const defaultPersistent = Object.freeze( { features: [], @@ -50,10 +50,10 @@ const reducer = createReducer( defaultTransient, defaultPersistent, { changeTransient( state, payload ), /** - * Updates todos list + * Updates features list * * @param {Object} state Current state - * @param {Object} payload Update payload + * @param {Object} payload Update payload containing features array * @return {Object} Updated state */ [ ACTION_TYPES.SET_FEATURES ]: ( state, payload ) => { @@ -65,7 +65,7 @@ const reducer = createReducer( defaultTransient, defaultPersistent, { * * @param {Object} state Current state * @param {Object} payload Hydration payload containing server data - * @param {Object} payload.data The todos data to hydrate + * @param {Object} payload.data The features data to hydrate * @return {Object} Hydrated state */ [ ACTION_TYPES.HYDRATE ]: ( state, payload ) => diff --git a/modules/ppcp-settings/resources/js/data/features/resolvers.js b/modules/ppcp-settings/resources/js/data/features/resolvers.js index 5e79d8de7..4d9de5d2c 100644 --- a/modules/ppcp-settings/resources/js/data/features/resolvers.js +++ b/modules/ppcp-settings/resources/js/data/features/resolvers.js @@ -11,26 +11,24 @@ import { __ } from '@wordpress/i18n'; import apiFetch from '@wordpress/api-fetch'; -import { REST_HYDRATE_PATH } from './constants'; +import { REST_PATH } from './constants'; /** - * Retrieve settings from the site's REST API. + * Hydrates the features data from the API. + * + * @return {Object} Action to dispatch. */ -export function persistentData() { - return async ( { dispatch, registry } ) => { +export function getFeatures() { + return async ( { dispatch } ) => { try { - const result = await apiFetch( { path: REST_HYDRATE_PATH } ); - await dispatch.hydrate( result ); - await dispatch.setIsReady( true ); - } catch ( e ) { - await registry - .dispatch( 'core/notices' ) - .createErrorNotice( - __( - 'Error retrieving features details.', - 'woocommerce-paypal-payments' - ) - ); + const response = await apiFetch( { path: REST_PATH } ); + + if ( response?.features ) { + dispatch.setFeatures( response.features ); + dispatch.setIsReady( true ); + } + } catch ( error ) { + console.error( 'Error fetching features:', error ); } }; } diff --git a/modules/ppcp-settings/resources/js/data/features/selectors.js b/modules/ppcp-settings/resources/js/data/features/selectors.js index 14334fcf3..98100dec9 100644 --- a/modules/ppcp-settings/resources/js/data/features/selectors.js +++ b/modules/ppcp-settings/resources/js/data/features/selectors.js @@ -8,6 +8,7 @@ */ const EMPTY_OBJ = Object.freeze( {} ); +const EMPTY_ARR = Object.freeze( [] ); const getState = ( state ) => state || EMPTY_OBJ; @@ -19,3 +20,8 @@ export const transientData = ( state ) => { const { data, ...transientState } = getState( state ); return transientState || EMPTY_OBJ; }; + +export const getFeatures = ( state ) => { + const features = state?.features || persistentData( state ).features; + return features || EMPTY_ARR; +}; diff --git a/modules/ppcp-settings/services.php b/modules/ppcp-settings/services.php index 443dbaf7e..e67cdacc0 100644 --- a/modules/ppcp-settings/services.php +++ b/modules/ppcp-settings/services.php @@ -378,25 +378,25 @@ return array( $capabilities['google_pay'] && ! $gateways['google_pay'], // Enable Google Pay. ); }, - 'settings.rest.features' => static function ( ContainerInterface $container ) : FeaturesRestEndpoint { + 'settings.rest.features' => static function ( ContainerInterface $container ) : FeaturesRestEndpoint { return new FeaturesRestEndpoint( $container->get( 'settings.data.definition.features' ), $container->get( 'settings.rest.settings' ) ); }, - 'settings.data.definition.features' => static function ( ContainerInterface $container ) : FeaturesDefinition { + 'settings.data.definition.features' => static function ( ContainerInterface $container ) : FeaturesDefinition { return new FeaturesDefinition( $container->get( 'settings.service.features_eligibilities' ), $container->get( 'settings.data.general' ) ); }, - 'settings.service.features_eligibilities' => static function( ContainerInterface $container ): FeaturesEligibilityService { + 'settings.service.features_eligibilities' => static function( ContainerInterface $container ): FeaturesEligibilityService { $features = apply_filters( 'woocommerce_paypal_payments_rest_common_merchant_features', array() ); - $payment_endpoint = $container->get('settings.rest.payment'); + $payment_endpoint = $container->get( 'settings.rest.payment' ); $settings = $payment_endpoint->get_details()->get_data(); // Settings status. @@ -418,8 +418,8 @@ return array( $capabilities['save_paypal'], // Save PayPal and Venmo eligibility. $capabilities['acdc'] && ! $gateways['card-button'], // Advanced credit and debit cards eligibility. $capabilities['apm'], // Alternative payment methods eligibility. - $capabilities['acdc'] && ! $capabilities['google_pay'], // Google Pay eligibility. - $capabilities['acdc'] && ! $capabilities['apple_pay'], // Apple Pay eligibility. + $capabilities['acdc'] && $capabilities['google_pay'], // Google Pay eligibility. + $capabilities['acdc'] && $capabilities['apple_pay'], // Apple Pay eligibility. $capabilities['paylater'], // Pay Later eligibility. ); }, diff --git a/modules/ppcp-settings/src/Data/Definition/FeaturesDefinition.php b/modules/ppcp-settings/src/Data/Definition/FeaturesDefinition.php index a4c9ca3b4..bbe105d9c 100644 --- a/modules/ppcp-settings/src/Data/Definition/FeaturesDefinition.php +++ b/modules/ppcp-settings/src/Data/Definition/FeaturesDefinition.php @@ -18,8 +18,8 @@ use WooCommerce\PayPalCommerce\Settings\Data\GeneralSettings; * Provides the definitions for all available features in the system. * Each feature has a title, description, eligibility condition, and associated action. */ -class FeaturesDefinition -{ +class FeaturesDefinition { + /** * The features eligibility service. @@ -39,15 +39,14 @@ class FeaturesDefinition * Constructor. * * @param FeaturesEligibilityService $eligibilities The features eligibility service. - * @param GeneralSettings $settings The general settings service. + * @param GeneralSettings $settings The general settings service. */ public function __construct( FeaturesEligibilityService $eligibilities, - GeneralSettings $settings - ) - { + GeneralSettings $settings + ) { $this->eligibilities = $eligibilities; - $this->settings = $settings; + $this->settings = $settings; } /** @@ -55,10 +54,9 @@ class FeaturesDefinition * * @return array The array of feature definitions. */ - public function get(): array - { + public function get(): array { $eligibility_checks = $this->eligibilities->get_eligibility_checks(); - $paylaterCountries = [ + $paylater_countries = array( 'UK', 'ES', 'IT', @@ -66,216 +64,216 @@ class FeaturesDefinition 'US', 'DE', 'AU', - ]; - $storeCountry = $this->settings->get_woo_settings()['country']; - $countryLocation = in_array($storeCountry, $paylaterCountries) ? strtolower($storeCountry) : 'us'; + ); + $store_country = $this->settings->get_woo_settings()['country']; + $country_location = in_array( $store_country, $paylater_countries, true ) ? strtolower( $store_country ) : 'us'; return array( - 'save_paypal_and_venmo' => array( - 'title' => __('Save PayPal and Venmo', 'woocommerce-paypal-payments'), - 'description' => __('Securely save PayPal and Venmo payment methods for subscriptions or return buyers.', 'woocommerce-paypal-payments'), - 'isEligible' => $eligibility_checks['save_paypal_and_venmo'], - 'buttons' => array( + 'save_paypal_and_venmo' => array( + 'title' => __( 'Save PayPal and Venmo', 'woocommerce-paypal-payments' ), + 'description' => __( 'Securely save PayPal and Venmo payment methods for subscriptions or return buyers.', 'woocommerce-paypal-payments' ), + 'isEligible' => $eligibility_checks['save_paypal_and_venmo'], + 'buttons' => array( array( - 'type' => 'secondary', - 'text' => __('Configure', 'woocommerce-paypal-payments'), - 'action' => array( - 'type' => 'tab', - 'tab' => 'settings', + 'type' => 'secondary', + 'text' => __( 'Configure', 'woocommerce-paypal-payments' ), + 'action' => array( + 'type' => 'tab', + 'tab' => 'settings', 'section' => 'ppcp--save-payment-methods', ), 'showWhen' => 'enabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'secondary', - 'text' => __('Sign up', 'woocommerce-paypal-payments'), - 'urls' => array( + 'type' => 'secondary', + 'text' => __( 'Sign up', 'woocommerce-paypal-payments' ), + 'urls' => array( 'sandbox' => 'https://www.sandbox.paypal.com/bizsignup/entry?product=ADVANCED_VAULTING', - 'live' => 'https://www.paypal.com/bizsignup/entry?product=ADVANCED_VAULTING', + 'live' => 'https://www.paypal.com/bizsignup/entry?product=ADVANCED_VAULTING', ), 'showWhen' => 'disabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'tertiary', - 'text' => __('Learn more', 'woocommerce-paypal-payments'), - 'url' => 'https://www.paypal.com/us/enterprise/payment-processing/accept-venmo', + 'type' => 'tertiary', + 'text' => __( 'Learn more', 'woocommerce-paypal-payments' ), + 'url' => 'https://www.paypal.com/us/enterprise/payment-processing/accept-venmo', 'class' => 'small-button', ), ), ), 'advanced_credit_and_debit_cards' => array( - 'title' => __('Advanced Credit and Debit Cards', 'woocommerce-paypal-payments'), - 'description' => __('Process major credit and debit cards including Visa, Mastercard, American Express and Discover.', 'woocommerce-paypal-payments'), - 'isEligible' => $eligibility_checks['advanced_credit_and_debit_cards'], - 'buttons' => array( + 'title' => __( 'Advanced Credit and Debit Cards', 'woocommerce-paypal-payments' ), + 'description' => __( 'Process major credit and debit cards including Visa, Mastercard, American Express and Discover.', 'woocommerce-paypal-payments' ), + 'isEligible' => $eligibility_checks['advanced_credit_and_debit_cards'], + 'buttons' => array( array( - 'type' => 'secondary', - 'text' => __('Configure', 'woocommerce-paypal-payments'), - 'action' => array( - 'type' => 'tab', - 'tab' => 'payment_methods', + 'type' => 'secondary', + 'text' => __( 'Configure', 'woocommerce-paypal-payments' ), + 'action' => array( + 'type' => 'tab', + 'tab' => 'payment_methods', 'section' => 'ppcp-card-payments-card', - 'modal' => 'ppcp-credit-card-gateway', + 'modal' => 'ppcp-credit-card-gateway', ), 'showWhen' => 'enabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'secondary', - 'text' => __('Sign up', 'woocommerce-paypal-payments'), - 'urls' => array( + 'type' => 'secondary', + 'text' => __( 'Sign up', 'woocommerce-paypal-payments' ), + 'urls' => array( 'sandbox' => 'https://www.sandbox.paypal.com/bizsignup/entry?product=ppcp', - 'live' => 'https://www.paypal.com/bizsignup/entry?product=ppcp', + 'live' => 'https://www.paypal.com/bizsignup/entry?product=ppcp', ), 'showWhen' => 'disabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'tertiary', - 'text' => __('Learn more', 'woocommerce-paypal-payments'), - 'url' => 'https://developer.paypal.com/studio/checkout/advanced', + 'type' => 'tertiary', + 'text' => __( 'Learn more', 'woocommerce-paypal-payments' ), + 'url' => 'https://developer.paypal.com/studio/checkout/advanced', 'class' => 'small-button', ), ), ), - 'alternative_payment_methods' => array( - 'title' => __('Alternative Payment Methods', 'woocommerce-paypal-payments'), - 'description' => __('Offer global, country-specific payment options for your customers.', 'woocommerce-paypal-payments'), - 'isEligible' => $eligibility_checks['alternative_payment_methods'], - 'buttons' => array( + 'alternative_payment_methods' => array( + 'title' => __( 'Alternative Payment Methods', 'woocommerce-paypal-payments' ), + 'description' => __( 'Offer global, country-specific payment options for your customers.', 'woocommerce-paypal-payments' ), + 'isEligible' => $eligibility_checks['alternative_payment_methods'], + 'buttons' => array( array( - 'type' => 'secondary', - 'text' => __('Configure', 'woocommerce-paypal-payments'), - 'action' => array( - 'type' => 'tab', - 'tab' => 'payment_methods', + 'type' => 'secondary', + 'text' => __( 'Configure', 'woocommerce-paypal-payments' ), + 'action' => array( + 'type' => 'tab', + 'tab' => 'payment_methods', 'section' => 'ppcp-alternative-payments-card', ), 'showWhen' => 'enabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'secondary', - 'text' => __('Sign up', 'woocommerce-paypal-payments'), - 'url' => 'https://developer.paypal.com/docs/checkout/apm/', + 'type' => 'secondary', + 'text' => __( 'Sign up', 'woocommerce-paypal-payments' ), + 'url' => 'https://developer.paypal.com/docs/checkout/apm/', 'showWhen' => 'disabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'tertiary', - 'text' => __('Learn more', 'woocommerce-paypal-payments'), - 'url' => 'https://developer.paypal.com/docs/checkout/apm/', + 'type' => 'tertiary', + 'text' => __( 'Learn more', 'woocommerce-paypal-payments' ), + 'url' => 'https://developer.paypal.com/docs/checkout/apm/', 'class' => 'small-button', ), ), ), - 'google_pay' => array( - 'title' => __('Google Pay', 'woocommerce-paypal-payments'), - 'description' => __('Let customers pay using their Google Pay wallet.', 'woocommerce-paypal-payments'), - 'isEligible' => $eligibility_checks['google_pay'], - 'buttons' => array( + 'google_pay' => array( + 'title' => __( 'Google Pay', 'woocommerce-paypal-payments' ), + 'description' => __( 'Let customers pay using their Google Pay wallet.', 'woocommerce-paypal-payments' ), + 'isEligible' => $eligibility_checks['google_pay'], + 'buttons' => array( array( - 'type' => 'secondary', - 'text' => __('Configure', 'woocommerce-paypal-payments'), - 'action' => array( - 'type' => 'tab', - 'tab' => 'payment_methods', + 'type' => 'secondary', + 'text' => __( 'Configure', 'woocommerce-paypal-payments' ), + 'action' => array( + 'type' => 'tab', + 'tab' => 'payment_methods', 'section' => 'ppcp-card-payments-card', - 'modal' => 'ppcp-googlepay', + 'modal' => 'ppcp-googlepay', ), 'showWhen' => 'enabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'secondary', - 'text' => __('Sign up', 'woocommerce-paypal-payments'), - 'urls' => array( + 'type' => 'secondary', + 'text' => __( 'Sign up', 'woocommerce-paypal-payments' ), + 'urls' => array( 'sandbox' => 'https://www.sandbox.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=GOOGLE_PAY', - 'live' => 'https://www.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=GOOGLE_PAY', + 'live' => 'https://www.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=GOOGLE_PAY', ), 'showWhen' => 'disabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'tertiary', - 'text' => __('Learn more', 'woocommerce-paypal-payments'), - 'url' => 'https://developer.paypal.com/docs/checkout/apm/google-pay/', + 'type' => 'tertiary', + 'text' => __( 'Learn more', 'woocommerce-paypal-payments' ), + 'url' => 'https://developer.paypal.com/docs/checkout/apm/google-pay/', 'class' => 'small-button', ), ), - 'notes' => array( - __('¹PayPal Q2 Earnings-2021.', 'woocommerce-paypal-payments'), + 'notes' => array( + __( '¹PayPal Q2 Earnings-2021.', 'woocommerce-paypal-payments' ), ), ), - 'apple_pay' => array( - 'title' => __('Apple Pay', 'woocommerce-paypal-payments'), - 'description' => __('Let customers pay using their Apple Pay wallet.', 'woocommerce-paypal-payments'), - 'isEligible' => $eligibility_checks['apple_pay'], - 'buttons' => array( + 'apple_pay' => array( + 'title' => __( 'Apple Pay', 'woocommerce-paypal-payments' ), + 'description' => __( 'Let customers pay using their Apple Pay wallet.', 'woocommerce-paypal-payments' ), + 'isEligible' => $eligibility_checks['apple_pay'], + 'buttons' => array( array( - 'type' => 'secondary', - 'text' => __('Configure', 'woocommerce-paypal-payments'), - 'action' => array( - 'type' => 'tab', - 'tab' => 'payment_methods', + 'type' => 'secondary', + 'text' => __( 'Configure', 'woocommerce-paypal-payments' ), + 'action' => array( + 'type' => 'tab', + 'tab' => 'payment_methods', 'section' => 'ppcp-card-payments-card', - 'modal' => 'ppcp-applepay', + 'modal' => 'ppcp-applepay', ), 'showWhen' => 'enabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'secondary', - 'text' => __('Domain registration', 'woocommerce-paypal-payments'), - 'urls' => array( + 'type' => 'secondary', + 'text' => __( 'Domain registration', 'woocommerce-paypal-payments' ), + 'urls' => array( 'sandbox' => 'https://www.sandbox.paypal.com/uccservicing/apm/applepay', - 'live' => 'https://www.paypal.com/uccservicing/apm/applepay', + 'live' => 'https://www.paypal.com/uccservicing/apm/applepay', ), 'showWhen' => 'enabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'secondary', - 'text' => __('Sign up', 'woocommerce-paypal-payments'), - 'urls' => array( + 'type' => 'secondary', + 'text' => __( 'Sign up', 'woocommerce-paypal-payments' ), + 'urls' => array( 'sandbox' => 'https://www.sandbox.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=APPLE_PAY', - 'live' => 'https://www.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=APPLE_PAY', + 'live' => 'https://www.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=APPLE_PAY', ), 'showWhen' => 'disabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'tertiary', - 'text' => __('Learn more', 'woocommerce-paypal-payments'), - 'url' => 'https://developer.paypal.com/docs/checkout/apm/apple-pay/', + 'type' => 'tertiary', + 'text' => __( 'Learn more', 'woocommerce-paypal-payments' ), + 'url' => 'https://developer.paypal.com/docs/checkout/apm/apple-pay/', 'class' => 'small-button', ), ), ), - 'pay_later' => array( - 'title' => __('Pay Later Messaging', 'woocommerce-paypal-payments'), + 'pay_later' => array( + 'title' => __( 'Pay Later Messaging', 'woocommerce-paypal-payments' ), 'description' => __( 'Let customers know they can buy now and pay later with PayPal. Adding this messaging can boost conversion rates and increase cart sizes by 39%¹, with no extra cost to you—plus, you get paid up front.', 'woocommerce-paypal-payments' ), - 'isEligible' => $eligibility_checks['pay_later'], - 'buttons' => array( + 'isEligible' => $eligibility_checks['pay_later'], + 'buttons' => array( array( - 'type' => 'secondary', - 'text' => __('Configure', 'woocommerce-paypal-payments'), - 'action' => array( + 'type' => 'secondary', + 'text' => __( 'Configure', 'woocommerce-paypal-payments' ), + 'action' => array( 'type' => 'tab', 'tab' => 'pay_later_messaging', ), 'showWhen' => 'enabled', - 'class' => 'small-button', + 'class' => 'small-button', ), array( - 'type' => 'tertiary', - 'text' => __('Learn more', 'woocommerce-paypal-payments'), - 'url' => "https://www.paypal.com/$countryLocation/business/accept-payments/checkout/installments", + 'type' => 'tertiary', + 'text' => __( 'Learn more', 'woocommerce-paypal-payments' ), + 'url' => "https://www.paypal.com/{$country_location}/business/accept-payments/checkout/installments", 'class' => 'small-button', ), ), diff --git a/modules/ppcp-settings/src/Endpoint/FeaturesRestEndpoint.php b/modules/ppcp-settings/src/Endpoint/FeaturesRestEndpoint.php index 6112a2804..6bb486fb9 100644 --- a/modules/ppcp-settings/src/Endpoint/FeaturesRestEndpoint.php +++ b/modules/ppcp-settings/src/Endpoint/FeaturesRestEndpoint.php @@ -1,9 +1,8 @@ features_definition->get() as $id => $feature ) { - // Check eligibility and add to features if eligible. - if ( $feature['isEligible']() ) { - $features[] = array_merge( - array( 'id' => $id ), - array_diff_key( $feature, array( 'isEligible' => true ) ) - ); + // Evaluate eligibility check. + if ( is_callable( $feature['isEligible'] ) ) { + $is_eligible = $feature['isEligible'](); + } else { + $is_eligible = (bool) $feature['isEligible']; } + + // Include all features with their eligibility state. + $features[] = array_merge( + array( 'id' => $id ), + array_diff_key( $feature, array( 'isEligible' => true ) ), + array( 'isEligible' => $is_eligible ) + ); } return $this->return_success( diff --git a/modules/ppcp-settings/src/Service/FeaturesEligibilityService.php b/modules/ppcp-settings/src/Service/FeaturesEligibilityService.php index 3475487df..9f3fe4db7 100644 --- a/modules/ppcp-settings/src/Service/FeaturesEligibilityService.php +++ b/modules/ppcp-settings/src/Service/FeaturesEligibilityService.php @@ -77,12 +77,12 @@ class FeaturesEligibilityService { bool $is_apple_pay_eligible, bool $is_pay_later_eligible ) { - $this->is_save_paypal_and_venmo_eligible = $is_save_paypal_and_venmo_eligible; - $this->is_advanced_credit_and_debit_cards_eligible = $is_advanced_credit_and_debit_cards_eligible; - $this->is_alternative_payment_methods_eligible = $is_alternative_payment_methods_eligible; - $this->is_google_pay_eligible = $is_google_pay_eligible; - $this->is_apple_pay_eligible = $is_apple_pay_eligible; - $this->is_pay_later_eligible = $is_pay_later_eligible; + $this->is_save_paypal_and_venmo_eligible = $is_save_paypal_and_venmo_eligible; + $this->is_advanced_credit_and_debit_cards_eligible = $is_advanced_credit_and_debit_cards_eligible; + $this->is_alternative_payment_methods_eligible = $is_alternative_payment_methods_eligible; + $this->is_google_pay_eligible = $is_google_pay_eligible; + $this->is_apple_pay_eligible = $is_apple_pay_eligible; + $this->is_pay_later_eligible = $is_pay_later_eligible; } /** @@ -92,12 +92,12 @@ class FeaturesEligibilityService { */ public function get_eligibility_checks(): array { return array( - 'save_paypal_and_venmo' => fn() => $this->is_save_paypal_and_venmo_eligible, - 'advanced_credit_and_debit_cards' => fn() => $this->is_advanced_credit_and_debit_cards_eligible, - 'alternative_payment_methods' => fn() => $this->is_alternative_payment_methods_eligible, - 'google_pay' => fn() => $this->is_google_pay_eligible, - 'apple_pay' => fn() => $this->is_apple_pay_eligible, - 'pay_later' => fn() => $this->is_pay_later_eligible, + 'save_paypal_and_venmo' => fn() => $this->is_save_paypal_and_venmo_eligible, + 'advanced_credit_and_debit_cards' => fn() => $this->is_advanced_credit_and_debit_cards_eligible, + 'alternative_payment_methods' => fn() => $this->is_alternative_payment_methods_eligible, + 'google_pay' => fn() => $this->is_google_pay_eligible, + 'apple_pay' => fn() => $this->is_apple_pay_eligible, + 'pay_later' => fn() => $this->is_pay_later_eligible, ); } }