2018-07-05 03:14:40 +00:00
|
|
|
/** @format */
|
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
2018-10-10 20:29:12 +00:00
|
|
|
import { __ } from '@wordpress/i18n';
|
2018-08-06 21:33:55 +00:00
|
|
|
import { Component, Fragment } from '@wordpress/element';
|
|
|
|
import { compose } from '@wordpress/compose';
|
2018-10-11 17:07:59 +00:00
|
|
|
import { format as formatDate } from '@wordpress/date';
|
|
|
|
import PropTypes from 'prop-types';
|
2018-10-11 08:30:51 +00:00
|
|
|
import { withSelect } from '@wordpress/data';
|
2018-10-11 17:07:59 +00:00
|
|
|
import { map, find, isEqual } from 'lodash';
|
2018-07-05 03:14:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
2018-10-10 20:29:12 +00:00
|
|
|
import {
|
2018-10-11 17:07:59 +00:00
|
|
|
Chart,
|
|
|
|
ChartPlaceholder,
|
2018-10-10 20:29:12 +00:00
|
|
|
ReportFilters,
|
|
|
|
SummaryList,
|
|
|
|
SummaryListPlaceholder,
|
|
|
|
SummaryNumber,
|
|
|
|
} from '@woocommerce/components';
|
2018-09-11 07:58:11 +00:00
|
|
|
import { filters, advancedFilterConfig } from './config';
|
2018-10-10 20:29:12 +00:00
|
|
|
import { formatCurrency } from 'lib/currency';
|
|
|
|
import { getNewPath } from 'lib/nav-utils';
|
|
|
|
import { getReportChartData } from 'store/reports/utils';
|
2018-10-11 17:07:59 +00:00
|
|
|
import {
|
|
|
|
getAllowedIntervalsForQuery,
|
|
|
|
getCurrentDates,
|
|
|
|
getDateParamsFromQuery,
|
|
|
|
getDateFormatsForInterval,
|
|
|
|
getIntervalForQuery,
|
|
|
|
getPreviousDate,
|
|
|
|
} from 'lib/date';
|
2018-10-10 20:29:12 +00:00
|
|
|
import { MAX_PER_PAGE } from 'store/constants';
|
2018-10-11 08:30:51 +00:00
|
|
|
import OrdersReportTable from './table';
|
2018-07-05 03:14:40 +00:00
|
|
|
|
|
|
|
class OrdersReport extends Component {
|
|
|
|
constructor( props ) {
|
|
|
|
super( props );
|
|
|
|
|
2018-10-10 20:29:12 +00:00
|
|
|
this.state = {
|
|
|
|
primaryTotals: null,
|
|
|
|
secondaryTotals: null,
|
|
|
|
};
|
2018-07-05 03:14:40 +00:00
|
|
|
}
|
|
|
|
|
2018-10-11 16:00:06 +00:00
|
|
|
// Track primary and secondary 'totals' indepdent of query.
|
|
|
|
// We don't want each little query update (interval, sorting, etc)
|
|
|
|
componentDidUpdate( prevProps ) {
|
|
|
|
/* eslint-disable react/no-did-update-set-state */
|
|
|
|
|
|
|
|
if ( ! isEqual( prevProps.dates, this.props.dates ) ) {
|
|
|
|
this.setState( {
|
|
|
|
primaryTotals: null,
|
|
|
|
secondaryTotals: null,
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
const { secondaryData, primaryData } = this.props;
|
|
|
|
if ( ! isEqual( prevProps.secondaryData, secondaryData ) ) {
|
|
|
|
if ( secondaryData && secondaryData.data && secondaryData.data.totals ) {
|
|
|
|
this.setState( { secondaryTotals: secondaryData.data.totals } );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! isEqual( prevProps.primaryData, primaryData ) ) {
|
|
|
|
if ( primaryData && primaryData.data && primaryData.data.totals ) {
|
|
|
|
this.setState( { primaryTotals: primaryData.data.totals } );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* eslint-enable react/no-did-update-set-state */
|
|
|
|
}
|
|
|
|
|
2018-10-10 20:29:12 +00:00
|
|
|
getCharts() {
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
key: 'net_revenue',
|
|
|
|
label: __( 'Net Revenue', 'wc-admin' ),
|
|
|
|
type: 'currency',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: 'avg_order_value',
|
|
|
|
label: __( 'Avergae Order Value', 'wc-admin' ),
|
|
|
|
type: 'currency',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: 'avg_items_per_order',
|
|
|
|
label: __( 'Average Items Per Order', 'wc-admin' ),
|
|
|
|
type: 'number',
|
|
|
|
},
|
|
|
|
{
|
2018-10-11 16:00:06 +00:00
|
|
|
key: 'orders_count',
|
2018-10-10 20:29:12 +00:00
|
|
|
label: __( 'Orders Count', 'wc-admin' ),
|
|
|
|
type: 'number',
|
|
|
|
},
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
getSelectedChart() {
|
|
|
|
const { query } = this.props;
|
|
|
|
const charts = this.getCharts();
|
|
|
|
|
|
|
|
const chart = find( charts, { key: query.chart } );
|
|
|
|
if ( chart ) {
|
|
|
|
return chart;
|
|
|
|
}
|
|
|
|
|
|
|
|
return charts[ 0 ];
|
|
|
|
}
|
|
|
|
|
|
|
|
renderChartSummaryNumbers() {
|
|
|
|
const selectedChart = this.getSelectedChart();
|
|
|
|
const charts = this.getCharts();
|
|
|
|
if ( ! this.state.primaryTotals || ! this.state.secondaryTotals ) {
|
|
|
|
return <SummaryListPlaceholder numberOfItems={ charts.length } />;
|
|
|
|
}
|
|
|
|
|
|
|
|
const totals = this.state.primaryTotals || {};
|
|
|
|
const secondaryTotals = this.state.secondaryTotals || {};
|
|
|
|
const { compare } = getDateParamsFromQuery( this.props.query );
|
|
|
|
|
|
|
|
const summaryNumbers = map( this.getCharts(), chart => {
|
|
|
|
const { key, label, type } = chart;
|
|
|
|
const isSelected = selectedChart.key === key;
|
|
|
|
|
|
|
|
let value = parseFloat( totals[ key ] );
|
|
|
|
let secondaryValue =
|
|
|
|
( secondaryTotals[ key ] && parseFloat( secondaryTotals[ key ] ) ) || undefined;
|
|
|
|
|
|
|
|
let delta = 0;
|
|
|
|
if ( secondaryValue && secondaryValue !== 0 ) {
|
|
|
|
delta = Math.round( ( value - secondaryValue ) / secondaryValue * 100 );
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ( type ) {
|
|
|
|
case 'currency':
|
|
|
|
value = formatCurrency( value );
|
|
|
|
secondaryValue = secondaryValue && formatCurrency( secondaryValue );
|
|
|
|
break;
|
|
|
|
case 'number':
|
|
|
|
value = value;
|
|
|
|
secondaryValue = secondaryValue;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
const href = getNewPath( { chart: key } );
|
|
|
|
|
|
|
|
return (
|
|
|
|
<SummaryNumber
|
|
|
|
key={ key }
|
|
|
|
value={ value }
|
|
|
|
label={ label }
|
|
|
|
selected={ isSelected }
|
|
|
|
prevValue={ secondaryValue }
|
|
|
|
prevLabel={
|
|
|
|
'previous_period' === compare
|
|
|
|
? __( 'Previous Period:', 'wc-admin' )
|
|
|
|
: __( 'Previous Year:', 'wc-admin' )
|
|
|
|
}
|
|
|
|
delta={ delta }
|
|
|
|
href={ href }
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
} );
|
|
|
|
|
|
|
|
return <SummaryList>{ summaryNumbers }</SummaryList>;
|
|
|
|
}
|
|
|
|
|
2018-10-11 17:07:59 +00:00
|
|
|
renderChart() {
|
|
|
|
const { primaryData, secondaryData, query } = this.props;
|
|
|
|
|
|
|
|
if ( primaryData.isRequesting || secondaryData.isRequesting ) {
|
|
|
|
return (
|
|
|
|
<Fragment>
|
|
|
|
<span className="screen-reader-text">
|
|
|
|
{ __( 'Your requested data is loading', 'wc-admin' ) }
|
|
|
|
</span>
|
|
|
|
<ChartPlaceholder />
|
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const currentInterval = getIntervalForQuery( query );
|
|
|
|
const allowedIntervals = getAllowedIntervalsForQuery( query );
|
|
|
|
const formats = getDateFormatsForInterval( currentInterval );
|
|
|
|
|
|
|
|
const { primary, secondary } = getCurrentDates( query );
|
|
|
|
const selectedChart = this.getSelectedChart();
|
|
|
|
|
|
|
|
const primaryKey = `${ primary.label } (${ primary.range })`;
|
|
|
|
const secondaryKey = `${ secondary.label } (${ secondary.range })`;
|
|
|
|
|
|
|
|
const chartData = primaryData.data.intervals.map( function( interval, index ) {
|
|
|
|
const secondaryDate = getPreviousDate(
|
|
|
|
formatDate( 'Y-m-d', interval.date_start ),
|
|
|
|
primary.after,
|
|
|
|
secondary.after,
|
|
|
|
query.compare,
|
|
|
|
currentInterval
|
|
|
|
);
|
|
|
|
|
|
|
|
const secondaryInterval = secondaryData.data.intervals[ index ];
|
|
|
|
return {
|
|
|
|
date: formatDate( 'Y-m-d\\TH:i:s', interval.date_start ),
|
|
|
|
[ primaryKey ]: {
|
|
|
|
labelDate: interval.date_start,
|
|
|
|
value: interval.subtotals[ selectedChart.key ] || 0,
|
|
|
|
},
|
|
|
|
[ secondaryKey ]: {
|
|
|
|
labelDate: secondaryDate,
|
|
|
|
value: ( secondaryInterval && secondaryInterval.subtotals[ selectedChart.key ] ) || 0,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
} );
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Chart
|
|
|
|
data={ chartData }
|
|
|
|
title={ selectedChart.label }
|
|
|
|
interval={ currentInterval }
|
|
|
|
allowedIntervals={ allowedIntervals }
|
|
|
|
mode="time-comparison"
|
|
|
|
pointLabelFormat={ formats.pointLabelFormat }
|
|
|
|
tooltipTitle={ selectedChart.label }
|
|
|
|
xFormat={ formats.xFormat }
|
|
|
|
x2Format={ formats.x2Format }
|
|
|
|
dateParser={ '%Y-%m-%dT%H:%M:%S' }
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-07-05 03:14:40 +00:00
|
|
|
render() {
|
2018-10-11 08:30:51 +00:00
|
|
|
const { isRequesting, orders, path, query } = this.props;
|
|
|
|
|
2018-07-05 03:14:40 +00:00
|
|
|
return (
|
|
|
|
<Fragment>
|
2018-08-08 21:24:48 +00:00
|
|
|
<ReportFilters
|
|
|
|
query={ query }
|
|
|
|
path={ path }
|
|
|
|
filters={ filters }
|
|
|
|
advancedConfig={ advancedFilterConfig }
|
|
|
|
/>
|
2018-10-10 20:29:12 +00:00
|
|
|
{ this.renderChartSummaryNumbers() }
|
2018-10-11 17:07:59 +00:00
|
|
|
{ this.renderChart() }
|
2018-10-11 08:30:51 +00:00
|
|
|
<OrdersReportTable isRequesting={ isRequesting } orders={ orders } query={ query } />
|
2018-07-05 03:14:40 +00:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-11 17:07:59 +00:00
|
|
|
OrdersReport.propTypes = {
|
|
|
|
params: PropTypes.object.isRequired,
|
|
|
|
path: PropTypes.string.isRequired,
|
|
|
|
query: PropTypes.object.isRequired,
|
|
|
|
};
|
|
|
|
|
2018-07-05 03:14:40 +00:00
|
|
|
export default compose(
|
2018-10-10 20:29:12 +00:00
|
|
|
withSelect( ( select, props ) => {
|
2018-10-11 08:30:51 +00:00
|
|
|
const { getOrders } = select( 'wc-admin' );
|
|
|
|
const orders = getOrders();
|
|
|
|
const isRequesting = select( 'core/data' ).isResolving( 'wc-admin', 'getOrders' );
|
2018-10-10 20:29:12 +00:00
|
|
|
const { query } = props;
|
|
|
|
const interval = getIntervalForQuery( query );
|
|
|
|
const datesFromQuery = getCurrentDates( query );
|
|
|
|
const baseArgs = {
|
|
|
|
order: 'asc',
|
|
|
|
interval: interval,
|
|
|
|
per_page: MAX_PER_PAGE,
|
|
|
|
};
|
|
|
|
|
|
|
|
const primaryData = getReportChartData(
|
|
|
|
'orders',
|
|
|
|
{
|
|
|
|
...baseArgs,
|
|
|
|
after: datesFromQuery.primary.after,
|
|
|
|
before: datesFromQuery.primary.before,
|
|
|
|
},
|
|
|
|
select
|
|
|
|
);
|
|
|
|
|
|
|
|
const secondaryData = getReportChartData(
|
|
|
|
'orders',
|
|
|
|
{
|
|
|
|
...baseArgs,
|
|
|
|
after: datesFromQuery.secondary.after,
|
|
|
|
before: datesFromQuery.secondary.before,
|
|
|
|
},
|
|
|
|
select
|
|
|
|
);
|
2018-07-05 03:14:40 +00:00
|
|
|
return {
|
2018-10-11 15:43:25 +00:00
|
|
|
isRequesting,
|
|
|
|
orders,
|
2018-10-10 20:29:12 +00:00
|
|
|
primaryData,
|
|
|
|
secondaryData,
|
2018-07-05 03:14:40 +00:00
|
|
|
};
|
|
|
|
} )
|
|
|
|
)( OrdersReport );
|