feat: playbacks leaderboard

This commit is contained in:
2026-01-14 14:41:25 +01:00
parent c36cc5f020
commit f7992385d2
4 changed files with 881 additions and 10 deletions
+75 -6
View File
@@ -1,6 +1,14 @@
import { useIsFocused, useRoute } from '@react-navigation/native'
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { FlatList, Image, Pressable, StyleSheet, View, useWindowDimensions } from 'react-native'
import {
FlatList,
Image,
Pressable,
StyleSheet,
Text,
View,
useWindowDimensions,
} from 'react-native'
import { icons } from '../../assets'
import { projectsRef } from '../../config/firebase'
import useDataFromRef from '../../hooks/useDataFromRef'
@@ -8,12 +16,15 @@ import { useUser } from '../../providers/UserDataProvider'
import { Palette } from '../../styles'
import { FONT_FAMILY } from '../../styles/Fonts'
import PlaybackItem from './components/PlaybackItem.web'
import PlaybackCharts from './components/PlaybackCharts'
const Playbacks = () => {
const { height: windowHeight } = useWindowDimensions()
const [activeIndex, setActiveIndex] = useState(0)
const route = useRoute()
const focusProjectId = route?.params?.projectId || route?.params?.focusId || null
const initialFocusProjectId = route?.params?.projectId || route?.params?.focusId || null
const [focusProjectId, setFocusProjectId] = useState(initialFocusProjectId)
const [viewMode, setViewMode] = useState(initialFocusProjectId ? 'feed' : 'charts')
const userCache = useRef(new Map())
const { getUserByUid } = useUser() || {}
const isFocused = useIsFocused()
@@ -44,9 +55,6 @@ const Playbacks = () => {
const activePlayback = playbacks?.[activeIndex] || null
const activeVideoUrl = activePlayback?.playbackUrl || null
const activeTitle = typeof activePlayback?.title === 'string' ? activePlayback.title.trim() : ''
const activeCreatorName = activePlayback?.userName
const backgroundVideoRef = useRef(null)
const lastActiveIndexRef = useRef(0)
const backgroundSeekPendingRef = useRef(false)
@@ -161,7 +169,6 @@ const Playbacks = () => {
}
}, [activeVideoUrl])
const triedLoadMoreRef = useRef(0)
const hasAppliedFocusRef = useRef(false)
const focusLoadAttemptsRef = useRef(0)
@@ -189,6 +196,27 @@ const Playbacks = () => {
}
}, [focusIndex, focusProjectId, loadMore, playbacks])
useEffect(() => {
const nextFocusId = route?.params?.projectId || route?.params?.focusId || null
setFocusProjectId(nextFocusId)
if (nextFocusId) {
setViewMode('feed')
}
}, [route?.params?.focusId, route?.params?.projectId])
useEffect(() => {
if (viewMode !== 'feed') {
return
}
lastActiveIndexRef.current = 0
setActiveIndex(0)
requestAnimationFrame(() => {
try {
listRef.current?.scrollToOffset?.({ offset: 0, animated: false })
} catch (_e) {}
})
}, [viewMode])
// === FlatList (one real page per item) ===
// keep active index in sync with scroll
const onMomentumScrollEnd = useCallback(
@@ -294,6 +322,24 @@ const Playbacks = () => {
[activeIndex, handleActiveIndexChange, hasMore, loadMore, playbacks.length, windowHeight]
)
const showFeed = viewMode === 'feed'
const openFeedForPlayback = useCallback((project) => {
const nextId =
project && typeof project === 'object'
? project?.id || project?.projectId || null
: project || null
if (!nextId) {
return
}
setFocusProjectId(nextId)
setViewMode('feed')
}, [])
if (!showFeed) {
return <PlaybackCharts onPlaybackPress={openFeedForPlayback} />
}
return (
<View style={styles.screen}>
{activeVideoUrl ? (
@@ -396,6 +442,14 @@ const Playbacks = () => {
</Pressable>
</View>
)}
<Pressable
style={styles.backToCharts}
hitSlop={12}
onPress={() => setViewMode('charts')}
accessibilityLabel="Revenir au classement des playbacks"
>
<Text style={styles.backToChartsText}>Classement</Text>
</Pressable>
</View>
// </Page>
)
@@ -505,4 +559,19 @@ const styles = StyleSheet.create({
fontFamily: FONT_FAMILY.InterMedium,
textAlign: 'center',
},
backToCharts: {
position: 'absolute',
top: 32,
right: 24,
paddingVertical: 8,
paddingHorizontal: 12,
borderRadius: 12,
backgroundColor: 'rgba(0,0,0,0.55)',
zIndex: 20,
},
backToChartsText: {
color: Palette.white,
fontSize: 12,
fontFamily: FONT_FAMILY.InterSemiBold,
},
})