Skip to content
This repository has been archived by the owner on Jun 7, 2022. It is now read-only.

Commit

Permalink
Hook up performance indicators to the REST API
Browse files Browse the repository at this point in the history
  • Loading branch information
justinshreve committed Jan 17, 2019
1 parent dbdcbcb commit e835acc
Show file tree
Hide file tree
Showing 20 changed files with 473 additions and 156 deletions.
2 changes: 1 addition & 1 deletion client/analytics/components/report-summary/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { SummaryList, SummaryListPlaceholder, SummaryNumber } from '@woocommerce
*/
import { getSummaryNumbers } from 'store/reports/utils';
import ReportError from 'analytics/components/report-error';
import { calculateDelta, formatValue } from './utils';
import { calculateDelta, formatValue } from 'lib/number';
import withSelect from 'wc-api/with-select';

/**
Expand Down
42 changes: 0 additions & 42 deletions client/analytics/components/report-summary/utils.js

This file was deleted.

2 changes: 1 addition & 1 deletion client/dashboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default class Dashboard extends Component {
<Fragment>
<Header sections={ [ __( 'Dashboard', 'wc-admin' ) ] } />
<ReportFilters query={ query } path={ path } />
<StorePerformance />
<StorePerformance query={ query } />
<Leaderboards query={ query } />
<DashboardCharts query={ query } path={ path } />
</Fragment>
Expand Down
235 changes: 169 additions & 66 deletions client/dashboard/store-performance/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { __, sprintf } from '@wordpress/i18n';
import { ToggleControl } from '@wordpress/components';
import { Component, Fragment } from '@wordpress/element';
import { compose } from '@wordpress/compose';
import { withDispatch } from '@wordpress/data';
import { getCurrentDates, appendTimestamp, getDateParamsFromQuery } from '@woocommerce/date';
import { getNewPath, getPersistedQuery } from '@woocommerce/navigation';
import moment from 'moment';
import { find } from 'lodash';

/**
* Internal dependencies
Expand All @@ -16,99 +22,196 @@ import {
MenuTitle,
SectionHeader,
SummaryList,
SummaryListPlaceholder,
SummaryNumber,
} from '@woocommerce/components';
import withSelect from 'wc-api/with-select';
import './style.scss';
import { calculateDelta, formatValue } from 'lib/number';

class StorePerformance extends Component {
constructor() {
super( ...arguments );
constructor( props ) {
super( props );
this.state = {
showCustomers: true,
showProducts: true,
showOrders: true,
userPrefs: props.userPrefs || [],
};

this.toggle = this.toggle.bind( this );
}

toggle( type ) {
toggle( statKey ) {
return () => {
this.setState( state => ( { [ type ]: ! state[ type ] } ) );
this.setState( state => {
const prefs = [ ...state.userPrefs ];
let newPrefs = [];
if ( ! prefs.includes( statKey ) ) {
prefs.push( statKey );
newPrefs = prefs;
} else {
newPrefs = prefs.filter( pref => pref !== statKey );
}
this.props.updateCurrentUserData( {
dashboard_performance_indicators: newPrefs,
} );
return {
userPrefs: newPrefs,
};
} );
};
}

renderMenu() {
const { indicators } = this.props;
return (
<EllipsisMenu label={ __( 'Choose which analytics to display', 'wc-admin' ) }>
<MenuTitle>{ __( 'Display Stats:', 'wc-admin' ) }</MenuTitle>
<MenuItem onInvoke={ this.toggle( 'showCustomers' ) }>
<ToggleControl
label={ __( 'Show Customers', 'wc-admin' ) }
checked={ this.state.showCustomers }
onChange={ this.toggle( 'showCustomers' ) }
/>
</MenuItem>
<MenuItem onInvoke={ this.toggle( 'showProducts' ) }>
<ToggleControl
label={ __( 'Show Products', 'wc-admin' ) }
checked={ this.state.showProducts }
onChange={ this.toggle( 'showProducts' ) }
/>
</MenuItem>
<MenuItem onInvoke={ this.toggle( 'showOrders' ) }>
<ToggleControl
label={ __( 'Show Orders', 'wc-admin' ) }
checked={ this.state.showOrders }
onChange={ this.toggle( 'showOrders' ) }
/>
</MenuItem>
{ indicators.map( ( indicator, i ) => {
const checked = ! this.state.userPrefs.includes( indicator.stat );
return (
<MenuItem onInvoke={ this.toggle( indicator.stat ) } key={ i }>
<ToggleControl
label={ sprintf( __( 'Show %s', 'wc-admin' ), indicator.label ) }
checked={ checked }
onChange={ this.toggle( indicator.stat ) }
/>
</MenuItem>
);
} ) }
</EllipsisMenu>
);
}

render() {
const totalOrders = 10;
const totalProducts = 1000;
const { showCustomers, showProducts, showOrders } = this.state;
renderList() {
const {
query,
primaryRequesting,
secondaryRequesting,
primaryError,
secondaryError,
primaryData,
secondaryData,
userIndicators,
} = this.props;
if ( primaryRequesting || secondaryRequesting ) {
return <SummaryListPlaceholder numberOfItems={ userIndicators.length } />;
}

if ( primaryError || secondaryError ) {
return null;
}

const persistedQuery = getPersistedQuery( query );

const { compare } = getDateParamsFromQuery( query );
const prevLabel =
'previous_period' === compare
? __( 'Previous Period:', 'wc-admin' )
: __( 'Previous Year:', 'wc-admin' );
return (
<SummaryList>
{ userIndicators.map( ( indicator, i ) => {
const primaryItem = find( primaryData.data, data => data.stat === indicator.stat );
const secondaryItem = find( secondaryData.data, data => data.stat === indicator.stat );

if ( ! primaryItem || ! secondaryItem ) {
return null;
}

const href =
( primaryItem._links &&
primaryItem._links.report[ 0 ] &&
primaryItem._links.report[ 0 ].href ) ||
'';
const reportUrl =
( href && getNewPath( persistedQuery, href, { chart: primaryItem.chart } ) ) || '';
const delta = calculateDelta( primaryItem.value, secondaryItem.value );
const primaryValue = formatValue( primaryItem.format, primaryItem.value );
const secondaryValue = formatValue( secondaryItem.format, secondaryItem.value );

return (
<SummaryNumber
key={ i }
href={ reportUrl }
label={ indicator.label }
value={ primaryValue }
prevLabel={ prevLabel }
prevValue={ secondaryValue }
delta={ delta }
/>
);
} ) }
</SummaryList>
);
}

render() {
return (
<Fragment>
<SectionHeader title={ __( 'Store Performance', 'wc-admin' ) } menu={ this.renderMenu() } />
<Card className="woocommerce-dashboard__store-performance">
<SummaryList>
{ showCustomers && (
<SummaryNumber
label={ __( 'New Customers', 'wc-admin' ) }
value={ '2' }
prevLabel={ __( 'Previous Week:', 'wc-admin' ) }
prevValue={ 3 }
delta={ -33 }
/>
) }
{ showProducts && (
<SummaryNumber
label={ __( 'Total Products', 'wc-admin' ) }
value={ totalProducts }
prevLabel={ __( 'Previous Week:', 'wc-admin' ) }
prevValue={ totalProducts }
delta={ 0 }
/>
) }
{ showOrders && (
<SummaryNumber
label={ __( 'Total Orders', 'wc-admin' ) }
value={ totalOrders }
prevLabel={ __( 'Previous Week:', 'wc-admin' ) }
prevValue={ totalOrders }
delta={ 0 }
/>
) }
</SummaryList>
</Card>
<Card className="woocommerce-dashboard__store-performance">{ this.renderList() }</Card>
</Fragment>
);
}
}
export default compose(
withSelect( ( select, props ) => {
const { query } = props;
const {
getCurrentUserData,
getReportItems,
getReportItemsError,
isReportItemsRequesting,
} = select( 'wc-api' );
const userData = getCurrentUserData();
const userPrefs = userData.dashboard_performance_indicators;

const datesFromQuery = getCurrentDates( query );
const endPrimary = datesFromQuery.primary.before;
const endSecondary = datesFromQuery.secondary.before;

const indicators = wcSettings.dataEndpoints.performanceIndicators;
const userIndicators = indicators.filter( indicator => ! userPrefs.includes( indicator.stat ) );
const statKeys = userIndicators.map( indicator => indicator.stat ).join( ',' );

export default StorePerformance;
const primaryQuery = {
after: appendTimestamp( datesFromQuery.primary.after, 'start' ),
before: appendTimestamp( endPrimary, endPrimary.isSame( moment(), 'day' ) ? 'now' : 'end' ),
stats: statKeys,
};

const secondaryQuery = {
after: appendTimestamp( datesFromQuery.secondary.after, 'start' ),
before: appendTimestamp(
endSecondary,
endSecondary.isSame( moment(), 'day' ) ? 'now' : 'end'
),
stats: statKeys,
};

const primaryData = getReportItems( 'performance-indicators', primaryQuery );
const primaryError = getReportItemsError( 'performance-indicators', primaryQuery ) || null;
const primaryRequesting = isReportItemsRequesting( 'performance-indicators', primaryQuery );

const secondaryData = getReportItems( 'performance-indicators', secondaryQuery );
const secondaryError = getReportItemsError( 'performance-indicators', secondaryQuery ) || null;
const secondaryRequesting = isReportItemsRequesting( 'performance-indicators', secondaryQuery );

return {
userPrefs,
userIndicators,
indicators,
primaryData,
primaryError,
primaryRequesting,
secondaryData,
secondaryError,
secondaryRequesting,
};
} ),
withDispatch( dispatch => {
const { updateCurrentUserData } = dispatch( 'wc-api' );

return {
updateCurrentUserData,
};
} )
)( StorePerformance );
35 changes: 35 additions & 0 deletions client/lib/number/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
/** @format */

