woocommerce/plugins/woocommerce-blocks/assets/js/blocks/reviews-by-product/edit.js

356 lines
10 KiB
JavaScript
Raw Normal View History

Create Reviews by Product block (https://github.com/woocommerce/woocommerce-blocks/pull/658) * Create Reviews by Product block * Honor Content settings * Fix wrong className * Load new wc-packages file * Add reviews-by-product JS files to webpack config * Cleanup * Remove error messages * Add Reviews by Product icon * Update sort options * Allow additional CSS classes attribute * Refactor block styles * Fix wrong default for reviews_orderby * Don't enforce CSS chunks * Add reviews count to Reviews by Product controls (https://github.com/woocommerce/woocommerce-blocks/pull/671) * Add label to Reviews by Product controls count (https://github.com/woocommerce/woocommerce-blocks/pull/677) * Add reviews count to Reviews by Product controls * Add label to Reviews by Product controls count * Add label to Reviews by Product controls count * Update components package * Review ordering and placeholders (https://github.com/woocommerce/woocommerce-blocks/pull/688) * Add support for comment_count ordering and add to productcontrol * Add a placeholder if rating count is 0 * Update assets/js/components/utils/index.js Co-Authored-By: Albert Juhé Lluveras <contact@albertjuhe.com> * Update assets/js/blocks/reviews-by-product/block.js Co-Authored-By: Albert Juhé Lluveras <contact@albertjuhe.com> * grammar * Fix some linting errors and warnings (https://github.com/woocommerce/woocommerce-blocks/pull/693) * Create Reviews by Product block placeholder (https://github.com/woocommerce/woocommerce-blocks/pull/691) * Create Reviews by Product block placeholder * Reviews by Product: load and render reviews with JS (https://github.com/woocommerce/woocommerce-blocks/pull/696) * Reviews by Product: load and render reviews with JS * Add dangerouslySetInnerHTML explanatory comment * Fix wrong dependency source * Debounce getReviews call when creating the Reviews by Product block * Rename 'Reviewer Picture' with 'Avatar' (https://github.com/woocommerce/woocommerce-blocks/pull/702) * Lint errors * Replace stringify query with addQueryArgs (https://github.com/woocommerce/woocommerce-blocks/pull/707) * Add reviews endpoint (https://github.com/woocommerce/woocommerce-blocks/pull/705) * Prevent state updates on unmounted components (https://github.com/woocommerce/woocommerce-blocks/pull/715) * Add Order by and Load more controls in Reviews by Product frontend (https://github.com/woocommerce/woocommerce-blocks/pull/716) * Export IconReviewsByProduct (https://github.com/woocommerce/woocommerce-blocks/pull/721) * Fix Reviews by Product layout in IE11 (https://github.com/woocommerce/woocommerce-blocks/pull/723) * Set minimum to per page input field (https://github.com/woocommerce/woocommerce-blocks/pull/731) * Hide avatars in Reviews by Products if 'show_avatars' settings is false (https://github.com/woocommerce/woocommerce-blocks/pull/730) * Blocks API - Reviews endpoint with rating sort and category filtering (https://github.com/woocommerce/woocommerce-blocks/pull/726) * Move file to correct location * We are only using the reviews endpoint not revioews/id * Remove sensistive data and make endpoint public * Allow guest access to approved reviews * Add support for rating sorting * category filtering * update arg name * fix category query * Reviews by Product: add placeholders when loading reviews (https://github.com/woocommerce/woocommerce-blocks/pull/732) * Add placeholder animation (https://github.com/woocommerce/woocommerce-blocks/pull/733) * Hook up Reviews by Product 'Order by' with endpoint (https://github.com/woocommerce/woocommerce-blocks/pull/736) * Hook up Reviews by Product 'Order by' with endpoint * Use onChange instead of onBlur in select control * Reviews by Product: Hide ratings if they are disabled in settings (https://github.com/woocommerce/woocommerce-blocks/pull/740) * Hide ratings in Reviews by Product if disabled in settings * Hide order by select if ratings are disabled * Reviews by Product cleanup (https://github.com/woocommerce/woocommerce-blocks/pull/773) * Fix wrong method name * Reduce the number of dependencies used in Reviews by Product (https://github.com/woocommerce/woocommerce-blocks/pull/774) * Reduce the number of dependencies used in Reviews by Product * Use 'withComponentId' HOC * Remove debounce * Fix wrong proptype * Get rid of JS warning * Load render from react-dom * Add formatted_date_created item schema (https://github.com/woocommerce/woocommerce-blocks/pull/788) * Fix import of WithComponentID * Add new settings to Reviews by Product block (https://github.com/woocommerce/woocommerce-blocks/pull/787) * 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 * Reviews by Product: prevent importing all HOCs and import only withComponentId (https://github.com/woocommerce/woocommerce-blocks/pull/811) * Reviews by product: Update review styling and content (https://github.com/woocommerce/woocommerce-blocks/pull/806) * 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 * Review design/layout * verified icons * Read more component * remove comment * expanded -> isExpanded * Localise and change default elipses * Simplify ReadMore * Support children rather than passing content * remove outside * remove list style * Update assets/js/components/read-more/index.js Co-Authored-By: Albert Juhé Lluveras <contact@albertjuhe.com> * Update assets/js/components/read-more/index.js Co-Authored-By: Albert Juhé Lluveras <contact@albertjuhe.com> * merge set state * Add missing parameter doc in renderReview (https://github.com/woocommerce/woocommerce-blocks/pull/820) * Fix Reviews by Product order by select not honoring default setting (https://github.com/woocommerce/woocommerce-blocks/pull/818) * Read more component - change how clamped content is shown (https://github.com/woocommerce/woocommerce-blocks/pull/821) * Pass review as components * Build summary from content and track both * Toggle display after inital load * remove unused variable * remove componentDidUpdate * Simplify clampLines * Put back componentDidUpdate, but store final summary in state * clampEnabled * Call clampLines from componentDidMount (https://github.com/woocommerce/woocommerce-blocks/pull/826) * truncate html tests * implement trimHTML and pass test * Feedback * test short content * Use withProduct HOC in ReviewsByProductEditor (https://github.com/woocommerce/woocommerce-blocks/pull/828) * Use withProduct HOC * Convert ReviewsByProductEditor to a functional component * Add loading and error states * Prevent loading screen appearing when changing products * Reviews: only save wrapper element to post (https://github.com/woocommerce/woocommerce-blocks/pull/830) * Fix bundlesize config not picking frontend files (https://github.com/woocommerce/woocommerce-blocks/pull/840) * Reviews by Product: split 'block.js' into smaller chunks (https://github.com/woocommerce/woocommerce-blocks/pull/841) * Split 'block.js' into smaller chunks * Move frontend blocks to their specific folder * Order imports * Typo * Add frontend components proptypes * Fix indentation * Call 'this.getDefaultArgs' directly inside 'getReviews' * Move access to wc_product_block_data to the top of the file * Rename 'frontend' folder to 'base' * Rename base components and move styles to their folder * Fix Reviews by Product using rating count instead of review count (https://github.com/woocommerce/woocommerce-blocks/pull/860) * Improve Reviews by Product accessibility (https://github.com/woocommerce/woocommerce-blocks/pull/861) * Improve Reviews by Product accessibility * Make 'onClick' prop not required in <LoadMoreButton> * Wrap Reviews by Product editor block with <Disabled> * Reviews: fix reviews without rating not appearing when sorting by rating (https://github.com/woocommerce/woocommerce-blocks/pull/863)
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';
const enableReviewRating = !! ( typeof wc_product_block_data !== 'undefined' && wc_product_block_data.enableReviewRating );
const showAvatars = !! ( typeof wc_product_block_data !== 'undefined' && wc_product_block_data.showAvatars );
/**
* 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,
},
] }
/>
</BlockControls>
);
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 }
/>
</PanelBody>
<PanelBody title={ __( 'Content', 'woo-gutenberg-products-block' ) }>
<ToggleControl
label={ __( 'Product rating', 'woo-gutenberg-products-block' ) }
checked={ attributes.showReviewRating }
onChange={ () => setAttributes( { showReviewRating: ! attributes.showReviewRating } ) }
/>
{ ( attributes.showReviewRating && ! enableReviewRating ) && (
<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>' ) }
</RawHTML>
</Notice>
) }
<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 } ) }
/>
{ ( attributes.imageType === 'reviewer' && ! showAvatars ) && (
<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>' ) }
</RawHTML>
</Notice>
) }
</Fragment>
) }
</PanelBody>
<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 }
/>
) }
</PanelBody>
</InspectorControls>
);
};
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 />
</Placeholder>
);
};
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' ) }
</Button>
</div>
</Placeholder>
);
};
const renderViewMode = () => {
const showReviewImage = ( showAvatars || attributes.imageType === 'product' ) && attributes.showReviewImage;
const showReviewRating = enableReviewRating && attributes.showReviewRating;
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>'
),
} } />
</Placeholder>
) : (
<Disabled>
<div className={ classes }>
<EditorBlock attributes={ attributes } />
</div>
</Disabled>
) }
</Fragment>
);
};
if ( error ) {
return renderApiError();
}
if ( ! productId || editMode ) {
return renderEditMode();
}
if ( ! product || isLoading ) {
return renderLoadingScreen();
}
return (
<Fragment>
{ getBlockControls() }
{ getInspectorControls() }
{ renderViewMode() }
</Fragment>
);
};
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 );