woocommerce/plugins/woocommerce-admin/client/dashboard/customizable.js

378 lines
9.5 KiB
JavaScript
Raw Normal View History

/**
* External dependencies
*/
2019-04-30 00:35:37 +00:00
import { __, sprintf } from '@wordpress/i18n';
Use Route based code splitting to optimize bundle size (https://github.com/woocommerce/woocommerce-admin/pull/4094) * Use lazy loading to split up the size of the js downloaded * Use lazy loading to split up the size of the js downloaded * Add Moment Timezone plugin to reduce size of data file. * Lazy load header panels and use Dashicons for faster loading * Load assets from the correct publicPath * Load assets from the correct publicPath * PHP cs fixes * Fix missing quotes on string literal. * Fix PropType warning for lazy loaded component. * Separate the task list and dashboard chunks. * Lazy load dashboard sections. * Restore original icons and reduce size by importing only the icons needed * Lazy load alerts to save more Kb on initial load * Minify built JS in production mode. * Add preload tags for WC Admin assets. (https://github.com/woocommerce/woocommerce-admin/pull/4162) * Fix linting errors. * Add modified UnminifiedWebpackPlugin. * Produce minified and unminified bundles for all builds. * Remove unused variable from webpack config. * Run unminify after sourcemap generation. * Only hook after optimization if we're using a devtool. * Add minification suffix in Loader::get_url(). * Lazy load OBW on new home screen. * Move OBW style up a level to layout. * Hydrate ProfileWizard independently of withSelect and withDispatch * Fix order of composition and fallback function when using hydration. Co-authored-by: Jeff Stieler <jeff.m.stieler@gmail.com> Co-authored-by: Paul Sealock <psealock@gmail.com>
2020-04-29 18:01:27 +00:00
import { Component, Fragment, Suspense, lazy } from '@wordpress/element';
import { compose } from '@wordpress/compose';
import { partial, get } from 'lodash';
2019-04-30 00:35:37 +00:00
import { IconButton, Icon, Dropdown, Button } from '@wordpress/components';
import { withDispatch } from '@wordpress/data';
import { applyFilters } from '@wordpress/hooks';
/**
* WooCommerce dependencies
*/
Use Route based code splitting to optimize bundle size (https://github.com/woocommerce/woocommerce-admin/pull/4094) * Use lazy loading to split up the size of the js downloaded * Use lazy loading to split up the size of the js downloaded * Add Moment Timezone plugin to reduce size of data file. * Lazy load header panels and use Dashicons for faster loading * Load assets from the correct publicPath * Load assets from the correct publicPath * PHP cs fixes * Fix missing quotes on string literal. * Fix PropType warning for lazy loaded component. * Separate the task list and dashboard chunks. * Lazy load dashboard sections. * Restore original icons and reduce size by importing only the icons needed * Lazy load alerts to save more Kb on initial load * Minify built JS in production mode. * Add preload tags for WC Admin assets. (https://github.com/woocommerce/woocommerce-admin/pull/4162) * Fix linting errors. * Add modified UnminifiedWebpackPlugin. * Produce minified and unminified bundles for all builds. * Remove unused variable from webpack config. * Run unminify after sourcemap generation. * Only hook after optimization if we're using a devtool. * Add minification suffix in Loader::get_url(). * Lazy load OBW on new home screen. * Move OBW style up a level to layout. * Hydrate ProfileWizard independently of withSelect and withDispatch * Fix order of composition and fallback function when using hydration. Co-authored-by: Jeff Stieler <jeff.m.stieler@gmail.com> Co-authored-by: Paul Sealock <psealock@gmail.com>
2020-04-29 18:01:27 +00:00
import { H, Spinner } from '@woocommerce/components';
import { SETTINGS_STORE_NAME } from '@woocommerce/data';
/**
* Internal dependencies
*/
import './style.scss';
import defaultSections from './default-sections';
import Section from './section';
import withSelect from 'wc-api/with-select';
2019-07-01 10:16:12 +00:00
import { recordEvent } from 'lib/tracks';
import { isOnboardingEnabled } from 'dashboard/utils';
import {
getCurrentDates,
getDateParamsFromQuery,
isoDateFormat,
} from 'lib/date';
import ReportFilters from 'analytics/components/report-filters';
Use Route based code splitting to optimize bundle size (https://github.com/woocommerce/woocommerce-admin/pull/4094) * Use lazy loading to split up the size of the js downloaded * Use lazy loading to split up the size of the js downloaded * Add Moment Timezone plugin to reduce size of data file. * Lazy load header panels and use Dashicons for faster loading * Load assets from the correct publicPath * Load assets from the correct publicPath * PHP cs fixes * Fix missing quotes on string literal. * Fix PropType warning for lazy loaded component. * Separate the task list and dashboard chunks. * Lazy load dashboard sections. * Restore original icons and reduce size by importing only the icons needed * Lazy load alerts to save more Kb on initial load * Minify built JS in production mode. * Add preload tags for WC Admin assets. (https://github.com/woocommerce/woocommerce-admin/pull/4162) * Fix linting errors. * Add modified UnminifiedWebpackPlugin. * Produce minified and unminified bundles for all builds. * Remove unused variable from webpack config. * Run unminify after sourcemap generation. * Only hook after optimization if we're using a devtool. * Add minification suffix in Loader::get_url(). * Lazy load OBW on new home screen. * Move OBW style up a level to layout. * Hydrate ProfileWizard independently of withSelect and withDispatch * Fix order of composition and fallback function when using hydration. Co-authored-by: Jeff Stieler <jeff.m.stieler@gmail.com> Co-authored-by: Paul Sealock <psealock@gmail.com>
2020-04-29 18:01:27 +00:00
const TaskList = lazy( () =>
import( /* webpackChunkName: "task-list" */ './task-list' )
);
const DASHBOARD_FILTERS_FILTER = 'woocommerce_admin_dashboard_filters';
const filters = applyFilters( DASHBOARD_FILTERS_FILTER, [] );
class CustomizableDashboard extends Component {
constructor( props ) {
super( props );
this.state = {
sections: this.mergeSectionsWithDefaults( props.userPrefSections ),
};
2019-04-30 00:35:37 +00:00
this.onMove = this.onMove.bind( this );
this.updateSection = this.updateSection.bind( this );
}
mergeSectionsWithDefaults( prefSections ) {
if ( ! prefSections || prefSections.length === 0 ) {
return defaultSections;
}
const defaultKeys = defaultSections.map( ( section ) => section.key );
const prefKeys = prefSections.map( ( section ) => section.key );
const keys = new Set( [ ...prefKeys, ...defaultKeys ] );
const sections = [];
keys.forEach( ( key ) => {
const defaultSection = defaultSections.find(
( section ) => section.key === key
);
if ( ! defaultSection ) {
return;
}
const prefSection = prefSections.find(
( section ) => section.key === key
);
sections.push( {
...defaultSection,
...prefSection,
} );
} );
return sections;
}
updateSections( newSections ) {
this.setState( { sections: newSections } );
this.props.updateCurrentUserData( { dashboard_sections: newSections } );
}
updateSection( updatedKey, newSettings ) {
const newSections = this.state.sections.map( ( section ) => {
if ( section.key === updatedKey ) {
return {
...section,
...newSettings,
};
}
return section;
} );
this.updateSections( newSections );
}
onChangeHiddenBlocks( updatedKey ) {
return ( updatedHiddenBlocks ) => {
this.updateSection( updatedKey, {
hiddenBlocks: updatedHiddenBlocks,
} );
};
}
onSectionTitleUpdate( updatedKey ) {
return ( updatedTitle ) => {
recordEvent( 'dash_section_rename', { key: updatedKey } );
this.updateSection( updatedKey, { title: updatedTitle } );
};
}
2019-04-30 00:35:37 +00:00
toggleVisibility( key, onToggle ) {
return () => {
if ( onToggle ) {
// Close the dropdown before setting state so an action is not performed on an unmounted component.
onToggle();
}
// When toggling visibility, place section at the end of the array.
const sections = [ ...this.state.sections ];
const index = sections.findIndex( ( s ) => key === s.key );
const toggledSection = sections.splice( index, 1 ).shift();
toggledSection.isVisible = ! toggledSection.isVisible;
sections.push( toggledSection );
if ( toggledSection.isVisible ) {
recordEvent( 'dash_section_add', { key: toggledSection.key } );
} else {
recordEvent( 'dash_section_remove', {
key: toggledSection.key,
} );
2019-07-01 10:16:12 +00:00
}
this.updateSections( sections );
2019-04-30 00:35:37 +00:00
};
}
onMove( index, change ) {
const sections = [ ...this.state.sections ];
const movedSection = sections.splice( index, 1 ).shift();
const newIndex = index + change;
// Figure out the index of the skipped section.
const nextJumpedSectionIndex = change < 0 ? newIndex : newIndex - 1;
if (
sections[ nextJumpedSectionIndex ].isVisible || // Is the skipped section visible?
index === 0 || // Will this be the first element?
index === sections.length - 1 // Will this be the last element?
) {
// Yes, lets insert.
sections.splice( newIndex, 0, movedSection );
this.updateSections( sections );
const eventProps = {
key: movedSection.key,
direction: change > 0 ? 'down' : 'up',
};
recordEvent( 'dash_section_order_change', eventProps );
} else {
// No, lets try the next one.
this.onMove( index, change + change );
}
2019-04-30 00:35:37 +00:00
}
renderAddMore() {
const { sections } = this.state;
const hiddenSections = sections.filter(
( section ) => section.isVisible === false
);
2019-04-30 00:35:37 +00:00
if ( hiddenSections.length === 0 ) {
2019-04-30 00:35:37 +00:00
return null;
}
return (
<Dropdown
position="top center"
className="woocommerce-dashboard-section__add-more"
renderToggle={ ( { onToggle, isOpen } ) => (
<IconButton
onClick={ onToggle }
icon="plus-alt"
title={ __( 'Add more sections', 'woocommerce-admin' ) }
aria-expanded={ isOpen }
/>
) }
renderContent={ ( { onToggle } ) => (
<Fragment>
<H>
{ __( 'Dashboard Sections', 'woocommerce-admin' ) }
</H>
2019-04-30 00:35:37 +00:00
<div className="woocommerce-dashboard-section__add-more-choices">
{ hiddenSections.map( ( section ) => {
2019-04-30 00:35:37 +00:00
return (
<Button
key={ section.key }
onClick={ this.toggleVisibility(
section.key,
onToggle
) }
2019-04-30 00:35:37 +00:00
className="woocommerce-dashboard-section__add-more-btn"
title={ sprintf(
__(
'Add %s section',
'woocommerce-admin'
),
section.title
) }
2019-04-30 00:35:37 +00:00
>
<Icon
icon={ section.icon }
size={ 30 }
/>
2019-04-30 00:35:37 +00:00
<span className="woocommerce-dashboard-section__add-more-btn-title">
{ section.title }
</span>
</Button>
);
} ) }
</div>
</Fragment>
) }
/>
);
}
renderDashboardReports() {
wp.data Settings refactor add data store for settings using wp.data add use-select-with-refresh example replace fresh-data usage with new settings data store for settings page Add data package move to packages Fix isDirty after save Add isBusy to primary button when saving update Readme remove comment readme to use useSelect Revert "update Readme" This reverts commit 7402fd49b8f384fde5878e0bee0616f0a87bb4f6. Data Layer: Settings page to use Settings store (https://github.com/woocommerce/woocommerce-admin/pull/3430) * Data Layer: Settings store as source of truth for settings page This reverts commit 7402fd49b8f384fde5878e0bee0616f0a87bb4f6. * fixup * save on reset * non mutable constants * add set/getSettings * save using setSettings * separate HOC * cleanup * remove settingsToData * withHydration * remove withSettings HOC * renmove useSettins for now * withSettingsHydration updates * Revert "withSettingsHydration updates" This reverts commit f2adf108fbe19b574978fea5925a1a18e7ed3007. * rename withSettingsHydration * redo withSettingsHydration simplification * restore * useSettings * render using useSettings * handleInputChange working * get setIsDirty working * saving works * reset and cleanup * cleanup * use snake case on hook files * use clearIsDirty * Avoid mutation on setting update * remove @todo * persiting -> isPersisting * better reducer ternaries * add wcSettings as arg to withSettingsHydration reset package-lock Settings: split out mutable wcAdminSettings (https://github.com/woocommerce/woocommerce-admin/pull/3675) Settings: handle async settings groups (https://github.com/woocommerce/woocommerce-admin/pull/3707)
2020-03-25 03:20:17 +00:00
const { query, path, defaultDateRange } = this.props;
const { sections } = this.state;
const { period, compare, before, after } = getDateParamsFromQuery(
wp.data Settings refactor add data store for settings using wp.data add use-select-with-refresh example replace fresh-data usage with new settings data store for settings page Add data package move to packages Fix isDirty after save Add isBusy to primary button when saving update Readme remove comment readme to use useSelect Revert "update Readme" This reverts commit 7402fd49b8f384fde5878e0bee0616f0a87bb4f6. Data Layer: Settings page to use Settings store (https://github.com/woocommerce/woocommerce-admin/pull/3430) * Data Layer: Settings store as source of truth for settings page This reverts commit 7402fd49b8f384fde5878e0bee0616f0a87bb4f6. * fixup * save on reset * non mutable constants * add set/getSettings * save using setSettings * separate HOC * cleanup * remove settingsToData * withHydration * remove withSettings HOC * renmove useSettins for now * withSettingsHydration updates * Revert "withSettingsHydration updates" This reverts commit f2adf108fbe19b574978fea5925a1a18e7ed3007. * rename withSettingsHydration * redo withSettingsHydration simplification * restore * useSettings * render using useSettings * handleInputChange working * get setIsDirty working * saving works * reset and cleanup * cleanup * use snake case on hook files * use clearIsDirty * Avoid mutation on setting update * remove @todo * persiting -> isPersisting * better reducer ternaries * add wcSettings as arg to withSettingsHydration reset package-lock Settings: split out mutable wcAdminSettings (https://github.com/woocommerce/woocommerce-admin/pull/3675) Settings: handle async settings groups (https://github.com/woocommerce/woocommerce-admin/pull/3707)
2020-03-25 03:20:17 +00:00
query,
defaultDateRange
);
const {
primary: primaryDate,
secondary: secondaryDate,
wp.data Settings refactor add data store for settings using wp.data add use-select-with-refresh example replace fresh-data usage with new settings data store for settings page Add data package move to packages Fix isDirty after save Add isBusy to primary button when saving update Readme remove comment readme to use useSelect Revert "update Readme" This reverts commit 7402fd49b8f384fde5878e0bee0616f0a87bb4f6. Data Layer: Settings page to use Settings store (https://github.com/woocommerce/woocommerce-admin/pull/3430) * Data Layer: Settings store as source of truth for settings page This reverts commit 7402fd49b8f384fde5878e0bee0616f0a87bb4f6. * fixup * save on reset * non mutable constants * add set/getSettings * save using setSettings * separate HOC * cleanup * remove settingsToData * withHydration * remove withSettings HOC * renmove useSettins for now * withSettingsHydration updates * Revert "withSettingsHydration updates" This reverts commit f2adf108fbe19b574978fea5925a1a18e7ed3007. * rename withSettingsHydration * redo withSettingsHydration simplification * restore * useSettings * render using useSettings * handleInputChange working * get setIsDirty working * saving works * reset and cleanup * cleanup * use snake case on hook files * use clearIsDirty * Avoid mutation on setting update * remove @todo * persiting -> isPersisting * better reducer ternaries * add wcSettings as arg to withSettingsHydration reset package-lock Settings: split out mutable wcAdminSettings (https://github.com/woocommerce/woocommerce-admin/pull/3675) Settings: handle async settings groups (https://github.com/woocommerce/woocommerce-admin/pull/3707)
2020-03-25 03:20:17 +00:00
} = getCurrentDates( query, defaultDateRange );
const dateQuery = {
period,
compare,
before,
after,
primaryDate,
secondaryDate,
};
const visibleSectionKeys = sections
.filter( ( section ) => section.isVisible )
.map( ( section ) => section.key );
return (
<Fragment>
<ReportFilters
report="dashboard"
query={ query }
path={ path }
dateQuery={ dateQuery }
isoDateFormat={ isoDateFormat }
filters={ filters }
/>
{ sections.map( ( section, index ) => {
if ( section.isVisible ) {
return (
<Section
component={ section.component }
hiddenBlocks={ section.hiddenBlocks }
key={ section.key }
onChangeHiddenBlocks={ this.onChangeHiddenBlocks(
section.key
) }
onTitleUpdate={ this.onSectionTitleUpdate(
section.key
) }
path={ path }
query={ query }
title={ section.title }
onMove={ partial( this.onMove, index ) }
onRemove={ this.toggleVisibility(
section.key
) }
isFirst={
section.key === visibleSectionKeys[ 0 ]
}
isLast={
section.key ===
visibleSectionKeys[
visibleSectionKeys.length - 1
]
}
/>
);
}
return null;
} ) }
2019-04-30 00:35:37 +00:00
{ this.renderAddMore() }
</Fragment>
);
}
render() {
const { query, taskListHidden, taskListComplete } = this.props;
const isTaskListEnabled = isOnboardingEnabled() && ! taskListHidden;
const isDashboardShown =
! isTaskListEnabled || ( ! query.task && taskListComplete );
return (
<Fragment>
{ isTaskListEnabled && (
Use Route based code splitting to optimize bundle size (https://github.com/woocommerce/woocommerce-admin/pull/4094) * Use lazy loading to split up the size of the js downloaded * Use lazy loading to split up the size of the js downloaded * Add Moment Timezone plugin to reduce size of data file. * Lazy load header panels and use Dashicons for faster loading * Load assets from the correct publicPath * Load assets from the correct publicPath * PHP cs fixes * Fix missing quotes on string literal. * Fix PropType warning for lazy loaded component. * Separate the task list and dashboard chunks. * Lazy load dashboard sections. * Restore original icons and reduce size by importing only the icons needed * Lazy load alerts to save more Kb on initial load * Minify built JS in production mode. * Add preload tags for WC Admin assets. (https://github.com/woocommerce/woocommerce-admin/pull/4162) * Fix linting errors. * Add modified UnminifiedWebpackPlugin. * Produce minified and unminified bundles for all builds. * Remove unused variable from webpack config. * Run unminify after sourcemap generation. * Only hook after optimization if we're using a devtool. * Add minification suffix in Loader::get_url(). * Lazy load OBW on new home screen. * Move OBW style up a level to layout. * Hydrate ProfileWizard independently of withSelect and withDispatch * Fix order of composition and fallback function when using hydration. Co-authored-by: Jeff Stieler <jeff.m.stieler@gmail.com> Co-authored-by: Paul Sealock <psealock@gmail.com>
2020-04-29 18:01:27 +00:00
<Suspense fallback={ <Spinner /> }>
<TaskList
query={ query }
inline={ isDashboardShown }
/>
</Suspense>
) }
{ isDashboardShown && this.renderDashboardReports() }
</Fragment>
);
}
}
export default compose(
withSelect( ( select ) => {
const {
getCurrentUserData,
isGetProfileItemsRequesting,
getOptions,
isGetOptionsRequesting,
} = select( 'wc-api' );
const userData = getCurrentUserData();
wp.data Settings refactor add data store for settings using wp.data add use-select-with-refresh example replace fresh-data usage with new settings data store for settings page Add data package move to packages Fix isDirty after save Add isBusy to primary button when saving update Readme remove comment readme to use useSelect Revert "update Readme" This reverts commit 7402fd49b8f384fde5878e0bee0616f0a87bb4f6. Data Layer: Settings page to use Settings store (https://github.com/woocommerce/woocommerce-admin/pull/3430) * Data Layer: Settings store as source of truth for settings page This reverts commit 7402fd49b8f384fde5878e0bee0616f0a87bb4f6. * fixup * save on reset * non mutable constants * add set/getSettings * save using setSettings * separate HOC * cleanup * remove settingsToData * withHydration * remove withSettings HOC * renmove useSettins for now * withSettingsHydration updates * Revert "withSettingsHydration updates" This reverts commit f2adf108fbe19b574978fea5925a1a18e7ed3007. * rename withSettingsHydration * redo withSettingsHydration simplification * restore * useSettings * render using useSettings * handleInputChange working * get setIsDirty working * saving works * reset and cleanup * cleanup * use snake case on hook files * use clearIsDirty * Avoid mutation on setting update * remove @todo * persiting -> isPersisting * better reducer ternaries * add wcSettings as arg to withSettingsHydration reset package-lock Settings: split out mutable wcAdminSettings (https://github.com/woocommerce/woocommerce-admin/pull/3675) Settings: handle async settings groups (https://github.com/woocommerce/woocommerce-admin/pull/3707)
2020-03-25 03:20:17 +00:00
const { woocommerce_default_date_range: defaultDateRange } = select(
SETTINGS_STORE_NAME
).getSetting( 'wc_admin', 'wcAdminSettings' );
const withSelectData = {
userPrefSections: userData.dashboard_sections,
wp.data Settings refactor add data store for settings using wp.data add use-select-with-refresh example replace fresh-data usage with new settings data store for settings page Add data package move to packages Fix isDirty after save Add isBusy to primary button when saving update Readme remove comment readme to use useSelect Revert "update Readme" This reverts commit 7402fd49b8f384fde5878e0bee0616f0a87bb4f6. Data Layer: Settings page to use Settings store (https://github.com/woocommerce/woocommerce-admin/pull/3430) * Data Layer: Settings store as source of truth for settings page This reverts commit 7402fd49b8f384fde5878e0bee0616f0a87bb4f6. * fixup * save on reset * non mutable constants * add set/getSettings * save using setSettings * separate HOC * cleanup * remove settingsToData * withHydration * remove withSettings HOC * renmove useSettins for now * withSettingsHydration updates * Revert "withSettingsHydration updates" This reverts commit f2adf108fbe19b574978fea5925a1a18e7ed3007. * rename withSettingsHydration * redo withSettingsHydration simplification * restore * useSettings * render using useSettings * handleInputChange working * get setIsDirty working * saving works * reset and cleanup * cleanup * use snake case on hook files * use clearIsDirty * Avoid mutation on setting update * remove @todo * persiting -> isPersisting * better reducer ternaries * add wcSettings as arg to withSettingsHydration reset package-lock Settings: split out mutable wcAdminSettings (https://github.com/woocommerce/woocommerce-admin/pull/3675) Settings: handle async settings groups (https://github.com/woocommerce/woocommerce-admin/pull/3707)
2020-03-25 03:20:17 +00:00
defaultDateRange,
requesting: false,
};
if ( isOnboardingEnabled() ) {
const options = getOptions( [
'woocommerce_task_list_complete',
'woocommerce_task_list_hidden',
] );
withSelectData.taskListHidden =
get( options, [ 'woocommerce_task_list_hidden' ], 'no' ) ===
'yes';
withSelectData.taskListComplete = get(
options,
[ 'woocommerce_task_list_complete' ],
false
);
withSelectData.requesting =
withSelectData.requesting || isGetProfileItemsRequesting();
withSelectData.requesting =
withSelectData.requesting ||
isGetOptionsRequesting( [
'woocommerce_task_list_payments',
'woocommerce_task_list_hidden',
] );
}
return withSelectData;
} ),
withDispatch( ( dispatch ) => {
const { updateCurrentUserData } = dispatch( 'wc-api' );
return {
updateCurrentUserData,
};
} )
)( CustomizableDashboard );