forked from Lumina-eX/TaskChain
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathaverage-score-display.tsx
More file actions
99 lines (89 loc) · 2.39 KB
/
Copy pathaverage-score-display.tsx
File metadata and controls
99 lines (89 loc) · 2.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
"use client";
import { Star } from "lucide-react";
import { cn } from "@/lib/utils";
import { ReviewCard } from "@/components/ui/review-card";
export interface Review {
id: number;
contractId: number;
reviewerId: number;
reviewerName: string;
reviewerAvatar?: string;
freelancerId: number;
freelancerName: string;
rating: number;
comment?: string;
verified: boolean;
createdAt: string;
}
export interface AverageScoreDisplayProps {
reviews: Review[];
className?: string;
showCount?: boolean;
size?: "sm" | "md" | "lg";
}
export function AverageScoreDisplay({
reviews,
className,
showCount = true,
size = "md",
}: AverageScoreDisplayProps) {
const sizeConfig = {
sm: {
container: "px-3 py-1.5 rounded-lg",
star: "h-3.5 w-3.5",
text: "text-sm",
value: "text-base",
},
md: {
container: "px-4 py-2 rounded-xl",
star: "h-5 w-5",
text: "text-base",
value: "text-lg",
},
lg: {
container: "px-5 py-3 rounded-2xl",
star: "h-6 w-6",
text: "text-lg",
value: "text-xl",
},
};
const config = sizeConfig[size];
if (reviews.length === 0) {
return (
<div className={cn("text-center text-muted-foreground", config.text)}>
No reviews available
</div>
);
}
const averageRating = reviews.reduce((sum, review) => sum + review.rating, 0) / reviews.length;
const maxRating = 5;
const getRatingColor = (rating: number) => {
if (rating >= 4.5) return "text-emerald-400";
if (rating >= 4.0) return "text-green-400";
if (rating >= 3.5) return "text-lime-400";
if (rating >= 3.0) return "text-yellow-400";
if (rating >= 2.0) return "text-orange-400";
return "text-destructive";
};
return (
<div
className={cn(
"inline-flex items-center gap-2 bg-card/50 border border-border/60 rounded-xl",
config.container,
className
)}
>
<div className="flex items-center gap-1">
<Star className={cn("fill-current", config.star, getRatingColor(averageRating))} />
<span className={cn("font-bold", config.value, getRatingColor(averageRating))}>
{averageRating.toFixed(1)}
</span>
</div>
{showCount && (
<span className={cn("text-muted-foreground", config.text)}>
({reviews.length} review{reviews.length !== 1 ? "s" : ""})
</span>
)}
</div>
);
}