Refactor app flows and refresh UI components

This commit is contained in:
Jacques_tirot
2026-09-08 14:20:23 +02:00
parent 4e14a38d4e
commit 814e1d27fb
71 changed files with 1984 additions and 509 deletions
+72 -12
View File
@@ -7,10 +7,24 @@ import { useGlobal } from 'reactn'
import firebase, {
arrayUnion,
notificationsRef,
projectsRef,
serverTimestamp,
usersRef,
} from '../config/firebase'
import useDataFromRef from '../hooks/useDataFromRef'
import { Routes } from '../navigation'
import { navigate } from '../navigation/NavigationService'
if (Platform.OS !== 'web') {
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldPlaySound: true,
shouldSetBadge: true,
shouldShowBanner: true,
shouldShowList: true,
}),
})
}
export const NotificationContext = createContext(null)
@@ -19,11 +33,14 @@ export default function NotificationProvider({ children }) {
const [uid] = useGlobal('currentUID')
const [pendingData, setPendingData] = useGlobal('pendingData')
const [activeRouteName] = useGlobal('activeRouteName')
const [notifInit, setNotifInit] = useState(false)
const [allowNotifications, setAllowNotifications] = useState(false)
const notificationListener = useRef()
const responseListener = useRef()
const handledResponseId = useRef(null)
const handledNavigationKey = useRef(null)
const notificationsQuery = useMemo(() => {
if (!uid) {
@@ -149,24 +166,29 @@ export default function NotificationProvider({ children }) {
return
}
notificationListener.current = Notifications.addNotificationReceivedListener(
async (notification) => {
(notification) => {
console.log('Notification received', notification)
await Notifications.scheduleNotificationAsync(notification?.request)
}
)
responseListener.current = Notifications.addNotificationResponseReceivedListener(
async (response) => {
console.log('Notification response', response)
if (response?.actionIdentifier === 'expo.modules.notifications.actions.DEFAULT') {
const { data } = response.notification.request.content
if (data) {
console.log('Notification data', data)
await setPendingData(data)
}
const handleNotificationResponse = async (response) => {
const requestId = response?.notification?.request?.identifier || null
if (requestId && handledResponseId.current === requestId) return
if (requestId) handledResponseId.current = requestId
console.log('Notification response', response)
if (response?.actionIdentifier === Notifications.DEFAULT_ACTION_IDENTIFIER) {
const data = response?.notification?.request?.content?.data || null
if (data) {
console.log('Notification data', data)
await setPendingData(data)
}
}
)
}
Notifications.getLastNotificationResponseAsync().then(handleNotificationResponse)
responseListener.current =
Notifications.addNotificationResponseReceivedListener(handleNotificationResponse)
return () => {
Notifications.removeNotificationSubscription(notificationListener.current)
@@ -174,6 +196,44 @@ export default function NotificationProvider({ children }) {
}
}, [allowNotifications, setPendingData])
useEffect(() => {
const notificationType = pendingData?.type
const projectId = pendingData?.projectId
if (
!uid ||
!activeRouteName ||
notificationType !== 'PLAYBACK_GENERATION_SUCCESS' ||
!projectId
) {
return
}
const navigationKey = `${notificationType}:${projectId}`
if (handledNavigationKey.current === navigationKey) return
handledNavigationKey.current = navigationKey
const openGeneratedPlayback = async () => {
try {
const projectSnap = await projectsRef.doc(projectId).get()
if (!projectSnap.exists) return
navigate(Routes.PlaybackAiStatus, {
project: {
...projectSnap.data(),
id: projectSnap.id,
},
})
} catch (error) {
console.log('openGeneratedPlayback error:', error)
} finally {
await setPendingData(null)
}
}
openGeneratedPlayback()
}, [activeRouteName, pendingData, setPendingData, uid])
async function registerForPushNotificationsAsync() {
try {
const isWeb = Platform.OS === 'web'
+17 -1
View File
@@ -10,6 +10,14 @@ import { UserDataContext } from './UserDataProvider'
const APP_SCHEME = 'musicland'
const APP_PATH_PREFIX = 'app'
const APP_STORE_FALLBACK_URL = appleAppStoreUrl
const NATIVE_DEEP_LINK_RESOURCES = new Set([
'music',
'musics',
'playback',
'playbacks',
'task',
'tasks',
])
const normalizePath = (rawPath = '') => {
if (!rawPath) return ''
@@ -27,6 +35,14 @@ const buildAppSchemeUrl = (rawPath, queryParams = {}) => {
return `${APP_SCHEME}://${fullPath}${queryString ? `?${queryString}` : ''}`
}
const shouldOpenNativeApp = (rawPath) => {
const normalizedPath = normalizePath(rawPath)
if (normalizedPath.toLowerCase() === 'link') return true
const [resource, identifier] = normalizedPath.split('/').filter(Boolean)
return !!identifier && NATIVE_DEEP_LINK_RESOURCES.has(resource?.toLowerCase())
}
const UniversalLinkProvider = ({ children }) => {
const { currentUID } = useContext(UserDataContext)
const { isFullyLoaded } = useContext(SplashAnimationContext)
@@ -137,7 +153,7 @@ const UniversalLinkProvider = ({ children }) => {
const isIOSBrowser =
/iPad|iPhone|iPod/.test(userAgent) ||
(/Macintosh/.test(userAgent) && navigator.maxTouchPoints && navigator.maxTouchPoints > 2)
if (isIOSBrowser) {
if (isIOSBrowser && shouldOpenNativeApp(path)) {
try {
const canOpen = await Linking.canOpenURL(appSchemeURL)
if (canOpen) {