/**
* External dependencies
*/
import { formatCurrency } from '@woocommerce/currency';
import { isFinite } from 'lodash';

/**
* Formats a number using site's current locale
*
Expand All @@ -18,3 +26,30 @@ export function numberFormat( number ) {
}
return new Intl.NumberFormat( locale ).format( number );
}

export function formatValue( type, value ) {
if ( ! isFinite( value ) ) {
return null;
}

switch ( type ) {
case 'average':
return Math.round( value );
case 'currency':
return formatCurrency( value );
case 'number':
return numberFormat( value );
}
}

export function calculateDelta( primaryValue, secondaryValue ) {
if ( ! isFinite( primaryValue ) || ! isFinite( secondaryValue ) ) {
return null;
}

if ( secondaryValue === 0 ) {
return 0;
}

return Math.round( ( primaryValue - secondaryValue ) / secondaryValue * 100 );
}
1 change: 1 addition & 0 deletions client/wc-api/reports/items/operations.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const typeEndpointMap = {
'report-items-query-downloads': 'downloads',
'report-items-query-customers': 'customers',
'report-items-query-stock': 'stock',
'report-items-query-performance-indicators': 'performance-indicators',
};

function read( resourceNames, fetch = apiFetch ) {
Expand Down
1 change: 1 addition & 0 deletions client/wc-api/user/operations.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ function updateCurrentUserData( resourceNames, data, fetch ) {
'revenue_report_columns',
'taxes_report_columns',
'variations_report_columns',
'dashboard_performance_indicators',
'dashboard_charts',
'dashboard_chart_type',
'dashboard_chart_interval',
Expand Down

0 comments on commit e835acc

Please sign in to comment.