Customer Reviews
Customer Reviews é um componente para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.
Bund UI
MIT
other
O que é
Customer Reviews é um componente para React e Tailwind CSS, da biblioteca Bund UI, com licença MIT. Copia e cola no teu projeto.
Como usar
Abre o componente no catálogo, carrega em copiar, e cola no teu projeto. O prompt copiado leva o código e as regras para o teu agente o reproduzir sem alterar nada.
Cinco cópias grátis por mês. Sem cartão.
Precisa de
npm i lucide-react
Licença
Este componente vem de Bund UI e é redistribuído sob a licença MIT, que permite uso comercial. O aviso de copyright viaja com o código.
Customer Reviews
export const reviews = [
{
id: 1,
customerName: "Sarah Johnson",
customerAvatar:
"https://plus.unsplash.com/premium_photo-1671656349218-5218444643d8?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&q=80&w=200",
rating: 5,
reviewDate: "2 week ago",
totalSpend: 450,
totalReviews: 8,
reviewText:
"Absolutely love this product! The quality exceeded my expectations and the customer service was outstanding. I've been a loyal customer for over a year now and have never been disappointed. Highly recommend to anyone looking for premium quality."
},
{
id: 2,
customerName: "Michael Chen",
customerAvatar:
"https://images.unsplash.com/photo-1701615004837-40d8573b6652?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTl8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&q=60&w=200",
rating: 4,
reviewDate: "Yesterday",
totalSpend: 680,
totalReviews: 12,
reviewText:
"Great experience overall! The product arrived quickly and was exactly as described. The attention to detail is impressive. Only giving 4 stars because I wish there were more color options available, but that's a minor issue."
},
{
id: 3,
customerName: "Emma Davis",
customerAvatar:
"https://plus.unsplash.com/premium_photo-1689551670902-19b441a6afde?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MjV8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&q=60&w=200",
rating: 5,
reviewDate: "1 week ago",
totalSpend: 320,
totalReviews: 6,
reviewText:
"This is my third purchase and I keep coming back because the quality is consistently excellent. The packaging is beautiful and the product itself is even better in person. Will definitely be ordering again!"
},
{
id: 4,
customerName: "James Wilson",
customerAvatar:
"https://images.unsplash.com/photo-1623582854588-d60de57fa33f?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MjJ8fGF2YXRhcnxlbnwwfHwwfHx8MA%3D%3D&auto=format&fit=crop&q=60&w=200",
rating: 5,
reviewDate: "4 days ago",
totalSpend: 890,
totalReviews: 15,
reviewText:
"Outstanding quality and craftsmanship! I've recommended this to all my friends and family. The value for money is incredible and the customer support team went above and beyond to ensure I was satisfied with my purchase."
}
];
import { ReviewCard } from "./review-card";
import { reviews } from "./data";
export default function CustomerReviews() {
const averageRating = (
reviews.reduce((acc, review) => acc + review.rating, 0) / reviews.length
).toFixed(1);
const totalReviews = reviews.length;
return (
<section className="py-10 lg:py-20">
<div className="mx-auto max-w-3xl px-4">
<header className="mb-6 flex flex-col justify-between border-b pb-4 lg:mb-10 lg:flex-row lg:pb-6">
<h1 className="text-foreground font-heading text-xl md:text-2xl">Customer Reviews</h1>
<div className="text-muted-foreground flex items-center gap-2 lg:items-end lg:justify-center">
<div className="flex items-center gap-2 lg:items-end">
<span className="text-lg font-bold text-amber-500 md:text-2xl">{averageRating}</span>
<span className="text-sm">out of 5</span>
</div>
<span>•</span>
<span className="text-sm">based on {totalReviews} reviews</span>
</div>
</header>
<div className="grid gap-6 divide-y lg:grid-cols-1 lg:gap-10 [&>div]:pb-6 lg:[&>div]:pb-10">
{reviews.map((review, i) => (
<ReviewCard key={i} review={review} />
))}
</div>
</div>
</section>
);
}
import { Star, ThumbsUp, ThumbsDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Avatar, AvatarImage } from "@/components/ui/avatar";
import { ButtonGroup, ButtonGroupSeparator } from "@/components/ui/button-group";
interface ReviewCardProps {
customerName: string;
customerAvatar?: string;
rating: number;
reviewDate: string;
totalSpend: number;
totalReviews: number;
reviewText: string;
}
export const ReviewCard = ({ review }: { review: ReviewCardProps }) => {
const renderStars = () => {
return Array(5)
.fill("")
.map((_, i) =>
i < review.rating ? (
<Star key={i} className="size-4 fill-amber-500 text-amber-500 lg:size-5" />
) : (
<Star key={i} className="text-muted-foreground size-4 lg:size-5" />
)
);
};
return (
<div className="flex gap-4">
<Avatar className="size-12 rounded-none lg:size-20">
<AvatarImage
src={review.customerAvatar}
alt={review.customerName}
className="object-cover"
/>
</Avatar>
{/* Content */}
<div className="min-w-0 flex-1">
{/* Header */}
<div className="mb-3 flex items-start justify-between gap-4">
<div>
<h3 className="mb-1 font-semibold">{review.customerName}</h3>
<div className="text-muted-foreground flex gap-1 text-sm">
Total Spend: <span className="font-semibold">${review.totalSpend}</span>
</div>
</div>
<div className="flex flex-col items-end gap-2">
<div className="flex items-center gap-1">{renderStars()}</div>
<span className="text-muted-foreground text-sm whitespace-nowrap">
{review.reviewDate}
</span>
</div>
</div>
{/* Review Text */}
<p className="text-muted-foreground mb-4 leading-relaxed">{review.reviewText}</p>
{/* Actions */}
<div className="flex items-center gap-3">
<ButtonGroup>
<Button variant="secondary" size="sm">
<ThumbsUp />
</Button>
<ButtonGroupSeparator />
<Button variant="outline" size="icon-sm" disabled>
15
</Button>
</ButtonGroup>
<ButtonGroup>
<Button variant="secondary" size="sm">
<ThumbsDown />
</Button>
<ButtonGroupSeparator />
<Button variant="outline" size="icon-sm" disabled>
2
</Button>
</ButtonGroup>
</div>
</div>
</div>
);
};