From 3fc69b973977d7d84e776efea7920f98494a621b Mon Sep 17 00:00:00 2001 From: Paul Sealock Date: Tue, 5 May 2020 10:58:39 +1200 Subject: [PATCH] Homepage: Add stats overview selection (https://github.com/woocommerce/woocommerce-admin/pull/4264) * Homwpage: add stats overview stat toggle * toggle stats * fix * tests * better hook name * clean up * add back in Fragment * remove extra prop * better test name --- .../dashboard/store-performance/index.js | 2 +- .../client/homepage/index.js | 3 +- .../homepage/stats-overview/defaults.js | 19 +++ .../client/homepage/stats-overview/index.js | 123 ++++++++++++++++++ .../homepage/stats-overview/test/index.js | 68 ++++++++++ .../client/homepage/test/index.js | 15 --- .../client/wc-api/user/operations.js | 1 + .../src/Features/AnalyticsDashboard.php | 5 +- .../tests/js/setup-globals.js | 25 +++- 9 files changed, 241 insertions(+), 20 deletions(-) create mode 100644 plugins/woocommerce-admin/client/homepage/stats-overview/defaults.js create mode 100644 plugins/woocommerce-admin/client/homepage/stats-overview/index.js create mode 100644 plugins/woocommerce-admin/client/homepage/stats-overview/test/index.js delete mode 100644 plugins/woocommerce-admin/client/homepage/test/index.js diff --git a/plugins/woocommerce-admin/client/dashboard/store-performance/index.js b/plugins/woocommerce-admin/client/dashboard/store-performance/index.js index fb3ed77075d..ca0ccf70d4a 100644 --- a/plugins/woocommerce-admin/client/dashboard/store-performance/index.js +++ b/plugins/woocommerce-admin/client/dashboard/store-performance/index.js @@ -39,7 +39,7 @@ import { recordEvent } from 'lib/tracks'; import { CurrencyContext } from 'lib/currency-context'; const { performanceIndicators: indicators } = getSetting( 'dataEndpoints', { - performanceIndicators: '', + performanceIndicators: [], } ); class StorePerformance extends Component { diff --git a/plugins/woocommerce-admin/client/homepage/index.js b/plugins/woocommerce-admin/client/homepage/index.js index 5cd4517a3fa..5789f1e59f6 100644 --- a/plugins/woocommerce-admin/client/homepage/index.js +++ b/plugins/woocommerce-admin/client/homepage/index.js @@ -14,6 +14,7 @@ import { Spinner } from '@woocommerce/components'; */ import withSelect from 'wc-api/with-select'; import { isOnboardingEnabled } from 'dashboard/utils'; +import StatsOverview from './stats-overview'; const ProfileWizard = lazy( () => import( /* webpackChunkName: "profile-wizard" */ '../profile-wizard' ) @@ -28,7 +29,7 @@ const Homepage = ( { profileItems, query } ) => { ); } - return
Hello World
; + return ; }; export default compose( diff --git a/plugins/woocommerce-admin/client/homepage/stats-overview/defaults.js b/plugins/woocommerce-admin/client/homepage/stats-overview/defaults.js new file mode 100644 index 00000000000..b9327aec07f --- /dev/null +++ b/plugins/woocommerce-admin/client/homepage/stats-overview/defaults.js @@ -0,0 +1,19 @@ +/** + * External dependencies + */ +import { applyFilters } from '@wordpress/hooks'; + +export const DEFAULT_STATS = applyFilters( + 'woocommerce_admin_homepage_default_stats', + [ + 'revenue/total_sales', + 'revenue/net_revenue', + 'orders/orders_count', + 'products/items_sold', + ] +); + +export const DEFAULT_HIDDEN_STATS = [ + 'revenue/net_revenue', + 'products/items_sold', +]; diff --git a/plugins/woocommerce-admin/client/homepage/stats-overview/index.js b/plugins/woocommerce-admin/client/homepage/stats-overview/index.js new file mode 100644 index 00000000000..5c13e69a201 --- /dev/null +++ b/plugins/woocommerce-admin/client/homepage/stats-overview/index.js @@ -0,0 +1,123 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { compose } from '@wordpress/compose'; +import { Fragment } from '@wordpress/element'; +import { xor } from 'lodash'; +import { withDispatch } from '@wordpress/data'; +import PropTypes from 'prop-types'; +import { recordEvent } from 'lib/tracks'; + +/** + * WooCommerce dependencies + */ +import { + Card, + EllipsisMenu, + MenuItem, + MenuTitle, +} from '@woocommerce/components'; +import { getSetting } from '@woocommerce/wc-admin-settings'; + +/** + * Internal dependencies + */ +import withSelect from 'wc-api/with-select'; +import { DEFAULT_STATS, DEFAULT_HIDDEN_STATS } from './defaults'; + +const { performanceIndicators } = getSetting( 'dataEndpoints', { + performanceIndicators: [], +} ); +const stats = performanceIndicators.filter( ( indicator ) => { + return DEFAULT_STATS.includes( indicator.stat ); +} ); + +export const StatsOverview = ( { userPrefs, updateCurrentUserData } ) => { + const userHiddenStats = userPrefs.hiddenStats; + const hiddenStats = userHiddenStats + ? userHiddenStats + : DEFAULT_HIDDEN_STATS; + + const toggleStat = ( stat ) => { + const nextHiddenStats = xor( hiddenStats, [ stat ] ); + updateCurrentUserData( { + homepage_stats: { hiddenStats: nextHiddenStats }, + } ); + recordEvent( 'statsoverview_indicators_toggle', { + indicator_name: stat, + status: nextHiddenStats.includes( stat ) ? 'off' : 'on', + } ); + }; + + return ( + ( + + + { __( 'Display stats:', 'woocommerce-admin' ) } + + { stats.map( ( item ) => { + const checked = ! hiddenStats.includes( + item.stat + ); + + return ( + + toggleStat( item.stat ) + } + > + { item.label } + + ); + } ) } + + ) } + /> + } + > + Content Here + + ); +}; + +StatsOverview.propTypes = { + /** + * Homepage user preferences. + */ + userPrefs: PropTypes.object.isRequired, + /** + * A method to update user meta. + */ + updateCurrentUserData: PropTypes.func.isRequired, +}; + +export default compose( + withSelect( ( select ) => { + const { getCurrentUserData } = select( 'wc-api' ); + + return { + userPrefs: getCurrentUserData().homepage_stats || {}, + }; + } ), + withDispatch( ( dispatch ) => { + const { updateCurrentUserData } = dispatch( 'wc-api' ); + + return { + updateCurrentUserData, + }; + } ) +)( StatsOverview ); diff --git a/plugins/woocommerce-admin/client/homepage/stats-overview/test/index.js b/plugins/woocommerce-admin/client/homepage/stats-overview/test/index.js new file mode 100644 index 00000000000..b2c8b4fab16 --- /dev/null +++ b/plugins/woocommerce-admin/client/homepage/stats-overview/test/index.js @@ -0,0 +1,68 @@ +/** + * External dependencies + */ +import { render, fireEvent, screen } from '@testing-library/react'; +import { StatsOverview } from '../index'; +import { recordEvent } from 'lib/tracks'; + +jest.mock( 'lib/tracks' ); + +describe( 'StatsOverview tracking', () => { + it( 'should record an event when a stat is toggled', () => { + render( + {} } + /> + ); + + const ellipsisBtn = screen.getByTitle( + 'Choose which values to display' + ); + fireEvent.click( ellipsisBtn ); + const totalSalesBtn = screen.getByText( 'Total Sales' ); + fireEvent.click( totalSalesBtn ); + + expect( recordEvent ).toHaveBeenCalledWith( + 'statsoverview_indicators_toggle', + { + indicator_name: 'revenue/total_sales', + status: 'off', + } + ); + } ); +} ); + +describe( 'StatsOverview toggle and persist stat preference', () => { + it( 'should update preferences', () => { + const updateCurrentUserData = jest.fn(); + + render( + + ); + + const ellipsisBtn = screen.getByTitle( + 'Choose which values to display' + ); + fireEvent.click( ellipsisBtn ); + const totalSalesBtn = screen.getByText( 'Total Sales' ); + fireEvent.click( totalSalesBtn ); + + expect( updateCurrentUserData ).toHaveBeenCalledWith( { + homepage_stats: { + hiddenStats: [ + 'revenue/net_revenue', + 'products/items_sold', + 'revenue/total_sales', + ], + }, + } ); + } ); +} ); diff --git a/plugins/woocommerce-admin/client/homepage/test/index.js b/plugins/woocommerce-admin/client/homepage/test/index.js deleted file mode 100644 index eb54bdecc40..00000000000 --- a/plugins/woocommerce-admin/client/homepage/test/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import { render } from '@testing-library/react'; -import Homepage from '../index'; - -describe( 'homepage', () => { - it( 'should render', () => { - const { container } = render( ); - expect( container ).toMatchInlineSnapshot( ` -
-
- Hello World -
-
- ` ); - } ); -} ); diff --git a/plugins/woocommerce-admin/client/wc-api/user/operations.js b/plugins/woocommerce-admin/client/wc-api/user/operations.js index a2ad997608d..d1d188084f4 100644 --- a/plugins/woocommerce-admin/client/wc-api/user/operations.js +++ b/plugins/woocommerce-admin/client/wc-api/user/operations.js @@ -47,6 +47,7 @@ function updateCurrentUserData( resourceNames, data, fetch ) { 'dashboard_chart_interval', 'dashboard_leaderboard_rows', 'activity_panel_inbox_last_read', + 'homepage_stats', ]; if ( resourceNames.includes( resourceName ) ) { diff --git a/plugins/woocommerce-admin/src/Features/AnalyticsDashboard.php b/plugins/woocommerce-admin/src/Features/AnalyticsDashboard.php index 74bf8461529..3985abc7f63 100644 --- a/plugins/woocommerce-admin/src/Features/AnalyticsDashboard.php +++ b/plugins/woocommerce-admin/src/Features/AnalyticsDashboard.php @@ -71,6 +71,7 @@ class AnalyticsDashboard { 'dashboard_chart_type', 'dashboard_chart_interval', 'dashboard_leaderboard_rows', + 'homepage_stats', ) ); } @@ -80,8 +81,8 @@ class AnalyticsDashboard { */ public function register_page() { $features = wc_admin_get_feature_config(); - $id = $features['homepage'] ? 'woocommerce-home' : 'woocommerce-dashboard'; - $title = $features['homepage'] ? __( 'Home', 'woocommerce-admin' ) : __( 'Dashboard', 'woocommerce-admin' ); + $id = $features['homepage'] ? 'woocommerce-home' : 'woocommerce-dashboard'; + $title = $features['homepage'] ? __( 'Home', 'woocommerce-admin' ) : __( 'Dashboard', 'woocommerce-admin' ); wc_admin_register_page( array( diff --git a/plugins/woocommerce-admin/tests/js/setup-globals.js b/plugins/woocommerce-admin/tests/js/setup-globals.js index 15531f1eb0c..da284fcba87 100644 --- a/plugins/woocommerce-admin/tests/js/setup-globals.js +++ b/plugins/woocommerce-admin/tests/js/setup-globals.js @@ -62,7 +62,30 @@ global.wcSettings = { woocommerce_actionable_order_statuses: [], woocommerce_excluded_report_order_statuses: [], }, - dataEndpoints: {}, + dataEndpoints: { + performanceIndicators: [ + { + chart: 'total_sales', + label: 'Total Sales', + stat: 'revenue/total_sales', + }, + { + chart: 'net_revenue', + label: 'Net Sales', + stat: 'revenue/net_revenue', + }, + { + chart: 'orders_count', + label: 'Orders', + stat: 'orders/orders_count', + }, + { + chart: 'items_sold', + label: 'Items Sold', + stat: 'products/items_sold', + }, + ], + }, }; wordPressPackages.forEach( ( lib ) => {