Skip to content

Commit

Permalink
feat(ras): skip campaign setup (#3051)
Browse files Browse the repository at this point in the history
* feat(ras): skip campaign setup boilerplate

added new route, added fe logic

* feat(ras): added `is_skipped` to prerequisite status endpoint

* refactor: moved callback to named function

added ui to indicate async skipping flow

* feat: added skip logic to prerequisite component

combined "skipped" and "active" into single `isValid` const

* feat: `is_skipped` property to prerequisite type

added skip logic to RAS wizard

* fix: circle ci / typescript

* fix: ci / eslint

* refactor: remove redirect after skip

added allow continue when skipped.

* refactor: allow parametrized skip

* refactor: revert any type cast

* feat: pr feedback - added redirect, activation skip and remove `activationStep[0]`

* feat: pr feedback, appended `[skipped]` to select items
  • Loading branch information
jaredrethman authored Apr 25, 2024
1 parent 4a2859b commit 9ef0e6d
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 30 deletions.
19 changes: 10 additions & 9 deletions assets/wizards/engagement/components/prerequisite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ export default function Prerequisite( {
saveConfig,
}: PrequisiteProps ) {
const { href } = prerequisite;
const isValid = Boolean( prerequisite.active || prerequisite.is_skipped );

// If the prerequisite is active but has empty fields, show a warning.
const hasEmptyFields = () => {
if ( prerequisite.active && prerequisite.fields && prerequisite.warning ) {
if ( isValid && prerequisite.fields && prerequisite.warning ) {
const emptyValues = Object.keys( prerequisite.fields ).filter(
fieldName => '' === config[ fieldName as keyof Config ]
);
Expand Down Expand Up @@ -93,9 +94,7 @@ export default function Prerequisite( {
: sprintf(
// Translators: Save or Update settings.
__( '%s settings', 'newspack-plugin' ),
prerequisite.active
? __( 'Update', 'newspack-plugin' )
: __( 'Save', 'newspack-plugin' )
isValid ? __( 'Update', 'newspack-plugin' ) : __( 'Save', 'newspack-plugin' )
) }
</Button>
</div>
Expand Down Expand Up @@ -138,7 +137,7 @@ export default function Prerequisite( {
} }
>
{ /* eslint-disable no-nested-ternary */ }
{ ( prerequisite.active
{ ( isValid
? __( 'Update ', 'newspack-plugin' )
: prerequisite.fields
? __( 'Save ', 'newspack-plugin' )
Expand All @@ -158,8 +157,10 @@ export default function Prerequisite( {
);

let status = __( 'Pending', 'newspack-plugin' );
if ( prerequisite.active ) {
status = __( 'Ready', 'newspack-plugin' );
if ( isValid ) {
status = `${ __( 'Ready', 'newspack-plugin' ) } ${
prerequisite.is_skipped ? `(${ __( 'Skipped', 'newspack-plugin' ) })` : ''
}`;
}
if ( prerequisite.is_unavailable ) {
status = __( 'Unavailable', 'newspack-plugin' );
Expand All @@ -170,14 +171,14 @@ export default function Prerequisite( {
className="newspack-ras-wizard__prerequisite"
isMedium
expandable={ ! prerequisite.is_unavailable }
collapse={ prerequisite.active }
collapse={ isValid }
title={ prerequisite.label }
description={ sprintf(
/* translators: %s: Prerequisite status */
__( 'Status: %s', 'newspack-plugin' ),
status
) }
checkbox={ prerequisite.active ? 'checked' : 'unchecked' }
checkbox={ isValid ? 'checked' : 'unchecked' }
notificationLevel="info"
notification={ hasEmptyFields() }
>
Expand Down
1 change: 1 addition & 0 deletions assets/wizards/engagement/components/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ export type PrequisiteProps = {
action_enabled?: boolean;
disabled_text?: string;
is_unavailable?: boolean;
is_skipped?: boolean;
};
};

Expand Down
65 changes: 63 additions & 2 deletions assets/wizards/engagement/views/reader-activation/campaign.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,26 @@ import {
SectionHeader,
Waiting,
withWizardScreen,
utils,
} from '../../../../components/src';
import Prompt from '../../components/prompt';
import Router from '../../../../components/src/proxied-imports/router';
import './style.scss';

const { useHistory } = Router;

export default withWizardScreen( () => {
const { is_skipped_campaign_setup, reader_activation_url } = newspack_engagement_wizard;

const [ inFlight, setInFlight ] = useState( false );
const [ error, setError ] = useState( false );
const [ prompts, setPrompts ] = useState( null );
const [ allReady, setAllReady ] = useState( false );
const { reader_activation_url } = newspack_engagement_wizard;
const [ skipped, setSkipped ] = useState( {
status: '',
isSkipped: is_skipped_campaign_setup === '1',
} );
const history = useHistory();

const fetchPrompts = () => {
setError( false );
Expand All @@ -40,6 +50,45 @@ export default withWizardScreen( () => {
.finally( () => setInFlight( false ) );
};

/**
* Display prompt requiring editors to confirm skipping, on confirmation send request to
* server to store skipped option in options table and redirect back to RAS
*
* @return {void}
*/
async function onSkipCampaignSetup() {
if (
! utils.confirmAction(
__(
'Are you sure you want to skip setting up a reader activation campaign?',
'newspack-plugin'
)
)
) {
return;
}
setError( false );
setSkipped( { ...skipped, status: 'pending' } );
try {
const request = await apiFetch( {
path: '/newspack/v1/wizard/newspack-engagement-wizard/reader-activation/skip-campaign-setup',
method: 'POST',
data: { skip: ! skipped.isSkipped },
} );
if ( ! request.updated ) {
setError( { message: __( 'Server not updated', 'newspack-plugin' ) } );
setSkipped( { isSkipped: false, status: '' } );
return;
}
setSkipped( { isSkipped: Boolean( request.skipped ), status: '' } );
newspack_engagement_wizard.is_skipped_campaign_setup = request.skipped ? '1' : '';
history.push( '/reader-activation/complete' );
} catch ( err ) {
setError( err );
setSkipped( { isSkipped: false, status: '' } );
}
}

useEffect( () => {
window.scrollTo( 0, 0 );
fetchPrompts();
Expand Down Expand Up @@ -83,9 +132,21 @@ export default withWizardScreen( () => {
/>
) ) }
<div className="newspack-buttons-card">
<Button
isTertiary
disabled={ inFlight || skipped.isSkipped || skipped.status === 'pending' }
onClick={ onSkipCampaignSetup }
>
{ /* eslint-disable-next-line no-nested-ternary */ }
{ skipped.status === 'pending'
? __( 'Skipping…', 'newspack-plugin' )
: skipped.isSkipped
? __( 'Skipped', 'newspack-plugin' )
: __( 'Skip', 'newspack-plugin' ) }
</Button>
<Button
isPrimary
disabled={ inFlight || ! allReady }
disabled={ inFlight || ( ! allReady && ! skipped.isSkipped ) }
href={ `${ reader_activation_url }/complete` }
>
{ __( 'Continue', 'newspack-plugin' ) }
Expand Down
63 changes: 49 additions & 14 deletions assets/wizards/engagement/views/reader-activation/complete.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,26 @@ import {
} from '../../../../components/src';

const listItems = [
__(
'Your <strong>current segments and prompts</strong> will be deactivated and archived.',
'newspack-plugin'
),
__(
'<strong>Reader registration</strong> will be activated to enable better targeting for driving engagement and conversations.',
'newspack-plugin'
),
__(
'The <strong>Reader Activation campaign</strong> will be activated with default segments and settings.',
'newspack-plugin'
),
{
text: __(
'Your <strong>current segments and prompts</strong> will be deactivated and archived.',
'newspack-plugin'
),
isSkipped: '<span class="is-skipped">[skipped]</span>',
},
{
text: __(
'<strong>Reader registration</strong> will be activated to enable better targeting for driving engagement and conversations.',
'newspack-plugin'
),
},
{
text: __(
'The <strong>Reader Activation campaign</strong> will be activated with default segments and settings.',
'newspack-plugin'
),
isSkipped: '<span class="is-skipped">[skipped]</span>',
},
];

const activationSteps = [
Expand All @@ -42,6 +50,8 @@ const activationSteps = [
__( 'Activating Reader Activation Campaign…', 'newspack-plugin' ),
];

const activationStepsCount = activationSteps.length;

/**
* Get a random number between min and max.
*
Expand All @@ -60,7 +70,29 @@ export default withWizardScreen( () => {
const [ progressLabel, setProgressLabel ] = useState( false );
const [ completed, setCompleted ] = useState( false );
const timer = useRef();
const { reader_activation_url } = newspack_engagement_wizard;
const { reader_activation_url, is_skipped_campaign_setup = '' } = newspack_engagement_wizard;
const isSkippedCampaignSetup = is_skipped_campaign_setup === '1';

/**
* If skipped, remove first item.
*/
if ( isSkippedCampaignSetup && activationSteps.length !== activationStepsCount - 1 ) {
activationSteps.shift();
}

/**
* Generate step list strings
*/
for ( const listItemIndex in listItems ) {
if ( ! listItems[ listItemIndex ].text ) {
continue;
}
const suffix = isSkippedCampaignSetup ? ` ${ listItems[ listItemIndex ].isSkipped ?? '' }` : '';
listItems[ listItemIndex ] = `${ listItems[ listItemIndex ].text }${ suffix }`;
if ( isSkippedCampaignSetup ) {
listItems[ listItemIndex ] += ` ${ listItems[ listItemIndex ].isSkipped ?? '' }`;
}
}

useEffect( () => {
if ( timer.current ) {
Expand All @@ -80,7 +112,7 @@ export default withWizardScreen( () => {
setProgressLabel( __( 'Done!', 'newspack-plugin' ) );
setTimeout( () => {
setInFlight( false );
window.location = reader_activation_url;
// window.location = reader_activation_url;
}, 3000 );
}
}, [ completed, progress ] );
Expand All @@ -95,6 +127,9 @@ export default withWizardScreen( () => {
await apiFetch( {
path: '/newspack/v1/wizard/newspack-engagement-wizard/reader-activation/activate',
method: 'post',
data: {
skip_activation: isSkippedCampaignSetup,
},
} )
);
} catch ( err ) {
Expand Down
4 changes: 3 additions & 1 deletion assets/wizards/engagement/views/reader-activation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ export default withWizardScreen( ( { wizardApiFetch } ) => {
const _allReady =
! missingPlugins.length &&
prerequisites &&
Object.keys( prerequisites ).every( key => prerequisites[ key ]?.active );
Object.keys( prerequisites ).every(
key => prerequisites[ key ]?.active || prerequisites[ key ]?.skipped
);

setAllReady( _allReady );

Expand Down
4 changes: 4 additions & 0 deletions assets/wizards/engagement/views/reader-activation/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
margin-top: 0 !important;
}

span.is-skipped {
color: wp-colors.$gray-700;
}

.newspack-ras-campaign {
&__prompt-wizard,
&__completed {
Expand Down
3 changes: 2 additions & 1 deletion includes/reader-activation/class-reader-activation.php
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ public static function is_transactional_email_configured() {
* TODO: Make this dynamic once the third UI screen to generate the prompts is built.
*/
public static function is_ras_campaign_configured() {
return self::is_enabled();
return self::is_enabled() || get_option( Engagement_Wizard::SKIP_CAMPAIGN_SETUP_OPTION, '' ) === '1';
}

/**
Expand Down Expand Up @@ -500,6 +500,7 @@ public static function get_prerequisites_status() {
],
'ras_campaign' => [
'active' => self::is_ras_campaign_configured(),
'is_skipped' => get_option( Engagement_Wizard::SKIP_CAMPAIGN_SETUP_OPTION, '' ) === '1',
'plugins' => [
'newspack-popups' => class_exists( '\Newspack_Popups_Model' ),
],
Expand Down
33 changes: 30 additions & 3 deletions includes/wizards/class-engagement-wizard.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

namespace Newspack;

use WP_Error, WP_Query;
use TypeError;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

defined( 'ABSPATH' ) || exit;

Expand All @@ -18,6 +21,8 @@
*/
class Engagement_Wizard extends Wizard {

const SKIP_CAMPAIGN_SETUP_OPTION = '_newspack_ras_skip_campaign_setup';

/**
* The slug of this wizard.
*
Expand Down Expand Up @@ -108,6 +113,24 @@ public function register_api_endpoints() {
'permission_callback' => [ $this, 'api_permissions_check' ],
]
);
register_rest_route(
NEWSPACK_API_NAMESPACE,
'/wizard/' . $this->slug . '/reader-activation/skip-campaign-setup',
[
'methods' => \WP_REST_Server::EDITABLE,
'callback' => function( $request ) {
$skip = $request->get_param( 'skip' );
$skip_campaign_setup = update_option( static::SKIP_CAMPAIGN_SETUP_OPTION, $skip );
return rest_ensure_response(
[
'skipped' => $skip,
'updated' => $skip_campaign_setup,
]
);
},
'permission_callback' => [ $this, 'api_permissions_check' ],
]
);
register_rest_route(
NEWSPACK_API_NAMESPACE,
'/wizard/' . $this->slug . '/newsletters',
Expand Down Expand Up @@ -262,10 +285,12 @@ public function api_update_reader_activation_settings( $request ) {
/**
* Activate reader activation and publish RAS prompts/segments.
*
* @param WP_REST_Request $request WP Rest Request object.
* @return WP_REST_Response
*/
public function api_activate_reader_activation() {
$response = Reader_Activation::activate();
public function api_activate_reader_activation( WP_REST_Request $request ) {
$skip_activation = $request->get_param( 'skip_activation' ) ?? false;
$response = $skip_activation ? true : Reader_Activation::activate();

if ( \is_wp_error( $response ) ) {
return new \WP_REST_Response( [ 'message' => $response->get_error_message() ], 400 );
Expand Down Expand Up @@ -429,6 +454,8 @@ public function enqueue_scripts_and_styles() {
$data['preview_archive'] = $newspack_popups->preview_archive();
}

$data['is_skipped_campaign_setup'] = get_option( static::SKIP_CAMPAIGN_SETUP_OPTION, '' );

\wp_localize_script(
'newspack-engagement-wizard',
'newspack_engagement_wizard',
Expand Down

0 comments on commit 9ef0e6d

Please sign in to comment.