Add extended task list support to the new REST api task lists (https://github.com/woocommerce/woocommerce-admin/pull/7730)

* Add extended task list support to the new REST api task lists

* Some small refactors

* Small refactors from PR review

* Create extended tasks on the fly if added on the client

* Remove unneeded change

* Add level and additionalInfo support, also adding it to the WooCommerce Payments task

* Fix a mis-type in a comment
This commit is contained in:
louwie17 2021-10-01 15:46:23 -03:00 committed by GitHub
parent 9c5c39732b
commit 5c9bf5d925
10 changed files with 257 additions and 54 deletions

View File

@ -56,6 +56,8 @@ export const TaskListItem: React.FC< TaskListItemProps > = ( {
isSnoozeable,
time,
title,
level,
additionalInfo,
} = task;
const slot = useSlot( `woocommerce_onboarding_task_list_item_${ id }` );
@ -160,8 +162,10 @@ export const TaskListItem: React.FC< TaskListItemProps > = ( {
key={ id }
title={ title }
content={ content }
additionalInfo={ additionalInfo }
time={ time }
action={ onClickActions }
level={ level }
actionLabel={ actionLabel }
{ ...taskItemProps }
{ ...props }

View File

@ -116,6 +116,10 @@ export const Tasks: React.FC< TasksProps > = ( { query } ) => {
tasks,
} = taskList;
if ( isHidden ) {
return null;
}
return (
<Fragment key={ id }>
<TaskList

View File

@ -34,6 +34,7 @@
"@wordpress/i18n": "3.17.0",
"@wordpress/url": "2.21.0",
"md5": "^2.3.0",
"qs": "6.9.6",
"rememo": "^3.0.0"
},
"devDependencies": {

View File

@ -217,6 +217,30 @@ export function* updateProfileItems( items ) {
}
}
/**
* Used to keep backwards compatibility with the extended task list filter on the client.
* This can be removed after version WC Admin 2.10 (see deprecated notice in resolvers.js).
*
* @param {Object} task the returned task object.
* @param {Array} keys to keep in the task object.
* @return {Object} task with the keys specified.
*/
function possiblyPruneTaskData( task, keys ) {
if ( ! task.time && ! task.title ) {
// client side task
return keys.reduce(
( simplifiedTask, key ) => {
return {
...simplifiedTask,
[ key ]: task[ key ],
};
},
{ id: task.id }
);
}
return task;
}
export function* snoozeTask( id ) {
yield snoozeTaskRequest( id );
@ -226,7 +250,13 @@ export function* snoozeTask( id ) {
method: 'POST',
} );
yield snoozeTaskSuccess( task );
yield snoozeTaskSuccess(
possiblyPruneTaskData( task, [
'isSnoozed',
'isDismissed',
'snoozedUntil',
] )
);
} catch ( error ) {
yield snoozeTaskError( id, error );
throw new Error();
@ -242,7 +272,13 @@ export function* undoSnoozeTask( id ) {
method: 'POST',
} );
yield undoSnoozeTaskSuccess( task );
yield undoSnoozeTaskSuccess(
possiblyPruneTaskData( task, [
'isSnoozed',
'isDismissed',
'snoozedUntil',
] )
);
} catch ( error ) {
yield undoSnoozeTaskError( id, error );
throw new Error();
@ -258,7 +294,9 @@ export function* dismissTask( id ) {
method: 'POST',
} );
yield dismissTaskSuccess( task );
yield dismissTaskSuccess(
possiblyPruneTaskData( task, [ 'isDismissed', 'isSnoozed' ] )
);
} catch ( error ) {
yield dismissTaskError( id, error );
throw new Error();
@ -274,7 +312,9 @@ export function* undoDismissTask( id ) {
method: 'POST',
} );
yield undoDismissTaskSuccess( task );
yield undoDismissTaskSuccess(
possiblyPruneTaskData( task, [ 'isDismissed', 'isSnoozed' ] )
);
} catch ( error ) {
yield undoDismissTaskError( id, error );
throw new Error();

View File

@ -2,6 +2,9 @@
* External dependencies
*/
import { apiFetch } from '@wordpress/data-controls';
import { applyFilters } from '@wordpress/hooks';
import deprecated from '@wordpress/deprecated';
import { parse } from 'qs';
/**
* Internal dependencies
@ -60,11 +63,57 @@ export function* getTasksStatus() {
}
}
function getQuery() {
const searchString = window.location && window.location.search;
if ( ! searchString ) {
return {};
}
const search = searchString.substring( 1 );
return parse( search );
}
/**
* This function will be depreciated in favour of registering tasks on the back-end.
*
*/
function getTasksFromDeprecatedFilter() {
const filteredTasks = applyFilters(
'woocommerce_admin_onboarding_task_list',
[],
getQuery()
);
if ( filteredTasks && filteredTasks.length > 0 ) {
deprecated( 'woocommerce_admin_onboarding_task_list', {
version: '2.10.0',
alternative: 'TaskLists::add_task()',
plugin: '@woocommerce/data',
} );
return filteredTasks.map( ( task ) => ( {
title: task.title,
content: task.content,
additional_info: task.additionalInfo,
time: task.time,
level: task.level ? parseInt( task.level, 10 ) : 3,
list_id: task.type || 'extended',
is_visible: task.visible,
id: task.key,
is_snoozeable: task.allowRemindMeLater,
is_dismissable: task.isDismissable,
} ) );
}
return [];
}
export function* getTaskLists() {
const tasksFromDeprecatedFilter = getTasksFromDeprecatedFilter();
try {
const results = yield apiFetch( {
path: WC_ADMIN_NAMESPACE + '/onboarding/tasks',
method: 'GET',
method: tasksFromDeprecatedFilter.length > 0 ? 'POST' : 'GET',
data: tasksFromDeprecatedFilter.length && {
extended_tasks: tasksFromDeprecatedFilter,
},
} );
yield getTaskListsSuccess( results );

View File

@ -10,6 +10,7 @@ namespace Automattic\WooCommerce\Admin\API;
use Automattic\WooCommerce\Admin\Features\Onboarding;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Init as OnboardingTasksFeature;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskLists;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
defined( 'ABSPATH' ) || exit;
@ -119,6 +120,26 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
'callback' => array( $this, 'get_tasks' ),
'permission_callback' => array( $this, 'get_tasks_permission_check' ),
),
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array( $this, 'get_tasks' ),
'permission_callback' => array( $this, 'get_tasks_permission_check' ),
'args' => array(
'extended_tasks' => array(
'description' => __( 'List of extended deprecated tasks from the client side filter.', 'woocommerce-admin' ),
'type' => 'array',
'validate_callback' => function( $param, $request, $key ) {
$has_valid_keys = true;
foreach ( $param as $task ) {
if ( $has_valid_keys ) {
$has_valid_keys = array_key_exists( 'list_id', $task ) && array_key_exists( 'id', $task );
}
}
return $has_valid_keys;
},
),
),
),
'schema' => array( $this, 'get_public_item_schema' ),
)
);
@ -750,11 +771,13 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
/**
* Get the onboarding tasks.
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Response|WP_Error
*/
public function get_tasks() {
$lists = TaskLists::get_lists();
$json = array_map(
public function get_tasks( $request ) {
$extended_tasks = $request->get_param( 'extended_tasks' );
$lists = TaskLists::get_lists( $extended_tasks );
$json = array_map(
function( $list ) {
return $list->get_json();
},
@ -774,6 +797,15 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
$id = $request->get_param( 'id' );
$task = TaskLists::get_task( $id );
if ( ! $task && $id ) {
$task = new Task(
array(
'id' => $id,
'is_dismissable' => true,
)
);
}
if ( ! $task || ! $task->is_dismissable ) {
return new \WP_Error(
'woocommerce_rest_invalid_task',
@ -798,6 +830,15 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
$id = $request->get_param( 'id' );
$task = TaskLists::get_task( $id );
if ( ! $task && $id ) {
$task = new Task(
array(
'id' => $id,
'is_dismissable' => true,
)
);
}
if ( ! $task || ! $task->is_dismissable ) {
return new \WP_Error(
'woocommerce_rest_invalid_task',
@ -809,6 +850,7 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
}
$task->undo_dismiss();
return rest_ensure_response( $task->get_json() );
}
@ -826,6 +868,15 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
$task = TaskLists::get_task( $task_id, $task_list_id );
if ( ! $task && $task_id ) {
$task = new Task(
array(
'id' => $task_id,
'is_snoozeable' => true,
)
);
}
if ( ! $task || ! $task->is_snoozeable ) {
return new \WP_Error(
'woocommerce_tasks_invalid_task',
@ -850,6 +901,15 @@ class OnboardingTasks extends \WC_REST_Data_Controller {
$id = $request->get_param( 'id' );
$task = TaskLists::get_task( $id );
if ( ! $task && $id ) {
$task = new Task(
array(
'id' => $id,
'is_snoozeable' => true,
)
);
}
if ( ! $task || ! $task->is_snoozeable ) {
return new \WP_Error(
'woocommerce_tasks_invalid_task',

View File

@ -815,7 +815,7 @@ class Onboarding {
if ( $extended_list ) {
$help_tab['content'] .= '<h3>' . __( 'Extended task List', 'woocommerce-admin' ) . '</h3>';
$help_tab['content'] .= '<p>' . __( 'If you need to enable or disable the extended task lists, please click on the button below.', 'woocommerce-admin' ) . '</p>' .
( $extended_task->is_hidden()
( $extended_list->is_hidden()
? '<p><a href="' . wc_admin_url( '&reset_extended_task_list=1' ) . '" class="button button-primary">' . __( 'Enable', 'woocommerce-admin' ) . '</a></p>'
: '<p><a href="' . wc_admin_url( '&reset_extended_task_list=0' ) . '" class="button button-primary">' . __( 'Disable', 'woocommerce-admin' ) . '</a></p>'
);

View File

@ -24,12 +24,19 @@ class Task {
public $title = '';
/**
* Title.
* Content.
*
* @var string
*/
public $content = '';
/**
* Additional info.
*
* @var string
*/
public $additional_info = '';
/**
* Action label.
*
@ -65,6 +72,13 @@ class Task {
*/
public $time = null;
/**
* Level of task importance.
*
* @var int|null
*/
public $level = null;
/**
* Dismissability.
*
@ -118,31 +132,35 @@ class Task {
*/
public function __construct( $data = array() ) {
$defaults = array(
'id' => null,
'title' => '',
'content' => '',
'action_label' => __( "Let's go", 'woocommerce-admin' ),
'action_url' => null,
'is_complete' => false,
'can_view' => true,
'time' => null,
'is_dismissable' => false,
'is_snoozeable' => false,
'snoozed_until' => null,
'id' => null,
'title' => '',
'content' => '',
'action_label' => __( "Let's go", 'woocommerce-admin' ),
'action_url' => null,
'is_complete' => false,
'can_view' => true,
'level' => null,
'time' => null,
'is_dismissable' => false,
'is_snoozeable' => false,
'snoozed_until' => null,
'additional_info' => '',
);
$data = wp_parse_args( $data, $defaults );
$this->id = (string) $data['id'];
$this->title = (string) $data['title'];
$this->content = (string) $data['content'];
$this->action_label = (string) $data['action_label'];
$this->action_url = (string) $data['action_url'];
$this->is_complete = (bool) $data['is_complete'];
$this->can_view = (bool) $data['can_view'];
$this->time = (string) $data['time'];
$this->is_dismissable = (bool) $data['is_dismissable'];
$this->is_snoozeable = (bool) $data['is_snoozeable'];
$this->id = (string) $data['id'];
$this->title = (string) $data['title'];
$this->content = (string) $data['content'];
$this->action_label = (string) $data['action_label'];
$this->action_url = (string) $data['action_url'];
$this->is_complete = (bool) $data['is_complete'];
$this->can_view = (bool) $data['can_view'];
$this->level = (int) $data['level'];
$this->additional_info = (string) $data['additional_info'];
$this->time = (string) $data['time'];
$this->is_dismissable = (bool) $data['is_dismissable'];
$this->is_snoozeable = (bool) $data['is_snoozeable'];
$snoozed_tasks = get_option( self::SNOOZED_OPTION, array() );
if ( isset( $snoozed_tasks[ $this->id ] ) ) {
@ -268,20 +286,22 @@ class Task {
*/
public function get_json() {
return array(
'id' => $this->id,
'title' => $this->title,
'canView' => $this->can_view,
'content' => $this->content,
'actionLabel' => $this->action_label,
'actionUrl' => $this->action_url,
'isComplete' => $this->is_complete,
'canView' => $this->can_view,
'time' => $this->time,
'isDismissed' => $this->is_dismissed(),
'isDismissable' => $this->is_dismissable,
'isSnoozed' => $this->is_snoozed(),
'isSnoozeable' => $this->is_snoozeable,
'snoozedUntil' => $this->snoozed_until,
'id' => $this->id,
'title' => $this->title,
'canView' => $this->can_view,
'content' => $this->content,
'additionalInfo' => $this->additional_info,
'actionLabel' => $this->action_label,
'actionUrl' => $this->action_url,
'isComplete' => $this->is_complete,
'canView' => $this->can_view,
'time' => $this->time,
'level' => $this->level,
'isDismissed' => $this->is_dismissed(),
'isDismissable' => $this->is_dismissable,
'isSnoozed' => $this->is_snoozed(),
'isSnoozeable' => $this->is_snoozeable,
'snoozedUntil' => $this->snoozed_until,
);
}

View File

@ -14,6 +14,7 @@ use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\Shipping;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\StoreDetails;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\Tax;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Tasks\WooCommercePayments;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
use Automattic\WooCommerce\Admin\Loader;
/**
@ -96,6 +97,13 @@ class TaskLists {
)
);
self::add_list(
array(
'id' => 'extended',
'title' => __( 'Things to do next', 'woocommerce-admin' ),
)
);
self::add_task( 'setup', StoreDetails::get_task() );
self::add_task( 'setup', Purchase::get_task() );
self::add_task( 'setup', Products::get_task() );
@ -107,13 +115,26 @@ class TaskLists {
self::add_task( 'setup', Appearance::get_task() );
}
/**
* Add default extended task lists.
*
* @param array $extended_tasks list of extended tasks.
*/
public static function maybe_add_extended_tasks( $extended_tasks = array() ) {
foreach ( $extended_tasks as $extended_task ) {
self::add_task( $extended_task['list_id'], $extended_task );
}
}
/**
* Get all task lists.
*
* @param array $extended_tasks array of optional extended tasks.
* @return array
*/
public static function get_lists() {
public static function get_lists( $extended_tasks = array() ) {
self::maybe_add_default_tasks();
self::maybe_add_extended_tasks( $extended_tasks );
return self::$lists;
}

View File

@ -16,19 +16,23 @@ class WooCommercePayments {
*/
public static function get_task() {
return array(
'id' => 'woocommerce-payments',
'title' => __( 'Get paid with WooCommerce Payments', 'woocommerce-admin' ),
'content' => __(
'id' => 'woocommerce-payments',
'title' => __( 'Get paid with WooCommerce Payments', 'woocommerce-admin' ),
'content' => __(
"You're only one step away from getting paid. Verify your business details to start managing transactions with WooCommerce Payments.",
'woocommerce-admin'
),
'action_label' => __( 'Finish setup', 'woocommerce-admin' ),
'expanded' => true,
'is_complete' => self::is_connected(),
'can_view' => self::is_requested() &&
'action_label' => __( 'Finish setup', 'woocommerce-admin' ),
'expanded' => true,
'is_complete' => self::is_connected(),
'can_view' => self::is_requested() &&
self::is_installed() &&
self::is_supported(),
'time' => __( '2 minutes', 'woocommerce-admin' ),
'time' => __( '2 minutes', 'woocommerce-admin' ),
'additional_info' => __(
'By setting up, you are agreeing to the <a href="https://wordpress.com/tos/" target="_blank">Terms of Service</a>',
'woocommerce-admin'
),
);
}