Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 1x 1x 16x 16x 15x 15x 15x 16x 16x 16x 16x 37x 16x 16x 16x 37x 37x 37x 37x 37x 37x 37x 37x 37x 25x 25x 125x 125x 125x 125x 112x 13x 125x 125x 25x 25x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 37x 24x 37x 37x 37x 24x 24x 24x 24x 24x 37x 37x 37x | 'use client';
import { useEffect, useRef } from 'react';
import { Star, Quote } from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { trackEvent } from '@/lib/analytics/track';
import { getInitials, stringToColor } from '@/lib/utils';
import type { Testimonial } from '@/types/database';
interface TestimonialListProps {
testimonials: Testimonial[];
profileId: string;
}
export function TestimonialList({ testimonials, profileId }: TestimonialListProps) {
const tracked = useRef(false);
// Track testimonial view when component is visible
useEffect(() => {
if (tracked.current) return;
tracked.current = true;
trackEvent(profileId, 'testimonial_view');
}, [profileId]);
return (
<div className="grid gap-4 sm:grid-cols-2">
{testimonials.map((testimonial) => (
<TestimonialCard key={testimonial.id} testimonial={testimonial} />
))}
</div>
);
}
function TestimonialCard({ testimonial }: { testimonial: Testimonial }) {
const initials = getInitials(testimonial.author_name);
const fallbackColor = stringToColor(testimonial.author_name);
return (
<Card className="h-full">
<CardContent className="p-6">
{/* Quote Icon */}
<Quote className="mb-4 h-8 w-8 text-primary/20" />
{/* Content */}
<p className="mb-4 text-muted-foreground">“{testimonial.content}”</p>
{/* Rating */}
{testimonial.rating && (
<div className="mb-4 flex gap-1">
{Array.from({ length: 5 }).map((_, i) => (
<Star
key={i}
className={`h-4 w-4 ${
i < testimonial.rating!
? 'fill-yellow-400 text-yellow-400'
: 'fill-muted text-muted'
}`}
/>
))}
</div>
)}
{/* Author */}
<div className="flex items-center gap-3">
<Avatar className="h-10 w-10">
<AvatarImage src={testimonial.author_avatar_url || undefined} />
<AvatarFallback
className="text-xs font-semibold text-white"
style={{ backgroundColor: fallbackColor }}
>
{initials}
</AvatarFallback>
</Avatar>
<div>
<p className="font-medium">{testimonial.author_name}</p>
{testimonial.author_title && (
<p className="text-sm text-muted-foreground">{testimonial.author_title}</p>
)}
</div>
</div>
{/* Source badge */}
{testimonial.source && (
<div className="mt-4">
<span className="inline-flex items-center rounded-full bg-muted px-2 py-1 text-xs text-muted-foreground">
via {testimonial.source}
</span>
</div>
)}
</CardContent>
</Card>
);
}
|