Merge pull request #32742 from woocommerce/fix/32714_wcpay_blank_page
Add task list slot fill support in the sectioned task list
This commit is contained in:
commit
542f7ef918
|
@ -160,7 +160,7 @@ export const TasksReminderBar: React.FC< ReminderBarProps > = ( {
|
||||||
|
|
||||||
const tracksProps = {
|
const tracksProps = {
|
||||||
completed: completedTasksCount,
|
completed: completedTasksCount,
|
||||||
is_homescreen: isHomescreen,
|
is_homescreen: !! isHomescreen,
|
||||||
is_active_task_page: isActiveTaskPage,
|
is_active_task_page: isActiveTaskPage,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,22 +5,15 @@ import { __ } from '@wordpress/i18n';
|
||||||
import { useEffect, useRef, useState } from '@wordpress/element';
|
import { useEffect, useRef, useState } from '@wordpress/element';
|
||||||
import { Panel, PanelBody, PanelRow } from '@wordpress/components';
|
import { Panel, PanelBody, PanelRow } from '@wordpress/components';
|
||||||
import { useSelect, useDispatch } from '@wordpress/data';
|
import { useSelect, useDispatch } from '@wordpress/data';
|
||||||
import {
|
|
||||||
updateQueryString,
|
|
||||||
getHistory,
|
|
||||||
getNewPath,
|
|
||||||
} from '@woocommerce/navigation';
|
|
||||||
import {
|
import {
|
||||||
OPTIONS_STORE_NAME,
|
OPTIONS_STORE_NAME,
|
||||||
ONBOARDING_STORE_NAME,
|
ONBOARDING_STORE_NAME,
|
||||||
TaskType,
|
|
||||||
getVisibleTasks,
|
getVisibleTasks,
|
||||||
WCDataSelector,
|
WCDataSelector,
|
||||||
} from '@woocommerce/data';
|
} from '@woocommerce/data';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
import { List, TaskItem } from '@woocommerce/experimental';
|
import { List } from '@woocommerce/experimental';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { History } from 'history';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -31,6 +24,7 @@ import TaskListCompleted from './completed';
|
||||||
import { TaskListProps } from '~/tasks/task-list';
|
import { TaskListProps } from '~/tasks/task-list';
|
||||||
import { ProgressHeader } from '~/task-lists/progress-header';
|
import { ProgressHeader } from '~/task-lists/progress-header';
|
||||||
import { SectionPanelTitle } from './section-panel-title';
|
import { SectionPanelTitle } from './section-panel-title';
|
||||||
|
import { TaskListItem } from './task-list-item';
|
||||||
|
|
||||||
type PanelBodyProps = Omit< PanelBody.Props, 'title' | 'onToggle' > & {
|
type PanelBodyProps = Omit< PanelBody.Props, 'title' | 'onToggle' > & {
|
||||||
title: string | React.ReactNode | undefined;
|
title: string | React.ReactNode | undefined;
|
||||||
|
@ -48,10 +42,7 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
|
||||||
sections,
|
sections,
|
||||||
displayProgressHeader,
|
displayProgressHeader,
|
||||||
} ) => {
|
} ) => {
|
||||||
const { createNotice } = useDispatch( 'core/notices' );
|
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
|
||||||
const { updateOptions, dismissTask, undoDismissTask } = useDispatch(
|
|
||||||
OPTIONS_STORE_NAME
|
|
||||||
);
|
|
||||||
const { profileItems } = useSelect( ( select: WCDataSelector ) => {
|
const { profileItems } = useSelect( ( select: WCDataSelector ) => {
|
||||||
const { getProfileItems } = select( ONBOARDING_STORE_NAME );
|
const { getProfileItems } = select( ONBOARDING_STORE_NAME );
|
||||||
return {
|
return {
|
||||||
|
@ -92,18 +83,6 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
|
||||||
}
|
}
|
||||||
}, [ query ] );
|
}, [ query ] );
|
||||||
|
|
||||||
const onDismissTask = ( taskId: string ) => {
|
|
||||||
dismissTask( taskId );
|
|
||||||
createNotice( 'success', __( 'Task dismissed' ), {
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
label: __( 'Undo', 'woocommerce-admin' ),
|
|
||||||
onClick: () => undoDismissTask( taskId ),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
} );
|
|
||||||
};
|
|
||||||
|
|
||||||
const hideTasks = () => {
|
const hideTasks = () => {
|
||||||
hideTaskList( id );
|
hideTaskList( id );
|
||||||
};
|
};
|
||||||
|
@ -127,28 +106,6 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
|
||||||
selectedHeaderCard = visibleTasks[ visibleTasks.length - 1 ];
|
selectedHeaderCard = visibleTasks[ visibleTasks.length - 1 ];
|
||||||
}
|
}
|
||||||
|
|
||||||
const trackClick = ( task: TaskType ) => {
|
|
||||||
recordEvent( `${ eventPrefix }_click`, {
|
|
||||||
task_name: task.id,
|
|
||||||
} );
|
|
||||||
};
|
|
||||||
|
|
||||||
const onTaskSelected = ( task: TaskType ) => {
|
|
||||||
trackClick( task );
|
|
||||||
if ( task.actionUrl ) {
|
|
||||||
if ( task.actionUrl.startsWith( 'http' ) ) {
|
|
||||||
window.location.href = task.actionUrl;
|
|
||||||
} else {
|
|
||||||
( getHistory() as History ).push(
|
|
||||||
getNewPath( {}, task.actionUrl, {} )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateQueryString( { task: task.id } );
|
|
||||||
};
|
|
||||||
|
|
||||||
const getSectionTasks = ( sectionTaskIds: string[] ) => {
|
const getSectionTasks = ( sectionTaskIds: string[] ) => {
|
||||||
return visibleTasks.filter( ( task ) =>
|
return visibleTasks.filter( ( task ) =>
|
||||||
sectionTaskIds.includes( task.id )
|
sectionTaskIds.includes( task.id )
|
||||||
|
@ -229,51 +186,13 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
|
||||||
<PanelRow>
|
<PanelRow>
|
||||||
<List animation="custom">
|
<List animation="custom">
|
||||||
{ getSectionTasks( section.tasks ).map(
|
{ getSectionTasks( section.tasks ).map(
|
||||||
( task ) => {
|
( task ) => (
|
||||||
const className = classnames(
|
<TaskListItem
|
||||||
'woocommerce-task-list__item',
|
|
||||||
{
|
|
||||||
complete: task.isComplete,
|
|
||||||
'is-disabled':
|
|
||||||
task.isDisabled,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<TaskItem
|
|
||||||
key={ task.id }
|
key={ task.id }
|
||||||
className={ className }
|
task={ task }
|
||||||
title={ task.title }
|
eventPrefix={ eventPrefix }
|
||||||
completed={
|
|
||||||
task.isComplete
|
|
||||||
}
|
|
||||||
expanded={
|
|
||||||
! task.isComplete
|
|
||||||
}
|
|
||||||
content={ task.content }
|
|
||||||
onClick={ () => {
|
|
||||||
if (
|
|
||||||
! task.isDisabled
|
|
||||||
) {
|
|
||||||
onTaskSelected(
|
|
||||||
task
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} }
|
|
||||||
onDismiss={
|
|
||||||
task.isDismissable
|
|
||||||
? () =>
|
|
||||||
onDismissTask(
|
|
||||||
task.id
|
|
||||||
)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
action={ () => {} }
|
|
||||||
actionLabel={
|
|
||||||
task.actionLabel
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
)
|
||||||
}
|
|
||||||
) }
|
) }
|
||||||
</List>
|
</List>
|
||||||
</PanelRow>
|
</PanelRow>
|
||||||
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import {
|
||||||
|
getHistory,
|
||||||
|
getNewPath,
|
||||||
|
updateQueryString,
|
||||||
|
} from '@woocommerce/navigation';
|
||||||
|
import { OPTIONS_STORE_NAME, TaskType } from '@woocommerce/data';
|
||||||
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
|
import { TaskItem, useSlot } from '@woocommerce/experimental';
|
||||||
|
import { useCallback } from '@wordpress/element';
|
||||||
|
import { useDispatch } from '@wordpress/data';
|
||||||
|
import { WooOnboardingTaskListItem } from '@woocommerce/onboarding';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { History } from 'history';
|
||||||
|
|
||||||
|
export type TaskListItemProps = {
|
||||||
|
task: TaskType;
|
||||||
|
eventPrefix?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TaskListItem: React.FC< TaskListItemProps > = ( {
|
||||||
|
task,
|
||||||
|
eventPrefix,
|
||||||
|
} ) => {
|
||||||
|
const { createNotice } = useDispatch( 'core/notices' );
|
||||||
|
const {
|
||||||
|
dismissTask,
|
||||||
|
undoDismissTask,
|
||||||
|
snoozeTask,
|
||||||
|
undoSnoozeTask,
|
||||||
|
} = useDispatch( OPTIONS_STORE_NAME );
|
||||||
|
|
||||||
|
const slot = useSlot(
|
||||||
|
`woocommerce_onboarding_task_list_item_${ task.id }`
|
||||||
|
);
|
||||||
|
const hasFills = Boolean( slot?.fills?.length );
|
||||||
|
|
||||||
|
const trackClick = () => {
|
||||||
|
recordEvent( `${ eventPrefix }click`, {
|
||||||
|
task_name: task.id,
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
|
const onTaskSelected = () => {
|
||||||
|
trackClick();
|
||||||
|
|
||||||
|
if ( task.actionUrl ) {
|
||||||
|
if ( task.actionUrl.startsWith( 'http' ) ) {
|
||||||
|
window.location.href = task.actionUrl;
|
||||||
|
} else {
|
||||||
|
( getHistory() as History ).push(
|
||||||
|
getNewPath( {}, task.actionUrl, {} )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.document.documentElement.scrollTop = 0;
|
||||||
|
updateQueryString( { task: task.id } );
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDismiss = useCallback( () => {
|
||||||
|
dismissTask( task.id );
|
||||||
|
createNotice( 'success', __( 'Task dismissed' ), {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: __( 'Undo', 'woocommerce' ),
|
||||||
|
onClick: () => undoDismissTask( task.id ),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} );
|
||||||
|
}, [ task.id ] );
|
||||||
|
|
||||||
|
const onSnooze = useCallback( () => {
|
||||||
|
snoozeTask( task.id );
|
||||||
|
createNotice(
|
||||||
|
'success',
|
||||||
|
__( 'Task postponed until tomorrow', 'woocommerce' ),
|
||||||
|
{
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: __( 'Undo', 'woocommerce' ),
|
||||||
|
onClick: () => undoSnoozeTask( task.id ),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, [ task.id ] );
|
||||||
|
|
||||||
|
const className = classnames( 'woocommerce-task-list__item', {
|
||||||
|
complete: task.isComplete,
|
||||||
|
'is-disabled': task.isDisabled,
|
||||||
|
} );
|
||||||
|
|
||||||
|
const taskItemProps = {
|
||||||
|
completed: task.isComplete,
|
||||||
|
onSnooze: task.isSnoozeable && onSnooze,
|
||||||
|
onDismiss: task.isDismissable && onDismiss,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DefaultTaskItem = useCallback(
|
||||||
|
( props ) => {
|
||||||
|
const onClickActions = () => {
|
||||||
|
if ( props.onClick ) {
|
||||||
|
trackClick();
|
||||||
|
return props.onClick();
|
||||||
|
}
|
||||||
|
return onTaskSelected();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<TaskItem
|
||||||
|
key={ task.id }
|
||||||
|
className={ className }
|
||||||
|
title={ task.title }
|
||||||
|
completed={ task.isComplete }
|
||||||
|
expanded={ ! task.isComplete }
|
||||||
|
additionalInfo={ task.additionalInfo }
|
||||||
|
content={ task.content }
|
||||||
|
onDismiss={ task.isDismissable && onDismiss }
|
||||||
|
action={ () => {} }
|
||||||
|
actionLabel={ task.actionLabel }
|
||||||
|
{ ...props }
|
||||||
|
onClick={ () => {
|
||||||
|
if ( task.isDisabled ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onClickActions();
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[
|
||||||
|
task.id,
|
||||||
|
task.title,
|
||||||
|
task.content,
|
||||||
|
task.time,
|
||||||
|
task.actionLabel,
|
||||||
|
task.isComplete,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return hasFills ? (
|
||||||
|
<WooOnboardingTaskListItem.Slot
|
||||||
|
id={ task.id }
|
||||||
|
fillProps={ {
|
||||||
|
defaultTaskItem: DefaultTaskItem,
|
||||||
|
isComplete: task.isComplete,
|
||||||
|
...taskItemProps,
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<DefaultTaskItem />
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: patch
|
||||||
|
Type: fix
|
||||||
|
|
||||||
|
Addressing issues with certain tasks in task list experiment leading to blank page. #32742
|
Loading…
Reference in New Issue