@@ -10,52 +10,100 @@ export interface ContentfulCarouselSlideFields {
10
10
undismissable : boolean ;
11
11
startDate ?: string ;
12
12
endDate ?: string ;
13
+ priorityPlacement ?: boolean ;
13
14
}
14
15
15
16
export type ContentfulSlideSkeleton =
16
17
EntrySkeletonType < ContentfulCarouselSlideFields > ;
17
18
18
- const space = process . env . FEATURES_ANNOUNCEMENTS_SPACE_ID ;
19
- const accessToken = process . env . FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN ;
20
- const environment = isProduction ( ) ? 'master' : 'dev' ;
21
- const contentType = 'promotionalBanner' ;
22
- const defaultDomain = isProduction ( )
19
+ const SPACE_ID = process . env . FEATURES_ANNOUNCEMENTS_SPACE_ID ;
20
+ const ACCESS_TOKEN = process . env . FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN ;
21
+ const ENVIRONMENT = isProduction ( ) ? 'master' : 'dev' ;
22
+ const CONTENT_TYPE = 'promotionalBanner' ;
23
+ const DEFAULT_DOMAIN = isProduction ( )
23
24
? 'cdn.contentful.com'
24
25
: 'preview.contentful.com' ;
25
- const host = `https://${ defaultDomain } /spaces/${ space } /environments/${ environment } /entries` ;
26
26
27
- if ( ! space || ! accessToken ) {
28
- throw new Error (
29
- 'Missing Contentful environment variables: CONTENTFUL_SPACE_ID or CONTENTFUL_ACCESS_TOKEN' ,
30
- ) ;
27
+ interface ContentfulSysField {
28
+ sys : { id : string } ;
31
29
}
32
30
33
- const contentfulClient = createClient ( {
34
- space,
35
- accessToken,
36
- environment,
37
- host,
38
- } ) ;
31
+ export async function fetchCarouselSlidesFromContentful ( ) : Promise < {
32
+ prioritySlides : CarouselSlide [ ] ;
33
+ regularSlides : CarouselSlide [ ] ;
34
+ } > {
35
+ if ( ! SPACE_ID || ! ACCESS_TOKEN ) {
36
+ console . warn (
37
+ 'Missing Contentful env variables: FEATURES_ANNOUNCEMENTS_SPACE_ID, FEATURES_ANNOUNCEMENTS_ACCESS_TOKEN.' ,
38
+ ) ;
39
+ return { prioritySlides : [ ] , regularSlides : [ ] } ;
40
+ }
39
41
40
- interface ContentfulSysField {
41
- sys : { id : string } ;
42
+ const host = `https://${ DEFAULT_DOMAIN } /spaces/${ SPACE_ID } /environments/${ ENVIRONMENT } /entries` ;
43
+
44
+ // First try through the Contentful Client
45
+ try {
46
+ const contentfulClient = createClient ( {
47
+ space : SPACE_ID ,
48
+ accessToken : ACCESS_TOKEN ,
49
+ environment : ENVIRONMENT ,
50
+ host,
51
+ } ) ;
52
+
53
+ const entries = await contentfulClient . getEntries ( {
54
+ content_type : CONTENT_TYPE ,
55
+ 'fields.showInMobile' : true , // Only banners marked for mobile
56
+ } ) ;
57
+ const { prioritySlides, regularSlides } = mapContentfulEntriesToSlides (
58
+ entries . items ,
59
+ entries . includes ?. Asset ?? [ ] ,
60
+ ) ;
61
+ return { prioritySlides, regularSlides } ;
62
+ } catch ( err ) {
63
+ // If the Contentful SDK fails, fall back to a direct fetch
64
+ console . warn ( 'Contentful SDK failed, falling back to direct fetch' , err ) ;
65
+ }
66
+ try {
67
+ const url = new URL ( `${ host } ` ) ;
68
+ url . searchParams . set ( 'access_token' , ACCESS_TOKEN ) ;
69
+ url . searchParams . set ( 'content_type' , CONTENT_TYPE ) ;
70
+ url . searchParams . set ( 'fields.showInMobile' , 'true' ) ;
71
+
72
+ const response = await fetch ( url . toString ( ) ) ;
73
+ const json = await response . json ( ) ;
74
+ const { prioritySlides, regularSlides } = mapContentfulEntriesToSlides (
75
+ json . items ,
76
+ json . includes ?. Asset ?? [ ] ,
77
+ ) ;
78
+ return { prioritySlides, regularSlides } ;
79
+ } catch ( fallbackError ) {
80
+ console . error (
81
+ '[fetchCarouselSlidesFromContentful] Fallback fetch failed:' ,
82
+ fallbackError ,
83
+ ) ;
84
+ return { prioritySlides : [ ] , regularSlides : [ ] } ;
85
+ }
42
86
}
43
87
44
- export async function fetchCarouselSlidesFromContentful ( ) : Promise <
45
- CarouselSlide [ ]
46
- > {
47
- const entries = await contentfulClient . getEntries ( {
48
- content_type : contentType ,
49
- 'fields.showInMobile' : true , // Only banners marked for mobile
50
- } ) ;
51
- const assets = ( entries . includes ?. Asset ?? [ ] ) as any [ ] ;
88
+ function mapContentfulEntriesToSlides (
89
+ items : any [ ] ,
90
+ assets : any [ ] ,
91
+ ) : { prioritySlides : CarouselSlide [ ] ; regularSlides : CarouselSlide [ ] } {
92
+ if ( ! items || ! Array . isArray ( items ) ) {
93
+ console . warn ( '[mapContentfulEntriesToSlides] Invalid items format:' , items ) ;
94
+ return { prioritySlides : [ ] , regularSlides : [ ] } ;
95
+ }
96
+
52
97
const resolveImage = ( imageRef : ContentfulSysField ) => {
53
98
const asset = assets . find ( ( a ) => a . sys . id === imageRef ?. sys ?. id ) ;
54
99
const rawUrl = asset ?. fields ?. file ?. url || '' ;
55
100
return rawUrl . startsWith ( '//' ) ? `https:${ rawUrl } ` : rawUrl ;
56
101
} ;
57
102
58
- return entries . items . map ( ( entry ) => {
103
+ const prioritySlides : CarouselSlide [ ] = [ ] ;
104
+ const regularSlides : CarouselSlide [ ] = [ ] ;
105
+
106
+ for ( const entry of items ) {
59
107
const {
60
108
headline,
61
109
teaser,
@@ -64,9 +112,10 @@ export async function fetchCarouselSlidesFromContentful(): Promise<
64
112
undismissable,
65
113
startDate,
66
114
endDate,
115
+ priorityPlacement,
67
116
} = entry . fields ;
68
117
69
- return {
118
+ const slide : CarouselSlide = {
70
119
id : `contentful-${ entry . sys . id } ` ,
71
120
title : headline ,
72
121
description : teaser ,
@@ -79,10 +128,18 @@ export async function fetchCarouselSlidesFromContentful(): Promise<
79
128
testID : `carousel_slide_${ entry . sys . id } ` ,
80
129
testIDTitle : `carousel_slide_title_${ entry . sys . id } ` ,
81
130
testIDCloseButton : `carousel_slide_close_${ entry . sys . id } ` ,
82
- startDate : startDate ,
83
- endDate : endDate ,
131
+ startDate,
132
+ endDate,
84
133
} ;
85
- } ) ;
134
+
135
+ if ( priorityPlacement ) {
136
+ prioritySlides . push ( slide ) ;
137
+ } else {
138
+ regularSlides . push ( slide ) ;
139
+ }
140
+ }
141
+
142
+ return { prioritySlides, regularSlides } ;
86
143
}
87
144
88
145
export function isActive (
0 commit comments