diff options
Diffstat (limited to 'src/view/shell')
-rw-r--r-- | src/view/shell/createNativeStackNavigatorWithAuth.tsx | 150 | ||||
-rw-r--r-- | src/view/shell/index.web.tsx | 29 |
2 files changed, 152 insertions, 27 deletions
diff --git a/src/view/shell/createNativeStackNavigatorWithAuth.tsx b/src/view/shell/createNativeStackNavigatorWithAuth.tsx new file mode 100644 index 000000000..c7b5d1d2e --- /dev/null +++ b/src/view/shell/createNativeStackNavigatorWithAuth.tsx @@ -0,0 +1,150 @@ +import * as React from 'react' +import {View} from 'react-native' + +// Based on @react-navigation/native-stack/src/createNativeStackNavigator.ts +// MIT License +// Copyright (c) 2017 React Navigation Contributors + +import { + createNavigatorFactory, + EventArg, + ParamListBase, + StackActionHelpers, + StackActions, + StackNavigationState, + StackRouter, + StackRouterOptions, + useNavigationBuilder, +} from '@react-navigation/native' +import type { + NativeStackNavigationEventMap, + NativeStackNavigationOptions, +} from '@react-navigation/native-stack' +import type {NativeStackNavigatorProps} from '@react-navigation/native-stack/src/types' +import {NativeStackView} from '@react-navigation/native-stack' + +import {BottomBarWeb} from './bottom-bar/BottomBarWeb' +import {DesktopLeftNav} from './desktop/LeftNav' +import {DesktopRightNav} from './desktop/RightNav' +import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' +import {useOnboardingState} from '#/state/shell' +import { + useLoggedOutView, + useLoggedOutViewControls, +} from '#/state/shell/logged-out' +import {useSession} from '#/state/session' +import {isWeb} from 'platform/detection' +import {LoggedOut} from '../com/auth/LoggedOut' +import {Onboarding} from '../com/auth/Onboarding' + +type NativeStackNavigationOptionsWithAuth = NativeStackNavigationOptions & { + requireAuth?: boolean +} + +function NativeStackNavigator({ + id, + initialRouteName, + children, + screenListeners, + screenOptions, + ...rest +}: NativeStackNavigatorProps) { + // --- this is copy and pasted from the original native stack navigator --- + const {state, descriptors, navigation, NavigationContent} = + useNavigationBuilder< + StackNavigationState<ParamListBase>, + StackRouterOptions, + StackActionHelpers<ParamListBase>, + NativeStackNavigationOptionsWithAuth, + NativeStackNavigationEventMap + >(StackRouter, { + id, + initialRouteName, + children, + screenListeners, + screenOptions, + }) + React.useEffect( + () => + // @ts-expect-error: there may not be a tab navigator in parent + navigation?.addListener?.('tabPress', (e: any) => { + const isFocused = navigation.isFocused() + + // Run the operation in the next frame so we're sure all listeners have been run + // This is necessary to know if preventDefault() has been called + requestAnimationFrame(() => { + if ( + state.index > 0 && + isFocused && + !(e as EventArg<'tabPress', true>).defaultPrevented + ) { + // When user taps on already focused tab and we're inside the tab, + // reset the stack to replicate native behaviour + navigation.dispatch({ + ...StackActions.popToTop(), + target: state.key, + }) + } + }) + }), + [navigation, state.index, state.key], + ) + + // --- our custom logic starts here --- + const {hasSession} = useSession() + const activeRoute = state.routes[state.index] + const activeDescriptor = descriptors[activeRoute.key] + const activeRouteRequiresAuth = activeDescriptor.options.requireAuth ?? false + const onboardingState = useOnboardingState() + const {showLoggedOut} = useLoggedOutView() + const {setShowLoggedOut} = useLoggedOutViewControls() + const {isMobile} = useWebMediaQueries() + if (activeRouteRequiresAuth && !hasSession) { + return <LoggedOut /> + } + if (showLoggedOut) { + return <LoggedOut onDismiss={() => setShowLoggedOut(false)} /> + } + if (onboardingState.isActive) { + return <Onboarding /> + } + const newDescriptors: typeof descriptors = {} + for (let key in descriptors) { + const descriptor = descriptors[key] + const requireAuth = descriptor.options.requireAuth ?? false + newDescriptors[key] = { + ...descriptor, + render() { + if (requireAuth && !hasSession) { + return <View /> + } else { + return descriptor.render() + } + }, + } + } + return ( + <NavigationContent> + <NativeStackView + {...rest} + state={state} + navigation={navigation} + descriptors={newDescriptors} + /> + {isWeb && isMobile && <BottomBarWeb />} + {isWeb && !isMobile && ( + <> + <DesktopLeftNav /> + <DesktopRightNav /> + </> + )} + </NavigationContent> + ) +} + +export const createNativeStackNavigatorWithAuth = createNavigatorFactory< + StackNavigationState<ParamListBase>, + NativeStackNavigationOptionsWithAuth, + NativeStackNavigationEventMap, + typeof NativeStackNavigator +>(NativeStackNavigator) diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx index 74477243d..38da860bd 100644 --- a/src/view/shell/index.web.tsx +++ b/src/view/shell/index.web.tsx @@ -1,7 +1,5 @@ import React, {useEffect} from 'react' import {View, StyleSheet, TouchableOpacity} from 'react-native' -import {DesktopLeftNav} from './desktop/LeftNav' -import {DesktopRightNav} from './desktop/RightNav' import {ErrorBoundary} from '../com/util/ErrorBoundary' import {Lightbox} from '../com/lightbox/Lightbox' import {ModalsContainer} from '../com/modals/Modal' @@ -11,27 +9,19 @@ import {s, colors} from 'lib/styles' import {RoutesContainer, FlatNavigator} from '../../Navigation' import {DrawerContent} from './Drawer' import {useWebMediaQueries} from '../../lib/hooks/useWebMediaQueries' -import {BottomBarWeb} from './bottom-bar/BottomBarWeb' import {useNavigation} from '@react-navigation/native' import {NavigationProp} from 'lib/routes/types' import {useAuxClick} from 'lib/hooks/useAuxClick' import {t} from '@lingui/macro' -import { - useIsDrawerOpen, - useSetDrawerOpen, - useOnboardingState, -} from '#/state/shell' +import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell' import {useCloseAllActiveElements} from '#/state/util' -import {useLoggedOutView} from '#/state/shell/logged-out' function ShellInner() { const isDrawerOpen = useIsDrawerOpen() const setDrawerOpen = useSetDrawerOpen() - const onboardingState = useOnboardingState() - const {isDesktop, isMobile} = useWebMediaQueries() + const {isDesktop} = useWebMediaQueries() const navigator = useNavigation<NavigationProp>() const closeAllActiveElements = useCloseAllActiveElements() - const {showLoggedOut} = useLoggedOutView() useAuxClick() @@ -42,8 +32,6 @@ function ShellInner() { return unsubscribe }, [navigator, closeAllActiveElements]) - const showBottomBar = isMobile && !onboardingState.isActive - const showSideNavs = !isMobile && !onboardingState.isActive && !showLoggedOut return ( <View style={[s.hContentRegion, {overflow: 'hidden'}]}> <View style={s.hContentRegion}> @@ -51,22 +39,9 @@ function ShellInner() { <FlatNavigator /> </ErrorBoundary> </View> - - {showSideNavs && ( - <> - <DesktopLeftNav /> - <DesktopRightNav /> - </> - )} - <Composer winHeight={0} /> - - {showBottomBar && <BottomBarWeb />} - <ModalsContainer /> - <Lightbox /> - {!isDesktop && isDrawerOpen && ( <TouchableOpacity onPress={() => setDrawerOpen(false)} |