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