* Add Task model API * Add task dismiss and snooze methods * Add tests * Fix snooze time check
This commit is contained in:
parent
2be141bd16
commit
9a361dde6c
|
@ -0,0 +1,296 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles task related methods.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task class.
|
||||||
|
*/
|
||||||
|
class Task {
|
||||||
|
/**
|
||||||
|
* ID.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $id = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $title = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $content = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action label.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $action_label = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action URL.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $action_url = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task completion.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $is_complete = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Viewing capability.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $can_view = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time string.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $time = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismissability.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $is_dismissable = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snoozeability.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $is_snoozeable = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snoozeability.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
public $snoozed_until = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the dismiss option.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const DISMISSED_OPTION = 'woocommerce_task_list_dismissed_tasks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the snooze option.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const SNOOZED_OPTION = 'woocommerce_task_list_remind_me_later_tasks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Duration to milisecond mapping.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $duration_to_ms = array(
|
||||||
|
'day' => DAY_IN_SECONDS * 1000,
|
||||||
|
'hour' => HOUR_IN_SECONDS * 1000,
|
||||||
|
'week' => WEEK_IN_SECONDS * 1000,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param array $data Task list data.
|
||||||
|
*/
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
|
$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'];
|
||||||
|
|
||||||
|
$snoozed_tasks = get_option( self::SNOOZED_OPTION, array() );
|
||||||
|
if ( isset( $snoozed_tasks[ $this->id ] ) ) {
|
||||||
|
$this->snoozed_until = $snoozed_tasks[ $this->id ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bool for task dismissal.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_dismissed() {
|
||||||
|
if ( ! $this->is_dismissable ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dismissed = get_option( self::DISMISSED_OPTION, array() );
|
||||||
|
|
||||||
|
return in_array( $this->id, $dismissed, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismiss the task.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function dismiss() {
|
||||||
|
if ( ! $this->is_dismissable ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dismissed = get_option( self::DISMISSED_OPTION, array() );
|
||||||
|
$dismissed[] = $this->id;
|
||||||
|
$update = update_option( self::DISMISSED_OPTION, array_unique( $dismissed ) );
|
||||||
|
|
||||||
|
if ( $update ) {
|
||||||
|
wc_admin_record_tracks_event( 'tasklist_dismiss_task', array( 'task_name' => $this->id ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $update;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo task dismissal.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function undo_dismiss() {
|
||||||
|
$dismissed = get_option( self::DISMISSED_OPTION, array() );
|
||||||
|
$dismissed = array_diff( $dismissed, array( $this->id ) );
|
||||||
|
$update = update_option( self::DISMISSED_OPTION, $dismissed );
|
||||||
|
|
||||||
|
if ( $update ) {
|
||||||
|
wc_admin_record_tracks_event( 'tasklist_undo_dismiss_task', array( 'task_name' => $this->id ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $update;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bool for task snoozed.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_snoozed() {
|
||||||
|
if ( ! $this->is_snoozeable ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$snoozed = get_option( self::SNOOZED_OPTION, array() );
|
||||||
|
|
||||||
|
return isset( $snoozed[ $this->id ] ) && $snoozed[ $this->id ] > ( time() * 1000 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snooze the task.
|
||||||
|
*
|
||||||
|
* @param string $duration Duration to snooze. day|hour|week.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function snooze( $duration = 'day' ) {
|
||||||
|
if ( ! $this->is_snoozeable ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$snoozed = get_option( self::SNOOZED_OPTION, array() );
|
||||||
|
$snoozed_until = $this->duration_to_ms[ $duration ] + ( time() * 1000 );
|
||||||
|
$snoozed[ $this->id ] = $snoozed_until;
|
||||||
|
$update = update_option( self::SNOOZED_OPTION, $snoozed );
|
||||||
|
|
||||||
|
if ( $update ) {
|
||||||
|
if ( $update ) {
|
||||||
|
wc_admin_record_tracks_event( 'tasklist_remindmelater_task', array( 'task_name' => $this->id ) );
|
||||||
|
$this->snoozed_until = $snoozed_until;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $update;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undo task snooze.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function undo_snooze() {
|
||||||
|
$snoozed = get_option( self::SNOOZED_OPTION, array() );
|
||||||
|
unset( $snoozed[ $this->id ] );
|
||||||
|
$update = update_option( self::SNOOZED_OPTION, $snoozed );
|
||||||
|
|
||||||
|
if ( $update ) {
|
||||||
|
wc_admin_record_tracks_event( 'tasklist_undo_remindmelater_task', array( 'task_name' => $this->id ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $update;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bool for task visibility.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_visible() {
|
||||||
|
return $this->can_view && ! $this->is_snoozed() && ! $this->is_dismissed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the task as JSON.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_json() {
|
||||||
|
return array(
|
||||||
|
'id' => $this->id,
|
||||||
|
'title' => $this->title,
|
||||||
|
'content' => $this->content,
|
||||||
|
'actionLabel' => $this->action_label,
|
||||||
|
'actionUrl' => $this->action_url,
|
||||||
|
'isComplete' => $this->is_complete,
|
||||||
|
'isVisible' => $this->is_visible(),
|
||||||
|
'time' => $this->time,
|
||||||
|
'isDismissed' => $this->is_dismissed(),
|
||||||
|
'isDismissable' => $this->is_dismissable,
|
||||||
|
'isSnoozed' => $this->is_snoozed(),
|
||||||
|
'isSnoozeable' => $this->is_snoozeable,
|
||||||
|
'snoozedUntil' => $this->snoozed_until,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
|
namespace Automattic\WooCommerce\Admin\Features\OnboardingTasks;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Task List class.
|
* Task List class.
|
||||||
*/
|
*/
|
||||||
|
@ -107,7 +109,7 @@ class TaskList {
|
||||||
* @param array $args Task properties.
|
* @param array $args Task properties.
|
||||||
*/
|
*/
|
||||||
public function add_task( $args ) {
|
public function add_task( $args ) {
|
||||||
$this->tasks[] = $args;
|
$this->tasks[] = new Task( $args );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -121,7 +123,12 @@ class TaskList {
|
||||||
'title' => $this->title,
|
'title' => $this->title,
|
||||||
'isHidden' => $this->is_hidden(),
|
'isHidden' => $this->is_hidden(),
|
||||||
'isComplete' => $this->is_complete(),
|
'isComplete' => $this->is_complete(),
|
||||||
'tasks' => $this->tasks,
|
'tasks' => array_map(
|
||||||
|
function( $task ) {
|
||||||
|
return $task->get_json();
|
||||||
|
},
|
||||||
|
$this->tasks
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,246 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Test the Task class.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\Admin\Tests\OnboardingTasks
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class WC_Tests_OnboardingTasks_Task
|
||||||
|
*/
|
||||||
|
class WC_Tests_OnboardingTasks_Task extends WC_Unit_Test_Case {
|
||||||
|
/**
|
||||||
|
* Task.
|
||||||
|
*
|
||||||
|
* @var Task|null
|
||||||
|
*/
|
||||||
|
protected $task = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a task is visible by default.
|
||||||
|
*/
|
||||||
|
public function test_capability_visible() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-task',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals( true, $task->is_visible() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a task is not visible when not capable of being viewed.
|
||||||
|
*/
|
||||||
|
public function test_capability_not_visible() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-task',
|
||||||
|
'can_view' => false,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals( false, $task->is_visible() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a task can be dismissed.
|
||||||
|
*/
|
||||||
|
public function test_dismiss() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-task',
|
||||||
|
'is_dismissable' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$update = $task->dismiss();
|
||||||
|
$dismissed = get_option( Task::DISMISSED_OPTION, array() );
|
||||||
|
$this->assertEquals( true, $update );
|
||||||
|
$this->assertContains( $task->id, $dismissed );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a dismissal can be undone.
|
||||||
|
*/
|
||||||
|
public function test_undo_dismiss() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-task',
|
||||||
|
'is_dismissable' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$task->dismiss();
|
||||||
|
$task->undo_dismiss();
|
||||||
|
$dismissed = get_option( Task::DISMISSED_OPTION, array() );
|
||||||
|
$this->assertNotContains( $task->id, $dismissed );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a non-dismissable task cannot be dismissed.
|
||||||
|
*/
|
||||||
|
public function test_not_dismissable() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-non-dismissable-task',
|
||||||
|
'is_dismissable' => false,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$update = $task->dismiss();
|
||||||
|
$dismissed = get_option( Task::DISMISSED_OPTION, array() );
|
||||||
|
$this->assertEquals( false, $update );
|
||||||
|
$this->assertNotContains( $task->id, $dismissed );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a dismissed task is not visible.
|
||||||
|
*/
|
||||||
|
public function test_dismissed_visibility() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-task',
|
||||||
|
'is_dismissable' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$task->dismiss();
|
||||||
|
$this->assertEquals( false, $task->is_visible() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a task can be snoozed.
|
||||||
|
*/
|
||||||
|
public function test_snooze() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-snoozeable-task',
|
||||||
|
'is_snoozeable' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$update = $task->snooze();
|
||||||
|
$snoozed = get_option( Task::SNOOZED_OPTION, array() );
|
||||||
|
$this->assertEquals( true, $update );
|
||||||
|
$this->assertArrayHasKey( $task->id, $snoozed );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a task can be unsnoozed.
|
||||||
|
*/
|
||||||
|
public function test_undo_snooze() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-snoozeable-task',
|
||||||
|
'is_snoozeable' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$task->snooze();
|
||||||
|
$task->undo_snooze();
|
||||||
|
$snoozed = get_option( Task::SNOOZED_OPTION, array() );
|
||||||
|
$this->assertArrayNotHasKey( $task->id, $snoozed );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a task is not visible when snoozed.
|
||||||
|
*/
|
||||||
|
public function test_snoozed_visibility() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-snoozeable-task',
|
||||||
|
'is_snoozeable' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$task->snooze();
|
||||||
|
$this->assertEquals( false, $task->is_visible() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a task's snooze time is automatically added.
|
||||||
|
*/
|
||||||
|
public function test_snoozed_until() {
|
||||||
|
$time = time() * 1000;
|
||||||
|
$snoozed = get_option( Task::SNOOZED_OPTION, array() );
|
||||||
|
$snoozed['wc-unit-test-task'] = $time;
|
||||||
|
update_option( Task::SNOOZED_OPTION, $snoozed );
|
||||||
|
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-task',
|
||||||
|
'is_snoozeable' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals( $time, $task->snoozed_until );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a non snoozeable task cannot be snoozed.
|
||||||
|
*/
|
||||||
|
public function test_not_snoozeable() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-snoozeable-task',
|
||||||
|
'is_snoozeable' => false,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$task->snooze();
|
||||||
|
$this->assertEquals( false, $task->is_snoozed() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a task is no longer consider snoozed after the time has passed.
|
||||||
|
*/
|
||||||
|
public function test_snooze_time() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-snoozeable-task',
|
||||||
|
'is_snoozeable' => true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$time = time() * 1000 - 1;
|
||||||
|
$snoozed = get_option( Task::SNOOZED_OPTION, array() );
|
||||||
|
$snoozed['wc-unit-test-snoozeable-task'] = $time;
|
||||||
|
update_option( Task::SNOOZED_OPTION, $snoozed );
|
||||||
|
|
||||||
|
$this->assertEquals( false, $task->is_snoozed() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that a task's properties are returned as JSON.
|
||||||
|
*/
|
||||||
|
public function test_json() {
|
||||||
|
$task = new Task(
|
||||||
|
array(
|
||||||
|
'id' => 'wc-unit-test-task',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$json = $task->get_json();
|
||||||
|
|
||||||
|
$this->assertArrayHasKey( 'id', $json );
|
||||||
|
$this->assertArrayHasKey( 'title', $json );
|
||||||
|
$this->assertArrayHasKey( 'content', $json );
|
||||||
|
$this->assertArrayHasKey( 'actionLabel', $json );
|
||||||
|
$this->assertArrayHasKey( 'actionUrl', $json );
|
||||||
|
$this->assertArrayHasKey( 'isComplete', $json );
|
||||||
|
$this->assertArrayHasKey( 'isVisible', $json );
|
||||||
|
$this->assertArrayHasKey( 'time', $json );
|
||||||
|
$this->assertArrayHasKey( 'isDismissed', $json );
|
||||||
|
$this->assertArrayHasKey( 'isDismissable', $json );
|
||||||
|
$this->assertArrayHasKey( 'isSnoozed', $json );
|
||||||
|
$this->assertArrayHasKey( 'isSnoozeable', $json );
|
||||||
|
$this->assertArrayHasKey( 'snoozedUntil', $json );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue