/** * External dependencies */ import { __, _n, sprintf } from '@wordpress/i18n'; import { Component, Fragment } from '@wordpress/element'; import { withSelect } from '@wordpress/data'; import PropTypes from 'prop-types'; import interpolateComponents from 'interpolate-components'; import { keyBy, map, merge } from 'lodash'; import { EmptyContent, Flag, H, Link, OrderStatus, Section, } from '@woocommerce/components'; import { getNewPath } from '@woocommerce/navigation'; import { getAdminLink, getSetting } from '@woocommerce/wc-admin-settings'; import { REPORTS_STORE_NAME, ITEMS_STORE_NAME } from '@woocommerce/data'; import { recordEvent } from '@woocommerce/tracks'; /** * Internal dependencies */ import { ActivityCard, ActivityCardPlaceholder, } from '../../../header/activity-panel/activity-card'; import { DEFAULT_ACTIONABLE_STATUSES } from '../../../analytics/settings/config'; import { CurrencyContext } from '../../../lib/currency-context'; import './style.scss'; class OrdersPanel extends Component { recordOrderEvent( eventName ) { recordEvent( `activity_panel_orders_${ eventName }`, {} ); } renderEmptyCard() { return ( 🎉 { __( 'You’ve fulfilled all your orders', 'woocommerce-admin' ) } this.recordOrderEvent( 'orders_manage' ) } className="woocommerce-layout__activity-panel-outbound-link woocommerce-layout__activity-panel-empty" type="wp-admin" > { __( 'Manage all orders', 'woocommerce-admin' ) } ); } renderOrders() { const { orders } = this.props; const Currency = this.context; if ( orders.length === 0 ) { return this.renderEmptyCard(); } const getCustomerString = ( order ) => { const extendedInfo = order.extended_info || {}; const { first_name: firstName, last_name: lastName } = extendedInfo.customer || {}; if ( ! firstName && ! lastName ) { return ''; } const name = [ firstName, lastName ].join( ' ' ); return `{{customerLink}}${ name }{{/customerLink}}`; }; const orderCardTitle = ( order ) => { const { extended_info: extendedInfo, order_id: orderId, order_number: orderNumber, } = order; const { customer } = extendedInfo || {}; const customerUrl = customer.customer_id ? getNewPath( {}, '/analytics/customers', { filter: 'single_customer', customers: customer.customer_id, } ) : null; return ( { interpolateComponents( { mixedString: sprintf( __( '{{orderLink}}Order #%(orderNumber)s{{/orderLink}} %(customerString)s', 'woocommerce-admin' ), { orderNumber, customerString: getCustomerString( order ), } ), components: { orderLink: ( this.recordOrderEvent( 'order_number' ) } type="wp-admin" /> ), destinationFlag: customer.country ? ( ) : null, customerLink: customerUrl ? ( this.recordOrderEvent( 'customer_name' ) } type="wc-admin" /> ) : ( ), }, } ) } ); }; const cards = []; orders.forEach( ( order ) => { const { date_created_gmt: dateCreatedGmt, extended_info: extendedInfo, order_id: orderId, total_sales: totalSales, } = order; const productsCount = extendedInfo && extendedInfo.products ? extendedInfo.products.length : 0; const total = totalSales; cards.push( { this.recordOrderEvent( 'orders_begin_fulfillment' ); if ( ! target.href ) { window.location.href = getAdminLink( `post.php?action=edit&post=${ orderId }` ); } } } subtitle={
{ sprintf( _n( '%d product', '%d products', productsCount, 'woocommerce-admin' ), productsCount ) } { Currency.formatAmount( total ) }
} >
); } ); return ( { cards } this.recordOrderEvent( 'orders_manage' ) } type="wp-admin" > { __( 'Manage all orders', 'woocommerce-admin' ) } ); } render() { const { isRequesting, isError, orderStatuses } = this.props; if ( isError ) { if ( ! orderStatuses.length ) { return ( ); } const title = __( 'There was an error getting your orders. Please try again.', 'woocommerce-admin' ); const actionLabel = __( 'Reload', 'woocommerce-admin' ); const actionCallback = () => { // @todo Add tracking for how often an error is displayed, and the reload action is clicked. window.location.reload(); }; return ( ); } return (
{ isRequesting ? ( ) : ( this.renderOrders() ) }
); } } OrdersPanel.propTypes = { orders: PropTypes.array.isRequired, isError: PropTypes.bool, isRequesting: PropTypes.bool, }; OrdersPanel.defaultProps = { orders: [], isError: false, isRequesting: false, }; OrdersPanel.contextType = CurrencyContext; export default withSelect( ( select, props ) => { const { countUnreadOrders } = props; const { getItems, getItemsError } = select( ITEMS_STORE_NAME ); const { getReportItems, getReportItemsError, isResolving } = select( REPORTS_STORE_NAME ); if ( countUnreadOrders === null ) { return { isRequesting: true }; } if ( countUnreadOrders === 0 ) { return { isRequesting: false }; } // Query the core Orders endpoint for the most up-to-date statuses. const actionableOrdersQuery = { page: 1, per_page: 5, status: DEFAULT_ACTIONABLE_STATUSES, _fields: [ 'id', 'date_created_gmt', 'status' ], }; // eslint-disable-next-line @wordpress/no-unused-vars-before-return const actionableOrders = Array.from( getItems( 'orders', actionableOrdersQuery ).values() ); const isRequestingActionable = isResolving( 'getItems', [ 'orders', actionableOrdersQuery, ] ); if ( isRequestingActionable ) { return { isError: Boolean( getItemsError( 'orders', actionableOrdersQuery ) ), isRequesting: isRequestingActionable, orderStatuses: DEFAULT_ACTIONABLE_STATUSES, }; } // Retrieve the Order stats data from our reporting table. const ordersQuery = { page: 1, per_page: 5, extended_info: true, order_includes: map( actionableOrders, 'id' ), _fields: [ 'order_id', 'order_number', 'status', 'data_created_gmt', 'total_sales', 'extended_info.customer', 'extended_info.products', ], }; const reportOrders = getReportItems( 'orders', ordersQuery ).data; const isError = Boolean( getReportItemsError( 'orders', ordersQuery ) ); const isRequesting = isResolving( 'getReportItems', [ 'orders', ordersQuery, ] ); let orders = []; if ( reportOrders && reportOrders.length ) { // Merge the core endpoint data with our reporting table. const actionableOrdersById = keyBy( actionableOrders, 'id' ); orders = reportOrders.map( ( order ) => merge( {}, order, actionableOrdersById[ order.order_id ] || {} ) ); } return { orders, isError, isRequesting, orderStatuses: DEFAULT_ACTIONABLE_STATUSES, }; } )( OrdersPanel );