feat: update onboarding and application flows

This commit is contained in:
Jacques_tirot
2026-08-25 15:55:11 +02:00
parent 4fb8a3e1e0
commit bc7edcf3a7
38 changed files with 7234 additions and 289 deletions
+66 -67
View File
@@ -1,19 +1,8 @@
import AsyncStorage from '@react-native-async-storage/async-storage'
import { useCallback, useEffect, useRef, useState } from 'react'
import {
ActivityIndicator,
Image,
Platform,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native'
import { background, icons } from '../assets'
import EntryJingle from '../components/EntryJingle'
import { useCallback, useMemo, useState } from 'react'
import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
import { background, icons, videos } from '../assets'
import FullscreenIntroVideo from '../components/FullscreenIntroVideo'
import { videosRef } from '../config/firebase'
import useDataFromRef from '../hooks/useDataFromRef'
import Page from '../layouts/Page'
import { Routes } from '../navigation'
import { navigate, reset } from '../navigation/NavigationService'
@@ -22,45 +11,25 @@ import { Palette } from '../styles'
import { FONT_FAMILY } from '../styles/Fonts'
const LANGUAGE_STORAGE_KEY = 'preferredLanguage'
const FLOW_PHASE = {
JINGLE: 'jingle',
LANGUAGE: 'language',
WELCOME_VIDEO: 'welcomeVideo',
}
export default function LandingPage() {
export default function LandingPage({ route }) {
const { currentUID } = useUser()
const [videoUrl, setVideoUrl] = useState(null)
const [phase, setPhase] = useState(() =>
route?.params?.startAtLanguage ? FLOW_PHASE.LANGUAGE : FLOW_PHASE.JINGLE
)
const [selectedLanguage, setSelectedLanguage] = useState(null)
const continuationHandledRef = useRef(false)
const isAuthenticated = !!currentUID
const { data: welcomeVideo, loading: welcomeVideoLoading } = useDataFromRef({
ref: selectedLanguage ? videosRef.doc(selectedLanguage) : null,
initialState: null,
simpleRef: true,
condition: !!selectedLanguage,
refreshArray: [selectedLanguage],
})
const openRegistration = useCallback(() => {
navigate(Routes.Register)
}, [])
const handleSelectLanguage = useCallback(async (language) => {
try {
await AsyncStorage.setItem(LANGUAGE_STORAGE_KEY, language)
} catch (error) {
console.warn('LandingPage: failed to persist language', error)
}
continuationHandledRef.current = false
setSelectedLanguage(language)
}, [])
const handleVideoClose = useCallback(() => {
setVideoUrl(null)
openRegistration()
}, [openRegistration])
useEffect(() => {
if (!isAuthenticated) {
return
}
const openMainMenu = useCallback(() => {
reset({
index: 0,
routes: [
@@ -73,33 +42,55 @@ export default function LandingPage() {
},
],
})
}, [isAuthenticated])
}, [])
useEffect(() => {
if (
!selectedLanguage ||
welcomeVideoLoading ||
continuationHandledRef.current ||
isAuthenticated
) {
const handleJingleClose = useCallback(() => {
if (isAuthenticated) {
openMainMenu()
return
}
setPhase(FLOW_PHASE.LANGUAGE)
}, [isAuthenticated, openMainMenu])
continuationHandledRef.current = true
const nextVideoUrl =
Platform.OS === 'web' ? welcomeVideo?.registrationIntroWeb : welcomeVideo?.registrationIntro
if (typeof nextVideoUrl === 'string' && nextVideoUrl.trim().length > 0) {
setVideoUrl(nextVideoUrl)
return
const handleSelectLanguage = useCallback(async (language) => {
try {
await AsyncStorage.setItem(LANGUAGE_STORAGE_KEY, language)
} catch (error) {
console.warn('LandingPage: failed to persist language', error)
}
setSelectedLanguage(language)
setPhase(FLOW_PHASE.WELCOME_VIDEO)
}, [])
openRegistration()
}, [isAuthenticated, openRegistration, selectedLanguage, welcomeVideo, welcomeVideoLoading])
const handleWelcomeVideoClose = useCallback(() => {
setSelectedLanguage(null)
setPhase(FLOW_PHASE.LANGUAGE)
requestAnimationFrame(openRegistration)
}, [openRegistration])
const activeVideo = useMemo(() => {
if (phase === FLOW_PHASE.JINGLE) return videos.entryJingle
if (phase !== FLOW_PHASE.WELCOME_VIDEO) return null
return selectedLanguage === 'en' ? videos.welcomeEn : videos.welcomeFr
}, [phase, selectedLanguage])
const activeVideoClose =
phase === FLOW_PHASE.JINGLE ? handleJingleClose : handleWelcomeVideoClose
const skipLabel =
phase === FLOW_PHASE.JINGLE
? 'Passer / Skip'
: selectedLanguage === 'en'
? 'Skip video'
: 'Passer la vidéo'
const playLabel =
phase === FLOW_PHASE.JINGLE
? 'Lancer le jingle / Play jingle'
: selectedLanguage === 'en'
? 'Play video with sound'
: 'Lire la vidéo avec le son'
return (
<>
<EntryJingle active={!isAuthenticated && !selectedLanguage} />
<Page title="Landing Page" backgroundImg={background.homeBGWeb}>
<View
style={{
@@ -109,7 +100,7 @@ export default function LandingPage() {
}}
>
<View style={styles.content}>
{!selectedLanguage && (
{phase === FLOW_PHASE.LANGUAGE ? (
<View style={styles.languageRow}>
<TouchableOpacity
style={[styles.languageButton]}
@@ -126,14 +117,22 @@ export default function LandingPage() {
<Text style={styles.languageText}>English</Text>
</TouchableOpacity>
</View>
)}
{selectedLanguage && welcomeVideoLoading ? (
<ActivityIndicator color={Palette.white} size="large" />
) : null}
</View>
</View>
</Page>
<FullscreenIntroVideo url={videoUrl} visible={!!videoUrl} onClose={handleVideoClose} />
{activeVideo ? (
<FullscreenIntroVideo
key={phase}
url={activeVideo}
visible
onClose={activeVideoClose}
contentFit="contain"
requireAudio
skipLabel={skipLabel}
playLabel={playLabel}
/>
) : null}
</>
)
}