Skip to content

Commit

Permalink
Connect in Place: Prompt Plans after connection (#13348)
Browse files Browse the repository at this point in the history
* 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 `<PlansPrompt />` component out of the main `render` method.

* Add `<JetpackLogo />` component readme file.

* Redirect to dashboard if the user is on a paid plan.


Co-authored-by: Piotr Delawski <piotr.delawski@xwp.co>
Co-authored-by: Piotr Delawski <delawski@users.noreply.github.com>
  • Loading branch information
3 people authored and jeherve committed Aug 30, 2019
1 parent 9bb5468 commit 3dd06e7
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 25 deletions.
5 changes: 5 additions & 0 deletions _inc/client/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ function render() {
name={ i18n.translate( 'Plans', { context: 'Navigation item.' } ) }
component={ Main }
/>
<Route
path="/plans-prompt"
name={ i18n.translate( 'Plans', { context: 'Navigation item.' } ) }
component={ Main }
/>
<Route
path="/settings"
name={ i18n.translate( 'Settings', { context: 'Navigation item.' } ) }
Expand Down
18 changes: 18 additions & 0 deletions _inc/client/components/jetpack-logo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
JetpackLogo
========

Component that renders the Jetpack SVG logo.
It consists of the Jetpack symbol followed by the name.
It takes width and height properties but defaults to 32px in height.

#### How to use:

```js
<JetpackLogo height={ 48 } className="jp-logo" />
```

#### 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.
44 changes: 44 additions & 0 deletions _inc/client/components/jetpack-logo/index.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<svg
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
viewBox="0 0 118 32"
{ ...this.props }
>
<path
fill="#00BE28"
d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M15,19H7l8-16V19z M17,29V13h8L17,29z"
/>
<path d="M41.3,26.6c-0.5-0.7-0.9-1.4-1.3-2.1c2.3-1.4,3-2.5,3-4.6V8h-3V6h6v13.4C46,22.8,45,24.8,41.3,26.6z" />
<path d="M65,18.4c0,1.1,0.8,1.3,1.4,1.3c0.5,0,2-0.2,2.6-0.4v2.1c-0.9,0.3-2.5,0.5-3.7,0.5c-1.5,0-3.2-0.5-3.2-3.1V12H60v-2h2.1V7.1 H65V10h4v2h-4V18.4z" />
<path d="M71,10h3v1.3c1.1-0.8,1.9-1.3,3.3-1.3c2.5,0,4.5,1.8,4.5,5.6s-2.2,6.3-5.8,6.3c-0.9,0-1.3-0.1-2-0.3V28h-3V10z M76.5,12.3 c-0.8,0-1.6,0.4-2.5,1.2v5.9c0.6,0.1,0.9,0.2,1.8,0.2c2,0,3.2-1.3,3.2-3.9C79,13.4,78.1,12.3,76.5,12.3z" />
<path d="M93,22h-3v-1.5c-0.9,0.7-1.9,1.5-3.5,1.5c-1.5,0-3.1-1.1-3.1-3.2c0-2.9,2.5-3.4,4.2-3.7l2.4-0.3v-0.3c0-1.5-0.5-2.3-2-2.3 c-0.7,0-2.3,0.5-3.7,1.1L84,11c1.2-0.4,3-1,4.4-1c2.7,0,4.6,1.4,4.6,4.7L93,22z M90,16.4l-2.2,0.4c-0.7,0.1-1.4,0.5-1.4,1.6 c0,0.9,0.5,1.4,1.3,1.4s1.5-0.5,2.3-1V16.4z" />
<path d="M104.5,21.3c-1.1,0.4-2.2,0.6-3.5,0.6c-4.2,0-5.9-2.4-5.9-5.9c0-3.7,2.3-6,6.1-6c1.4,0,2.3,0.2,3.2,0.5V13 c-0.8-0.3-2-0.6-3.2-0.6c-1.7,0-3.2,0.9-3.2,3.6c0,2.9,1.5,3.8,3.3,3.8c0.9,0,1.9-0.2,3.2-0.7V21.3z" />
<path d="M110,15.2c0.2-0.3,0.2-0.8,3.8-5.2h3.7l-4.6,5.7l5,6.3h-3.7l-4.2-5.8V22h-3V6h3V15.2z" />
<path d="M58.5,21.3c-1.5,0.5-2.7,0.6-4.2,0.6c-3.6,0-5.8-1.8-5.8-6c0-3.1,1.9-5.9,5.5-5.9s4.9,2.5,4.9,4.9c0,0.8,0,1.5-0.1,2h-7.3 c0.1,2.5,1.5,2.8,3.6,2.8c1.1,0,2.2-0.3,3.4-0.7C58.5,19,58.5,21.3,58.5,21.3z M56,15c0-1.4-0.5-2.9-2-2.9c-1.4,0-2.3,1.3-2.4,2.9 C51.6,15,56,15,56,15z" />
</svg>
);
}
}

