@@ -20,106 +20,151 @@ export type TeamMember = {
2020 tShirtAdditionalInfo : string | null
2121}
2222
23+ function mapProfile ( m : any ) : TeamMember {
24+ return {
25+ id : m . id ,
26+ avatarUrl : m . attributes ?. avatar ?. data ?. attributes ?. url || null ,
27+ color : m . attributes ?. color || null ,
28+ firstName : m . attributes ?. firstName || null ,
29+ lastName : m . attributes ?. lastName || null ,
30+ companyRole : m . attributes ?. companyRole || null ,
31+ location : m . attributes ?. location || null ,
32+ country : m . attributes ?. country || null ,
33+ teams : ( m . attributes ?. teams ?. data || [ ] ) . map ( ( t : any ) => t . attributes ?. name ) ,
34+ leadsTeams : ( m . attributes ?. leadTeams ?. data || [ ] ) . map ( ( t : any ) => t . attributes ?. name ) ,
35+ pineappleOnPizza : m . attributes ?. pineappleOnPizza ?? null ,
36+ startDate : m . attributes ?. startDate || null ,
37+ tShirtFit : m . attributes ?. tShirt ?. fit || null ,
38+ tShirtSize : m . attributes ?. tShirt ?. size || null ,
39+ tShirtAdditionalInfo : m . attributes ?. tShirt ?. additionalInfo || null ,
40+ }
41+ }
42+
43+ async function fetchPaginated (
44+ url : string ,
45+ headers : HeadersInit ,
46+ filters : Record < string , any > ,
47+ populate : Record < string , any > ,
48+ sort : string [ ]
49+ ) : Promise < any [ ] | null > {
50+ const allData : any [ ] = [ ]
51+ let page = 1
52+ let pageCount = 1
53+
54+ while ( page <= pageCount ) {
55+ const query = qs . stringify (
56+ { populate, filters, pagination : { page, pageSize : 100 } , sort } ,
57+ { encodeValuesOnly : true }
58+ )
59+ const res = await fetch ( `${ url } ?${ query } ` , { headers } )
60+ if ( ! res . ok ) return null
61+
62+ const { data, meta } = await res . json ( )
63+ if ( ! data ) return null
64+
65+ allData . push ( ...data )
66+ pageCount = meta ?. pagination ?. pageCount || 1
67+ page ++
68+ }
69+
70+ return allData
71+ }
72+
2373export function useTeamMembers ( ) {
2474 const { getJwt } = useUser ( )
2575 const [ teamMembers , setTeamMembers ] = useState < TeamMember [ ] > ( [ ] )
76+ const [ futureJoiners , setFutureJoiners ] = useState < TeamMember [ ] > ( [ ] )
2677 const [ loading , setLoading ] = useState ( true )
2778
2879 useEffect ( ( ) => {
29- const fetchTeamMembers = async ( ) => {
80+ const fetchAll = async ( ) => {
3081 try {
3182 const token = await getJwt ( )
3283 const headers : HeadersInit = token ? { Authorization : `Bearer ${ token } ` } : { }
33-
34- const allData : any [ ] = [ ]
35- let page = 1
36- let pageCount = 1
37-
38- while ( page <= pageCount ) {
39- const query = qs . stringify (
40- {
41- populate : {
42- avatar : { fields : [ 'url' ] } ,
43- teams : { fields : [ 'name' ] } ,
44- leadTeams : { fields : [ 'name' ] } ,
45- tShirt : true ,
46- } ,
47- filters : {
48- teams : { id : { $notNull : true } } ,
49- id : { $ne : 28378 } ,
50- } ,
51- pagination : { page, pageSize : 100 } ,
52- sort : [ 'startDate:asc' ] ,
53- } ,
54- { encodeValuesOnly : true }
55- )
56-
57- const res = await fetch ( `${ process . env . GATSBY_SQUEAK_API_HOST } /api/profiles?${ query } ` , { headers } )
58- if ( ! res . ok ) {
59- console . error ( 'Failed to fetch team members' , res . status )
60- setLoading ( false )
61- return
62- }
63-
64- const { data, meta } = await res . json ( )
65- if ( ! data ) {
66- setLoading ( false )
67- return
68- }
69-
70- allData . push ( ...data )
71- pageCount = meta ?. pagination ?. pageCount || 1
72- page ++
84+ const apiUrl = `${ process . env . GATSBY_SQUEAK_API_HOST } /api/profiles`
85+ const populate = {
86+ avatar : { fields : [ 'url' ] } ,
87+ teams : { fields : [ 'name' ] } ,
88+ leadTeams : { fields : [ 'name' ] } ,
89+ tShirt : true ,
7390 }
7491
75- const members : TeamMember [ ] = allData . map ( ( m : any ) => ( {
76- id : m . id ,
77- avatarUrl : m . attributes ?. avatar ?. data ?. attributes ?. url || null ,
78- color : m . attributes ?. color || null ,
79- firstName : m . attributes ?. firstName || null ,
80- lastName : m . attributes ?. lastName || null ,
81- companyRole : m . attributes ?. companyRole || null ,
82- location : m . attributes ?. location || null ,
83- country : m . attributes ?. country || null ,
84- teams : ( m . attributes ?. teams ?. data || [ ] ) . map ( ( t : any ) => t . attributes ?. name ) ,
85- leadsTeams : ( m . attributes ?. leadTeams ?. data || [ ] ) . map ( ( t : any ) => t . attributes ?. name ) ,
86- pineappleOnPizza : m . attributes ?. pineappleOnPizza ?? null ,
87- startDate : m . attributes ?. startDate || null ,
88- tShirtFit : m . attributes ?. tShirt ?. fit || null ,
89- tShirtSize : m . attributes ?. tShirt ?. size || null ,
90- tShirtAdditionalInfo : m . attributes ?. tShirt ?. additionalInfo || null ,
91- } ) )
92+ const today = new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ]
93+ const isFuture = ( m : TeamMember ) => m . startDate != null && m . startDate > today
94+
95+ const [ teamData , futureData ] = await Promise . all ( [
96+ fetchPaginated (
97+ apiUrl ,
98+ headers ,
99+ { teams : { id : { $notNull : true } } , id : { $ne : 28378 } } ,
100+ populate ,
101+ [ 'startDate:asc' ]
102+ ) ,
103+ fetchPaginated ( apiUrl , headers , { startDate : { $gt : today } , id : { $ne : 28378 } } , populate , [
104+ 'startDate:asc' ,
105+ ] ) ,
106+ ] )
107+
108+ const allWithTeams = ( teamData || [ ] ) . map ( mapProfile )
109+ const members = allWithTeams . filter ( ( m ) => ! isFuture ( m ) )
110+
111+ const futureFromTeams = allWithTeams . filter ( isFuture )
112+ const futureWithoutTeams = ( futureData || [ ] ) . map ( mapProfile )
113+ const seenIds = new Set ( futureFromTeams . map ( ( m ) => m . id ) )
114+ const joiners = [ ...futureFromTeams , ...futureWithoutTeams . filter ( ( m ) => ! seenIds . has ( m . id ) ) ]
92115
93116 setTeamMembers ( members )
117+ setFutureJoiners ( joiners )
94118 setLoading ( false )
95119 } catch ( err ) {
96120 console . error ( 'Failed to fetch team members' , err )
97121 setLoading ( false )
98122 }
99123 }
100124
101- fetchTeamMembers ( )
125+ fetchAll ( )
102126 } , [ ] )
103127
104- const updateProfile = async ( profileId : number , updates : Partial < TeamMember > ) => {
128+ const updateProfile = async ( profileId : number , updates : Partial < TeamMember > ) : Promise < boolean > => {
105129 const token = await getJwt ( )
106- if ( ! token ) return
130+ if ( ! token ) return false
107131
132+ const current = teamMembers . find ( ( m ) => m . id === profileId ) || futureJoiners . find ( ( m ) => m . id === profileId )
108133 setTeamMembers ( ( prev ) => prev . map ( ( m ) => ( m . id === profileId ? { ...m , ...updates } : m ) ) )
134+ setFutureJoiners ( ( prev ) => prev . map ( ( m ) => ( m . id === profileId ? { ...m , ...updates } : m ) ) )
135+
136+ const apiData : Record < string , any > = { }
137+ const hasTShirtField = 'tShirtFit' in updates || 'tShirtSize' in updates || 'tShirtAdditionalInfo' in updates
138+ if ( hasTShirtField ) {
139+ apiData . tShirt = {
140+ fit : current ?. tShirtFit ?? null ,
141+ size : current ?. tShirtSize ?? null ,
142+ additionalInfo : current ?. tShirtAdditionalInfo ?? null ,
143+ }
144+ if ( 'tShirtFit' in updates ) apiData . tShirt . fit = updates . tShirtFit
145+ if ( 'tShirtSize' in updates ) apiData . tShirt . size = updates . tShirtSize
146+ if ( 'tShirtAdditionalInfo' in updates ) apiData . tShirt . additionalInfo = updates . tShirtAdditionalInfo
147+ }
148+ for ( const [ key , value ] of Object . entries ( updates ) ) {
149+ if ( key === 'tShirtFit' || key === 'tShirtSize' || key === 'tShirtAdditionalInfo' ) continue
150+ apiData [ key ] = value
151+ }
109152
110153 try {
111- await fetch ( `${ process . env . GATSBY_SQUEAK_API_HOST } /api/profiles/${ profileId } ` , {
154+ const res = await fetch ( `${ process . env . GATSBY_SQUEAK_API_HOST } /api/profiles/${ profileId } ` , {
112155 method : 'PUT' ,
113- body : JSON . stringify ( { data : updates } ) ,
156+ body : JSON . stringify ( { data : apiData } ) ,
114157 headers : {
115158 'Content-Type' : 'application/json' ,
116159 Authorization : `Bearer ${ token } ` ,
117160 } ,
118161 } )
162+ return res . ok
119163 } catch ( err ) {
120164 console . error ( 'Failed to update profile' , err )
165+ return false
121166 }
122167 }
123168
124- return { teamMembers, loading, updateProfile }
169+ return { teamMembers, futureJoiners , loading, updateProfile }
125170}
0 commit comments