mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at ruby-v 5.4 kB view raw
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 {isNative, isWeb} from '#/platform/detection' 27import {useSession} from '#/state/session' 28import {useOnboardingState} from '#/state/shell' 29import { 30 useLoggedOutView, 31 useLoggedOutViewControls, 32} from '#/state/shell/logged-out' 33import {LoggedOut} from '#/view/com/auth/LoggedOut' 34import {Deactivated} from '#/screens/Deactivated' 35import {Onboarding} from '#/screens/Onboarding' 36import {SignupQueued} from '#/screens/SignupQueued' 37import {atoms as a} from '#/alf' 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 // --- this is copy and pasted from the original native stack navigator --- 55 const {state, descriptors, navigation, NavigationContent} = 56 useNavigationBuilder< 57 StackNavigationState<ParamListBase>, 58 StackRouterOptions, 59 StackActionHelpers<ParamListBase>, 60 NativeStackNavigationOptionsWithAuth, 61 NativeStackNavigationEventMap 62 >(StackRouter, { 63 id, 64 initialRouteName, 65 children, 66 screenListeners, 67 screenOptions, 68 }) 69 React.useEffect( 70 () => 71 // @ts-expect-error: there may not be a tab navigator in parent 72 navigation?.addListener?.('tabPress', (e: any) => { 73 const isFocused = navigation.isFocused() 74 75 // Run the operation in the next frame so we're sure all listeners have been run 76 // This is necessary to know if preventDefault() has been called 77 requestAnimationFrame(() => { 78 if ( 79 state.index > 0 && 80 isFocused && 81 !(e as EventArg<'tabPress', true>).defaultPrevented 82 ) { 83 // When user taps on already focused tab and we're inside the tab, 84 // reset the stack to replicate native behaviour 85 navigation.dispatch({ 86 ...StackActions.popToTop(), 87 target: state.key, 88 }) 89 } 90 }) 91 }), 92 [navigation, state.index, state.key], 93 ) 94 95 // --- our custom logic starts here --- 96 const {hasSession, currentAccount} = useSession() 97 const activeRoute = state.routes[state.index] 98 const activeDescriptor = descriptors[activeRoute.key] 99 const activeRouteRequiresAuth = activeDescriptor.options.requireAuth ?? false 100 const onboardingState = useOnboardingState() 101 const {showLoggedOut} = useLoggedOutView() 102 const {setShowLoggedOut} = useLoggedOutViewControls() 103 const {isMobile, isTabletOrMobile} = useWebMediaQueries() 104 if (!hasSession && (!PWI_ENABLED || activeRouteRequiresAuth || isNative)) { 105 return <LoggedOut /> 106 } 107 if (hasSession && currentAccount?.signupQueued) { 108 return <SignupQueued /> 109 } 110 if (showLoggedOut) { 111 return <LoggedOut onDismiss={() => setShowLoggedOut(false)} /> 112 } 113 if (currentAccount?.status === 'deactivated') { 114 return <Deactivated /> 115 } 116 if (onboardingState.isActive) { 117 return <Onboarding /> 118 } 119 const newDescriptors: typeof descriptors = {} 120 for (let key in descriptors) { 121 const descriptor = descriptors[key] 122 const requireAuth = descriptor.options.requireAuth ?? false 123 newDescriptors[key] = { 124 ...descriptor, 125 render() { 126 if (requireAuth && !hasSession) { 127 return <View /> 128 } else { 129 return descriptor.render() 130 } 131 }, 132 } 133 } 134 135 // 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 136 // on both tablet and mobile web so that we see the sign up CTA. 137 const showBottomBar = hasSession ? isMobile : isTabletOrMobile 138 139 return ( 140 <NavigationContent> 141 <View role="main" style={a.flex_1}> 142 <NativeStackView 143 {...rest} 144 state={state} 145 navigation={navigation} 146 descriptors={newDescriptors} 147 /> 148 </View> 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)