/** * External dependencies */ import { __, sprintf } from '@wordpress/i18n'; import classnames from 'classnames'; import { Component, Fragment } from '@wordpress/element'; import { withSelect } from '@wordpress/data'; import { Button } from '@wordpress/components'; import CheckmarkIcon from 'gridicons/dist/checkmark'; import TimeIcon from 'gridicons/dist/time'; import interpolateComponents from 'interpolate-components'; import { get, isNull } from 'lodash'; import PropTypes from 'prop-types'; import { EmptyContent, Gravatar, Link, ProductImage, ReviewRating, Section, } from '@woocommerce/components'; import { getAdminLink } from '@woocommerce/wc-admin-settings'; import { REVIEWS_STORE_NAME, QUERY_DEFAULTS } from '@woocommerce/data'; import { recordEvent } from '@woocommerce/tracks'; /** * Internal dependencies */ import { ActivityCard, ActivityCardPlaceholder } from '../activity-card'; import ActivityHeader from '../activity-header'; import sanitizeHTML from '../../../lib/sanitize-html'; class ReviewsPanel extends Component { constructor() { super(); this.mountTime = new Date().getTime(); } recordReviewEvent( eventName ) { recordEvent( `activity_panel_reviews_${ eventName }`, {} ); } renderReview( review, props ) { const { lastRead } = props; const product = ( review && review._embedded && review._embedded.up && review._embedded.up[ 0 ] ) || null; if ( isNull( product ) ) { return null; } const title = interpolateComponents( { mixedString: sprintf( __( '{{productLink}}%s{{/productLink}} reviewed by {{authorLink}}%s{{/authorLink}}', 'woocommerce-admin' ), product.name, review.reviewer ), components: { productLink: ( this.recordReviewEvent( 'product' ) } type="external" /> ), authorLink: ( this.recordReviewEvent( 'customer' ) } type="external" /> ), }, } ); const subtitle = ( { review.verified && ( { __( 'Verified customer', 'woocommerce-admin' ) } ) } ); const productImage = get( product, [ 'images', 0 ] ) || get( product, [ 'image' ] ); const productImageClasses = classnames( 'woocommerce-review-activity-card__image-overlay__product', { 'is-placeholder': ! productImage || ! productImage.src, } ); const icon = (
); const manageReviewEvent = { date: review.date_created_gmt, status: review.status, }; const cardActions = ( ); return ( lastRead } > ); } renderEmptyMessage() { const { lastApprovedReviewTime } = this.props; const title = __( 'You have no reviews to moderate', 'woocommerce-admin' ); let buttonUrl = ''; let buttonTarget = ''; let buttonText = ''; let content = ''; let eventName = 'learn_more'; if ( lastApprovedReviewTime ) { const now = new Date(); const DAY = 24 * 60 * 60 * 1000; if ( ( now.getTime() - lastApprovedReviewTime ) / DAY > 30 ) { buttonUrl = 'https://woocommerce.com/posts/reviews-woocommerce-best-practices/'; buttonTarget = '_blank'; buttonText = __( 'Learn more', 'woocommerce-admin' ); content = (

{ __( "We noticed that it's been a while since your products had any reviews.", 'woocommerce-admin' ) }

{ __( 'Take some time to learn about best practices for collecting and using your reviews.', 'woocommerce-admin' ) }

); } else { buttonUrl = getAdminLink( 'edit-comments.php?comment_type=review' ); buttonText = __( 'View all Reviews', 'woocommerce-admin' ); content = (

{ __( /* eslint-disable max-len */ "Awesome, you've moderated all of your product reviews. How about responding to some of those negative reviews?", 'woocommerce-admin' /* eslint-enable */ ) }

); eventName = 'view_reviews'; } } else { buttonUrl = 'https://woocommerce.com/posts/reviews-woocommerce-best-practices/'; buttonTarget = '_blank'; buttonText = __( 'Learn more', 'woocommerce-admin' ); content = (

{ __( "Your customers haven't started reviewing your products.", 'woocommerce-admin' ) }

{ __( 'Take some time to learn about best practices for collecting and using your reviews.', 'woocommerce-admin' ) }

); } return ( } actions={ } > { content } ); } render() { const { isError, isRequesting, reviews } = this.props; if ( isError ) { const title = __( 'There was an error getting your reviews. Please try again.', 'woocommerce-admin' ); const actionLabel = __( 'Reload', 'woocommerce-admin' ); const actionCallback = () => { window.location.reload(); }; return ( ); } const title = isRequesting || reviews.length ? __( 'Reviews', 'woocommerce-admin' ) : __( 'No reviews to moderate', 'woocommerce-admin' ); return (
{ isRequesting ? ( ) : ( { reviews.length ? reviews.map( ( review ) => this.renderReview( review, this.props ) ) : this.renderEmptyMessage() } ) }
); } } ReviewsPanel.propTypes = { reviews: PropTypes.array.isRequired, isError: PropTypes.bool, isRequesting: PropTypes.bool, }; ReviewsPanel.defaultProps = { reviews: [], isError: false, isRequesting: false, }; export default withSelect( ( select, props ) => { const { hasUnapprovedReviews } = props; const { getReviews, getReviewsError, isResolving } = select( REVIEWS_STORE_NAME ); let reviews = []; let isError = false; let isRequesting = false; let lastApprovedReviewTime = null; if ( hasUnapprovedReviews ) { const reviewsQuery = { page: 1, per_page: QUERY_DEFAULTS.pageSize, status: 'hold', _embed: 1, }; reviews = getReviews( reviewsQuery ); isError = Boolean( getReviewsError( reviewsQuery ) ); isRequesting = isResolving( 'getReviews', [ reviewsQuery ] ); } else { const approvedReviewsQuery = { page: 1, per_page: 1, status: 'approved', _embed: 1, }; const approvedReviews = getReviews( approvedReviewsQuery ); if ( approvedReviews.length ) { const lastApprovedReview = approvedReviews[ 0 ]; if ( lastApprovedReview.date_created_gmt ) { const creationDate = new Date( lastApprovedReview.date_created_gmt ); lastApprovedReviewTime = creationDate.getTime(); } } isError = Boolean( getReviewsError( approvedReviewsQuery ) ); isRequesting = isResolving( 'getReviews', [ approvedReviewsQuery ] ); } return { reviews, isError, isRequesting, lastApprovedReviewTime, }; } )( ReviewsPanel );