From 579f57375c267e3ed2ff11f71215a198390fc8a6 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Sat, 19 Oct 2024 11:17:12 +0200 Subject: [PATCH 1/7] types: return empty reco array instead of undefined --- src/features/home/api/useHomeRecommendedOffers.ts | 5 +++-- .../home/components/modules/RecommendationModule.tsx | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/features/home/api/useHomeRecommendedOffers.ts b/src/features/home/api/useHomeRecommendedOffers.ts index 7f8ac66faf4..c2b310f9c26 100644 --- a/src/features/home/api/useHomeRecommendedOffers.ts +++ b/src/features/home/api/useHomeRecommendedOffers.ts @@ -53,7 +53,7 @@ export const useHomeRecommendedOffers = ( moduleId: string, recommendationParameters?: RecommendedOffersModule['recommendationParameters'], userId?: number -): { offers?: Offer[]; recommendationApiParams?: RecommendationApiParams } => { +): { offers: Offer[]; recommendationApiParams?: RecommendationApiParams } => { const subcategoryLabelMapping = useSubcategoryLabelMapping() const isFocused = useIsFocused() const requestParameters = getRecommendationParameters( @@ -72,7 +72,8 @@ export const useHomeRecommendedOffers = ( }) return { - offers: useAlgoliaRecommendedOffers(data?.playlistRecommendedOffers ?? [], moduleId, true), + offers: + useAlgoliaRecommendedOffers(data?.playlistRecommendedOffers ?? [], moduleId, true) || [], recommendationApiParams: data?.params, } } diff --git a/src/features/home/components/modules/RecommendationModule.tsx b/src/features/home/components/modules/RecommendationModule.tsx index 74ee4438470..a793293b7b7 100644 --- a/src/features/home/components/modules/RecommendationModule.tsx +++ b/src/features/home/components/modules/RecommendationModule.tsx @@ -42,7 +42,7 @@ export const RecommendationModule = (props: RecommendationModuleProps) => { recommendationParameters, profile?.id ) - const nbOffers = offers?.length ?? 0 + const nbOffers = offers.length ?? 0 const shouldModuleBeDisplayed = nbOffers > displayParameters.minOffers const moduleName = displayParameters.title @@ -58,7 +58,7 @@ export const RecommendationModule = (props: RecommendationModuleProps) => { moduleType: ContentTypes.RECOMMENDATION, index, homeEntryId, - offers: offers?.length ? offers.map((offer) => offer.objectID) : undefined, + offers: offers.length ? offers.map((offer) => offer.objectID) : undefined, }) } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -106,7 +106,7 @@ export const RecommendationModule = (props: RecommendationModuleProps) => { testID="recommendationModuleList" title={displayParameters.title} subtitle={displayParameters.subtitle} - data={offers ?? []} + data={offers} itemHeight={itemHeight} itemWidth={itemWidth} renderItem={renderItem} From bbef5ace9496caa9cb181f4bf0b290bc0c1c5b7d Mon Sep 17 00:00:00 2001 From: Tanguy Date: Sat, 19 Oct 2024 11:17:51 +0200 Subject: [PATCH 2/7] feat: add recoParams to CF adapter --- src/libs/contentful/adapters/modules/adaptOffersModule.ts | 5 ++++- src/libs/contentful/types.ts | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libs/contentful/adapters/modules/adaptOffersModule.ts b/src/libs/contentful/adapters/modules/adaptOffersModule.ts index c290fbf828f..30be398f4a0 100644 --- a/src/libs/contentful/adapters/modules/adaptOffersModule.ts +++ b/src/libs/contentful/adapters/modules/adaptOffersModule.ts @@ -1,5 +1,6 @@ import { HomepageModuleType, OffersModule } from 'features/home/types' import { buildOffersParams } from 'libs/contentful/adapters/helpers/buildOffersParams' +import { buildRecommendationParams } from 'libs/contentful/adapters/modules/adaptRecommendationModule' import { AlgoliaContentModel } from 'libs/contentful/types' export const adaptOffersModule = (module: AlgoliaContentModel): OffersModule | null => { @@ -8,7 +9,8 @@ export const adaptOffersModule = (module: AlgoliaContentModel): OffersModule | n if (module.fields.displayParameters.fields === undefined) return null const additionalAlgoliaParameters = module.fields.additionalAlgoliaParameters ?? [] - + const { recommendationParameters } = module.fields + const cleanRecommendationParameters = buildRecommendationParams(recommendationParameters) const offersList = buildOffersParams(module.fields.algoliaParameters, additionalAlgoliaParameters) if (offersList.length === 0) return null @@ -19,5 +21,6 @@ export const adaptOffersModule = (module: AlgoliaContentModel): OffersModule | n title: module.fields.title, displayParameters: module.fields.displayParameters.fields, offersModuleParameters: offersList, + recommendationParameters: cleanRecommendationParameters, } } diff --git a/src/libs/contentful/types.ts b/src/libs/contentful/types.ts index 607680b8b15..e1bcf9c228d 100644 --- a/src/libs/contentful/types.ts +++ b/src/libs/contentful/types.ts @@ -227,6 +227,7 @@ export interface AlgoliaFields { displayParameters: DisplayParameters cover?: Cover additionalAlgoliaParameters?: AlgoliaParameters[] + recommendationParameters?: RecommendationParameters } // Taken from https://app.contentful.com/spaces/2bg01iqy0isv/environments/testing/content_types/venuesPlaylist/fields From 2e1f87d46ab14753e451cf2c9299207caa69bec3 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Sat, 19 Oct 2024 11:18:46 +0200 Subject: [PATCH 3/7] feat: add reco offers ta algolia playlist when reco params are present --- .../home/components/modules/OffersModule.tsx | 48 ++++++++++++++++--- src/features/home/types.ts | 1 + .../modules/adaptRecommendationModule.ts | 2 +- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/features/home/components/modules/OffersModule.tsx b/src/features/home/components/modules/OffersModule.tsx index 75ed3940138..faa1a23f875 100644 --- a/src/features/home/components/modules/OffersModule.tsx +++ b/src/features/home/components/modules/OffersModule.tsx @@ -1,8 +1,13 @@ -import React, { useCallback, useEffect } from 'react' +import React, { useCallback, useEffect, useMemo } from 'react' import { useAuthContext } from 'features/auth/context/AuthContext' +import { useHomeRecommendedOffers } from 'features/home/api/useHomeRecommendedOffers' import { HomeOfferTile } from 'features/home/components/HomeOfferTile' -import { ModuleData, OffersModule as OffersModuleType } from 'features/home/types' +import { + ModuleData, + OffersModule as OffersModuleType, + RecommendedOffersModule, +} from 'features/home/types' import { getSearchStackConfig } from 'features/navigation/SearchStackNavigator/helpers' import { useAdaptOffersPlaylistParameters } from 'libs/algolia/fetchAlgolia/fetchMultipleOffers/helpers/useAdaptOffersPlaylistParameters' import { analytics } from 'libs/analytics' @@ -11,6 +16,7 @@ import { usePlaylistItemDimensionsFromLayout } from 'libs/contentful/usePlaylist import { useFeatureFlag } from 'libs/firebase/firestore/featureFlags/useFeatureFlag' import { RemoteStoreFeatureFlags } from 'libs/firebase/firestore/types' import useFunctionOnce from 'libs/hooks/useFunctionOnce' +import { useLocation } from 'libs/location' import { formatDates } from 'libs/parsers/formatDates' import { getDisplayPrice } from 'libs/parsers/getDisplayPrice' import { useCategoryHomeLabelMapping, useCategoryIdMapping } from 'libs/subcategories' @@ -26,17 +32,34 @@ export type OffersModuleProps = { index: number homeEntryId: string | undefined data: ModuleData | undefined + recommendationParameters?: RecommendedOffersModule['recommendationParameters'] } const keyExtractor = (item: Offer) => item.objectID export const OffersModule = (props: OffersModuleProps) => { const isNewOfferTileDisplayed = useFeatureFlag(RemoteStoreFeatureFlags.WIP_NEW_OFFER_TILE) - const { displayParameters, offersModuleParameters, index, moduleId, homeEntryId, data } = props + const { + displayParameters, + offersModuleParameters, + index, + moduleId, + homeEntryId, + data, + recommendationParameters, + } = props const adaptedPlaylistParameters = useAdaptOffersPlaylistParameters() const mapping = useCategoryIdMapping() const labelMapping = useCategoryHomeLabelMapping() const { user } = useAuthContext() + const { userLocation } = useLocation() + + const { offers: recommandationOffers, recommendationApiParams } = useHomeRecommendedOffers( + userLocation, + moduleId, + recommendationParameters, + user?.id + ) const { playlistItems, nbPlaylistResults } = data ?? { playlistItems: [], @@ -59,7 +82,11 @@ export const OffersModule = (props: OffersModuleProps) => { // @ts-expect-error: because of noUncheckedIndexedAccess const moduleName = displayParameters.title ?? parameters.title const logHasSeenAllTilesOnce = useFunctionOnce(() => - analytics.logAllTilesSeen({ moduleName, numberOfTiles: playlistItems.length }) + analytics.logAllTilesSeen({ + moduleName, + numberOfTiles: playlistItems.length, + apiRecoParams: props.recommendationParameters ? recommendationApiParams : undefined, + }) ) const showSeeMore = @@ -122,13 +149,22 @@ export const OffersModule = (props: OffersModuleProps) => { }, [onPressSeeMore, showSeeMore, searchTabConfig] ) + const hybridPlaylistItems = useMemo( + () => [...playlistItems, ...recommandationOffers], + [recommandationOffers, playlistItems] + ) + + const offersToDisplay = useMemo(() => { + return props.recommendationParameters ? hybridPlaylistItems : playlistItems + }, [hybridPlaylistItems, playlistItems, props.recommendationParameters]) const shouldModuleBeDisplayed = - playlistItems.length > 0 && playlistItems.length >= displayParameters.minOffers + offersToDisplay.length > 0 && offersToDisplay.length >= displayParameters.minOffers useEffect(() => { if (shouldModuleBeDisplayed) { analytics.logModuleDisplayedOnHomepage({ + call_id: props.recommendationParameters ? recommendationApiParams?.call_id : undefined, moduleId, moduleType: ContentTypes.ALGOLIA, index, @@ -146,7 +182,7 @@ export const OffersModule = (props: OffersModuleProps) => { testID="offersModuleList" title={displayParameters.title} subtitle={displayParameters.subtitle} - data={playlistItems} + data={offersToDisplay} itemHeight={itemHeight} itemWidth={itemWidth} onPressSeeMore={onPressSeeMore} diff --git a/src/features/home/types.ts b/src/features/home/types.ts index 0e0a66e06e5..189f3c043b1 100644 --- a/src/features/home/types.ts +++ b/src/features/home/types.ts @@ -115,6 +115,7 @@ export type OffersModule = { offersModuleParameters: OffersModuleParameters[] displayParameters: DisplayParameters data?: ModuleData + recommendationParameters?: RecommendedOffersParameters } type DisplayParameters = { diff --git a/src/libs/contentful/adapters/modules/adaptRecommendationModule.ts b/src/libs/contentful/adapters/modules/adaptRecommendationModule.ts index ae9f0faede9..5eb3620b6be 100644 --- a/src/libs/contentful/adapters/modules/adaptRecommendationModule.ts +++ b/src/libs/contentful/adapters/modules/adaptRecommendationModule.ts @@ -25,7 +25,7 @@ const mapMusicTypes = (recoMusicTypes: RecommendationParametersFields['musicType const mapShowTypes = (recoShowTypes: RecommendationParametersFields['showTypes']) => recoShowTypes?.fields?.showTypes -const buildRecommendationParams = ( +export const buildRecommendationParams = ( recommendationParams?: RecommendationParameters ): RecommendedOffersModule['recommendationParameters'] | undefined => { if (recommendationParams?.fields === undefined) return undefined From a1f4adca3f65de6ccd45668a27244877dd20da36 Mon Sep 17 00:00:00 2001 From: Tanguy Date: Sat, 19 Oct 2024 11:19:01 +0200 Subject: [PATCH 4/7] tests: update fixture --- src/features/home/fixtures/homepage.fixture.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/features/home/fixtures/homepage.fixture.ts b/src/features/home/fixtures/homepage.fixture.ts index d6c340377a3..05073da78b3 100644 --- a/src/features/home/fixtures/homepage.fixture.ts +++ b/src/features/home/fixtures/homepage.fixture.ts @@ -181,6 +181,7 @@ export const formattedOffersModule: OffersModule = { bookTypes: ['Carrière/Concours', 'Scolaire & Parascolaire', 'Gestion/entreprise'], }, ], + recommendationParameters: undefined, } export const formattedCategoryListModule: CategoryListModule = { From 8317fe906cebe29b91c070383b15fdb7bef34afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?In=C3=A8s=20Mouandjo=20Lob=C3=A9?= Date: Tue, 22 Oct 2024 09:45:56 +0200 Subject: [PATCH 5/7] Update snapshot --- scripts/noUncheckedIndexedAccess_snapshot.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/noUncheckedIndexedAccess_snapshot.txt b/scripts/noUncheckedIndexedAccess_snapshot.txt index 954925c4982..870318a4882 100644 --- a/scripts/noUncheckedIndexedAccess_snapshot.txt +++ b/scripts/noUncheckedIndexedAccess_snapshot.txt @@ -39,9 +39,9 @@ ./src/features/deeplinks/helpers/getScreenFromDeeplink.ts:24 ./src/features/home/api/helpers/mapVenuesDataAndModules.ts:13 ./src/features/home/api/helpers/mapVenuesDataAndModules.ts:15 -./src/features/home/components/modules/OffersModule.tsx:51 -./src/features/home/components/modules/OffersModule.tsx:59 -./src/features/home/components/modules/OffersModule.tsx:68 +./src/features/home/components/modules/OffersModule.tsx:74 +./src/features/home/components/modules/OffersModule.tsx:82 +./src/features/home/components/modules/OffersModule.tsx:95 ./src/features/home/components/modules/video/OldVideoModuleDesktop.tsx:96 ./src/features/home/components/modules/video/OldVideoModuleMobile.tsx:70 ./src/features/home/components/modules/video/VideoModuleDesktop.tsx:86 From 88d13b4b600ff778138ee6deb759673c1cdee25f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?In=C3=A8s=20Mouandjo=20Lob=C3=A9?= Date: Tue, 22 Oct 2024 13:37:14 +0200 Subject: [PATCH 6/7] attempt to fix coverage --- src/features/home/components/modules/RecommendationModule.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/home/components/modules/RecommendationModule.tsx b/src/features/home/components/modules/RecommendationModule.tsx index a793293b7b7..651405df2ec 100644 --- a/src/features/home/components/modules/RecommendationModule.tsx +++ b/src/features/home/components/modules/RecommendationModule.tsx @@ -42,7 +42,7 @@ export const RecommendationModule = (props: RecommendationModuleProps) => { recommendationParameters, profile?.id ) - const nbOffers = offers.length ?? 0 + const nbOffers = offers.length const shouldModuleBeDisplayed = nbOffers > displayParameters.minOffers const moduleName = displayParameters.title From bdd42d9f0c1951d8b2623837904444ea6d9e78a7 Mon Sep 17 00:00:00 2001 From: NolwenMajorFrances <144016890+NolwenMajorFrances@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:09:20 +0200 Subject: [PATCH 7/7] (PC-31746) tests(RecommendationModule): add test --- .../RecommendationModule.native.test.tsx | 23 +++++++++++++++---- .../modules/RecommendationModule.tsx | 2 +- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/features/home/components/modules/RecommendationModule.native.test.tsx b/src/features/home/components/modules/RecommendationModule.native.test.tsx index 0f7878fc367..16b752b631c 100644 --- a/src/features/home/components/modules/RecommendationModule.native.test.tsx +++ b/src/features/home/components/modules/RecommendationModule.native.test.tsx @@ -23,11 +23,13 @@ const defaultRecommendationApiParams: RecommendationApiParams = { reco_origin: 'unknown', } +const mockUseHomeRecommendedOffers = jest.fn().mockReturnValue({ + offers: mockedAlgoliaResponse.hits, + recommendationApiParams: defaultRecommendationApiParams, +}) + jest.mock('features/home/api/useHomeRecommendedOffers', () => ({ - useHomeRecommendedOffers: jest.fn(() => ({ - offers: mockedAlgoliaResponse.hits, - recommendationApiParams: defaultRecommendationApiParams, - })), + useHomeRecommendedOffers: () => mockUseHomeRecommendedOffers(), })) const useFeatureFlagSpy = jest.spyOn(useFeatureFlagAPI, 'useFeatureFlag').mockReturnValue(false) @@ -84,6 +86,19 @@ describe('RecommendationModule', () => { expect(analytics.logModuleDisplayedOnHomepage).not.toHaveBeenCalled() }) + + it('should not display RecommendationModule if no offer', async () => { + useFeatureFlagSpy.mockReturnValueOnce(true) + mockUseHomeRecommendedOffers.mockReturnValueOnce({ + offers: [], + recommendationApiParams: defaultRecommendationApiParams, + }) + renderRecommendationModule() + + await waitFor(() => { + expect(screen.toJSON()).toBeNull() + }) + }) }) const renderRecommendationModule = (additionalDisplayParams?: DisplayParametersFields) => diff --git a/src/features/home/components/modules/RecommendationModule.tsx b/src/features/home/components/modules/RecommendationModule.tsx index 651405df2ec..ab8973fab16 100644 --- a/src/features/home/components/modules/RecommendationModule.tsx +++ b/src/features/home/components/modules/RecommendationModule.tsx @@ -58,7 +58,7 @@ export const RecommendationModule = (props: RecommendationModuleProps) => { moduleType: ContentTypes.RECOMMENDATION, index, homeEntryId, - offers: offers.length ? offers.map((offer) => offer.objectID) : undefined, + offers: offers.map((offer) => offer.objectID), }) } // eslint-disable-next-line react-hooks/exhaustive-deps