Adding context property to tasklist tracks event, introducing LayoutContext (#33287)

This commit is contained in:
Joel Thiessen 2022-06-14 11:31:50 -07:00 committed by GitHub
parent 143d86490d
commit 183ac65c82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 242 additions and 137 deletions

View File

@ -6,11 +6,9 @@ import { TaskType } from './types';
/**
* Filters tasks to only visible tasks, taking in account snoozed tasks.
*/
export function getVisibleTasks( tasks: TaskType[] ) {
const nowTimestamp = Date.now();
return tasks.filter(
export const getVisibleTasks = ( tasks: TaskType[] ) =>
tasks.filter(
( task ) =>
! task.isDismissed &&
( ! task.isSnoozed || task.snoozedUntil < nowTimestamp )
( ! task.isSnoozed || task.snoozedUntil < Date.now() )
);
}

View File

@ -2,7 +2,7 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { lazy, useState } from '@wordpress/element';
import { lazy, useState, useContext, useMemo } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import { uniqueId, find } from 'lodash';
import { Icon, help as helpIcon, external } from '@wordpress/icons';
@ -12,6 +12,7 @@ import {
OPTIONS_STORE_NAME,
useUser,
useUserPreferences,
getVisibleTasks,
} from '@woocommerce/data';
import { getHistory } from '@woocommerce/navigation';
import { recordEvent } from '@woocommerce/tracks';
@ -36,6 +37,8 @@ import {
import { getUnapprovedReviews } from '../homescreen/activity-panel/reviews/utils';
import { ABBREVIATED_NOTIFICATION_SLOT_NAME } from './panels/inbox/abbreviated-notifications-panel';
import { getAdminSetting } from '~/utils/admin-settings';
import { useActiveSetupTasklist } from '~/tasks';
import { LayoutContext } from '~/layout';
const HelpPanel = lazy( () =>
import( /* webpackChunkName: "activity-panels-help" */ './panels/help' )
@ -61,6 +64,12 @@ export const ActivityPanel = ( { isEmbedded, query } ) => {
const { fills } = useSlot( ABBREVIATED_NOTIFICATION_SLOT_NAME );
const hasExtendedNotifications = Boolean( fills?.length );
const { updateUserPreferences, ...userData } = useUserPreferences();
const activeSetupList = useActiveSetupTasklist();
const layoutContext = useContext( LayoutContext );
const updatedLayoutContext = useMemo(
() => layoutContext.getExtendedContext( 'activity-panel' ),
[ layoutContext ]
);
const getPreviewSiteBtnTrackData = ( select, getOption ) => {
let trackData = {};
@ -137,6 +146,8 @@ export const ActivityPanel = ( { isEmbedded, query } ) => {
requestingTaskListOptions,
setupTaskListComplete,
setupTaskListHidden,
setupTasksCompleteCount,
setupTasksCount,
previewSiteBtnTrackData,
} = useSelect( ( select ) => {
const { getOption } = select( OPTIONS_STORE_NAME );
@ -144,7 +155,10 @@ export const ActivityPanel = ( { isEmbedded, query } ) => {
ONBOARDING_STORE_NAME
);
const isSetupTaskListHidden = getTaskList( 'setup' )?.isHidden;
const setupList = getTaskList( activeSetupList );
const isSetupTaskListHidden = setupList?.isHidden;
const setupVisibleTasks = getVisibleTasks( setupList?.tasks || [] );
const extendedTaskList = getTaskList( 'extended' );
const thingsToDoCount = getThingsToDoNextCount( extendedTaskList );
@ -160,8 +174,12 @@ export const ActivityPanel = ( { isEmbedded, query } ) => {
requestingTaskListOptions: ! hasFinishedResolution(
'getTaskLists'
),
setupTaskListComplete: getTaskList( 'setup' )?.isComplete,
setupTaskListComplete: setupList?.isComplete,
setupTaskListHidden: isSetupTaskListHidden,
setupTasksCount: setupVisibleTasks.length,
setupTasksCompleteCount: setupVisibleTasks.filter(
( task ) => task.isComplete
).length,
isCompletedTask: Boolean(
query.task && getTask( query.task )?.isComplete
),
@ -230,7 +248,14 @@ export const ActivityPanel = ( { isEmbedded, query } ) => {
const setup = {
name: 'setup',
title: __( 'Finish setup', 'woocommerce' ),
icon: <SetupProgress />,
icon: (
<SetupProgress
setupTasksComplete={ setupTasksCompleteCount }
setupCompletePercent={ Math.ceil(
( setupTasksCompleteCount / setupTasksCount ) * 100
) }
/>
),
visible:
currentUserCan( 'manage_woocommerce' ) &&
! requestingTaskListOptions &&
@ -349,55 +374,57 @@ export const ActivityPanel = ( { isEmbedded, query } ) => {
const showHelpHighlightTooltip = shouldShowHelpTooltip();
return (
<div>
<H id={ headerId } className="screen-reader-text">
{ __( 'Store Activity', 'woocommerce' ) }
</H>
<Section
component="aside"
id="woocommerce-activity-panel"
className="woocommerce-layout__activity-panel"
aria-labelledby={ headerId }
>
<Tabs
tabs={ tabs }
tabOpen={ isPanelOpen }
selectedTab={ currentTab }
onTabClick={ ( tab, tabOpen ) => {
if ( tab.onClick ) {
tab.onClick();
return;
}
<LayoutContext.Provider value={ updatedLayoutContext }>
<div>
<H id={ headerId } className="screen-reader-text">
{ __( 'Store Activity', 'woocommerce' ) }
</H>
<Section
component="aside"
id="woocommerce-activity-panel"
className="woocommerce-layout__activity-panel"
aria-labelledby={ headerId }
>
<Tabs
tabs={ tabs }
tabOpen={ isPanelOpen }
selectedTab={ currentTab }
onTabClick={ ( tab, tabOpen ) => {
if ( tab.onClick ) {
tab.onClick();
return;
}
togglePanel( tab, tabOpen );
} }
/>
<Panel
currentTab
isPanelOpen={ isPanelOpen }
isPanelSwitching={ isPanelSwitching }
tab={ find( getTabs(), { name: currentTab } ) }
content={ getPanelContent( currentTab ) }
closePanel={ () => closePanel() }
clearPanel={ () => clearPanel() }
/>
</Section>
{ showHelpHighlightTooltip ? (
<HighlightTooltip
delay={ 1000 }
useAnchor={ true }
title={ __( "We're here for help", 'woocommerce' ) }
content={ __(
'If you have any questions, feel free to explore the WooCommerce docs listed here.',
'woocommerce'
) }
closeButtonText={ __( 'Got it', 'woocommerce' ) }
id="activity-panel-tab-help"
onClose={ () => closedHelpPanelHighlight() }
onShow={ () => recordEvent( 'help_tooltip_view' ) }
/>
) : null }
</div>
togglePanel( tab, tabOpen );
} }
/>
<Panel
currentTab
isPanelOpen={ isPanelOpen }
isPanelSwitching={ isPanelSwitching }
tab={ find( getTabs(), { name: currentTab } ) }
content={ getPanelContent( currentTab ) }
closePanel={ () => closePanel() }
clearPanel={ () => clearPanel() }
/>
</Section>
{ showHelpHighlightTooltip ? (
<HighlightTooltip
delay={ 1000 }
useAnchor={ true }
title={ __( "We're here for help", 'woocommerce' ) }
content={ __(
'If you have any questions, feel free to explore the WooCommerce docs listed here.',
'woocommerce'
) }
closeButtonText={ __( 'Got it', 'woocommerce' ) }
id="activity-panel-tab-help"
onClose={ () => closedHelpPanelHighlight() }
onShow={ () => recordEvent( 'help_tooltip_view' ) }
/>
) : null }
</div>
</LayoutContext.Provider>
);
};

View File

@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
import Tasks from '~/tasks';
import { Tasks } from '~/tasks';
type QueryTypeProps = {
query: {

View File

@ -1,21 +1,38 @@
export const SetupProgress = () => (
export const SetupProgress = ( {
setupTasksComplete,
setupCompletePercent,
} ) => (
<svg
className="woocommerce-layout__activity-panel-tab-icon setup-progress"
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 25 25"
>
<path
d="M12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20Z"
stroke="#DCDCDE"
strokeWidth="2"
className="setup-progress-ring"
d="M 12.476 23.237 C 18.369 23.237 23.146 18.414 23.146 12.464 C 23.146 6.512 18.369 1.687 12.476 1.687 C 6.581 1.687 1.803 6.512 1.803 12.464 C 1.803 18.414 6.581 23.237 12.476 23.237 Z"
/>
<path
d="M4 12V12C4 16.4183 7.58172 20 12 20V20C16.4183 20 20 16.4183 20 12V12C20 7.58172 16.4183 4 12 4V4"
strokeWidth="2"
strokeLinecap="round"
className="setup-progress-slice"
transform="matrix(-0.034188, 0, 0, 0.034134, 38.373184, -8.278505)"
d="M 522 607 A 237 237 0 0 1 759 370 L 759 607 Z"
fill={ setupTasksComplete > 0 ? 'currentColor' : 'white' }
/>
<path
className="setup-progress-slice"
transform="matrix(-0.034188, 0, 0, -0.034134, 38.368454, 33.13131)"
d="M 522 607 A 237 237 0 0 1 759 370 L 759 607 Z"
fill={ setupCompletePercent >= 50 ? 'currentColor' : 'white' }
/>
<path
className="setup-progress-slice"
transform="matrix(0.034188, 0, 0, -0.034134, -13.500516, 33.133827)"
d="M 522 607 A 237 237 0 0 1 759 370 L 759 607 Z"
fill={ setupCompletePercent >= 75 ? 'currentColor' : 'white' }
/>
<path
className="setup-progress-slice"
transform="matrix(0.034188, 0, 0, 0.034134, -13.495783, -8.281025)"
d="M 522 607 A 237 237 0 0 1 759 370 L 759 607 Z"
fill="white"
/>
</svg>
);

View File

@ -29,11 +29,12 @@
}
}
// custom progress icon, requires specific coloring
&.setup-progress {
path:first-child {
stroke: '#DCDCDE';
}
.setup-progress-slice {
stroke: none;
}
.setup-progress-ring {
stroke-width: 2px;
}
}
@ -69,8 +70,6 @@
outline: none;
cursor: pointer;
background-color: $studio-white;
max-width: min-content;
min-width: 80px;
width: 100%;
height: $header-height;
color: $gray-700;
@ -204,16 +203,15 @@
}
transform: translateX(100%);
@include activity-panel-slide();
position: fixed;
position: absolute;
right: 0;
top: #{$header-height + $adminbar-height-mobile};
top: 100%;
z-index: 1000;
overflow-x: hidden;
overflow-y: auto;
@include breakpoint( '>782px' ) {
height: calc(100vh - #{$header-height + $adminbar-height});
top: #{$header-height + $adminbar-height};
}
.has-woocommerce-navigation & {
height: calc(100vh - #{$header-height});

View File

@ -44,7 +44,9 @@ import { getAdminSetting } from '~/utils/admin-settings';
import { ProgressTitle } from '../task-lists';
const Tasks = lazy( () =>
import( /* webpackChunkName: "tasks" */ '../tasks' )
import( /* webpackChunkName: "tasks" */ '../tasks' ).then( ( module ) => ( {
default: module.Tasks,
} ) )
);
const TwoColumnTasks = lazy( () =>

View File

@ -4,7 +4,7 @@
import { SlotFillProvider } from '@wordpress/components';
import { compose } from '@wordpress/compose';
import { withSelect } from '@wordpress/data';
import { Component, lazy, Suspense } from '@wordpress/element';
import { Component, lazy, Suspense, createContext } from '@wordpress/element';
import {
unstable_HistoryRouter as HistoryRouter,
Route,
@ -15,7 +15,7 @@ import {
} from 'react-router-dom';
import { Children, cloneElement } from 'react';
import PropTypes from 'prop-types';
import { get, isFunction, identity } from 'lodash';
import { get, isFunction, identity, memoize } from 'lodash';
import { parse } from 'qs';
import { getHistory, getQuery } from '@woocommerce/navigation';
import {
@ -51,6 +51,20 @@ const WCPayUsageModal = lazy( () =>
)
);
const LayoutContextPrototype = {
getExtendedContext( newItem ) {
return { ...this, path: [ ...this.path, newItem ] };
},
toString() {
return this.path.join( '/' );
},
path: [],
};
export const LayoutContext = createContext(
LayoutContextPrototype.getExtendedContext( 'root' )
);
export class PrimaryLayout extends Component {
render() {
const { children } = this.props;
@ -111,6 +125,13 @@ const LayoutSwitchWrapper = ( props ) => {
};
class _Layout extends Component {
memoizedLayoutContext = memoize( ( page ) =>
LayoutContextPrototype.getExtendedContext(
page?.breadcrumbs[ page.breadcrumbs.length - 1 ]?.toLowerCase() ||
'page'
)
);
componentDidMount() {
this.recordPageViewTrack();
}
@ -195,38 +216,45 @@ class _Layout extends Component {
const query = this.getQuery( location && location.search );
return (
<SlotFillProvider>
<div className="woocommerce-layout">
<Header
sections={
isFunction( breadcrumbs )
? breadcrumbs( this.props )
: breadcrumbs
}
isEmbedded={ isEmbedded }
query={ query }
/>
<TransientNotices />
{ ! isEmbedded && (
<PrimaryLayout>
<div className="woocommerce-layout__main">
<Controller { ...restProps } query={ query } />
</div>
</PrimaryLayout>
) }
<LayoutContext.Provider
value={ this.memoizedLayoutContext( page ) }
>
<SlotFillProvider>
<div className="woocommerce-layout">
<Header
sections={
isFunction( breadcrumbs )
? breadcrumbs( this.props )
: breadcrumbs
}
isEmbedded={ isEmbedded }
query={ query }
/>
<TransientNotices />
{ ! isEmbedded && (
<PrimaryLayout>
<div className="woocommerce-layout__main">
<Controller
{ ...restProps }
query={ query }
/>
</div>
</PrimaryLayout>
) }
{ isEmbedded && this.isWCPaySettingsPage() && (
<Suspense fallback={ null }>
<WCPayUsageModal />
</Suspense>
{ isEmbedded && this.isWCPaySettingsPage() && (
<Suspense fallback={ null }>
<WCPayUsageModal />
</Suspense>
) }
</div>
<PluginArea scope="woocommerce-admin" />
{ window.wcAdminFeatures.navigation && (
<PluginArea scope="woocommerce-navigation" />
) }
</div>
<PluginArea scope="woocommerce-admin" />
{ window.wcAdminFeatures.navigation && (
<PluginArea scope="woocommerce-navigation" />
) }
<PluginArea scope="woocommerce-tasks" />
</SlotFillProvider>
<PluginArea scope="woocommerce-tasks" />
</SlotFillProvider>
</LayoutContext.Provider>
);
}
}

View File

@ -1,11 +1,10 @@
/**
* Internal dependencies
*/
import { Tasks } from './tasks';
import './fills';
import './deprecated-tasks';
export * from './tasks';
export * from './placeholder';
export * from './reminder-bar';
export * from './hooks/useActiveSetupList';
export default Tasks;

View File

@ -6,7 +6,8 @@ import { useSelect, useDispatch } from '@wordpress/data';
import {
ONBOARDING_STORE_NAME,
OPTIONS_STORE_NAME,
TaskListType,
TaskType,
getVisibleTasks,
} from '@woocommerce/data';
import { Button } from '@wordpress/components';
import { Link } from '@woocommerce/components';
@ -112,15 +113,10 @@ export const TasksReminderBar: React.FC< ReminderBarProps > = ( {
REMINDER_BAR_HIDDEN_OPTION,
] );
const visibleTasks =
taskList?.tasks.filter(
( task ) =>
! task.isDismissed &&
( ! task.isSnoozed || task.snoozedUntil < Date.now() )
) || [];
const visibleTasks = getVisibleTasks( taskList?.tasks || [] );
const completedTasks =
visibleTasks?.filter( ( task ) => task.isComplete ) || [];
visibleTasks.filter( ( task: TaskType ) => task.isComplete ) || [];
const isResolved = taskListIsResolved && optionIsResolved;

View File

@ -10,13 +10,14 @@ import {
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { TaskItem, useSlot } from '@woocommerce/experimental';
import { useCallback } from '@wordpress/element';
import { useCallback, useContext } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { WooOnboardingTaskListItem } from '@woocommerce/onboarding';
/**
* Internal dependencies
*/
import { LayoutContext } from '~/layout';
import './task-list.scss';
export type TaskListItemProps = {
@ -35,6 +36,7 @@ export const TaskListItem: React.FC< TaskListItemProps > = ( {
task,
} ) => {
const { createNotice } = useDispatch( 'core/notices' );
const layoutContext = useContext( LayoutContext );
const {
dismissTask,
@ -117,6 +119,7 @@ export const TaskListItem: React.FC< TaskListItemProps > = ( {
const trackClick = () => {
recordEvent( 'tasklist_click', {
task_name: id,
context: layoutContext.toString(),
} );
if ( ! isComplete ) {

View File

@ -2,7 +2,7 @@
* External dependencies
*/
import { __, _n, sprintf } from '@wordpress/i18n';
import { useEffect, useRef, useState } from '@wordpress/element';
import { useEffect, useRef, useState, useContext } from '@wordpress/element';
import { Card, CardHeader } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { Badge } from '@woocommerce/components';
@ -21,6 +21,7 @@ import { TaskListItem } from './task-list-item';
import { TaskListMenu } from './task-list-menu';
import './task-list.scss';
import { ProgressHeader } from '~/task-lists/progress-header';
import { LayoutContext } from '~/layout';
export type TaskListProps = TaskListType & {
query: {
@ -51,6 +52,7 @@ export const TaskList: React.FC< TaskListProps > = ( {
} );
const prevQueryRef = useRef( query );
const visibleTasks = getVisibleTasks( tasks );
const layoutContext = useContext( LayoutContext );
const incompleteTasks = tasks.filter(
( task ) => ! task.isComplete && ! task.isDismissed
@ -64,6 +66,7 @@ export const TaskList: React.FC< TaskListProps > = ( {
recordEvent( eventPrefix + 'view', {
number_tasks: visibleTasks.length,
store_connected: profileItems.wccom_connected,
context: layoutContext.toString(),
} );
};

View File

@ -4,7 +4,7 @@
import { __ } from '@wordpress/i18n';
import { MenuGroup, MenuItem } from '@wordpress/components';
import { check } from '@wordpress/icons';
import { Fragment, useEffect } from '@wordpress/element';
import { Fragment, useEffect, useState } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import {
ONBOARDING_STORE_NAME,
@ -33,6 +33,7 @@ import { SectionedTaskListPlaceholder } from '~/two-column-tasks/sectioned-task-
export type TasksProps = {
query: { task?: string };
context?: string;
};
function getTaskListComponent( taskListId: string ) {
@ -155,12 +156,9 @@ export const Tasks: React.FC< TasksProps > = ( { query } ) => {
? id.endsWith( 'two_column' )
: ! id.endsWith( 'two_column' )
)
.filter( ( { isVisible }: TaskListType ) => isVisible )
.map( ( taskList: TaskListType ) => {
const { id, isHidden, isVisible, isToggleable } = taskList;
if ( ! isVisible ) {
return null;
}
const { id, isHidden, isToggleable } = taskList;
const TaskListComponent = getTaskListComponent( id );
return (

View File

@ -144,6 +144,7 @@ describe( 'TaskList', () => {
);
expect( recordEvent ).toHaveBeenCalledTimes( 1 );
expect( recordEvent ).toHaveBeenCalledWith( 'tasklist_view', {
context: 'root',
number_tasks: 0,
store_connected: null,
} );
@ -166,6 +167,7 @@ describe( 'TaskList', () => {
);
expect( recordEvent ).toHaveBeenCalledTimes( 1 );
expect( recordEvent ).toHaveBeenCalledWith( 'extended_tasklist_view', {
context: 'root',
number_tasks: 0,
store_connected: null,
} );

View File

@ -1,7 +1,7 @@
/**
* External dependencies
*/
import { useEffect, useRef, useState } from '@wordpress/element';
import { useEffect, useRef, useState, useContext } from '@wordpress/element';
import { Panel, PanelBody, PanelRow } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { ONBOARDING_STORE_NAME, getVisibleTasks } from '@woocommerce/data';
@ -20,6 +20,7 @@ import { ProgressHeader } from '~/task-lists/progress-header';
import { SectionPanelTitle } from './section-panel-title';
import { TaskListItem } from './task-list-item';
import { TaskListCompletedHeader } from './completed-header';
import { LayoutContext } from '~/layout';
type PanelBodyProps = Omit< PanelBody.Props, 'title' | 'onToggle' > & {
title: string | React.ReactNode | undefined;
@ -51,6 +52,7 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
const [ openPanel, setOpenPanel ] = useState< string | null >(
sections?.find( ( section ) => ! section.isComplete )?.id || null
);
const layoutContext = useContext( LayoutContext );
const prevQueryRef = useRef( query );
@ -64,6 +66,7 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
recordEvent( `${ eventPrefix }view`, {
number_tasks: visibleTasks.length,
store_connected: profileItems.wccom_connected,
context: layoutContext.toString(),
} );
};

View File

@ -5,17 +5,21 @@ import { __ } from '@wordpress/i18n';
import { getNewPath, navigateTo } from '@woocommerce/navigation';
import {
ONBOARDING_STORE_NAME,
OPTIONS_STORE_NAME,
TaskType,
useUserPreferences,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { TaskItem, useSlot } from '@woocommerce/experimental';
import { useCallback } from '@wordpress/element';
import { useCallback, useContext } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { WooOnboardingTaskListItem } from '@woocommerce/onboarding';
import classnames from 'classnames';
/**
* Internal dependencies
*/
import { LayoutContext } from '~/layout';
export type TaskListItemProps = {
task: TaskType;
eventPrefix?: string;
@ -35,6 +39,8 @@ export const TaskListItem: React.FC< TaskListItemProps > = ( {
undoSnoozeTask,
} = useDispatch( ONBOARDING_STORE_NAME );
const layoutContext = useContext( LayoutContext );
const slot = useSlot(
`woocommerce_onboarding_task_list_item_${ task.id }`
);
@ -68,6 +74,7 @@ export const TaskListItem: React.FC< TaskListItemProps > = ( {
const trackClick = () => {
recordEvent( `${ eventPrefix }click`, {
task_name: task.id,
context: layoutContext.toString(),
} );
if ( ! task.isComplete ) {

View File

@ -2,7 +2,13 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { useEffect, useRef, useState, createElement } from '@wordpress/element';
import {
useEffect,
useRef,
useState,
createElement,
useContext,
} from '@wordpress/element';
import { Button, Card } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { EllipsisMenu } from '@woocommerce/components';
@ -29,6 +35,7 @@ import TaskListCompleted from './completed';
import { ProgressHeader } from '~/task-lists/progress-header';
import { TaskListItemTwoColumn } from './task-list-item-two-column';
import { TaskListCompletedHeader } from './completed-header';
import { LayoutContext } from '~/layout';
export type TaskListProps = TaskListType & {
eventName?: string;
@ -71,6 +78,7 @@ export const TaskList: React.FC< TaskListProps > = ( {
} >( {} );
const [ activeTaskId, setActiveTaskId ] = useState( '' );
const [ showDismissModal, setShowDismissModal ] = useState( false );
const layoutContext = useContext( LayoutContext );
const prevQueryRef = useRef( query );
@ -83,6 +91,7 @@ export const TaskList: React.FC< TaskListProps > = ( {
recordEvent( `${ listEventPrefix }view`, {
number_tasks: visibleTasks.length,
store_connected: profileItems.wccom_connected,
context: layoutContext.toString(),
} );
};
@ -179,6 +188,7 @@ export const TaskList: React.FC< TaskListProps > = ( {
const trackClick = ( task: TaskType ) => {
recordEvent( `${ listEventPrefix }click`, {
task_name: task.id,
context: layoutContext.toString(),
} );
};

View File

@ -148,6 +148,7 @@ describe( 'TaskList', () => {
);
expect( recordEvent ).toHaveBeenCalledTimes( 1 );
expect( recordEvent ).toHaveBeenCalledWith( 'tasklist_view', {
context: 'root',
number_tasks: 0,
store_connected: null,
} );
@ -170,6 +171,7 @@ describe( 'TaskList', () => {
);
expect( recordEvent ).toHaveBeenCalledTimes( 1 );
expect( recordEvent ).toHaveBeenCalledWith( 'tasklist_view', {
context: 'root',
number_tasks: 0,
store_connected: null,
} );
@ -193,6 +195,7 @@ describe( 'TaskList', () => {
);
expect( recordEvent ).toHaveBeenCalledTimes( 1 );
expect( recordEvent ).toHaveBeenCalledWith( 'extended_tasklist_view', {
context: 'root',
number_tasks: 0,
store_connected: null,
} );

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Adding property to tasks tracks events to indicate context.

View File

@ -171,7 +171,7 @@ class TaskList {
* @return bool
*/
public function is_visible() {
if ( ! $this->visible ) {
if ( ! $this->visible || ! count( $this->get_viewable_tasks() ) > 0 ) {
return false;
}
return ! $this->is_hidden();

View File

@ -104,7 +104,6 @@ class WC_Tests_Payment_Tokens extends WC_Unit_Test_Case {
* Test getting a customers default token, when there no token is expictly set.
* This should be the "first created".
* @see WC_Payment_Token::create()
* @group failing
* @since 2.6.0
*/
public function test_wc_get_customer_default_token_returns_first_created_when_no_default_token_set() {

View File

@ -8,6 +8,7 @@
require_once __DIR__ . '/test-task.php';
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\TaskList;
use Automattic\WooCommerce\Admin\Features\OnboardingTasks\Task;
/**
* class WC_Admin_Tests_OnboardingTasks_TaskList
@ -89,6 +90,13 @@ class WC_Admin_Tests_OnboardingTasks_TaskList extends WC_Unit_Test_Case {
* Tests that lists can be hidden.
*/
public function test_visible() {
$this->assertFalse( $this->list->is_visible() );
$this->list->add_task(
new TestTask(
new TaskList(),
array( 'id' => 'my-task' )
)
);
$this->assertTrue( $this->list->is_visible() );
}