mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import * as React from 'react' 2import {View} from 'react-native' 3// Based on @react-navigation/native-stack/src/createNativeStackNavigator.ts 4// MIT License 5// Copyright (c) 2017 React Navigation Contributors 6import { 7 createNavigatorFactory, 8 EventArg, 9 ParamListBase, 10 StackActionHelpers, 11 StackActions, 12 StackNavigationState, 13 StackRouter, 14 StackRouterOptions, 15 useNavigationBuilder, 16} from '@react-navigation/native' 17import type { 18 NativeStackNavigationEventMap, 19 NativeStackNavigationOptions, 20} from '@react-navigation/native-stack' 21import {NativeStackView} from '@react-navigation/native-stack' 22import type {NativeStackNavigatorProps} from '@react-navigation/native-stack/src/types' 23 24import {PWI_ENABLED} from '#/lib/build-flags' 25import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 26import {useSession} from '#/state/session' 27import {useOnboardingState} from '#/state/shell' 28import { 29 useLoggedOutView, 30 useLoggedOutViewControls, 31} from '#/state/shell/logged-out' 32import {useGate} from 'lib/statsig/statsig' 33import {isNative, isWeb} from 'platform/detection' 34import {Deactivated} from '#/screens/Deactivated' 35import {Onboarding} from '#/screens/Onboarding' 36import {SignupQueued} from '#/screens/SignupQueued' 37import {LoggedOut} from '../com/auth/LoggedOut' 38import {BottomBarWeb} from './bottom-bar/BottomBarWeb' 39import {DesktopLeftNav} from './desktop/LeftNav' 40import {DesktopRightNav} from './desktop/RightNav' 41 42type NativeStackNavigationOptionsWithAuth = NativeStackNavigationOptions & { 43 requireAuth?: boolean 44} 45 46function NativeStackNavigator({ 47 id, 48 initialRouteName, 49 children, 50 screenListeners, 51 screenOptions, 52 ...rest 53}: NativeStackNavigatorProps) { 54 const gate = useGate() 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 ( 106 !hasSession && 107 (!PWI_ENABLED || 108 activeRouteRequiresAuth || 109 (isNative && gate('native_pwi_disabled'))) 110 ) { 111 return <LoggedOut /> 112 } 113 if (hasSession && currentAccount?.signupQueued) { 114 return <SignupQueued /> 115 } 116 if (showLoggedOut) { 117 return <LoggedOut onDismiss={() => setShowLoggedOut(false)} /> 118 } 119 if (currentAccount?.status === 'deactivated') { 120 return <Deactivated /> 121 } 122 if (onboardingState.isActive) { 123 return <Onboarding /> 124 } 125 const newDescriptors: typeof descriptors = {} 126 for (let key in descriptors) { 127 const descriptor = descriptors[key] 128 const requireAuth = descriptor.options.requireAuth ?? false 129 newDescriptors[key] = { 130 ...descriptor, 131 render() { 132 if (requireAuth && !hasSession) { 133 return <View /> 134 } else { 135 return descriptor.render() 136 } 137 }, 138 } 139 } 140 141 // 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 142 // on both tablet and mobile web so that we see the sign up CTA. 143 const showBottomBar = hasSession ? isMobile : isTabletOrMobile 144 145 return ( 146 <NavigationContent> 147 <NativeStackView 148 {...rest} 149 state={state} 150 navigation={navigation} 151 descriptors={newDescriptors} 152 /> 153 {isWeb && showBottomBar && <BottomBarWeb />} 154 {isWeb && !showBottomBar && ( 155 <> 156 <DesktopLeftNav /> 157 <DesktopRightNav routeName={activeRoute.name} /> 158 </> 159 )} 160 </NavigationContent> 161 ) 162} 163 164export const createNativeStackNavigatorWithAuth = createNavigatorFactory< 165 StackNavigationState<ParamListBase>, 166 NativeStackNavigationOptionsWithAuth, 167 NativeStackNavigationEventMap, 168 typeof NativeStackNavigator 169>(NativeStackNavigator)