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

Support: Add concierge offer to contact form #16144

Merged
merged 8 commits into from
Jul 14, 2017
66 changes: 66 additions & 0 deletions client/me/help/chat-business-concierge-notice/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* External dependencies
*/
import { identity } from 'lodash';
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import i18n, { localize } from 'i18n-calypso';

/**
* Internal dependencies
*/
import analytics from 'lib/analytics';
import HelpTeaserButton from '../help-teaser-button';
import { isBusinessPlanUser } from 'state/selectors';

class ChatBusinessConciergeNotice extends Component {
static propTypes = {
translate: PropTypes.func,
isBusinessPlanUser: PropTypes.bool.isRequired,
from: PropTypes.string.isRequired,
to: PropTypes.string.isRequired,
};

static defaultProps = {
translate: identity,
};

trackCalendlyOfferClick = () => {
analytics.tracks.recordEvent( 'calypso_help_calendly_offer_click' );
};

render = () => {
const { translate } = this.props;
Copy link
Contributor

Choose a reason for hiding this comment

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

Just nitpicking around, not a blocker but I guess we could destructure all used props here instead of using this.props

const fromDate = i18n.moment( this.props.from );
const toDate = i18n.moment( this.props.to );

if ( ! i18n.moment().isAfter( fromDate ) || ! i18n.moment().isBefore( toDate ) ) {
return null;
}

if ( ! this.props.isBusinessPlanUser ) {
return (
<HelpTeaserButton
title={ translate( 'Chat is temporarily closed.' ) }
description={ translate(
'We\'re still available over email in the meantime. ' +
'Chat will be back on Friday, July 21st!'
) } />
);
}

return (
<HelpTeaserButton
onClick={ this.trackCalendlyOfferClick }
href="https://calendly.com/wordpressdotcom/wordpress-com-business-site-setup/"
title={ translate( 'Chat with us over screenshare!' ) }
description={ translate( 'Click here to get one-on-one help with a Happiness Engineer.' ) } />
);
}
}

