diff --git a/src/features/venue/components/VenueContent/VenueContent.tsx b/src/features/venue/components/VenueContent/VenueContent.tsx index 1f94e3b2aca..d76973586fb 100644 --- a/src/features/venue/components/VenueContent/VenueContent.tsx +++ b/src/features/venue/components/VenueContent/VenueContent.tsx @@ -11,6 +11,7 @@ import { VenueCTA } from 'features/venue/components/VenueCTA/VenueCTA' import { VenueHeader } from 'features/venue/components/VenueHeader/VenueHeader' import { VenueTopComponent } from 'features/venue/components/VenueTopComponent/VenueTopComponent' import { VenueWebMetaHeader } from 'features/venue/components/VenueWebMetaHeader' +import { VideoSection } from 'features/venue/components/VideoSection/VideoSection' import { isCloseToBottom } from 'libs/analytics' import { useFunctionOnce } from 'libs/hooks' import { BatchEvent, BatchUser } from 'libs/react-native-batch' @@ -23,6 +24,7 @@ type Props = { venue: VenueResponse gtlPlaylists?: GtlPlaylistData[] venueOffers?: VenueOffers + videoSectionVisible?: boolean } const trackEventHasSeenVenueForSurvey = () => BatchUser.trackEvent(BatchEvent.hasSeenVenueForSurvey) @@ -32,6 +34,7 @@ export const VenueContent: React.FunctionComponent = ({ venue, gtlPlaylists, venueOffers, + videoSectionVisible, }) => { const triggerBatch = useFunctionOnce(trackEventHasSeenVenueForSurvey) const scrollViewRef = useRef(null) @@ -86,6 +89,9 @@ export const VenueContent: React.FunctionComponent = ({ {isLargeScreen ? : null} + {videoSectionVisible ? ( + false} /> + ) : null} void +} + +export const FakeVideoPlayer: FunctionComponent = ({ + imageSource, + width, + height, + onPress, +}) => { + return ( + + + + + + + + + ) +} + +const Container = styled.View>( + ({ theme, width, height }) => ({ + width, + height, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: theme.colors.black, + }) +) + +const PlayIconWrapper = styled(View)({ + position: 'absolute', + width: '100%', + height: '100%', + justifyContent: 'center', + alignItems: 'center', + zIndex: 2, +}) + +const BackgroundImage = styled(FastImage)({ + width: '100%', + height: '100%', + opacity: 0.4, +}) + +const PlayIcon = styled(Play).attrs(({ theme }) => ({ + size: getSpacing(24), + color: theme.colors.brownLight, +}))`` diff --git a/src/features/venue/components/VideoSection/VideoSection.tsx b/src/features/venue/components/VideoSection/VideoSection.tsx new file mode 100644 index 00000000000..33243a99aa8 --- /dev/null +++ b/src/features/venue/components/VideoSection/VideoSection.tsx @@ -0,0 +1,49 @@ +import React, { useRef } from 'react' +import { useWindowDimensions } from 'react-native' +import { useTheme } from 'styled-components' +import styled from 'styled-components/native' + +import { VenueTypeCodeKey } from 'api/gen' +import { + getVideoPlayerDimensions, + RATIO169, +} from 'features/home/components/helpers/getVideoPlayerDimensions' +import { FakeVideoPlayer } from 'features/venue/components/VideoSection/FakeVideoPlayer' +import { getFakeVideoBackground } from 'features/venue/helpers/getFakeVideoBackground' +import { SectionWithDivider } from 'ui/components/SectionWithDivider' +import { getSpacing, Spacer, Typo } from 'ui/theme' +import { getHeadingAttrs } from 'ui/theme/typographyAttrs/getHeadingAttrs' + +type VideoSectionProps = { + onPress: () => void + venueType?: VenueTypeCodeKey | null +} + +export const VideoSection = ({ venueType, onPress }: VideoSectionProps) => { + const { isDesktopViewport } = useTheme() + const { width: windowWidth } = useWindowDimensions() + const { playerHeight, playerWidth } = getVideoPlayerDimensions( + isDesktopViewport, + windowWidth, + RATIO169 + ) + + const fakeVideoBackgroundSource = useRef(getFakeVideoBackground(venueType)).current + + return ( + + + <FakeVideoPlayer + imageSource={fakeVideoBackgroundSource} + height={playerHeight} + width={playerWidth} + onPress={onPress} + /> + <Spacer.Column numberOfSpaces={2} /> + </SectionWithDivider> + ) +} + +const Title = styled(Typo.Title3).attrs({ ...getHeadingAttrs(2), children: 'Vidéo de ce lieu' })({ + marginLeft: getSpacing(6), +}) diff --git a/src/features/venue/components/VideoSection/VideoSection.web.tsx b/src/features/venue/components/VideoSection/VideoSection.web.tsx new file mode 100644 index 00000000000..1d3a2132d03 --- /dev/null +++ b/src/features/venue/components/VideoSection/VideoSection.web.tsx @@ -0,0 +1,9 @@ +import { Source } from 'react-native-fast-image' + +type VideoSectionProps = { + title: string + source: number | Source + onPress: () => void +} + +export const VideoSection = (_props: VideoSectionProps) => null diff --git a/src/features/venue/helpers/getFakeVideoBackground.ts b/src/features/venue/helpers/getFakeVideoBackground.ts new file mode 100644 index 00000000000..78e848253d1 --- /dev/null +++ b/src/features/venue/helpers/getFakeVideoBackground.ts @@ -0,0 +1,34 @@ +import { VenueTypeCodeKey } from 'api/gen' +import bookstore from 'ui/images/bg-bookstore.jpeg' +import concert from 'ui/images/bg-concert.jpeg' +import movie from 'ui/images/bg-movie.jpeg' +import museum from 'ui/images/bg-museum.jpeg' +import other from 'ui/images/bg-other.jpeg' +import store from 'ui/images/bg-store.jpeg' + +export const getFakeVideoBackground = (type?: VenueTypeCodeKey | null) => { + switch (type) { + case VenueTypeCodeKey.BOOKSTORE: + case VenueTypeCodeKey.LIBRARY: + return bookstore + case VenueTypeCodeKey.MOVIE: + case VenueTypeCodeKey.TRAVELING_CINEMA: + return movie + case VenueTypeCodeKey.FESTIVAL: + case VenueTypeCodeKey.CONCERT_HALL: + case VenueTypeCodeKey.PERFORMING_ARTS: + return concert + case VenueTypeCodeKey.RECORD_STORE: + case VenueTypeCodeKey.DISTRIBUTION_STORE: + case VenueTypeCodeKey.CREATIVE_ARTS_STORE: + case VenueTypeCodeKey.MUSICAL_INSTRUMENT_STORE: + return store + case VenueTypeCodeKey.VISUAL_ARTS: + case VenueTypeCodeKey.CULTURAL_CENTRE: + case VenueTypeCodeKey.MUSEUM: + case VenueTypeCodeKey.PATRIMONY_TOURISM: + return museum + default: + return other + } +} diff --git a/src/features/venue/pages/Venue/Venue.native.test.tsx b/src/features/venue/pages/Venue/Venue.native.test.tsx index ccc9661ad42..71563a01988 100644 --- a/src/features/venue/pages/Venue/Venue.native.test.tsx +++ b/src/features/venue/pages/Venue/Venue.native.test.tsx @@ -10,12 +10,17 @@ import { venueDataTest } from 'features/venue/fixtures/venueDataTest' import { Venue } from 'features/venue/pages/Venue/Venue' import { analytics } from 'libs/analytics' import * as useFeatureFlag from 'libs/firebase/firestore/featureFlags/useFeatureFlag' +import { RemoteStoreFeatureFlags } from 'libs/firebase/firestore/types' import { Offer } from 'shared/offer/types' import { mockServer } from 'tests/mswServer' import { reactQueryProviderHOC } from 'tests/reactQueryProviderHOC' import { fireEvent, render, screen, waitFor } from 'tests/utils' -jest.spyOn(useFeatureFlag, 'useFeatureFlag').mockReturnValue(false) +const useFeatureFlagSpy = jest.spyOn(useFeatureFlag, 'useFeatureFlag').mockReturnValue(false) + +const activateFeatureFlags = (activeFeatureFlags: RemoteStoreFeatureFlags[] = []) => { + useFeatureFlagSpy.mockImplementation((flag) => activeFeatureFlags.includes(flag)) +} jest.useFakeTimers() @@ -95,6 +100,7 @@ jest.mock('@batch.com/react-native-plugin', () => describe('<Venue />', () => { beforeEach(() => { + activateFeatureFlags() mockServer.getApi<VenueResponse>(`/v1/venue/${venueId}`, venueDataTest) }) @@ -114,6 +120,13 @@ describe('<Venue />', () => { expect(screen).toMatchSnapshot() }) + it('should display video section with FF on', async () => { + activateFeatureFlags([RemoteStoreFeatureFlags.WIP_FAKEDOOR_VIDEO_VENUE]) + renderVenue(venueId) + + expect(await screen.findByText('Vidéo de ce lieu')).toBeOnTheScreen() + }) + describe('analytics', () => { it.each([['deeplink'], ['venueMap']])( 'should log consult venue when URL from param equal to %s', diff --git a/src/features/venue/pages/Venue/Venue.tsx b/src/features/venue/pages/Venue/Venue.tsx index 6198f715538..6ff3e7b8874 100644 --- a/src/features/venue/pages/Venue/Venue.tsx +++ b/src/features/venue/pages/Venue/Venue.tsx @@ -7,12 +7,15 @@ import { useVenue } from 'features/venue/api/useVenue' import { useVenueOffers } from 'features/venue/api/useVenueOffers' import { VenueContent } from 'features/venue/components/VenueContent/VenueContent' import { analytics } from 'libs/analytics' +import { useFeatureFlag } from 'libs/firebase/firestore/featureFlags/useFeatureFlag' +import { RemoteStoreFeatureFlags } from 'libs/firebase/firestore/types' export const Venue: FunctionComponent = () => { const { params } = useRoute<UseRouteType<'Venue'>>() const { data: venue } = useVenue(params.id) const { gtlPlaylists } = useGTLPlaylists({ venue, queryKey: 'VENUE_GTL_PLAYLISTS' }) const { data: venueOffers } = useVenueOffers(venue) + const videoSectionVisible = useFeatureFlag(RemoteStoreFeatureFlags.WIP_FAKEDOOR_VIDEO_VENUE) useEffect(() => { if ((params.from === 'deeplink' || params.from === 'venueMap') && venue?.id) { @@ -22,5 +25,12 @@ export const Venue: FunctionComponent = () => { if (!venue) return null - return <VenueContent venue={venue} gtlPlaylists={gtlPlaylists} venueOffers={venueOffers} /> + return ( + <VenueContent + venue={venue} + gtlPlaylists={gtlPlaylists} + venueOffers={venueOffers} + videoSectionVisible={videoSectionVisible} + /> + ) } diff --git a/src/image.d.ts b/src/image.d.ts new file mode 100644 index 00000000000..46a069dac35 --- /dev/null +++ b/src/image.d.ts @@ -0,0 +1,9 @@ +declare module '*.png' { + const value: any + export = value +} + +declare module '*.jpeg' { + const value: any + export = value +} diff --git a/src/libs/firebase/firestore/types.ts b/src/libs/firebase/firestore/types.ts index 9ac276a2c2b..5aecc385609 100644 --- a/src/libs/firebase/firestore/types.ts +++ b/src/libs/firebase/firestore/types.ts @@ -56,4 +56,5 @@ export enum RemoteStoreFeatureFlags { WIP_NEW_EXCLUSIVITY_MODULE = 'wipNewExclusivityModule', TARGET_XP_CINE_FROM_OFFER = 'targetXpCineFromOffer', WIP_ARTIST_PAGE = 'wipArtistPage', + WIP_FAKEDOOR_VIDEO_VENUE = 'wipFakeDoorVideoVenue', } diff --git a/src/ui/images/bg-bookstore.jpeg b/src/ui/images/bg-bookstore.jpeg new file mode 100644 index 00000000000..d6b9ea1cca2 Binary files /dev/null and b/src/ui/images/bg-bookstore.jpeg differ diff --git a/src/ui/images/bg-concert.jpeg b/src/ui/images/bg-concert.jpeg new file mode 100644 index 00000000000..da69afa95a6 Binary files /dev/null and b/src/ui/images/bg-concert.jpeg differ diff --git a/src/ui/images/bg-movie.jpeg b/src/ui/images/bg-movie.jpeg new file mode 100644 index 00000000000..f051bb10291 Binary files /dev/null and b/src/ui/images/bg-movie.jpeg differ diff --git a/src/ui/images/bg-museum.jpeg b/src/ui/images/bg-museum.jpeg new file mode 100644 index 00000000000..63ec626226f Binary files /dev/null and b/src/ui/images/bg-museum.jpeg differ diff --git a/src/ui/images/bg-other.jpeg b/src/ui/images/bg-other.jpeg new file mode 100644 index 00000000000..f8623454ee1 Binary files /dev/null and b/src/ui/images/bg-other.jpeg differ diff --git a/src/ui/images/bg-store.jpeg b/src/ui/images/bg-store.jpeg new file mode 100644 index 00000000000..5ff6ed1d4cf Binary files /dev/null and b/src/ui/images/bg-store.jpeg differ