Skip to content

Commit

Permalink
feat: add pre-send confirmation (#181)
Browse files Browse the repository at this point in the history
- display subscriber count in group select

Closes #139
  • Loading branch information
adekbadek authored May 1, 2020
1 parent f253342 commit 3579363
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 61 deletions.
63 changes: 49 additions & 14 deletions src/components/send-button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,22 @@
*/
import { withDispatch, withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { Button } from '@wordpress/components';
import { Button, Modal } from '@wordpress/components';
import { Fragment, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* External dependencies
*/
import { get } from 'lodash';

/**
* Internal dependencies
*/
import { getServiceProvider } from '../../service-providers';

const { renderPreSendInfo } = getServiceProvider();

export default compose( [
withDispatch( dispatch => {
const { editPost, savePost } = dispatch( 'core/editor' );
Expand All @@ -26,16 +34,17 @@ export default compose( [
isSavingPost,
isEditedPostBeingScheduled,
} = select( 'core/editor' );
const meta = getEditedPostAttribute( 'meta' );
const { newsletterData = {}, newsletterValidationErrors } = getEditedPostAttribute( 'meta' );
return {
isPublishable: forceIsDirty || isEditedPostPublishable(),
isSaveable: isEditedPostSaveable(),
isSaving: forceIsSaving || isSavingPost(),
validationErrors: meta.newsletterValidationErrors,
validationErrors: newsletterValidationErrors,
status: getEditedPostAttribute( 'status' ),
isEditedPostBeingScheduled: isEditedPostBeingScheduled(),
hasPublishAction: get( getCurrentPost(), [ '_links', 'wp:action-publish' ], false ),
visibility: getEditedPostVisibility(),
newsletterData,
};
} ),
] )(
Expand All @@ -50,6 +59,7 @@ export default compose( [
isEditedPostBeingScheduled,
hasPublishAction,
visibility,
newsletterData,
} ) => {
const isButtonEnabled =
( isPublishable || isEditedPostBeingScheduled ) &&
Expand Down Expand Up @@ -82,22 +92,47 @@ export default compose( [
publishStatus = 'publish';
}

const onClick = () => {
const triggerCampaignSend = () => {
editPost( { status: publishStatus } );
savePost();
};

const [ modalVisible, setModalVisible ] = useState( false );

return (
<Button
className="editor-post-publish-button"
isBusy={ isSaving && 'publish' === status }
isPrimary
isLarge
onClick={ onClick }
disabled={ ! isButtonEnabled }
>
{ label }
</Button>
<Fragment>
<Button
className="editor-post-publish-button"
isBusy={ isSaving && 'publish' === status }
isPrimary
isLarge
onClick={ () => setModalVisible( true ) }
disabled={ ! isButtonEnabled }
>
{ label }
</Button>
{ modalVisible && (
<Modal
className="newspack-newsletters__modal"
title={ __( 'Send your newsletter?', 'newspack-newsletters' ) }
onRequestClose={ () => setModalVisible( false ) }
>
{ renderPreSendInfo( newsletterData ) }
<Button
isPrimary
onClick={ () => {
triggerCampaignSend();
setModalVisible( false );
} }
>
{ __( 'Send', 'newspack-newsletters' ) }
</Button>
<Button isSecondary onClick={ () => setModalVisible( false ) }>
{ __( 'Cancel', 'newspack-newsletters' ) }
</Button>
</Modal>
) }
</Fragment>
);
}
);
10 changes: 10 additions & 0 deletions src/editor/editor/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,13 @@
}
}
}

.newspack-newsletters {
&__modal {
max-width: 360px;

.components-button + .components-button {
margin-left: 12px;
}
}
}
2 changes: 1 addition & 1 deletion src/editor/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default compose( [
</Button>
{ warningModalVisible && (
<Modal
className="newspack-newsletters-layouts__modal"
className="newspack-newsletters__modal"
title={ __( 'Overwrite newsletter content?', 'newspack-newsletters' ) }
onRequestClose={ () => setWarningModalVisible( false ) }
>
Expand Down
8 changes: 0 additions & 8 deletions src/editor/layout/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,4 @@
padding: 4px 2px;
text-align: center;
}

&__modal {
max-width: 360px;

.components-button + .components-button {
margin-left: 12px;
}
}
}
14 changes: 14 additions & 0 deletions src/service-providers/example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,22 @@ const ProviderSidebar = ( {
);
};

/**
* A function to render additional info in the pre-send confirmation modal.
* Can return null if no additional info is to be presented.
*
* @param {Object} newsletterData the data returned by getFetchDataConfig handler
* @return {any} A React component
*/
const renderPreSendInfo = ( newsletterData = {} ) => (
<p>
{ __( 'Sending newsletter to:', 'newspack-newsletters' ) } { newsletterData.listName }
</p>
);

export default {
validateNewsletter,
getFetchDataConfig,
ProviderSidebar,
renderPreSendInfo,
};
46 changes: 9 additions & 37 deletions src/service-providers/mailchimp/ProviderSidebar.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
/**
* External dependencies
*/
import { get } from 'lodash';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { Fragment, useEffect } from '@wordpress/element';
import { ExternalLink, SelectControl, Spinner, Notice } from '@wordpress/components';

/**
* Internal dependencies
*/
import { getListInterestsSettings } from './utils';

const ProviderSidebar = ( {
renderSubject,
renderFrom,
Expand All @@ -20,7 +20,6 @@ const ProviderSidebar = ( {
updateMeta,
} ) => {
const campaign = newsletterData.campaign;
const interestCategories = newsletterData.interest_categories;
const lists = newsletterData.lists ? newsletterData.lists.lists : [];

const setList = listId =>
Expand Down Expand Up @@ -55,47 +54,20 @@ const ProviderSidebar = ( {
}, [ campaign ]);

const renderInterestCategories = () => {
if (
! interestCategories ||
! interestCategories.categories ||
! interestCategories.categories.length
) {
const interestSettings = getListInterestsSettings( newsletterData );
if ( ! interestSettings ) {
return;
}
const options = interestCategories.categories.reduce( ( accumulator, item ) => {
const { title, interests, id } = item;
accumulator.push( {
label: title,
disabled: true,
} );
if ( interests && interests.interests && interests.interests.length ) {
interests.interests.forEach( interest => {
const isDisabled = parseInt( interest.subscriber_count ) === 0;
accumulator.push( {
label:
'- ' +
interest.name +
( isDisabled ? __( ' (no subscribers)', 'newspack-newsletters' ) : '' ),
value: 'interests-' + id + ':' + interest.id,
disabled: isDisabled,
} );
} );
}
return accumulator;
}, [] );
const field = get( campaign, 'recipients.segment_opts.conditions.[0].field' );
const interest_id = get( campaign, 'recipients.segment_opts.conditions.[0].value.[0]' );
const interestValue = field && interest_id ? field + ':' + interest_id : 0;
return (
<SelectControl
label={ __( 'Groups', 'newspack-newsletters' ) }
value={ interestValue }
value={ interestSettings.interestValue }
options={ [
{
label: __( '-- Select a group --', 'newspack-newsletters' ),
value: 'no_interests',
},
...options,
...interestSettings.options,
] }
onChange={ setInterest }
disabled={ inFlight }
Expand Down
55 changes: 54 additions & 1 deletion src/service-providers/mailchimp/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { __, sprintf, _n } from '@wordpress/i18n';
import { Fragment } from '@wordpress/element';

/**
* External dependencies
*/
import { find } from 'lodash';

/**
* Internal dependencies
*/
import ProviderSidebar from './ProviderSidebar';
import { getListInterestsSettings } from './utils';

const validateNewsletter = ( { campaign } ) => {
const { recipients, settings, status } = campaign || {};
Expand Down Expand Up @@ -36,8 +43,54 @@ const getFetchDataConfig = ( { postId } ) => ( {
path: `/newspack-newsletters/v1/mailchimp/${ postId }`,
} );

const renderPreSendInfo = newsletterData => {
if ( ! newsletterData.campaign ) {
return null;
}
let listData;
if ( newsletterData.campaign && newsletterData.lists ) {
const list = find( newsletterData.lists.lists, [
'id',
newsletterData.campaign.recipients.list_id,
] );
const interestSettings = getListInterestsSettings( newsletterData );

if ( list ) {
listData = { name: list.name, subscribers: parseInt( list.stats.member_count ) };
if ( interestSettings && interestSettings.setInterest ) {
listData.groupName = interestSettings.setInterest.rawInterest.name;
listData.subscribers = parseInt(
interestSettings.setInterest.rawInterest.subscriber_count
);
}
}
}

return (
<p>
{ __( "You're about to send a newsletter to:", 'newspack-newsletters' ) }
<br />
<strong>{ listData.name }</strong>
<br />
{ listData.groupName && (
<Fragment>
{ __( 'Group:', 'newspack-newsletters' ) } <strong>{ listData.groupName }</strong>
<br />
</Fragment>
) }
<strong>
{ sprintf(
_n( '%d subscriber', '%d subscribers', listData.subscribers, 'newspack-newsletters' ),
listData.subscribers
) }
</strong>
</p>
);
};

export default {
validateNewsletter,
getFetchDataConfig,
ProviderSidebar,
renderPreSendInfo,
};
55 changes: 55 additions & 0 deletions src/service-providers/mailchimp/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* WordPress dependencies
*/
import { sprintf, _n } from '@wordpress/i18n';

/**
* External dependencies
*/
import { get, find } from 'lodash';

/**
* Get interest settings for a Mailchimp campaign.
* An interest is a subset of a list.
*/
export const getListInterestsSettings = ( {
campaign,
interest_categories: interestCategories,
} ) => {
if (
! interestCategories ||
! interestCategories.categories ||
! interestCategories.categories.length
) {
return;
}
const options = interestCategories.categories.reduce( ( accumulator, item ) => {
const { title, interests, id } = item;
accumulator.push( {
label: title,
disabled: true,
} );
if ( interests && interests.interests && interests.interests.length ) {
interests.interests.forEach( interest => {
const subscriberCount = parseInt( interest.subscriber_count );
const subscriberCountInfo = sprintf(
_n( '%d subscriber', '%d subscribers', subscriberCount, 'newspack-newsletters' ),
subscriberCount
);

accumulator.push( {
label: `- ${ interest.name } (${ subscriberCountInfo })`,
value: `interests-${ id }:${ interest.id }`,
disabled: subscriberCount === 0,
rawInterest: interest,
} );
} );
}
return accumulator;
}, [] );
const field = get( campaign, 'recipients.segment_opts.conditions.[0].field' );
const interest_id = get( campaign, 'recipients.segment_opts.conditions.[0].value.[0]' );
const interestValue = field && interest_id ? field + ':' + interest_id : 0;

return { options, interestValue, setInterest: find( options, [ 'value', interestValue ] ) };
};

0 comments on commit 3579363

Please sign in to comment.