Skip to content

Commit 607b12b

Browse files
committed
addressed comments
1 parent b0692ec commit 607b12b

File tree

2 files changed

+108
-37
lines changed

2 files changed

+108
-37
lines changed

app/components/UI/Carousel/fetchCarouselSlidesFromContentful.ts

Lines changed: 88 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,52 +10,100 @@ export interface ContentfulCarouselSlideFields {
1010
undismissable: boolean;
1111
startDate?: string;
1212
endDate?: string;
13+
priorityPlacement?: boolean;
1314
}
1415

1516
export type ContentfulSlideSkeleton =
1617
EntrySkeletonType<ContentfulCarouselSlideFields>;
1718

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()
2324
? 'cdn.contentful.com'
2425
: 'preview.contentful.com';
25-
const host = `https://${defaultDomain}/spaces/${space}/environments/${environment}/entries`;
2626

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 };
3129
}
3230

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+
}
3941

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+
}
4286
}
4387

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+
5297
const resolveImage = (imageRef: ContentfulSysField) => {
5398
const asset = assets.find((a) => a.sys.id === imageRef?.sys?.id);
5499
const rawUrl = asset?.fields?.file?.url || '';
55100
return rawUrl.startsWith('//') ? `https:${rawUrl}` : rawUrl;
56101
};
57102

58-
return entries.items.map((entry) => {
103+
const prioritySlides: CarouselSlide[] = [];
104+
const regularSlides: CarouselSlide[] = [];
105+
106+
for (const entry of items) {
59107
const {
60108
headline,
61109
teaser,
@@ -64,9 +112,10 @@ export async function fetchCarouselSlidesFromContentful(): Promise<
64112
undismissable,
65113
startDate,
66114
endDate,
115+
priorityPlacement,
67116
} = entry.fields;
68117

69-
return {
118+
const slide: CarouselSlide = {
70119
id: `contentful-${entry.sys.id}`,
71120
title: headline,
72121
description: teaser,
@@ -79,10 +128,18 @@ export async function fetchCarouselSlidesFromContentful(): Promise<
79128
testID: `carousel_slide_${entry.sys.id}`,
80129
testIDTitle: `carousel_slide_title_${entry.sys.id}`,
81130
testIDCloseButton: `carousel_slide_close_${entry.sys.id}`,
82-
startDate: startDate,
83-
endDate: endDate,
131+
startDate,
132+
endDate,
84133
};
85-
});
134+
135+
if (priorityPlacement) {
136+
prioritySlides.push(slide);
137+
} else {
138+
regularSlides.push(slide);
139+
}
140+
}
141+
142+
return { prioritySlides, regularSlides };
86143
}
87144

88145
export function isActive(

app/components/UI/Carousel/index.tsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ const MAX_CAROUSEL_SLIDES = 15;
4242
const CarouselComponent: FC<CarouselProps> = ({ style }) => {
4343
const [selectedIndex, setSelectedIndex] = useState(0);
4444
const [pressedSlideId, setPressedSlideId] = useState<string | null>(null);
45-
const [fetchedSlides, setFetchedSlides] = useState<CarouselSlide[]>([]);
45+
const [priorityContentfulSlides, setPriorityContentfulSlides] = useState<
46+
CarouselSlide[]
47+
>([]);
48+
const [regularContentfulSlides, setRegularContentfulSlides] = useState<
49+
CarouselSlide[]
50+
>([]);
4651
const isContentfulCarouselEnabled = useSelector(
4752
selectContentfulCarouselEnabledFlag,
4853
);
@@ -67,9 +72,14 @@ const CarouselComponent: FC<CarouselProps> = ({ style }) => {
6772
const loadContentfulSlides = async () => {
6873
if (!isContentfulCarouselEnabled) return;
6974
try {
70-
const remoteSlides = await fetchCarouselSlidesFromContentful();
71-
const activeSlides = remoteSlides.filter((slide) => isActive(slide));
72-
setFetchedSlides(activeSlides);
75+
const { prioritySlides, regularSlides } =
76+
await fetchCarouselSlidesFromContentful();
77+
setPriorityContentfulSlides(
78+
prioritySlides.filter((slides) => isActive(slides)),
79+
);
80+
setRegularContentfulSlides(
81+
regularSlides.filter((slides) => isActive(slides)),
82+
);
7383
} catch (err) {
7484
console.warn('Failed to fetch Contentful slides:', err);
7585
}
@@ -79,7 +89,11 @@ const CarouselComponent: FC<CarouselProps> = ({ style }) => {
7989

8090
// Merge all slides (predefined + contentful),
8191
const slidesConfig = useMemo(() => {
82-
const baseSlides = [...PREDEFINED_SLIDES, ...fetchedSlides];
92+
const baseSlides = [
93+
...priorityContentfulSlides,
94+
...PREDEFINED_SLIDES,
95+
...regularContentfulSlides,
96+
];
8397
return baseSlides.map((slide) => {
8498
if (slide.id === 'fund' && isZeroBalance) {
8599
return {
@@ -92,7 +106,7 @@ const CarouselComponent: FC<CarouselProps> = ({ style }) => {
92106
undismissable: false,
93107
};
94108
});
95-
}, [isZeroBalance, fetchedSlides]);
109+
}, [isZeroBalance, priorityContentfulSlides, regularContentfulSlides]);
96110

97111
const visibleSlides = useMemo(() => {
98112
const filtered = slidesConfig.filter((slide: CarouselSlide) => {

0 commit comments

Comments
 (0)