export default JetpackLogo;
22 changes: 2 additions & 20 deletions _inc/client/components/masthead/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -76,26 +77,7 @@ export class Masthead extends React.Component {
<div className="jp-masthead__inside-container">
<div className="jp-masthead__logo-container">
<a onClick={ this.trackLogoClick } className="jp-masthead__logo-link" href="#dashboard">
<svg
className="jetpack-logo__masthead"
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
height="32"
viewBox="0 0 118 32"
>
<path
fill="#00BE28"
d="M16,0C7.2,0,0,7.2,0,16s7.2,16,16,16s16-7.2,16-16S24.8,0,16,0z M15,19H7l8-16V19z M17,29V13h8L17,29z"
/>
<path d="M41.3,26.6c-0.5-0.7-0.9-1.4-1.3-2.1c2.3-1.4,3-2.5,3-4.6V8h-3V6h6v13.4C46,22.8,45,24.8,41.3,26.6z" />
<path d="M65,18.4c0,1.1,0.8,1.3,1.4,1.3c0.5,0,2-0.2,2.6-0.4v2.1c-0.9,0.3-2.5,0.5-3.7,0.5c-1.5,0-3.2-0.5-3.2-3.1V12H60v-2h2.1V7.1 H65V10h4v2h-4V18.4z" />
<path d="M71,10h3v1.3c1.1-0.8,1.9-1.3,3.3-1.3c2.5,0,4.5,1.8,4.5,5.6s-2.2,6.3-5.8,6.3c-0.9,0-1.3-0.1-2-0.3V28h-3V10z M76.5,12.3 c-0.8,0-1.6,0.4-2.5,1.2v5.9c0.6,0.1,0.9,0.2,1.8,0.2c2,0,3.2-1.3,3.2-3.9C79,13.4,78.1,12.3,76.5,12.3z" />
<path d="M93,22h-3v-1.5c-0.9,0.7-1.9,1.5-3.5,1.5c-1.5,0-3.1-1.1-3.1-3.2c0-2.9,2.5-3.4,4.2-3.7l2.4-0.3v-0.3c0-1.5-0.5-2.3-2-2.3 c-0.7,0-2.3,0.5-3.7,1.1L84,11c1.2-0.4,3-1,4.4-1c2.7,0,4.6,1.4,4.6,4.7L93,22z M90,16.4l-2.2,0.4c-0.7,0.1-1.4,0.5-1.4,1.6 c0,0.9,0.5,1.4,1.3,1.4s1.5-0.5,2.3-1V16.4z" />
<path d="M104.5,21.3c-1.1,0.4-2.2,0.6-3.5,0.6c-4.2,0-5.9-2.4-5.9-5.9c0-3.7,2.3-6,6.1-6c1.4,0,2.3,0.2,3.2,0.5V13 c-0.8-0.3-2-0.6-3.2-0.6c-1.7,0-3.2,0.9-3.2,3.6c0,2.9,1.5,3.8,3.3,3.8c0.9,0,1.9-0.2,3.2-0.7V21.3z" />
<path d="M110,15.2c0.2-0.3,0.2-0.8,3.8-5.2h3.7l-4.6,5.7l5,6.3h-3.7l-4.2-5.8V22h-3V6h3V15.2z" />
<path d="M58.5,21.3c-1.5,0.5-2.7,0.6-4.2,0.6c-3.6,0-5.8-1.8-5.8-6c0-3.1,1.9-5.9,5.5-5.9s4.9,2.5,4.9,4.9c0,0.8,0,1.5-0.1,2h-7.3 c0.1,2.5,1.5,2.8,3.6,2.8c1.1,0,2.2-0.3,3.4-0.7C58.5,19,58.5,21.3,58.5,21.3z M56,15c0-1.4-0.5-2.9-2-2.9c-1.4,0-2.3,1.3-2.4,2.9 C51.6,15,56,15,56,15z" />
</svg>
<JetpackLogo className="jetpack-logo__masthead" />
</a>
{ devNotice }
{ sandboxedBadge }
Expand Down
30 changes: 27 additions & 3 deletions _inc/client/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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() {
Expand Down Expand Up @@ -211,6 +213,10 @@ class Main extends React.Component {
/>
);
break;
case '/plans-prompt':
navComponent = null;
pageComponent = <PlansPrompt siteAdminUrl={ this.props.siteAdminUrl } />;
break;
case '/settings':
case '/security':
case '/performance':
Expand Down Expand Up @@ -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 (
<div>
<Masthead route={ this.props.route } />
{ this.shouldShowMasthead() && <Masthead route={ this.props.route } /> }
<div className="jp-lower">
{ this.props.isSiteConnected && <QueryRewindStatus /> }
{ this.shouldShowRewindStatus() && <QueryRewindStatus /> }
<AdminNotices />
<JetpackNotices />
{ this.renderMainContent( this.props.route.path ) }
{ this.shouldShowSupportCard() && <SupportCard path={ this.props.route.path } /> }
{ this.shouldShowAppsCard() && <AppsCard /> }
</div>
<Footer siteAdminUrl={ this.props.siteAdminUrl } />
{ this.shouldShowFooter() && <Footer siteAdminUrl={ this.props.siteAdminUrl } /> }
<Tracker analytics={ analytics } />
</div>
);
Expand Down
61 changes: 61 additions & 0 deletions _inc/client/plans-prompt/index.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="plans-prompt__banner">
<JetpackLogo className="plans-prompt__logo" />
<h2 className="plans-prompt__heading">{ __( 'Explore our Jetpack plans' ) }</h2>
<p className="plans-prompt__intro">
{ __( "Now that you're set up, pick a plan that fits your needs." ) }
</p>
</div>
);
}

