Add leaderboard section (https://github.com/woocommerce/woocommerce-admin/pull/1234)
* Add leaderboard section to dashboard * Add rows per table user preference * Pass in rowsPerTable to leaderboards to adjust total rows * Add styling for rows select dropdown * Set default for total rows if tableQuery is undefined * Remove double localization on leaderboard labels * Simplify toggle logic for hidden leaderboards * Move updateCurrentUserData outside of setState callback
This commit is contained in:
parent
9fef5d4f5d
commit
ef6d7ec4cb
|
@ -23,9 +23,18 @@ import './style.scss';
|
|||
|
||||
export class Leaderboard extends Component {
|
||||
render() {
|
||||
const { getHeadersContent, getRowsContent, isRequesting, isError, items, title } = this.props;
|
||||
const {
|
||||
getHeadersContent,
|
||||
getRowsContent,
|
||||
isRequesting,
|
||||
isError,
|
||||
items,
|
||||
tableQuery,
|
||||
title,
|
||||
} = this.props;
|
||||
const data = get( items, [ 'data' ], [] );
|
||||
const rows = getRowsContent( data );
|
||||
const totalRows = tableQuery ? tableQuery.per_page : 5;
|
||||
|
||||
if ( isError ) {
|
||||
return <ReportError className="woocommerce-leaderboard" isError />;
|
||||
|
@ -47,9 +56,9 @@ export class Leaderboard extends Component {
|
|||
headers={ getHeadersContent() }
|
||||
isLoading={ isRequesting }
|
||||
rows={ rows }
|
||||
rowsPerPage={ 5 }
|
||||
rowsPerPage={ totalRows }
|
||||
title={ title }
|
||||
totalRows={ 5 }
|
||||
totalRows={ totalRows }
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -9,11 +9,11 @@ import { Component, Fragment } from '@wordpress/element';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
import Header from 'header';
|
||||
import StorePerformance from './store-performance';
|
||||
import TopSellingProducts from './top-selling-products';
|
||||
import DashboardCharts from './dashboard-charts';
|
||||
import Header from 'header';
|
||||
import Leaderboards from './leaderboards';
|
||||
import { ReportFilters } from '@woocommerce/components';
|
||||
import StorePerformance from './store-performance';
|
||||
|
||||
export default class Dashboard extends Component {
|
||||
render() {
|
||||
|
@ -23,11 +23,7 @@ export default class Dashboard extends Component {
|
|||
<Header sections={ [ __( 'Dashboard', 'wc-admin' ) ] } />
|
||||
<ReportFilters query={ query } path={ path } />
|
||||
<StorePerformance />
|
||||
<div className="woocommerce-dashboard__columns">
|
||||
<div>
|
||||
<TopSellingProducts query={ query } />
|
||||
</div>
|
||||
</div>
|
||||
<Leaderboards query={ query } />
|
||||
<DashboardCharts query={ query } path={ path } />
|
||||
</Fragment>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/** @format */
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Component, Fragment } from '@wordpress/element';
|
||||
import { compose } from '@wordpress/compose';
|
||||
import { isEqual, xor } from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import { SelectControl, ToggleControl } from '@wordpress/components';
|
||||
import { withDispatch } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* WooCommerce dependencies
|
||||
*/
|
||||
import { EllipsisMenu, MenuItem, MenuTitle, SectionHeader } from '@woocommerce/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import withSelect from 'wc-api/with-select';
|
||||
import TopSellingProducts from './top-selling-products';
|
||||
import './style.scss';
|
||||
|
||||
class Leaderboards extends Component {
|
||||
constructor( props ) {
|
||||
super( ...arguments );
|
||||
this.state = {
|
||||
hiddenLeaderboardKeys: props.userPrefLeaderboards || [],
|
||||
rowsPerTable: props.userPrefLeaderboardRows || 5,
|
||||
};
|
||||
|
||||
this.toggle = this.toggle.bind( this );
|
||||
}
|
||||
|
||||
componentDidUpdate( {
|
||||
userPrefLeaderboardRows: prevUserPrefLeaderboardRows,
|
||||
userPrefLeaderboards: prevUserPrefLeaderboards,
|
||||
} ) {
|
||||
const { userPrefLeaderboardRows, userPrefLeaderboards } = this.props;
|
||||
if ( userPrefLeaderboards && ! isEqual( userPrefLeaderboards, prevUserPrefLeaderboards ) ) {
|
||||
/* eslint-disable react/no-did-update-set-state */
|
||||
this.setState( {
|
||||
hiddenLeaderboardKeys: userPrefLeaderboards,
|
||||
} );
|
||||
/* eslint-enable react/no-did-update-set-state */
|
||||
}
|
||||
if (
|
||||
userPrefLeaderboardRows &&
|
||||
parseInt( userPrefLeaderboardRows ) !== parseInt( prevUserPrefLeaderboardRows )
|
||||
) {
|
||||
/* eslint-disable react/no-did-update-set-state */
|
||||
this.setState( {
|
||||
rowsPerTable: parseInt( userPrefLeaderboardRows ),
|
||||
} );
|
||||
/* eslint-enable react/no-did-update-set-state */
|
||||
}
|
||||
}
|
||||
|
||||
toggle( key ) {
|
||||
return () => {
|
||||
const hiddenLeaderboardKeys = xor( this.state.hiddenLeaderboardKeys, [ key ] );
|
||||
this.setState( { hiddenLeaderboardKeys } );
|
||||
const userDataFields = {
|
||||
[ 'dashboard_leaderboards' ]: hiddenLeaderboardKeys,
|
||||
};
|
||||
this.props.updateCurrentUserData( userDataFields );
|
||||
};
|
||||
}
|
||||
|
||||
setRowsPerTable = rows => {
|
||||
this.setState( { rowsPerTable: parseInt( rows ) } );
|
||||
const userDataFields = {
|
||||
[ 'dashboard_leaderboard_rows' ]: parseInt( rows ),
|
||||
};
|
||||
this.props.updateCurrentUserData( userDataFields );
|
||||
};
|
||||
|
||||
renderMenu() {
|
||||
const { hiddenLeaderboardKeys, rowsPerTable } = this.state;
|
||||
const allLeaderboards = [
|
||||
{
|
||||
key: 'top-products',
|
||||
label: __( 'Top Products', 'wc-admin' ),
|
||||
},
|
||||
{
|
||||
key: 'top-categories',
|
||||
label: __( 'Top Categories', 'wc-admin' ),
|
||||
},
|
||||
{
|
||||
key: 'top-coupons',
|
||||
label: __( 'Top Coupons', 'wc-admin' ),
|
||||
},
|
||||
];
|
||||
return (
|
||||
<EllipsisMenu label={ __( 'Choose which leaderboards to display', 'wc-admin' ) }>
|
||||
<Fragment>
|
||||
<MenuTitle>{ __( 'Leaderboards', 'wc-admin' ) }</MenuTitle>
|
||||
{ allLeaderboards.map( leaderboard => {
|
||||
return (
|
||||
<MenuItem onInvoke={ this.toggle( leaderboard.key ) } key={ leaderboard.key }>
|
||||
<ToggleControl
|
||||
label={ leaderboard.label }
|
||||
checked={ ! hiddenLeaderboardKeys.includes( leaderboard.key ) }
|
||||
onChange={ this.toggle( leaderboard.key ) }
|
||||
/>
|
||||
</MenuItem>
|
||||
);
|
||||
} ) }
|
||||
<MenuTitle>{ __( 'Rows Per Table', 'wc-admin' ) }</MenuTitle>
|
||||
<SelectControl
|
||||
className="woocommerce-ellipsis-menu__item"
|
||||
value={ rowsPerTable }
|
||||
options={ Array.from( { length: 20 }, ( v, key ) => ( {
|
||||
v: key + 1,
|
||||
label: key + 1,
|
||||
} ) ) }
|
||||
onChange={ this.setRowsPerTable }
|
||||
/>
|
||||
</Fragment>
|
||||
</EllipsisMenu>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { hiddenLeaderboardKeys, rowsPerTable } = this.state;
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="woocommerce-dashboard__dashboard-leaderboards">
|
||||
<SectionHeader title={ __( 'Leaderboards', 'wc-admin' ) } menu={ this.renderMenu() } />
|
||||
<div className="woocommerce-dashboard__columns">
|
||||
<div>
|
||||
{ ! hiddenLeaderboardKeys.includes( 'top-products' ) && (
|
||||
<TopSellingProducts query={ this.props.query } totalRows={ rowsPerTable } />
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Leaderboards.propTypes = {
|
||||
query: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default compose(
|
||||
withSelect( select => {
|
||||
const { getCurrentUserData } = select( 'wc-api' );
|
||||
const userData = getCurrentUserData();
|
||||
|
||||
return {
|
||||
userPrefLeaderboards: userData.dashboard_leaderboards,
|
||||
userPrefLeaderboardRows: userData.dashboard_leaderboard_rows,
|
||||
};
|
||||
} ),
|
||||
withDispatch( dispatch => {
|
||||
const { updateCurrentUserData } = dispatch( 'wc-api' );
|
||||
|
||||
return {
|
||||
updateCurrentUserData,
|
||||
};
|
||||
} )
|
||||
)( Leaderboards );
|
|
@ -0,0 +1,11 @@
|
|||
/** @format */
|
||||
|
||||
.woocommerce-dashboard__dashboard-leaderboards {
|
||||
.components-base-control__field {
|
||||
width: 100%;
|
||||
}
|
||||
.components-select-control__input {
|
||||
border: 1px solid $core-grey-light-700;
|
||||
height: 34px;
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ import { getAdminLink } from '@woocommerce/navigation';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { numberFormat } from 'lib/number';
|
||||
import Leaderboard from 'dashboard/leaderboard';
|
||||
import Leaderboard from 'analytics/components/leaderboard';
|
||||
|
||||
export class TopSellingProducts extends Component {
|
||||
constructor( props ) {
|
||||
|
@ -88,10 +88,11 @@ export class TopSellingProducts extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { query, totalRows } = this.props;
|
||||
const tableQuery = {
|
||||
orderby: 'items_sold',
|
||||
order: 'desc',
|
||||
per_page: 5, //TODO replace with user configured leaderboard per page value.
|
||||
per_page: totalRows,
|
||||
extended_info: true,
|
||||
};
|
||||
|
||||
|
@ -100,7 +101,7 @@ export class TopSellingProducts extends Component {
|
|||
endpoint="products"
|
||||
getHeadersContent={ this.getHeadersContent }
|
||||
getRowsContent={ this.getRowsContent }
|
||||
query={ this.props.query }
|
||||
query={ query }
|
||||
tableQuery={ tableQuery }
|
||||
title={ __( 'Top Selling Products', 'wc-admin' ) }
|
||||
/>
|
|
@ -42,6 +42,8 @@ function updateCurrentUserData( resourceNames, data, fetch ) {
|
|||
'variations_report_columns',
|
||||
'dashboard_charts',
|
||||
'dashboard_chart_type',
|
||||
'dashboard_leaderboards',
|
||||
'dashboard_leaderboard_rows',
|
||||
];
|
||||
|
||||
if ( resourceNames.includes( resourceName ) ) {
|
||||
|
|
|
@ -401,6 +401,8 @@ function wc_admin_get_user_data_fields() {
|
|||
'variations_report_columns',
|
||||
'dashboard_charts',
|
||||
'dashboard_chart_type',
|
||||
'dashboard_leaderboards',
|
||||
'dashboard_leaderboard_rows',
|
||||
);
|
||||
|
||||
return apply_filters( 'wc_admin_get_user_data_fields', $user_data_fields );
|
||||
|
|
Loading…
Reference in New Issue