2019-08-15 14:55:57 +00:00
/ * *
* External dependencies
* /
import { _ _ , _n , sprintf } from '@wordpress/i18n' ;
import {
BlockControls ,
InspectorControls ,
} from '@wordpress/editor' ;
import {
Button ,
Disabled ,
Notice ,
PanelBody ,
Placeholder ,
RangeControl ,
SelectControl ,
Spinner ,
ToggleControl ,
Toolbar ,
withSpokenMessages ,
} from '@wordpress/components' ;
import classNames from 'classnames' ;
import { SearchListItem } from '@woocommerce/components' ;
import { Fragment , RawHTML } from '@wordpress/element' ;
import { compose } from '@wordpress/compose' ;
import { escapeHTML } from '@wordpress/escape-html' ;
import PropTypes from 'prop-types' ;
import { getAdminLink } from '@woocommerce/navigation' ;
/ * *
* Internal dependencies
* /
import ApiErrorPlaceholder from '../../components/api-error-placeholder' ;
import EditorBlock from './editor-block.js' ;
import ProductControl from '../../components/product-control' ;
import ToggleButtonControl from '../../components/toggle-button-control' ;
import { IconReviewsByProduct } from '../../components/icons' ;
import { withProduct } from '../../hocs' ;
2019-08-17 09:14:11 +00:00
import { ENABLE _REVIEW _RATING , SHOW _AVATARS } from '../../constants' ;
2019-08-15 14:55:57 +00:00
/ * *
* Component to handle edit mode of "Reviews by Product" .
* /
const ReviewsByProductEditor = ( { attributes , debouncedSpeak , error , getProduct , isLoading , product , setAttributes } ) => {
const { className , editMode , productId , showReviewDate , showReviewerName } = attributes ;
const getBlockControls = ( ) => (
< BlockControls >
< Toolbar
controls = { [
{
icon : 'edit' ,
title : _ _ ( 'Edit' ) ,
onClick : ( ) => setAttributes ( { editMode : ! editMode } ) ,
isActive : editMode ,
} ,
] }
/ >
< / B l o c k C o n t r o l s >
) ;
const renderProductControlItem = ( args ) => {
const { item = 0 } = args ;
return (
< SearchListItem
{ ... args }
countLabel = { sprintf (
_n (
'%d Review' ,
'%d Reviews' ,
item . review _count ,
'woo-gutenberg-products-block'
) ,
item . review _count
) }
showCount
aria - label = { sprintf (
_n (
'%s, has %d review' ,
'%s, has %d reviews' ,
item . review _count ,
'woo-gutenberg-products-block'
) ,
item . name ,
item . review _count
) }
/ >
) ;
} ;
const getInspectorControls = ( ) => {
const minPerPage = 1 ;
const maxPerPage = 20 ;
return (
< InspectorControls key = "inspector" >
< PanelBody
title = { _ _ ( 'Product' , 'woo-gutenberg-products-block' ) }
initialOpen = { false }
>
< ProductControl
selected = { attributes . productId || 0 }
onChange = { ( value = [ ] ) => {
const id = value [ 0 ] ? value [ 0 ] . id : 0 ;
setAttributes ( { productId : id } ) ;
} }
renderItem = { renderProductControlItem }
/ >
< / P a n e l B o d y >
< PanelBody title = { _ _ ( 'Content' , 'woo-gutenberg-products-block' ) } >
< ToggleControl
label = { _ _ ( 'Product rating' , 'woo-gutenberg-products-block' ) }
checked = { attributes . showReviewRating }
onChange = { ( ) => setAttributes ( { showReviewRating : ! attributes . showReviewRating } ) }
/ >
2019-08-17 09:14:11 +00:00
{ ( attributes . showReviewRating && ! ENABLE _REVIEW _RATING ) && (
2019-08-15 14:55:57 +00:00
< Notice className = "wc-block-reviews-by-product__notice" isDismissible = { false } >
< RawHTML >
{ sprintf ( _ _ ( 'Product rating is disabled in your %sstore settings%s.' , 'woo-gutenberg-products-block' ) , ` <a href=" ${ getAdminLink ( 'admin.php?page=wc-settings&tab=products' ) } " target="_blank"> ` , '</a>' ) }
< / R a w H T M L >
< / N o t i c e >
) }
< ToggleControl
label = { _ _ ( 'Reviewer name' , 'woo-gutenberg-products-block' ) }
checked = { attributes . showReviewerName }
onChange = { ( ) => setAttributes ( { showReviewerName : ! attributes . showReviewerName } ) }
/ >
< ToggleControl
label = { _ _ ( 'Image' , 'woo-gutenberg-products-block' ) }
checked = { attributes . showReviewImage }
onChange = { ( ) => setAttributes ( { showReviewImage : ! attributes . showReviewImage } ) }
/ >
< ToggleControl
label = { _ _ ( 'Review date' , 'woo-gutenberg-products-block' ) }
checked = { attributes . showReviewDate }
onChange = { ( ) => setAttributes ( { showReviewDate : ! attributes . showReviewDate } ) }
/ >
{ attributes . showReviewImage && (
< Fragment >
< ToggleButtonControl
label = { _ _ ( 'Review image' , 'woo-gutenberg-products-block' ) }
value = { attributes . imageType }
options = { [
{ label : _ _ ( 'Reviewer photo' , 'woo-gutenberg-products-block' ) , value : 'reviewer' } ,
{ label : _ _ ( 'Product' , 'woo-gutenberg-products-block' ) , value : 'product' } ,
] }
onChange = { ( value ) => setAttributes ( { imageType : value } ) }
/ >
2019-08-17 09:14:11 +00:00
{ ( attributes . imageType === 'reviewer' && ! SHOW _AVATARS ) && (
2019-08-15 14:55:57 +00:00
< Notice className = "wc-block-reviews-by-product__notice" isDismissible = { false } >
< RawHTML >
{ sprintf ( _ _ ( 'Reviewer photo is disabled in your %ssite settings%s.' , 'woo-gutenberg-products-block' ) , ` <a href=" ${ getAdminLink ( 'options-discussion.php' ) } " target="_blank"> ` , '</a>' ) }
< / R a w H T M L >
< / N o t i c e >
) }
< / F r a g m e n t >
) }
< / P a n e l B o d y >
< PanelBody title = { _ _ ( 'List Settings' , 'woo-gutenberg-products-block' ) } >
< ToggleControl
label = { _ _ ( 'Order by' , 'woo-gutenberg-products-block' ) }
checked = { attributes . showOrderby }
onChange = { ( ) => setAttributes ( { showOrderby : ! attributes . showOrderby } ) }
/ >
< SelectControl
label = { _ _ ( 'Order Product Reviews by' , 'woo-gutenberg-products-block' ) }
value = { attributes . orderby }
options = { [
{ label : 'Most recent' , value : 'most-recent' } ,
{ label : 'Highest Rating' , value : 'highest-rating' } ,
{ label : 'Lowest Rating' , value : 'lowest-rating' } ,
] }
onChange = { ( orderby ) => setAttributes ( { orderby } ) }
/ >
< RangeControl
label = { _ _ ( 'Starting Number of Reviews' , 'woo-gutenberg-products-block' ) }
value = { attributes . reviewsOnPageLoad }
onChange = { ( reviewsOnPageLoad ) => setAttributes ( { reviewsOnPageLoad } ) }
max = { maxPerPage }
min = { minPerPage }
/ >
< ToggleControl
label = { _ _ ( 'Load more' , 'woo-gutenberg-products-block' ) }
checked = { attributes . showLoadMore }
onChange = { ( ) => setAttributes ( { showLoadMore : ! attributes . showLoadMore } ) }
/ >
{ attributes . showLoadMore && (
< RangeControl
label = { _ _ ( 'Load More Reviews' , 'woo-gutenberg-products-block' ) }
value = { attributes . reviewsOnLoadMore }
onChange = { ( reviewsOnLoadMore ) => setAttributes ( { reviewsOnLoadMore } ) }
max = { maxPerPage }
min = { minPerPage }
/ >
) }
< / P a n e l B o d y >
< / I n s p e c t o r C o n t r o l s >
) ;
} ;
const renderApiError = ( ) => (
< ApiErrorPlaceholder
className = "wc-block-featured-product-error"
error = { error }
isLoading = { isLoading }
onRetry = { getProduct }
/ >
) ;
const renderLoadingScreen = ( ) => {
return (
< Placeholder
icon = { < IconReviewsByProduct className = "block-editor-block-icon" / > }
label = { _ _ ( 'Reviews by Product' , 'woo-gutenberg-products-block' ) }
className = "wc-block-reviews-by-product"
>
< Spinner / >
< / P l a c e h o l d e r >
) ;
} ;
const renderEditMode = ( ) => {
const onDone = ( ) => {
setAttributes ( { editMode : false } ) ;
debouncedSpeak (
_ _ (
'Showing Reviews by Product block preview.' ,
'woo-gutenberg-products-block'
)
) ;
} ;
return (
< Placeholder
icon = { < IconReviewsByProduct className = "block-editor-block-icon" / > }
label = { _ _ ( 'Reviews by Product' , 'woo-gutenberg-products-block' ) }
className = "wc-block-reviews-by-product"
>
{ _ _ (
'Show reviews of your product to build trust' ,
'woo-gutenberg-products-block'
) }
< div className = "wc-block-reviews-by-product__selection" >
< ProductControl
selected = { attributes . productId || 0 }
onChange = { ( value = [ ] ) => {
const id = value [ 0 ] ? value [ 0 ] . id : 0 ;
setAttributes ( { productId : id } ) ;
} }
queryArgs = { {
orderby : 'comment_count' ,
order : 'desc' ,
} }
renderItem = { renderProductControlItem }
/ >
< Button isDefault onClick = { onDone } >
{ _ _ ( 'Done' , 'woo-gutenberg-products-block' ) }
< / B u t t o n >
< / d i v >
< / P l a c e h o l d e r >
) ;
} ;
const renderViewMode = ( ) => {
2019-08-17 09:14:11 +00:00
const showReviewImage = ( SHOW _AVATARS || attributes . imageType === 'product' ) && attributes . showReviewImage ;
const showReviewRating = ENABLE _REVIEW _RATING && attributes . showReviewRating ;
2019-08-15 14:55:57 +00:00
const classes = classNames ( 'wc-block-reviews-by-product' , className , {
'has-image' : showReviewImage ,
'has-name' : showReviewerName ,
'has-date' : showReviewDate ,
'has-rating' : showReviewRating ,
} ) ;
return (
< Fragment >
{ product . review _count === 0 ? (
< Placeholder
className = "wc-block-reviews-by-product"
icon = { < IconReviewsByProduct className = "block-editor-block-icon" / > }
label = { _ _ ( 'Reviews by Product' , 'woo-gutenberg-products-block' ) }
>
< div dangerouslySetInnerHTML = { {
_ _html : sprintf (
_ _ (
"This block lists reviews for a selected product. %s doesn't have any reviews yet, but they will show up here when it does." ,
'woo-gutenberg-products-block'
) ,
'<strong>' + escapeHTML ( product . name ) + '</strong>'
) ,
} } / >
< / P l a c e h o l d e r >
) : (
< Disabled >
< div className = { classes } >
< EditorBlock attributes = { attributes } / >
< / d i v >
< / D i s a b l e d >
) }
< / F r a g m e n t >
) ;
} ;
if ( error ) {
return renderApiError ( ) ;
}
if ( ! productId || editMode ) {
return renderEditMode ( ) ;
}
if ( ! product || isLoading ) {
return renderLoadingScreen ( ) ;
}
return (
< Fragment >
{ getBlockControls ( ) }
{ getInspectorControls ( ) }
{ renderViewMode ( ) }
< / F r a g m e n t >
) ;
} ;
ReviewsByProductEditor . propTypes = {
/ * *
* The attributes for this block .
* /
attributes : PropTypes . object . isRequired ,
/ * *
* The register block name .
* /
name : PropTypes . string . isRequired ,
/ * *
* A callback to update attributes .
* /
setAttributes : PropTypes . func . isRequired ,
// from withProduct
error : PropTypes . object ,
getProduct : PropTypes . func ,
isLoading : PropTypes . bool ,
product : PropTypes . shape ( {
name : PropTypes . node ,
review _count : PropTypes . number ,
} ) ,
// from withSpokenMessages
debouncedSpeak : PropTypes . func . isRequired ,
} ;
export default compose ( [
withProduct ,
withSpokenMessages ,
] ) ( ReviewsByProductEditor ) ;