renderFooter() {
return (
<div className="plans-prompt__footer">
<Button
href={ this.props.siteAdminUrl + 'admin.php?page=jetpack' }
onClick={ this.trackStartWithFreeClick }
>
{ __( 'Start with free' ) }
<Gridicon icon={ 'arrow-right' } size={ 18 } />
</Button>
</div>
);
}

render() {
return (
<div className="plans-prompt">
{ this.renderBanner() }
<Plans />
{ this.renderFooter() }
</div>
);
}
}

export default PlansPrompt;
24 changes: 24 additions & 0 deletions _inc/client/plans-prompt/style.scss
Original file line number Diff line number Diff line change
@@ -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;
}
}
3 changes: 2 additions & 1 deletion _inc/client/plans/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions _inc/client/scss/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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';
24 changes: 23 additions & 1 deletion _inc/connect-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jQuery( document ).ready( function( $ ) {

var jetpackConnectButton = {
isRegistering: false,
isPaidPlan: false,
startConnectionFlow: function() {
var abTestName = 'jetpack_connect_in_place';
$.ajax( {
Expand All @@ -45,6 +46,7 @@ jQuery( document ).ready( function( $ ) {
.text( jpConnect.buttonTextRegistering )
.attr( 'disabled', true )
.blur();

$.ajax( {
url: jpConnect.apiBaseUrl + '/connection/register',
type: 'POST',
Expand All @@ -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 &&
Expand All @@ -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 );
Expand Down
3 changes: 3 additions & 0 deletions class.jetpack-connection-banner.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' ),
)
);
}
Expand Down

0 comments on commit 3dd06e7

Please sign in to comment.