2018-10-16 16:07:43 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { __ } from '@wordpress/i18n';
|
|
|
|
import { Component } from '@wordpress/element';
|
|
|
|
import { compose } from '@wordpress/compose';
|
2020-09-03 21:45:40 +00:00
|
|
|
import { withSelect } from '@wordpress/data';
|
2018-10-16 16:07:43 +00:00
|
|
|
import PropTypes from 'prop-types';
|
2018-11-05 21:02:04 +00:00
|
|
|
import { getNewPath } from '@woocommerce/navigation';
|
2020-02-14 02:23:21 +00:00
|
|
|
import {
|
|
|
|
SummaryList,
|
|
|
|
SummaryListPlaceholder,
|
|
|
|
SummaryNumber,
|
|
|
|
} from '@woocommerce/components';
|
2020-04-02 21:54:38 +00:00
|
|
|
import { calculateDelta, formatValue } from '@woocommerce/number';
|
2020-08-14 11:19:04 +00:00
|
|
|
import { getSummaryNumbers, SETTINGS_STORE_NAME } from '@woocommerce/data';
|
2020-08-17 21:53:13 +00:00
|
|
|
import { getDateParamsFromQuery } from '@woocommerce/date';
|
2020-08-20 04:59:52 +00:00
|
|
|
import { recordEvent } from '@woocommerce/tracks';
|
2018-10-30 18:57:48 +00:00
|
|
|
|
2018-10-16 16:07:43 +00:00
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
2020-08-13 02:05:22 +00:00
|
|
|
import ReportError from '../report-error';
|
|
|
|
import { CurrencyContext } from '../../../lib/currency-context';
|
2018-10-18 20:45:36 +00:00
|
|
|
|
2018-12-22 11:46:10 +00:00
|
|
|
/**
|
|
|
|
* Component to render summary numbers in reports.
|
|
|
|
*/
|
2018-12-07 21:13:02 +00:00
|
|
|
export class ReportSummary extends Component {
|
2019-02-07 09:57:47 +00:00
|
|
|
formatVal( val, type ) {
|
2020-06-17 23:33:40 +00:00
|
|
|
const { formatAmount, getCurrencyConfig } = this.context;
|
2020-02-14 02:23:21 +00:00
|
|
|
return type === 'currency'
|
2020-06-17 23:33:40 +00:00
|
|
|
? formatAmount( val )
|
|
|
|
: formatValue( getCurrencyConfig(), type, val );
|
2019-02-07 09:57:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
getValues( key, type ) {
|
|
|
|
const { emptySearchResults, summaryData } = this.props;
|
|
|
|
const { totals } = summaryData;
|
|
|
|
|
2020-10-16 18:47:29 +00:00
|
|
|
const primaryTotal = totals.primary ? totals.primary[ key ] : 0;
|
|
|
|
const secondaryTotal = totals.secondary ? totals.secondary[ key ] : 0;
|
|
|
|
|
|
|
|
const primaryValue = emptySearchResults ? 0 : primaryTotal;
|
|
|
|
const secondaryValue = emptySearchResults ? 0 : secondaryTotal;
|
2019-02-07 09:57:47 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
delta: calculateDelta( primaryValue, secondaryValue ),
|
|
|
|
prevValue: this.formatVal( secondaryValue, type ),
|
|
|
|
value: this.formatVal( primaryValue, type ),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-10-16 16:07:43 +00:00
|
|
|
render() {
|
2019-07-02 10:05:37 +00:00
|
|
|
const {
|
|
|
|
charts,
|
|
|
|
query,
|
|
|
|
selectedChart,
|
|
|
|
summaryData,
|
|
|
|
endpoint,
|
|
|
|
report,
|
2020-03-25 03:20:17 +00:00
|
|
|
defaultDateRange,
|
2019-07-02 10:05:37 +00:00
|
|
|
} = this.props;
|
2020-07-27 23:45:36 +00:00
|
|
|
const { isError, isRequesting } = summaryData;
|
2018-10-17 18:56:50 +00:00
|
|
|
|
2018-12-07 21:13:02 +00:00
|
|
|
if ( isError ) {
|
2021-06-01 10:07:35 +00:00
|
|
|
return <ReportError />;
|
2018-10-17 18:56:50 +00:00
|
|
|
}
|
|
|
|
|
2020-07-27 23:45:36 +00:00
|
|
|
if ( isRequesting ) {
|
2018-10-16 16:07:43 +00:00
|
|
|
return <SummaryListPlaceholder numberOfItems={ charts.length } />;
|
|
|
|
}
|
|
|
|
|
2020-03-25 03:20:17 +00:00
|
|
|
const { compare } = getDateParamsFromQuery( query, defaultDateRange );
|
2018-10-16 16:07:43 +00:00
|
|
|
|
2019-01-17 03:28:41 +00:00
|
|
|
const renderSummaryNumbers = ( { onToggle } ) =>
|
2020-02-14 02:23:21 +00:00
|
|
|
charts.map( ( chart ) => {
|
2021-07-28 00:50:01 +00:00
|
|
|
const {
|
|
|
|
key,
|
|
|
|
order,
|
|
|
|
orderby,
|
|
|
|
label,
|
|
|
|
type,
|
|
|
|
isReverseTrend,
|
|
|
|
} = chart;
|
2019-02-15 10:54:41 +00:00
|
|
|
const newPath = { chart: key };
|
|
|
|
if ( orderby ) {
|
|
|
|
newPath.orderby = orderby;
|
|
|
|
}
|
|
|
|
if ( order ) {
|
|
|
|
newPath.order = order;
|
|
|
|
}
|
|
|
|
const href = getNewPath( newPath );
|
2019-01-17 03:28:41 +00:00
|
|
|
const isSelected = selectedChart.key === key;
|
2019-02-07 09:57:47 +00:00
|
|
|
const { delta, prevValue, value } = this.getValues( key, type );
|
2018-10-16 16:07:43 +00:00
|
|
|
|
2019-01-17 03:28:41 +00:00
|
|
|
return (
|
|
|
|
<SummaryNumber
|
|
|
|
key={ key }
|
|
|
|
delta={ delta }
|
|
|
|
href={ href }
|
|
|
|
label={ label }
|
2021-07-28 00:50:01 +00:00
|
|
|
reverseTrend={ isReverseTrend }
|
2019-01-17 03:28:41 +00:00
|
|
|
prevLabel={
|
2020-02-14 02:23:21 +00:00
|
|
|
compare === 'previous_period'
|
2021-08-13 18:54:24 +00:00
|
|
|
? __( 'Previous period:', 'woocommerce-admin' )
|
|
|
|
: __( 'Previous year:', 'woocommerce-admin' )
|
2019-01-17 03:28:41 +00:00
|
|
|
}
|
|
|
|
prevValue={ prevValue }
|
|
|
|
selected={ isSelected }
|
|
|
|
value={ value }
|
2019-07-02 10:05:37 +00:00
|
|
|
onLinkClickCallback={ () => {
|
|
|
|
// Wider than a certain breakpoint, there is no dropdown so avoid calling onToggle.
|
|
|
|
if ( onToggle ) {
|
|
|
|
onToggle();
|
|
|
|
}
|
2020-02-14 02:23:21 +00:00
|
|
|
recordEvent( 'analytics_chart_tab_click', {
|
|
|
|
report: report || endpoint,
|
|
|
|
key,
|
|
|
|
} );
|
2019-07-02 10:05:37 +00:00
|
|
|
} }
|
2019-01-17 03:28:41 +00:00
|
|
|
/>
|
|
|
|
);
|
|
|
|
} );
|
2018-10-16 16:07:43 +00:00
|
|
|
|
2019-01-17 03:28:41 +00:00
|
|
|
return <SummaryList>{ renderSummaryNumbers }</SummaryList>;
|
2018-10-16 16:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ReportSummary.propTypes = {
|
2018-12-22 11:46:10 +00:00
|
|
|
/**
|
|
|
|
* Properties of all the charts available for that report.
|
|
|
|
*/
|
2018-10-16 16:07:43 +00:00
|
|
|
charts: PropTypes.array.isRequired,
|
2018-12-22 11:46:10 +00:00
|
|
|
/**
|
|
|
|
* The endpoint to use in API calls to populate the Summary Numbers.
|
|
|
|
* For example, if `taxes` is provided, data will be fetched from the report
|
2019-11-12 18:15:55 +00:00
|
|
|
* `taxes` endpoint (ie: `/wc-analytics/reports/taxes/stats`). If the provided endpoint
|
2018-12-22 11:46:10 +00:00
|
|
|
* doesn't exist, an error will be shown to the user with `ReportError`.
|
|
|
|
*/
|
2018-10-16 16:07:43 +00:00
|
|
|
endpoint: PropTypes.string.isRequired,
|
2019-02-27 16:28:18 +00:00
|
|
|
/**
|
2019-03-07 02:57:22 +00:00
|
|
|
* Allows specifying properties different from the `endpoint` that will be used
|
2019-02-27 16:28:18 +00:00
|
|
|
* to limit the items when there is an active search.
|
|
|
|
*/
|
2019-03-07 02:57:22 +00:00
|
|
|
limitProperties: PropTypes.array,
|
2018-12-22 11:46:10 +00:00
|
|
|
/**
|
|
|
|
* The query string represented in object form.
|
|
|
|
*/
|
2018-10-16 16:07:43 +00:00
|
|
|
query: PropTypes.object.isRequired,
|
2018-12-22 11:46:10 +00:00
|
|
|
/**
|
|
|
|
* Properties of the selected chart.
|
|
|
|
*/
|
|
|
|
selectedChart: PropTypes.shape( {
|
|
|
|
/**
|
|
|
|
* Key of the selected chart.
|
|
|
|
*/
|
|
|
|
key: PropTypes.string.isRequired,
|
2019-05-20 01:57:06 +00:00
|
|
|
/**
|
|
|
|
* Chart label.
|
|
|
|
*/
|
|
|
|
label: PropTypes.string.isRequired,
|
|
|
|
/**
|
|
|
|
* Order query argument.
|
|
|
|
*/
|
|
|
|
order: PropTypes.oneOf( [ 'asc', 'desc' ] ),
|
|
|
|
/**
|
|
|
|
* Order by query argument.
|
|
|
|
*/
|
|
|
|
orderby: PropTypes.string,
|
|
|
|
/**
|
|
|
|
* Number type for formatting.
|
|
|
|
*/
|
|
|
|
type: PropTypes.oneOf( [ 'average', 'number', 'currency' ] ).isRequired,
|
2018-12-22 11:46:10 +00:00
|
|
|
} ).isRequired,
|
2019-02-07 09:57:47 +00:00
|
|
|
/**
|
|
|
|
* Data to display in the SummaryNumbers.
|
|
|
|
*/
|
|
|
|
summaryData: PropTypes.object,
|
2019-07-02 10:05:37 +00:00
|
|
|
/**
|
|
|
|
* Report name, if different than the endpoint.
|
|
|
|
*/
|
|
|
|
report: PropTypes.string,
|
2019-02-07 09:57:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
ReportSummary.defaultProps = {
|
|
|
|
summaryData: {
|
|
|
|
totals: {
|
|
|
|
primary: {},
|
|
|
|
secondary: {},
|
|
|
|
},
|
|
|
|
isError: false,
|
|
|
|
},
|
2018-10-16 16:07:43 +00:00
|
|
|
};
|
|
|
|
|
2020-04-02 21:54:38 +00:00
|
|
|
ReportSummary.contextType = CurrencyContext;
|
|
|
|
|
2018-10-16 16:07:43 +00:00
|
|
|
export default compose(
|
|
|
|
withSelect( ( select, props ) => {
|
2020-02-14 02:23:21 +00:00
|
|
|
const {
|
2020-03-31 15:08:40 +00:00
|
|
|
charts,
|
2020-02-14 02:23:21 +00:00
|
|
|
endpoint,
|
|
|
|
limitProperties,
|
|
|
|
query,
|
|
|
|
filters,
|
|
|
|
advancedFilters,
|
|
|
|
} = props;
|
2019-03-07 02:57:22 +00:00
|
|
|
const limitBy = limitProperties || [ endpoint ];
|
2019-02-27 14:43:34 +00:00
|
|
|
|
2020-02-14 02:23:21 +00:00
|
|
|
const hasLimitByParam = limitBy.some(
|
|
|
|
( item ) => query[ item ] && query[ item ].length
|
|
|
|
);
|
2019-03-07 02:57:22 +00:00
|
|
|
|
|
|
|
if ( query.search && ! hasLimitByParam ) {
|
2019-02-07 09:57:47 +00:00
|
|
|
return {
|
|
|
|
emptySearchResults: true,
|
|
|
|
};
|
|
|
|
}
|
2019-02-27 14:43:34 +00:00
|
|
|
|
2020-06-17 23:33:40 +00:00
|
|
|
const fields = charts && charts.map( ( chart ) => chart.key );
|
2020-03-31 15:08:40 +00:00
|
|
|
|
2020-03-25 03:20:17 +00:00
|
|
|
const { woocommerce_default_date_range: defaultDateRange } = select(
|
|
|
|
SETTINGS_STORE_NAME
|
|
|
|
).getSetting( 'wc_admin', 'wcAdminSettings' );
|
|
|
|
|
2019-03-21 03:25:05 +00:00
|
|
|
const summaryData = getSummaryNumbers( {
|
|
|
|
endpoint,
|
|
|
|
query,
|
|
|
|
select,
|
|
|
|
limitBy,
|
|
|
|
filters,
|
|
|
|
advancedFilters,
|
2020-03-25 03:20:17 +00:00
|
|
|
defaultDateRange,
|
2020-03-31 15:08:40 +00:00
|
|
|
fields,
|
2019-03-21 03:25:05 +00:00
|
|
|
} );
|
2018-10-16 16:07:43 +00:00
|
|
|
|
|
|
|
return {
|
2018-12-07 21:13:02 +00:00
|
|
|
summaryData,
|
2020-03-25 03:20:17 +00:00
|
|
|
defaultDateRange,
|
2018-10-16 16:07:43 +00:00
|
|
|
};
|
|
|
|
} )
|
|
|
|
)( ReportSummary );
|