From 3dd06e7ee554df0e4c6ee252a1ccf57bcebdc4c0 Mon Sep 17 00:00:00 2001 From: Miguel Lezama Date: Fri, 30 Aug 2019 09:47:26 -0300 Subject: [PATCH] Connect in Place: Prompt Plans after connection (#13348) * thanks Piotr! [not verified] * Move plans prompt to a separate screen. * fix free plan link * fix mobile card not hiding * Use a separate selector to prevent potential bugs. * Add Jetpack logo at the top of the plans prompt page. * Update _inc/client/admin.js Co-Authored-By: Marin Atanasov <8436925+tyxla@users.noreply.github.com> * Extract Jetpack logo to a separate component since it's used twice. * Predefine redirect URL after successful authorization. * Add 'Start with free' button clicks tracking. * Update tracking target name. * Hard-code some of the Jetpack logo's SVG properties. * Move `` component out of the main `render` method. * Add `` component readme file. * Redirect to dashboard if the user is on a paid plan. Co-authored-by: Piotr Delawski Co-authored-by: Piotr Delawski --- _inc/client/admin.js | 5 ++ _inc/client/components/jetpack-logo/README.md | 18 ++++++ _inc/client/components/jetpack-logo/index.jsx | 44 +++++++++++++ _inc/client/components/masthead/index.jsx | 22 +------ _inc/client/main.jsx | 30 ++++++++- _inc/client/plans-prompt/index.jsx | 61 +++++++++++++++++++ _inc/client/plans-prompt/style.scss | 24 ++++++++ _inc/client/plans/style.scss | 3 +- _inc/client/scss/style.scss | 1 + _inc/connect-button.js | 24 +++++++- class.jetpack-connection-banner.php | 3 + 11 files changed, 210 insertions(+), 25 deletions(-) create mode 100644 _inc/client/components/jetpack-logo/README.md create mode 100644 _inc/client/components/jetpack-logo/index.jsx create mode 100644 _inc/client/plans-prompt/index.jsx create mode 100644 _inc/client/plans-prompt/style.scss diff --git a/_inc/client/admin.js b/_inc/client/admin.js index d699bcb8c5819..277c40d0ba1b0 100644 --- a/_inc/client/admin.js +++ b/_inc/client/admin.js @@ -85,6 +85,11 @@ function render() { name={ i18n.translate( 'Plans', { context: 'Navigation item.' } ) } component={ Main } /> + +``` + +#### Props + +* `className`: String - (default: `jetpack-logo`) the class name set on the SVG element. +* `height`: Number - (default: 32) set the height of the logo. +* `width`: Number - (optional) set the width of the logo. diff --git a/_inc/client/components/jetpack-logo/index.jsx b/_inc/client/components/jetpack-logo/index.jsx new file mode 100644 index 0000000000000..74d58422ea68a --- /dev/null +++ b/_inc/client/components/jetpack-logo/index.jsx @@ -0,0 +1,44 @@ +/** + * External dependencies + */ +import PropTypes from 'prop-types'; +import React from 'react'; + +class JetpackLogo extends React.Component { + static propTypes = { + className: PropTypes.string, + width: PropTypes.number, + height: PropTypes.number, + }; + + static defaultProps = { + className: 'jetpack-logo', + height: 32, + }; + + render() { + return ( + + + + + + + + + + + ); + } +} + +export default JetpackLogo; diff --git a/_inc/client/components/masthead/index.jsx b/_inc/client/components/masthead/index.jsx index 6058355616c90..cedc7333d0802 100644 --- a/_inc/client/components/masthead/index.jsx +++ b/_inc/client/components/masthead/index.jsx @@ -18,6 +18,7 @@ import { fetchSiteConnectionTest, } from 'state/connection'; import { getCurrentVersion, userCanEditPosts } from 'state/initial-state'; +import JetpackLogo from '../jetpack-logo'; export class Masthead extends React.Component { static defaultProps = { @@ -76,26 +77,7 @@ export class Masthead extends React.Component {
- - - - - - - - - - + { devNotice } { sandboxedBadge } diff --git a/_inc/client/main.jsx b/_inc/client/main.jsx index da4c816effec7..6521c91a6cbce 100644 --- a/_inc/client/main.jsx +++ b/_inc/client/main.jsx @@ -32,6 +32,7 @@ import { getSearchTerm } from 'state/search'; import AtAGlance from 'at-a-glance/index.jsx'; import MyPlan from 'my-plan/index.jsx'; import Plans from 'plans/index.jsx'; +import PlansPrompt from 'plans-prompt/index.jsx'; import Footer from 'components/footer'; import SupportCard from 'components/support-card'; import AppsCard from 'components/apps-card'; @@ -45,6 +46,7 @@ import QueryRewindStatus from 'components/data/query-rewind-status'; import { getRewindStatus } from 'state/rewind'; const dashboardRoutes = [ '#/', '#/dashboard', '#/my-plan', '#/plans' ]; +const plansPromptRoute = '#/plans-prompt'; class Main extends React.Component { UNSAFE_componentWillMount() { @@ -211,6 +213,10 @@ class Main extends React.Component { /> ); break; + case '/plans-prompt': + navComponent = null; + pageComponent = ; + break; case '/settings': case '/security': case '/performance': @@ -266,19 +272,37 @@ class Main extends React.Component { return this.props.isSiteConnected && includes( dashboardRoutes, hashRoute ); } + shouldShowRewindStatus() { + // Do not show on plans prompt page + const hashRoute = '#' + this.props.route.path; + return this.props.isSiteConnected && hashRoute !== plansPromptRoute; + } + + shouldShowMasthead() { + // Do not show on plans prompt page + const hashRoute = '#' + this.props.route.path; + return hashRoute !== plansPromptRoute; + } + + shouldShowFooter() { + // Do not show on plans prompt page + const hashRoute = '#' + this.props.route.path; + return hashRoute !== plansPromptRoute; + } + render() { return (
- + { this.shouldShowMasthead() && }
- { this.props.isSiteConnected && } + { this.shouldShowRewindStatus() && } { this.renderMainContent( this.props.route.path ) } { this.shouldShowSupportCard() && } { this.shouldShowAppsCard() && }
-
+ { this.shouldShowFooter() &&
}
); diff --git a/_inc/client/plans-prompt/index.jsx b/_inc/client/plans-prompt/index.jsx new file mode 100644 index 0000000000000..3f6015d6f6206 --- /dev/null +++ b/_inc/client/plans-prompt/index.jsx @@ -0,0 +1,61 @@ +/** + * External dependencies + */ +import React from 'react'; + +/** + * Internal dependencies + */ +import analytics from 'lib/analytics'; +import Button from 'components/button'; +import Plans from '../plans'; +import { translate as __ } from 'i18n-calypso'; +import Gridicon from '../components/gridicon'; +import JetpackLogo from '../components/jetpack-logo'; + +export class PlansPrompt extends React.Component { + trackStartWithFreeClick() { + analytics.tracks.recordJetpackClick( { + target: 'free-plan', + feature: 'plans-prompt', + } ); + } + + renderBanner() { + return ( +
+ +

{ __( 'Explore our Jetpack plans' ) }

+

+ { __( "Now that you're set up, pick a plan that fits your needs." ) } +

+
+ ); + } + + renderFooter() { + return ( +
+ +
+ ); + } + + render() { + return ( +
+ { this.renderBanner() } + + { this.renderFooter() } +
+ ); + } +} + +export default PlansPrompt; diff --git a/_inc/client/plans-prompt/style.scss b/_inc/client/plans-prompt/style.scss new file mode 100644 index 0000000000000..7f1f16cbdb063 --- /dev/null +++ b/_inc/client/plans-prompt/style.scss @@ -0,0 +1,24 @@ +.plans-prompt__banner { + padding: 32px 0; + text-align: center; +} + +.plans-prompt__heading { + font-size: 22px; + margin-bottom: 0; +} + +.plans-prompt__intro { + font-size: 14px; + margin-top: 0.5em; +} + +.plans-prompt__footer { + margin: 2em 0; + text-align: center; + + .dops-button .gridicon { + padding-left: 4px; + margin-right: -5px; + } +} diff --git a/_inc/client/plans/style.scss b/_inc/client/plans/style.scss index cebbbbf36d054..bc285970ce357 100644 --- a/_inc/client/plans/style.scss +++ b/_inc/client/plans/style.scss @@ -207,7 +207,8 @@ $plan-features-sidebar-width: 272px; } } -.plans-mobile-notice { +.plans-mobile-notice, +.plans-mobile-notice.dops-card { @include breakpoint( ">660px" ) { display: none; } diff --git a/_inc/client/scss/style.scss b/_inc/client/scss/style.scss index bd263be1bee4e..d9f990c3040de 100644 --- a/_inc/client/scss/style.scss +++ b/_inc/client/scss/style.scss @@ -52,5 +52,6 @@ @import '../at-a-glance/style'; @import '../my-plan/style'; @import '../plans/style'; +@import '../plans-prompt/style'; @import '../settings/style'; @import '../traffic/style'; diff --git a/_inc/connect-button.js b/_inc/connect-button.js index ed03aa1873a0c..009b86f3daf4c 100644 --- a/_inc/connect-button.js +++ b/_inc/connect-button.js @@ -21,6 +21,7 @@ jQuery( document ).ready( function( $ ) { var jetpackConnectButton = { isRegistering: false, + isPaidPlan: false, startConnectionFlow: function() { var abTestName = 'jetpack_connect_in_place'; $.ajax( { @@ -45,6 +46,7 @@ jQuery( document ).ready( function( $ ) { .text( jpConnect.buttonTextRegistering ) .attr( 'disabled', true ) .blur(); + $.ajax( { url: jpConnect.apiBaseUrl + '/connection/register', type: 'POST', @@ -54,12 +56,26 @@ jQuery( document ).ready( function( $ ) { }, error: jetpackConnectButton.handleConnectionError, success: function( data ) { + jetpackConnectButton.fetchPlanType(); window.addEventListener( 'message', jetpackConnectButton.receiveData ); jetpackConnectIframe.attr( 'src', data.authorizeUrl ); $( '.jp-connect-full__button-container' ).html( jetpackConnectIframe ); }, } ); }, + fetchPlanType: function() { + $.ajax( { + url: jpConnect.apiBaseUrl + '/site', + type: 'GET', + data: { + _wpnonce: jpConnect.apiSiteDataNonce, + }, + success: function( data ) { + var siteData = JSON.parse( data.data ); + jetpackConnectButton.isPaidPlan = ! siteData.plan.is_free; + }, + } ); + }, receiveData: function( event ) { if ( event.origin === jpConnect.jetpackApiDomain && @@ -72,7 +88,13 @@ jQuery( document ).ready( function( $ ) { }, handleAuthorizationComplete: function() { jetpackConnectButton.isRegistering = false; - location.reload(); + + if ( jetpackConnectButton.isPaidPlan ) { + window.location.assign( jpConnect.dashboardUrl ); + } else { + window.location.assign( jpConnect.plansPromptUrl ); + } + window.location.reload( true ); }, handleConnectionError: function( error ) { console.warn( 'Connection failed. Falling back to the regular flow', error ); diff --git a/class.jetpack-connection-banner.php b/class.jetpack-connection-banner.php index cf701c7e74229..5c629d571f53f 100644 --- a/class.jetpack-connection-banner.php +++ b/class.jetpack-connection-banner.php @@ -165,9 +165,12 @@ public static function enqueue_connect_button_scripts() { 'apiBaseUrl' => site_url( '/wp-json/jetpack/v4' ), 'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ), 'apiNonce' => wp_create_nonce( 'wp_rest' ), + 'apiSiteDataNonce' => wp_create_nonce( 'wp_rest' ), 'buttonTextRegistering' => __( 'Loading...', 'jetpack' ), 'jetpackApiDomain' => $jetpackApiUrl['scheme'] . '://' . $jetpackApiUrl['host'], 'forceVariation' => $force_variation, + 'dashboardUrl' => Jetpack::admin_url( 'page=jetpack#/dashboard' ), + 'plansPromptUrl' => Jetpack::admin_url( 'page=jetpack#/plans-prompt' ), ) ); }