@@ -46,6 +46,23 @@ function determineNewsletter(element: Record<string, any> | null): string | null
4646 return null ;
4747}
4848
49+ // Human labels for the category slugs. These map the values stored in Strapi
50+ // (the `resource_type`/`newsletter` enums, or the `tags` field while those
51+ // enums aren't deployed yet) to what is shown in the filter pills and cards.
52+ const TYPE_LABELS : Record < string , string > = {
53+ podcast : 'Podcast' ,
54+ article : 'Article' ,
55+ rapport : 'Rapport' ,
56+ prise_de_position : 'Prise de position' ,
57+ autre : 'Autre' ,
58+ } ;
59+ const NEWSLETTER_LABELS : Record < string , string > = {
60+ techno_lucides : 'Techno-lucides' ,
61+ vers_lautonomie : "Vers l'autonomie et au-delà" ,
62+ } ;
63+ const TYPE_SLUGS = Object . keys ( TYPE_LABELS ) ;
64+ const NEWSLETTER_SLUGS = Object . keys ( NEWSLETTER_LABELS ) ;
65+
4966interface TransformedResource {
5067 id : number | undefined ;
5168 title : string ;
@@ -57,7 +74,7 @@ interface TransformedResource {
5774 tags : string [ ] ;
5875 isBlank : boolean ;
5976 year : number ;
60- type : string ;
77+ types : string [ ] ;
6178 newsletter : string | null ;
6279}
6380
@@ -68,6 +85,19 @@ function transformBlogsData(resources: NonNullable<BlogsPageData>): TransformedR
6885
6986 const tagStrings = getTagsAsStrings ( element ?. tags ) ;
7087
88+ // Categories are read, in priority order, from: the structured Strapi enum
89+ // (once deployed), then the `tags` field (where editors currently store the
90+ // slugs), then a best-effort heuristic. A resource can hold several types
91+ // (e.g. a "communiqué" that is both article and prise de position), so types
92+ // is a list; newsletter is single.
93+ const tagTypeSlugs = tagStrings . filter ( tag => TYPE_SLUGS . includes ( tag ) ) ;
94+ const types = element ?. resource_type
95+ ? [ element . resource_type ]
96+ : ( tagTypeSlugs . length > 0 ? tagTypeSlugs : [ determineType ( element ) ] ) ;
97+ const newsletter = element ?. newsletter
98+ ?? tagStrings . find ( tag => NEWSLETTER_SLUGS . includes ( tag ) )
99+ ?? determineNewsletter ( element ) ;
100+
71101 const publishedDate = element ?. published_date ?? '' ;
72102 const parsedDate = new Date ( publishedDate ) ;
73103 const isValidDate = ! isNaN ( parsedDate . getTime ( ) ) ;
@@ -79,17 +109,16 @@ function transformBlogsData(resources: NonNullable<BlogsPageData>): TransformedR
79109 date : isValidDate ? parsedDate . toLocaleString ( undefined , { dateStyle : 'medium' } ) : '' ,
80110 image : element ?. thumbnail ?. url ?? '/images/dataforgood.svg' ,
81111 link : isBlog ? `/blog/${ element ?. slug ?? '' } ` : getPressReleaseLink ( element as any ) ,
82- subInfos : tagStrings ,
112+ // Show category slugs with their human labels; keep any other free tag as-is.
113+ subInfos : tagStrings . map ( tag => TYPE_LABELS [ tag ] ?? NEWSLETTER_LABELS [ tag ] ?? tag ) ,
83114 tags : [
84115 isValidDate ? parsedDate . toLocaleDateString ( undefined , { dateStyle : 'long' } ) : null ,
85116 element ?. media_name ,
86117 ] . filter ( Boolean ) ,
87118 isBlank : true ,
88119 year : isValidDate ? parsedDate . getFullYear ( ) : 0 ,
89- // `resource_type`/`newsletter` are the source of truth once set in Strapi;
90- // fall back to a best-effort guess for rows not yet categorized by editors.
91- type : element ?. resource_type ?? determineType ( element ) ,
92- newsletter : element ?. newsletter ?? determineNewsletter ( element ) ,
120+ types,
121+ newsletter,
93122 } ;
94123 } ) ;
95124}
@@ -139,7 +168,7 @@ export default function BlogPage({data, pagination: _pagination}: BlogsPageProps
139168 } ) ) {
140169 return false ;
141170 }
142- if ( activeTypes . length > 0 && ! activeTypes . includes ( resource . type ) ) {
171+ if ( activeTypes . length > 0 && ! activeTypes . some ( t => resource . types . includes ( t ) ) ) {
143172 return false ;
144173 }
145174 if ( activeNewsletters . length > 0 ) {
@@ -203,18 +232,8 @@ export default function BlogPage({data, pagination: _pagination}: BlogsPageProps
203232 { filterName : '2026' , filterValue : '2026' } ,
204233 ] ;
205234
206- const typeFilters = [
207- { filterName : 'Podcast' , filterValue : 'podcast' } ,
208- { filterName : 'Article' , filterValue : 'article' } ,
209- { filterName : 'Rapport' , filterValue : 'rapport' } ,
210- { filterName : 'Prise de position' , filterValue : 'prise_de_position' } ,
211- { filterName : 'Autre' , filterValue : 'autre' } ,
212- ] ;
213-
214- const newsletterFilters = [
215- { filterName : 'Techno-lucides' , filterValue : 'techno_lucides' } ,
216- { filterName : "Vers l'autonomie et au-delà" , filterValue : 'vers_lautonomie' } ,
217- ] ;
235+ const typeFilters = TYPE_SLUGS . map ( slug => ( { filterName : TYPE_LABELS [ slug ] , filterValue : slug } ) ) ;
236+ const newsletterFilters = NEWSLETTER_SLUGS . map ( slug => ( { filterName : NEWSLETTER_LABELS [ slug ] , filterValue : slug } ) ) ;
218237
219238 const allActiveFilterValues = [ ...activeYears , ...activeTypes , ...activeNewsletters ] ;
220239
0 commit comments