From af4c2b0905df93598c0bc9ee6e6105a9c8861124 Mon Sep 17 00:00:00 2001 From: inpsyde-maticluznar Date: Fri, 25 Oct 2024 06:45:01 +0200 Subject: [PATCH 1/7] Create dashboard container --- .../reusable-components/_settings-wrapper.scss | 4 +++- .../Components/ReusableComponents/Container.js | 17 +++++++++++++++-- .../Components/Screens/Dashboard/Dashboard.js | 6 ++++-- .../Components/Screens/Onboarding/Onboarding.js | 7 ++++--- .../resources/js/Components/Screens/Settings.js | 2 +- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss index c38fb5ae1..f98e8675c 100644 --- a/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss +++ b/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss @@ -9,9 +9,11 @@ } &-container { - box-shadow: $shadow-card; max-width: 1024px; margin: 0 auto; + &--settings{ + max-width: 938px; + } } &-card { diff --git a/modules/ppcp-settings/resources/js/Components/ReusableComponents/Container.js b/modules/ppcp-settings/resources/js/Components/ReusableComponents/Container.js index b52058d79..e6b83e691 100644 --- a/modules/ppcp-settings/resources/js/Components/ReusableComponents/Container.js +++ b/modules/ppcp-settings/resources/js/Components/ReusableComponents/Container.js @@ -1,5 +1,18 @@ -const Container = ( props ) => { - return
{ props.children }
; +export const PAGE_ONBOARDING = 'onboarding'; +export const PAGE_SETTINGS = 'settings'; + +const Container = ( { isCard = true, page, children } ) => { + let className = 'ppcp-r-container'; + + if ( isCard ) { + className += ' ppcp-r-container--card'; + } + + if ( page ) { + className += ` ppcp-r-container--${ page }`; + } + + return
{ children }
; }; export default Container; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/Dashboard.js b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/Dashboard.js index 62dd76cf6..ed5954762 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/Dashboard.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/Dashboard.js @@ -1,10 +1,12 @@ import TabNavigation from '../../ReusableComponents/TabNavigation'; +import Container from '../../ReusableComponents/Container'; +import { PAGE_SETTINGS } from '../../ReusableComponents/Container'; const Dashboard = () => { return ( -
+ -
+ ); }; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/Onboarding.js b/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/Onboarding.js index f2f78246e..767f1c304 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/Onboarding.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/Onboarding.js @@ -1,15 +1,16 @@ -import Container from '../../ReusableComponents/Container.js'; +import Container, { + PAGE_ONBOARDING, +} from '../../ReusableComponents/Container.js'; import StepWelcome from './StepWelcome.js'; import StepBusiness from './StepBusiness.js'; import StepProducts from './StepProducts.js'; import { useState } from '@wordpress/element'; -import Dashboard from '../Dashboard/Dashboard'; const Onboarding = () => { const [ step, setStep ] = useState( 0 ); return ( - +
diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings.js index ee112096d..562d8d9b4 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Settings.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Settings.js @@ -5,7 +5,7 @@ import Dashboard from './Dashboard/Dashboard'; const Settings = () => { const [ onboarded, setOnboarded ] = useState( true ); - return <>{ onboarded ? : }; + return <>{ onboarded ? : }; }; export default Settings; From cc3e52046b9168a441157704faaea7f3c9d7f72d Mon Sep 17 00:00:00 2001 From: Philipp Stracker Date: Fri, 25 Oct 2024 12:34:15 +0200 Subject: [PATCH 2/7] =?UTF-8?q?=F0=9F=A7=90=20Add=20console=20tool=20to=20?= =?UTF-8?q?dump=20the=20store=20contents?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ppcp-settings/resources/js/data/store.js | 19 +++++++++++++++++++ modules/ppcp-settings/src/SettingsModule.php | 1 + 2 files changed, 20 insertions(+) diff --git a/modules/ppcp-settings/resources/js/data/store.js b/modules/ppcp-settings/resources/js/data/store.js index f5a1a4b13..f416cb94f 100644 --- a/modules/ppcp-settings/resources/js/data/store.js +++ b/modules/ppcp-settings/resources/js/data/store.js @@ -27,4 +27,23 @@ export const initStore = () => { } ); register( store ); + + /* eslint-disable no-console */ + // Provide a debug tool to inspect the Redux store via the JS console. + if ( window.ppcpSettings?.debug && console?.groupCollapsed ) { + window.ppcpSettings.dumpStore = () => { + const storeSelector = `wp.data.select('${ STORE_NAME }')`; + console.group( `[STORE] ${ storeSelector }` ); + + const storeState = wp.data.select( STORE_NAME ); + Object.keys( selectors ).forEach( ( selector ) => { + console.groupCollapsed( `[SELECTOR] .${ selector }()` ); + console.table( storeState[ selector ]() ); + console.groupEnd(); + } ); + + console.groupEnd(); + }; + } + /* eslint-enable no-console */ }; diff --git a/modules/ppcp-settings/src/SettingsModule.php b/modules/ppcp-settings/src/SettingsModule.php index fdc286521..3533c2394 100644 --- a/modules/ppcp-settings/src/SettingsModule.php +++ b/modules/ppcp-settings/src/SettingsModule.php @@ -86,6 +86,7 @@ class SettingsModule implements ServiceModule, ExecutableModule { 'assets' => array( 'imagesUrl' => $module_url . '/images/', ), + 'debug' => defined( 'WP_DEBUG' ) && WP_DEBUG, ) ); } From 3c577c8b2d78823edf93c0c22eab20fc5fc2edd2 Mon Sep 17 00:00:00 2001 From: Philipp Stracker Date: Fri, 25 Oct 2024 13:01:01 +0200 Subject: [PATCH 3/7] =?UTF-8?q?=E2=9C=A8=20Add=20new=20eligibility=20flags?= =?UTF-8?q?=20to=20Redux=20store?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/js/data/onboarding/reducer.js | 3 + .../src/Data/OnboardingProfile.php | 57 +++++++++++++++++++ .../src/Endpoint/OnboardingRestEndpoint.php | 22 +++++-- 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/modules/ppcp-settings/resources/js/data/onboarding/reducer.js b/modules/ppcp-settings/resources/js/data/onboarding/reducer.js index 954801995..e37d145b0 100644 --- a/modules/ppcp-settings/resources/js/data/onboarding/reducer.js +++ b/modules/ppcp-settings/resources/js/data/onboarding/reducer.js @@ -8,6 +8,9 @@ const defaultState = { useManualConnection: false, clientId: '', clientSecret: '', + canUseCasualSelling: false, + canUseVaulting: false, + canUseCardPayments: false, }, }; diff --git a/modules/ppcp-settings/src/Data/OnboardingProfile.php b/modules/ppcp-settings/src/Data/OnboardingProfile.php index 9cfd29d46..a59960af7 100644 --- a/modules/ppcp-settings/src/Data/OnboardingProfile.php +++ b/modules/ppcp-settings/src/Data/OnboardingProfile.php @@ -37,6 +37,9 @@ class OnboardingProfile extends AbstractDataModel { 'use_manual_connection' => false, 'client_id' => '', 'client_secret' => '', + 'can_use_casual_selling' => false, + 'can_use_vaulting' => false, + 'can_use_card_payments' => false, ); } @@ -131,4 +134,58 @@ class OnboardingProfile extends AbstractDataModel { public function set_client_secret( string $client_secret ) : void { $this->data['client_secret'] = sanitize_text_field( $client_secret ); } + + /** + * Gets whether casual selling can be used. + * + * @return bool + */ + public function get_can_use_casual_selling() : bool { + return (bool) $this->data['can_use_casual_selling']; + } + + /** + * Sets whether casual selling can be used. + * + * @param bool $can_use_casual_selling Whether casual selling can be used. + */ + public function set_can_use_casual_selling( bool $can_use_casual_selling ) : void { + $this->data['can_use_casual_selling'] = $can_use_casual_selling; + } + + /** + * Gets whether vaulting can be used. + * + * @return bool + */ + public function get_can_use_vaulting() : bool { + return (bool) $this->data['can_use_vaulting']; + } + + /** + * Sets whether vaulting can be used. + * + * @param bool $can_use_vaulting Whether vaulting can be used. + */ + public function set_can_use_vaulting( bool $can_use_vaulting ) : void { + $this->data['can_use_vaulting'] = $can_use_vaulting; + } + + /** + * Gets whether Credit Card payments can be used. + * + * @return bool + */ + public function get_can_use_card_payments() : bool { + return (bool) $this->data['can_use_card_payments']; + } + + /** + * Sets whether Credit Card payments can be used. + * + * @param bool $can_use_card_payments Whether Credit Card payments can be used. + */ + public function set_can_use_card_payments( bool $can_use_card_payments ) : void { + $this->data['can_use_card_payments'] = $can_use_card_payments; + } } diff --git a/modules/ppcp-settings/src/Endpoint/OnboardingRestEndpoint.php b/modules/ppcp-settings/src/Endpoint/OnboardingRestEndpoint.php index dd8f19e67..eff234218 100644 --- a/modules/ppcp-settings/src/Endpoint/OnboardingRestEndpoint.php +++ b/modules/ppcp-settings/src/Endpoint/OnboardingRestEndpoint.php @@ -41,26 +41,38 @@ class OnboardingRestEndpoint extends RestEndpoint { * @var array */ private array $field_map = array( - 'step' => array( + 'step' => array( 'js_name' => 'step', 'sanitize' => 'to_number', ), - 'use_sandbox' => array( + 'use_sandbox' => array( 'js_name' => 'useSandbox', 'sanitize' => 'to_boolean', ), - 'use_manual_connection' => array( + 'use_manual_connection' => array( 'js_name' => 'useManualConnection', 'sanitize' => 'to_boolean', ), - 'client_id' => array( + 'client_id' => array( 'js_name' => 'clientId', 'sanitize' => 'sanitize_text_field', ), - 'client_secret' => array( + 'client_secret' => array( 'js_name' => 'clientSecret', 'sanitize' => 'sanitize_text_field', ), + 'can_use_casual_selling' => array( + 'js_name' => 'canUseCasualSelling', + 'sanitize' => 'to_boolean', + ), + 'can_use_vaulting' => array( + 'js_name' => 'canUseVaulting', + 'sanitize' => 'to_boolean', + ), + 'can_use_card_payments' => array( + 'js_name' => 'canUseCardPayments', + 'sanitize' => 'to_boolean', + ), ); /** From 7b596dbea5cda723ba1c9a895ab9f5b4191b8075 Mon Sep 17 00:00:00 2001 From: Philipp Stracker Date: Fri, 25 Oct 2024 13:02:22 +0200 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=91=94=20Resolve=20eligibility=20flag?= =?UTF-8?q?s=20on=20server=20side?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/ppcp-settings/services.php | 15 ++++++- .../src/Data/OnboardingProfile.php | 39 +++++++++++++++---- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/modules/ppcp-settings/services.php b/modules/ppcp-settings/services.php index c8bb64144..f34257f79 100644 --- a/modules/ppcp-settings/services.php +++ b/modules/ppcp-settings/services.php @@ -26,7 +26,20 @@ return array( ); }, 'settings.data.onboarding' => static function ( ContainerInterface $container ) : OnboardingProfile { - return new OnboardingProfile(); + $can_use_casual_selling = false; + $can_use_vaulting = $container->has( 'save-payment-methods.eligible' ) && $container->get( 'save-payment-methods.eligible' ); + $can_use_card_payments = $container->has( 'card-fields.eligible' ) && $container->get( 'card-fields.eligible' ); + + // Card payments are disabled for this plugin when WooPayments is active. + if ( class_exists( '\WC_Payments' ) ) { + $can_use_card_payments = false; + } + + return new OnboardingProfile( + $can_use_casual_selling, + $can_use_vaulting, + $can_use_card_payments + ); }, 'settings.rest.onboarding' => static function ( ContainerInterface $container ) : OnboardingRestEndpoint { return new OnboardingRestEndpoint( $container->get( 'settings.data.onboarding' ) ); diff --git a/modules/ppcp-settings/src/Data/OnboardingProfile.php b/modules/ppcp-settings/src/Data/OnboardingProfile.php index a59960af7..c30dd7301 100644 --- a/modules/ppcp-settings/src/Data/OnboardingProfile.php +++ b/modules/ppcp-settings/src/Data/OnboardingProfile.php @@ -9,12 +9,16 @@ declare( strict_types = 1 ); namespace WooCommerce\PayPalCommerce\Settings\Data; +use RuntimeException; + /** * Class OnboardingProfile * * This class serves as a container for managing the onboarding profile details - * within the WooCommerce PayPal Commerce plugin. It provides methods to retrieve - * and save the onboarding profile data using WordPress options. + * within the WooCommerce PayPal Commerce plugin. + * + * This profile impacts the onboarding wizard and help to apply default + * settings. The details here should not be used outside the onboarding process. */ class OnboardingProfile extends AbstractDataModel { @@ -25,6 +29,27 @@ class OnboardingProfile extends AbstractDataModel { */ protected const OPTION_KEY = 'woocommerce-ppcp-data-onboarding'; + /** + * Constructor. + * + * @param bool $can_use_casual_selling Whether casual selling is enabled in the store's country. + * @param bool $can_use_vaulting Whether vaulting is enabled in the store's country. + * @param bool $can_use_card_payments Whether credit card payments are possible. + * + * @throws RuntimeException If the OPTION_KEY is not defined in the child class. + */ + public function __construct( + bool $can_use_casual_selling = false, + bool $can_use_vaulting = false, + bool $can_use_card_payments = false + ) { + parent::__construct(); + + $this->set_can_use_casual_selling( $can_use_casual_selling ); + $this->set_can_use_vaulting( $can_use_vaulting ); + $this->set_can_use_card_payments( $can_use_card_payments ); + } + /** * Get default values for the model. * @@ -32,11 +57,11 @@ class OnboardingProfile extends AbstractDataModel { */ protected function get_defaults() : array { return array( - 'step' => 0, - 'use_sandbox' => false, - 'use_manual_connection' => false, - 'client_id' => '', - 'client_secret' => '', + 'step' => 0, + 'use_sandbox' => false, + 'use_manual_connection' => false, + 'client_id' => '', + 'client_secret' => '', 'can_use_casual_selling' => false, 'can_use_vaulting' => false, 'can_use_card_payments' => false, From 3b274d02afba616a23b3d2718048791aa7caabcb Mon Sep 17 00:00:00 2001 From: Philipp Stracker Date: Fri, 25 Oct 2024 13:29:21 +0200 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=91=94=20Make=20eligibility=20flags?= =?UTF-8?q?=20read-only?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Data/AbstractDataModel.php | 7 ++-- .../src/Data/OnboardingProfile.php | 39 +++---------------- .../src/Endpoint/OnboardingRestEndpoint.php | 6 +-- .../src/Endpoint/RestEndpoint.php | 7 +++- 4 files changed, 17 insertions(+), 42 deletions(-) diff --git a/modules/ppcp-settings/src/Data/AbstractDataModel.php b/modules/ppcp-settings/src/Data/AbstractDataModel.php index d9cd0fbae..1d711cbe5 100644 --- a/modules/ppcp-settings/src/Data/AbstractDataModel.php +++ b/modules/ppcp-settings/src/Data/AbstractDataModel.php @@ -57,8 +57,9 @@ abstract class AbstractDataModel { * Loads the model data from WordPress options. */ public function load() : void { - $saved_data = get_option( static::OPTION_KEY, array() ); - $this->data = array_merge( $this->data, $saved_data ); + $saved_data = get_option( static::OPTION_KEY, array() ); + $filtered_data = array_intersect_key( $saved_data, $this->data ); + $this->data = array_merge( $this->data, $filtered_data ); } /** @@ -91,8 +92,6 @@ abstract class AbstractDataModel { $setter = "set_$key"; if ( method_exists( $this, $setter ) ) { $this->$setter( $value ); - } else { - $this->data[ $key ] = $value; } } } diff --git a/modules/ppcp-settings/src/Data/OnboardingProfile.php b/modules/ppcp-settings/src/Data/OnboardingProfile.php index c30dd7301..c9a45ead0 100644 --- a/modules/ppcp-settings/src/Data/OnboardingProfile.php +++ b/modules/ppcp-settings/src/Data/OnboardingProfile.php @@ -45,9 +45,9 @@ class OnboardingProfile extends AbstractDataModel { ) { parent::__construct(); - $this->set_can_use_casual_selling( $can_use_casual_selling ); - $this->set_can_use_vaulting( $can_use_vaulting ); - $this->set_can_use_card_payments( $can_use_card_payments ); + $this->data['can_use_casual_selling'] = $can_use_casual_selling; + $this->data['can_use_vaulting'] = $can_use_vaulting; + $this->data['can_use_card_payments'] = $can_use_card_payments; } /** @@ -62,9 +62,9 @@ class OnboardingProfile extends AbstractDataModel { 'use_manual_connection' => false, 'client_id' => '', 'client_secret' => '', - 'can_use_casual_selling' => false, - 'can_use_vaulting' => false, - 'can_use_card_payments' => false, + 'can_use_casual_selling' => null, + 'can_use_vaulting' => null, + 'can_use_card_payments' => null, ); } @@ -169,15 +169,6 @@ class OnboardingProfile extends AbstractDataModel { return (bool) $this->data['can_use_casual_selling']; } - /** - * Sets whether casual selling can be used. - * - * @param bool $can_use_casual_selling Whether casual selling can be used. - */ - public function set_can_use_casual_selling( bool $can_use_casual_selling ) : void { - $this->data['can_use_casual_selling'] = $can_use_casual_selling; - } - /** * Gets whether vaulting can be used. * @@ -187,15 +178,6 @@ class OnboardingProfile extends AbstractDataModel { return (bool) $this->data['can_use_vaulting']; } - /** - * Sets whether vaulting can be used. - * - * @param bool $can_use_vaulting Whether vaulting can be used. - */ - public function set_can_use_vaulting( bool $can_use_vaulting ) : void { - $this->data['can_use_vaulting'] = $can_use_vaulting; - } - /** * Gets whether Credit Card payments can be used. * @@ -204,13 +186,4 @@ class OnboardingProfile extends AbstractDataModel { public function get_can_use_card_payments() : bool { return (bool) $this->data['can_use_card_payments']; } - - /** - * Sets whether Credit Card payments can be used. - * - * @param bool $can_use_card_payments Whether Credit Card payments can be used. - */ - public function set_can_use_card_payments( bool $can_use_card_payments ) : void { - $this->data['can_use_card_payments'] = $can_use_card_payments; - } } diff --git a/modules/ppcp-settings/src/Endpoint/OnboardingRestEndpoint.php b/modules/ppcp-settings/src/Endpoint/OnboardingRestEndpoint.php index eff234218..e5a38af5d 100644 --- a/modules/ppcp-settings/src/Endpoint/OnboardingRestEndpoint.php +++ b/modules/ppcp-settings/src/Endpoint/OnboardingRestEndpoint.php @@ -63,15 +63,15 @@ class OnboardingRestEndpoint extends RestEndpoint { ), 'can_use_casual_selling' => array( 'js_name' => 'canUseCasualSelling', - 'sanitize' => 'to_boolean', + 'sanitize' => 'read_only', ), 'can_use_vaulting' => array( 'js_name' => 'canUseVaulting', - 'sanitize' => 'to_boolean', + 'sanitize' => 'read_only', ), 'can_use_card_payments' => array( 'js_name' => 'canUseCardPayments', - 'sanitize' => 'to_boolean', + 'sanitize' => 'read_only', ), ); diff --git a/modules/ppcp-settings/src/Endpoint/RestEndpoint.php b/modules/ppcp-settings/src/Endpoint/RestEndpoint.php index 63e543d59..9bb98dfac 100644 --- a/modules/ppcp-settings/src/Endpoint/RestEndpoint.php +++ b/modules/ppcp-settings/src/Endpoint/RestEndpoint.php @@ -53,7 +53,11 @@ class RestEndpoint extends WC_REST_Controller { $source_key = $details['js_name'] ?? ''; $sanitation_cb = $details['sanitize'] ?? null; - if ( ! $source_key || ! isset( $params[ $source_key ] ) ) { + if ( + ! $source_key + || ! isset( $params[ $source_key ] ) + || 'read_only' === $sanitation_cb + ) { continue; } @@ -121,5 +125,4 @@ class RestEndpoint extends WC_REST_Controller { protected function to_number( $value ) { return $value !== null ? ( is_numeric( $value ) ? $value + 0 : null ) : null; } - } From 2afc530af5c54fb596c44dc8bdf32b567df2a8e3 Mon Sep 17 00:00:00 2001 From: inpsyde-maticluznar Date: Fri, 25 Oct 2024 14:35:16 +0200 Subject: [PATCH 6/7] TODO implementation and partial status implementation on the dashobard page --- modules/ppcp-settings/images/icon-close.svg | 3 + .../images/icon-dashboard-list.svg | 9 + .../images/icon-dashboard-status.svg | 6 + .../images/icon-dashboard-support.svg | 9 + .../resources/css/_variables.scss | 2 + .../reusable-components/_button.scss | 13 +- .../reusable-components/_fields.scss | 43 +++ .../_settings-wrapper.scss | 33 +- .../components/reusable-components/_tabs.scss | 27 ++ .../screens/dashboard/_tab-dashboard.scss | 67 ++++ .../screens/onboarding/_step-welcome.scss | 7 + .../ppcp-settings/resources/css/style.scss | 3 + .../Components/ReusableComponents/Fields.js | 50 +++ .../ReusableComponents/SelectBox.js | 52 +--- .../ReusableComponents/SettingsCard.js | 29 ++ .../ReusableComponents/TabNavigation.js | 32 +- .../Screens/Dashboard/TabDashboard.js | 288 ++++++++++++++++++ .../Screens/Dashboard/TabPaymentMethods.js | 5 + .../Screens/Dashboard/TabSettings.js | 5 + .../Screens/Dashboard/TabStyling.js | 5 + .../Screens/Onboarding/StepWelcome.js | 4 +- .../js/Components/Screens/Settings.js | 1 - modules/ppcp-settings/webpack.config.js | 1 + 23 files changed, 636 insertions(+), 58 deletions(-) create mode 100644 modules/ppcp-settings/images/icon-close.svg create mode 100644 modules/ppcp-settings/images/icon-dashboard-list.svg create mode 100644 modules/ppcp-settings/images/icon-dashboard-status.svg create mode 100644 modules/ppcp-settings/images/icon-dashboard-support.svg create mode 100644 modules/ppcp-settings/resources/css/components/reusable-components/_fields.scss create mode 100644 modules/ppcp-settings/resources/css/components/reusable-components/_tabs.scss create mode 100644 modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss create mode 100644 modules/ppcp-settings/resources/js/Components/ReusableComponents/Fields.js create mode 100644 modules/ppcp-settings/resources/js/Components/ReusableComponents/SettingsCard.js create mode 100644 modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabDashboard.js create mode 100644 modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabPaymentMethods.js create mode 100644 modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabSettings.js create mode 100644 modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabStyling.js diff --git a/modules/ppcp-settings/images/icon-close.svg b/modules/ppcp-settings/images/icon-close.svg new file mode 100644 index 000000000..cfb1aef48 --- /dev/null +++ b/modules/ppcp-settings/images/icon-close.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ppcp-settings/images/icon-dashboard-list.svg b/modules/ppcp-settings/images/icon-dashboard-list.svg new file mode 100644 index 000000000..a9dcb265d --- /dev/null +++ b/modules/ppcp-settings/images/icon-dashboard-list.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/modules/ppcp-settings/images/icon-dashboard-status.svg b/modules/ppcp-settings/images/icon-dashboard-status.svg new file mode 100644 index 000000000..38a142a4c --- /dev/null +++ b/modules/ppcp-settings/images/icon-dashboard-status.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/modules/ppcp-settings/images/icon-dashboard-support.svg b/modules/ppcp-settings/images/icon-dashboard-support.svg new file mode 100644 index 000000000..b1dc452c4 --- /dev/null +++ b/modules/ppcp-settings/images/icon-dashboard-support.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/modules/ppcp-settings/resources/css/_variables.scss b/modules/ppcp-settings/resources/css/_variables.scss index 4e5f07bc5..072f22240 100644 --- a/modules/ppcp-settings/resources/css/_variables.scss +++ b/modules/ppcp-settings/resources/css/_variables.scss @@ -1,4 +1,5 @@ $color-white: #fff; +$color-black: #000; $color-blue: #1D35B4; $color-blueberry: #3858E9; $color-gray-900: #1E1E1E; @@ -6,6 +7,7 @@ $color-gray-800: #2F2F2F; $color-gray-700: #757575; $color-gray-600: #949494; $color-gray-500: #BBBBBB; +$color-gray-400: #CCCCCC; $color-gray-200: #E0E0E0; $color-gray: #646970; diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_button.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_button.scss index be4174a0a..844200970 100644 --- a/modules/ppcp-settings/resources/css/components/reusable-components/_button.scss +++ b/modules/ppcp-settings/resources/css/components/reusable-components/_button.scss @@ -24,11 +24,14 @@ button.components-button { @include font(13, 16, 500); } - &.is-secondary { - padding: 6px 12px; - @include font(13, 20, 500); - color: $color-white; - border: none; + &.is-secondary:not(:disabled) { + border-color:$color-blueberry; + background-color:$color-white; + color:$color-blueberry; + &:hover{ + background-color:$color-white; + background:none; + } } &.is-tertiary { diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_fields.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_fields.scss new file mode 100644 index 000000000..9f6274085 --- /dev/null +++ b/modules/ppcp-settings/resources/css/components/reusable-components/_fields.scss @@ -0,0 +1,43 @@ +.ppcp-r { + + &__radio-value { + @include hide-input-field; + + &:checked { + + .ppcp-r__radio-presentation { + background: $color-white; + width: 20px; + height: 20px; + border: 6px solid $color-blueberry; + } + } + } + + &__checkbox-value { + @include hide-input-field; + + &:not(:checked) + .ppcp-r__checkbox-presentation img { + display: none; + } + + &:checked { + + .ppcp-r__checkbox-presentation { + width: 20px; + height: 20px; + border: none; + + img { + border-radius: 2px; + } + } + } + } + + &__radio-presentation { + @include fake-input-field(20px); + } + + &__checkbox-presentation { + @include fake-input-field(2px); + } +} diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss index f98e8675c..5afc2940d 100644 --- a/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss +++ b/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss @@ -4,14 +4,15 @@ width: 652px; max-width: 100%; margin: 0 auto; - padding:0 16px; + padding: 0 16px; box-sizing: border-box; } &-container { max-width: 1024px; margin: 0 auto; - &--settings{ + + &--settings { max-width: 938px; } } @@ -20,4 +21,32 @@ box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.15); background-color: $color-white; } + + &-settings-card { + background-color: $color-white; + padding: 48px; + border-radius: 8px; + box-shadow: 0 2px 4px 0 #0000001A; + + &__header { + display: flex; + align-items: center; + gap: 18px; + padding-bottom: 18px; + border-bottom: 2px solid $color-gray-700; + margin-bottom: 32px; + } + + &__title { + @include font(16, 24, 600); + color: $color-blueberry; + margin:0 0 4px 0; + display: block; + } + &__description{ + @include font(14, 20, 400); + color:$color-gray-800; + margin:0; + } + } } diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_tabs.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_tabs.scss new file mode 100644 index 000000000..5eaa4fb56 --- /dev/null +++ b/modules/ppcp-settings/resources/css/components/reusable-components/_tabs.scss @@ -0,0 +1,27 @@ +.components-tab-panel__tabs { + width: 100%; + position: relative; + margin:0 0 48px 0; + &::after { + content: ''; + position: absolute; + display: block; + width: 100%; + height: 1px; + background-color: $color-gray-400; + bottom: 0; + left: 0; + z-index: -1; + } + + button { + padding: 16px 20px; + @include font(13, 16, 400); + color: $color-gray-900; + + &.active-tab { + font-weight: 600; + box-shadow: 0px -4px 0px 0px $color-blueberry inset; + } + } +} diff --git a/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss b/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss new file mode 100644 index 000000000..07ca60d3e --- /dev/null +++ b/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss @@ -0,0 +1,67 @@ +.ppcp-r-tab-dashboard-todo { + margin: 0 0 48px 0; +} + +.ppcp-r-todo-item { + position: relative; + display: flex; + align-items: center; + gap: 18px; + width: 100%; + + &:not(:last-child) { + border-bottom: 1px solid $color-gray-400; + padding-bottom: 24px; + } + + &:not(:first-child) { + padding-top: 24px; + } + + p { + @include font(14, 20, 400); + } + + &__inner { + position: relative; + display: flex; + align-items: center; + gap: 18px; + } + + &__close { + margin-left: auto; + + &:hover { + cursor: pointer; + color: $color-blueberry; + } + } +} + +.ppcp-r-feature-item { + padding-top: 32px; + border-top: 1px solid $color-gray-400; + + &__title { + @include font(16, 20, 600); + color: $color-black; + display: block; + margin: 0 0 8px 0; + } + + &__description { + @include font(14, 20, 400); + color: $color-gray-800; + margin: 0 0 18px 0; + } + + &:not(:last-child) { + padding-bottom: 32px; + } + + &__buttons { + display: flex; + gap: 18px; + } +} diff --git a/modules/ppcp-settings/resources/css/components/screens/onboarding/_step-welcome.scss b/modules/ppcp-settings/resources/css/components/screens/onboarding/_step-welcome.scss index e9861b900..c37822b41 100644 --- a/modules/ppcp-settings/resources/css/components/screens/onboarding/_step-welcome.scss +++ b/modules/ppcp-settings/resources/css/components/screens/onboarding/_step-welcome.scss @@ -34,6 +34,12 @@ .components-base-control__field { margin: 0 0 24px 0; } + .ppcp-r-toggle-block__toggled-content > button{ + padding: 6px 12px; + @include font(13, 20, 500); + color: $color-white; + border: none; + } } .ppcp-r-welcome-features { @@ -81,3 +87,4 @@ } } } + diff --git a/modules/ppcp-settings/resources/css/style.scss b/modules/ppcp-settings/resources/css/style.scss index 95b407d67..4b99d7b1a 100644 --- a/modules/ppcp-settings/resources/css/style.scss +++ b/modules/ppcp-settings/resources/css/style.scss @@ -12,7 +12,10 @@ @import './components/reusable-components/settings-wrapper'; @import './components/reusable-components/select-box'; @import './components/reusable-components/navigation'; + @import './components/reusable-components/tabs'; + @import './components/reusable-components/fields'; @import './components/screens/onboarding/step-welcome'; @import './components/screens/onboarding/step-business'; @import './components/screens/onboarding/step-products'; + @import './components/screens/dashboard/tab-dashboard'; } diff --git a/modules/ppcp-settings/resources/js/Components/ReusableComponents/Fields.js b/modules/ppcp-settings/resources/js/Components/ReusableComponents/Fields.js new file mode 100644 index 000000000..9872c07bf --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/ReusableComponents/Fields.js @@ -0,0 +1,50 @@ +import data from '../../utils/data'; + +export const PayPalCheckbox = ( props ) => { + return ( +
+ + props.handleCheckboxState( e.target.checked, props ) + } + /> + + { data().getImage( 'icon-checkbox.svg' ) } + +
+ ); +}; + +export const PayPalRdb = ( props ) => { + return ( +
+ props.handleRdbState( props.value ) } + /> + +
+ ); +}; + +export const handleCheckboxState = ( checked, props ) => { + let newValue = null; + if ( checked ) { + newValue = [ ...props.currentValue, props.value ]; + props.changeCallback( newValue ); + } else { + newValue = props.currentValue.filter( + ( value ) => value !== props.value + ); + } + props.changeCallback( newValue ); +}; diff --git a/modules/ppcp-settings/resources/js/Components/ReusableComponents/SelectBox.js b/modules/ppcp-settings/resources/js/Components/ReusableComponents/SelectBox.js index 739397a13..06a56c5ac 100644 --- a/modules/ppcp-settings/resources/js/Components/ReusableComponents/SelectBox.js +++ b/modules/ppcp-settings/resources/js/Components/ReusableComponents/SelectBox.js @@ -1,19 +1,7 @@ import data from '../../utils/data'; +import { PayPalCheckbox, PayPalRdb, handleCheckboxState } from './Fields'; const SelectBox = ( props ) => { - const handleCheckboxState = ( checked ) => { - let newValue = null; - if ( checked ) { - newValue = [ ...props.currentValue, props.value ]; - props.changeCallback( newValue ); - } else { - newValue = props.currentValue.filter( - ( value ) => value !== props.value - ); - } - props.changeCallback( newValue ); - }; - let boxClassName = 'ppcp-r-select-box'; if ( @@ -27,34 +15,20 @@ const SelectBox = ( props ) => { return (
{ props.type === 'radio' && ( -
- props.changeCallback( props.value ) } - /> - -
+ ) } { props.type === 'checkbox' && ( -
- - handleCheckboxState( e.target.checked ) - } - /> - - { data().getImage( 'icon-checkbox.svg' ) } - -
+ ) }
{ data().getImage( props.icon ) } diff --git a/modules/ppcp-settings/resources/js/Components/ReusableComponents/SettingsCard.js b/modules/ppcp-settings/resources/js/Components/ReusableComponents/SettingsCard.js new file mode 100644 index 000000000..bd0a76449 --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/ReusableComponents/SettingsCard.js @@ -0,0 +1,29 @@ +import data from '../../utils/data'; + +const SettingsCard = ( props ) => { + let className = 'ppcp-r-settings-card'; + + if ( props?.className ) { + className += ' ' + props.className; + } + return ( +
+
+ { data().getImage( props.icon ) } +
+ + { props.title } + +

+ { props.description } +

+
+
+
+ { props.children } +
+
+ ); +}; + +export default SettingsCard; diff --git a/modules/ppcp-settings/resources/js/Components/ReusableComponents/TabNavigation.js b/modules/ppcp-settings/resources/js/Components/ReusableComponents/TabNavigation.js index 487847e72..12c912ef3 100644 --- a/modules/ppcp-settings/resources/js/Components/ReusableComponents/TabNavigation.js +++ b/modules/ppcp-settings/resources/js/Components/ReusableComponents/TabNavigation.js @@ -1,24 +1,35 @@ import { TabPanel } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; +import TabDashboard from '../Screens/Dashboard/TabDashboard'; +import TabPaymentMethods from '../Screens/Dashboard/TabPaymentMethods'; +import TabSettings from '../Screens/Dashboard/TabSettings'; +import TabStyling from '../Screens/Dashboard/TabStyling'; -const onSelect = ( tabName ) => { - console.log( 'Selecting tab', tabName ); -}; +const TAB_DASHBOARD = 'TabDashboard'; +const TAB_PAYMENT_METHODS = 'TabPaymentMethods'; +const TAB_SETTINGS = 'TabSettings'; +const TAB_STYLING = 'TabStyling'; const TabNavigation = () => { + const tabComponents = { + [ TAB_DASHBOARD ]: TabDashboard, + [ TAB_PAYMENT_METHODS ]: TabPaymentMethods, + [ TAB_SETTINGS ]: TabSettings, + [ TAB_STYLING ]: TabStyling, + }; + return ( { className: 'ppcp-r-tab-payment-methods', }, { - name: 'settings', + name: TAB_SETTINGS, title: __( 'Settings', 'woocommerce-paypal-payments' ), className: 'ppcp-r-tab-settings', }, { - name: 'styling', + name: TAB_STYLING, title: __( 'Styling', 'woocommerce-paypal-payments' ), className: 'ppcp-r-tab-styling', }, ] } > - { ( tab ) =>

{ tab.title }

} + { ( tab ) => { + const Component = tabComponents[ tab.name ]; + return ; + } }
); }; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabDashboard.js b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabDashboard.js new file mode 100644 index 000000000..e10f398c1 --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabDashboard.js @@ -0,0 +1,288 @@ +import SettingsCard from '../../ReusableComponents/SettingsCard'; +import { __ } from '@wordpress/i18n'; +import { + PayPalCheckbox, + handleCheckboxState, +} from '../../ReusableComponents/Fields'; +import { useState } from '@wordpress/element'; +import data from '../../../utils/data'; +import { Button, TextControl } from '@wordpress/components'; + +const TabDashboard = () => { + const [ todos, setTodos ] = useState( [] ); + const [ todosData, setTodosData ] = useState( todosDataDefault ); + + return ( +
+ +
+ { todosData.map( ( todo ) => ( + + ) ) } +
+
+ + { featuresDefault.map( ( feature ) => { + return ( + + ); + } ) } + +
+ ); +}; + +const TodoItem = ( props ) => { + return ( +
+
+ { ' ' } +

{ props.description }

+
+
+ removeTodo( + props.value, + props.todosData, + props.changeTodos + ) + } + > + { data().getImage( 'icon-close.svg' ) } +
+
+ ); +}; + +const FeatureItem = ( props ) => { + return ( +
+ + { props.title } + { props.status && ( + + { props.status } + + ) } + +

+ { props.description } +

+
+ { props.buttons.map( ( button ) => { + console.log( button ); + return ( + + ); + } ) } +
+
+ ); +}; + +const removeTodo = ( todoValue, todosData, changeTodos ) => { + changeTodos( todosData.filter( ( todo ) => todo.value !== todoValue ) ); +}; + +const todosDataDefault = [ + { + value: 'paypal_later_messaging', + description: __( + 'Enable Pay Later messaging', + 'woocommerce-paypal-payments' + ), + }, + { + value: 'capture_authorized_payments', + description: __( + 'Capture authorized payments', + 'woocommerce-paypal-payments' + ), + }, + { + value: 'enable_google_pay', + description: __( 'Enable Google Pay', 'woocommerce-paypal-payments' ), + }, + { + value: 'paypal_shortcut', + description: __( + 'Add PayPal shortcut to the Cart page', + 'woocommerce-paypal-payments' + ), + }, + { + value: 'advanced_cards', + description: __( + 'Add Advanced Cards to Blocks Checkout', + 'woocommerce-paypal-payments' + ), + }, +]; + +const featuresDefault = [ + { + 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: 'primary', + text: __( 'Configure', 'woocommerce-paypal-payments' ), + }, + { + type: 'secondary', + text: __( 'Learn more', 'woocommerce-paypal-payments' ), + }, + ], + notes: [ __( '', 'woocommerce-paypal-payments' ) ], + }, + { + 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: 'primary', + text: __( 'Configure', 'woocommerce-paypal-payments' ), + }, + { + type: 'secondary', + text: __( 'Learn more', 'woocommerce-paypal-payments' ), + }, + ], + notes: [ __( '', 'woocommerce-paypal-payments' ) ], + }, + { + 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: 'primary', + text: __( 'Apply', 'woocommerce-paypal-payments' ), + }, + { + type: 'secondary', + text: __( 'Learn more', 'woocommerce-paypal-payments' ), + }, + ], + notes: [ __( '', 'woocommerce-paypal-payments' ) ], + }, + { + id: 'google_pay', + title: __( 'Google Pay', 'woocommerce-paypal-payments' ), + description: __( + 'Let customers pay using their Google Pay wallet.', + 'woocommerce-paypal-payments' + ), + buttons: [ + { + type: 'primary', + text: __( 'Configure', 'woocommerce-paypal-payments' ), + }, + { + type: 'secondary', + text: __( 'Learn more', 'woocommerce-paypal-payments' ), + }, + ], + notes: [ __( '', '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: 'primary', + text: __( + 'Domain registration', + 'woocommerce-paypal-payments' + ), + }, + { + type: 'secondary', + text: __( 'Learn more', 'woocommerce-paypal-payments' ), + }, + ], + notes: [ __( '', 'woocommerce-paypal-payments' ) ], + }, + { + 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: 'primary', + text: __( 'Configure', 'woocommerce-paypal-payments' ), + }, + { + type: 'secondary', + text: __( 'Learn more', 'woocommerce-paypal-payments' ), + }, + ], + notes: [ __( '', 'woocommerce-paypal-payments' ) ], + }, +]; +export default TabDashboard; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabPaymentMethods.js b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabPaymentMethods.js new file mode 100644 index 000000000..56df4838c --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabPaymentMethods.js @@ -0,0 +1,5 @@ +const TabPaymentMethods = () => { + return
PaymentMethods tab
; +}; + +export default TabPaymentMethods; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabSettings.js b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabSettings.js new file mode 100644 index 000000000..da94c89c8 --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabSettings.js @@ -0,0 +1,5 @@ +const TabSettings = () => { + return
Settings tab
; +}; + +export default TabSettings; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabStyling.js b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabStyling.js new file mode 100644 index 000000000..c61b2b296 --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabStyling.js @@ -0,0 +1,5 @@ +const TabStyling = () => { + return
Styling tab
; +}; + +export default TabStyling; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepWelcome.js b/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepWelcome.js index c105eba07..4241676ae 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepWelcome.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepWelcome.js @@ -94,7 +94,7 @@ const WelcomeForm = () => { 'woocommerce-paypal-payments' ) } > - @@ -120,7 +120,7 @@ const WelcomeForm = () => { ) } type="password" > - diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Settings.js b/modules/ppcp-settings/resources/js/Components/Screens/Settings.js index 562d8d9b4..69f4cc7ca 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Settings.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Settings.js @@ -4,7 +4,6 @@ import Dashboard from './Dashboard/Dashboard'; const Settings = () => { const [ onboarded, setOnboarded ] = useState( true ); - return <>{ onboarded ? : }; }; diff --git a/modules/ppcp-settings/webpack.config.js b/modules/ppcp-settings/webpack.config.js index e0223be80..93cd4afb5 100644 --- a/modules/ppcp-settings/webpack.config.js +++ b/modules/ppcp-settings/webpack.config.js @@ -3,6 +3,7 @@ const path = require( 'path' ); module.exports = { ...defaultConfig, + cache: false, ...{ entry: { index: path.resolve( process.cwd(), 'resources/js', 'index.js' ), From 8b67aa42656de2980e8f5d49fe61f83007156c47 Mon Sep 17 00:00:00 2001 From: inpsyde-maticluznar Date: Mon, 28 Oct 2024 12:26:13 +0100 Subject: [PATCH 7/7] Implements dashboard layout --- .../ppcp-settings/images/icon-arrow-down.svg | 3 + modules/ppcp-settings/images/icon-refresh.svg | 4 + .../reusable-components/_button.scss | 3 +- .../_settings-wrapper.scss | 12 +- .../reusable-components/_title-badge.scss | 15 + .../screens/dashboard/_tab-dashboard.scss | 115 ++++++++ .../ppcp-settings/resources/css/style.scss | 1 + .../ReusableComponents/TitleBadge.js | 8 + .../Screens/Dashboard/TabDashboard.js | 262 ++++++++++++++---- 9 files changed, 368 insertions(+), 55 deletions(-) create mode 100644 modules/ppcp-settings/images/icon-arrow-down.svg create mode 100644 modules/ppcp-settings/images/icon-refresh.svg create mode 100644 modules/ppcp-settings/resources/css/components/reusable-components/_title-badge.scss create mode 100644 modules/ppcp-settings/resources/js/Components/ReusableComponents/TitleBadge.js diff --git a/modules/ppcp-settings/images/icon-arrow-down.svg b/modules/ppcp-settings/images/icon-arrow-down.svg new file mode 100644 index 000000000..3adce0c2e --- /dev/null +++ b/modules/ppcp-settings/images/icon-arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/modules/ppcp-settings/images/icon-refresh.svg b/modules/ppcp-settings/images/icon-refresh.svg new file mode 100644 index 000000000..6a7c9f262 --- /dev/null +++ b/modules/ppcp-settings/images/icon-refresh.svg @@ -0,0 +1,4 @@ + + + + diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_button.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_button.scss index 844200970..d084ce4d7 100644 --- a/modules/ppcp-settings/resources/css/components/reusable-components/_button.scss +++ b/modules/ppcp-settings/resources/css/components/reusable-components/_button.scss @@ -1,4 +1,4 @@ -button.components-button { +button.components-button, a.components-button { &.is-primary, &.is-secondary { &:not(:disabled) { background-color: $color-blueberry; @@ -22,6 +22,7 @@ button.components-button { &.is-primary { @include font(13, 16, 500); + color:$color-white; } &.is-secondary:not(:disabled) { diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss index 5afc2940d..c936dd8ea 100644 --- a/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss +++ b/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss @@ -27,6 +27,9 @@ padding: 48px; border-radius: 8px; box-shadow: 0 2px 4px 0 #0000001A; + @media screen and (max-width: 480px) { + padding: 24px; + } &__header { display: flex; @@ -40,13 +43,14 @@ &__title { @include font(16, 24, 600); color: $color-blueberry; - margin:0 0 4px 0; + margin: 0 0 4px 0; display: block; } - &__description{ + + &__description { @include font(14, 20, 400); - color:$color-gray-800; - margin:0; + color: $color-gray-800; + margin: 0; } } } diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_title-badge.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_title-badge.scss new file mode 100644 index 000000000..2490f67e8 --- /dev/null +++ b/modules/ppcp-settings/resources/css/components/reusable-components/_title-badge.scss @@ -0,0 +1,15 @@ +.ppcp-r-title-badge{ + @include font(12, 16, 400); + margin-left:12px; + padding:4px 8px; + border-radius: 2px; + white-space: nowrap; + &--positive{ + color:#005C12; + background-color: #EDFAEF; + } + &--negative{ + color:#5c0000; + background-color: #faeded; + } +} diff --git a/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss b/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss index 07ca60d3e..f9ac41a0d 100644 --- a/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss +++ b/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss @@ -64,4 +64,119 @@ display: flex; gap: 18px; } + + &__notes { + display: flex; + flex-direction: column; + + span { + font-weight: 500; + } + } +} + +.ppcp-r-connection-status { + display: flex; + gap: 32px; + padding-bottom: 48px; + margin-bottom: 48px; + border-bottom: 2px solid $color-gray-500; + + &__status-status { + margin: 0 0 8px 0; + + strong { + @include font(14, 20, 700); + color: $color-black; + } + } + + &__show-all-data { + margin-left: 12px; + + &:hover { + cursor: pointer; + opacity: 0.8; + } + } + + &__status-label { + span { + @include font(12, 16, 400); + color: $color-gray-700; + } + } + + &__data { + display: flex; + flex-direction: column; + gap: 12px; + } + + &__status-row { + display: flex; + align-items: center; + + strong { + @include font(14, 20, 600); + color: $color-gray-800; + margin-right: 12px; + white-space: nowrap; + } + + span { + @include font(14, 20, 400); + color: $color-gray-800; + } + } + + @media screen and (max-width: 767px) { + flex-wrap: wrap; + &__status { + width: 100%; + } + &__status-row { + flex-wrap: wrap; + strong{ + width: 100%; + } + span{ + word-break:break-all; + } + } + } +} + +.ppcp-r-feature-refresh { + display: flex; + gap: 12px; + margin-bottom: 24px; + + &__row { + display: flex; + align-items: center; + } + + &__content { + width: 100%; + + &-title { + @include font(16, 20, 700); + color: $color-black; + display: block; + margin: 0 0 4px 0; + } + + p { + @include font(12, 20, 400); + color: $color-gray-700; + margin: 0; + } + } + + button { + display: flex; + gap: 4px; + @include font(13, 20, 400); + } } diff --git a/modules/ppcp-settings/resources/css/style.scss b/modules/ppcp-settings/resources/css/style.scss index 4b99d7b1a..f50f9bab8 100644 --- a/modules/ppcp-settings/resources/css/style.scss +++ b/modules/ppcp-settings/resources/css/style.scss @@ -14,6 +14,7 @@ @import './components/reusable-components/navigation'; @import './components/reusable-components/tabs'; @import './components/reusable-components/fields'; + @import './components/reusable-components/title-badge'; @import './components/screens/onboarding/step-welcome'; @import './components/screens/onboarding/step-business'; @import './components/screens/onboarding/step-products'; diff --git a/modules/ppcp-settings/resources/js/Components/ReusableComponents/TitleBadge.js b/modules/ppcp-settings/resources/js/Components/ReusableComponents/TitleBadge.js new file mode 100644 index 000000000..25c5c8645 --- /dev/null +++ b/modules/ppcp-settings/resources/js/Components/ReusableComponents/TitleBadge.js @@ -0,0 +1,8 @@ +const TitleBadge = ( { text, type } ) => { + const className = 'ppcp-r-title-badge ' + `ppcp-r-title-badge--${ type }`; + return { text }; +}; + +export const TITLE_BADGE_POSITIVE = 'positive'; +export const TITLE_BADGE_NEGATIVE = 'negative'; +export default TitleBadge; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabDashboard.js b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabDashboard.js index e10f398c1..214f7510f 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabDashboard.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Dashboard/TabDashboard.js @@ -6,41 +6,58 @@ import { } from '../../ReusableComponents/Fields'; import { useState } from '@wordpress/element'; import data from '../../../utils/data'; -import { Button, TextControl } from '@wordpress/components'; +import { Button } from '@wordpress/components'; +import TitleBadge, { + TITLE_BADGE_NEGATIVE, + TITLE_BADGE_POSITIVE, +} from '../../ReusableComponents/TitleBadge'; const TabDashboard = () => { const [ todos, setTodos ] = useState( [] ); const [ todosData, setTodosData ] = useState( todosDataDefault ); + const [ connectionData, setConnectionData ] = useState( { + connectionStatus: true, + showAllData: false, + email: 'bt_us@woocommerce.com', + merchantId: 'AT45V2DGMKLRY', + clientId: 'BAARTJLxtUNN4d2GMB6Eut3suMDYad72xQA-FntdIFuJ6FmFJITxAY8', + } ); + + const showAllData = () => { + setConnectionData( { ...connectionData, showAllData: true } ); + }; return (
- -
- { todosData.map( ( todo ) => ( - - ) ) } -
-
+ { todosData.length > 0 && ( + +
+ { todosData.map( ( todo ) => ( + + ) ) } +
+
+ ) } { 'woocommerce-paypal-payments' ) } > + + { featuresDefault.map( ( feature ) => { return ( - + ); } ) } @@ -65,6 +82,110 @@ const TabDashboard = () => { ); }; +const ConnectionStatus = ( { connectionData, showAllData } ) => { + return ( +
+
+
+ + { __( 'Connection', 'woocommerce-paypal-payments' ) } + + { connectionData.connectionStatus ? ( + + ) : ( + + ) } +
+
+ + { __( + 'PayPal Account Details', + 'woocommerce-paypal-payments' + ) } + +
+
+ { connectionData.connectionStatus && ( +
+
+ + { __( + 'Email address:', + 'woocommerce-paypal-payments' + ) } + + { connectionData.email } + { ! connectionData.showAllData && ( + showAllData() }> + { data().getImage( + 'icon-arrow-down.svg', + 'ppcp-r-connection-status__show-all-data' + ) } + + ) } +
+ { connectionData.showAllData && ( + <> +
+ + { __( + 'Merchant ID:', + 'woocommerce-paypal-payments' + ) } + + { connectionData.merchantId } +
+
+ + { __( + 'Client ID:', + 'woocommerce-paypal-payments' + ) } + + { connectionData.clientId } +
+ + ) } +
+ ) } +
+ ); +}; + +const FeaturesRefresh = () => { + return ( +
+
+ + { __( 'Features', 'woocommerce-paypal-payments' ) } + +

+ { __( + 'After making changes to your PayPal account, click Refresh to update your store features.', + 'woocommerce-paypal-payments' + ) } +

+
+ +
+ ); +}; + const TodoItem = ( props ) => { return (
@@ -93,25 +214,55 @@ const TodoItem = ( props ) => { ); }; -const FeatureItem = ( props ) => { +const FeatureItem = ( { feature } ) => { + const printNotes = () => { + if ( ! feature?.notes ) { + return null; + } + + if ( Array.isArray( feature.notes ) && feature.notes.length === 0 ) { + return null; + } + + return ( + <> +
+
+ + { feature.notes.map( ( note, index ) => { + return { note }; + } ) } + + + ); + }; + return (
- { props.title } - { props.status && ( - - { props.status } - + { feature.title } + { feature?.featureStatus && ( + ) }

- { props.description } + { feature.description } + { printNotes() }

- { props.buttons.map( ( button ) => { - console.log( button ); + { feature.buttons.map( ( button ) => { return ( - ); @@ -172,13 +323,14 @@ const featuresDefault = [ { type: 'primary', text: __( 'Configure', 'woocommerce-paypal-payments' ), + url: '#', }, { type: 'secondary', text: __( 'Learn more', 'woocommerce-paypal-payments' ), + url: '#', }, ], - notes: [ __( '', 'woocommerce-paypal-payments' ) ], }, { id: 'advanced_credit_and_debit_cards', @@ -186,6 +338,7 @@ const featuresDefault = [ 'Advanced Credit and Debit Cards', 'woocommerce-paypal-payments' ), + featureStatus: true, description: __( 'Process major credit and debit cards including Visa, Mastercard, American Express and Discover.', 'woocommerce-paypal-payments' @@ -194,13 +347,14 @@ const featuresDefault = [ { type: 'primary', text: __( 'Configure', 'woocommerce-paypal-payments' ), + url: '#', }, { type: 'secondary', text: __( 'Learn more', 'woocommerce-paypal-payments' ), + url: '#', }, ], - notes: [ __( '', 'woocommerce-paypal-payments' ) ], }, { id: 'alternative_payment_methods', @@ -216,13 +370,14 @@ const featuresDefault = [ { type: 'primary', text: __( 'Apply', 'woocommerce-paypal-payments' ), + url: '#', }, { type: 'secondary', text: __( 'Learn more', 'woocommerce-paypal-payments' ), + url: '#', }, ], - notes: [ __( '', 'woocommerce-paypal-payments' ) ], }, { id: 'google_pay', @@ -231,17 +386,22 @@ const featuresDefault = [ 'Let customers pay using their Google Pay wallet.', 'woocommerce-paypal-payments' ), + featureStatus: true, buttons: [ { type: 'primary', text: __( 'Configure', 'woocommerce-paypal-payments' ), + url: '#', }, { type: 'secondary', text: __( 'Learn more', 'woocommerce-paypal-payments' ), + url: '#', }, ], - notes: [ __( '', 'woocommerce-paypal-payments' ) ], + notes: [ + __( '¹PayPal Q2 Earnings-2021.', 'woocommerce-paypal-payments' ), + ], }, { id: 'apple_pay', @@ -257,13 +417,14 @@ const featuresDefault = [ 'Domain registration', 'woocommerce-paypal-payments' ), + url: '#', }, { type: 'secondary', text: __( 'Learn more', 'woocommerce-paypal-payments' ), + url: '#', }, ], - notes: [ __( '', 'woocommerce-paypal-payments' ) ], }, { id: 'pay_later_messaging', @@ -276,13 +437,14 @@ const featuresDefault = [ { type: 'primary', text: __( 'Configure', 'woocommerce-paypal-payments' ), + url: '#', }, { type: 'secondary', text: __( 'Learn more', 'woocommerce-paypal-payments' ), + url: '#', }, ], - notes: [ __( '', 'woocommerce-paypal-payments' ) ], }, ]; export default TabDashboard;