Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugins (wpcom): Update design and text #4995

Merged
merged 7 commits into from
Apr 27, 2016
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions client/my-sites/plugins-wpcom/business-plugins-panel.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import classNames from 'classnames';

import Card from 'components/card';
import SectionHeader from 'components/section-header';
import BusinessPlugin from './plugin-types/business-plugin';
import PurchaseButton from './purchase-button';
import { recordTracksEvent } from 'state/analytics/actions';

import Plugin from './plugin';

export const BusinessPluginsPanel = React.createClass( {
render() {
const {
isActive = false,
onClick,
purchaseLink,
plugins = []
} = this.props;
Expand All @@ -26,9 +30,10 @@ export const BusinessPluginsPanel = React.createClass( {

<Card className={ cardClasses }>
<div className="wpcom-plugins__list">
{ plugins.map( ( { name, descriptionLink, icon, plan, description } ) =>
<BusinessPlugin
{ ...{ name, key: name, descriptionLink, icon, plan, description } }
{ plugins.map( ( { name, descriptionLink, icon, category, description } ) =>
<Plugin
onClick={ () => onClick( name ) }
{ ...{ name, key: name, descriptionLink, icon, category, description } }
/>
) }
</div>
Expand All @@ -44,4 +49,17 @@ BusinessPluginsPanel.propTypes = {
plugins: PropTypes.array
};

export default BusinessPluginsPanel;
const trackClick = name => recordTracksEvent(
'calypso_plugin_wpcom_click',
{
plugin_name: name,
plugin_plan: 'business'
}
);

const mapDispatchToProps = dispatch => ( {
onClick: name => dispatch( trackClick( name ) )
} );

export default connect( null, mapDispatchToProps )( BusinessPluginsPanel );

20 changes: 10 additions & 10 deletions client/my-sites/plugins-wpcom/default-plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ export const defaultStandardPlugins = [
description: i18n.translate( 'Advanced anti-spam security.' )
},
{
name: i18n.translate( 'Backup' ),
name: i18n.translate( 'Backup & Export' ),
descriptionLink: 'https://en.support.wordpress.com/export/#backups',
icon: 'lock',
category: 'Security',
description: i18n.translate( '24/7 backup of your entire site.' )
description: i18n.translate( '24/7 backup of your entire site. Export everything.' )
},
{
name: i18n.translate( 'Photon CDN' ),
Expand Down Expand Up @@ -100,7 +100,7 @@ export const defaultStandardPlugins = [
descriptionLink: 'https://en.support.wordpress.com/infinite-scroll/',
icon: 'posts',
category: 'Appearance',
description: i18n.translate( 'Load more posts when you reach the bottom of a page.' )
description: i18n.translate( 'Load more posts when you reach the bottom of a page on your site.' )
},
{
name: i18n.translate( 'Related Posts' ),
Expand All @@ -124,7 +124,7 @@ export const defaultStandardPlugins = [
description: i18n.translate( 'Text formatting using a lightweight markup language. ' )
},
{
name: i18n.translate( 'Advanced Commenting' ),
name: i18n.translate( 'Advanced Comments' ),
descriptionLink: 'https://en.support.wordpress.com/category/comments/',
icon: 'comment',
category: 'Misc',
Expand All @@ -140,21 +140,21 @@ export const defaultPremiumPlugins = [
name: i18n.translate( 'No Advertising' ),
descriptionLink: 'https://en.support.wordpress.com/no-ads/',
icon: 'block',
plan: 'Premium',
description: i18n.translate( 'Remove all ads from your site.' )
category: 'Premium',
description: i18n.translate( 'Remove WordPress.com ads from your site.' )
},
{
name: i18n.translate( 'Custom Design' ),
descriptionLink: 'https://en.support.wordpress.com/custom-design/',
icon: 'customize',
plan: 'Premium',
category: 'Premium',
description: i18n.translate( 'Customize your blog\'s look with custom fonts, a CSS editor, and more.' )
},
{
name: i18n.translate( 'Video Uploads' ),
descriptionLink: 'https://en.support.wordpress.com/videopress/',
icon: 'video-camera',
plan: 'Premium',
category: 'Premium',
description: i18n.translate( 'Upload and host your video files on your site with VideoPress.' )
}
];
Expand All @@ -165,9 +165,9 @@ export const defaultPremiumPlugins = [
export const defaultBusinessPlugins = [
{
name: i18n.translate( 'Google Analytics' ),
descriptionLink: '/plans/features/google-analytics/{siteSlug}',
descriptionLink: '/categorys/features/google-analytics/{siteSlug}',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

categories?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question marks?

not sure I understand what you are commenting here @gwwar 😉

maybe this is a typo and it needs to remain plans - I did a find/replace so that's probably it

icon: 'stats',
plan: 'Business',
category: 'Business',
description: i18n.translate( 'Advanced features to complement WordPress.com stats. Funnel reports, goal conversion, and more.' )
}
];
73 changes: 0 additions & 73 deletions client/my-sites/plugins-wpcom/plugin-types/business-plugin.jsx

This file was deleted.

57 changes: 0 additions & 57 deletions client/my-sites/plugins-wpcom/plugin-types/premium-plugin.jsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import get from 'lodash/get';
import noop from 'lodash/noop';

import { recordTracksEvent } from 'state/analytics/actions';

import Gridicon from 'components/gridicon';

export const StandardPlugin = React.createClass( {
const hasHttpProtocol = url => ( /^https?:\/\//.test( url ) );

export const Plugin = React.createClass( {
getInitialState() {
return { isUnderMouse: false };
},

startHover() {
this.setState( { isUnderMouse: true } );
},

stopHover() {
this.setState( { isUnderMouse: false } );
},

render() {
const {
category,
Expand All @@ -18,11 +28,29 @@ export const StandardPlugin = React.createClass( {
descriptionLink
} = this.props;

const { isUnderMouse } = this.state;

const isExternalLink = hasHttpProtocol( descriptionLink );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add this as a prop, instead of testing for this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gwwar we deliberated on this point and I think it's best to keep the logic contained inside this component. it's only effect is visual and I don't think there's any need to couple that to the "outside world" I like being able to only care about adding the URL in the plugin data structure instead of having to think about how to represent that data.


const target = isExternalLink
? '_blank'
: '_self';

const linkIcon = ( isExternalLink && isUnderMouse )
? 'external'
: icon;

return (
<div className="wpcom-plugins__plugin-item">
<a onClick={ onClick } href={ descriptionLink } target="_blank">
<a
href={ descriptionLink }
onClick={ onClick }
onMouseEnter={ this.startHover }
onMouseLeave={ this.stopHover }
target={ target }
>
<div className="wpcom-plugins__plugin-icon">
<Gridicon { ...{ icon } } />
<Gridicon icon={ linkIcon } />
</div>
<div className="wpcom-plugins__plugin-title">{ name }</div>
<div className="wpcom-plugins__plugin-category">{ category }</div>
Expand All @@ -33,7 +61,7 @@ export const StandardPlugin = React.createClass( {
}
} );

StandardPlugin.propTypes = {
Plugin.propTypes = {
category: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
icon: PropTypes.string,
Expand All @@ -42,16 +70,4 @@ StandardPlugin.propTypes = {
descriptionLink: PropTypes.string.isRequired
};

const trackClick = name => recordTracksEvent(
'calypso_plugin_wpcom_click',
{
plugin_name: name,
plugin_plan: 'standard'
}
);

const mapDispatchToProps = ( dispatch, props ) => ( {
onClick: get( props, 'onClick', () => dispatch( trackClick( props.name ) ) )
} );

export default connect( null, mapDispatchToProps )( StandardPlugin );
export default Plugin;
27 changes: 22 additions & 5 deletions client/my-sites/plugins-wpcom/premium-plugins-panel.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import classNames from 'classnames';

import Card from 'components/card';
import SectionHeader from 'components/section-header';
import PremiumPlugin from './plugin-types/premium-plugin';
import PurchaseButton from './purchase-button';
import { recordTracksEvent } from 'state/analytics/actions';

import Plugin from './plugin';

export const PremiumPluginsPanel = React.createClass( {
render() {
const {
isActive = false,
onClick,
purchaseLink,
plugins = []
} = this.props;
Expand All @@ -26,9 +30,10 @@ export const PremiumPluginsPanel = React.createClass( {

<Card className={ cardClasses }>
<div className="wpcom-plugins__list">
{ plugins.map( ( { name, descriptionLink, icon, plan, description } ) =>
<PremiumPlugin
{ ...{ name, key: name, descriptionLink, icon, plan, description } }
{ plugins.map( ( { name, descriptionLink, icon, category, description } ) =>
<Plugin
onClick={ () => onClick( name ) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can avoid a fat arrow here, if we move the default analytics tracking down a level to the Plugin component. The Plugin component will have name available as a prop.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was difficult. The plugin component is the same regardless of the plan level, so the analytics code needs to know whether it's for a standard, premium, or business plugin. I tried hard to eliminate the fat-arrow function but didn't find any good way to do so. Granted, I could eliminate it per se, but the underlying process (creating a new closure) was going to happen regardless. I chose to keep it here where it was obvious to someone reading the code.

For example, I could have made onClick = name => () => dispatch( tracking( name ) ) but that would hide what's happening and I think that takes a step away from what we want semantically to happen.

Further, I didn't want to arbitrarily add props to the plugin piece itself or its onClick function because I felt that the meaning of onClick should be just that: a generic function that gets called when the plugin is clicked, verses some specialized function taking specific parameters.

Feel free to disagree and point out why you think this is wrong.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:) The fat arrow warnings are non-blocking, but its just nice if we can avoid them.

Another alternative is to let the plugin provide an interface, where the plugin prop values are provided, and we pass through a trackClick function.

In Plugin:

onClick() {
     this.props.trackClick( this.props );
     this.props.onClick();
}

{ ...{ name, key: name, descriptionLink, icon, category, description } }
/>
) }
</div>
Expand All @@ -44,4 +49,16 @@ PremiumPluginsPanel.propTypes = {
plugins: PropTypes.array
};

export default PremiumPluginsPanel;
const trackClick = name => recordTracksEvent(
'calypso_plugin_wpcom_click',
{
plugin_name: name,
plugin_plan: 'premium'
}
);

const mapDispatchToProps = dispatch => ( {
onClick: name => dispatch( trackClick( name ) )
} );

export default connect( null, mapDispatchToProps )( PremiumPluginsPanel );
Loading