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:
parent
9038bdfdae
commit
41e5d00708
|
@ -92,7 +92,7 @@ class ActivityPanel extends Component {
|
||||||
|
|
||||||
// @todo Pull in dynamic unread status/count
|
// @todo Pull in dynamic unread status/count
|
||||||
getTabs() {
|
getTabs() {
|
||||||
const { unreadNotes, unreadOrders } = this.props;
|
const { unreadNotes, unreadOrders, unreadReviews } = this.props;
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: 'inbox',
|
name: 'inbox',
|
||||||
|
@ -119,7 +119,7 @@ class ActivityPanel extends Component {
|
||||||
name: 'reviews',
|
name: 'reviews',
|
||||||
title: __( 'Reviews', 'woocommerce-admin' ),
|
title: __( 'Reviews', 'woocommerce-admin' ),
|
||||||
icon: <Gridicon icon="star" />,
|
icon: <Gridicon icon="star" />,
|
||||||
unread: false,
|
unread: unreadReviews,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
].filter( Boolean );
|
].filter( Boolean );
|
||||||
|
@ -135,7 +135,8 @@ class ActivityPanel extends Component {
|
||||||
case 'stock':
|
case 'stock':
|
||||||
return <StockPanel />;
|
return <StockPanel />;
|
||||||
case 'reviews':
|
case 'reviews':
|
||||||
return <ReviewsPanel />;
|
const { numberOfReviews } = this.props;
|
||||||
|
return <ReviewsPanel numberOfReviews={ numberOfReviews } />;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -270,12 +271,16 @@ export default withSelect( select => {
|
||||||
getReportItemsError,
|
getReportItemsError,
|
||||||
isGetNotesRequesting,
|
isGetNotesRequesting,
|
||||||
isReportItemsRequesting,
|
isReportItemsRequesting,
|
||||||
|
getReviews,
|
||||||
|
getReviewsTotalCount,
|
||||||
|
getReviewsError,
|
||||||
|
isGetReviewsRequesting,
|
||||||
} = select( 'wc-api' );
|
} = select( 'wc-api' );
|
||||||
|
const userData = getCurrentUserData();
|
||||||
const orderStatuses = wcSettings.wcAdminSettings.woocommerce_actionable_order_statuses || [
|
const orderStatuses = wcSettings.wcAdminSettings.woocommerce_actionable_order_statuses || [
|
||||||
'processing',
|
'processing',
|
||||||
'on-hold',
|
'on-hold',
|
||||||
];
|
];
|
||||||
const userData = getCurrentUserData();
|
|
||||||
|
|
||||||
const notesQuery = {
|
const notesQuery = {
|
||||||
page: 1,
|
page: 1,
|
||||||
|
@ -290,10 +295,10 @@ export default withSelect( select => {
|
||||||
new Date( latestNote[ 0 ].date_created_gmt ).getTime() >
|
new Date( latestNote[ 0 ].date_created_gmt ).getTime() >
|
||||||
userData.activity_panel_inbox_last_read;
|
userData.activity_panel_inbox_last_read;
|
||||||
|
|
||||||
|
let unreadOrders = null;
|
||||||
if ( ! orderStatuses.length ) {
|
if ( ! orderStatuses.length ) {
|
||||||
return { unreadNotes, unreadOrders: false };
|
unreadOrders = false;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
const ordersQuery = {
|
const ordersQuery = {
|
||||||
page: 1,
|
page: 1,
|
||||||
per_page: 0,
|
per_page: 0,
|
||||||
|
@ -301,18 +306,41 @@ export default withSelect( select => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const totalOrders = getReportItems( 'orders', ordersQuery ).totalResults;
|
const totalOrders = getReportItems( 'orders', ordersQuery ).totalResults;
|
||||||
const isError = Boolean( getReportItemsError( 'orders', ordersQuery ) );
|
const isOrdersError = Boolean( getReportItemsError( 'orders', ordersQuery ) );
|
||||||
const isRequesting = isReportItemsRequesting( 'orders', ordersQuery );
|
const isOrdersRequesting = isReportItemsRequesting( 'orders', ordersQuery );
|
||||||
|
|
||||||
let unreadOrders = null;
|
if ( ! isOrdersError && ! isOrdersRequesting ) {
|
||||||
|
|
||||||
if ( ! isError && ! isRequesting ) {
|
|
||||||
if ( totalOrders > 0 ) {
|
if ( totalOrders > 0 ) {
|
||||||
unreadOrders = true;
|
unreadOrders = true;
|
||||||
} else {
|
} else {
|
||||||
unreadOrders = false;
|
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 ) );
|
} )( clickOutside( ActivityPanel ) );
|
||||||
|
|
|
@ -7,8 +7,10 @@ import { Component, Fragment } from '@wordpress/element';
|
||||||
import { compose } from '@wordpress/compose';
|
import { compose } from '@wordpress/compose';
|
||||||
import Gridicon from 'gridicons';
|
import Gridicon from 'gridicons';
|
||||||
import interpolateComponents from 'interpolate-components';
|
import interpolateComponents from 'interpolate-components';
|
||||||
|
import moment from 'moment';
|
||||||
import { noop, isNull } from 'lodash';
|
import { noop, isNull } from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { withDispatch } from '@wordpress/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WooCommerce dependencies
|
* WooCommerce dependencies
|
||||||
|
@ -33,7 +35,21 @@ import sanitizeHTML from 'lib/sanitize-html';
|
||||||
import withSelect from 'wc-api/with-select';
|
import withSelect from 'wc-api/with-select';
|
||||||
|
|
||||||
class ReviewsPanel extends Component {
|
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 =
|
const product =
|
||||||
( review && review._embedded && review._embedded.up && review._embedded.up[ 0 ] ) || null;
|
( review && review._embedded && review._embedded.up && review._embedded.up[ 0 ] ) || null;
|
||||||
|
|
||||||
|
@ -109,15 +125,40 @@ class ReviewsPanel extends Component {
|
||||||
key={ review.id }
|
key={ review.id }
|
||||||
title={ title }
|
title={ title }
|
||||||
subtitle={ subtitle }
|
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 }
|
icon={ icon }
|
||||||
actions={ cardActions() }
|
actions={ cardActions() }
|
||||||
|
unread={
|
||||||
|
! lastRead ||
|
||||||
|
! review.date_created_gmt ||
|
||||||
|
new Date( review.date_created_gmt + 'Z' ).getTime() > lastRead
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<span dangerouslySetInnerHTML={ sanitizeHTML( review.review ) } />
|
<span dangerouslySetInnerHTML={ sanitizeHTML( review.review ) } />
|
||||||
</ActivityCard>
|
</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() {
|
render() {
|
||||||
const { isError, isRequesting, reviews } = this.props;
|
const { isError, isRequesting, reviews } = this.props;
|
||||||
|
|
||||||
|
@ -148,14 +189,11 @@ class ReviewsPanel extends Component {
|
||||||
<ActivityHeader title={ __( 'Reviews', 'woocommerce-admin' ) } />
|
<ActivityHeader title={ __( 'Reviews', 'woocommerce-admin' ) } />
|
||||||
<Section>
|
<Section>
|
||||||
{ isRequesting ? (
|
{ isRequesting ? (
|
||||||
<ActivityCardPlaceholder
|
this.renderPlaceholders()
|
||||||
className="woocommerce-review-activity-card"
|
|
||||||
hasAction
|
|
||||||
hasDate
|
|
||||||
lines={ 2 }
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<Fragment>{ reviews.map( this.renderReview ) }</Fragment>
|
<Fragment>
|
||||||
|
{ reviews.map( review => this.renderReview( review, this.props ) ) }
|
||||||
|
</Fragment>
|
||||||
) }
|
) }
|
||||||
</Section>
|
</Section>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
@ -167,17 +205,26 @@ ReviewsPanel.propTypes = {
|
||||||
reviews: PropTypes.array.isRequired,
|
reviews: PropTypes.array.isRequired,
|
||||||
isError: PropTypes.bool,
|
isError: PropTypes.bool,
|
||||||
isRequesting: PropTypes.bool,
|
isRequesting: PropTypes.bool,
|
||||||
|
numberOfReviews: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
ReviewsPanel.defaultProps = {
|
ReviewsPanel.defaultProps = {
|
||||||
reviews: [],
|
reviews: [],
|
||||||
isError: false,
|
isError: false,
|
||||||
isRequesting: false,
|
isRequesting: false,
|
||||||
|
numberOfReviews: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
withSelect( select => {
|
withSelect( ( select, props ) => {
|
||||||
const { getReviews, getReviewsError, isGetReviewsRequesting } = select( 'wc-api' );
|
const { numberOfReviews } = props;
|
||||||
|
const { getCurrentUserData, getReviews, getReviewsError, isGetReviewsRequesting } = select(
|
||||||
|
'wc-api'
|
||||||
|
);
|
||||||
|
if ( numberOfReviews === 0 ) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const userData = getCurrentUserData();
|
||||||
const reviewsQuery = {
|
const reviewsQuery = {
|
||||||
page: 1,
|
page: 1,
|
||||||
per_page: QUERY_DEFAULTS.pageSize,
|
per_page: QUERY_DEFAULTS.pageSize,
|
||||||
|
@ -188,6 +235,13 @@ export default compose(
|
||||||
const isError = Boolean( getReviewsError( reviewsQuery ) );
|
const isError = Boolean( getReviewsError( reviewsQuery ) );
|
||||||
const isRequesting = isGetReviewsRequesting( 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 );
|
)( ReviewsPanel );
|
||||||
|
|
|
@ -47,6 +47,7 @@ function updateCurrentUserData( resourceNames, data, fetch ) {
|
||||||
'dashboard_leaderboards',
|
'dashboard_leaderboards',
|
||||||
'dashboard_leaderboard_rows',
|
'dashboard_leaderboard_rows',
|
||||||
'activity_panel_inbox_last_read',
|
'activity_panel_inbox_last_read',
|
||||||
|
'activity_panel_reviews_last_read',
|
||||||
];
|
];
|
||||||
|
|
||||||
if ( resourceNames.includes( resourceName ) ) {
|
if ( resourceNames.includes( resourceName ) ) {
|
||||||
|
|
|
@ -450,6 +450,7 @@ function wc_admin_get_user_data_fields() {
|
||||||
'dashboard_leaderboards',
|
'dashboard_leaderboards',
|
||||||
'dashboard_leaderboard_rows',
|
'dashboard_leaderboard_rows',
|
||||||
'activity_panel_inbox_last_read',
|
'activity_panel_inbox_last_read',
|
||||||
|
'activity_panel_reviews_last_read',
|
||||||
);
|
);
|
||||||
|
|
||||||
return apply_filters( 'wc_admin_get_user_data_fields', $user_data_fields );
|
return apply_filters( 'wc_admin_get_user_data_fields', $user_data_fields );
|
||||||
|
|
Loading…
Reference in New Issue