11'use client' ;
22
3+ import Link from 'next/link' ;
34import { Star } from 'lucide-react' ;
45
5- interface Testimonial {
6+ export interface Testimonial {
67 id : string ;
7- text : string ;
8+ clientId : string ;
9+ creatorId : string ;
10+ bountyId ?: string ;
11+ /** Display name of the client/author */
812 author : string ;
913 role : string ;
14+ quote : string ;
1015 rating : number ;
16+ featured : boolean ;
17+ createdAt : string ;
18+ creatorProfile ?: { name : string ; avatar ?: string ; slug : string } ;
19+ bountyTitle ?: string ;
20+ /** S3 URL for a video testimonial */
21+ videoUrl ?: string ;
1122}
1223
1324const testimonials : Testimonial [ ] = [
1425 {
1526 id : '1' ,
16- text : 'Stellar connected us with incredible designers who transformed our product. The process was seamless and professional.' ,
27+ clientId : 'client-001' ,
28+ creatorId : 'creator-001' ,
29+ bountyId : 'bounty-101' ,
1730 author : 'Sarah Chen' ,
1831 role : 'Product Manager, TechStartup' ,
32+ quote :
33+ 'Stellar connected us with incredible designers who transformed our product. The process was seamless and professional.' ,
1934 rating : 5 ,
35+ featured : true ,
36+ createdAt : '2024-11-12T10:00:00Z' ,
37+ bountyTitle : 'Dashboard UI Redesign' ,
38+ creatorProfile : { name : 'Alex Rivera' , slug : 'alex-rivera' } ,
2039 } ,
2140 {
2241 id : '2' ,
23- text : 'As a freelancer, this platform gave me access to high-quality projects and clients who truly value creative work.' ,
42+ clientId : 'client-002' ,
43+ creatorId : 'creator-002' ,
44+ bountyId : 'bounty-102' ,
2445 author : 'Marcus Johnson' ,
2546 role : 'UI/UX Designer' ,
47+ quote :
48+ 'As a freelancer, this platform gave me access to high-quality projects and clients who truly value creative work.' ,
2649 rating : 5 ,
50+ featured : true ,
51+ createdAt : '2024-12-01T14:30:00Z' ,
52+ bountyTitle : 'Mobile App Prototype' ,
53+ creatorProfile : { name : 'Jordan Kim' , slug : 'jordan-kim' } ,
54+ videoUrl : 'https://assets.stellar.app/testimonials/marcus-johnson.mp4' ,
2755 } ,
2856 {
2957 id : '3' ,
30- text : 'The bounty system is revolutionary. We found the perfect content creator for our campaign in days, not weeks.' ,
58+ clientId : 'client-003' ,
59+ creatorId : 'creator-003' ,
60+ bountyId : 'bounty-103' ,
3161 author : 'Emily Rodriguez' ,
3262 role : 'Marketing Director, GrowthCo' ,
63+ quote :
64+ 'The bounty system is revolutionary. We found the perfect content creator for our campaign in days, not weeks.' ,
3365 rating : 5 ,
66+ featured : true ,
67+ createdAt : '2025-01-08T09:15:00Z' ,
68+ bountyTitle : 'Brand Campaign Content' ,
69+ creatorProfile : { name : 'Sam Okafor' , slug : 'sam-okafor' } ,
3470 } ,
3571] ;
3672
37- export function TestimonialsSection ( ) {
73+ /** Initials avatar fallback */
74+ function InitialsAvatar ( { name } : { name : string } ) {
75+ const initials = name
76+ . split ( ' ' )
77+ . map ( ( w ) => w [ 0 ] )
78+ . slice ( 0 , 2 )
79+ . join ( '' )
80+ . toUpperCase ( ) ;
81+ return (
82+ < span className = "inline-flex items-center justify-center w-10 h-10 rounded-full bg-accent/20 text-accent font-semibold text-sm select-none" >
83+ { initials }
84+ </ span >
85+ ) ;
86+ }
87+
88+ function CaseStudyCard ( { testimonial } : { testimonial : Testimonial } ) {
89+ return (
90+ < div className = "flex flex-col bg-card border border-border rounded-lg p-8 hover:shadow-lg transition-all duration-300 hover:-translate-y-1" >
91+ { /* Rating */ }
92+ < div className = "flex gap-1 mb-4" >
93+ { Array . from ( { length : 5 } ) . map ( ( _ , i ) => (
94+ < Star
95+ key = { i }
96+ size = { 18 }
97+ className = { i < testimonial . rating ? 'fill-accent text-accent' : 'text-muted-foreground' }
98+ />
99+ ) ) }
100+ </ div >
101+
102+ { /* Quote */ }
103+ < p className = "text-foreground mb-4 italic leading-relaxed flex-1" >
104+ “{ testimonial . quote } ”
105+ </ p >
106+
107+ { /* Optional video testimonial */ }
108+ { testimonial . videoUrl && (
109+ < div className = "mb-4 rounded-md overflow-hidden border border-border" >
110+ < video
111+ src = { testimonial . videoUrl }
112+ controls
113+ muted
114+ playsInline
115+ className = "w-full max-h-48 object-cover"
116+ aria-label = { `Video testimonial from ${ testimonial . author } ` }
117+ />
118+ </ div >
119+ ) }
120+
121+ { /* Author */ }
122+ < div className = "flex items-center gap-3 mb-4" >
123+ < InitialsAvatar name = { testimonial . author } />
124+ < div >
125+ < p className = "font-semibold text-foreground leading-tight" > { testimonial . author } </ p >
126+ < p className = "text-sm text-muted-foreground" > { testimonial . role } </ p >
127+ </ div >
128+ </ div >
129+
130+ { /* Links */ }
131+ < div className = "flex flex-wrap gap-3 text-sm mt-auto" >
132+ { testimonial . creatorProfile && (
133+ < Link
134+ href = { `/creators/${ testimonial . creatorProfile . slug } ` }
135+ className = "text-accent hover:underline font-medium"
136+ >
137+ View creator →
138+ </ Link >
139+ ) }
140+ { testimonial . bountyId && (
141+ < Link
142+ href = { `/bounties/${ testimonial . bountyId } ` }
143+ className = "text-muted-foreground hover:text-foreground hover:underline"
144+ >
145+ View bounty →
146+ </ Link >
147+ ) }
148+ </ div >
149+ </ div >
150+ ) ;
151+ }
152+
153+ interface TestimonialsSectionProps {
154+ featuredOnly ?: boolean ;
155+ }
156+
157+ export function TestimonialsSection ( { featuredOnly = true } : TestimonialsSectionProps ) {
158+ const displayed = featuredOnly
159+ ? testimonials . filter ( ( t ) => t . featured )
160+ : testimonials ;
161+
38162 return (
39163 < section className = "py-20 sm:py-32 bg-muted/30 border-b border-border" >
40164 < div className = "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8" >
41165 { /* Section Header */ }
42166 < div className = "text-center mb-16" >
43167 < h2 className = "text-3xl sm:text-4xl md:text-5xl font-bold text-foreground mb-4" >
44- Loved by Creators & Clients
168+ Loved by Creators & Clients
45169 </ h2 >
46170 < p className = "text-lg text-muted-foreground max-w-2xl mx-auto" >
47171 See what industry leaders are saying about Stellar
@@ -50,29 +174,8 @@ export function TestimonialsSection() {
50174
51175 { /* Testimonials Grid */ }
52176 < div className = "grid grid-cols-1 md:grid-cols-3 gap-8" >
53- { testimonials . map ( ( testimonial ) => (
54- < div
55- key = { testimonial . id }
56- className = "bg-card border border-border rounded-lg p-8 hover:shadow-lg transition-all duration-300 hover:-translate-y-1"
57- >
58- { /* Rating */ }
59- < div className = "flex gap-1 mb-4" >
60- { Array . from ( { length : testimonial . rating } ) . map ( ( _ , i ) => (
61- < Star key = { i } size = { 18 } className = "fill-accent text-accent" />
62- ) ) }
63- </ div >
64-
65- { /* Quote */ }
66- < p className = "text-foreground mb-6 italic leading-relaxed" >
67- "{ testimonial . text } "
68- </ p >
69-
70- { /* Author */ }
71- < div >
72- < p className = "font-semibold text-foreground" > { testimonial . author } </ p >
73- < p className = "text-sm text-muted-foreground" > { testimonial . role } </ p >
74- </ div >
75- </ div >
177+ { displayed . map ( ( testimonial ) => (
178+ < CaseStudyCard key = { testimonial . id } testimonial = { testimonial } />
76179 ) ) }
77180 </ div >
78181 </ div >
0 commit comments