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