woocommerce/plugins/woocommerce-admin/client/task-list/index.js

436 lines
10 KiB
JavaScript
Raw Normal View History

/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Component, cloneElement, Fragment } from '@wordpress/element';
import { compose } from '@wordpress/compose';
import classNames from 'classnames';
import {
Button,
Card,
CardBody,
CardHeader,
__experimentalText as Text,
} from '@wordpress/components';
import { withDispatch, withSelect } from '@wordpress/data';
import { Icon, check } from '@wordpress/icons';
import { xor } from 'lodash';
import { List, EllipsisMenu } from '@woocommerce/components';
import { updateQueryString } from '@woocommerce/navigation';
import {
PLUGINS_STORE_NAME,
OPTIONS_STORE_NAME,
ONBOARDING_STORE_NAME,
SETTINGS_STORE_NAME,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
/**
* Internal dependencies
*/
import './style.scss';
import CartModal from '../dashboard/components/cart-modal';
import { getAllTasks, recordTaskViewEvent } from './tasks';
import { getCountryCode } from '../dashboard/utils';
import sanitizeHTML from '../lib/sanitize-html';
class TaskDashboard extends Component {
constructor( props ) {
super( props );
this.state = {
isCartModalOpen: false,
};
}
componentDidMount() {
document.body.classList.add( 'woocommerce-onboarding' );
document.body.classList.add( 'woocommerce-task-dashboard__body' );
this.recordTaskView();
this.recordTaskListView();
this.possiblyCompleteTaskList();
this.possiblyTrackCompletedTasks();
}
componentDidUpdate( prevProps ) {
const { query } = this.props;
const { query: prevQuery } = prevProps;
const { task: prevTask } = prevQuery;
const { task } = query;
if ( prevTask !== task ) {
window.document.documentElement.scrollTop = 0;
this.recordTaskView();
}
this.possiblyCompleteTaskList();
this.possiblyTrackCompletedTasks();
}
possiblyCompleteTaskList() {
const { isTaskListComplete, updateOptions } = this.props;
if ( ! this.getIncompleteTasks().length && ! isTaskListComplete ) {
updateOptions( {
woocommerce_task_list_complete: 'yes',
} );
}
}
getCompletedTaskKeys() {
return this.getVisibleTasks()
.filter( ( task ) => task.completed )
.map( ( task ) => task.key );
}
getIncompleteTasks() {
return this.getAllTasks().filter(
( task ) => task.visible && ! task.completed
);
}
possiblyTrackCompletedTasks() {
const { trackedCompletedTasks, updateOptions } = this.props;
const completedTaskKeys = this.getCompletedTaskKeys();
if ( xor( trackedCompletedTasks, completedTaskKeys ).length !== 0 ) {
updateOptions( {
woocommerce_task_list_tracked_completed_tasks: completedTaskKeys,
} );
}
}
dismissTask( key ) {
const { createNotice, dismissedTasks, updateOptions } = this.props;
createNotice( 'success', __( 'Task dismissed' ), {
actions: [
{
label: __( 'Undo', 'woocommerce-admin' ),
onClick: () => this.undoDismissTask( key ),
},
],
} );
recordEvent( 'tasklist_dismiss_task', { task_name: key } );
updateOptions( {
woocommerce_task_list_dismissed_tasks: [ ...dismissedTasks, key ],
} );
}
undoDismissTask( key ) {
const { dismissedTasks, updateOptions } = this.props;
const updatedDismissedTasks = dismissedTasks.filter(
( task ) => task !== key
);
updateOptions( {
woocommerce_task_list_dismissed_tasks: updatedDismissedTasks,
} );
}
componentWillUnmount() {
document.body.classList.remove( 'woocommerce-onboarding' );
document.body.classList.remove( 'woocommerce-task-dashboard__body' );
}
getAllTasks() {
const {
activePlugins,
countryCode,
createNotice,
installAndActivatePlugins,
installedPlugins,
isJetpackConnected,
onboardingStatus,
profileItems,
query,
} = this.props;
return getAllTasks( {
activePlugins,
countryCode,
createNotice,
installAndActivatePlugins,
installedPlugins,
isJetpackConnected,
onboardingStatus,
profileItems,
query,
toggleCartModal: this.toggleCartModal.bind( this ),
} );
}
getVisibleTasks() {
const { dismissedTasks } = this.props;
return this.getAllTasks().filter(
( task ) => task.visible && ! dismissedTasks.includes( task.key )
);
}
recordTaskView() {
const {
isJetpackConnected,
activePlugins,
installedPlugins,
query,
} = this.props;
const { task: taskName } = query;
Version/1.0 master merge (https://github.com/woocommerce/woocommerce-admin/pull/3797) * Try: Moving Customers to main Woo Menu (https://github.com/woocommerce/woocommerce-admin/pull/3632) * Only add onboarding settings on wc-admin pages when task list should be shown. (https://github.com/woocommerce/woocommerce-admin/pull/3722) * Use cron for unsnoozing admin notes (https://github.com/woocommerce/woocommerce-admin/pull/3662) * Use wp-cron for admin note snoozing. * Remove "unsnooze" scheduled action. * Use correct version. * Avoid using deprecated method for unscheduling actions. * Onboarding: Fix toggle tracking events (https://github.com/woocommerce/woocommerce-admin/pull/3645) * Fix errant wcadmin prefix on event name * Track the onboarding toggle on the option in case enable_onboarding isn't used * Move toggle actions to separate function * Move onboarding actions * Move onboarding filters * Move help tab updates to add_toggle_actions * Only run onboarding actions when enabled * Onboarding: Add tracks events when profiler steps are completed (https://github.com/woocommerce/woocommerce-admin/pull/3726) * Add tracks for store profiler step completion * Record event when profiler is completed * Ensure continue setup loads the onboarding profiler (https://github.com/woocommerce/woocommerce-admin/pull/3646) * 'All that include' option removed when input field is empty (https://github.com/woocommerce/woocommerce-admin/pull/3700) * 'All that include' option removed when input field is empty Added a control to check that when the input field 'Search by customer name' is empty, the 'All that include' option is not appearing. * Const name improved The constant name hasValues was changed to optionsHaveValues (more descriptive) * Fix select text alignment (https://github.com/woocommerce/woocommerce-admin/pull/3723) * Stock panel indicator - cache and use lookup tables. (https://github.com/woocommerce/woocommerce-admin/pull/3729) * Stock panel indicator - cache and use lookup tables. * Revise query, clear transient on product update. * Fix error, ht Josh. * Checklist: Remove sideloaded images to reduce build size, take 2 (https://github.com/woocommerce/woocommerce-admin/pull/3731) * Remove homepage template images. * Use other-small on all industries, adjust text color. * Remove background dim and opacity set to 0 * Fix/3631 (https://github.com/woocommerce/woocommerce-admin/pull/3730) * Added CBD as an industry type CBD was added as an industry type in API * Industries options modified Modified the industries options. Now we are able to choose if we will use an input or not in the option. * API control changed for industries. API control changed for industries. Now it accepts the data type we need. * Added input in Industries list for the option "Other" Added an input for the option "Other" in the industries list * Added suggested changes in review comments. * Added data preparation for recordEvent * Changed variable to snake_case The variable "industriesWithDetail" was changed to "industries_with_detail" (snake_case) * Onboarding: Create homepage without redirect (https://github.com/woocommerce/woocommerce-admin/pull/3727) * Add link to edit homepage instead of redirect * Add busy state to homepage creation button * Publish homepage on create via API * Update homepage notice to show on first post update * Update homepage creation notice per design * Record event on customize homepage * Set homepage to frontpage on creation * Add deactivation note for feature plugin (https://github.com/woocommerce/woocommerce-admin/pull/3687) * Add version deactivation note * Add the note to deactivate if the version is older than the current WC version * Deactivate wc admin feature plugin on action click * Add notes version hooks * change the Package class namespace to exclude from standalone autoloader * add use statement for FeaturePlugin * add note explaining namespace * use wc-admin-deactivate-plugin note name * Rename file and class to WC_Admin_Notes_Deactivate_Plugin Co-authored-by: Ron Rennick <ron@ronandandrea.com> Co-authored-by: Paul Sealock <psealock@gmail.com> * Add Travis tests on GH for release branch (https://github.com/woocommerce/woocommerce-admin/pull/3751) * Add Travis tests on GH for release branch * fix linter errors * ActivityPanels.php -> use public static functions * Remove free text Search option when no query exists (https://github.com/woocommerce/woocommerce-admin/pull/3755) * Revert changes in woocommerce/woocommerce-admin#3700 * Don't add free text search if no query exists * Add tests for Search without query * Add test for showing free text search option * Fix image sideloading for store industries. (https://github.com/woocommerce/woocommerce-admin/pull/3743) * Fix image sideloading for store industries. Data format changed in https://github.com/woocommerce/woocommerce-admin/pull/3730 * Fix industry image sideload in cases where the count is less than requested. * Be backwards compatible with the old industry data format. * Added event props to identify stores with WCS and Jetpack installed (https://github.com/woocommerce/woocommerce-admin/pull/3750) * Added event props to identify stores with WCS and Jetpack installed Also, added Jeckpack connected status * Improved variable name * Simplified method Simplified method. "intersection" check was removed * Tests errors repeared The method "clear_low_out_of_stock_count_transient" now is static. * OBW: fix sideloading image test error (https://github.com/woocommerce/woocommerce-admin/pull/3762) * Release 0.26.0 changes (https://github.com/woocommerce/woocommerce-admin/pull/3753) * add deactivation hook to Package.php (https://github.com/woocommerce/woocommerce-admin/pull/3770) * Add active version functions (https://github.com/woocommerce/woocommerce-admin/pull/3772) * add active version functions to Package.php Co-authored-by: Joshua T Flowers <joshuatf@gmail.com> * 0.26.1 changes (https://github.com/woocommerce/woocommerce-admin/pull/3773) * Customers Report: fix missing report param in search (https://github.com/woocommerce/woocommerce-admin/pull/3778) * Product titles include encoded entities (https://github.com/woocommerce/woocommerce-admin/pull/3765) * Stripped HTML from product titles and decoded before displaying them Stripped html from product titles and entities are decoded before displaying them * Stripped HTML from product titles and decoded in Stock report Stripped html from product titles and entities are decoded before displaying them. Now in Stock report * Added support for HTML tags and encoded entities on product titles Added support for HTML tags and encoded entities on filtered product list, dropdown menus and tag names. Also, strip_tags() function was replaced with wp_strip_all_tags() instead. * strip_tags() function was replaced with wp_strip_all_tags() instead. * Added control for a variable Added control for "item->data" before applying wp_strip_all_tags method. * pre-commit changes * Test text corrected * fix linting issues * fix mis-merged changes * Update jsdoc Co-Authored-By: Paul Sealock <psealock@gmail.com> Co-authored-by: Timmy Crawford <timmyc@users.noreply.github.com> Co-authored-by: Jeff Stieler <jeff.m.stieler@gmail.com> Co-authored-by: Joshua T Flowers <joshuatf@gmail.com> Co-authored-by: Fernando <ultimoround@gmail.com> Co-authored-by: edmundcwm <edmundcwm@gmail.com> Co-authored-by: Paul Sealock <psealock@gmail.com>
2020-03-02 22:22:32 +00:00
if ( ! taskName ) {
return;
}
recordTaskViewEvent(
taskName,
isJetpackConnected,
activePlugins,
installedPlugins
);
}
recordTaskListView() {
if ( this.getCurrentTask() ) {
return;
}
const { profileItems } = this.props;
const tasks = this.getVisibleTasks();
recordEvent( 'tasklist_view', {
number_tasks: tasks.length,
store_connected: profileItems.wccom_connected,
} );
}
hideTaskCard( action ) {
recordEvent( 'tasklist_completed', {
action,
completed_task_count: this.getCompletedTaskKeys().length,
incomplete_task_count: this.getIncompleteTasks().length,
} );
this.props.updateOptions( {
woocommerce_task_list_hidden: 'yes',
woocommerce_task_list_prompt_shown: true,
} );
}
getCurrentTask() {
const { query } = this.props;
const { task } = query;
const currentTask = this.getAllTasks().find( ( s ) => s.key === task );
if ( ! currentTask ) {
return null;
}
return currentTask;
}
renderMenu() {
return (
<div className="woocommerce-card__menu woocommerce-card__header-item">
<EllipsisMenu
label={ __( 'Task List Options', 'woocommerce-admin' ) }
renderContent={ () => (
<div className="woocommerce-task-card__section-controls">
<Button
onClick={ () =>
this.hideTaskCard( 'remove_card' )
}
>
{ __( 'Hide this', 'woocommerce-admin' ) }
</Button>
</div>
) }
/>
</div>
);
}
toggleCartModal() {
const { isCartModalOpen } = this.state;
if ( ! isCartModalOpen ) {
recordEvent( 'tasklist_purchase_extensions' );
}
this.setState( { isCartModalOpen: ! isCartModalOpen } );
}
render() {
const { query } = this.props;
const { isCartModalOpen } = this.state;
const currentTask = this.getCurrentTask();
const listTasks = this.getVisibleTasks().map( ( task ) => {
task.className = classNames(
task.completed ? 'is-complete' : null,
task.className
);
task.before = (
<div className="woocommerce-task__icon">
{ task.completed && <Icon icon={ check } /> }
</div>
);
task.title = (
<Text
as="div"
variant={ task.completed ? 'body.small' : 'button' }
>
{ task.title }
{ task.additionalInfo && (
<div
className="woocommerce-task__additional-info"
dangerouslySetInnerHTML={ sanitizeHTML(
task.additionalInfo
) }
></div>
) }
{ task.time && ! task.completed && (
<div className="woocommerce-task__estimated-time">
{ task.time }
</div>
) }
</Text>
);
if ( ! task.completed && task.isDismissable ) {
task.after = (
<Button
data-testid={ `${ task.key }-dismiss-button` }
isTertiary
onClick={ ( event ) => {
event.stopPropagation();
this.dismissTask( task.key );
} }
>
{ __( 'Dismiss', 'woocommerce-admin' ) }
</Button>
);
}
if ( ! task.onClick ) {
task.onClick = ( e ) => {
if ( e.target.nodeName === 'A' ) {
// This is a nested link, so don't activate this task.
return false;
}
updateQueryString( { task: task.key } );
};
}
return task;
} );
const progressBarClass = classNames(
'woocommerce-task-card__progress-bar',
{
completed:
listTasks.length === this.getCompletedTaskKeys().length,
}
);
return (
<Fragment>
<div className="woocommerce-task-dashboard__container">
{ currentTask ? (
cloneElement( currentTask.container, {
query,
} )
) : (
<Fragment>
<Card
size="large"
className="woocommerce-task-card woocommerce-dashboard-card"
>
<progress
className={ progressBarClass }
max={ listTasks.length }
value={ this.getCompletedTaskKeys().length }
/>
<CardHeader size="medium">
<Text variant="title.small">
{ __(
'Finish setup',
'woocommerce-admin'
) }
</Text>
{ this.renderMenu() }
</CardHeader>
<CardBody>
<List items={ listTasks } />
</CardBody>
</Card>
</Fragment>
) }
</div>
{ isCartModalOpen && (
<CartModal
onClose={ () => this.toggleCartModal() }
onClickPurchaseLater={ () => this.toggleCartModal() }
/>
) }
</Fragment>
);
}
}
export default compose(
withSelect( ( select ) => {
const { getProfileItems, getTasksStatus } = select(
ONBOARDING_STORE_NAME
);
const { getOption } = select( OPTIONS_STORE_NAME );
const { getSettings } = select( SETTINGS_STORE_NAME );
const {
getActivePlugins,
getInstalledPlugins,
isJetpackConnected,
} = select( PLUGINS_STORE_NAME );
const profileItems = getProfileItems();
const isTaskListComplete =
getOption( 'woocommerce_task_list_complete' ) === 'yes';
const trackedCompletedTasks =
getOption( 'woocommerce_task_list_tracked_completed_tasks' ) || [];
const dismissedTasks =
getOption( 'woocommerce_task_list_dismissed_tasks' ) || [];
const { general: generalSettings = {} } = getSettings( 'general' );
const countryCode = getCountryCode(
generalSettings.woocommerce_default_country
);
const activePlugins = getActivePlugins();
const installedPlugins = getInstalledPlugins();
const onboardingStatus = getTasksStatus();
return {
activePlugins,
countryCode,
dismissedTasks,
isJetpackConnected: isJetpackConnected(),
installedPlugins,
isTaskListComplete,
onboardingStatus,
profileItems,
trackedCompletedTasks,
};
} ),
withDispatch( ( dispatch ) => {
const { createNotice } = dispatch( 'core/notices' );
const { updateOptions } = dispatch( OPTIONS_STORE_NAME );
const { installAndActivatePlugins } = dispatch( PLUGINS_STORE_NAME );
return {
createNotice,
installAndActivatePlugins,
updateOptions,
};
} )
)( TaskDashboard );