Activity Panel: set reviews unread indicator based on real data (https://github.com/woocommerce/woocommerce-admin/pull/1860)

* Activity Panel: set reviews unread indicator based on real data

* Unify date comparisons to GMT

* Add numberOfReviews propType

* Verify date_created_gmt exists before using it
This commit is contained in:
Albert Juhé Lluveras 2019-03-21 12:35:46 +01:00 committed by GitHub
parent 9038bdfdae
commit 41e5d00708
4 changed files with 120 additions and 36 deletions

View File

@ -92,7 +92,7 @@ class ActivityPanel extends Component {
// @todo Pull in dynamic unread status/count
getTabs() {
const { unreadNotes, unreadOrders } = this.props;
const { unreadNotes, unreadOrders, unreadReviews } = this.props;
return [
{
name: 'inbox',
@ -119,7 +119,7 @@ class ActivityPanel extends Component {
name: 'reviews',
title: __( 'Reviews', 'woocommerce-admin' ),
icon: <Gridicon icon="star" />,
unread: false,
unread: unreadReviews,
}
: null,
].filter( Boolean );
@ -135,7 +135,8 @@ class ActivityPanel extends Component {
case 'stock':
return <StockPanel />;
case 'reviews':
return <ReviewsPanel />;
const { numberOfReviews } = this.props;
return <ReviewsPanel numberOfReviews={ numberOfReviews } />;
default:
return null;
}
@ -270,12 +271,16 @@ export default withSelect( select => {
getReportItemsError,
isGetNotesRequesting,
isReportItemsRequesting,
getReviews,
getReviewsTotalCount,
getReviewsError,
isGetReviewsRequesting,
} = select( 'wc-api' );
const userData = getCurrentUserData();
const orderStatuses = wcSettings.wcAdminSettings.woocommerce_actionable_order_statuses || [
'processing',
'on-hold',
];
const userData = getCurrentUserData();
const notesQuery = {
page: 1,
@ -290,29 +295,52 @@ export default withSelect( select => {
new Date( latestNote[ 0 ].date_created_gmt ).getTime() >
userData.activity_panel_inbox_last_read;
if ( ! orderStatuses.length ) {
return { unreadNotes, unreadOrders: false };
}
const ordersQuery = {
page: 1,
per_page: 0,
status_is: orderStatuses,
};
const totalOrders = getReportItems( 'orders', ordersQuery ).totalResults;
const isError = Boolean( getReportItemsError( 'orders', ordersQuery ) );
const isRequesting = isReportItemsRequesting( 'orders', ordersQuery );
let unreadOrders = null;
if ( ! orderStatuses.length ) {
unreadOrders = false;
} else {
const ordersQuery = {
page: 1,
per_page: 0,
status_is: orderStatuses,
};
if ( ! isError && ! isRequesting ) {
if ( totalOrders > 0 ) {
unreadOrders = true;
} else {
unreadOrders = false;
const totalOrders = getReportItems( 'orders', ordersQuery ).totalResults;
const isOrdersError = Boolean( getReportItemsError( 'orders', ordersQuery ) );
const isOrdersRequesting = isReportItemsRequesting( 'orders', ordersQuery );
if ( ! isOrdersError && ! isOrdersRequesting ) {
if ( totalOrders > 0 ) {
unreadOrders = true;
} else {
unreadOrders = false;
}
}
}
return { unreadNotes, unreadOrders };
let numberOfReviews = null;
let unreadReviews = false;
if ( 'yes' === wcSettings.reviewsEnabled ) {
const reviewsQuery = {
order: 'desc',
orderby: 'date_gmt',
page: 1,
per_page: 1,
};
const reviews = getReviews( reviewsQuery );
const totalReviews = getReviewsTotalCount( reviewsQuery );
const isReviewsError = Boolean( getReviewsError( reviewsQuery ) );
const isReviewsRequesting = isGetReviewsRequesting( reviewsQuery );
if ( ! isReviewsError && ! isReviewsRequesting ) {
numberOfReviews = totalReviews;
unreadReviews =
reviews.length &&
reviews[ 0 ].date_created_gmt &&
new Date( reviews[ 0 ].date_created_gmt + 'Z' ).getTime() >
userData.activity_panel_reviews_last_read;
}
}
return { unreadNotes, unreadOrders, unreadReviews, numberOfReviews };
} )( clickOutside( ActivityPanel ) );

View File

@ -7,8 +7,10 @@ import { Component, Fragment } from '@wordpress/element';
import { compose } from '@wordpress/compose';
import Gridicon from 'gridicons';
import interpolateComponents from 'interpolate-components';
import moment from 'moment';
import { noop, isNull } from 'lodash';
import PropTypes from 'prop-types';
import { withDispatch } from '@wordpress/data';
/**
* WooCommerce dependencies
@ -33,7 +35,21 @@ import sanitizeHTML from 'lib/sanitize-html';
import withSelect from 'wc-api/with-select';
class ReviewsPanel extends Component {
renderReview( review ) {
constructor() {
super();
this.mountTime = new Date().getTime();
}
componentWillUnmount() {
const userDataFields = {
[ 'activity_panel_reviews_last_read' ]: this.mountTime,
};
this.props.updateCurrentUserData( userDataFields );
}
renderReview( review, props ) {
const { lastRead } = props;
const product =
( review && review._embedded && review._embedded.up && review._embedded.up[ 0 ] ) || null;
@ -109,15 +125,40 @@ class ReviewsPanel extends Component {
key={ review.id }
title={ title }
subtitle={ subtitle }
date={ review.date_created }
date={
review.date_created_gmt
? moment( review.date_created_gmt + 'Z' ).format( 'YYYY-MM-DDTH:mm:ss' )
: null
}
icon={ icon }
actions={ cardActions() }
unread={
! lastRead ||
! review.date_created_gmt ||
new Date( review.date_created_gmt + 'Z' ).getTime() > lastRead
}
>
<span dangerouslySetInnerHTML={ sanitizeHTML( review.review ) } />
</ActivityCard>
);
}
renderPlaceholders() {
const { numberOfReviews } = this.props;
const placeholders = new Array( numberOfReviews );
return placeholders
.fill( 0 )
.map( ( p, i ) => (
<ActivityCardPlaceholder
className="woocommerce-review-activity-card"
key={ i }
hasAction
hasDate
lines={ 2 }
/>
) );
}
render() {
const { isError, isRequesting, reviews } = this.props;
@ -148,14 +189,11 @@ class ReviewsPanel extends Component {
<ActivityHeader title={ __( 'Reviews', 'woocommerce-admin' ) } />
<Section>
{ isRequesting ? (
<ActivityCardPlaceholder
className="woocommerce-review-activity-card"
hasAction
hasDate
lines={ 2 }
/>
this.renderPlaceholders()
) : (
<Fragment>{ reviews.map( this.renderReview ) }</Fragment>
<Fragment>
{ reviews.map( review => this.renderReview( review, this.props ) ) }
</Fragment>
) }
</Section>
</Fragment>
@ -167,17 +205,26 @@ ReviewsPanel.propTypes = {
reviews: PropTypes.array.isRequired,
isError: PropTypes.bool,
isRequesting: PropTypes.bool,
numberOfReviews: PropTypes.number,
};
ReviewsPanel.defaultProps = {
reviews: [],
isError: false,
isRequesting: false,
numberOfReviews: 0,
};
export default compose(
withSelect( select => {
const { getReviews, getReviewsError, isGetReviewsRequesting } = select( 'wc-api' );
withSelect( ( select, props ) => {
const { numberOfReviews } = props;
const { getCurrentUserData, getReviews, getReviewsError, isGetReviewsRequesting } = select(
'wc-api'
);
if ( numberOfReviews === 0 ) {
return {};
}
const userData = getCurrentUserData();
const reviewsQuery = {
page: 1,
per_page: QUERY_DEFAULTS.pageSize,
@ -188,6 +235,13 @@ export default compose(
const isError = Boolean( getReviewsError( reviewsQuery ) );
const isRequesting = isGetReviewsRequesting( reviewsQuery );
return { reviews, isError, isRequesting };
return { reviews, isError, isRequesting, lastRead: userData.activity_panel_reviews_last_read };
} ),
withDispatch( dispatch => {
const { updateCurrentUserData } = dispatch( 'wc-api' );
return {
updateCurrentUserData,
};
} )
)( ReviewsPanel );

View File

@ -47,6 +47,7 @@ function updateCurrentUserData( resourceNames, data, fetch ) {
'dashboard_leaderboards',
'dashboard_leaderboard_rows',
'activity_panel_inbox_last_read',
'activity_panel_reviews_last_read',
];
if ( resourceNames.includes( resourceName ) ) {

View File

@ -450,6 +450,7 @@ function wc_admin_get_user_data_fields() {
'dashboard_leaderboards',
'dashboard_leaderboard_rows',
'activity_panel_inbox_last_read',
'activity_panel_reviews_last_read',
);
return apply_filters( 'wc_admin_get_user_data_fields', $user_data_fields );