Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Add new settings to Reviews by Product block (#787)
Browse files Browse the repository at this point in the history
* Add new settings to Reviews by Product block

* Remove helpText and add notices

* Use RangeControl for numeric settings

* Prevent fetching new reviews if all were already fetched

* Enable product image in reviews

* Remove unnecessary catch

* Refactor getReviews

* Move getReviews back to block's code

* Cleanup

* Fix wrong order in editor

* Hide 'Load More Reviews' if showLoadMore is false

* Move getReviews to utils.js

* Add @woocommerce/navigation to package.json

* Make notices non-dismissable
  • Loading branch information
Aljullu authored and mikejolley committed Aug 6, 2019
1 parent e5cf69e commit 654d1f8
Show file tree
Hide file tree
Showing 10 changed files with 354 additions and 189 deletions.
163 changes: 87 additions & 76 deletions assets/js/blocks/reviews-by-product/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import { Component } from 'react';
import PropTypes from 'prop-types';

/**
* Internal dependencies
*/
import { renderReview } from './utils';
import { getReviews, renderReview } from './utils';
import { withComponentId } from '../../hocs';

/**
Expand All @@ -19,56 +18,98 @@ class ReviewsByProduct extends Component {
constructor() {
super( ...arguments );
const { attributes } = this.props;
const { order, orderby } = this.getOrderArgs( attributes.orderby );

this.state = {
orderby: attributes.orderby,
order,
orderby,
reviews: [],
totalReviews: 0,
};

this.onChangeOrderby = this.onChangeOrderby.bind( this );
this.getReviews = this.getReviews.bind( this );
this.appendReviews = this.appendReviews.bind( this );
}

componentDidMount() {
this.getReviews();
this.loadFirstReviews();
}

componentDidUpdate( prevProps ) {
if (
prevProps.attributes.orderby !== this.props.attributes.orderby ||
prevProps.attributes.perPage !== this.props.attributes.perPage ||
prevProps.attributes.productId !== this.props.attributes.productId
) {
this.getReviews();
this.loadFirstReviews();
} else if ( prevProps.attributes.reviewsOnPageLoad !== this.props.attributes.reviewsOnPageLoad ) {
const isIncreasing = this.props.attributes.reviewsOnPageLoad > prevProps.attributes.reviewsOnPageLoad;
const allReviewsWereAlreadyLoaded = this.state.reviews.length >= this.state.totalReviews && this.state.totalReviews > 0;

if ( isIncreasing && allReviewsWereAlreadyLoaded ) {
return;
}
this.loadFirstReviews();
}
}

onChangeOrderby( event ) {
const { attributes } = this.props;
const { perPage } = attributes;
const { totalReviews } = this.state;
const newReviews = Math.min( totalReviews, perPage );
this.setState( {
reviews: Array( newReviews ).fill( {} ),
orderby: event.target.value,
getDefaultArgs() {
const { attributes, isPreview } = this.props;
const { order, orderby } = isPreview ? this.getOrderArgs( attributes.orderby ) : this.state;
const { productId, reviewsOnPageLoad } = attributes;

return {
order,
orderby,
per_page: reviewsOnPageLoad,
product_id: productId,
};
}

loadFirstReviews( argsAttr = {} ) {
const args = {
...this.getDefaultArgs(),
...argsAttr,
};

getReviews( args ).then( ( { reviews, totalReviews } ) => {
this.setState( { reviews, totalReviews } );
} ).catch( () => {
this.setState( { reviews: [] } );
} );
this.getReviews( event.target.value );
}

getOrderParams( orderValue ) {
const { attributes, isPreview } = this.props;
const selectedOrder = isPreview ? attributes.orderby :
orderValue || this.state.orderby || attributes.orderby;
appendReviews() {
const { attributes } = this.props;
const { reviewsOnLoadMore } = attributes;
const { reviews, totalReviews } = this.state;

const reviewsToLoad = Math.min( totalReviews - reviews.length, reviewsOnLoadMore );
this.setState( { reviews: reviews.concat( Array( reviewsToLoad ).fill( {} ) ) } );

const args = {
...this.getDefaultArgs(),
offset: reviews.length,
per_page: reviewsOnLoadMore,
};
getReviews( args ).then( ( { reviews: newReviews, totalReviews: newTotalReviews } ) => {
this.setState( {
reviews: reviews.filter( ( review ) => Object.keys( review ).length ).concat( newReviews ),
totalReviews: newTotalReviews,
} );
} ).catch( () => {
this.setState( { reviews: [] } );
} );
}

getOrderArgs( orderValue ) {
if ( wc_product_block_data.enableReviewRating ) {
if ( selectedOrder === 'lowest-rating' ) {
if ( orderValue === 'lowest-rating' ) {
return {
order: 'asc',
orderby: 'rating',
};
}
if ( selectedOrder === 'highest-rating' ) {
if ( orderValue === 'highest-rating' ) {
return {
order: 'desc',
orderby: 'rating',
Expand All @@ -82,70 +123,40 @@ class ReviewsByProduct extends Component {
};
}

getReviews( orderValue, page = 1 ) {
onChangeOrderby( event ) {
const { attributes } = this.props;
const { perPage, productId } = attributes;
const { reviews } = this.state;
const { order, orderby } = this.getOrderParams( orderValue );
const { reviewsOnPageLoad } = attributes;
const { totalReviews } = this.state;
const { order, orderby } = this.getOrderArgs( event.target.value );
const newReviews = Math.min( totalReviews, reviewsOnPageLoad );

if ( ! productId ) {
// We've removed the selected product, or no product is selected yet.
return;
}
this.setState( {
reviews: Array( newReviews ).fill( {} ),
order,
orderby,
} );

const args = {
...this.getDefaultArgs(),
order,
orderby,
page,
per_page: parseInt( perPage, 10 ) || 1,
product_id: productId,
per_page: reviewsOnPageLoad,
};
apiFetch( {
path: '/wc/blocks/products/reviews?' + Object.entries( args ).map( ( arg ) => arg.join( '=' ) ).join( '&' ),
parse: false,
} ).then( ( response ) => {
if ( response.json ) {
response.json().then( ( newReviews ) => {
const totalReviews = parseInt( response.headers.get( 'x-wp-total' ), 10 );
if ( page === 1 ) {
this.setState( { reviews: newReviews, totalReviews } );
} else {
this.setState( {
reviews: reviews.filter( ( review ) => Object.keys( review ).length ).concat( newReviews ),
totalReviews,
} );
}
} ).catch( () => {
this.setState( { reviews: [] } );
} );
} else {
this.setState( { reviews: [] } );
}
getReviews( args ).then( ( { reviews, totalReviews: newTotalReviews } ) => {
this.setState( { reviews, totalReviews: newTotalReviews } );
} ).catch( () => {
this.setState( { reviews: [] } );
} );
}

appendReviews() {
const { attributes } = this.props;
const { perPage } = attributes;
const { reviews, totalReviews } = this.state;

const newReviews = Math.min( totalReviews - reviews.length, perPage );
this.setState( { reviews: reviews.concat( Array( newReviews ).fill( {} ) ) } );

const page = Math.round( reviews.length / perPage ) + 1;
this.getReviews( null, page );
}

renderOrderBySelect() {
if ( ! wc_product_block_data.enableReviewRating ) {
return null;
}

const { attributes, componentId, isPreview } = this.props;
const { orderby } = this.state;

if ( ! attributes.showOrderby || ! wc_product_block_data.enableReviewRating ) {
return null;
}

const selectId = `wc-block-reviews-by-product__orderby__select-${ componentId }`;
const selectProps = isPreview ? {
readOnly: true,
Expand Down Expand Up @@ -181,12 +192,12 @@ class ReviewsByProduct extends Component {
renderReviewsList() {
const { attributes, componentId } = this.props;
const { reviews } = this.state;
const showAvatar = wc_product_block_data.showAvatars && attributes.showAvatar;
const showProductRating = wc_product_block_data.enableReviewRating && attributes.showProductRating;
const showReviewImage = ( wc_product_block_data.showAvatars || attributes.imageType === 'product' ) && attributes.showReviewImage;
const showReviewRating = wc_product_block_data.enableReviewRating && attributes.showReviewRating;
const attrs = {
...attributes,
showAvatar,
showProductRating,
showReviewImage,
showReviewRating,
};

return (
Expand All @@ -206,10 +217,10 @@ class ReviewsByProduct extends Component {
}

renderLoadMoreButton() {
const { componentId, isPreview } = this.props;
const { attributes, componentId, isPreview } = this.props;
const { reviews, totalReviews } = this.state;

if ( totalReviews <= reviews.length ) {
if ( ! attributes.showLoadMore || totalReviews <= reviews.length ) {
return null;
}

Expand Down
Loading

0 comments on commit 654d1f8

Please sign in to comment.