woocommerce/plugins/woocommerce-blocks/assets/js/blocks/reviews-by-product/frontend-block.js

170 lines
4.4 KiB
JavaScript

/**
* External dependencies
*/
import { __, _n, sprintf } from '@wordpress/i18n';
import { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { speak } from '@wordpress/a11y';
/**
* Internal dependencies
*/
import { getOrderArgs, getReviews } from './utils';
import LoadMoreButton from '../../base/components/load-more-button';
import ReviewOrderSelect from '../../base/components/review-order-select';
import ReviewList from '../../base/components/review-list';
import withComponentId from '../../base/hocs/with-component-id';
const enableReviewRating = !! ( typeof wc_product_block_data !== 'undefined' && wc_product_block_data.enableReviewRating );
/**
* Block rendered in the frontend.
*/
class FrontendBlock extends Component {
constructor() {
super( ...arguments );
const { attributes } = this.props;
this.state = {
orderby: attributes.orderby,
reviews: [],
totalReviews: 0,
};
this.onChangeOrderby = this.onChangeOrderby.bind( this );
this.appendReviews = this.appendReviews.bind( this );
}
componentDidMount() {
this.loadFirstReviews();
}
getDefaultArgs() {
const { attributes } = this.props;
const { order, orderby } = getOrderArgs( this.state.orderby );
const { productId, reviewsOnPageLoad } = attributes;
return {
order,
orderby,
per_page: reviewsOnPageLoad,
product_id: productId,
};
}
loadFirstReviews() {
getReviews( this.getDefaultArgs() ).then( ( { reviews, totalReviews } ) => {
this.setState( { reviews, totalReviews } );
} ).catch( () => {
this.setState( { reviews: [] } );
speak(
__( 'There was an error loading the reviews.', 'woo-gutenberg-products-block' )
);
} );
}
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,
} );
speak(
sprintf(
_n(
'%d review loaded.',
'%d reviews loaded.',
'woo-gutenberg-products-block'
),
newReviews.length
)
);
} ).catch( () => {
this.setState( { reviews: [] } );
speak(
__( 'There was an error loading the reviews.', 'woo-gutenberg-products-block' )
);
} );
}
onChangeOrderby( event ) {
const { attributes } = this.props;
const { reviewsOnPageLoad } = attributes;
const { totalReviews } = this.state;
const { order, orderby } = getOrderArgs( event.target.value );
const newReviews = Math.min( totalReviews, reviewsOnPageLoad );
this.setState( {
reviews: Array( newReviews ).fill( {} ),
orderby: event.target.value,
} );
const args = {
...this.getDefaultArgs(),
order,
orderby,
per_page: reviewsOnPageLoad,
};
getReviews( args ).then( ( { reviews, totalReviews: newTotalReviews } ) => {
this.setState( { reviews, totalReviews: newTotalReviews } );
speak( __( 'Reviews order updated.', 'woo-gutenberg-products-block' ) );
} ).catch( () => {
this.setState( { reviews: [] } );
speak(
__( 'There was an error loading the reviews.', 'woo-gutenberg-products-block' )
);
} );
}
render() {
const { attributes, componentId } = this.props;
const { orderby, reviews, totalReviews } = this.state;
return (
<Fragment>
{ ( attributes.showOrderby && enableReviewRating ) && (
<ReviewOrderSelect
componentId={ componentId }
onChange={ this.onChangeOrderby }
value={ orderby }
/>
) }
<ReviewList
attributes={ attributes }
componentId={ componentId }
reviews={ reviews }
/>
{ ( attributes.showLoadMore && totalReviews > reviews.length ) && (
<LoadMoreButton
onClick={ this.appendReviews }
screenReaderLabel={ __( 'Load more reviews', 'woo-gutenberg-products-block' ) }
/>
) }
</Fragment>
);
}
}
FrontendBlock.propTypes = {
/**
* The attributes for this block.
*/
attributes: PropTypes.object.isRequired,
// from withComponentId
componentId: PropTypes.number,
};
export default withComponentId( FrontendBlock );