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

[HOLD] feat(popups): default segments UI #1524

Closed
wants to merge 9 commits into from
162 changes: 120 additions & 42 deletions assets/wizards/popups/views/segments/SegmentsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@
* WordPress dependencies.
*/
import { useEffect, useRef, useState, Fragment } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import { Draggable, MenuItem } from '@wordpress/components';
import { ESCAPE } from '@wordpress/keycodes';
import { Icon, chevronDown, chevronUp, dragHandle, moreVertical } from '@wordpress/icons';

/**
* Internal dependencies.
*/
import { ActionCard, Button, Card, Notice, Popover, Router } from '../../../../components/src';
import {
ActionCard,
Button,
Card,
Modal,
Notice,
Popover,
Router,
} from '../../../../components/src';
import { descriptionForSegment, getFavoriteCategoryNames } from '../../utils';

const { NavLink, useHistory } = Router;
Expand Down Expand Up @@ -255,9 +263,13 @@ const SegmentActionCard = ( {
const SegmentsList = ( { wizardApiFetch, segments, setSegments, isLoading } ) => {
const [ dropTargetIndex, setDropTargetIndex ] = useState( null );
const [ sortedSegments, setSortedSegments ] = useState( null );
const [ showDefaultModal, setShowDefaultModal ] = useState( false );
const [ defaultsCreated, setDefaultsCreated ] = useState( false );
const [ inFlight, setInFlight ] = useState( false );
const [ error, setError ] = useState( null );
const ref = useRef();
const { default_segments: defaultSegments } = window.newspack_popups_wizard_data || {};

const deleteSegment = segment => {
setInFlight( true );
setError( null );
Expand Down Expand Up @@ -296,6 +308,26 @@ const SegmentsList = ( { wizardApiFetch, segments, setSegments, isLoading } ) =>
setSegments( segments );
} );
};
const generateDefaultSegments = () => {
setInFlight( true );
setError( null );
wizardApiFetch( {
path: '/newspack/v1/wizard/newspack-popups-wizard/segmentation-defaults',
method: 'POST',
quiet: true,
} )
.then( _segments => {
setSegments( _segments );
} )
adekbadek marked this conversation as resolved.
Show resolved Hide resolved
.catch( e => {
setError( e.message || __( 'Error creating default segments. Please try again.' ) );
} )
.finally( () => {
setInFlight( false );
setShowDefaultModal( false );
setDefaultsCreated( true );
} );
};

if ( segments === null ) {
return null;
Expand All @@ -304,47 +336,93 @@ const SegmentsList = ( { wizardApiFetch, segments, setSegments, isLoading } ) =>
// Optimistically update the order of the list while the sort request is pending.
const segmentsToShow = sortedSegments || segments;

return segments.length ? (
<Fragment>
{ error && <Notice noticeText={ error } isError /> }
<Card headerActions noBorder>
<h2>{ __( 'Audience segments', 'newspack' ) }</h2>
<AddNewSegmentLink />
</Card>
<div
className={ 'newspack-campaigns-wizard-segments__list' + ( inFlight ? ' is-loading' : '' ) }
ref={ ref }
>
{ segmentsToShow.map( ( segment, index ) => (
<SegmentActionCard
deleteSegment={ deleteSegment }
key={ segment.id }
inFlight={ inFlight || isLoading > 0 }
segment={ segment }
segments={ segments }
sortSegments={ sortSegments }
index={ index }
wrapperRef={ ref }
dropTargetIndex={ dropTargetIndex }
setDropTargetIndex={ setDropTargetIndex }
totalSegments={ segments.length }
/>
) ) }
</div>
</Fragment>
) : (
<Fragment>
<Card headerActions noBorder>
<h2>{ __( 'You have no saved audience segments.', 'newspack' ) }</h2>
<AddNewSegmentLink />
</Card>
<p>
{ __(
'Create audience segments to target visitors by engagement, activity, and more.',
'newspack'
return (
<>
{ segments.length ? (
<>
{ error && <Notice noticeText={ error } isError /> }
<Card headerActions noBorder>
<h2>{ __( 'Audience segments', 'newspack' ) }</h2>
<AddNewSegmentLink />
</Card>
<div
className={
'newspack-campaigns-wizard-segments__list' + ( inFlight ? ' is-loading' : '' )
}
ref={ ref }
>
{ segmentsToShow.map( ( segment, index ) => (
<SegmentActionCard
deleteSegment={ deleteSegment }
key={ segment.id }
inFlight={ inFlight || isLoading > 0 }
segment={ segment }
segments={ segments }
sortSegments={ sortSegments }
index={ index }
wrapperRef={ ref }
dropTargetIndex={ dropTargetIndex }
setDropTargetIndex={ setDropTargetIndex }
totalSegments={ segments.length }
/>
) ) }
</div>
</>
) : (
<>
<Card headerActions noBorder>
<h2>{ __( 'You have no saved audience segments.', 'newspack' ) }</h2>
<AddNewSegmentLink />
</Card>
<p>
{ __(
'Create audience segments to target visitors by engagement, activity, and more.',
'newspack'
) }
</p>
</>
) }
{ showDefaultModal && (
<Modal
title={ __( 'Default segments', 'newspack' ) }
onRequestClose={ () => setShowDefaultModal( false ) }
>
<p>
{ sprintf(
// Translators: help message before generating default segments.
__(
'This will %1$s set of default segments that represent a basic engagement funnel.%2$s Proceed?',
'newspack'
),
defaultSegments ? __( 'regenerate the', 'newspack' ) : __( 'generate a', 'newspack' ),
defaultSegments
? __(
' Any changes you’ve made to the default segments will be ovewritten.',
'newspack'
)
: ''
) }
</p>
<Card buttonsCard noBorder className="justify-end">
<Button isSecondary onClick={ () => setShowDefaultModal( false ) }>
{ __( 'Cancel', 'newspack' ) }
</Button>
<Button isPrimary onClick={ () => generateDefaultSegments() }>
{ __( 'OK', 'newspack' ) }
</Button>
</Card>
</Modal>
) }
<Button isPrimary onClick={ () => setShowDefaultModal( true ) }>
{ sprintf(
// Translators: button label for generating or resetting the default segments.
__( '%s default segments', 'newspack' ),
defaultSegments || defaultsCreated
adekbadek marked this conversation as resolved.
Show resolved Hide resolved
? __( 'Reset', 'newspack' )
adekbadek marked this conversation as resolved.
Show resolved Hide resolved
: __( 'Generate', 'newspack' )
) }
</p>
</Fragment>
</Button>
</>
);
};

Expand Down
1 change: 0 additions & 1 deletion assets/wizards/popups/views/segments/SingleSegment.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ const SingleSegment = ( { segmentId, setSegments, wizardApiFetch } ) => {
const history = useHistory();

const [ segmentInitially, setSegmentInitially ] = useState( null );

const isSegmentValid =
name.length > 0 && JSON.stringify( segmentConfig ) !== JSON.stringify( DEFAULT_CONFIG ); // Segment has a name. // Segment differs from the default config.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,24 @@ public function sort_segments( $segment_ids ) {
$this->unconfigured_error();
}

/**
* Get segment IDs of default segments.
*/
public function get_default_segments() {
return $this->is_configured() ?
\Newspack_Popups_Segmentation::get_default_segments() :
$this->unconfigured_error();
}

/**
* Create or update default segments.
*/
public function create_default_segmetns() {
return $this->is_configured() ?
\Newspack_Popups_Segmentation::create_default_segments() :
$this->unconfigured_error();
}

/**
* Activate campaign group.
*
Expand Down
23 changes: 23 additions & 0 deletions includes/wizards/class-popups-wizard.php
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,16 @@ public function register_api_endpoints() {
]
);

register_rest_route(
NEWSPACK_API_NAMESPACE,
'/wizard/' . $this->slug . '/segmentation-defaults',
[
'methods' => \WP_REST_Server::EDITABLE,
'callback' => [ $this, 'api_create_default_segments' ],
'permission_callback' => [ $this, 'api_permissions_check' ],
]
);

// Register newspack/v1/popups-analytics/report endpoint.
register_rest_route(
NEWSPACK_API_NAMESPACE,
Expand Down Expand Up @@ -475,6 +485,7 @@ public function enqueue_scripts_and_styles() {
$overlay_placements = $newspack_popups_configuration_manager->get_overlay_placements();
$overlay_sizes = $newspack_popups_configuration_manager->get_overlay_sizes();
$preview_query_keys = $newspack_popups_configuration_manager->preview_query_keys();
$default_segments = $newspack_popups_configuration_manager->get_default_segments();

\wp_localize_script(
'newspack-popups-wizard',
Expand All @@ -487,6 +498,7 @@ public function enqueue_scripts_and_styles() {
'overlay_placements' => $overlay_placements,
'overlay_sizes' => $overlay_sizes,
'preview_query_keys' => $preview_query_keys,
'default_segments' => $default_segments,
]
);

Expand Down Expand Up @@ -853,6 +865,17 @@ public function api_sort_segments( $request ) {
return $response;
}

/**
* Generate default segments. If they've already been generated, rebuild them with default parameters.
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function api_create_default_segments() {
$newspack_popups_configuration_manager = Configuration_Managers::configuration_manager_class_for_plugin_slug( 'newspack-popups' );
$response = $newspack_popups_configuration_manager->create_default_segmetns();
return $response;
}

/**
* Activate a campaign group.
* Activate a campaign.
Expand Down