Merge pull request woocommerce/woocommerce-admin#1075 from woocommerce/add/extend-customers-data-from-endpoint

Extend customers table data with data from WC endpoint
This commit is contained in:
Albert Juhé Lluveras 2018-12-18 09:30:03 +01:00 committed by GitHub
commit 9ef07a41b6
7 changed files with 188 additions and 12 deletions

View File

@ -21,6 +21,7 @@ import { onQueryChange } from '@woocommerce/navigation';
import ReportError from 'analytics/components/report-error';
import { getReportChartData, getReportTableData } from 'store/reports/utils';
import withSelect from 'wc-api/with-select';
import { extendTableData } from './utils';
const TABLE_FILTER = 'woocommerce_admin_report_table';
@ -115,6 +116,16 @@ ReportTable.propTypes = {
* The endpoint to use in API calls.
*/
endpoint: PropTypes.string,
/**
* Name of the methods available via `select( 'wc-api' )` that will be used to
* load more data for table items. If omitted, no call will be made and only
* the data returned by the reports endpoint will be used.
*/
extendItemsMethodNames: PropTypes.shape( {
getError: PropTypes.string,
isRequesting: PropTypes.string,
load: PropTypes.string,
} ),
/**
* A function that returns the headers object to build the table.
*/
@ -162,10 +173,11 @@ export default compose(
? getReportChartData( chartEndpoint, 'primary', query, select )
: {};
const queriedTableData = tableData || getReportTableData( endpoint, query, select, tableQuery );
const extendedTableData = extendTableData( select, props, queriedTableData );
const selectProps = {
primaryData,
tableData: queriedTableData,
tableData: extendedTableData,
};
if ( columnPrefsKey ) {

View File

@ -0,0 +1,54 @@
/** @format */
/**
* External dependencies
*/
import { first } from 'lodash';
export function extendTableData( select, props, queriedTableData ) {
const { extendItemsMethodNames, itemIdField } = props;
const itemsData = queriedTableData.items.data;
if (
! Array.isArray( itemsData ) ||
! itemsData.length ||
! extendItemsMethodNames ||
! itemIdField
) {
return queriedTableData;
}
const {
[ extendItemsMethodNames.getError ]: getErrorMethod,
[ extendItemsMethodNames.isRequesting ]: isRequestingMethod,
[ extendItemsMethodNames.load ]: loadMethod,
} = select( 'wc-api' );
const extendQuery = {
include: itemsData.map( item => item[ itemIdField ] ).join( ',' ),
per_page: itemsData.length,
};
const extendedItems = loadMethod( extendQuery );
const isExtendedItemsRequesting = isRequestingMethod ? isRequestingMethod( extendQuery ) : false;
const isExtendedItemsError = getErrorMethod ? getErrorMethod( extendQuery ) : false;
const extendedItemsData = itemsData.map( item => {
const extendedItemData = first(
extendedItems.filter( extendedItem => item.id === extendedItem.id )
);
return {
...item,
...extendedItemData,
};
} );
const isRequesting = queriedTableData.isRequesting || isExtendedItemsRequesting;
const isError = queriedTableData.isError || isExtendedItemsError;
return {
...queriedTableData,
isRequesting,
isError,
items: {
...queriedTableData.items,
data: extendedItemsData,
},
};
}

View File

@ -66,7 +66,7 @@ export default class CustomersReportTable extends Component {
{
label: __( 'AOV', 'wc-admin' ),
screenReaderLabel: __( 'Average Order Value', 'wc-admin' ),
key: 'average_order_value',
key: 'avg_order_value',
isNumeric: true,
},
{
@ -98,19 +98,20 @@ export default class CustomersReportTable extends Component {
return customers.map( customer => {
const {
average_order_value,
id,
city,
country,
avg_order_value,
billing,
date_last_active,
date_sign_up,
email,
name,
first_name,
id,
last_name,
orders_count,
postal_code,
username,
total_spend,
} = customer;
const { postcode, city, country } = billing || {};
const name = `${ first_name } ${ last_name }`;
const customerNameLink = (
<Link href={ 'user-edit.php?user_id=' + id } type="wp-admin">
@ -144,8 +145,8 @@ export default class CustomersReportTable extends Component {
value: getCurrencyFormatDecimal( total_spend ),
},
{
display: average_order_value,
value: getCurrencyFormatDecimal( average_order_value ),
display: formatCurrency( avg_order_value ),
value: getCurrencyFormatDecimal( avg_order_value ),
},
{
display: formatDate( formats.tableFormat, date_last_active ),
@ -160,8 +161,8 @@ export default class CustomersReportTable extends Component {
value: city,
},
{
display: postal_code,
value: postal_code,
display: postcode,
value: postcode,
},
];
} );
@ -174,6 +175,11 @@ export default class CustomersReportTable extends Component {
<ReportTable
compareBy="customers"
endpoint="customers"
extendItemsMethodNames={ {
load: 'getCustomers',
getError: 'getCustomersError',
isRequesting: 'isGetCustomersRequesting',
} }
getHeadersContent={ this.getHeadersContent }
getRowsContent={ this.getRowsContent }
itemIdField="id"

View File

@ -0,0 +1,11 @@
/** @format */
/**
* Internal dependencies
*/
import operations from './operations';
import selectors from './selectors';
export default {
operations,
selectors,
};

View File

@ -0,0 +1,47 @@
/** @format */
/**
* External dependencies
*/
import apiFetch from '@wordpress/api-fetch';
/**
* WooCommerce dependencies
*/
import { stringifyQuery } from '@woocommerce/navigation';
/**
* Internal dependencies
*/
import { isResourcePrefix, getResourceIdentifier, getResourceName } from '../utils';
import { NAMESPACE } from '../constants';
function read( resourceNames, fetch = apiFetch ) {
const filteredNames = resourceNames.filter( name => isResourcePrefix( name, 'customers-query' ) );
return filteredNames.map( async resourceName => {
const query = getResourceIdentifier( resourceName );
const url = `${ NAMESPACE }/customers${ stringifyQuery( query ) }`;
try {
const customers = await fetch( { path: url } );
const ids = customers.map( customer => customer.id );
const customerResources = customers.reduce( ( resources, customer ) => {
resources[ getResourceName( 'customer', customer.id ) ] = { data: customer };
return resources;
}, {} );
return {
[ resourceName ]: {
data: ids,
},
...customerResources,
};
} catch ( error ) {
return { [ resourceName ]: { error } };
}
} );
}
export default {
read,
};

View File

@ -0,0 +1,43 @@
/** @format */
/**
* External dependencies
*/
import { isNil } from 'lodash';
/**
* Internal dependencies
*/
import { getResourceName } from '../utils';
import { DEFAULT_REQUIREMENT } from '../constants';
const getCustomers = ( getResource, requireResource ) => (
query = {},
requirement = DEFAULT_REQUIREMENT
) => {
const resourceName = getResourceName( 'customers-query', query );
const ids = requireResource( requirement, resourceName ).data || [];
return ids.map( id => getResource( getResourceName( 'customer', id ) ).data || {} );
};
const getCustomersError = getResource => ( query = {} ) => {
const resourceName = getResourceName( 'customers-query', query );
return getResource( resourceName ).error;
};
const isGetCustomersRequesting = getResource => ( query = {} ) => {
const resourceName = getResourceName( 'customers-query', query );
const { lastRequested, lastReceived } = getResource( resourceName );
if ( isNil( lastRequested ) || isNil( lastReceived ) ) {
return true;
}
return lastRequested > lastReceived;
};
export default {
getCustomers,
getCustomersError,
isGetCustomersRequesting,
};

View File

@ -3,6 +3,7 @@
/**
* Internal dependencies
*/
import customers from './customers';
import notes from './notes';
import orders from './orders';
import reportItems from './reports/items';
@ -16,6 +17,7 @@ function createWcApiSpec() {
...user.mutations,
},
selectors: {
...customers.selectors,
...notes.selectors,
...orders.selectors,
...reportItems.selectors,
@ -26,6 +28,7 @@ function createWcApiSpec() {
operations: {
read( resourceNames ) {
return [
...customers.operations.read( resourceNames ),
...notes.operations.read( resourceNames ),
...orders.operations.read( resourceNames ),
...reportItems.operations.read( resourceNames ),