From f8ca397d74cf5d372884e8a7b7f5aac710d35ca1 Mon Sep 17 00:00:00 2001 From: Miguel Peixe Date: Fri, 29 Nov 2024 08:36:59 -0300 Subject: [PATCH] feat(ia): audience checkout/payment and donations wizard (#3564) --- includes/class-donations.php | 29 +- includes/class-newspack.php | 2 +- includes/class-salesforce.php | 2 +- includes/class-wizards.php | 2 +- .../class-reader-activation.php | 3 +- .../audience/class-audience-donations.php | 312 +++++++++ .../audience/class-audience-wizard.php | 360 +++++++++- .../wizards/class-reader-revenue-wizard.php | 624 ------------------ src/components/src/handoff-message/index.js | 3 - src/components/src/wizard/store/utils.js | 7 +- .../components/billing-fields/index.tsx | 85 +++ .../components/cover-fees-settings/index.js | 95 +++ .../components/money-input/index.js | 0 .../components/money-input/style.scss | 0 .../components}/nrh-settings/index.js | 46 +- .../components}/payment-methods/index.js | 10 +- .../components}/payment-methods/stripe.js | 5 +- .../components}/payment-methods/style.scss | 0 .../payment-methods/woopayments.js | 5 +- .../components}/platform/index.js | 6 +- .../components}/salesforce/index.js | 24 +- .../{readerRevenue => audience}/constants.js | 2 +- .../views/donations/configuration}/index.tsx | 218 ++---- src/wizards/audience/views/donations/index.js | 53 ++ .../audience/views/donations/revenue/index.js | 39 ++ src/wizards/audience/views/setup/index.js | 10 +- src/wizards/audience/views/setup/payment.js | 29 + src/wizards/audience/views/setup/setup.js | 7 + .../audience/views/setup/woocommerce.js | 25 - src/wizards/index.tsx | 9 + src/wizards/readerRevenue/components/index.js | 1 - src/wizards/readerRevenue/index.js | 86 --- .../readerRevenue/views/emails/index.js | 112 ---- src/wizards/readerRevenue/views/index.js | 6 - .../payment-methods/additional-settings.js | 105 --- .../setup/views/services/ReaderRevenue.js | 6 +- src/wizards/setup/views/services/index.js | 4 +- src/wizards/syndication/views/intro/index.js | 2 +- src/wizards/types/hooks.d.ts | 27 + src/wizards/types/window.d.ts | 2 +- src/wizards/wizards-tab.tsx | 17 +- tests/unit-tests/api-wizards-controller.php | 4 +- 42 files changed, 1162 insertions(+), 1222 deletions(-) create mode 100644 includes/wizards/audience/class-audience-donations.php delete mode 100644 includes/wizards/class-reader-revenue-wizard.php create mode 100644 src/wizards/audience/components/billing-fields/index.tsx create mode 100644 src/wizards/audience/components/cover-fees-settings/index.js rename src/wizards/{readerRevenue => audience}/components/money-input/index.js (100%) rename src/wizards/{readerRevenue => audience}/components/money-input/style.scss (100%) rename src/wizards/{readerRevenue/views => audience/components}/nrh-settings/index.js (78%) rename src/wizards/{readerRevenue/views => audience/components}/payment-methods/index.js (84%) rename src/wizards/{readerRevenue/views => audience/components}/payment-methods/stripe.js (95%) rename src/wizards/{readerRevenue/views => audience/components}/payment-methods/style.scss (100%) rename src/wizards/{readerRevenue/views => audience/components}/payment-methods/woopayments.js (95%) rename src/wizards/{readerRevenue/views => audience/components}/platform/index.js (91%) rename src/wizards/{readerRevenue/views => audience/components}/salesforce/index.js (90%) rename src/wizards/{readerRevenue => audience}/constants.js (61%) rename src/wizards/{readerRevenue/views/donation => audience/views/donations/configuration}/index.tsx (60%) create mode 100644 src/wizards/audience/views/donations/index.js create mode 100644 src/wizards/audience/views/donations/revenue/index.js create mode 100644 src/wizards/audience/views/setup/payment.js delete mode 100644 src/wizards/audience/views/setup/woocommerce.js delete mode 100644 src/wizards/readerRevenue/components/index.js delete mode 100644 src/wizards/readerRevenue/index.js delete mode 100644 src/wizards/readerRevenue/views/emails/index.js delete mode 100644 src/wizards/readerRevenue/views/index.js delete mode 100644 src/wizards/readerRevenue/views/payment-methods/additional-settings.js diff --git a/includes/class-donations.php b/includes/class-donations.php index 54d21e369a..c2b0aaa6c4 100644 --- a/includes/class-donations.php +++ b/includes/class-donations.php @@ -75,6 +75,7 @@ public static function init() { add_filter( 'newspack_blocks_donate_billing_fields_keys', [ __CLASS__, 'get_billing_fields' ] ); add_action( 'woocommerce_checkout_create_order_line_item', [ __CLASS__, 'checkout_create_order_line_item' ], 10, 4 ); add_action( 'woocommerce_coupons_enabled', [ __CLASS__, 'disable_coupons' ] ); + add_filter( 'render_block', [ __CLASS__, 'prevent_rendering_donate_block' ], 10, 2 ); } } @@ -429,8 +430,7 @@ public static function get_donation_settings() { $parsed_settings['amounts'][ $frequency ] = array_map( 'floatval', $amounts ); } - $parsed_settings['platform'] = self::get_platform_slug(); - $parsed_settings['billingFields'] = self::get_billing_fields(); + $parsed_settings['platform'] = self::get_platform_slug(); // If NYP isn't available, force untiered config. if ( ! self::can_use_name_your_price() ) { @@ -461,13 +461,6 @@ public static function set_donation_settings( $args ) { if ( isset( $args['saveDonationProduct'] ) && $args['saveDonationProduct'] === true ) { self::update_donation_product( $configuration ); } - - // Update the billing fields. - $billing_fields = isset( $args['billingFields'] ) ? $args['billingFields'] : []; - if ( ! empty( $billing_fields ) ) { - $billing_fields = array_map( 'sanitize_text_field', $billing_fields ); - self::update_billing_fields( $billing_fields ); - } } Logger::log( 'Save donation settings' ); @@ -619,7 +612,6 @@ public static function get_platform_slug() { * @param string $platform Platform slug. */ public static function set_platform_slug( $platform ) { - delete_option( self::NEWSPACK_READER_REVENUE_PLATFORM ); update_option( self::NEWSPACK_READER_REVENUE_PLATFORM, $platform, true ); } @@ -1094,5 +1086,22 @@ public static function disable_coupons( $enabled ) { } return false; } + + /** + * Prevent rendering of Donate block if Reader Revenue platform is set to 'other. + * + * @param string $block_content The block content about to be rendered. + * @param array $block The data of the block about to be rendered. + */ + public static function prevent_rendering_donate_block( $block_content, $block ) { + if ( + isset( $block['blockName'] ) + && 'newspack-blocks/donate' === $block['blockName'] + && self::is_platform_other() + ) { + return ''; + } + return $block_content; + } } Donations::init(); diff --git a/includes/class-newspack.php b/includes/class-newspack.php index 1824a7d106..a5e933c4d2 100644 --- a/includes/class-newspack.php +++ b/includes/class-newspack.php @@ -148,6 +148,7 @@ private function includes() { // Audience Wizard. include_once NEWSPACK_ABSPATH . 'includes/wizards/audience/class-audience-wizard.php'; include_once NEWSPACK_ABSPATH . 'includes/wizards/audience/class-audience-campaigns.php'; + include_once NEWSPACK_ABSPATH . 'includes/wizards/audience/class-audience-donations.php'; // Network Wizard. include_once NEWSPACK_ABSPATH . 'includes/wizards/class-network-wizard.php'; @@ -159,7 +160,6 @@ private function includes() { include_once NEWSPACK_ABSPATH . 'includes/wizards/class-settings.php'; include_once NEWSPACK_ABSPATH . 'includes/wizards/class-analytics-wizard.php'; include_once NEWSPACK_ABSPATH . 'includes/wizards/class-engagement-wizard.php'; - include_once NEWSPACK_ABSPATH . 'includes/wizards/class-reader-revenue-wizard.php'; include_once NEWSPACK_ABSPATH . 'includes/wizards/class-site-design-wizard.php'; include_once NEWSPACK_ABSPATH . 'includes/wizards/class-syndication-wizard.php'; include_once NEWSPACK_ABSPATH . 'includes/wizards/class-health-check-wizard.php'; diff --git a/includes/class-salesforce.php b/includes/class-salesforce.php index 366413fd9c..256da2efd1 100644 --- a/includes/class-salesforce.php +++ b/includes/class-salesforce.php @@ -708,7 +708,7 @@ private static function sync_salesforce( $order ) { * @return string Redirect URL. */ public static function get_redirect_url() { - return get_admin_url( null, 'admin.php?page=newspack-reader-revenue-wizard#/salesforce' ); + return get_admin_url( null, 'admin.php?page=newspack-audience' ); } /** diff --git a/includes/class-wizards.php b/includes/class-wizards.php index 6c833aeba7..06f31897fb 100644 --- a/includes/class-wizards.php +++ b/includes/class-wizards.php @@ -31,7 +31,6 @@ public static function init() { self::$wizards = [ 'setup' => new Setup_Wizard(), 'site-design' => new Site_Design_Wizard(), - 'reader-revenue' => new Reader_Revenue_Wizard(), 'syndication' => new Syndication_Wizard(), 'analytics' => new Analytics_Wizard(), 'components-demo' => new Components_Demo(), @@ -55,6 +54,7 @@ public static function init() { 'advertising-sponsors' => new Advertising_Sponsors(), 'audience' => new Audience_Wizard(), 'audience-campaigns' => new Audience_Campaigns(), + 'audience-donations' => new Audience_Donations(), 'listings' => new Listings_Wizard(), 'network' => new Network_Wizard(), 'newsletters' => new Newsletters_Wizard(), diff --git a/includes/reader-activation/class-reader-activation.php b/includes/reader-activation/class-reader-activation.php index 077a406258..ece512628f 100644 --- a/includes/reader-activation/class-reader-activation.php +++ b/includes/reader-activation/class-reader-activation.php @@ -550,8 +550,7 @@ public static function get_prerequisites_status() { 'description' => __( 'Setting suggested donation amounts is required for enabling a streamlined donation experience.', 'newspack-plugin' ), 'instructions' => __( 'Set platform to "Newspack" or "News Revenue Hub" and configure your default donation settings. If using News Revenue Hub, set an Organization ID and a Donor Landing Page in News Revenue Hub Settings.', 'newspack-plugin' ), 'help_url' => 'https://help.newspack.com/engagement/reader-activation-system', - // @TODO: Update when platform is added. - 'href' => \admin_url( '/admin.php?page=newspack-reader-revenue-wizard' ), + 'href' => \admin_url( '/admin.php?page=newspack-audience#/payment' ), 'action_text' => __( 'Reader Revenue settings' ), ], 'ras_campaign' => [ diff --git a/includes/wizards/audience/class-audience-donations.php b/includes/wizards/audience/class-audience-donations.php new file mode 100644 index 0000000000..256bcee0b5 --- /dev/null +++ b/includes/wizards/audience/class-audience-donations.php @@ -0,0 +1,312 @@ +parent_slug, + $this->get_name(), + esc_html__( 'Donations', 'newspack-plugin' ), + $this->capability, + $this->slug, + [ $this, 'render_wizard' ] + ); + } + + /** + * Enqueue scripts and styles. + */ + public function enqueue_scripts_and_styles() { + if ( ! $this->is_wizard_page() ) { + return; + } + + parent::enqueue_scripts_and_styles(); + + wp_enqueue_script( 'newspack-wizards' ); + + \wp_localize_script( + 'newspack-wizards', + 'newspackAudienceDonations', + [ + 'can_use_name_your_price' => Donations::can_use_name_your_price(), + 'revenue_link' => admin_url( 'admin.php?page=wc-reports' ), + ] + ); + } + + /** + * Register the endpoints needed for the wizard screens. + */ + public function register_api_endpoints() { + // Get donations settings. + register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug, + [ + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'api_get_donation_settings' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + ] + ); + + // Update donations settings. + register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug, + [ + 'methods' => \WP_REST_Server::EDITABLE, + 'callback' => [ $this, 'api_update_donation_settings' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + 'args' => [ + 'amounts' => [ + 'required' => false, + ], + 'tiered' => [ + 'required' => false, + 'sanitize_callback' => 'Newspack\newspack_string_to_bool', + ], + 'disabledFrequencies' => [ + 'required' => false, + ], + 'platform' => [ + 'required' => false, + 'sanitize_callback' => 'sanitize_text_field', + ], + ], + ] + ); + + // Save additional settings. + register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug . '/settings/', + [ + 'methods' => \WP_REST_Server::EDITABLE, + 'callback' => [ $this, 'api_update_additional_settings' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + 'args' => [ + 'fee_multiplier' => [ + 'sanitize_callback' => 'Newspack\newspack_clean', + 'validate_callback' => function ( $value ) { + if ( (float) $value > 10 ) { + return new WP_Error( + 'newspack_invalid_param', + __( 'Fee multiplier must be smaller than 10.', 'newspack' ) + ); + } + return true; + }, + ], + 'fee_static' => [ + 'sanitize_callback' => 'Newspack\newspack_clean', + ], + 'allow_covering_fees' => [ + 'sanitize_callback' => 'Newspack\newspack_string_to_bool', + ], + 'allow_covering_fees_default' => [ + 'sanitize_callback' => 'Newspack\newspack_string_to_bool', + ], + 'allow_covering_fees_label' => [ + 'sanitize_callback' => 'Newspack\newspack_clean', + ], + 'location_code' => [ + 'sanitize_callback' => 'Newspack\newspack_clean', + ], + ], + ] + ); + } + + /** + * Handler for setting additional settings. + * + * @param object $settings Settings. + * @return WP_REST_Response with the latest settings. + */ + public function update_additional_settings( $settings ) { + if ( isset( $settings['allow_covering_fees'] ) ) { + update_option( 'newspack_donations_allow_covering_fees', $settings['allow_covering_fees'] ); + } + if ( isset( $settings['allow_covering_fees_default'] ) ) { + update_option( 'newspack_donations_allow_covering_fees_default', $settings['allow_covering_fees_default'] ); + } + + if ( isset( $settings['allow_covering_fees_label'] ) ) { + update_option( 'newspack_donations_allow_covering_fees_label', $settings['allow_covering_fees_label'] ); + } + if ( isset( $settings['fee_multiplier'] ) ) { + update_option( 'newspack_blocks_donate_fee_multiplier', $settings['fee_multiplier'] ); + } + if ( isset( $settings['fee_static'] ) ) { + update_option( 'newspack_blocks_donate_fee_static', $settings['fee_static'] ); + } + return $this->fetch_all_data(); + } + + /** + * Save additional payment method settings (e.g. transaction fees). + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response Response. + */ + public function api_update_additional_settings( $request ) { + $params = $request->get_params(); + $result = $this->update_additional_settings( $params ); + return \rest_ensure_response( $result ); + } + + /** + * API endpoint for setting the donation settings. + * + * @param WP_REST_Request $request Request containing settings. + * @return WP_REST_Response with the latest settings. + */ + public function api_update_donation_settings( $request ) { + return $this->update_donation_settings( $request->get_params() ); + } + + /** + * Handler for setting the donation settings. + * + * @param object $settings Donation settings. + * @return WP_REST_Response with the latest settings. + */ + public function update_donation_settings( $settings ) { + $donations_response = Donations::set_donation_settings( $settings ); + if ( is_wp_error( $donations_response ) ) { + return rest_ensure_response( $donations_response ); + } + return \rest_ensure_response( $this->fetch_all_data() ); + } + + /** + * Fetch all data needed to render the Wizard + * + * @return Array + */ + public function fetch_all_data() { + $platform = Donations::get_platform_slug(); + + $args = [ + 'platform_data' => [ + 'platform' => $platform, + ], + 'additional_settings' => [ + 'allow_covering_fees' => get_option( 'newspack_donations_allow_covering_fees', true ), + 'allow_covering_fees_default' => get_option( 'newspack_donations_allow_covering_fees_default', false ), + 'allow_covering_fees_label' => get_option( 'newspack_donations_allow_covering_fees_label', '' ), + 'fee_multiplier' => get_option( 'newspack_blocks_donate_fee_multiplier', '2.9' ), + 'fee_static' => get_option( 'newspack_blocks_donate_fee_static', '0.3' ), + ], + 'donation_data' => Donations::get_donation_settings(), + 'donation_page' => Donations::get_donation_page_info(), + ]; + if ( 'wc' === $platform ) { + $plugin_status = true; + $managed_plugins = Plugin_Manager::get_managed_plugins(); + $required_plugins = [ + 'woocommerce', + 'woocommerce-subscriptions', + ]; + foreach ( $required_plugins as $required_plugin ) { + if ( 'active' !== $managed_plugins[ $required_plugin ]['Status'] ) { + $plugin_status = false; + } + } + $args = wp_parse_args( + [ + 'plugin_status' => $plugin_status, + ], + $args + ); + } elseif ( Donations::is_platform_nrh() ) { + $nrh_config = NRH::get_settings(); + $args['platform_data'] = wp_parse_args( $nrh_config, $args['platform_data'] ); + } + return $args; + } + + /** + * API endpoint for getting donation settings. + * + * @return WP_REST_Response containing info. + */ + public function api_get_donation_settings() { + if ( Donations::is_platform_wc() ) { + $required_plugins_installed = $this->check_required_plugins_installed(); + if ( is_wp_error( $required_plugins_installed ) ) { + return rest_ensure_response( $required_plugins_installed ); + } + } + + return rest_ensure_response( $this->fetch_all_data() ); + } + + /** + * Check whether WooCommerce is installed and active. + * + * @return bool | WP_Error True on success, WP_Error on failure. + */ + protected function check_required_plugins_installed() { + if ( ! function_exists( 'WC' ) ) { + return new WP_Error( + 'newspack_missing_required_plugin', + esc_html__( 'The WooCommerce plugin is not installed and activated. Install and/or activate it to access this feature.', 'newspack' ), + [ + 'status' => 400, + 'level' => 'fatal', + ] + ); + } + + return true; + } +} diff --git a/includes/wizards/audience/class-audience-wizard.php b/includes/wizards/audience/class-audience-wizard.php index 4d81c235f3..c7fc502714 100644 --- a/includes/wizards/audience/class-audience-wizard.php +++ b/includes/wizards/audience/class-audience-wizard.php @@ -78,10 +78,13 @@ public function enqueue_scripts_and_styles() { return; } parent::enqueue_scripts_and_styles(); + $salesforce_settings = Salesforce::get_salesforce_settings(); $data = [ - 'has_memberships' => class_exists( 'WC_Memberships' ), - 'reader_activation_url' => admin_url( 'admin.php?page=newspack-audience#/' ), - 'esp_metadata_fields' => Reader_Activation\Sync\Metadata::get_default_fields(), + 'has_memberships' => class_exists( 'WC_Memberships' ), + 'reader_activation_url' => admin_url( 'admin.php?page=newspack-audience#/' ), + 'esp_metadata_fields' => Reader_Activation\Sync\Metadata::get_default_fields(), + 'can_use_salesforce' => ! empty( $salesforce_settings['client_id'] ), + 'salesforce_redirect_url' => Salesforce::get_redirect_url(), ]; if ( method_exists( 'Newspack\Newsletters\Subscription_Lists', 'get_add_new_url' ) ) { @@ -207,6 +210,152 @@ public function register_api_endpoints() { 'permission_callback' => [ $this, 'api_permissions_check' ], ] ); + + // Get Salesforce settings. + register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug . '/salesforce', + [ + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'api_get_salesforce_settings' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + ] + ); + + // Save Salesforce settings. + register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug . '/salesforce', + [ + 'methods' => \WP_REST_Server::EDITABLE, + 'callback' => [ $this, 'api_update_salesforce_settings' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + 'args' => [ + 'client_id' => [ + 'sanitize_callback' => 'sanitize_text_field', + ], + 'client_secret' => [ + 'sanitize_callback' => 'sanitize_text_field', + ], + 'access_token' => [ + 'sanitize_callback' => 'sanitize_text_field', + ], + 'refresh_token' => [ + 'sanitize_callback' => 'sanitize_text_field', + ], + ], + ] + ); + + // Get payment settings data. + \register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug . '/payment', + [ + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'api_get_payment_settings' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + ] + ); + + // Save basic data about reader revenue platform. + \register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug . '/payment', + [ + 'methods' => \WP_REST_Server::EDITABLE, + 'callback' => [ $this, 'api_update_payment_settings' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + 'args' => [ + 'platform' => [ + 'sanitize_callback' => 'Newspack\newspack_clean', + 'validate_callback' => [ $this, 'api_validate_platform' ], + ], + 'nrh_organization_id' => [ + 'sanitize_callback' => 'Newspack\newspack_clean', + 'validate_callback' => [ $this, 'api_validate_not_empty' ], + ], + 'nrh_custom_domain' => [ + 'sanitize_callback' => 'Newspack\newspack_clean', + ], + 'nrh_salesforce_campaign_id' => [ + 'sanitize_callback' => 'Newspack\newspack_clean', + ], + 'donor_landing_page' => [ + 'sanitize_callback' => 'Newspack\newspack_clean', + ], + ], + ] + ); + + // Get billing fields info. + \register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug . '/billing-fields', + [ + 'methods' => \WP_REST_Server::READABLE, + 'callback' => [ $this, 'api_get_billing_fields' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + ] + ); + + // Update billing fields info. + \register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug . '/billing-fields', + [ + 'methods' => \WP_REST_Server::EDITABLE, + 'callback' => [ $this, 'api_update_billing_fields' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + 'args' => [ + 'billing_fields' => [ + 'sanitize_callback' => [ $this, 'sanitize_billing_fields' ], + 'validate_callback' => [ $this, 'api_validate_not_empty' ], + ], + ], + ] + ); + + // Save Stripe info. + register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug . '/payment/stripe/', + [ + 'methods' => \WP_REST_Server::EDITABLE, + 'callback' => [ $this, 'api_update_stripe_settings' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + 'args' => [ + 'activate' => [ + 'sanitize_callback' => 'Newspack\newspack_string_to_bool', + ], + 'enabled' => [ + 'sanitize_callback' => 'Newspack\newspack_string_to_bool', + ], + 'location_code' => [ + 'sanitize_callback' => 'Newspack\newspack_clean', + ], + ], + ] + ); + + // Save WooPayments info. + register_rest_route( + NEWSPACK_API_NAMESPACE, + '/wizard/' . $this->slug . '/payment/woopayments/', + [ + 'methods' => \WP_REST_Server::EDITABLE, + 'callback' => [ $this, 'api_update_woopayments_settings' ], + 'permission_callback' => [ $this, 'api_permissions_check' ], + 'args' => [ + 'activate' => [ + 'sanitize_callback' => 'Newspack\newspack_string_to_bool', + ], + 'enabled' => [ + 'sanitize_callback' => 'Newspack\newspack_string_to_bool', + ], + ], + ] + ); } /** @@ -295,6 +444,211 @@ public function api_update_content_gating_settings( $request ) { return rest_ensure_response( self::get_memberships_settings() ); } + /** + * API endpoint to get Salesforce settings. + * + * @return WP_REST_Response with Salesforce settings. + */ + public function api_get_salesforce_settings() { + return \rest_ensure_response( Salesforce::get_salesforce_settings() ); + } + + /** + * API endpoint for setting Salesforce settings. + * + * @param WP_REST_Request $request Request containing settings. + * @return WP_REST_Response with the latest settings. + */ + public function api_update_salesforce_settings( $request ) { + $salesforce_response = Salesforce::set_salesforce_settings( $request->get_params() ); + if ( is_wp_error( $salesforce_response ) ) { + return rest_ensure_response( $salesforce_response ); + } + return \rest_ensure_response( Salesforce::get_salesforce_settings() ); + } + + /** + * Validate platform ID. + * + * @param mixed $value A param value. + * @return bool + */ + public function api_validate_platform( $value ) { + return in_array( $value, [ 'nrh', 'wc', 'other' ] ); + } + + /** + * Get payment settings. + * + * @return WP_REST_Response containing ad units info. + */ + public function api_get_payment_settings() { + return \rest_ensure_response( $this->get_payment_data() ); + } + + /** + * Sanitize payment billing fields. + * + * @param mixed $value A param value. + * + * @return array + */ + public function sanitize_billing_fields( $value ) { + return is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : []; + } + + /** + * Set payment settings. + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response Boolean success. + */ + public function api_update_payment_settings( $request ) { + $params = $request->get_params(); + + Donations::set_platform_slug( $params['platform'] ); + + // Update NRH settings. + if ( Donations::is_platform_nrh() ) { + NRH::update_settings( $params ); + } + + // Ensure that any Reader Revenue settings changed while the platform wasn't WC are persisted to WC products. + if ( Donations::is_platform_wc() ) { + Donations::update_donation_product( Donations::get_donation_settings() ); + } + + return \rest_ensure_response( $this->get_payment_data() ); + } + + /** + * API callback to get billing fields. + * + * @return WP_REST_Response Response. + */ + public function api_get_billing_fields() { + return \rest_ensure_response( $this->get_billing_fields() ); + } + + /** + * Update billing fields. + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response Response. + */ + public function api_update_billing_fields( $request ) { + $params = $request->get_params(); + Donations::update_billing_fields( $params['billing_fields'] ); + return \rest_ensure_response( $this->get_billing_fields() ); + } + + /** + * Get billing fields data. + */ + public function get_billing_fields() { + $available_billing_fields = []; + $checkout = new \WC_Checkout(); + $fields = $checkout->get_checkout_fields(); + if ( ! empty( $fields['billing'] ) ) { + $available_billing_fields = $fields['billing']; + } + return [ + 'available_billing_fields' => $available_billing_fields, + 'billing_fields' => Donations::get_billing_fields(), + ]; + } + + /** + * Save Stripe settings. + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response Response. + */ + public function api_update_stripe_settings( $request ) { + $params = $request->get_params(); + $result = $this->update_stripe_settings( $params ); + return \rest_ensure_response( $result ); + } + + /** + * Handler for setting Stripe settings. + * + * @param object $settings Stripe settings. + * @return WP_REST_Response with the latest settings. + */ + public function update_stripe_settings( $settings ) { + if ( ! empty( $settings['activate'] ) ) { + // If activating the Stripe Gateway plugin, let's enable it. + $settings = [ 'enabled' => true ]; + } + $result = Stripe_Connection::update_stripe_data( $settings ); + if ( \is_wp_error( $result ) ) { + return $result; + } + + return $this->get_payment_data(); + } + + /** + * Save WooPayments settings. + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response Response. + */ + public function api_update_woopayments_settings( $request ) { + $wc_configuration_manager = Configuration_Managers::configuration_manager_class_for_plugin_slug( 'woocommerce' ); + + $params = $request->get_params(); + $result = $wc_configuration_manager->update_wc_woopayments_settings( $params ); + return \rest_ensure_response( $result ); + } + + /** + * Get payment data for the wizard. + * + * @return Array + */ + public function get_payment_data() { + $platform = Donations::get_platform_slug(); + $wc_configuration_manager = Configuration_Managers::configuration_manager_class_for_plugin_slug( 'woocommerce' ); + $stripe_data = Stripe_Connection::get_stripe_data(); + + $args = [ + 'payment_gateways' => [ + 'stripe' => $stripe_data, + 'woopayments' => $wc_configuration_manager->woopayments_data(), + ], + 'platform_data' => [ + 'platform' => $platform, + ], + 'is_ssl' => is_ssl(), + 'errors' => [], + ]; + if ( 'wc' === $platform ) { + $plugin_status = true; + $managed_plugins = Plugin_Manager::get_managed_plugins(); + $required_plugins = [ + 'woocommerce', + 'woocommerce-subscriptions', + ]; + foreach ( $required_plugins as $required_plugin ) { + if ( 'active' !== $managed_plugins[ $required_plugin ]['Status'] ) { + $plugin_status = false; + } + } + $args = wp_parse_args( + [ + 'plugin_status' => $plugin_status, + ], + $args + ); + } elseif ( Donations::is_platform_nrh() ) { + $nrh_config = NRH::get_settings(); + $args['platform_data'] = wp_parse_args( $nrh_config, $args['platform_data'] ); + } + return $args; + } + /** * Get memberships settings. * diff --git a/includes/wizards/class-reader-revenue-wizard.php b/includes/wizards/class-reader-revenue-wizard.php deleted file mode 100644 index dc64c1b703..0000000000 --- a/includes/wizards/class-reader-revenue-wizard.php +++ /dev/null @@ -1,624 +0,0 @@ -slug, - [ - 'methods' => \WP_REST_Server::READABLE, - 'callback' => [ $this, 'api_fetch' ], - 'permission_callback' => [ $this, 'api_permissions_check' ], - ] - ); - // Save basic data about reader revenue platform. - \register_rest_route( - NEWSPACK_API_NAMESPACE, - '/wizard/' . $this->slug, - [ - 'methods' => \WP_REST_Server::EDITABLE, - 'callback' => [ $this, 'api_update' ], - 'permission_callback' => [ $this, 'api_permissions_check' ], - 'args' => [ - 'platform' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - 'validate_callback' => [ $this, 'api_validate_platform' ], - ], - 'nrh_organization_id' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - 'validate_callback' => [ $this, 'api_validate_not_empty' ], - ], - 'nrh_custom_domain' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - ], - 'nrh_salesforce_campaign_id' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - ], - 'donor_landing_page' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - ], - ], - ] - ); - - // Save location info. - register_rest_route( - NEWSPACK_API_NAMESPACE, - '/wizard/' . $this->slug . '/location/', - [ - 'methods' => \WP_REST_Server::EDITABLE, - 'callback' => [ $this, 'api_update_location' ], - 'permission_callback' => [ $this, 'api_permissions_check' ], - 'args' => [ - 'countrystate' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - 'validate_callback' => [ $this, 'api_validate_not_empty' ], - ], - 'address1' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - 'validate_callback' => [ $this, 'api_validate_not_empty' ], - ], - 'address2' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - ], - 'city' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - 'validate_callback' => [ $this, 'api_validate_not_empty' ], - ], - 'postcode' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - 'validate_callback' => [ $this, 'api_validate_not_empty' ], - ], - 'currency' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - 'validate_callback' => [ $this, 'api_validate_not_empty' ], - ], - ], - ] - ); - - // Save Stripe info. - register_rest_route( - NEWSPACK_API_NAMESPACE, - '/wizard/' . $this->slug . '/stripe/', - [ - 'methods' => \WP_REST_Server::EDITABLE, - 'callback' => [ $this, 'api_update_stripe_settings' ], - 'permission_callback' => [ $this, 'api_permissions_check' ], - 'args' => [ - 'activate' => [ - 'sanitize_callback' => 'Newspack\newspack_string_to_bool', - ], - 'enabled' => [ - 'sanitize_callback' => 'Newspack\newspack_string_to_bool', - ], - 'location_code' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - ], - ], - ] - ); - - // Save WooPayments info. - register_rest_route( - NEWSPACK_API_NAMESPACE, - '/wizard/' . $this->slug . '/woopayments/', - [ - 'methods' => \WP_REST_Server::EDITABLE, - 'callback' => [ $this, 'api_update_woopayments_settings' ], - 'permission_callback' => [ $this, 'api_permissions_check' ], - 'args' => [ - 'activate' => [ - 'sanitize_callback' => 'Newspack\newspack_string_to_bool', - ], - 'enabled' => [ - 'sanitize_callback' => 'Newspack\newspack_string_to_bool', - ], - ], - ] - ); - - // Save additional settings info. - register_rest_route( - NEWSPACK_API_NAMESPACE, - '/wizard/' . $this->slug . '/settings/', - [ - 'methods' => \WP_REST_Server::EDITABLE, - 'callback' => [ $this, 'api_update_additional_settings' ], - 'permission_callback' => [ $this, 'api_permissions_check' ], - 'args' => [ - 'fee_multiplier' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - 'validate_callback' => function ( $value ) { - if ( (float) $value > 10 ) { - return new WP_Error( - 'newspack_invalid_param', - __( 'Fee multiplier must be smaller than 10.', 'newspack' ) - ); - } - return true; - }, - ], - 'fee_static' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - ], - 'allow_covering_fees' => [ - 'sanitize_callback' => 'Newspack\newspack_string_to_bool', - ], - 'allow_covering_fees_default' => [ - 'sanitize_callback' => 'Newspack\newspack_string_to_bool', - ], - 'allow_covering_fees_label' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - ], - 'location_code' => [ - 'sanitize_callback' => 'Newspack\newspack_clean', - ], - ], - ] - ); - - // Update Donations settings. - register_rest_route( - NEWSPACK_API_NAMESPACE, - '/wizard/' . $this->slug . '/donations/', - [ - 'methods' => \WP_REST_Server::EDITABLE, - 'callback' => [ $this, 'api_update_donation_settings' ], - 'permission_callback' => [ $this, 'api_permissions_check' ], - 'args' => [ - 'amounts' => [ - 'required' => false, - ], - 'tiered' => [ - 'required' => false, - 'sanitize_callback' => 'Newspack\newspack_string_to_bool', - ], - 'disabledFrequencies' => [ - 'required' => false, - ], - 'platform' => [ - 'required' => false, - 'sanitize_callback' => 'sanitize_text_field', - ], - ], - ] - ); - - // Save Salesforce settings. - register_rest_route( - NEWSPACK_API_NAMESPACE, - '/wizard/' . $this->slug . '/salesforce/', - [ - 'methods' => \WP_REST_Server::EDITABLE, - 'callback' => [ $this, 'api_update_salesforce_settings' ], - 'permission_callback' => [ $this, 'api_permissions_check' ], - 'args' => [ - 'client_id' => [ - 'sanitize_callback' => 'sanitize_text_field', - ], - 'client_secret' => [ - 'sanitize_callback' => 'sanitize_text_field', - ], - 'access_token' => [ - 'sanitize_callback' => 'sanitize_text_field', - ], - 'refresh_token' => [ - 'sanitize_callback' => 'sanitize_text_field', - ], - ], - ] - ); - - register_rest_route( - NEWSPACK_API_NAMESPACE, - '/wizard/' . $this->slug . '/donations/', - [ - 'methods' => \WP_REST_Server::READABLE, - 'callback' => [ $this, 'api_get_donation_settings' ], - 'permission_callback' => [ $this, 'api_permissions_check' ], - ] - ); - } - - /** - * Get all Wizard Data - * - * @return WP_REST_Response containing ad units info. - */ - public function api_fetch() { - return \rest_ensure_response( $this->fetch_all_data() ); - } - - /** - * Save top-level data. - * - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response Boolean success. - */ - public function api_update( $request ) { - $params = $request->get_params(); - Donations::set_platform_slug( $params['platform'] ); - - // Update NRH settings. - if ( Donations::is_platform_nrh() ) { - NRH::update_settings( $params ); - } - - // Ensure that any Reader Revenue settings changed while the platform wasn't WC are persisted to WC products. - if ( Donations::is_platform_wc() ) { - Donations::update_donation_product( Donations::get_donation_settings() ); - } - - return \rest_ensure_response( $this->fetch_all_data() ); - } - - /** - * Save location info. - * - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response Boolean success. - */ - public function api_update_location( $request ) { - $required_plugins_installed = $this->check_required_plugins_installed(); - if ( is_wp_error( $required_plugins_installed ) ) { - return rest_ensure_response( $required_plugins_installed ); - } - $wc_configuration_manager = Configuration_Managers::configuration_manager_class_for_plugin_slug( 'woocommerce' ); - - $params = $request->get_params(); - - $defaults = [ - 'countrystate' => '', - 'address1' => '', - 'address2' => '', - 'city' => '', - 'postcode' => '', - 'currency' => '', - ]; - - $args = wp_parse_args( $params, $defaults ); - $wc_configuration_manager->update_location( $args ); - - // @todo when is the best time to do this? - $wc_configuration_manager->set_smart_defaults(); - - return \rest_ensure_response( $this->fetch_all_data() ); - } - - /** - * Handler for setting Stripe settings. - * - * @param object $settings Stripe settings. - * @return WP_REST_Response with the latest settings. - */ - public function update_stripe_settings( $settings ) { - if ( ! empty( $settings['activate'] ) ) { - // If activating the Stripe Gateway plugin, let's enable it. - $settings = [ 'enabled' => true ]; - } - $result = Stripe_Connection::update_stripe_data( $settings ); - if ( \is_wp_error( $result ) ) { - return $result; - } - - return $this->fetch_all_data(); - } - - /** - * Handler for setting additional settings. - * - * @param object $settings Settings. - * @return WP_REST_Response with the latest settings. - */ - public function update_additional_settings( $settings ) { - if ( isset( $settings['allow_covering_fees'] ) ) { - update_option( 'newspack_donations_allow_covering_fees', $settings['allow_covering_fees'] ); - } - if ( isset( $settings['allow_covering_fees_default'] ) ) { - update_option( 'newspack_donations_allow_covering_fees_default', $settings['allow_covering_fees_default'] ); - } - - if ( isset( $settings['allow_covering_fees_label'] ) ) { - update_option( 'newspack_donations_allow_covering_fees_label', $settings['allow_covering_fees_label'] ); - } - if ( isset( $settings['fee_multiplier'] ) ) { - update_option( 'newspack_blocks_donate_fee_multiplier', $settings['fee_multiplier'] ); - } - if ( isset( $settings['fee_static'] ) ) { - update_option( 'newspack_blocks_donate_fee_static', $settings['fee_static'] ); - } - return $this->fetch_all_data(); - } - - /** - * Save Stripe settings. - * - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response Response. - */ - public function api_update_stripe_settings( $request ) { - $params = $request->get_params(); - $result = $this->update_stripe_settings( $params ); - return \rest_ensure_response( $result ); - } - - /** - * Save WooPayments settings. - * - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response Response. - */ - public function api_update_woopayments_settings( $request ) { - $wc_configuration_manager = Configuration_Managers::configuration_manager_class_for_plugin_slug( 'woocommerce' ); - - $params = $request->get_params(); - $result = $wc_configuration_manager->update_wc_woopayments_settings( $params ); - return \rest_ensure_response( $result ); - } - - /** - * Save additional payment method settings (e.g. transaction fees). - * - * @param WP_REST_Request $request Request object. - * @return WP_REST_Response Response. - */ - public function api_update_additional_settings( $request ) { - $params = $request->get_params(); - $result = $this->update_additional_settings( $params ); - return \rest_ensure_response( $result ); - } - - /** - * Handler for setting the donation settings. - * - * @param object $settings Donation settings. - * @return WP_REST_Response with the latest settings. - */ - public function update_donation_settings( $settings ) { - $donations_response = Donations::set_donation_settings( $settings ); - if ( is_wp_error( $donations_response ) ) { - return rest_ensure_response( $donations_response ); - } - return \rest_ensure_response( $this->fetch_all_data() ); - } - - /** - * API endpoint for setting the donation settings. - * - * @param WP_REST_Request $request Request containing settings. - * @return WP_REST_Response with the latest settings. - */ - public function api_update_donation_settings( $request ) { - return $this->update_donation_settings( $request->get_params() ); - } - - /** - * API endpoint for setting Salesforce settings. - * - * @param WP_REST_Request $request Request containing settings. - * @return WP_REST_Response with the latest settings. - */ - public function api_update_salesforce_settings( $request ) { - $salesforce_response = Salesforce::set_salesforce_settings( $request->get_params() ); - if ( is_wp_error( $salesforce_response ) ) { - return rest_ensure_response( $salesforce_response ); - } - return \rest_ensure_response( $this->fetch_all_data() ); - } - - /** - * Fetch all data needed to render the Wizard - * - * @return Array - */ - public function fetch_all_data() { - $platform = Donations::get_platform_slug(); - $wc_configuration_manager = Configuration_Managers::configuration_manager_class_for_plugin_slug( 'woocommerce' ); - $wc_installed = 'active' === Plugin_Manager::get_managed_plugin_status( 'woocommerce' ); - $stripe_data = Stripe_Connection::get_stripe_data(); - - $billing_fields = []; - if ( $wc_installed && Donations::is_platform_wc() ) { - $checkout = new \WC_Checkout(); - $fields = $checkout->get_checkout_fields(); - if ( ! empty( $fields['billing'] ) ) { - $billing_fields = $fields['billing']; - } - } - - $args = [ - 'country_state_fields' => newspack_get_countries(), - 'currency_fields' => newspack_get_currencies_options(), - 'location_data' => [], - 'payment_gateways' => [ - 'stripe' => $stripe_data, - 'woopayments' => $wc_configuration_manager->woopayments_data(), - ], - 'additional_settings' => [ - 'allow_covering_fees' => get_option( 'newspack_donations_allow_covering_fees', true ), - 'allow_covering_fees_default' => get_option( 'newspack_donations_allow_covering_fees_default', false ), - 'allow_covering_fees_label' => get_option( 'newspack_donations_allow_covering_fees_label', '' ), - 'fee_multiplier' => get_option( 'newspack_blocks_donate_fee_multiplier', '2.9' ), - 'fee_static' => get_option( 'newspack_blocks_donate_fee_static', '0.3' ), - ], - 'donation_data' => Donations::get_donation_settings(), - 'donation_page' => Donations::get_donation_page_info(), - 'available_billing_fields' => $billing_fields, - 'salesforce_settings' => [], - 'platform_data' => [ - 'platform' => $platform, - ], - 'is_ssl' => is_ssl(), - 'errors' => [], - ]; - if ( 'wc' === $platform ) { - $plugin_status = true; - $managed_plugins = Plugin_Manager::get_managed_plugins(); - $required_plugins = [ - 'woocommerce', - 'woocommerce-subscriptions', - ]; - foreach ( $required_plugins as $required_plugin ) { - if ( 'active' !== $managed_plugins[ $required_plugin ]['Status'] ) { - $plugin_status = false; - } - } - $args = wp_parse_args( - [ - 'salesforce_settings' => Salesforce::get_salesforce_settings(), - 'plugin_status' => $plugin_status, - ], - $args - ); - } elseif ( Donations::is_platform_nrh() ) { - $nrh_config = NRH::get_settings(); - $args['platform_data'] = wp_parse_args( $nrh_config, $args['platform_data'] ); - } - return $args; - } - - /** - * API endpoint for getting donation settings. - * - * @return WP_REST_Response containing info. - */ - public function api_get_donation_settings() { - if ( Donations::is_platform_wc() ) { - $required_plugins_installed = $this->check_required_plugins_installed(); - if ( is_wp_error( $required_plugins_installed ) ) { - return rest_ensure_response( $required_plugins_installed ); - } - } - - return rest_ensure_response( Donations::get_donation_settings() ); - } - - /** - * Check whether WooCommerce is installed and active. - * - * @return bool | WP_Error True on success, WP_Error on failure. - */ - protected function check_required_plugins_installed() { - if ( ! function_exists( 'WC' ) ) { - return new WP_Error( - 'newspack_missing_required_plugin', - esc_html__( 'The WooCommerce plugin is not installed and activated. Install and/or activate it to access this feature.', 'newspack' ), - [ - 'status' => 400, - 'level' => 'fatal', - ] - ); - } - - return true; - } - - /** - * Enqueue Subscriptions Wizard scripts and styles. - */ - public function enqueue_scripts_and_styles() { - parent::enqueue_scripts_and_styles(); - if ( filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) !== $this->slug ) { - return; - } - \wp_enqueue_media(); - \wp_register_script( - 'newspack-reader-revenue-wizard', - Newspack::plugin_url() . '/dist/readerRevenue.js', - $this->get_script_dependencies(), - NEWSPACK_PLUGIN_VERSION, - true - ); - \wp_localize_script( - 'newspack-reader-revenue-wizard', - 'newspack_reader_revenue', - [ - 'emails' => Emails::get_emails( [ Reader_Revenue_Emails::EMAIL_TYPES['RECEIPT'] ], false ), - 'email_cpt' => Emails::POST_TYPE, - 'salesforce_redirect_url' => Salesforce::get_redirect_url(), - 'can_use_name_your_price' => Donations::can_use_name_your_price(), - ] - ); - \wp_enqueue_script( 'newspack-reader-revenue-wizard' ); - } - - /** - * Validate platform ID. - * - * @param mixed $value A param value. - * @return bool - */ - public function api_validate_platform( $value ) { - return in_array( $value, [ 'nrh', 'wc', 'other' ] ); - } -} diff --git a/src/components/src/handoff-message/index.js b/src/components/src/handoff-message/index.js index ba8ecaa290..ea4bcf1e73 100644 --- a/src/components/src/handoff-message/index.js +++ b/src/components/src/handoff-message/index.js @@ -30,9 +30,6 @@ export default function HandoffMessage() { setHandoffMessage( false ); } }, 100 ); - - // Clean up the notification when unmounting. - return () => window.localStorage.removeItem( HANDOFF_KEY ); }, [] ); if ( ! handoffMessage ) { return null; diff --git a/src/components/src/wizard/store/utils.js b/src/components/src/wizard/store/utils.js index e9f17efb20..c1c83857ea 100644 --- a/src/components/src/wizard/store/utils.js +++ b/src/components/src/wizard/store/utils.js @@ -10,7 +10,8 @@ import { WIZARD_STORE_NAMESPACE } from '.'; export const createAction = type => payload => ( { type, payload } ); -export const useWizardData = ( wizardName, defaultValue = {} ) => - useSelect( select => - select( WIZARD_STORE_NAMESPACE ).getWizardAPIData( `newspack-${ wizardName }-wizard` ) +export const useWizardData = ( wizardName, defaultValue = {} ) => { + return useSelect( select => + select( WIZARD_STORE_NAMESPACE ).getWizardAPIData( wizardName ) ) || defaultValue; +}; diff --git a/src/wizards/audience/components/billing-fields/index.tsx b/src/wizards/audience/components/billing-fields/index.tsx new file mode 100644 index 0000000000..6746f32f51 --- /dev/null +++ b/src/wizards/audience/components/billing-fields/index.tsx @@ -0,0 +1,85 @@ +/** + * WordPress dependencies. + */ +import { useDispatch } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { CheckboxControl } from '@wordpress/components'; + +/** + * Internal dependencies. + */ +import { + Button, + Grid, + SectionHeader, + Wizard, +} from '../../../../components/src'; + +const BillingFields = () => { + const wizardData = Wizard.useWizardData( 'newspack-audience/billing-fields' ); + const { updateWizardSettings, saveWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); + + if ( ! wizardData ) { + return null; + } + + const changeHandler = ( value: any ) => + updateWizardSettings( { + slug: 'newspack-audience/billing-fields', + path: [ 'billing_fields' ], + value, + } ); + + const onSave = () => + saveWizardSettings( { + slug: 'newspack-audience/billing-fields', + } ); + + const availableFields = wizardData.available_billing_fields; + if ( ! availableFields || ! Object.keys( availableFields ).length ) { + return null; + } + + const billingFields = wizardData.billing_fields.length + ? wizardData.billing_fields + : Object.keys( availableFields ); + + return ( + <> + + + { Object.keys( availableFields ).map( fieldKey => ( + { + let newFields = [ ...billingFields ]; + if ( billingFields.includes( fieldKey ) ) { + newFields = newFields.filter( field => field !== fieldKey ); + } else { + newFields = [ ...newFields, fieldKey ]; + } + changeHandler( newFields ); + } } + /> + ) ) } + +
+ +
+ + ); +}; + +export default BillingFields; diff --git a/src/wizards/audience/components/cover-fees-settings/index.js b/src/wizards/audience/components/cover-fees-settings/index.js new file mode 100644 index 0000000000..7b11c063f4 --- /dev/null +++ b/src/wizards/audience/components/cover-fees-settings/index.js @@ -0,0 +1,95 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { CheckboxControl } from '@wordpress/components'; +import { useDispatch } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { + ActionCard, + Button, + Grid, + TextControl, + Wizard, +} from '../../../../components/src'; +import { AUDIENCE_DONATIONS_WIZARD_SLUG } from '../../constants'; + +export const CoverFeesSettings = () => { + const { additional_settings: settings = {} } = Wizard.useWizardData( AUDIENCE_DONATIONS_WIZARD_SLUG ); + const { updateWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); + const changeHandler = ( key, value ) => + updateWizardSettings( { + slug: AUDIENCE_DONATIONS_WIZARD_SLUG, + path: [ 'additional_settings', key ], + value, + } ); + + const { saveWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); + const onSave = () => + saveWizardSettings( { + slug: AUDIENCE_DONATIONS_WIZARD_SLUG, + section: 'settings', + payloadPath: [ 'additional_settings' ], + } ); + + return ( + { + changeHandler( 'allow_covering_fees', ! settings.allow_covering_fees ); + onSave(); + } } + hasGreyHeader={ settings.allow_covering_fees } + hasWhiteHeader={ ! settings.allow_covering_fees } + actionContent={ settings.allow_covering_fees && ( + + ) } + > + { settings.allow_covering_fees && ( + + changeHandler( 'fee_multiplier', value ) } + /> + changeHandler( 'fee_static', value ) } + /> + changeHandler( 'allow_covering_fees_label', value ) } + /> + changeHandler( 'allow_covering_fees_default', ! settings.allow_covering_fees_default ) } + help={ __( + 'If enabled, the option to cover the transaction fee will be checked by default.', + 'newspack-plugin' + ) } + /> + + ) } + + ); +} diff --git a/src/wizards/readerRevenue/components/money-input/index.js b/src/wizards/audience/components/money-input/index.js similarity index 100% rename from src/wizards/readerRevenue/components/money-input/index.js rename to src/wizards/audience/components/money-input/index.js diff --git a/src/wizards/readerRevenue/components/money-input/style.scss b/src/wizards/audience/components/money-input/style.scss similarity index 100% rename from src/wizards/readerRevenue/components/money-input/style.scss rename to src/wizards/audience/components/money-input/style.scss diff --git a/src/wizards/readerRevenue/views/nrh-settings/index.js b/src/wizards/audience/components/nrh-settings/index.js similarity index 78% rename from src/wizards/readerRevenue/views/nrh-settings/index.js rename to src/wizards/audience/components/nrh-settings/index.js index 8ebeab10dd..1298271191 100644 --- a/src/wizards/readerRevenue/views/nrh-settings/index.js +++ b/src/wizards/audience/components/nrh-settings/index.js @@ -9,18 +9,17 @@ import { useEffect, useState } from '@wordpress/element'; * Internal dependencies */ import { - ActionCard, AutocompleteWithSuggestions, Button, Grid, + SectionHeader, TextControl, Wizard, } from '../../../../components/src'; -import { READER_REVENUE_WIZARD_SLUG } from '../../constants'; const NRHSettings = () => { const [ selectedPage, setSelectedPage ] = useState( null ); - const wizardData = Wizard.useWizardData( 'reader-revenue' ); + const wizardData = Wizard.useWizardData( 'newspack-audience/payment' ); const { updateWizardSettings, saveWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); useEffect( () => { @@ -31,48 +30,42 @@ const NRHSettings = () => { const changeHandler = ( key, value ) => { return updateWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, + slug: 'newspack-audience/payment', path: [ 'platform_data', key ], value, } ); }; const onSave = () => saveWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, + slug: 'newspack-audience/payment', payloadPath: [ 'platform_data' ], } ); const settings = wizardData?.platform_data || {}; return ( - - { __( 'Save Settings' ) } - - } - > + <> +
changeHandler( 'nrh_organization_id', value ) } /> changeHandler( 'nrh_custom_domain', value ) } /> changeHandler( 'nrh_salesforce_campaign_id', value ) } @@ -82,7 +75,7 @@ const NRHSettings = () => { { settings.hasOwnProperty( 'donor_landing_page' ) && (

-

{ __( 'Donor Landing Page', 'newspack' ) }

+

{ __( 'Donor Landing Page', 'newspack-plugin' ) }

{ __( 'Set a page on your site as a donor landing page. Once a reader donates and lands on this page, they will be considered a donor.', @@ -90,7 +83,7 @@ const NRHSettings = () => { ) }

{ return changeHandler( 'donor_landing_page', item ); } } postTypes={ [ { slug: 'page', label: 'Page' } ] } - postTypeLabel={ __( 'page', 'newspack' ) } - postTypeLabelPlural={ __( 'pages', 'newspack' ) } + postTypeLabel={ __( 'page', 'newspack-plugin' ) } + postTypeLabelPlural={ __( 'pages', 'newspack-plugin' ) } selectedItems={ selectedPage ? [ selectedPage ] : [] } />
) } - +
+ +
+ ); }; diff --git a/src/wizards/readerRevenue/views/payment-methods/index.js b/src/wizards/audience/components/payment-methods/index.js similarity index 84% rename from src/wizards/readerRevenue/views/payment-methods/index.js rename to src/wizards/audience/components/payment-methods/index.js index 28c7da497e..c977317d88 100644 --- a/src/wizards/readerRevenue/views/payment-methods/index.js +++ b/src/wizards/audience/components/payment-methods/index.js @@ -7,7 +7,6 @@ import { ExternalLink } from '@wordpress/components'; /** * Internal dependencies */ -import { AdditionalSettings } from './additional-settings'; import { Stripe } from './stripe'; import { WooPayments } from './woopayments'; import { Notice, SectionHeader, Wizard } from '../../../../components/src'; @@ -18,16 +17,14 @@ const PaymentGateways = () => { payment_gateways: paymentGateways = {}, is_ssl, errors = [], - additional_settings: settings = {}, plugin_status, platform_data = {}, - } = Wizard.useWizardData( 'reader-revenue' ); + } = Wizard.useWizardData( 'newspack-audience/payment' ); if ( false === plugin_status || 'wc' !== platform_data?.platform ) { return null; } const { stripe = false, woopayments = false } = paymentGateways; - const hasPaymentGateway = Object.keys( paymentGateways ).some( gateway => paymentGateways[ gateway ]?.enabled ); return ( <> { ) } - { hasPaymentGateway && ( - - ) } ); }; diff --git a/src/wizards/readerRevenue/views/payment-methods/stripe.js b/src/wizards/audience/components/payment-methods/stripe.js similarity index 95% rename from src/wizards/readerRevenue/views/payment-methods/stripe.js rename to src/wizards/audience/components/payment-methods/stripe.js index f1df8df4c1..9142566189 100644 --- a/src/wizards/readerRevenue/views/payment-methods/stripe.js +++ b/src/wizards/audience/components/payment-methods/stripe.js @@ -13,7 +13,6 @@ import { Button, Wizard, } from '../../../../components/src'; -import { READER_REVENUE_WIZARD_SLUG } from '../../constants'; export const Stripe = ( { stripe } ) => { const isLoading = useSelect( select => select( Wizard.STORE_NAMESPACE ).isLoading() ); @@ -21,7 +20,7 @@ export const Stripe = ( { stripe } ) => { const { updateWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); const changeHandler = ( key, value ) => updateWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, + slug: 'newspack-audience/payment', path: [ 'payment_gateways', 'stripe', key ], value, } ); @@ -29,7 +28,7 @@ export const Stripe = ( { stripe } ) => { const { saveWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); const onSave = () => saveWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, + slug: 'newspack-audience/payment', section: 'stripe', payloadPath: [ 'payment_gateways', 'stripe' ], } ); diff --git a/src/wizards/readerRevenue/views/payment-methods/style.scss b/src/wizards/audience/components/payment-methods/style.scss similarity index 100% rename from src/wizards/readerRevenue/views/payment-methods/style.scss rename to src/wizards/audience/components/payment-methods/style.scss diff --git a/src/wizards/readerRevenue/views/payment-methods/woopayments.js b/src/wizards/audience/components/payment-methods/woopayments.js similarity index 95% rename from src/wizards/readerRevenue/views/payment-methods/woopayments.js rename to src/wizards/audience/components/payment-methods/woopayments.js index 54f92c013a..e7fb197016 100644 --- a/src/wizards/readerRevenue/views/payment-methods/woopayments.js +++ b/src/wizards/audience/components/payment-methods/woopayments.js @@ -13,7 +13,6 @@ import { Button, Wizard, } from '../../../../components/src'; -import { READER_REVENUE_WIZARD_SLUG } from '../../constants'; export const WooPayments = ( { woopayments } ) => { const isLoading = useSelect( select => select( Wizard.STORE_NAMESPACE ).isLoading() ); @@ -21,7 +20,7 @@ export const WooPayments = ( { woopayments } ) => { const { updateWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); const changeHandler = ( key, value ) => updateWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, + slug: 'newspack-audience/payment', path: [ 'payment_gateways', 'woopayments', key ], value, } ); @@ -29,7 +28,7 @@ export const WooPayments = ( { woopayments } ) => { const { saveWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); const onSave = () => saveWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, + slug: 'newspack-audience/payment', section: 'woopayments', payloadPath: [ 'payment_gateways', 'woopayments' ], } ); diff --git a/src/wizards/readerRevenue/views/platform/index.js b/src/wizards/audience/components/platform/index.js similarity index 91% rename from src/wizards/readerRevenue/views/platform/index.js rename to src/wizards/audience/components/platform/index.js index 4f090092a3..65997dcaad 100644 --- a/src/wizards/readerRevenue/views/platform/index.js +++ b/src/wizards/audience/components/platform/index.js @@ -15,7 +15,7 @@ import { NEWSPACK, NRH, OTHER } from '../../constants'; * Platform Selection Screen Component */ const Platform = () => { - const wizardData = Wizard.useWizardData( 'reader-revenue' ); + const wizardData = Wizard.useWizardData( 'newspack-audience/payment' ); const { saveWizardSettings, updateWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); return ( @@ -39,7 +39,7 @@ const Platform = () => { ] } onChange={ value => { saveWizardSettings( { - slug: 'newspack-reader-revenue-wizard', + slug: 'newspack-audience/payment', payloadPath: [ 'platform_data' ], updatePayload: { path: [ 'platform_data', 'platform' ], @@ -55,7 +55,7 @@ const Platform = () => { onStatus={ ( { complete } ) => { if ( complete ) { updateWizardSettings( { - slug: 'newspack-reader-revenue-wizard', + slug: 'newspack-audience/payment', path: [ 'plugin_status' ], value: true, } ); diff --git a/src/wizards/readerRevenue/views/salesforce/index.js b/src/wizards/audience/components/salesforce/index.js similarity index 90% rename from src/wizards/readerRevenue/views/salesforce/index.js rename to src/wizards/audience/components/salesforce/index.js index 9712b61278..111c6ff9d4 100644 --- a/src/wizards/readerRevenue/views/salesforce/index.js +++ b/src/wizards/audience/components/salesforce/index.js @@ -16,20 +16,18 @@ import { addQueryArgs } from '@wordpress/url'; * Internal dependencies. */ import { PluginSettings, Notice, Wizard } from '../../../../components/src'; -import { READER_REVENUE_WIZARD_SLUG } from '../../constants'; const Salesforce = () => { - const { salesforce_redirect_url: redirectUrl } = window?.newspack_reader_revenue || {}; + const { salesforce_redirect_url: redirectUrl } = window?.newspackAudience || {}; const [ hasCopied, setHasCopied ] = useState( false ); - const { salesforce_settings: salesforceData = {} } = Wizard.useWizardData( 'reader-revenue' ); + const salesforceData = Wizard.useWizardData( 'newspack-audience/salesforce' ); const [ isConnected, setIsConnected ] = useState( salesforceData.refresh_token ); const [ error, setError ] = useState( null ); const { saveWizardSettings, wizardApiFetch } = useDispatch( Wizard.STORE_NAMESPACE ); const saveAllSettings = value => saveWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, - section: 'salesforce', + slug: 'newspack-audience/salesforce', payloadPath: [ 'salesforce_settings' ], updatePayload: { path: [ 'salesforce_settings' ], @@ -73,7 +71,7 @@ const Salesforce = () => { setError( __( 'We couldn’t establish a connection to Salesforce. Please verify your Consumer Key and Secret and try connecting again.', - 'newspack' + 'newspack-plugin' ) ); } @@ -143,21 +141,21 @@ const Salesforce = () => { } } } pluginSlug="newspack/salesforce" - title={ __( 'Salesforce Settings', 'newspack' ) } + title={ __( 'Salesforce Settings', 'newspack-plugin' ) } description={ () => ( <> { error && } { isConnected && ! error && ( ) } { __( 'Establish a connection to sync WooCommerce order data to Salesforce. To connect with Salesforce, create or choose a Connected App for this site in your Salesforce dashboard. Make sure to paste the full URL for this page (', - 'newspack' + 'newspack-plugin' ) } { onFinishCopy={ () => setHasCopied( false ) } > { hasCopied - ? __( 'copied to clipboard!', 'newspack' ) - : __( 'copy to clipboard', 'newspack' ) } + ? __( 'copied to clipboard!', 'newspack-plugin' ) + : __( 'copy to clipboard', 'newspack-plugin' ) } { __( ') into the “Callback URL” field in the Connected App’s settings. ', - 'newspack' + 'newspack-plugin' ) } - { __( 'Learn how to create a Connected App', 'newspack' ) } + { __( 'Learn how to create a Connected App', 'newspack-plugin' ) } ) } diff --git a/src/wizards/readerRevenue/constants.js b/src/wizards/audience/constants.js similarity index 61% rename from src/wizards/readerRevenue/constants.js rename to src/wizards/audience/constants.js index 3407971a56..46d5c9d56c 100644 --- a/src/wizards/readerRevenue/constants.js +++ b/src/wizards/audience/constants.js @@ -6,4 +6,4 @@ export const NRH = 'nrh'; export const NEWSPACK = 'wc'; export const OTHER = 'other'; -export const READER_REVENUE_WIZARD_SLUG = 'newspack-reader-revenue-wizard'; +export const AUDIENCE_DONATIONS_WIZARD_SLUG = 'newspack-audience-donations'; diff --git a/src/wizards/readerRevenue/views/donation/index.tsx b/src/wizards/audience/views/donations/configuration/index.tsx similarity index 60% rename from src/wizards/readerRevenue/views/donation/index.tsx rename to src/wizards/audience/views/donations/configuration/index.tsx index 7a49c143f3..426d6c1137 100644 --- a/src/wizards/readerRevenue/views/donation/index.tsx +++ b/src/wizards/audience/views/donations/configuration/index.tsx @@ -3,14 +3,13 @@ */ import { useDispatch } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; -import { ToggleControl, CheckboxControl } from '@wordpress/components'; +import { ToggleControl } from '@wordpress/components'; /** * Internal dependencies. */ -import { MoneyInput } from '../../components'; +import MoneyInput from '../../../components/money-input'; import { - ActionCard, Button, Card, Grid, @@ -19,8 +18,10 @@ import { SelectControl, TextControl, Wizard, -} from '../../../../components/src'; -import { READER_REVENUE_WIZARD_SLUG } from '../../constants'; +} from '../../../../../components/src'; +import WizardsTab from '../../../../wizards-tab'; +import { AUDIENCE_DONATIONS_WIZARD_SLUG } from '../../../constants'; +import { CoverFeesSettings } from '../../../components/cover-fees-settings'; type FrequencySlug = 'once' | 'month' | 'year'; @@ -42,43 +43,8 @@ const FREQUENCIES: { }; const FREQUENCY_SLUGS: FrequencySlug[] = Object.keys( FREQUENCIES ) as FrequencySlug[]; -type WizardData = { - donation_data: - | { errors: { [ key: string ]: string[] } } - | { - amounts: { - [ Key in FrequencySlug as string ]: [ number, number, number, number ]; - }; - disabledFrequencies: { - [ Key in FrequencySlug as string ]: boolean; - }; - currencySymbol: string; - tiered: boolean; - minimumDonation: string; - billingFields: string[]; - }; - platform_data: { - platform: string; - }; - donation_page: { - editUrl: string; - status: string; - }; - available_billing_fields: { - [ key: string ]: { - autocomplete: string; - class: string[]; - label: string; - priority: number; - required: boolean; - type: string; - validate: string[]; - }; - }; -}; - export const DonationAmounts = () => { - const wizardData = Wizard.useWizardData( 'reader-revenue' ) as WizardData; + const wizardData = Wizard.useWizardData( AUDIENCE_DONATIONS_WIZARD_SLUG ) as AudienceDonationsWizardData; const { updateWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); if ( ! wizardData.donation_data || 'errors' in wizardData.donation_data ) { @@ -90,7 +56,7 @@ export const DonationAmounts = () => { const changeHandler = ( path: ( string | number )[] ) => ( value: any ) => updateWizardSettings( { - slug: 'newspack-reader-revenue-wizard', + slug: AUDIENCE_DONATIONS_WIZARD_SLUG, path: [ 'donation_data', ...path ], value, } ); @@ -104,7 +70,7 @@ export const DonationAmounts = () => { const minimumDonationFloat = parseFloat( minimumDonation ); // Whether we can use the Name Your Price extension. If not, layout is forced to Tiered. - const canUseNameYourPrice = window.newspack_reader_revenue?.can_use_name_your_price; + const canUseNameYourPrice = window.newspackAudienceDonations?.can_use_name_your_price; return ( <> @@ -265,140 +231,56 @@ export const DonationAmounts = () => { ); }; -const BillingFields = () => { - const wizardData = Wizard.useWizardData( 'reader-revenue' ) as WizardData; - const { updateWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); - - if ( ! wizardData.donation_data || 'errors' in wizardData.donation_data ) { - return null; - } - - const changeHandler = ( path: string[] ) => ( value: any ) => - updateWizardSettings( { - slug: 'newspack-reader-revenue-wizard', - path: [ 'donation_data', ...path ], - value, - } ); - - const availableFields = wizardData.available_billing_fields; - if ( ! availableFields || ! Object.keys( availableFields ).length ) { - return null; - } - - const billingFields = wizardData.donation_data.billingFields.length - ? wizardData.donation_data.billingFields - : Object.keys( availableFields ); - - return ( - <> - - - - - { Object.keys( availableFields ).map( fieldKey => ( - { - let newFields = [ ...billingFields ]; - if ( billingFields.includes( fieldKey ) ) { - newFields = newFields.filter( field => field !== fieldKey ); - } else { - newFields = [ ...newFields, fieldKey ]; - } - changeHandler( [ 'billingFields' ] )( newFields ); - } } - /> - ) ) } - - - ); -}; - const Donation = () => { - const wizardData = Wizard.useWizardData( 'reader-revenue' ) as WizardData; + const wizardData = Wizard.useWizardData( AUDIENCE_DONATIONS_WIZARD_SLUG ) as AudienceDonationsWizardData; const { saveWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); const onSaveDonationSettings = () => saveWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, - section: 'donations', + slug: AUDIENCE_DONATIONS_WIZARD_SLUG, payloadPath: [ 'donation_data' ], auxData: { saveDonationProduct: true }, } ); - const onSaveBillingFields = () => - saveWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, - section: 'donations', - payloadPath: [ 'donation_data' ], - } ); return ( - <> - - { __( 'Save Donation Settings', 'newspack-plugin' ) } - - } - > - { wizardData.donation_page && ( - <> - - - - - { 'publish' === wizardData.donation_page.status ? ( - - ) : ( - - ) } - - ) } - - - - { __( 'Save Modal Checkout Settings', 'newspack-plugin' ) } - - } - > - - - + + { wizardData.donation_page && ( + <> + + + + + { 'publish' === wizardData.donation_page.status ? ( + + ) : ( + + ) } + + ) } + +
+ +
+ + +
); }; diff --git a/src/wizards/audience/views/donations/index.js b/src/wizards/audience/views/donations/index.js new file mode 100644 index 0000000000..c14a9fc5fc --- /dev/null +++ b/src/wizards/audience/views/donations/index.js @@ -0,0 +1,53 @@ +import '../../../../shared/js/public-path'; + +/** + * External dependencies. + */ +import values from 'lodash/values'; + +/** + * WordPress dependencies. + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies. + */ +import { Wizard, Notice, withWizard } from '../../../../components/src'; +import Configuration from './configuration'; +import Revenue from './revenue'; +import { AUDIENCE_DONATIONS_WIZARD_SLUG, NEWSPACK, OTHER } from '../../constants'; + +const AudienceDonations = () => { + const { platform_data, donation_data } = Wizard.useWizardData( AUDIENCE_DONATIONS_WIZARD_SLUG ); + const usedPlatform = platform_data?.platform; + const sections = [ + { + label: __( 'Configuration', 'newspack-plugin' ), + path: '/configuration', + render: Configuration, + isHidden: usedPlatform === OTHER, + }, + { + label: __( 'Revenue', 'newspack-plugin' ), + path: '/revenue', + render: Revenue, + isHidden: usedPlatform !== NEWSPACK, + }, + ]; + return ( + + values( donation_data?.errors ).map( ( error, i ) => ( + + ) ) + } + requiredPlugins={ [ 'newspack-blocks' ] } + /> + ); +}; + +export default withWizard( AudienceDonations ); diff --git a/src/wizards/audience/views/donations/revenue/index.js b/src/wizards/audience/views/donations/revenue/index.js new file mode 100644 index 0000000000..ab80281431 --- /dev/null +++ b/src/wizards/audience/views/donations/revenue/index.js @@ -0,0 +1,39 @@ +/* globals newspackAudienceDonations */ +/** + * WordPress dependencies. + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies. + */ +import { Button, Card } from '../../../../../components/src'; +import WizardsTab from '../../../../wizards-tab'; + +/** + * Donation Revenues screen. + */ +const DonationsRevenue = () => ( + +
+ +

{ __( 'View Donation Revenue in WooCommerce', 'newspack-plugin' ) }

+

+ { + __( + 'You can view revenue from donations and subscriptions in the WooCommerce plugin.', + 'newspack-plugin' + ) + } +

+ + + +
+
+
+); + +export default DonationsRevenue; diff --git a/src/wizards/audience/views/setup/index.js b/src/wizards/audience/views/setup/index.js index ac41ffff83..8d38be42c2 100644 --- a/src/wizards/audience/views/setup/index.js +++ b/src/wizards/audience/views/setup/index.js @@ -19,7 +19,7 @@ import { withWizard } from '../../../../components/src'; import Router from '../../../../components/src/proxied-imports/router'; import ContentGating from './content-gating'; import TransactionalEmails from './transactional-emails'; -import WooCommerce from './woocommerce'; +import Payment from './payment'; const { HashRouter, Redirect, Route, Switch } = Router; @@ -85,12 +85,12 @@ function AudienceWizard( { pluginRequirements, wizardApiFetch } ) { path: '/content-gating', }, emails.length > 0 && { - label: __( 'Transacional Emails', 'newspack-plugin' ), + label: __( 'Transactional Emails', 'newspack-plugin' ), path: '/transactional-emails', }, { label: __( 'Checkout & Payment', 'newspack-plugin' ), - path: '/woocommerce', + path: '/payment', }, ]; tabs = tabs.filter( tab => tab ); @@ -139,9 +139,9 @@ function AudienceWizard( { pluginRequirements, wizardApiFetch } ) { ) } /> ( - + ) } /> + + { data?.platform_data?.platform === 'wc' && } + { data?.platform_data?.platform === 'wc' && } + { data?.platform_data?.platform === 'nrh' && } + + ); +} ); diff --git a/src/wizards/audience/views/setup/setup.js b/src/wizards/audience/views/setup/setup.js index b36430d6ad..065cbeab01 100644 --- a/src/wizards/audience/views/setup/setup.js +++ b/src/wizards/audience/views/setup/setup.js @@ -28,6 +28,7 @@ import MetadataFields from '../../components/metadata-fields'; import Mailchimp from '../../components/mailchimp'; import { HANDOFF_KEY } from '../../../../components/src/consts'; import SortableNewsletterListControl from '../../../../components/src/sortable-newsletter-list-control'; +import Salesforce from '../../components/salesforce'; export default withWizardScreen( ( { config, fetchConfig, updateConfig, saveConfig, prerequisites, espSyncErrors, error, inFlight } ) => { const [ allReady, setAllReady ] = useState( false ); @@ -375,6 +376,12 @@ export default withWizardScreen( ( { config, fetchConfig, updateConfig, saveConf ) }
+ { newspackAudience.can_use_salesforce && ( + <> +
+ + + ) } ) } diff --git a/src/wizards/audience/views/setup/woocommerce.js b/src/wizards/audience/views/setup/woocommerce.js deleted file mode 100644 index 294110c3ce..0000000000 --- a/src/wizards/audience/views/setup/woocommerce.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; - -/** - * Internal dependencies. - */ -import { withWizardScreen } from '../../../../components/src'; -import WizardsTab from '../../../wizards-tab'; - -export default withWizardScreen( function () { - return ( - -

In progress.

- {/* TODO: Add Platform from `/wp-admin/admin.php?page=newspack-reader-revenue-wizard#/`*/} - {/* TODO: Add Modal Checkout Billing Fields Settings from `/wp-admin/admin.php?page=newspack-reader-revenue-wizard#/donations`*/} - {/* TODO: Add Stripe Setup from `/wp-admin/admin.php?page=newspack-reader-revenue-wizard#/stripe-setup`*/} - {/* TODO: Add Saleforce Settings from `/wp-admin/admin.php?page=newspack-reader-revenue-wizard#/salesforce`*/} -
- ); -} ); diff --git a/src/wizards/index.tsx b/src/wizards/index.tsx index f33c8dce93..1d6428594b 100644 --- a/src/wizards/index.tsx +++ b/src/wizards/index.tsx @@ -64,6 +64,15 @@ const components: Record< string, any > = { ) ), }, + 'newspack-audience-donations': { + label: __( 'Audience Donations', 'newspack-plugin' ), + component: lazy( + () => + import( + /* webpackChunkName: "audience-wizards" */ './audience/views/donations' + ) + ), + }, } as const; const AdminPageLoader = ( { label }: { label: string } ) => { diff --git a/src/wizards/readerRevenue/components/index.js b/src/wizards/readerRevenue/components/index.js deleted file mode 100644 index cea2a876da..0000000000 --- a/src/wizards/readerRevenue/components/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default as MoneyInput } from './money-input'; diff --git a/src/wizards/readerRevenue/index.js b/src/wizards/readerRevenue/index.js deleted file mode 100644 index 6ecd543329..0000000000 --- a/src/wizards/readerRevenue/index.js +++ /dev/null @@ -1,86 +0,0 @@ -import '../../shared/js/public-path'; - -/** - * External dependencies. - */ -import values from 'lodash/values'; - -/** - * WordPress dependencies. - */ -import { render, createElement } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; - -/** - * Internal dependencies. - */ -import { Wizard, Notice } from '../../components/src'; -import * as Views from './views'; -import { READER_REVENUE_WIZARD_SLUG, NEWSPACK, NRH, OTHER } from './constants'; - -const ReaderRevenueWizard = () => { - const { platform_data, plugin_status, donation_data } = Wizard.useWizardData( 'reader-revenue' ); - const usedPlatform = platform_data?.platform; - const platformSection = { - label: __( 'Platform', 'newspack' ), - path: '/', - render: Views.Platform, - }; - - let sections = [ - { - label: __( 'Donations', 'newspack' ), - path: '/donations', - render: Views.Donation, - isHidden: usedPlatform === OTHER, - }, - { - label: __( 'Payment Methods', 'newspack' ), - path: '/payment-methods', - activeTabPaths: [ '/payment-methods' ], - render: Views.StripeSetup, - isHidden: usedPlatform !== NEWSPACK, - }, - { - label: __( 'Emails', 'newspack' ), - path: '/emails', - render: Views.Emails, - isHidden: usedPlatform !== NEWSPACK, - }, - { - label: __( 'Salesforce', 'newspack' ), - path: '/salesforce', - render: Views.Salesforce, - isHidden: usedPlatform !== NEWSPACK, - }, - { - label: __( 'News Revenue Hub Settings', 'newspack' ), - path: '/settings', - render: Views.NRHSettings, - isHidden: usedPlatform !== NRH, - }, - platformSection, - ]; - if ( usedPlatform === NEWSPACK && ! plugin_status ) { - sections = [ platformSection ]; - } - return ( - - values( donation_data?.errors ).map( ( error, i ) => ( - - ) ) - } - requiredPlugins={ [ 'newspack-blocks' ] } - /> - ); -}; - -render( - createElement( ReaderRevenueWizard ), - document.getElementById( 'newspack-reader-revenue-wizard' ) -); diff --git a/src/wizards/readerRevenue/views/emails/index.js b/src/wizards/readerRevenue/views/emails/index.js deleted file mode 100644 index e64cb745ae..0000000000 --- a/src/wizards/readerRevenue/views/emails/index.js +++ /dev/null @@ -1,112 +0,0 @@ -/* globals newspack_reader_revenue*/ - -/** - * WordPress dependencies - */ -import apiFetch from '@wordpress/api-fetch'; -import { useState } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; - -/** - * External dependencies - */ -import values from 'lodash/values'; - -/** - * Internal dependencies - */ -import { PluginInstaller, ActionCard, Notice } from '../../../../components/src'; - -const EMAILS = values( newspack_reader_revenue.emails ); -const postType = newspack_reader_revenue.email_cpt; - -const Emails = () => { - const [ pluginsReady, setPluginsReady ] = useState( null ); - const [ error, setError ] = useState( false ); - const [ inFlight, setInFlight ] = useState( false ); - const [ emails, setEmails ] = useState( EMAILS ); - - const updateStatus = ( postId, status ) => { - setError( false ); - setInFlight( true ); - apiFetch( { - path: `/wp/v2/${ postType }/${ postId }`, - method: 'post', - data: { status }, - } ) - .then( () => { - setEmails( - emails.map( email => { - if ( email.post_id === postId ) { - return { ...email, status }; - } - return email; - } ) - ); - } ) - .catch( setError ) - .finally( () => setInFlight( false ) ); - }; - - if ( false === pluginsReady ) { - return ( - <> - - { __( - 'Newspack uses Newspack Newsletters to handle editing email-type content. Please activate this plugin to proceed.', - 'newspack' - ) } - - - { __( 'Until this feature is configured, default receipts will be used.', 'newspack' ) } - - setPluginsReady( res.complete ) } - onInstalled={ () => window.location.reload() } - withoutFooterButton={ true } - /> - - ); - } - - return ( - <> - { emails.map( email => { - const isActive = email.status === 'publish'; - return ( - updateStatus( email.post_id, value ? 'publish' : 'draft' ) } - { ...( isActive - ? {} - : { - notification: __( - 'This email is not active. The default receipt will be used.', - 'newspack' - ), - notificationLevel: 'info', - } ) } - > - { error && ( - - ) } - - ); - } ) } - - ); -}; - -export default Emails; diff --git a/src/wizards/readerRevenue/views/index.js b/src/wizards/readerRevenue/views/index.js deleted file mode 100644 index c92ff44a8c..0000000000 --- a/src/wizards/readerRevenue/views/index.js +++ /dev/null @@ -1,6 +0,0 @@ -export { default as Donation } from './donation'; -export { default as NRHSettings } from './nrh-settings'; -export { default as Platform } from './platform'; -export { default as StripeSetup } from './payment-methods'; -export { default as Emails } from './emails'; -export { default as Salesforce } from './salesforce'; diff --git a/src/wizards/readerRevenue/views/payment-methods/additional-settings.js b/src/wizards/readerRevenue/views/payment-methods/additional-settings.js deleted file mode 100644 index 9884e1e84f..0000000000 --- a/src/wizards/readerRevenue/views/payment-methods/additional-settings.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { CheckboxControl } from '@wordpress/components'; -import { useDispatch } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { - ActionCard, - Button, - Grid, - SectionHeader, - TextControl, - Wizard, -} from '../../../../components/src'; -import { READER_REVENUE_WIZARD_SLUG } from '../../constants'; -import './style.scss'; - -export const AdditionalSettings = ( { settings } ) => { - const { updateWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); - const changeHandler = ( key, value ) => - updateWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, - path: [ 'additional_settings', key ], - value, - } ); - - const { saveWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); - const onSave = () => - saveWizardSettings( { - slug: READER_REVENUE_WIZARD_SLUG, - section: 'settings', - payloadPath: [ 'additional_settings' ], - } ); - - return ( - <> - - { - changeHandler( 'allow_covering_fees', ! settings.allow_covering_fees ); - onSave(); - } } - hasGreyHeader={ settings.allow_covering_fees } - hasWhiteHeader={ ! settings.allow_covering_fees } - actionContent={ settings.allow_covering_fees && ( - - ) } - > - { settings.allow_covering_fees && ( - - changeHandler( 'fee_multiplier', value ) } - /> - changeHandler( 'fee_static', value ) } - /> - changeHandler( 'allow_covering_fees_label', value ) } - /> - changeHandler( 'allow_covering_fees_default', ! settings.allow_covering_fees_default ) } - help={ __( - 'If enabled, the option to cover the transaction fee will be checked by default.', - 'newspack-plugin' - ) } - /> - - ) } - - - ); -} \ No newline at end of file diff --git a/src/wizards/setup/views/services/ReaderRevenue.js b/src/wizards/setup/views/services/ReaderRevenue.js index dc48df0436..01b78ebdde 100644 --- a/src/wizards/setup/views/services/ReaderRevenue.js +++ b/src/wizards/setup/views/services/ReaderRevenue.js @@ -12,12 +12,12 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import Platform from '../../../readerRevenue/views/platform'; -import { DonationAmounts } from '../../../readerRevenue/views/donation'; +import Platform from '../../../audience/components/platform'; +import { DonationAmounts } from '../../../audience/views/donations/configuration'; import { Wizard } from '../../../../components/src'; const ReaderRevenue = ( { className } ) => { - const wizardData = Wizard.useWizardData( 'reader-revenue' ); + const wizardData = Wizard.useWizardData( 'audience-donations' ); return (
diff --git a/src/wizards/setup/views/services/index.js b/src/wizards/setup/views/services/index.js index 2047f6c20c..f54dfd94ec 100644 --- a/src/wizards/setup/views/services/index.js +++ b/src/wizards/setup/views/services/index.js @@ -56,7 +56,7 @@ const Services = ( { renderPrimaryButton } ) => { const [ services, updateServices ] = hooks.useObjectState( SERVICES_LIST ); const [ isLoading, setIsLoading ] = useState( true ); const slugs = keys( services ); - const readerRevenueWizardData = Wizard.useWizardData( 'reader-revenue' ); + const wizardData = Wizard.useWizardData( 'audience-donations' ); useEffect( () => { apiFetch( { @@ -72,7 +72,7 @@ const Services = ( { renderPrimaryButton } ) => { // Add Reader Revenue Wizard data straight from the Wizard. data[ 'reader-revenue' ] = { ...data[ 'reader-revenue' ], - ...readerRevenueWizardData, + ...wizardData, }; return apiFetch( { path: '/newspack/v1/wizard/newspack-setup-wizard/services', diff --git a/src/wizards/syndication/views/intro/index.js b/src/wizards/syndication/views/intro/index.js index 05120b18ba..c01570b577 100644 --- a/src/wizards/syndication/views/intro/index.js +++ b/src/wizards/syndication/views/intro/index.js @@ -10,7 +10,7 @@ import { useDispatch } from '@wordpress/data'; import { PluginToggle, ActionCard, Wizard } from '../../../../components/src'; const Intro = () => { - const settingsData = Wizard.useWizardData( 'settings' ); + const settingsData = Wizard.useWizardData( 'newspack-settings-wizard' ); const { saveWizardSettings } = useDispatch( Wizard.STORE_NAMESPACE ); return ( <> diff --git a/src/wizards/types/hooks.d.ts b/src/wizards/types/hooks.d.ts index b34eb5f484..69db46e6e7 100644 --- a/src/wizards/types/hooks.d.ts +++ b/src/wizards/types/hooks.d.ts @@ -55,4 +55,31 @@ type WizardData = { // Define the type for the selector's return value type WizardSelector = { getWizardData: ( slug: string ) => WizardData; + isLoading: () => boolean; +}; + +/** + * Reader Revenue Wizard Data + */ +type AudienceDonationsWizardData = { + donation_data: + | { errors: { [ key: string ]: string[] } } + | { + amounts: { + [ Key in FrequencySlug as string ]: [ number, number, number, number ]; + }; + disabledFrequencies: { + [ Key in FrequencySlug as string ]: boolean; + }; + currencySymbol: string; + tiered: boolean; + minimumDonation: string; + }; + platform_data: { + platform: string; + }; + donation_page: { + editUrl: string; + status: string; + }; }; diff --git a/src/wizards/types/window.d.ts b/src/wizards/types/window.d.ts index 12f67b0897..c7df99e387 100644 --- a/src/wizards/types/window.d.ts +++ b/src/wizards/types/window.d.ts @@ -45,7 +45,7 @@ declare global { name: string; } >; }; - newspack_reader_revenue: { + newspackAudienceDonations: { can_use_name_your_price: boolean; }; } diff --git a/src/wizards/wizards-tab.tsx b/src/wizards/wizards-tab.tsx index 04eb259d78..0e9e299991 100644 --- a/src/wizards/wizards-tab.tsx +++ b/src/wizards/wizards-tab.tsx @@ -1,3 +1,13 @@ +/** + * WordPress dependencies. + */ +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies. + */ +import { WIZARD_STORE_NAMESPACE } from '../components/src/wizard/store'; + /** * Wizards Tab component. */ @@ -15,11 +25,16 @@ function WizardsTab( { className?: string; description?: React.ReactNode; } ) { + const isWizardLoading = useSelect( + ( select: ( namespace: string ) => WizardSelector ) => + select( WIZARD_STORE_NAMESPACE ).isLoading(), + [] + ); const className = props.className || ''; return (

{ title }

diff --git a/tests/unit-tests/api-wizards-controller.php b/tests/unit-tests/api-wizards-controller.php index e5126feb76..8423c3973a 100644 --- a/tests/unit-tests/api-wizards-controller.php +++ b/tests/unit-tests/api-wizards-controller.php @@ -17,7 +17,7 @@ class Newspack_Test_Wizards_Controller extends WP_UnitTestCase { * * @var string */ - protected $api_route = '/newspack/v1/wizards/reader-revenue'; + protected $api_route = '/newspack/v1/wizards/site-design'; /** * Set up stuff for testing API requests. @@ -61,7 +61,7 @@ public function test_get_wizard_authorized() { $this->assertEquals( 200, $response->get_status() ); $data = $response->get_data(); - $this->assertEquals( 'Reader Revenue', $data['name'] ); + $this->assertEquals( 'Site Design', $data['name'] ); } /**