1- // components/TeamSection.tsx
1+ // onboarding/ components/TeamSection.tsx
22"use client" ;
33
44import React , { useEffect , useState } from "react" ;
@@ -7,41 +7,37 @@ import { cn } from "@/lib/utils";
77// -------------------------
88// Types
99// -------------------------
10- type Person = {
11- name : string ;
12- role : string ;
13- image ?: string ;
14- } ;
15-
16- interface TeamResponse {
17- ADMINS ?: Person [ ] ;
18- MENTORS ?: Person [ ] ;
19- error ?: string ;
20- }
21-
22- // -------------------------
23- // CEO Fullname Reference
24- // -------------------------
25- const CEO_FULLNAME = "Jzeff Kendrew Somera" ; // <-- replace with actual first+last name from Supabase
10+ type Person = {
11+ name : string ;
12+ role : string ;
13+ image ?: string ;
14+ } ;
15+
16+ interface TeamResponse {
17+ ADMINS ?: Person [ ] ;
18+ MENTORS ?: Person [ ] ;
19+ CEO ?: Person | null ;
20+ error ?: string ;
21+ }
2622
2723// -------------------------
2824// Avatar
2925// -------------------------
30- function Avatar ( {
31- person,
32- size = 72 ,
33- position = "center top"
34- } : {
35- person : Person ;
36- size ?: number ;
37- position ?: string ;
38- } ) {
39- const initials = ( person . name || "" )
40- . split ( " " )
41- . slice ( 0 , 2 )
42- . map ( ( n ) => n [ 0 ] ?? "" )
43- . join ( "" )
44- . toUpperCase ( ) ;
26+ function Avatar ( {
27+ person,
28+ size = 72 ,
29+ position = "center top"
30+ } : {
31+ person : Person ;
32+ size ?: number ;
33+ position ?: string ;
34+ } ) {
35+ const initials = ( person . name || "" )
36+ . split ( " " )
37+ . slice ( 0 , 2 )
38+ . map ( ( n ) => n [ 0 ] ?? "" )
39+ . join ( "" )
40+ . toUpperCase ( ) ;
4541
4642 return person . image ? (
4743 < div
@@ -79,95 +75,85 @@ import { cn } from "@/lib/utils";
7975// -------------------------
8076// PersonCard
8177// -------------------------
82- function PersonCard ( { person } : { person : Person } ) {
83- return (
84- < div
85- className = { cn (
86- "group relative overflow-hidden rounded-2xl border" ,
87- "border-white/10 bg-white/[0.06] p-4 shadow-[0_10px_30px_-15px_rgba(0,0,0,0.6)] backdrop-blur-md" ,
88- "transition-all duration-300 hover:border-cyan-400/30 hover:shadow-cyan-500/20"
89- ) }
90- >
91- < div className = "flex items-center gap-3" >
92- < Avatar person = { person } size = { 56 } />
93- < div className = "min-w-0" >
94- < h4 className = "text-sm font-semibold text-white/90" > { person . name } </ h4 >
95- < p className = "truncate text-xs text-white/60" > { person . role } </ p >
96- </ div >
78+ function PersonCard ( { person } : { person : Person } ) {
79+ return (
80+ < div
81+ className = { cn (
82+ "group relative overflow-hidden rounded-2xl border" ,
83+ "border-white/10 bg-white/[0.06] p-4 shadow-[0_10px_30px_-15px_rgba(0,0,0,0.6)] backdrop-blur-md" ,
84+ "transition-all duration-300 hover:border-cyan-400/30 hover:shadow-cyan-500/20"
85+ ) }
86+ >
87+ < div className = "flex items-center gap-3" >
88+ < Avatar person = { person } size = { 56 } />
89+ < div className = "min-w-0" >
90+ < h4 className = "text-sm font-semibold text-white/90" > { person . name } </ h4 >
91+ < p className = "truncate text-xs text-white/60" > { person . role } </ p >
9792 </ div >
98- < span className = "pointer-events-none absolute inset-x-0 bottom-0 h-0.5 bg-gradient-to-r from-cyan-400 via-fuchsia-500 to-emerald-400 opacity-70" />
9993 </ div >
100- ) ;
101- }
94+ < span className = "pointer-events-none absolute inset-x-0 bottom-0 h-0.5 bg-gradient-to-r from-cyan-400 via-fuchsia-500 to-emerald-400 opacity-70" />
95+ </ div >
96+ ) ;
97+ }
10298
10399// -------------------------
104100// TeamSection
105101// -------------------------
106- export default function TeamSection ( ) {
107- const [ admins , setAdmins ] = useState < Person [ ] > ( [ ] ) ;
108- const [ mentors , setMentors ] = useState < Person [ ] > ( [ ] ) ;
109- const [ ceo , setCeo ] = useState < Person > ( {
110- name : "CEO Name" ,
111- role : "Founder / CEO" ,
112- image : ""
113- } ) ;
114- const [ loading , setLoading ] = useState ( true ) ;
115- const [ errMsg , setErrMsg ] = useState < string | null > ( null ) ;
116-
117- useEffect ( ( ) => {
118- let mounted = true ;
119- async function load ( ) {
120- setLoading ( true ) ;
121- setErrMsg ( null ) ;
122-
102+ export default function TeamSection ( ) {
103+ const [ admins , setAdmins ] = useState < Person [ ] > ( [ ] ) ;
104+ const [ mentors , setMentors ] = useState < Person [ ] > ( [ ] ) ;
105+ const [ ceo , setCeo ] = useState < Person > ( {
106+ name : "CEO Name" ,
107+ role : "Founder / CEO" ,
108+ image : ""
109+ } ) ;
110+ const [ loading , setLoading ] = useState ( true ) ;
111+ const [ errMsg , setErrMsg ] = useState < string | null > ( null ) ;
112+
113+ useEffect ( ( ) => {
114+ let mounted = true ;
115+ async function load ( ) {
116+ setLoading ( true ) ;
117+ setErrMsg ( null ) ;
118+
119+ try {
120+ const res = await fetch ( "/api/team" ) ;
121+
122+ let body : TeamResponse ;
123123 try {
124- const res = await fetch ( "/api/team" ) ;
125-
126- let body : TeamResponse ;
127- try {
128- body = ( await res . json ( ) ) as TeamResponse ;
129- } catch {
130- body = { } as TeamResponse ;
131- }
132-
133- if ( ! res . ok ) {
134- throw new Error ( body . error ?? `Fetch failed (${ res . status } )` ) ;
135- }
136-
137- if ( ! mounted ) return ;
138-
139- const adminsList = Array . isArray ( body . ADMINS ) ? body . ADMINS : [ ] ;
140- const mentorsList = Array . isArray ( body . MENTORS ) ? body . MENTORS : [ ] ;
141-
142- // Match CEO by full name in admins list
143- const foundCeo = adminsList . find (
144- ( p ) => p . name ?. trim ( ) . toLowerCase ( ) === CEO_FULLNAME . toLowerCase ( )
145- ) ;
146-
147- if ( foundCeo ) {
148- setCeo ( {
149- ...foundCeo ,
150- role : "Founder / CEO" // force CEO role
151- } ) ;
152- // Remove CEO from admins list so not duplicated
153- setAdmins ( adminsList . filter ( ( p ) => p !== foundCeo ) ) ;
154- } else {
155- setAdmins ( adminsList ) ;
156- }
157-
158- setMentors ( mentorsList ) ;
159- } catch ( err : any ) {
160- console . error ( "Error loading team:" , err ) ;
161- if ( mounted ) setErrMsg ( err ?. message ?? "Failed to load team" ) ;
162- } finally {
163- if ( mounted ) setLoading ( false ) ;
124+ body = ( await res . json ( ) ) as TeamResponse ;
125+ } catch {
126+ body = { } as TeamResponse ;
127+ }
128+
129+ if ( ! res . ok ) {
130+ throw new Error ( body . error ?? `Fetch failed (${ res . status } )` ) ;
164131 }
132+
133+ if ( ! mounted ) return ;
134+
135+ const adminsList = Array . isArray ( body . ADMINS ) ? body . ADMINS : [ ] ;
136+ const mentorsList = Array . isArray ( body . MENTORS ) ? body . MENTORS : [ ] ;
137+
138+ // Set CEO directly from API response
139+ if ( body . CEO ) {
140+ setCeo ( body . CEO ) ;
141+ }
142+
143+ setAdmins ( adminsList ) ;
144+ setMentors ( mentorsList ) ;
145+ } catch ( err : any ) {
146+ console . error ( "Error loading team:" , err ) ;
147+ if ( mounted ) setErrMsg ( err ?. message ?? "Failed to load team" ) ;
148+ } finally {
149+ if ( mounted ) setLoading ( false ) ;
165150 }
166- load ( ) ;
167- return ( ) => {
168- mounted = false ;
169- } ;
170- } , [ ] ) ;
151+ }
152+ load ( ) ;
153+ return ( ) => {
154+ mounted = false ;
155+ } ;
156+ } , [ ] ) ;
171157
172158 return (
173159 < section className = "relative w-full overflow-hidden bg-gradient-to-br from-zinc-900 via-zinc-950 to-black py-16 sm:py-20 lg:py-24" >
@@ -198,7 +184,7 @@ import { cn } from "@/lib/utils";
198184 < h3 className = "mb-4 text-center text-lg font-bold tracking-tight text-white/85" > Admins</ h3 >
199185 < div className = "grid grid-cols-1 gap-3 sm:grid-cols-2" >
200186 { admins . length > 0 ? (
201- admins . map ( ( p ) => < PersonCard key = { `${ p . name } -${ p . role } ` } person = { p } /> )
187+ admins . map ( ( p , idx ) => < PersonCard key = { `${ p . name } -${ idx } ` } person = { p } /> )
202188 ) : (
203189 < div className = "col-span-full text-center text-white/50" > No admins available</ div >
204190 ) }
@@ -220,7 +206,7 @@ import { cn } from "@/lib/utils";
220206 < h3 className = "mb-4 text-center text-lg font-bold tracking-tight text-white/85" > Mentors</ h3 >
221207 < div className = "grid grid-cols-1 gap-3 sm:grid-cols-2" >
222208 { mentors . length > 0 ? (
223- mentors . map ( ( p ) => < PersonCard key = { `${ p . name } -${ p . role } ` } person = { p } /> )
209+ mentors . map ( ( p , idx ) => < PersonCard key = { `${ p . name } -${ idx } ` } person = { p } /> )
224210 ) : (
225211 < div className = "col-span-full text-center text-white/50" > No mentors available</ div >
226212 ) }
0 commit comments