fix: lys hub show only incompleted and recent tasks (#46190)

* fix: lys hub show only incompleted and recent tasks

* disable completed task items

* Update plugins/woocommerce-admin/client/launch-your-store/hub/sidebar/tasklist.tsx

Co-authored-by: Ilyas Foo <foo.ilyas@gmail.com>

* strikethrough font color

---------

Co-authored-by: Ilyas Foo <foo.ilyas@gmail.com>
This commit is contained in:
RJ 2024-04-05 09:54:30 +08:00 committed by GitHub
parent 3f601b3f45
commit 34b48892e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 196 additions and 63 deletions

View File

@ -25,8 +25,9 @@ import {
*/
import type { SidebarComponentProps } from '../xstate';
import { SidebarContainer } from './sidebar-container';
import { taskCompleteIcon, taskIcons } from './icons';
import { taskCompleteIcon } from './icons';
import { SiteHub } from '~/customize-store/assembler-hub/site-hub';
import { CompletedTaskItem, IncompleteTaskItem } from '../tasklist';
export const LaunchYourStoreHubSidebar: React.FC< SidebarComponentProps > = (
props
) => {
@ -109,28 +110,25 @@ export const LaunchYourStoreHubSidebar: React.FC< SidebarComponentProps > = (
<ItemGroup className="edit-site-sidebar-navigation-screen-essential-tasks__group">
{ tasklist &&
hasIncompleteTasks &&
tasklist.tasks.map( ( task ) => (
<SidebarNavigationItem
className={ classnames( task.id, {
'is-complete': task.isComplete,
} ) }
icon={
task.isComplete
? taskCompleteIcon
: taskIcons[ task.id ]
}
withChevron
key={ task.id }
onClick={ () => {
props.sendEventToSidebar( {
type: 'TASK_CLICKED',
task,
} );
} }
>
{ task.title }
</SidebarNavigationItem>
) ) }
tasklist.tasks.map( ( task ) =>
task.isComplete ? (
<CompletedTaskItem
task={ task }
key={ task.id }
/>
) : (
<IncompleteTaskItem
task={ task }
key={ task.id }
onClick={ () => {
props.sendEventToSidebar( {
type: 'TASK_CLICKED',
task,
} );
} }
/>
)
) }
{ tasklist && ! hasIncompleteTasks && (
<SidebarNavigationItem
className="all-tasks-complete"

View File

@ -0,0 +1,117 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable @woocommerce/dependency-group */
/**
* External dependencies
*/
import { ONBOARDING_STORE_NAME, TaskType } from '@woocommerce/data';
import { navigateTo, getNewPath } from '@woocommerce/navigation';
import { resolveSelect } from '@wordpress/data';
import { applyFilters } from '@wordpress/hooks';
import classnames from 'classnames';
// @ts-ignore No types for this exist yet.
import SidebarNavigationItem from '@wordpress/edit-site/build-module/components/sidebar-navigation-item';
/**
* Internal dependencies
*/
import { createStorageUtils } from '~/utils/localStorage';
import { taskCompleteIcon, taskIcons } from './components/icons';
const SEVEN_DAYS_IN_SECONDS = 60 * 60 * 24 * 7;
export const LYS_RECENTLY_ACTIONED_TASKS_KEY = 'lys_recently_actioned_tasks';
export const {
getWithExpiry: getRecentlyActionedTasks,
setWithExpiry: saveRecentlyActionedTask,
} = createStorageUtils< string[] >(
LYS_RECENTLY_ACTIONED_TASKS_KEY,
SEVEN_DAYS_IN_SECONDS
);
export const getLysTasklist = async () => {
const LYS_TASKS_WHITELIST = [
'products',
'customize-store',
'woocommerce-payments',
'payments',
'shipping',
'tax',
];
/**
* This filter allows customizing the list of tasks to show in WooCommerce Launch Your Store feature.
*
* @filter woocommerce_launch_your_store_tasklist_whitelist
* @param {string[]} LYS_TASKS_WHITELIST Default list of task IDs to show in LYS.
*
*/
const filteredTasks = applyFilters(
'woocommerce_launch_your_store_tasklist_whitelist',
[ ...LYS_TASKS_WHITELIST ]
) as string[];
const tasklist = await resolveSelect(
ONBOARDING_STORE_NAME
).getTaskListsByIds( [ 'setup' ] );
const recentlyActionedTasks = getRecentlyActionedTasks() ?? [];
/**
* Show tasks that fulfill all the following conditions:
* 1. part of the whitelist of tasks to show in LYS
* 2. either not completed or recently actioned
*/
const visibleTasks = tasklist[ 0 ].tasks.filter(
( task ) =>
filteredTasks.includes( task.id ) &&
( ! task.isComplete || recentlyActionedTasks.includes( task.id ) )
);
return {
...tasklist[ 0 ],
tasks: visibleTasks,
};
};
export function taskClickedAction( event: {
type: 'TASK_CLICKED';
task: TaskType;
} ) {
const recentlyActionedTasks = getRecentlyActionedTasks() ?? [];
saveRecentlyActionedTask( [ ...recentlyActionedTasks, event.task.id ] );
if ( event.task.actionUrl ) {
navigateTo( { url: event.task.actionUrl } );
} else {
navigateTo( {
url: getNewPath( { task: event.task.id }, '/', {} ),
} );
}
}
export const CompletedTaskItem: React.FC< {
task: TaskType;
classNames?: string;
} > = ( { task, classNames } ) => (
<SidebarNavigationItem
className={ classnames( task.id, 'is-complete', classNames ) }
icon={ taskCompleteIcon }
disabled={ true }
>
{ task.title }
</SidebarNavigationItem>
);
export const IncompleteTaskItem: React.FC< {
task: TaskType;
classNames?: string;
onClick: () => void;
} > = ( { task, classNames, onClick } ) => (
<SidebarNavigationItem
className={ classnames( task.id, classNames ) }
icon={ taskIcons[ task.id ] }
withChevron
onClick={ onClick }
>
{ task.title }
</SidebarNavigationItem>
);

View File

@ -11,14 +11,8 @@ import {
} from 'xstate5';
import React from 'react';
import classnames from 'classnames';
import { getNewPath, getQuery, navigateTo } from '@woocommerce/navigation';
import { resolveSelect } from '@wordpress/data';
import {
ONBOARDING_STORE_NAME,
TaskListType,
TaskType,
} from '@woocommerce/data';
import { applyFilters } from '@wordpress/hooks';
import { getQuery, navigateTo } from '@woocommerce/navigation';
import { TaskListType, TaskType } from '@woocommerce/data';
/**
* Internal dependencies
@ -27,6 +21,7 @@ import { LaunchYourStoreHubSidebar } from './components/launch-store-hub';
import type { LaunchYourStoreComponentProps } from '..';
import type { mainContentMachine } from '../main-content/xstate';
import { updateQueryParams, createQueryParamsListener } from '../common';
import { taskClickedAction, getLysTasklist } from './tasklist';
export type SidebarMachineContext = {
externalUrl: string | null;
@ -52,31 +47,6 @@ const sidebarQueryParamListener = fromCallback( ( { sendBack } ) => {
return createQueryParamsListener( 'sidebar', sendBack );
} );
const getLysTasklist = async () => {
const LYS_TASKS = [
'products',
'customize-store',
'woocommerce-payments',
'payments',
'shipping',
'tax',
];
const tasklist = await resolveSelect(
ONBOARDING_STORE_NAME
).getTaskListsByIds( [ 'setup' ] );
const visibleTasks: string[] = applyFilters(
'woocommerce_launch_your_store_tasklist_visible',
[ ...LYS_TASKS ]
) as string[];
return {
...tasklist[ 0 ],
tasks: tasklist[ 0 ].tasks.filter( ( task ) =>
visibleTasks.includes( task.id )
),
};
};
export const sidebarMachine = setup( {
types: {} as {
context: SidebarMachineContext;
@ -107,13 +77,7 @@ export const sidebarMachine = setup( {
},
taskClicked: ( { event } ) => {
if ( event.type === 'TASK_CLICKED' ) {
if ( event.task.actionUrl ) {
navigateTo( { url: event.task.actionUrl } );
} else {
navigateTo( {
url: getNewPath( { task: event.task.id }, '/', {} ),
} );
}
taskClickedAction( event );
}
},
openWcAdminUrl: ( { event } ) => {

View File

@ -242,6 +242,15 @@
.edit-site-sidebar-navigation-item.is-complete {
text-decoration: line-through;
color: $gray-700;
&:hover {
background: transparent;
color: $gray-700;
}
.components-flex-block {
color: $gray-700;
}
}
}
}

View File

@ -0,0 +1,41 @@
type StoredItem< T > = {
data: T;
expiry: string;
};
/**
* This constructor function exists for type safety purposes, so when you create a pair of set/get functions they have the
* same type for the value they store/retrieve.
*/
export function createStorageUtils< T >(
key: string,
durationInSeconds: number
) {
return {
setWithExpiry: ( value: T ): void => {
const now = new Date();
const expiry = new Date( now.getTime() + durationInSeconds * 1000 );
const item: StoredItem< T > = {
data: value,
expiry: expiry.toISOString(),
};
localStorage.setItem( key, JSON.stringify( item ) );
},
getWithExpiry: (): T | null => {
const itemStr = localStorage.getItem( key );
if ( ! itemStr ) {
return null;
}
const item: StoredItem< T > = JSON.parse( itemStr );
const now = new Date();
if ( now > new Date( item.expiry ) ) {
localStorage.removeItem( key );
return null;
}
return item.data;
},
};
}

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Fix the LYS Hub tasklist so that it only shows incomplete tasks and tasks that were recently actioned