2018-06-14 20:15:11 +00:00
|
|
|
/** @format */
|
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { __ } from '@wordpress/i18n';
|
|
|
|
import { Component, Fragment } from '@wordpress/element';
|
2018-08-01 16:00:45 +00:00
|
|
|
import { format as formatDate } from '@wordpress/date';
|
|
|
|
import { map, noop } from 'lodash';
|
2018-06-14 20:15:11 +00:00
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import DatePicker from 'components/date-picker';
|
2018-08-01 16:00:45 +00:00
|
|
|
import { formatCurrency, getCurrencyFormatDecimal } from 'lib/currency';
|
2018-06-26 14:59:35 +00:00
|
|
|
import { getAdminLink, updateQueryString } from 'lib/nav-utils';
|
2018-06-26 21:02:08 +00:00
|
|
|
import { getReportData } from 'lib/swagger';
|
2018-06-28 13:52:45 +00:00
|
|
|
import Header from 'layout/header';
|
2018-06-14 20:15:11 +00:00
|
|
|
import { SummaryList, SummaryNumber } from 'components/summary';
|
2018-08-01 16:00:45 +00:00
|
|
|
import { TableCard } from 'components/table';
|
|
|
|
|
|
|
|
// Mock data until we fetch from an API
|
|
|
|
import rawData from './mock-data';
|
2018-06-20 15:09:37 +00:00
|
|
|
|
2018-06-14 20:15:11 +00:00
|
|
|
class RevenueReport extends Component {
|
2018-06-26 14:59:35 +00:00
|
|
|
constructor() {
|
|
|
|
super();
|
2018-08-01 16:00:45 +00:00
|
|
|
this.onQueryChange = this.onQueryChange.bind( this );
|
2018-06-26 21:02:08 +00:00
|
|
|
|
|
|
|
// TODO remove this when we implement real endpoints
|
|
|
|
this.state = { stats: {} };
|
2018-06-26 14:59:35 +00:00
|
|
|
}
|
|
|
|
|
2018-06-26 21:02:08 +00:00
|
|
|
componentDidMount() {
|
|
|
|
// Swagger doesn't support returning different data based on query args
|
|
|
|
// this is more or less to show how we will manipulate data calls based on props
|
|
|
|
const statsQueryArgs = {
|
|
|
|
interval: 'week',
|
|
|
|
after: '2018-04-22',
|
|
|
|
before: '2018-05-06',
|
|
|
|
};
|
|
|
|
|
|
|
|
getReportData( 'revenue/stats', statsQueryArgs ).then( response => {
|
|
|
|
if ( ! response.ok ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-01 16:00:45 +00:00
|
|
|
response.json().then( () => {
|
|
|
|
// Ignore data, just use our fake data once we have a response
|
|
|
|
this.setState( { stats: rawData } );
|
2018-06-26 21:02:08 +00:00
|
|
|
} );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2018-08-01 16:00:45 +00:00
|
|
|
/**
|
|
|
|
* This function returns an event handler for the given `param`
|
2018-08-06 17:01:41 +00:00
|
|
|
* @todo Move handling of this to a library?
|
2018-08-01 16:00:45 +00:00
|
|
|
* @param {string} param The parameter in the querystring which should be updated (ex `page`, `per_page`)
|
|
|
|
* @return {function} A callback which will update `param` to the passed value when called.
|
|
|
|
*/
|
|
|
|
onQueryChange( param ) {
|
2018-08-06 17:01:41 +00:00
|
|
|
switch ( param ) {
|
|
|
|
case 'sort':
|
|
|
|
return ( key, dir ) => updateQueryString( { orderby: key, order: dir } );
|
|
|
|
default:
|
|
|
|
return value => updateQueryString( { [ param ]: value } );
|
|
|
|
}
|
2018-08-01 16:00:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
getHeadersContent() {
|
|
|
|
return [
|
2018-08-06 17:01:41 +00:00
|
|
|
{
|
|
|
|
label: __( 'Date', 'wc-admin' ),
|
|
|
|
key: 'date_start',
|
|
|
|
required: true,
|
|
|
|
defaultSort: true,
|
|
|
|
isSortable: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Orders', 'wc-admin' ),
|
|
|
|
key: 'orders_count',
|
|
|
|
required: false,
|
|
|
|
isSortable: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Gross Revenue', 'wc-admin' ),
|
|
|
|
key: 'gross_revenue',
|
|
|
|
required: true,
|
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Refunds', 'wc-admin' ),
|
|
|
|
key: 'refunds',
|
|
|
|
required: false,
|
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Coupons', 'wc-admin' ),
|
|
|
|
key: 'coupons',
|
|
|
|
required: false,
|
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Taxes', 'wc-admin' ),
|
|
|
|
key: 'taxes',
|
|
|
|
required: false,
|
|
|
|
isSortable: false, // For example
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Shipping', 'wc-admin' ),
|
|
|
|
key: 'shipping',
|
|
|
|
required: false,
|
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'Net Revenue', 'wc-admin' ),
|
|
|
|
key: 'net_revenue',
|
|
|
|
required: false,
|
|
|
|
isSortable: true,
|
2018-08-13 15:25:32 +00:00
|
|
|
isNumeric: true,
|
2018-08-06 17:01:41 +00:00
|
|
|
},
|
2018-08-01 16:00:45 +00:00
|
|
|
];
|
2018-06-26 14:59:35 +00:00
|
|
|
}
|
|
|
|
|
2018-08-01 16:00:45 +00:00
|
|
|
getRowsContent( data = [] ) {
|
2018-06-26 22:17:05 +00:00
|
|
|
return map( data, row => {
|
|
|
|
const {
|
|
|
|
coupons,
|
|
|
|
gross_revenue,
|
|
|
|
net_revenue,
|
|
|
|
orders_count,
|
|
|
|
refunds,
|
|
|
|
shipping,
|
|
|
|
taxes,
|
|
|
|
} = row.subtotals;
|
|
|
|
|
2018-07-13 19:36:41 +00:00
|
|
|
// @TODO How to create this per-report? Can use `w`, `year`, `m` to build time-specific order links
|
|
|
|
// we need to know which kind of report this is, and parse the `label` to get this row's date
|
2018-06-20 15:09:37 +00:00
|
|
|
const orderLink = (
|
|
|
|
<a href={ getAdminLink( '/edit.php?post_type=shop_order&w=4&year=2018' ) }>
|
2018-06-26 22:17:05 +00:00
|
|
|
{ orders_count }
|
2018-06-20 15:09:37 +00:00
|
|
|
</a>
|
|
|
|
);
|
|
|
|
return [
|
2018-08-01 16:00:45 +00:00
|
|
|
{
|
|
|
|
display: formatDate( 'm/d/Y', row.date_start ),
|
|
|
|
value: row.date_start,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: orderLink,
|
|
|
|
value: Number( orders_count ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( gross_revenue ),
|
|
|
|
value: getCurrencyFormatDecimal( gross_revenue ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( refunds ),
|
|
|
|
value: getCurrencyFormatDecimal( refunds ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( coupons ),
|
|
|
|
value: getCurrencyFormatDecimal( coupons ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( taxes ),
|
|
|
|
value: getCurrencyFormatDecimal( taxes ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( shipping ),
|
|
|
|
value: getCurrencyFormatDecimal( shipping ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
display: formatCurrency( net_revenue ),
|
|
|
|
value: getCurrencyFormatDecimal( net_revenue ),
|
|
|
|
},
|
2018-06-20 15:09:37 +00:00
|
|
|
];
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2018-08-01 16:00:45 +00:00
|
|
|
getSummaryContent( data = {} ) {
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
label: __( 'gross revenue', 'wc-admin' ),
|
|
|
|
value: formatCurrency( data.gross_revenue ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'refunds', 'wc-admin' ),
|
|
|
|
value: formatCurrency( data.refunds ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'coupons', 'wc-admin' ),
|
|
|
|
value: formatCurrency( data.coupons ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'taxes', 'wc-admin' ),
|
|
|
|
value: formatCurrency( data.taxes ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'shipping', 'wc-admin' ),
|
|
|
|
value: formatCurrency( data.shipping ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: __( 'net revenue', 'wc-admin' ),
|
|
|
|
value: formatCurrency( data.net_revenue ),
|
|
|
|
},
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2018-06-14 20:15:11 +00:00
|
|
|
render() {
|
|
|
|
const { path, query } = this.props;
|
2018-08-01 16:00:45 +00:00
|
|
|
const { totals = {}, intervals = [] } = this.state.stats;
|
|
|
|
const summary = this.getSummaryContent( totals ) || [];
|
|
|
|
const rows = this.getRowsContent( intervals ) || [];
|
|
|
|
const headers = this.getHeadersContent();
|
2018-06-20 15:09:37 +00:00
|
|
|
|
2018-06-14 20:15:11 +00:00
|
|
|
return (
|
|
|
|
<Fragment>
|
|
|
|
<Header
|
|
|
|
sections={ [
|
2018-07-10 12:48:06 +00:00
|
|
|
[ '/analytics', __( 'Analytics', 'wc-admin' ) ],
|
|
|
|
__( 'Revenue', 'wc-admin' ),
|
2018-06-14 20:15:11 +00:00
|
|
|
] }
|
|
|
|
/>
|
2018-07-22 23:43:21 +00:00
|
|
|
<DatePicker query={ query } path={ path } key={ JSON.stringify( query ) } />
|
2018-06-14 20:15:11 +00:00
|
|
|
|
|
|
|
<SummaryList>
|
|
|
|
<SummaryNumber
|
2018-08-01 16:00:45 +00:00
|
|
|
value={ formatCurrency( totals.gross_revenue ) }
|
2018-07-10 12:48:06 +00:00
|
|
|
label={ __( 'Gross Revenue', 'wc-admin' ) }
|
2018-06-14 20:15:11 +00:00
|
|
|
delta={ 29 }
|
|
|
|
/>
|
|
|
|
<SummaryNumber
|
2018-08-01 16:00:45 +00:00
|
|
|
value={ formatCurrency( totals.refunds ) }
|
2018-07-10 12:48:06 +00:00
|
|
|
label={ __( 'Refunds', 'wc-admin' ) }
|
2018-06-14 20:15:11 +00:00
|
|
|
delta={ -10 }
|
|
|
|
selected
|
|
|
|
/>
|
2018-06-26 21:02:08 +00:00
|
|
|
<SummaryNumber
|
2018-08-01 16:00:45 +00:00
|
|
|
value={ formatCurrency( totals.coupons ) }
|
2018-07-10 12:48:06 +00:00
|
|
|
label={ __( 'Coupons', 'wc-admin' ) }
|
2018-06-26 21:02:08 +00:00
|
|
|
delta={ 15 }
|
|
|
|
/>
|
2018-06-26 21:39:29 +00:00
|
|
|
<SummaryNumber
|
2018-08-01 16:00:45 +00:00
|
|
|
value={ formatCurrency( totals.taxes ) }
|
2018-07-10 12:48:06 +00:00
|
|
|
label={ __( 'Taxes', 'wc-admin' ) }
|
2018-06-26 21:39:29 +00:00
|
|
|
/>
|
2018-06-14 20:15:11 +00:00
|
|
|
</SummaryList>
|
2018-06-26 14:59:35 +00:00
|
|
|
|
2018-08-01 16:00:45 +00:00
|
|
|
<TableCard
|
|
|
|
title={ __( 'Revenue Last Week', 'wc-admin' ) }
|
|
|
|
rows={ rows }
|
|
|
|
headers={ headers }
|
|
|
|
onClickDownload={ noop }
|
|
|
|
onQueryChange={ this.onQueryChange }
|
|
|
|
query={ query }
|
|
|
|
summary={ summary }
|
2018-06-26 14:59:35 +00:00
|
|
|
/>
|
2018-06-14 20:15:11 +00:00
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RevenueReport.propTypes = {
|
|
|
|
params: PropTypes.object.isRequired,
|
|
|
|
path: PropTypes.string.isRequired,
|
|
|
|
query: PropTypes.object.isRequired,
|
|
|
|
};
|
|
|
|
|
|
|
|
export default RevenueReport;
|