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

Display "Add review" link if there's no product rating #7929

Merged
merged 19 commits into from
Dec 28, 2022
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
10d7bb9
Display 5 'empty' stars if there's no product rating in All Products
kmanijak Dec 13, 2022
ae620d0
Display 5 'empty' stars if there's no product rating in Productsa and…
kmanijak Dec 13, 2022
51d5fa5
Display Add Review link in the All Products if there's no product rating
kmanijak Dec 15, 2022
6a49f8f
Merge branch 'trunk' into add/default-empty-rating
kmanijak Dec 15, 2022
b437747
Center the placeholder and Add Review link in the Products Editor
kmanijak Dec 15, 2022
6b1a4ac
Refactor product-elements/rating block
kmanijak Dec 15, 2022
44c79f4
Display Add Review link in the Products if there's no product rating
kmanijak Dec 15, 2022
86f4752
Bring back missing variable
kmanijak Dec 15, 2022
faaeaac
Remove unused variable
kmanijak Dec 15, 2022
76d68fd
Apply the font-size mixin to the Add Review link
kmanijak Dec 15, 2022
d7369d4
Make Add review link NOT clickable in editor
kmanijak Dec 15, 2022
aaef930
Merge branch 'trunk' into add/default-empty-rating
kmanijak Dec 15, 2022
dbf22c3
Escape URL used in the Add Review link
kmanijak Dec 16, 2022
dca9a01
Improve styles of Rating component so they support alignment in produ…
kmanijak Dec 16, 2022
cc77dd8
Limit the placeholder of Rating just to the All Products and Products…
kmanijak Dec 19, 2022
6f8b2fb
Move the logic to render link from render function to the filter
kmanijak Dec 27, 2022
002140c
Merge branch 'trunk' into add/default-empty-rating
kmanijak Dec 27, 2022
37708c9
Merge branch 'trunk' into add/default-empty-rating
kmanijak Dec 28, 2022
648581d
Merge branch 'trunk' into add/default-empty-rating
kmanijak Dec 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 81 additions & 44 deletions assets/js/atomic/blocks/product-elements/rating/block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ type Props = {
className?: string;
};

type RatingProps = {
reviews: number;
rating: number;
parentClassName?: string;
};

type AddReviewProps = {
href?: string;
};

