Skip to content

Commit

Permalink
refactor: separate useGetVenuesByDay in several hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
xlecunff-pass committed Nov 28, 2024
1 parent 4cf892c commit 2eb49ca
Show file tree
Hide file tree
Showing 14 changed files with 556 additions and 434 deletions.
4 changes: 3 additions & 1 deletion src/features/offer/api/useOffersStocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export const useOffersStocks = ({ offerIds }: { offerIds: number[] }) => {
return useQuery<OffersStocksResponseV2>(
[QueryKeys.OFFER, offerIds],
() => getStocksByOfferIds(offerIds, logType),
{ enabled: !!netInfo.isConnected }
{
enabled: !!netInfo.isConnected,
}
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ export const MovieCalendarDay: React.FC<Props> = ({
if (disabled) {
return DisabledCalendarText
}
if (selectedDate) {
if (isSelected) {
return SelectedCalendarText
}
return DefaultCalendarText
}, [disabled, selectedDate])
}, [disabled, isSelected])

return (
<CalendarCell
Expand All @@ -49,15 +49,17 @@ export const MovieCalendarDay: React.FC<Props> = ({
<CalendarText numberOfLines={1}>{dayDate}</CalendarText>
<CalendarText numberOfLines={1}>{month}</CalendarText>
</CalendarTextView>
{isSelected ? <SelectedBottomBar /> : null}
{isSelected ? <SelectedBottomBar disabled={disabled} /> : null}
</CalendarCell>
)
}

const SelectedBottomBar = styled(MovieCalendarBottomBar)(({ theme }) => ({
backgroundColor: theme.colors.primary,
borderRadius: getSpacing(1),
}))
const SelectedBottomBar = styled(MovieCalendarBottomBar)<{ disabled?: boolean }>(
({ theme, disabled }) => ({
backgroundColor: disabled ? theme.colors.greyMedium : theme.colors.primary,
borderRadius: getSpacing(1),
})
)

const CalendarTextView = styled(View)({
marginHorizontal: getSpacing(4),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type MovieCalendarContextType = {
displayCalendar: (shouldDisplayCalendar: boolean) => void
displayDates: (dates: Date[]) => void
disableDates: (dates: Date[]) => void
dates: Date[]
}

const MovieCalendarContext = createContext<MovieCalendarContextType | undefined>(undefined)
Expand Down Expand Up @@ -79,7 +80,7 @@ export const MovieCalendarProvider: React.FC<{
initialDates?: Date[]
}> = ({ containerStyle, children, initialDates = [] }) => {
const { dates, selectedDate, setSelectedDate, setDates } = useDaysSelector(initialDates)
const [_disabledDates, setDisabledDates] = useState<Date[]>([])
const [disabledDates, setDisabledDates] = useState<Date[]>([])
const flatListRef = useRef<FlatList | null>(null)
const { width: flatListWidth, onLayout: onFlatListLayout } = useLayout()
const { width: itemWidth, onLayout: onItemLayout } = useLayout()
Expand Down Expand Up @@ -129,13 +130,14 @@ export const MovieCalendarProvider: React.FC<{

const value = useMemo(
() => ({
dates,
selectedDate,
goToDate,
displayCalendar: setIsVisible,
displayDates,
disableDates: setDisabledDates,
}),
[selectedDate, goToDate, displayDates]
[dates, selectedDate, goToDate, displayDates]
)

return (
Expand All @@ -146,7 +148,7 @@ export const MovieCalendarProvider: React.FC<{
<MovieCalendar
dates={dates}
selectedDate={selectedDate}
disabledDates={[]}
disabledDates={disabledDates}
onTabChange={setSelectedDate}
flatListRef={flatListRef}
flatListWidth={flatListWidth}
Expand All @@ -172,3 +174,31 @@ export const useMovieCalendar = (): MovieCalendarContextType => {
}
return context
}

export const useDisableCalendarDates = (dates: Date[]) => {
const context = useContext(MovieCalendarContext)
if (context === undefined) {
throw new Error('useDisableCalendarDates must be used within a MovieCalendarProvider')
}

useEffect(() => {
context.disableDates(dates)
}, [context, dates])
}

export const useDisplayCalendar = (shouldDisplayCalendar: boolean) => {
const context = useContext(MovieCalendarContext)
if (context === undefined) {
throw new Error('useDisplayCalendar must be used within a MovieCalendarProvider')
}

useEffect(() => {
context.displayCalendar(shouldDisplayCalendar)
}, [context, shouldDisplayCalendar])
}

export const calendarContext = {
useDisplayCalendar,
useDisableCalendarDates,
useContext: useMovieCalendar,
}
58 changes: 37 additions & 21 deletions src/features/offer/components/OfferCine/CineBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { FunctionComponent } from 'react'
import { View } from 'react-native'
import styled from 'styled-components/native'
import styled, { useTheme } from 'styled-components/native'

import { OfferResponseV2 } from 'api/gen'
import { useMovieCalendar } from 'features/offer/components/MoviesScreeningCalendar/MovieCalendarContext'
Expand All @@ -16,14 +15,17 @@ export type CineBlockProps = {
offer: OfferResponseV2
onSeeVenuePress?: VoidFunction
nextDate?: Date
withDivider?: boolean
}

export const CineBlock: FunctionComponent<CineBlockProps> = ({
offer,
onSeeVenuePress,
nextDate,
withDivider,
}) => {
const { selectedDate, goToDate } = useMovieCalendar()
const theme = useTheme()

const subcategoriesMapping = useSubcategoriesMapping()

Expand All @@ -33,27 +35,41 @@ export const CineBlock: FunctionComponent<CineBlockProps> = ({
)

return (
<CineBlockContainer>
<Spacer.Column numberOfSpaces={6} />
<VenueBlock offer={offer} onSeeVenuePress={onSeeVenuePress} />
<Spacer.Column numberOfSpaces={4} />
{nextDate ? (
<NextScreeningButton
date={nextDate}
onPress={
isDateNotWithinNextNbDays(new Date(), nextDate, 15)
? () => onPressOfferCTA()
: () => goToDate(nextDate)
}
/>
) : (
<OfferEventCardList offer={offer} selectedDate={selectedDate} />
)}
{CTAOfferModal}
</CineBlockContainer>
<React.Fragment>
<CineBlockContainer>
<Spacer.Column numberOfSpaces={6} />
<VenueBlock offer={offer} onSeeVenuePress={onSeeVenuePress} />
<Spacer.Column numberOfSpaces={4} />
{nextDate ? (
<NextScreeningButton
date={nextDate}
onPress={
isDateNotWithinNextNbDays(new Date(), nextDate, 15)
? () => onPressOfferCTA()
: () => goToDate(nextDate)
}
/>
) : (
<OfferEventCardList offer={offer} selectedDate={selectedDate} />
)}
{CTAOfferModal}
</CineBlockContainer>
{withDivider ? (
<React.Fragment>
<Spacer.Column numberOfSpaces={theme.isDesktopViewport ? 6 : 4} />
<Divider />
</React.Fragment>
) : null}
</React.Fragment>
)
}

const CineBlockContainer = styled(View)(({ theme }) => ({
const CineBlockContainer = styled.View(({ theme }) => ({
marginHorizontal: theme.contentPage.marginHorizontal,
}))

const Divider = styled.View(({ theme }) => ({
height: 1,
backgroundColor: theme.colors.greyMedium,
marginHorizontal: theme.isDesktopViewport ? undefined : theme.contentPage.marginHorizontal,
}))
19 changes: 6 additions & 13 deletions src/features/offer/components/OfferCine/CineBlockSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { FunctionComponent } from 'react'
import { View } from 'react-native'
import { FlatList } from 'react-native-gesture-handler'
import styled from 'styled-components/native'

import { OfferEventCardListSkeleton } from 'features/offer/components/OfferEventCardList/OfferEventCardListSkeleton'
Expand All @@ -9,18 +8,12 @@ import { Spacer } from 'ui/theme'

export const CineBlockSkeleton: FunctionComponent = () => {
return (
<FlatList
testID="cine-block-skeleton"
data={Array.from({ length: 3 })}
renderItem={() => (
<CineBlockContainer>
<Spacer.Column numberOfSpaces={6} />
<VenueBlockSkeleton />
<Spacer.Column numberOfSpaces={4} />
<OfferEventCardListSkeleton />
</CineBlockContainer>
)}
/>
<CineBlockContainer>
<Spacer.Column numberOfSpaces={6} />
<VenueBlockSkeleton />
<Spacer.Column numberOfSpaces={4} />
<OfferEventCardListSkeleton />
</CineBlockContainer>
)
}

Expand Down
104 changes: 63 additions & 41 deletions src/features/offer/components/OfferCine/OfferCineContent.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,59 @@
import React, { FC, useRef, useCallback, useState, useEffect } from 'react'
import React, { FC, useRef, useCallback, useState } from 'react'
import { View } from 'react-native'
import Animated, { useAnimatedStyle, withTiming, Easing } from 'react-native-reanimated'
import styled, { useTheme } from 'styled-components/native'

import { OfferResponseV2 } from 'api/gen'
import { useMovieCalendar } from 'features/offer/components/MoviesScreeningCalendar/MovieCalendarContext'
import { calendarContext } from 'features/offer/components/MoviesScreeningCalendar/MovieCalendarContext'
import { CineBlock } from 'features/offer/components/OfferCine/CineBlock'
import { CineBlockSkeleton } from 'features/offer/components/OfferCine/CineBlockSkeleton'
import { useGetVenuesByDay } from 'features/offer/helpers/useGetVenueByDay/useGetVenuesByDay'
import {
getDaysWithNoScreenings,
useGetVenuesByDay,
} from 'features/offer/helpers/useGetVenueByDay/useGetVenuesByDay'
import { useListExpander } from 'features/offer/helpers/useListExpander/useListExpander'
import { useOffersStocksFromOfferQuery } from 'features/offer/helpers/useOffersStocksFromOfferQuery/useOffersStocksFromOfferQuery'
import { ButtonSecondary } from 'ui/components/buttons/ButtonSecondary'
import { PlainMore } from 'ui/svg/icons/PlainMore'
import { Spacer, TypoDS } from 'ui/theme'

const ANIMATION_DURATION = 300

export const OfferCineContent: FC<{
offer: OfferResponseV2
onSeeVenuePress?: VoidFunction
}> = ({ offer, onSeeVenuePress }) => {
const theme = useTheme()
const { animatedStyle, onContentSizeChange } = useAnimatedHeight()
const { selectedDate, displayCalendar } = useMovieCalendar()
const {
increaseCount,
isEnd: hasReachedVenueListEnd,
items,
isLoading,
hasStocksOnlyAfter15Days,
} = useGetVenuesByDay(selectedDate, offer, { initialCount: 6, nextCount: 3, radiusKm: 50 })

useEffect(() => {
displayCalendar(!hasStocksOnlyAfter15Days)
}, [displayCalendar, hasStocksOnlyAfter15Days])

const { data: offers, isLoading } = useOffersStocksFromOfferQuery(offer)
const { selectedDate, dates } = calendarContext.useContext()
const { movieOffers, hasStocksOnlyAfter15Days } = useGetVenuesByDay(selectedDate, offers.offers)

const { items, hasReachedEnd, showMore } = useListExpander(movieOffers, {
initialCount: 6,
nextCount: 3,
})

const disabledDates = getDaysWithNoScreenings(offers.offers, dates)

calendarContext.useDisplayCalendar(!hasStocksOnlyAfter15Days)
calendarContext.useDisableCalendarDates(disabledDates)

return (
<View>
{isLoading ? <CineBlockSkeleton /> : null}
<Animated.FlatList
<ExpandingFlatList
data={items}
style={animatedStyle}
onContentSizeChange={onContentSizeChange}
isLoading={isLoading}
skeletonListLength={3}
renderSkeleton={() => <CineBlockSkeleton />}
renderItem={({ item }) => (
<React.Fragment>
<CineBlock
offer={item.offer}
onSeeVenuePress={onSeeVenuePress}
nextDate={item.nextDate}
/>
<Spacer.Column numberOfSpaces={theme.isDesktopViewport ? 6 : 4} />
<Divider />
</React.Fragment>
<CineBlock
offer={item.offer}
onSeeVenuePress={onSeeVenuePress}
nextDate={item.nextDate}
withDivider
/>
)}
/>
{hasReachedVenueListEnd ? null : (
{hasReachedEnd ? null : (
<SeeMoreContainer>
<Spacer.Column numberOfSpaces={6} />
<Text>Aucune séance ne te correspond&nbsp;?</Text>
Expand All @@ -61,7 +62,7 @@ export const OfferCineContent: FC<{
mediumWidth
icon={PlainMore}
wording="Afficher plus de cinémas"
onPress={increaseCount}
onPress={showMore}
color={theme.colors.black}
/>
</SeeMoreContainer>
Expand All @@ -70,7 +71,34 @@ export const OfferCineContent: FC<{
)
}

const useAnimatedHeight = () => {
const ExpandingFlatList = <T,>({
isLoading,
renderSkeleton,
data,
renderItem,
skeletonListLength = 3,
animationDuration = 300,
...props
}: Animated.FlatListPropsWithLayout<T> & {
animationDuration?: number
isLoading?: boolean
skeletonListLength?: number
renderSkeleton: Animated.FlatListPropsWithLayout<T>['renderItem']
}) => {
const { animatedStyle, onContentSizeChange } = useAnimatedHeight(animationDuration)

return (
<Animated.FlatList
{...props}
data={isLoading ? Array(skeletonListLength).fill(undefined) : data}
renderItem={isLoading ? renderSkeleton : renderItem}
style={animatedStyle}
onContentSizeChange={onContentSizeChange}
/>
)
}

const useAnimatedHeight = (duration: number) => {
const [contentHeight, setContentHeight] = useState(0)
const isFirstRender = useRef(true)

Expand All @@ -82,7 +110,7 @@ const useAnimatedHeight = () => {

return {
height: withTiming(contentHeight, {
duration: ANIMATION_DURATION,
duration,
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
}),
}
Expand All @@ -95,12 +123,6 @@ const useAnimatedHeight = () => {
return { animatedStyle, onContentSizeChange }
}

const Divider = styled.View(({ theme }) => ({
height: 1,
backgroundColor: theme.colors.greyMedium,
marginHorizontal: theme.isDesktopViewport ? undefined : theme.contentPage.marginHorizontal,
}))

const SeeMoreContainer = styled.View(({ theme }) => ({
alignItems: theme.isMobileViewport ? 'center' : undefined,
}))
Expand Down
Loading

0 comments on commit 2eb49ca

Please sign in to comment.