mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import * as React from 'react' 2import {View} from 'react-native' 3import {PWI_ENABLED, NEW_ONBOARDING_ENABLED} from '#/lib/build-flags' 4 5// Based on @react-navigation/native-stack/src/createNativeStackNavigator.ts 6// MIT License 7// Copyright (c) 2017 React Navigation Contributors 8 9import { 10 createNavigatorFactory, 11 EventArg, 12 ParamListBase, 13 StackActionHelpers, 14 StackActions, 15 StackNavigationState, 16 StackRouter, 17 StackRouterOptions, 18 useNavigationBuilder, 19} from '@react-navigation/native' 20import type { 21 NativeStackNavigationEventMap, 22 NativeStackNavigationOptions, 23} from '@react-navigation/native-stack' 24import type {NativeStackNavigatorProps} from '@react-navigation/native-stack/src/types' 25import {NativeStackView} from '@react-navigation/native-stack' 26 27import {BottomBarWeb} from './bottom-bar/BottomBarWeb' 28import {DesktopLeftNav} from './desktop/LeftNav' 29import {DesktopRightNav} from './desktop/RightNav' 30import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 31import {useOnboardingState} from '#/state/shell' 32import { 33 useLoggedOutView, 34 useLoggedOutViewControls, 35} from '#/state/shell/logged-out' 36import {useSession} from '#/state/session' 37import {isWeb} from 'platform/detection' 38import {Deactivated} from '#/screens/Deactivated' 39import {LoggedOut} from '../com/auth/LoggedOut' 40import {Onboarding} from '../com/auth/Onboarding' 41import {Onboarding as NewOnboarding} from '#/screens/Onboarding' 42 43type NativeStackNavigationOptionsWithAuth = NativeStackNavigationOptions & { 44 requireAuth?: boolean 45} 46 47function NativeStackNavigator({ 48 id, 49 initialRouteName, 50 children, 51 screenListeners, 52 screenOptions, 53 ...rest 54}: NativeStackNavigatorProps) { 55 // --- this is copy and pasted from the original native stack navigator --- 56 const {state, descriptors, navigation, NavigationContent} = 57 useNavigationBuilder< 58 StackNavigationState<ParamListBase>, 59 StackRouterOptions, 60 StackActionHelpers<ParamListBase>, 61 NativeStackNavigationOptionsWithAuth, 62 NativeStackNavigationEventMap 63 >(StackRouter, { 64 id, 65 initialRouteName, 66 children, 67 screenListeners, 68 screenOptions, 69 }) 70 React.useEffect( 71 () => 72 // @ts-expect-error: there may not be a tab navigator in parent 73 navigation?.addListener?.('tabPress', (e: any) => { 74 const isFocused = navigation.isFocused() 75 76 // Run the operation in the next frame so we're sure all listeners have been run 77 // This is necessary to know if preventDefault() has been called 78 requestAnimationFrame(() => { 79 if ( 80 state.index > 0 && 81 isFocused && 82 !(e as EventArg<'tabPress', true>).defaultPrevented 83 ) { 84 // When user taps on already focused tab and we're inside the tab, 85 // reset the stack to replicate native behaviour 86 navigation.dispatch({ 87 ...StackActions.popToTop(), 88 target: state.key, 89 }) 90 } 91 }) 92 }), 93 [navigation, state.index, state.key], 94 ) 95 96 // --- our custom logic starts here --- 97 const {hasSession, currentAccount} = useSession() 98 const activeRoute = state.routes[state.index] 99 const activeDescriptor = descriptors[activeRoute.key] 100 const activeRouteRequiresAuth = activeDescriptor.options.requireAuth ?? false 101 const onboardingState = useOnboardingState() 102 const {showLoggedOut} = useLoggedOutView() 103 const {setShowLoggedOut} = useLoggedOutViewControls() 104 const {isMobile, isTabletOrMobile} = useWebMediaQueries() 105 if ((!PWI_ENABLED || activeRouteRequiresAuth) && !hasSession) { 106 return <LoggedOut /> 107 } 108 if (hasSession && currentAccount?.deactivated) { 109 return <Deactivated /> 110 } 111 if (showLoggedOut) { 112 return <LoggedOut onDismiss={() => setShowLoggedOut(false)} /> 113 } 114 if (onboardingState.isActive) { 115 if (NEW_ONBOARDING_ENABLED) { 116 return <NewOnboarding /> 117 } else { 118 return <Onboarding /> 119 } 120 } 121 const newDescriptors: typeof descriptors = {} 122 for (let key in descriptors) { 123 const descriptor = descriptors[key] 124 const requireAuth = descriptor.options.requireAuth ?? false 125 newDescriptors[key] = { 126 ...descriptor, 127 render() { 128 if (requireAuth && !hasSession) { 129 return <View /> 130 } else { 131 return descriptor.render() 132 } 133 }, 134 } 135 } 136 137 // Show the bottom bar if we have a session only on mobile web. If we don't have a session, we want to show it 138 // on both tablet and mobile web so that we see the sign up CTA. 139 const showBottomBar = hasSession ? isMobile : isTabletOrMobile 140 141 return ( 142 <NavigationContent> 143 <NativeStackView 144 {...rest} 145 state={state} 146 navigation={navigation} 147 descriptors={newDescriptors} 148 /> 149 {isWeb && showBottomBar && <BottomBarWeb />} 150 {isWeb && !showBottomBar && ( 151 <> 152 <DesktopLeftNav /> 153 <DesktopRightNav routeName={activeRoute.name} /> 154 </> 155 )} 156 </NavigationContent> 157 ) 158} 159 160export const createNativeStackNavigatorWithAuth = createNavigatorFactory< 161 StackNavigationState<ParamListBase>, 162 NativeStackNavigationOptionsWithAuth, 163 NativeStackNavigationEventMap, 164 typeof NativeStackNavigator 165>(NativeStackNavigator)