const getAverageRating = (
product: Omit< ProductResponseItem, 'average_rating' > & {
average_rating: string;
Expand All @@ -35,6 +45,11 @@ const getAverageRating = (
return Number.isFinite( rating ) && rating > 0 ? rating : 0;
};

const getReviewsHref = ( product: ProductResponseItem ) => {
const { permalink } = product;
return `${ permalink }#reviews`;
};

const getRatingCount = ( product: ProductResponseItem ) => {
const count = isNumber( product.review_count )
? product.review_count
Expand All @@ -43,27 +58,8 @@ const getRatingCount = ( product: ProductResponseItem ) => {
return Number.isFinite( count ) && count > 0 ? count : 0;
};

/**
* Product Rating Block Component.
*
* @param {Object} props Incoming props.
* @param {string} [props.className] CSS Class name for the component.
* @param {string} [props.textAlign] Text alignment.
*
* @return {*} The component.
*/
export const Block = ( props: Props ): JSX.Element | null => {
const { textAlign } = props;
const { parentClassName } = useInnerBlockLayoutContext();
const { product } = useProductDataContext();
const rating = getAverageRating( product );
const colorProps = useColorProps( props );
const typographyProps = useTypographyProps( props );
const spacingProps = useSpacingProps( props );

if ( ! rating ) {
return null;
}
const Rating = ( props: RatingProps ): JSX.Element => {
const { rating, reviews, parentClassName } = props;

const starStyle = {
width: ( rating / 5 ) * 100 + '%',
Expand All @@ -75,7 +71,6 @@ export const Block = ( props: Props ): JSX.Element | null => {
rating
);

const reviews = getRatingCount( product );
const ratingHTML = {
__html: sprintf(
/* translators: %1$s is referring to the average rating value, %2$s is referring to the number of ratings */
Expand All @@ -89,38 +84,80 @@ export const Block = ( props: Props ): JSX.Element | null => {
sprintf( '<span class="rating">%d</span>', reviews )
),
};

return (
<div
className={ classnames(
colorProps.className,
'wc-block-components-product-rating',
{
[ `${ parentClassName }__product-rating` ]: parentClassName,
},
{
[ `has-text-align-${ textAlign }` ]: textAlign,
}
'wc-block-components-product-rating__stars',
`${ parentClassName }__product-rating__stars`
) }
role="img"
aria-label={ ratingText }
>
<span style={ starStyle } dangerouslySetInnerHTML={ ratingHTML } />
</div>
);
};

const AddReview = ( props: AddReviewProps ): JSX.Element | null => {
const { href } = props;
const label = __( 'Add review', 'woo-gutenberg-products-block' );

return href ? (
<a className="wc-block-components-product-rating__link" href={ href }>
{ label }
</a>
) : null;
};

/**
* Product Rating Block Component.
*
* @param {Object} props Incoming props.
* @param {string} [props.className] CSS Class name for the component.
* @param {string} [props.textAlign] Text alignment.
*
* @return {*} The component.
*/
export const Block = ( props: Props ): JSX.Element | null => {
const { textAlign } = props;
const { parentClassName } = useInnerBlockLayoutContext();
const { product } = useProductDataContext();
const rating = getAverageRating( product );
const colorProps = useColorProps( props );
const typographyProps = useTypographyProps( props );
const spacingProps = useSpacingProps( props );
const reviews = getRatingCount( product );
const href = getReviewsHref( product );

const className = classnames(
colorProps.className,
'wc-block-components-product-rating',
{
[ `${ parentClassName }__product-rating` ]: parentClassName,
[ `has-text-align-${ textAlign }` ]: textAlign,
}
);

const content = reviews ? (
<Rating
rating={ rating }
reviews={ reviews }
parentClassName={ parentClassName }
/>
) : (
<AddReview href={ href } />
);

return (
<div
className={ className }
style={ {
...colorProps.style,
...typographyProps.style,
...spacingProps.style,
} }
>
<div
className={ classnames(
'wc-block-components-product-rating__stars',
`${ parentClassName }__product-rating__stars`
) }
role="img"
aria-label={ ratingText }
>
<span
style={ starStyle }
dangerouslySetInnerHTML={ ratingHTML }
/>
</div>
{ content }
</div>
);
};
Expand Down
1 change: 1 addition & 0 deletions assets/js/atomic/blocks/product-elements/rating/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Block from './block';
import withProductSelector from '../shared/with-product-selector';
import { BLOCK_TITLE, BLOCK_ICON } from './constants';
import { BlockAttributes } from './types';
import './editor.scss';

const Edit = ( {
attributes,
Expand Down
3 changes: 3 additions & 0 deletions assets/js/atomic/blocks/product-elements/rating/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.wc-block-components-product-rating__link {
pointer-events: none;
}
28 changes: 28 additions & 0 deletions assets/js/atomic/blocks/product-elements/rating/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
margin-bottom: $gap-small;

&__stars {
display: inline-block;
overflow: hidden;
position: relative;
width: 5.3em;
Expand Down Expand Up @@ -45,9 +46,36 @@
white-space: nowrap;
}
}

&__link {
display: inline-block;
width: 100%;
text-align: inherit;
@include font-size(small);
}
}

.wc-block-single-product {
.wc-block-components-product-rating__stars {
margin: 0;
}
}

.wc-block-all-products,
.wp-block-query {
.is-loading {
.wc-block-components-product-rating {
@include placeholder();
width: 7em;
margin-left: auto;
margin-right: auto;
}
}
}

// Fix applied specifically to Classic Template
.woocommerce-loop-product__link {
.wc-block-components-product-rating__stars {
display: block;
}
}
2 changes: 1 addition & 1 deletion assets/js/atomic/blocks/product-elements/sku/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ const blockConfig: CustomBlockConfiguration = {
edit,
};

registerBlockType( 'woocommerce/product-sku', { ...blockConfig } );
registerBlockType( 'woocommerce/product-sku', { ...blockConfig } );
1 change: 0 additions & 1 deletion src/BlockTypes/AbstractProductGrid.php
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,6 @@ protected function get_rating_html( $product ) {
return '';
}
$rating_count = $product->get_rating_count();
$review_count = $product->get_review_count();
$average = $product->get_average_rating();

if ( $rating_count > 0 ) {
Expand Down
7 changes: 6 additions & 1 deletion src/BlockTypes/ProductRating.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,16 @@ protected function get_block_type_uses_context() {
* @return string
*/
public function filter_rating_html( $html, $rating, $count ) {
if ( 0 < $rating ) {
$product_permalink = get_permalink();
if ( 0 < $rating || false === $product_permalink ) {
/* translators: %s: rating */
$label = sprintf( __( 'Rated %s out of 5', 'woo-gutenberg-products-block' ), $rating );
$html = '<div class="wc-block-components-product-rating__stars wc-block-grid__product-rating__stars" role="img" aria-label="' . esc_attr( $label ) . '">' . wc_get_star_rating_html( $rating, $count ) . '</div>';
} else {
$product_review_url = esc_url( $product_permalink . '#reviews' );
$html = '<a class="wc-block-components-product-rating__link" href="' . $product_review_url . '">' . __( 'Add review', 'woo-gutenberg-products-block' ) . '</a>';
}

return $html;
}

Expand Down