-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implements new organism component "RatingSummary"
- Loading branch information
Showing
14 changed files
with
469 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
packages/components/src/organisms/RatingSummary/RatingDistribution.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import React, { forwardRef, type HTMLAttributes } from 'react' | ||
import RatingDistributionItem from './RatingDistributionItem' | ||
|
||
export interface RatingDistributionProps | ||
extends HTMLAttributes<HTMLOListElement> { | ||
/** | ||
* The rating distribution | ||
*/ | ||
distribution: { | ||
starsOne: number | ||
starsTwo: number | ||
starsThree: number | ||
starsFour: number | ||
starsFive: number | ||
} | ||
/** | ||
* ID to find this component in testing tools (e.g.: cypress, testing library, and jest). | ||
*/ | ||
testId?: string | ||
} | ||
|
||
export const RatingDistribution = forwardRef< | ||
HTMLOListElement, | ||
RatingDistributionProps | ||
>(function RatingDistribution( | ||
{ | ||
distribution: { starsFive, starsFour, starsThree, starsTwo, starsOne }, | ||
testId = 'fs-rating-distribution', | ||
...props | ||
}, | ||
ref | ||
) { | ||
return ( | ||
<ol ref={ref} data-fs-rating-distribution data-testid={testId} {...props}> | ||
<RatingDistributionItem ratingIndex={5} value={starsFive} /> | ||
<RatingDistributionItem ratingIndex={4} value={starsFour} /> | ||
<RatingDistributionItem ratingIndex={3} value={starsThree} /> | ||
<RatingDistributionItem ratingIndex={2} value={starsTwo} /> | ||
<RatingDistributionItem ratingIndex={1} value={starsOne} /> | ||
</ol> | ||
) | ||
}) | ||
|
||
export default RatingDistribution |
57 changes: 57 additions & 0 deletions
57
packages/components/src/organisms/RatingSummary/RatingDistributionItem.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import React, { forwardRef, type HTMLAttributes } from 'react' | ||
import Icon from '../../atoms/Icon' | ||
|
||
export interface RatingDistributionItemProps | ||
extends HTMLAttributes<HTMLLIElement> { | ||
/** | ||
* Star rating index. It should be a number between 1 and 5. | ||
*/ | ||
ratingIndex: number | ||
/** | ||
* Percentage value. It should be a number between 0 and 100. | ||
*/ | ||
value: number | ||
/** | ||
* ID to find this component in testing tools (e.g.: cypress, testing library, and jest). | ||
*/ | ||
testId?: string | ||
} | ||
|
||
const ItemStar = ({ ratingIndex }: { ratingIndex: number }) => ( | ||
<span data-fs-rating-distribution-item-star> | ||
<p>{ratingIndex}</p> | ||
<Icon data-fs-rating-distribution-item-star-icon name="Star" /> | ||
</span> | ||
) | ||
|
||
const ItemBar = ({ value }: { value: number }) => ( | ||
<div data-fs-rating-distribution-item-bar> | ||
<div data-fs-rating-distribution-item-bar-track> | ||
<div | ||
data-fs-rating-distribution-item-bar-fill | ||
style={{ width: `${value}%` }} | ||
/> | ||
</div> | ||
</div> | ||
) | ||
|
||
const ItemPercentage = ({ percentage }: { percentage: number }) => ( | ||
<p data-fs-rating-distribution-item-percentage>{percentage}%</p> | ||
) | ||
|
||
const RatingDistributionItem = forwardRef< | ||
HTMLLIElement, | ||
RatingDistributionItemProps | ||
>(function RatingDistributionItem( | ||
{ ratingIndex, value, testId = 'fs-rating-distribution-item' }, | ||
ref | ||
) { | ||
return ( | ||
<li ref={ref} data-fs-distribution-item data-testid={testId}> | ||
<ItemStar ratingIndex={ratingIndex} /> | ||
<ItemBar value={value} /> | ||
<ItemPercentage percentage={value} /> | ||
</li> | ||
) | ||
}) | ||
export default RatingDistributionItem |
122 changes: 122 additions & 0 deletions
122
packages/components/src/organisms/RatingSummary/RatingSummary.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import React, { forwardRef, type HTMLAttributes } from 'react' | ||
import Rating from '../../molecules/Rating' | ||
import Button from '../../atoms/Button' | ||
import RatingDistribution from './RatingDistribution' | ||
|
||
export interface RatingSummaryProps extends HTMLAttributes<HTMLDivElement> { | ||
/** | ||
* The average rating of the product. A decimal number between 0 and 5. | ||
*/ | ||
average: number | ||
/** | ||
* The total number of reviews of the product. An integer number. | ||
*/ | ||
totalCount: number | ||
/** | ||
* The distribution percentage of the ratings | ||
*/ | ||
distribution: { | ||
starsOne: number | ||
starsTwo: number | ||
starsThree: number | ||
starsFour: number | ||
starsFive: number | ||
} | ||
/** | ||
* Text labels for the rating counter and create review button | ||
*/ | ||
textLabels?: { | ||
ratingCounter?: { | ||
noReviewsText?: string | ||
singleReviewText?: string | ||
multipleReviewsText?: string | ||
} | ||
createReviewButton?: { | ||
noReviewsText?: string | ||
defaultText?: string | ||
} | ||
} | ||
/** | ||
* ID to find this component in testing tools (e.g.: cypress, testing library, and jest). | ||
*/ | ||
testId?: string | ||
} | ||
|
||
const RatingSummaryHeader = ({ | ||
average, | ||
totalCount, | ||
noReviewsText, | ||
singleReviewText, | ||
multipleReviewsText, | ||
}: { | ||
average: number | ||
totalCount: number | ||
noReviewsText: string | ||
singleReviewText: string | ||
multipleReviewsText: string | ||
}) => { | ||
const formattedAverage = average > 0 ? average.toPrecision(2) : '' | ||
const totalCountText = | ||
totalCount > 0 | ||
? `${totalCount} ${totalCount === 1 ? singleReviewText : multipleReviewsText}` | ||
: noReviewsText | ||
|
||
return ( | ||
<div data-fs-rating-summary-header> | ||
<h2 data-fs-rating-summary-header-average>{formattedAverage}</h2> | ||
<Rating value={average} /> | ||
<p data-fs-rating-summary-header-total-count>{totalCountText}</p> | ||
</div> | ||
) | ||
} | ||
|
||
export const RatingSummary = forwardRef<HTMLDivElement, RatingSummaryProps>( | ||
function RatingSummary( | ||
{ | ||
average, | ||
totalCount, | ||
distribution, | ||
textLabels: { | ||
ratingCounter: { | ||
noReviewsText: ratingCounterNoReviewsText = 'No reviews yet', | ||
singleReviewText: ratingCounterSingleReviewText = 'Review', | ||
multipleReviewsText: ratingCounterMultipleReviewsText = 'Reviews', | ||
} = {}, | ||
createReviewButton: { | ||
noReviewsText: | ||
createReviewButtonNoReviewsText = 'Write the first review', | ||
defaultText: createReviewButtonDefaultText = 'Write a review', | ||
} = {}, | ||
} = {}, | ||
testId = 'fs-rating-summary', | ||
...props | ||
}, | ||
ref | ||
) { | ||
const buttonText = | ||
totalCount > 0 | ||
? createReviewButtonDefaultText | ||
: createReviewButtonNoReviewsText | ||
|
||
return ( | ||
<div ref={ref} data-fs-rating-summary data-testid={testId} {...props}> | ||
<RatingSummaryHeader | ||
average={average} | ||
totalCount={totalCount} | ||
noReviewsText={ratingCounterNoReviewsText} | ||
singleReviewText={ratingCounterSingleReviewText} | ||
multipleReviewsText={ratingCounterMultipleReviewsText} | ||
/> | ||
<Button | ||
variant="secondary" | ||
onClick={() => alert('Write a review button clicked!')} | ||
> | ||
{buttonText} | ||
</Button> | ||
{totalCount > 0 && <RatingDistribution distribution={distribution} />} | ||
</div> | ||
) | ||
} | ||
) | ||
|
||
export default RatingSummary |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default, type RatingSummaryProps } from './RatingSummary' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.