Merge getOrders and getItems (https://github.com/woocommerce/woocommerce-admin/pull/1438)
* Move labels loading logic into a lib * Move lib/labels into lib/async-requests * Implement tabular data filtering * Allow searching for string in report tables * Add table filtering to customers table * Get ids from searched string to populate the table * Fix autocompleter keyboard interactions * Improve props naming * Cleanup report customers data store * Prevent an edge case issue that might not update the selectedOptions when directily modifying the URL * Fix wrong selected autocompleter option * Add missing translation domain * Move searchItemsByString to wc-api/items/utils.js * Avoid autocompleter results appearing when there was no search string * Alphabetically order 'allowFreeTextSearch' prop * Reset selected table rows when directly modifying the URL * Simplify props destructuring * Undo customers data store change * Simplify isProductDetailsView expression * Improve order * Merge getOrders and getItems
This commit is contained in:
parent
d8ed3b6614
commit
666d8e4a3b
|
@ -18,7 +18,7 @@ export default class CategoryBreadcrumbs extends Component {
|
|||
let parent = category.parent;
|
||||
while ( parent ) {
|
||||
ancestors.unshift( parent );
|
||||
parent = categories[ parent ].parent;
|
||||
parent = categories.get( parent ).parent;
|
||||
}
|
||||
return ancestors;
|
||||
}
|
||||
|
@ -30,20 +30,20 @@ export default class CategoryBreadcrumbs extends Component {
|
|||
return;
|
||||
}
|
||||
if ( ancestorIds.length === 1 ) {
|
||||
return categories[ first( ancestorIds ) ].name + ' › ';
|
||||
return categories.get( first( ancestorIds ) ).name + ' › ';
|
||||
}
|
||||
if ( ancestorIds.length === 2 ) {
|
||||
return (
|
||||
categories[ first( ancestorIds ) ].name +
|
||||
categories.get( first( ancestorIds ) ).name +
|
||||
' › ' +
|
||||
categories[ last( ancestorIds ) ].name +
|
||||
categories.get( last( ancestorIds ) ).name +
|
||||
' › '
|
||||
);
|
||||
}
|
||||
return (
|
||||
categories[ first( ancestorIds ) ].name +
|
||||
categories.get( first( ancestorIds ) ).name +
|
||||
' … ' +
|
||||
categories[ last( ancestorIds ) ].name +
|
||||
categories.get( last( ancestorIds ) ).name +
|
||||
' › '
|
||||
);
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ class CategoriesReportTable extends Component {
|
|||
return map( categoryStats, categoryStat => {
|
||||
const { category_id, items_sold, net_revenue, products_count, orders_count } = categoryStat;
|
||||
const { categories, query } = this.props;
|
||||
const category = categories[ category_id ];
|
||||
const category = categories.get( category_id );
|
||||
const persistedQuery = getPersistedQuery( query );
|
||||
|
||||
return [
|
||||
|
|
|
@ -119,11 +119,11 @@ class ProductsReportTable extends Component {
|
|||
filter: 'single_product',
|
||||
products: product_id,
|
||||
} );
|
||||
const categories = this.props.categories;
|
||||
const { categories } = this.props;
|
||||
|
||||
const productCategories =
|
||||
( category_ids &&
|
||||
category_ids.map( category_id => categories[ category_id ] ).filter( Boolean ) ) ||
|
||||
category_ids.map( category_id => categories.get( category_id ) ).filter( Boolean ) ) ||
|
||||
[];
|
||||
|
||||
return [
|
||||
|
|
|
@ -92,6 +92,51 @@ function OrdersPanel( { orders, isRequesting, isError } ) {
|
|||
);
|
||||
};
|
||||
|
||||
const cards = [];
|
||||
orders.forEach( ( order, id ) => {
|
||||
// We want the billing address, but shipping can be used as a fallback.
|
||||
const address = { ...order.shipping, ...order.billing };
|
||||
const productsCount = order.line_items.reduce( ( total, line ) => total + line.quantity, 0 );
|
||||
|
||||
const total = order.total;
|
||||
const refundValue = getOrderRefundTotal( order );
|
||||
const remainingTotal = getCurrencyFormatDecimal( order.total ) + refundValue;
|
||||
|
||||
cards.push(
|
||||
<ActivityCard
|
||||
key={ id }
|
||||
className="woocommerce-order-activity-card"
|
||||
title={ orderCardTitle( order, address ) }
|
||||
date={ order.date_created }
|
||||
subtitle={
|
||||
<div>
|
||||
<span>
|
||||
{ sprintf(
|
||||
_n( '%d product', '%d products', productsCount, 'wc-admin' ),
|
||||
productsCount
|
||||
) }
|
||||
</span>
|
||||
{ refundValue ? (
|
||||
<span>
|
||||
<s>{ formatCurrency( total, order.currency_symbol ) }</s>{' '}
|
||||
{ formatCurrency( remainingTotal, order.currency_symbol ) }
|
||||
</span>
|
||||
) : (
|
||||
<span>{ formatCurrency( total, order.currency_symbol ) }</span>
|
||||
) }
|
||||
</div>
|
||||
}
|
||||
actions={
|
||||
<Button isDefault href={ getAdminLink( 'post.php?action=edit&post=' + order.id ) }>
|
||||
{ __( 'Begin fulfillment' ) }
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<OrderStatus order={ order } />
|
||||
</ActivityCard>
|
||||
);
|
||||
} );
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<ActivityHeader title={ __( 'Orders', 'wc-admin' ) } menu={ menu } />
|
||||
|
@ -105,55 +150,7 @@ function OrdersPanel( { orders, isRequesting, isError } ) {
|
|||
/>
|
||||
) : (
|
||||
<Fragment>
|
||||
{ orders.map( ( order, i ) => {
|
||||
// We want the billing address, but shipping can be used as a fallback.
|
||||
const address = { ...order.shipping, ...order.billing };
|
||||
const productsCount = order.line_items.reduce(
|
||||
( total, line ) => total + line.quantity,
|
||||
0
|
||||
);
|
||||
|
||||
const total = order.total;
|
||||
const refundValue = getOrderRefundTotal( order );
|
||||
const remainingTotal = getCurrencyFormatDecimal( order.total ) + refundValue;
|
||||
|
||||
return (
|
||||
<ActivityCard
|
||||
key={ i }
|
||||
className="woocommerce-order-activity-card"
|
||||
title={ orderCardTitle( order, address ) }
|
||||
date={ order.date_created }
|
||||
subtitle={
|
||||
<div>
|
||||
<span>
|
||||
{ sprintf(
|
||||
_n( '%d product', '%d products', productsCount, 'wc-admin' ),
|
||||
productsCount
|
||||
) }
|
||||
</span>
|
||||
{ refundValue ? (
|
||||
<span>
|
||||
<s>{ formatCurrency( total, order.currency_symbol ) }</s>{' '}
|
||||
{ formatCurrency( remainingTotal, order.currency_symbol ) }
|
||||
</span>
|
||||
) : (
|
||||
<span>{ formatCurrency( total, order.currency_symbol ) }</span>
|
||||
) }
|
||||
</div>
|
||||
}
|
||||
actions={
|
||||
<Button
|
||||
isDefault
|
||||
href={ getAdminLink( 'post.php?action=edit&post=' + order.id ) }
|
||||
>
|
||||
{ __( 'Begin fulfillment' ) }
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<OrderStatus order={ order } />
|
||||
</ActivityCard>
|
||||
);
|
||||
} ) }
|
||||
{ cards }
|
||||
<ActivityOutboundLink href={ 'edit.php?post_type=shop_order' }>
|
||||
{ __( 'Manage all orders' ) }
|
||||
</ActivityOutboundLink>
|
||||
|
@ -165,29 +162,29 @@ function OrdersPanel( { orders, isRequesting, isError } ) {
|
|||
}
|
||||
|
||||
OrdersPanel.propTypes = {
|
||||
orders: PropTypes.array.isRequired,
|
||||
orders: PropTypes.instanceOf( Map ).isRequired,
|
||||
isError: PropTypes.bool,
|
||||
isRequesting: PropTypes.bool,
|
||||
};
|
||||
|
||||
OrdersPanel.defaultProps = {
|
||||
orders: [],
|
||||
orders: new Map(),
|
||||
isError: false,
|
||||
isRequesting: false,
|
||||
};
|
||||
|
||||
export default compose(
|
||||
withSelect( select => {
|
||||
const { getOrders, getOrdersError, isGetOrdersRequesting } = select( 'wc-api' );
|
||||
const { getItems, getItemsError, isGetItemsRequesting } = select( 'wc-api' );
|
||||
const ordersQuery = {
|
||||
page: 1,
|
||||
per_page: QUERY_DEFAULTS.pageSize,
|
||||
status: 'processing',
|
||||
};
|
||||
|
||||
const orders = getOrders( ordersQuery );
|
||||
const isError = Boolean( getOrdersError( ordersQuery ) );
|
||||
const isRequesting = isGetOrdersRequesting( ordersQuery );
|
||||
const orders = getItems( 'orders', ordersQuery );
|
||||
const isError = Boolean( getItemsError( 'orders', ordersQuery ) );
|
||||
const isRequesting = isGetItemsRequesting( 'orders', ordersQuery );
|
||||
|
||||
return { orders, isError, isRequesting };
|
||||
} )
|
||||
|
|
|
@ -20,6 +20,7 @@ const typeEndpointMap = {
|
|||
'items-query-categories': 'products/categories',
|
||||
'items-query-customers': 'customers',
|
||||
'items-query-coupons': 'coupons',
|
||||
'items-query-orders': 'orders',
|
||||
'items-query-products': 'products',
|
||||
'items-query-taxes': 'taxes',
|
||||
};
|
||||
|
|
|
@ -18,13 +18,10 @@ const getItems = ( getResource, requireResource ) => (
|
|||
) => {
|
||||
const resourceName = getResourceName( `items-query-${ type }`, query );
|
||||
const ids = requireResource( requirement, resourceName ).data || [];
|
||||
const items = ids.reduce(
|
||||
( acc, id ) => ( {
|
||||
...acc,
|
||||
[ id ]: getResource( getResourceName( `items-query-${ type }-item`, id ) ).data || {},
|
||||
} ),
|
||||
{}
|
||||
);
|
||||
const items = new Map();
|
||||
ids.forEach( id => {
|
||||
items.set( id, getResource( getResourceName( `items-query-${ type }-item`, id ) ).data );
|
||||
} );
|
||||
return items;
|
||||
};
|
||||
|
||||
|
|
|
@ -16,15 +16,16 @@ export function searchItemsByString( select, endpoint, search ) {
|
|||
const { getItems } = select( 'wc-api' );
|
||||
const searchWords = search.split( ',' );
|
||||
|
||||
const items = searchWords.reduce( ( acc, searchWord ) => {
|
||||
return {
|
||||
...acc,
|
||||
...getItems( endpoint, {
|
||||
search: searchWord,
|
||||
per_page: 10,
|
||||
} ),
|
||||
};
|
||||
}, [] );
|
||||
const items = {};
|
||||
searchWords.forEach( searchWord => {
|
||||
const newItems = getItems( endpoint, {
|
||||
search: searchWord,
|
||||
per_page: 10,
|
||||
} );
|
||||
newItems.forEach( ( item, id ) => {
|
||||
items[ id ] = item;
|
||||
} );
|
||||
} );
|
||||
|
||||
return items;
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
/** @format */
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import operations from './operations';
|
||||
import selectors from './selectors';
|
||||
|
||||
export default {
|
||||
operations,
|
||||
selectors,
|
||||
};
|
|
@ -1,76 +0,0 @@
|
|||
/** @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 ) {
|
||||
return [ ...readOrders( resourceNames, fetch ), ...readOrderQueries( resourceNames, fetch ) ];
|
||||
}
|
||||
|
||||
function readOrderQueries( resourceNames, fetch ) {
|
||||
const filteredNames = resourceNames.filter( name => isResourcePrefix( name, 'order-query' ) );
|
||||
|
||||
return filteredNames.map( async resourceName => {
|
||||
const query = getResourceIdentifier( resourceName );
|
||||
const url = `${ NAMESPACE }/orders${ stringifyQuery( query ) }`;
|
||||
|
||||
try {
|
||||
const response = await fetch( {
|
||||
parse: false,
|
||||
path: url,
|
||||
} );
|
||||
|
||||
const orders = await response.json();
|
||||
const totalCount = parseInt( response.headers.get( 'x-wp-total' ) );
|
||||
const ids = orders.map( order => order.id );
|
||||
const orderResources = orders.reduce( ( resources, order ) => {
|
||||
resources[ getResourceName( 'order', order.id ) ] = { data: order };
|
||||
return resources;
|
||||
}, {} );
|
||||
|
||||
return {
|
||||
[ resourceName ]: {
|
||||
data: ids,
|
||||
totalCount,
|
||||
},
|
||||
...orderResources,
|
||||
};
|
||||
} catch ( error ) {
|
||||
return { [ resourceName ]: { error } };
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
function readOrders( resourceNames, fetch ) {
|
||||
const filteredNames = resourceNames.filter( name => isResourcePrefix( name, 'order' ) );
|
||||
return filteredNames.map( resourceName => readOrder( resourceName, fetch ) );
|
||||
}
|
||||
|
||||
function readOrder( resourceName, fetch ) {
|
||||
const id = getResourceIdentifier( resourceName );
|
||||
const url = `${ NAMESPACE }/orders/${ id }`;
|
||||
|
||||
return fetch( { path: url } )
|
||||
.then( order => {
|
||||
return { [ resourceName ]: { data: order } };
|
||||
} )
|
||||
.catch( error => {
|
||||
return { [ resourceName ]: { error } };
|
||||
} );
|
||||
}
|
||||
|
||||
export default {
|
||||
read,
|
||||
};
|
|
@ -1,53 +0,0 @@
|
|||
/** @format */
|
||||
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { isNil } from 'lodash';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { getResourceName } from '../utils';
|
||||
import { DEFAULT_REQUIREMENT } from '../constants';
|
||||
|
||||
const getOrders = ( getResource, requireResource ) => (
|
||||
query = {},
|
||||
requirement = DEFAULT_REQUIREMENT
|
||||
) => {
|
||||
const resourceName = getResourceName( 'order-query', query );
|
||||
const ids = requireResource( requirement, resourceName ).data || [];
|
||||
const orders = ids.map( id => getResource( getResourceName( 'order', id ) ).data || {} );
|
||||
return orders;
|
||||
};
|
||||
|
||||
const getOrdersError = getResource => ( query = {} ) => {
|
||||
const resourceName = getResourceName( 'order-query', query );
|
||||
return getResource( resourceName ).error;
|
||||
};
|
||||
|
||||
const getOrdersTotalCount = ( getResource, requireResource ) => (
|
||||
query = {},
|
||||
requirement = DEFAULT_REQUIREMENT
|
||||
) => {
|
||||
const resourceName = getResourceName( 'order-query', query );
|
||||
return requireResource( requirement, resourceName ).totalCount || 0;
|
||||
};
|
||||
|
||||
const isGetOrdersRequesting = getResource => ( query = {} ) => {
|
||||
const resourceName = getResourceName( 'order-query', query );
|
||||
const { lastRequested, lastReceived } = getResource( resourceName );
|
||||
|
||||
if ( isNil( lastRequested ) || isNil( lastReceived ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return lastRequested > lastReceived;
|
||||
};
|
||||
|
||||
export default {
|
||||
getOrders,
|
||||
getOrdersError,
|
||||
getOrdersTotalCount,
|
||||
isGetOrdersRequesting,
|
||||
};
|
|
@ -5,7 +5,6 @@
|
|||
*/
|
||||
import items from './items';
|
||||
import notes from './notes';
|
||||
import orders from './orders';
|
||||
import reportItems from './reports/items';
|
||||
import reportStats from './reports/stats';
|
||||
import reviews from './reviews';
|
||||
|
@ -21,7 +20,6 @@ function createWcApiSpec() {
|
|||
selectors: {
|
||||
...items.selectors,
|
||||
...notes.selectors,
|
||||
...orders.selectors,
|
||||
...reportItems.selectors,
|
||||
...reportStats.selectors,
|
||||
...reviews.selectors,
|
||||
|
@ -33,7 +31,6 @@ function createWcApiSpec() {
|
|||
return [
|
||||
...items.operations.read( resourceNames ),
|
||||
...notes.operations.read( resourceNames ),
|
||||
...orders.operations.read( resourceNames ),
|
||||
...reportItems.operations.read( resourceNames ),
|
||||
...reportStats.operations.read( resourceNames ),
|
||||
...reviews.operations.read( resourceNames ),
|
||||
|
|
Loading…
Reference in New Issue