diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_settings-card.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_settings-card.scss index 441cf4608..30826351f 100644 --- a/modules/ppcp-settings/resources/css/components/reusable-components/_settings-card.scss +++ b/modules/ppcp-settings/resources/css/components/reusable-components/_settings-card.scss @@ -69,4 +69,17 @@ $width_gap: 24px; color: var(--color-text-teriary); margin: 0; } + + .ppcp--card-actions { + opacity: 0.5; + transition: opacity 0.3s; + + &:hover { + opacity: 1; + } + + .components-button.is-tertiary:first-child { + padding-left: 0; + } + } } diff --git a/modules/ppcp-settings/resources/css/components/screens/_modals.scss b/modules/ppcp-settings/resources/css/components/screens/_modals.scss new file mode 100644 index 000000000..fee98d538 --- /dev/null +++ b/modules/ppcp-settings/resources/css/components/screens/_modals.scss @@ -0,0 +1,13 @@ +/** + * Modal for disconnecting the merchant from the current PayPal account. + */ +.ppcp--modal-disconnect { + .ppcp--toggle-danger { + --wp-components-color-accent: #cc1818 + } + + .ppcp--action-buttons { + text-align: right; + margin-top: 32px; + } +} diff --git a/modules/ppcp-settings/resources/css/style.scss b/modules/ppcp-settings/resources/css/style.scss index 0875dcad5..d70b4533f 100644 --- a/modules/ppcp-settings/resources/css/style.scss +++ b/modules/ppcp-settings/resources/css/style.scss @@ -11,3 +11,4 @@ @import './components/reusable-components/payment-method-modal'; @import './components/screens/fullscreen'; +@import './components/screens/modals'; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Settings/ConnectionStatus.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Settings/ConnectionStatus.js index 5ddc31a7c..341f11a3d 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Settings/ConnectionStatus.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Settings/ConnectionStatus.js @@ -59,7 +59,9 @@ const ConnectionDescription = () => { 'Your PayPal account connection details.', 'woocommerce-paypal-payments' ) } - +
+ +
); }; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Settings/Parts/DisconnectButton.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Settings/Parts/DisconnectButton.js index aabdd2192..8e5fbe9d6 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Settings/Parts/DisconnectButton.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Settings/Components/Settings/Parts/DisconnectButton.js @@ -1,5 +1,5 @@ import { __ } from '@wordpress/i18n'; -import { Button, Modal } from '@wordpress/components'; +import { Button, Modal, ToggleControl } from '@wordpress/components'; import { useCallback, useState } from '@wordpress/element'; import { CommonHooks } from '../../../../../../data'; @@ -7,6 +7,7 @@ import { HStack } from '../../../../../ReusableComponents/Stack'; const DisconnectButton = () => { const [ isOpen, setIsOpen ] = useState( false ); + const [ resetFlag, setResetFlag ] = useState( false ); const { disconnectMerchant } = CommonHooks.useDisconnectMerchant(); const handleOpen = useCallback( () => { @@ -18,9 +19,9 @@ const DisconnectButton = () => { }, [] ); const handleConfirm = useCallback( async () => { - await disconnectMerchant(); + await disconnectMerchant( resetFlag ); window.location.reload(); - }, [ disconnectMerchant ] ); + }, [ disconnectMerchant, resetFlag ] ); const confirmationTitle = __( 'Disconnect from PayPal?', @@ -39,6 +40,7 @@ const DisconnectButton = () => { { isOpen && ( { 'woocommerce-paypal-payments' ) }

- + + diff --git a/modules/ppcp-settings/resources/js/data/common/actions-thunk.js b/modules/ppcp-settings/resources/js/data/common/actions-thunk.js index 0de08f245..8e7448af8 100644 --- a/modules/ppcp-settings/resources/js/data/common/actions-thunk.js +++ b/modules/ppcp-settings/resources/js/data/common/actions-thunk.js @@ -153,13 +153,17 @@ export function authenticateWithOAuth( sharedId, authCode, useSandbox ) { /** * Side effect. Checks webhook simulation. * + * @param {boolean} fullReset When true, all plugin settings are reset to initial values. * @return {Function} The thunk function. */ -export function disconnectMerchant() { +export function disconnectMerchant( fullReset = false ) { return async () => { return await apiFetch( { path: REST_DISCONNECT_MERCHANT_PATH, method: 'POST', + data: { + reset: fullReset, + }, } ); }; } diff --git a/modules/ppcp-settings/services.php b/modules/ppcp-settings/services.php index 9381fee1b..e5ab98d74 100644 --- a/modules/ppcp-settings/services.php +++ b/modules/ppcp-settings/services.php @@ -38,6 +38,7 @@ use WooCommerce\PayPalCommerce\Settings\Service\OnboardingUrlManager; use WooCommerce\PayPalCommerce\Settings\Service\TodosEligibilityService; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\Settings\Service\DataSanitizer; +use WooCommerce\PayPalCommerce\Settings\Service\SettingsDataManager; return array( 'settings.url' => static function ( ContainerInterface $container ) : string { @@ -122,9 +123,10 @@ return array( $container->get( 'woocommerce.logger.woocommerce' ) ); }, - 'settings.rest.connect_manual' => static function ( ContainerInterface $container ) : AuthenticationRestEndpoint { + 'settings.rest.authentication' => static function ( ContainerInterface $container ) : AuthenticationRestEndpoint { return new AuthenticationRestEndpoint( $container->get( 'settings.service.authentication_manager' ), + $container->get( 'settings.service.data-manager' ) ); }, 'settings.rest.login_link' => static function ( ContainerInterface $container ) : LoginLinkRestEndpoint { @@ -246,6 +248,19 @@ return array( 'settings.service.sanitizer' => static function ( ContainerInterface $container ) : DataSanitizer { return new DataSanitizer(); }, + 'settings.service.data-manager' => static function ( ContainerInterface $container ) : SettingsDataManager { + $models = array( + $container->get( 'settings.data.onboarding' ), + $container->get( 'settings.data.general' ), + $container->get( 'settings.data.styling' ), + $container->get( 'settings.data.payment' ), + $container->get( 'settings.data.settings' ), + $container->get( 'settings.data.todos' ), + $container->get( 'settings.data.definition.todos' ), + ); + + return new SettingsDataManager( $models ); + }, 'settings.ajax.switch_ui' => static function ( ContainerInterface $container ) : SwitchSettingsUiEndpoint { return new SwitchSettingsUiEndpoint( $container->get( 'woocommerce.logger.woocommerce' ), @@ -270,14 +285,14 @@ return array( $container->get( 'settings.data.general' ) ); }, - 'settings.service.todos_eligibilities' => static function( ContainerInterface $container ): TodosEligibilityService { + 'settings.service.todos_eligibilities' => static function ( ContainerInterface $container ) : TodosEligibilityService { $features = apply_filters( 'woocommerce_paypal_payments_rest_common_merchant_features', array() ); $payment_endpoint = $container->get( 'settings.rest.payment' ); - $settings = $payment_endpoint->get_details()->get_data(); + $settings = $payment_endpoint->get_details()->get_data(); $pay_later_endpoint = $container->get( 'settings.rest.pay_later_messaging' ); $pay_later_settings = $pay_later_endpoint->get_details()->get_data(); @@ -312,20 +327,20 @@ return array( $is_pay_later_messaging_enabled_for_any_location = ! array_filter( $pay_later_statuses ); return new TodosEligibilityService( - $capabilities['acdc'] && ! $gateways['axo'], // Enable Fastlane. - $capabilities['acdc'] && ! $gateways['card-button'], // Enable Credit and Debit Cards on your checkout. - $is_pay_later_messaging_enabled_for_any_location, // Enable Pay Later messaging. - ! $is_pay_later_messaging_enabled_for_any_location && ! $pay_later_statuses['product'], // Add Pay Later messaging (Product page). - ! $is_pay_later_messaging_enabled_for_any_location && ! $pay_later_statuses['cart'], // Add Pay Later messaging (Cart). - ! $is_pay_later_messaging_enabled_for_any_location && ! $pay_later_statuses['checkout'], // Add Pay Later messaging (Checkout). - true, // Configure a PayPal Subscription. - true, // Add PayPal buttons. - true, // Register Domain for Apple Pay. + $capabilities['acdc'] && ! $gateways['axo'], // Enable Fastlane. + $capabilities['acdc'] && ! $gateways['card-button'], // Enable Credit and Debit Cards on your checkout. + $is_pay_later_messaging_enabled_for_any_location, // Enable Pay Later messaging. + ! $is_pay_later_messaging_enabled_for_any_location && ! $pay_later_statuses['product'], // Add Pay Later messaging (Product page). + ! $is_pay_later_messaging_enabled_for_any_location && ! $pay_later_statuses['cart'], // Add Pay Later messaging (Cart). + ! $is_pay_later_messaging_enabled_for_any_location && ! $pay_later_statuses['checkout'], // Add Pay Later messaging (Checkout). + true, // Configure a PayPal Subscription. + true, // Add PayPal buttons. + true, // Register Domain for Apple Pay. $capabilities['acdc'] && ! ( $capabilities['apple_pay'] && $capabilities['google_pay'] ), // Add digital wallets to your account. - $capabilities['acdc'] && ! $capabilities['apple_pay'], // Add Apple Pay to your account. - $capabilities['acdc'] && ! $capabilities['google_pay'], // Add Google Pay to your account. - true, // Configure a PayPal Subscription. - $capabilities['apple_pay'] && ! $gateways['apple_pay'], // Enable Apple Pay. + $capabilities['acdc'] && ! $capabilities['apple_pay'], // Add Apple Pay to your account. + $capabilities['acdc'] && ! $capabilities['google_pay'], // Add Google Pay to your account. + true, // Configure a PayPal Subscription. + $capabilities['apple_pay'] && ! $gateways['apple_pay'], // Enable Apple Pay. $capabilities['google_pay'] && ! $gateways['google_pay'], // Enable Google Pay. ); }, diff --git a/modules/ppcp-settings/src/Data/AbstractDataModel.php b/modules/ppcp-settings/src/Data/AbstractDataModel.php index 070015af2..13c3d1ddd 100644 --- a/modules/ppcp-settings/src/Data/AbstractDataModel.php +++ b/modules/ppcp-settings/src/Data/AbstractDataModel.php @@ -69,6 +69,13 @@ abstract class AbstractDataModel { update_option( static::OPTION_KEY, $this->data ); } + /** + * Deletes the settings entry from the WordPress database. + */ + public function purge() : void { + delete_option( static::OPTION_KEY ); + } + /** * Gets all model data as an array. * diff --git a/modules/ppcp-settings/src/Endpoint/AuthenticationRestEndpoint.php b/modules/ppcp-settings/src/Endpoint/AuthenticationRestEndpoint.php index 55a3b8353..d6499270b 100644 --- a/modules/ppcp-settings/src/Endpoint/AuthenticationRestEndpoint.php +++ b/modules/ppcp-settings/src/Endpoint/AuthenticationRestEndpoint.php @@ -14,6 +14,7 @@ use WP_REST_Request; use WP_REST_Response; use WP_REST_Server; use WooCommerce\PayPalCommerce\Settings\Service\AuthenticationManager; +use WooCommerce\PayPalCommerce\Settings\Service\SettingsDataManager; /** * REST controller for authenticating and connecting to a PayPal merchant account. @@ -40,6 +41,13 @@ class AuthenticationRestEndpoint extends RestEndpoint { */ private AuthenticationManager $authentication_manager; + /** + * Settings data manager service. + * + * @var SettingsDataManager + */ + private SettingsDataManager $data_manager; + /** * Defines the JSON response format (when connection was successful). * @@ -58,9 +66,12 @@ class AuthenticationRestEndpoint extends RestEndpoint { * Constructor. * * @param AuthenticationManager $authentication_manager The authentication manager. + * @param SettingsDataManager $data_manager Settings data manager, to reset + * settings. */ - public function __construct( AuthenticationManager $authentication_manager ) { + public function __construct( AuthenticationManager $authentication_manager, SettingsDataManager $data_manager ) { $this->authentication_manager = $authentication_manager; + $this->data_manager = $data_manager; } /** @@ -209,11 +220,19 @@ class AuthenticationRestEndpoint extends RestEndpoint { /** * Disconnect the merchant and clear the authentication details. * + * @param WP_REST_Request $request Full data about the request. + * * @return WP_REST_Response */ - public function disconnect() : WP_REST_Response { + public function disconnect( WP_REST_Request $request ) : WP_REST_Response { + $reset_settings = $request->get_param( 'reset' ); + $this->authentication_manager->disconnect(); + if ( $reset_settings ) { + $this->data_manager->reset_all_settings(); + } + return $this->return_success( 'OK' ); } } diff --git a/modules/ppcp-settings/src/Service/SettingsDataManager.php b/modules/ppcp-settings/src/Service/SettingsDataManager.php new file mode 100644 index 000000000..cb7aa6275 --- /dev/null +++ b/modules/ppcp-settings/src/Service/SettingsDataManager.php @@ -0,0 +1,62 @@ +models[] = $data_model; + } + } + } + + /** + * Completely purges all settings from the DB. + * + * @return void + */ + public function reset_all_settings() : void { + /** + * Broadcast the settings-reset event to allow other modules to perform + * cleanup tasks, if needed. + */ + do_action( 'woocommerce_paypal_payments_reset_settings' ); + + foreach ( $this->models as $model ) { + $model->purge(); + } + + // Clear any caches. + wp_cache_flush(); + } +} diff --git a/modules/ppcp-settings/src/SettingsModule.php b/modules/ppcp-settings/src/SettingsModule.php index 707f55e24..2035011d6 100644 --- a/modules/ppcp-settings/src/SettingsModule.php +++ b/modules/ppcp-settings/src/SettingsModule.php @@ -232,7 +232,7 @@ class SettingsModule implements ServiceModule, ExecutableModule { $endpoints = array( 'onboarding' => $container->get( 'settings.rest.onboarding' ), 'common' => $container->get( 'settings.rest.common' ), - 'connect_manual' => $container->get( 'settings.rest.connect_manual' ), + 'connect_manual' => $container->get( 'settings.rest.authentication' ), 'login_link' => $container->get( 'settings.rest.login_link' ), 'webhooks' => $container->get( 'settings.rest.webhooks' ), 'refresh_feature_status' => $container->get( 'settings.rest.refresh_feature_status' ),