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