Skip to content
This repository was archived by the owner on Feb 10, 2025. It is now read-only.

Commit 804d86d

Browse files
authored
fix(PAR-596): IconLabel review variant refactor into ReviewsCounterLabel (#54)
* chore: extended tailwind borderRadius theme * chore: implemented ReviewsCounterLabel * chore: removed reviews variant in IconLabel
1 parent 6891798 commit 804d86d

15 files changed

+357
-106
lines changed

src/components/IconLabel/IconLabel.stories.tsx

+1-38
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,7 @@ const meta: Meta<typeof IconLabel> = {
1313
argTypes: {
1414
type: {
1515
control: "select",
16-
options: [
17-
"default",
18-
"ai-evaluation",
19-
"date",
20-
"dateWithPrefix",
21-
"reviews",
22-
"address",
23-
"social",
24-
],
16+
options: ["default", "ai-evaluation", "date", "dateWithPrefix", "address", "social"],
2517
},
2618
platform: {
2719
control: "select",
@@ -58,20 +50,6 @@ const meta: Meta<typeof IconLabel> = {
5850
},
5951
if: { arg: "type", eq: "period" },
6052
},
61-
posReviews: {
62-
control: {
63-
type: "number",
64-
min: 0,
65-
},
66-
if: { arg: "type", eq: "reviews" },
67-
},
68-
negReviews: {
69-
control: {
70-
type: "number",
71-
min: 0,
72-
},
73-
if: { arg: "type", eq: "reviews" },
74-
},
7553
address: {
7654
control: "text",
7755
if: { arg: "type", eq: "address" },
@@ -114,8 +92,6 @@ export const Playground: Story = {
11492
percent: 77, // Default for evaluation
11593
date: new Date(), // Default for date
11694
prefix: "Applied on: ", // Default for dateWithPrefix
117-
posReviews: 3, // Default for reviews
118-
negReviews: 3, // Default for reviews
11995
address: "0xE307051C410e970b861CC55CBFD5Acc7BB477750", // Default for address
12096
link: "https://github.com/user", // Default for social
12197
isVerified: false, // Default for social
@@ -261,16 +237,3 @@ export const SocialTwitter: Story = {
261237
expect(linkText).toBeInTheDocument();
262238
},
263239
};
264-
// Reviews Label Story
265-
export const Reviews: Story = {
266-
args: {
267-
type: "reviews",
268-
posReviews: 3,
269-
negReviews: 2,
270-
},
271-
play: async ({ canvasElement }) => {
272-
const canvas = within(canvasElement);
273-
const reviewsText = await canvas.findByText("5 Reviews");
274-
expect(reviewsText).toBeInTheDocument();
275-
},
276-
};

src/components/IconLabel/IconLabel.tsx

+1-17
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,7 @@ import { getAddressLabel } from "@/lib/utils";
77
import { IconType } from "@/primitives/Icon";
88

99
import { IconLabelProps } from "./types";
10-
import {
11-
getEvaluation,
12-
renderReviewIcons,
13-
IconLabelContainer,
14-
getFormattedLink,
15-
RenderIcon,
16-
} from "./utils";
10+
import { getEvaluation, IconLabelContainer, getFormattedLink, RenderIcon } from "./utils";
1711
import { variants } from "./variants";
1812

1913
export const IconLabel: React.FC<IconLabelProps> = (props) => {
@@ -88,16 +82,6 @@ export const IconLabel: React.FC<IconLabelProps> = (props) => {
8882
)}`}</span>
8983
</IconLabelContainer>
9084
))
91-
.with({ type: "reviews" }, ({ posReviews = 0, negReviews = 0, className }) => {
92-
const totalReviews = Math.max(0, posReviews) + Math.max(0, negReviews);
93-
94-
return (
95-
<IconLabelContainer type="reviews" className={className}>
96-
<div className="flex items-center">{renderReviewIcons(posReviews, negReviews)}</div>
97-
<span className={text()}>{`${totalReviews} Reviews`}</span>
98-
</IconLabelContainer>
99-
);
100-
})
10185
.with({ type: "address" }, ({ address, ens, className }) => {
10286
const label = getAddressLabel(ens, address);
10387

src/components/IconLabel/types.ts

-7
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@ interface DateWithPrefixProps {
3333
className?: string;
3434
}
3535

36-
interface ReviewsProps {
37-
type: "reviews";
38-
posReviews?: number;
39-
negReviews?: number;
40-
className?: string;
41-
}
4236
interface AddressProps {
4337
type: "address";
4438
address?: string;
@@ -68,7 +62,6 @@ export type IconLabelProps =
6862
| DateProps
6963
| PeriodProps
7064
| RoundPeriodProps
71-
| ReviewsProps
7265
| AddressProps
7366
| SocialProps
7467
| DateWithPrefixProps

src/components/IconLabel/utils.tsx

+1-33
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Icon, IconType } from "@/primitives/Icon";
55

66
import { variants } from "./variants";
77

8-
const { container, icon } = variants();
8+
const { container } = variants();
99

1010
export function getEvaluation(percent: number) {
1111
percent = Math.min(Math.max(percent, 0), 100);
@@ -18,38 +18,6 @@ export function getEvaluation(percent: number) {
1818
}
1919
}
2020

21-
export function renderReviewIcons(posReviews: number, negReviews: number) {
22-
const totalReviews = Math.max(0, posReviews) + Math.max(0, negReviews);
23-
const icons = [];
24-
25-
for (let i = 0; i < totalReviews; i++) {
26-
const isPositive = i < posReviews;
27-
const isFirst = i === 0;
28-
const classes = getReviewIconClasses(isFirst, isPositive);
29-
30-
icons.push(
31-
<Icon key={i} type={isPositive ? IconType.CHECK : IconType.X} className={classes} />,
32-
);
33-
}
34-
35-
return icons;
36-
}
37-
38-
function getReviewIconClasses(isFirst: boolean, isPositive: boolean): string {
39-
const baseClasses = icon({ type: "reviews" });
40-
let variantClasses = "";
41-
42-
if (isPositive) {
43-
variantClasses = isFirst
44-
? icon({ reviewType: "posFirst" })
45-
: icon({ reviewType: "posNotFirst" });
46-
} else {
47-
variantClasses = icon({ reviewType: "neg" });
48-
}
49-
50-
return `${baseClasses} ${variantClasses}`;
51-
}
52-
5321
export const IconLabelContainer = ({
5422
type,
5523
iconVariant,

src/components/IconLabel/variants.ts

+1-9
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,10 @@ export const variants = tv({
3838
text: "text-[14px]/[17px] text-grey-700",
3939
icon: "size-4 fill-grey-700",
4040
},
41-
reviews: {
42-
container: "gap-2",
43-
icon: "size-7 rounded-full border border-grey-100 bg-white",
44-
},
41+
4542
verifiedBadge: {
4643
icon: "h-5 w-[28px]",
4744
},
4845
},
49-
reviewType: {
50-
posFirst: { icon: "fill-green-600" },
51-
posNotFirst: { icon: "-ml-2 fill-green-600" },
52-
neg: { icon: "-ml-2 fill-red-200" },
53-
},
5446
},
5547
});

src/features/checker/components/ProjectEvaluationList/ProjectEvaluationList.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { getReviewsCount } from "~checker/utils/getReviewsCount";
77
import { EvaluationAction, ProjectEvaluationAction } from "../ProjectEvaluationAction";
88
import { ProjectStatus } from "../ProjectEvaluationAction";
99
import { ProjectReview } from "../ProjectReviewList";
10+
import { ReviewsCounterLabel } from "../ReviewsCounterLabel";
1011

1112
export interface ProjectEvaluationListProps {
1213
evaluationStatus?: ProjectStatus;
@@ -50,7 +51,7 @@ export const ProjectEvaluationList = ({
5051
width: "1fr",
5152
render: (item) => {
5253
const { nApproved, nRejected } = getReviewsCount(item.reviews);
53-
return <IconLabel type="reviews" posReviews={nApproved} negReviews={nRejected} />;
54+
return <ReviewsCounterLabel positiveReviews={nApproved} negativeReviews={nRejected} />;
5455
},
5556
},
5657
{

src/features/checker/components/ProjectReviewList/ProjectReviewList.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { ListGrid, ListGridColumn } from "@/primitives/ListGrid";
55

66
import { getReviewsCount } from "~checker/utils/getReviewsCount";
77

8+
import { ReviewsCounterLabel } from "../ReviewsCounterLabel";
89
import { ProjectReview } from "./types";
910

1011
export interface ProjectReviewListProps {
@@ -45,7 +46,7 @@ export const ProjectReviewList = ({ reviewer, projects, action }: ProjectReviewL
4546
width: "1fr",
4647
render: (item) => {
4748
const { nApproved, nRejected } = getReviewsCount(item.reviews);
48-
return <IconLabel type="reviews" posReviews={nApproved} negReviews={nRejected} />;
49+
return <ReviewsCounterLabel positiveReviews={nApproved} negativeReviews={nRejected} />;
4950
},
5051
},
5152
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
3+
import { ReviewsCounterLabel } from "./ReviewsCounterLabel";
4+
5+
const meta: Meta<typeof ReviewsCounterLabel> = {
6+
title: "features/Checker/Components/ReviewsCounterLabel",
7+
component: ReviewsCounterLabel,
8+
argTypes: {
9+
positiveReviews: {
10+
control: {
11+
type: "number",
12+
min: 0,
13+
},
14+
},
15+
negativeReviews: {
16+
control: {
17+
type: "number",
18+
min: 0,
19+
},
20+
},
21+
className: {
22+
control: "text",
23+
description: "Additional CSS classes to apply to the component.",
24+
},
25+
},
26+
};
27+
28+
export default meta;
29+
type Story = StoryObj<typeof ReviewsCounterLabel>;
30+
31+
export const Default: Story = {
32+
args: {
33+
positiveReviews: 0,
34+
negativeReviews: 0,
35+
},
36+
};
37+
38+
export const Pending: Story = {
39+
args: {
40+
positiveReviews: 0,
41+
negativeReviews: 0,
42+
},
43+
};
44+
45+
export const WithoutMaxReviews: Story = {
46+
args: {
47+
positiveReviews: 1,
48+
negativeReviews: 2,
49+
},
50+
};
51+
52+
export const WithMaxReviews: Story = {
53+
args: {
54+
positiveReviews: 3,
55+
negativeReviews: 2,
56+
},
57+
};
58+
59+
export const TooManyReviews: Story = {
60+
args: {
61+
positiveReviews: 300,
62+
negativeReviews: 200,
63+
},
64+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from "react";
2+
3+
import { tv } from "tailwind-variants";
4+
5+
import { cn } from "@/lib/utils";
6+
7+
import { ReviewIconGroup } from "./components/ReviewIconGroup";
8+
9+
const variants = tv({
10+
slots: {
11+
container: "flex items-center gap-2",
12+
text: "truncate text-[16px]/[24px]",
13+
},
14+
});
15+
16+
interface ReviewsCounterLabelProps {
17+
positiveReviews?: number;
18+
negativeReviews?: number;
19+
className?: string;
20+
}
21+
22+
export const ReviewsCounterLabel: React.FC<ReviewsCounterLabelProps> = ({
23+
positiveReviews = 0,
24+
negativeReviews = 0,
25+
className,
26+
}) => {
27+
const { text, container } = variants();
28+
29+
const totalReviews = Math.max(0, positiveReviews) + Math.max(0, negativeReviews);
30+
31+
return (
32+
<div className={cn(container(), className)}>
33+
<ReviewIconGroup positiveReviews={positiveReviews} negativeReviews={negativeReviews} />
34+
<span className={text()}>
35+
{totalReviews ? `${totalReviews} Review${totalReviews > 1 ? "s" : ""}` : "Needs review"}
36+
</span>
37+
</div>
38+
);
39+
};

0 commit comments

Comments
 (0)