export default connect(
( state ) => ( {
isBusinessPlanUser: isBusinessPlanUser( state ),
} ),
Copy link
Contributor

Choose a reason for hiding this comment

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

This trailing comma doesn't cause a JS error?

Copy link
Contributor

@unDemian unDemian Jul 14, 2017

Choose a reason for hiding this comment

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

Nice catch, no it's not throwing an error for me and the linter is not complaining about it because it is a comma between connect parameters. The second parameter will be undefined with or without the comma so we could just remove it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I always thought trailing commas only worked for arrays and I maybe import definitions.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think it's standard for function calls, I mean connect( parameter, ) will work but looks weird. I'll remove it.

)( localize( ChatBusinessConciergeNotice ) );
7 changes: 7 additions & 0 deletions client/me/help/help-contact-form/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import FormTextInput from 'components/forms/form-text-input';
import FormButton from 'components/forms/form-button';
import SitesDropdown from 'components/sites-dropdown';
import ChatClosureNotice from '../chat-closure-notice';
import ChatBusinessConciergeNotice from '../chat-business-concierge-notice';
import { selectSiteId } from 'state/help/actions';
import { getHelpSelectedSite } from 'state/help/selectors';
import wpcomLib from 'lib/wp';
Expand Down Expand Up @@ -240,8 +241,14 @@ export const HelpContactForm = React.createClass( {
from="2016-12-24T00:00:00Z"
to="2017-01-02T00:00:00Z"
/>

{ formDescription && ( <p>{ formDescription }</p> ) }

<ChatBusinessConciergeNotice
from="2017-07-19T00:00:00Z"
to="2017-07-21T00:00:00Z"
/>

{ showHowCanWeHelpField && (
<div>
<FormLabel>{ translate( 'How can we help?' ) }</FormLabel>
Expand Down
2 changes: 2 additions & 0 deletions client/me/help/help-contact/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
isDirectlyReady,
isDirectlyUninitialized,
} from 'state/selectors';
import QueryUserPurchases from 'components/data/query-user-purchases';

/**
* Module variables
Expand Down Expand Up @@ -666,6 +667,7 @@ const HelpContact = React.createClass( {
<HappychatConnection />
<QueryOlark />
<QueryTicketSupportConfiguration />
<QueryUserPurchases userId={ this.props.currentUser.ID } />
</Main>
);
}
Expand Down
1 change: 1 addition & 0 deletions client/state/selectors/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export isActivatingJetpackModule from './is-activating-jetpack-module';
export isAmbiguousThemeFilterTerm from './is-ambiguous-theme-filter-term';
export isAutomatedTransferActive from './is-automated-transfer-active';
export isAutomatedTransferFailed from './is-automated-transfer-failed';
export isBusinessPlanUser from './is-business-plan-user';
export isDeactivatingJetpackJumpstart from './is-deactivating-jetpack-jumpstart';
export isDeactivatingJetpackModule from './is-deactivating-jetpack-module';
export isDeletingPublicizeShareAction from './is-deleting-publicize-share-action';
Expand Down
28 changes: 28 additions & 0 deletions client/state/selectors/is-business-plan-user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Internal dependencies
*/
import { getCurrentUserId } from 'state/current-user/selectors';
import { getUserPurchases } from 'state/purchases/selectors';
import { PLAN_BUSINESS } from 'lib/plans/constants';

/**
* Returns an boolean flag indicating if the current user is a business plan user.
Copy link
Contributor

Choose a reason for hiding this comment

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

"Returns an boolean flag"

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated.

*
* @param {Object} state Global state tree
* @return {Boolean} If the current user is a business plan user.
*/
export default ( state ) => {
const userId = getCurrentUserId( state );

if ( ! userId ) {
return false;
}

const purchases = getUserPurchases( state, userId );

if ( ! purchases || 0 === purchases.length ) {
return false;
}

return purchases.some( ( purchase ) => PLAN_BUSINESS === purchase.productSlug );
};
86 changes: 86 additions & 0 deletions client/state/selectors/test/is-business-plan-user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* External dependencies
*/
import { assert } from 'chai';
import deepFreeze from 'deep-freeze';

/**
* Internal dependencies
*/
import { isBusinessPlanUser } from '../';
import { PLAN_BUSINESS } from 'lib/plans/constants';

describe( 'isBusinessPlanUser()', () => {
it( 'should return true if any purchase is a business plan.', () => {
const state = deepFreeze( {
currentUser: {
id: 123,
},
purchases: {
data: [
{
user_id: '123',
product_slug: 'some-other-plan',
},
{
user_id: '123',
product_slug: PLAN_BUSINESS,
}
],
hasLoadedUserPurchasesFromServer: true,
},
} );

assert.isTrue( isBusinessPlanUser( state ) );
} );

it( 'should return false if non of the purchases is a business plan.', () => {
const state = deepFreeze( {
currentUser: {
id: 123,
},
purchases: {
data: [
{
user_id: '123',
product_slug: 'some-other-plan',
},
{
user_id: '123',
product_slug: 'yet-another-plan',
}
],
hasLoadedUserPurchasesFromServer: true,
},
} );

assert.isFalse( isBusinessPlanUser( state ) );
} );

it( 'should return false if current user id is null.', () => {
const state = deepFreeze( {
currentUser: {}
} );

assert.isFalse( isBusinessPlanUser( state ) );
} );

it( 'should return false if purchasing data is null.', () => {
const state = deepFreeze( {
currentUser: {
id: 123,
},
purchases: {
data: [
{ // intentionally put a purchase that doesn't belong to the user 123 here.
user_id: '789',
product_slug: PLAN_BUSINESS,
}
],
hasLoadedUserPurchasesFromServer: true,
},
} );

assert.isFalse( isBusinessPlanUser( state ) );
} );
} );