Skip to content

Commit

Permalink
feat: add reviews count to ProductTitle component (#2655)
Browse files Browse the repository at this point in the history
## What's the purpose of this pull request?

**Adds the number of reviews** next to the **Rating** component in the
**ProductTitle**. The review count, as well as the rating, should only
be visible if the corresponding flag in the **discovery.config** is
enabled in the code.

## How it works?

The following props have been added to **ProductTitle**:

- **reviewsCount?**: The amount of reviews for the product.
- **reviewsSectionId?**: The ID of the reviews section to link to.
- **noReviewsText?**: Default text for "No reviews yet."
- **reviewsCountText?**: Default text for "X reviews."

The review count text should be a link to the reviews section, which
will be located further down on the product page. This link will receive
the section ID through the **reviewsSectionId** prop. The labels for the
text can also be customized via props, but by default, they will be "No
reviews yet" and "X reviews."

## How to test it?

You can access the preview link and open any pdp. It already should be
able to show the reviews count for the product.
If the count label don't appear you can run `yarn cms-sync` in the
`start.store`
[branch](vtex-sites/starter.store#685)

<!--- Describe the steps with bullet points. Is there any external link
that can be used to better test it or an example? --->

### Starters Deploy Preview


[Preview](https://starter-git-feat-preview-product-title-count-vtex.vercel.app/)

<!--- Add a link to a deploy preview from `starter.store` with this
branch being used. --->

<!--- Tip: You can get an installable version of this branch from the
CodeSandbox generated when this PR is created. --->

## References

[JIRA TASK: SFS-2064](https://vtex-dev.atlassian.net/browse/SFS-2064)


[Figma](https://www.figma.com/design/YXU6IX2htN2yg7udpCumZv/Reviews-%26-Ratings?node-id=130-32961&t=sKkz60J8JEjxL8m4-4)


![image](https://github.com/user-attachments/assets/b3828116-34ee-49fe-abf4-d7478c18b725)

![image](https://github.com/user-attachments/assets/3d6b3c4a-11db-4b40-911e-171f076b676a)

---------

Co-authored-by: gutchenzo <[email protected]>
Co-authored-by: Larícia Mota <[email protected]>
Co-authored-by: Fanny Chien <[email protected]>
  • Loading branch information
4 people authored Feb 20, 2025
1 parent 5b1d946 commit 68b05c9
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 22 deletions.
52 changes: 48 additions & 4 deletions packages/components/src/molecules/ProductTitle/ProductTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,33 @@ export interface ProductTitleProps
*/
refNumber?: string
/**
* The current value of the rating, a number from 0 to 5.
* Object containing the rating value and reviews count
*/
ratingValue?: number
reviewsAndRating?: {
/**
* The current value of the rating, a number from 0 to 5.
*/
ratingValue?: number
/**
* The amount of reviews for the product.
*/
reviewsCount?: number
/**
* Text to display when there aren't reviews.
* @default "No reviews yet".
*/
noReviewsText?: string
/**
* Text to display when there is only one review.
* @default "review".
*/
singleReviewText?: string
/**
* Text to display when there are multiple reviews.
* @default "reviews".
*/
multipleReviewsText?: string
}
}

const ProductTitle = forwardRef<HTMLElement, ProductTitleProps>(
Expand All @@ -39,11 +63,19 @@ const ProductTitle = forwardRef<HTMLElement, ProductTitleProps>(
refTag = 'Ref.: ',
refNumber,
testId = 'fs-product-title',
ratingValue,
reviewsAndRating,
...otherProps
},
ref
) {
const {
ratingValue,
reviewsCount,
noReviewsText = 'No reviews yet',
singleReviewText = 'review',
multipleReviewsText = 'reviews',
} = reviewsAndRating || {}

return (
<header
ref={ref}
Expand All @@ -58,7 +90,19 @@ const ProductTitle = forwardRef<HTMLElement, ProductTitleProps>(

{(refNumber || ratingValue !== undefined) && (
<div data-fs-product-title-addendum>
{ratingValue !== undefined && <Rating value={ratingValue} />}
<div data-fs-product-title-rating>
{ratingValue !== undefined && <Rating value={ratingValue} />}

{reviewsCount !== undefined && (
<a href="#reviews-and-ratings" data-fs-product-title-reviews>
{reviewsCount === 0 && `(${noReviewsText})`}
{reviewsCount === 1 &&
`(${reviewsCount} ${singleReviewText})`}
{reviewsCount > 1 &&
`(${reviewsCount} ${multipleReviewsText})`}
</a>
)}
</div>
{refNumber && (
<>
{refTag} {refNumber}
Expand Down
21 changes: 21 additions & 0 deletions packages/core/cms/faststore/sections.json
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,27 @@
"title": "Show Reference Number?",
"type": "boolean",
"default": false
},
"rating": {
"title": "Rating",
"type": "object",
"properties": {
"noReviewsText": {
"title": "No reviews text",
"type": "string",
"default": "No reviews yet"
},
"multipleReviewsText": {
"title": "Multiple reviews text",
"type": "string",
"default": "reviews"
},
"singleReviewText": {
"title": "Single review text",
"type": "string",
"default": "review"
}
}
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ export interface ProductDetailsProps {
size: 'big' | 'small'
showDiscountBadge: boolean
}
rating: {
noReviewsText: string
singleReviewText: string
multipleReviewsText: string
}
}
buyButton: {
title: string
Expand Down Expand Up @@ -88,6 +93,7 @@ function ProductDetails({
productTitle: {
refNumber: showRefNumber,
discountBadge: { showDiscountBadge, size: discountBadgeSize },
rating: { noReviewsText, multipleReviewsText, singleReviewText },
},
buyButton: { icon: buyButtonIcon, title: buyButtonTitle },
shippingSimulator: {
Expand Down Expand Up @@ -199,9 +205,6 @@ function ProductDetails({
// Maybe now it's worth to make title always a h1 and receive only the name, as it would be easier for users to override.
title={<h1>{name}</h1>}
{...ProductTitle.props}
ratingValue={
apiConfig.reviewsAndRatings ? rating.average : undefined
}
label={
showDiscountBadge && (
<DiscountBadge.Component
Expand All @@ -223,6 +226,15 @@ function ProductDetails({
)
}
refNumber={showRefNumber && productId}
{...(apiConfig.reviewsAndRatings && {
reviewsAndRating: {
ratingValue: rating.average,
reviewsCount: rating.totalCount,
noReviewsText,
multipleReviewsText,
singleReviewText,
},
})}
/>
</header>
<ImageGallery.Component
Expand Down
53 changes: 38 additions & 15 deletions packages/ui/src/components/molecules/ProductTitle/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,43 @@
// --------------------------------------------------------

// Default properties
--fs-product-title-text-size : var(--fs-text-size-title-product);
--fs-product-title-text-weight : var(--fs-text-weight-regular);
--fs-product-title-line-height : 1.12;
--fs-product-title-column-gap : var(--fs-spacing-2);
--fs-product-title-row-gap : var(--fs-spacing-3);
--fs-product-title-text-size : var(--fs-text-size-title-product);
--fs-product-title-text-weight : var(--fs-text-weight-regular);
--fs-product-title-line-height : 1.12;
--fs-product-title-column-gap : var(--fs-spacing-2);
--fs-product-title-row-gap : var(--fs-spacing-3);

--fs-product-title-addendum-color : var(--fs-color-text-light);
--fs-product-title-addendum-size : var(--fs-text-size-1);
--fs-product-title-addendum-line-height : 1.7;
// Addendum
--fs-product-title-addendum-color : var(--fs-color-text-light);
--fs-product-title-addendum-size : var(--fs-text-size-1);
--fs-product-title-addendum-line-height : 1.7;

// Reviews
--fs-product-title-reviews-color : var(--fs-color-text-light);
--fs-product-title-reviews-size : var(--fs-text-size-1);
--fs-product-title-reviews-line-height : 1.42;

// --------------------------------------------------------
// Structural Styles
// --------------------------------------------------------

[data-fs-product-title-header] {
display: flex;
justify-content: space-between;
max-width: 42ch;
flex-wrap: wrap;
column-gap: var(--fs-product-title-column-gap);
row-gap: var(--fs-product-title-row-gap);
column-gap: var(--fs-product-title-column-gap);
justify-content: space-between;
max-width: 42ch;

// Title prop
& > *:first-child {
*:first-child {
font-size: var(--fs-product-title-text-size);
font-weight: var(--fs-product-title-text-weight);
line-height: var(--fs-product-title-line-height);
}

[data-fs-badge] { white-space: nowrap; }
[data-fs-badge] {
white-space: nowrap;
}

@include media(">=tablet", "<notebook") {
flex-direction: column;
Expand All @@ -43,11 +50,27 @@

[data-fs-product-title-addendum] {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
margin-top: var(--fs-product-title-row-gap);
font-size: var(--fs-product-title-addendum-size);
line-height: var(--fs-product-title-addendum-line-height);
color: var(--fs-product-title-addendum-color);
}

[data-fs-product-title-rating] {
display: flex;
flex-wrap: wrap;
gap: var(--fs-product-title-column-gap);
align-items: center;
}

[data-fs-product-title-reviews] {
font-size: inherit;
line-height: inherit;
color: inherit;
text-decoration: none;
cursor: pointer;
}
}

0 comments on commit 68b05c9

Please sign in to comment.