Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(PC-34400) feat(headlineOffer): handle headline offer from Algolia #7648

Merged
merged 7 commits into from
Feb 11, 2025
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -5596,7 +5596,7 @@ exports[`<Venue /> should match snapshot with headline offer 1`] = `
resizeMode="cover"
source={
{
"uri": "https://storage.googleapis.com/passculture-metier-prod-production-assets-fine-grained/thumbs/mediations/CDNQ",
"uri": "https://storage.googleapis.com/passculture-metier-ehp-testing-assets/thumbs/products/FARMG",
}
}
style={
Expand Down Expand Up @@ -5736,7 +5736,7 @@ exports[`<Venue /> should match snapshot with headline offer 1`] = `
size="small"
source={
{
"uri": "https://storage.googleapis.com/passculture-metier-prod-production-assets-fine-grained/thumbs/mediations/CDNQ",
"uri": "https://storage.googleapis.com/passculture-metier-ehp-testing-assets/thumbs/products/FARMG",
}
}
style={
Expand Down Expand Up @@ -5786,7 +5786,7 @@ exports[`<Venue /> should match snapshot with headline offer 1`] = `
]
}
>
Livre
Cinéma
</Text>
<Text
numberOfLines={2}
Expand All @@ -5801,7 +5801,7 @@ exports[`<Venue /> should match snapshot with headline offer 1`] = `
]
}
>
La nuit des temps
Titane - VF
</Text>
<Text
style={
Expand All @@ -5815,7 +5815,7 @@ exports[`<Venue /> should match snapshot with headline offer 1`] = `
]
}
>
Dès 28 €
Gratuit
</Text>
</View>
</View>
Expand Down
13 changes: 0 additions & 13 deletions src/api/useSearchVenuesOffer/useSearchVenueOffers.native.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,19 +116,6 @@ describe('useSearchVenueOffers', () => {
})

describe('filterVenueOfferHit', () => {
it('should return false when subcategory hit is undefined', () => {
const shouldFilterVenueOfferHit = filterVenueOfferHit({
hit: {
...mockedAlgoliaResponse.hits[0],
offer: { ...mockedAlgoliaResponse.hits[0].offer, subcategoryId: undefined },
},
offerId: 102283,
venueId: 2,
})

expect(shouldFilterVenueOfferHit).toEqual(false)
})

it('should return false when object id hit = offerId param', () => {
const shouldFilterVenueOfferHit = filterVenueOfferHit({
hit: toMutable(mockedAlgoliaResponse.hits)[0],
Expand Down
8 changes: 3 additions & 5 deletions src/api/useSearchVenuesOffer/useSearchVenueOffers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { formatFullAddressStartsWithPostalCode } from 'libs/address/useFormatFul
import { useSearchAnalyticsState } from 'libs/algolia/analytics/SearchAnalyticsWrapper'
import { FetchOffersResponse, fetchOffers } from 'libs/algolia/fetchAlgolia/fetchOffers'
import { useTransformOfferHits } from 'libs/algolia/fetchAlgolia/transformOfferHit'
import { AlgoliaHit, Geoloc } from 'libs/algolia/types'
import { AlgoliaOffer, Geoloc } from 'libs/algolia/types'
import { Position, useLocation } from 'libs/location'
import { LocationMode } from 'libs/location/types'
import { formatDistance } from 'libs/parsers/formatDistance'
Expand Down Expand Up @@ -39,7 +39,7 @@ type OfferVenueType = VenueListItem & {
}

type FilterVenueOfferType = {
hit: AlgoliaHit
hit: AlgoliaOffer
offerId: number
venueId: number | undefined
}
Expand Down Expand Up @@ -89,9 +89,7 @@ export function getVenueList(hits: Offer[], userLocation: Position) {
}

export const filterVenueOfferHit = ({ hit, offerId, venueId }: FilterVenueOfferType): boolean =>
typeof hit.offer.subcategoryId !== 'undefined' &&
clesausse-pass marked this conversation as resolved.
Show resolved Hide resolved
hit.objectID !== String(offerId) &&
hit.venue.id !== venueId
hit.objectID !== String(offerId) && hit.venue.id !== venueId

export const useSearchVenueOffers = ({
allocineId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { FunctionComponent } from 'react'

import { OfferResponseV2 } from 'api/gen'
import { HitOfferWithArtistAndEan } from 'features/offer/api/fetchOffersByArtist/fetchOffersByArtist'
import { OfferPlaylistItem } from 'features/offer/components/OfferPlaylistItem/OfferPlaylistItem'
import { PlaylistType } from 'features/offer/enums'
import { AlgoliaOfferWithArtistAndEan } from 'libs/algolia/types'
import { usePlaylistItemDimensionsFromLayout } from 'libs/contentful/usePlaylistItemDimensionsFromLayout'
import { getDisplayedPrice } from 'libs/parsers/getDisplayedPrice'
import { useCategoryIdMapping } from 'libs/subcategories'
Expand All @@ -16,10 +16,10 @@ import { PassPlaylist } from 'ui/components/PassPlaylist'
type ArtistPlaylistProps = {
offer: OfferResponseV2
artistName: string
items: HitOfferWithArtistAndEan[]
items: AlgoliaOfferWithArtistAndEan[]
}

const keyExtractor = (item: Offer | HitOfferWithArtistAndEan) => item.objectID
const keyExtractor = (item: Offer | AlgoliaOfferWithArtistAndEan) => item.objectID

export const ArtistPlaylist: FunctionComponent<ArtistPlaylistProps> = ({
offer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { FunctionComponent } from 'react'
import { FlatList } from 'react-native'
import styled from 'styled-components/native'

import { HitOfferWithArtistAndEan } from 'features/offer/api/fetchOffersByArtist/fetchOffersByArtist'
import { AlgoliaOfferWithArtistAndEan } from 'libs/algolia/types'
import { Offer } from 'shared/offer/types'
import { theme } from 'theme'
import { Separator } from 'ui/components/Separator'
Expand All @@ -11,16 +11,16 @@ import { Spacer, TypoDS, getSpacing } from 'ui/theme'

type Props = {
artistName: string
items: HitOfferWithArtistAndEan[]
items: AlgoliaOfferWithArtistAndEan[]
}

const keyExtractor = (item: Offer | HitOfferWithArtistAndEan) => item.objectID
const keyExtractor = (item: Offer | AlgoliaOfferWithArtistAndEan) => item.objectID

const renderItem = ({
item,
artistName,
}: {
item: HitOfferWithArtistAndEan
item: AlgoliaOfferWithArtistAndEan
artistName: string
}) => {
const subtitles = item.offer.bookFormat ? [item.offer.bookFormat] : undefined
Expand Down
4 changes: 2 additions & 2 deletions src/features/gtlPlaylist/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { OffersModuleParameters } from 'features/home/types'
import { AlgoliaHit } from 'libs/algolia/types'
import { AlgoliaOffer } from 'libs/algolia/types'
import { Layout, DisplayParametersFields } from 'libs/contentful/types'

export type GtlPlaylistRequest = {
Expand All @@ -10,7 +10,7 @@ export type GtlPlaylistRequest = {

export type GtlPlaylistData = {
title: string
offers: { hits: AlgoliaHit[] }
offers: { hits: AlgoliaOffer[] }
layout: Layout
minNumberOfOffers: number
entryId: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ describe('offerToHeadlineOfferData', () => {
})
})

it('should return null if offer is null', () => {
it('should return null if offer is undefined', () => {
const result = offerToHeadlineOfferData({
offer: null,
offer: undefined,
transformParameters: {
mapping: mockMapping,
labelMapping: mockLabelMapping,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type OfferToHeadlineOfferData = {
}

type OfferToHeadlineParams = {
offer: Offer | null
offer?: Offer
transformParameters: OfferToHeadlineOfferData
}

Expand Down
4 changes: 2 additions & 2 deletions src/features/home/api/helpers/mapOffersDataAndModules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { UseQueryResult } from 'react-query'

import { ModuleData, OfferModuleParamsInfo } from 'features/home/types'
import { filterOfferHit } from 'libs/algolia/fetchAlgolia/transformOfferHit'
import { AlgoliaHit } from 'libs/algolia/types'
import { AlgoliaOffer } from 'libs/algolia/types'
import { Offer } from 'shared/offer/types'

const isOfferModuleParamsInfo = (module: unknown): module is OfferModuleParamsInfo =>
Expand All @@ -15,7 +15,7 @@ const hasParams = (module: OfferModuleParamsInfo) => module.adaptedPlaylistParam
interface MapProps {
results: UseQueryResult<SearchResponse<Offer>[], unknown>
modulesParams: (OfferModuleParamsInfo | undefined)[]
transformHits: (hit: AlgoliaHit) => AlgoliaHit
transformHits: (hit: AlgoliaOffer) => AlgoliaOffer
}

export const mapOffersDataAndModules = ({ results, modulesParams, transformHits }: MapProps) => {
Expand Down
34 changes: 6 additions & 28 deletions src/features/home/api/useAlgoliaRecommendedOffers.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,15 @@
import { useMemo } from 'react'
import { useQuery } from 'react-query'

import { useIsUserUnderage } from 'features/profile/helpers/useIsUserUnderage'
import { fetchOffersByIds } from 'libs/algolia/fetchAlgolia/fetchOffersByIds'
import { filterOfferHit, useTransformOfferHits } from 'libs/algolia/fetchAlgolia/transformOfferHit'
import { IncompleteSearchHit } from 'libs/algolia/types'
import { useAlgoliaSimilarOffers } from 'features/offer/api/useAlgoliaSimilarOffers'
import { QueryKeys } from 'libs/queryKeys'
import { getSimilarOrRecoOffersInOrder } from 'shared/offer/getSimilarOrRecoOffersInOrder'
import { Offer } from 'shared/offer/types'

export const useAlgoliaRecommendedOffers = (
ids: string[],
moduleId: string,
shouldPreserveIdsOrder?: boolean
): Offer[] | undefined => {
const isUserUnderage = useIsUserUnderage()
const transformHits = useTransformOfferHits()

const moduleQueryKey = moduleId
const { data: hits } = useQuery(
[QueryKeys.RECOMMENDATION_HITS, moduleQueryKey, ids],
() => fetchOffersByIds({ objectIds: ids, isUserUnderage }),
{ enabled: ids.length > 0 }
)

return useMemo(() => {
if (!hits || hits.length === 0) return

if (shouldPreserveIdsOrder) {
const offers = getSimilarOrRecoOffersInOrder(ids, hits)
return (offers as IncompleteSearchHit[]).filter(filterOfferHit).map(transformHits) as Offer[]
}

return (hits as IncompleteSearchHit[]).filter(filterOfferHit).map(transformHits) as Offer[]
}, [hits, shouldPreserveIdsOrder, ids, transformHits])
return useAlgoliaSimilarOffers(ids, shouldPreserveIdsOrder, [
QueryKeys.RECOMMENDATION_HITS,
moduleId,
ids,
])
}
5 changes: 3 additions & 2 deletions src/features/home/api/useHighlightOffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { fetchOffersByEan } from 'libs/algolia/fetchAlgolia/fetchOffersByEan'
import { fetchOffersByIds } from 'libs/algolia/fetchAlgolia/fetchOffersByIds'
import { fetchOffersByTags } from 'libs/algolia/fetchAlgolia/fetchOffersByTags'
import { useTransformOfferHits } from 'libs/algolia/fetchAlgolia/transformOfferHit'
import { AlgoliaGeoloc } from 'libs/algolia/types'
import { useLocation } from 'libs/location'
import { Position } from 'libs/location/types'
import { computeDistanceInMeters } from 'libs/parsers/formatDistance'
import { QueryKeys } from 'libs/queryKeys'
import { Offer, OfferLocation } from 'shared/offer/types'
import { Offer } from 'shared/offer/types'

type UseHightlightOfferParams = {
id: string
Expand Down Expand Up @@ -104,7 +105,7 @@ export const useHighlightOffer = ({

const shouldDisplayHighlightOffer = (
position: Position,
offerLocation?: OfferLocation,
offerLocation?: AlgoliaGeoloc,
isGeolocated?: boolean,
aroundRadius?: number
) => {
Expand Down
4 changes: 2 additions & 2 deletions src/features/home/api/useVideoCarouselData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { fetchCarouselVideoOffers } from 'libs/algolia/fetchAlgolia/fetchCarouse
import { buildVideoCarouselOffersQueries } from 'libs/algolia/fetchAlgolia/fetchMultipleOffers/helpers/buildVideoCarouselOffersQueries'
import { searchResponsePredicate } from 'libs/algolia/fetchAlgolia/searchResponsePredicate'
import { filterOfferHit, useTransformOfferHits } from 'libs/algolia/fetchAlgolia/transformOfferHit'
import { AlgoliaHit, OfferModuleQuery } from 'libs/algolia/types'
import { AlgoliaOffer, OfferModuleQuery } from 'libs/algolia/types'
import { useLocation } from 'libs/location'
import { QueryKeys } from 'libs/queryKeys'
import { Offer } from 'shared/offer/types'
Expand All @@ -31,7 +31,7 @@ const getRedirectionMode = (item: VideoCarouselItem): RedirectionMode => {

const mapDataAndItem = (
offersResultList: UseQueryResult<SearchResponse<Offer>[], unknown>,
transformOfferHits: (hit: AlgoliaHit) => AlgoliaHit
transformOfferHits: (hit: AlgoliaOffer) => AlgoliaOffer
) => {
const { data } = offersResultList

Expand Down
2 changes: 1 addition & 1 deletion src/features/home/api/useVideoOffers.native.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('useVideoOffers', () => {
})

it('should return offers when only OffersModuleParameters are provided', async () => {
mockFetchMultipleOffers.mockResolvedValueOnce({ hits: mockOffers, nbHits: 6 })
mockFetchMultipleOffers.mockResolvedValueOnce([{ hits: mockOffers, nbHits: 6 }])

const { result } = renderHook(
() => useVideoOffers([{}] as OffersModuleParameters[], 'moduleId', undefined, undefined),
Expand Down
2 changes: 1 addition & 1 deletion src/features/home/api/useVideoOffers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const useVideoOffers = (
isUserUnderage,
})

return result.hits
return result.flatMap((data) => data.hits)
}
const queryByQueryMode = {
[QueryMode.OFFER_IDS]: offersByIdsQuery,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { SearchResponse } from '@algolia/client-search'

import { SearchGroupNameEnumv2 } from 'api/gen'
import {
HitOfferWithArtistAndEan,
buildAlgoliaFilter,
fetchOffersByArtist,
} from 'features/offer/api/fetchOffersByArtist/fetchOffersByArtist'
import { offerAttributesToRetrieve } from 'libs/algolia/fetchAlgolia/buildAlgoliaParameters/offerAttributesToRetrieve'
import * as multipleQueries from 'libs/algolia/fetchAlgolia/multipleQueries'
import { AlgoliaOfferWithArtistAndEan } from 'libs/algolia/types'
import { Position } from 'libs/location'

const mockMultipleQueries = jest.spyOn(multipleQueries, 'multipleQueries')
Expand All @@ -19,10 +19,10 @@ describe('fetchOffersByArtist', () => {
mockMultipleQueries.mockResolvedValueOnce([
{
hits: [],
} as unknown as SearchResponse<HitOfferWithArtistAndEan>,
} as unknown as SearchResponse<AlgoliaOfferWithArtistAndEan>,
{
hits: [],
} as unknown as SearchResponse<HitOfferWithArtistAndEan>,
} as unknown as SearchResponse<AlgoliaOfferWithArtistAndEan>,
])
await fetchOffersByArtist({
artists: 'Eiichiro Oda',
Expand Down
17 changes: 6 additions & 11 deletions src/features/offer/api/fetchOffersByArtist/fetchOffersByArtist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { EXCLUDED_ARTISTS } from 'features/offer/helpers/constants'
import { captureAlgoliaError } from 'libs/algolia/fetchAlgolia/AlgoliaError'
import { offerAttributesToRetrieve } from 'libs/algolia/fetchAlgolia/buildAlgoliaParameters/offerAttributesToRetrieve'
import { multipleQueries } from 'libs/algolia/fetchAlgolia/multipleQueries'
import { AlgoliaOfferWithArtistAndEan } from 'libs/algolia/types'
import { env } from 'libs/environment/env'
import { Position } from 'libs/location'
import { HitOffer, Offer } from 'shared/offer/types'

type BuildAlgoliaFilterType = {
artists?: string | null
Expand All @@ -18,13 +18,6 @@ export type FetchOfferByArtist = BuildAlgoliaFilterType & {
userLocation: Position
}

export type HitOfferWithArtistAndEan = Offer & {
offer: HitOffer & {
artist: string
ean: string
}
}

export const fetchOffersByArtist = async ({
artists,
searchGroupName,
Expand Down Expand Up @@ -75,9 +68,11 @@ export const fetchOffersByArtist = async ({
return { playlistHits: [], topOffersHits: [] }

try {
const [playlistResponse, topOffersResponse] = (await multipleQueries<HitOfferWithArtistAndEan>(
queries
)) as [SearchResponse<HitOfferWithArtistAndEan>, SearchResponse<HitOfferWithArtistAndEan>]
const [playlistResponse, topOffersResponse] =
(await multipleQueries<AlgoliaOfferWithArtistAndEan>(queries)) as [
SearchResponse<AlgoliaOfferWithArtistAndEan>,
SearchResponse<AlgoliaOfferWithArtistAndEan>,
]

return { playlistHits: playlistResponse.hits, topOffersHits: topOffersResponse.hits }
} catch (error) {
Expand Down
Loading
Loading