diff --git a/package-lock.json b/package-lock.json
index 7bd9a7ef2..29d564e76 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -29,7 +29,6 @@
"@react-native-picker/picker": "^2.11.1",
"@react-native-vector-icons/common": "^12.3.0",
"@react-navigation/bottom-tabs": "^7.4.6",
- "@react-navigation/drawer": "^7.5.7",
"@react-navigation/elements": "^2.6.3",
"@react-navigation/native": "^7.1.17",
"@react-navigation/native-stack": "^7.3.25",
@@ -6412,36 +6411,6 @@
"react": ">=16.8"
}
},
- "node_modules/@react-navigation/drawer": {
- "version": "7.5.7",
- "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-7.5.7.tgz",
- "integrity": "sha512-iRmeFUMZ4DPYgiuPVKsohL40flGAO0rxWwOg4iWkh0DsglI9yKpDXTUsUjmY4bMTv61jYYWV92OcSCBJjXwJoA==",
- "license": "MIT",
- "dependencies": {
- "@react-navigation/elements": "^2.6.3",
- "color": "^4.2.3",
- "react-native-drawer-layout": "^4.1.12",
- "use-latest-callback": "^0.2.4"
- },
- "peerDependencies": {
- "@react-navigation/native": "^7.1.17",
- "react": ">= 18.2.0",
- "react-native": "*",
- "react-native-gesture-handler": ">= 2.0.0",
- "react-native-reanimated": ">= 2.0.0",
- "react-native-safe-area-context": ">= 4.0.0",
- "react-native-screens": ">= 4.0.0"
- }
- },
- "node_modules/@react-navigation/drawer/node_modules/use-latest-callback": {
- "version": "0.2.4",
- "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.4.tgz",
- "integrity": "sha512-LS2s2n1usUUnDq4oVh1ca6JFX9uSqUncTfAm44WMg0v6TxL7POUTk1B044NH8TeLkFbNajIsgDHcgNpNzZucdg==",
- "license": "MIT",
- "peerDependencies": {
- "react": ">=16.8"
- }
- },
"node_modules/@react-navigation/elements": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.6.3.tgz",
@@ -19888,28 +19857,6 @@
"react-native-reanimated": ">=2.8.0"
}
},
- "node_modules/react-native-drawer-layout": {
- "version": "4.1.12",
- "resolved": "https://registry.npmjs.org/react-native-drawer-layout/-/react-native-drawer-layout-4.1.12.tgz",
- "integrity": "sha512-oKolvp5seiUieG+RHGjpFe8rH8Ds24iW0QBl31TlCVOX7tdn42IQIBl5tuD1i7h3q+VqqnbcT+NB2dcJ5suZkw==",
- "dependencies": {
- "use-latest-callback": "^0.2.4"
- },
- "peerDependencies": {
- "react": ">= 18.2.0",
- "react-native": "*",
- "react-native-gesture-handler": ">= 2.0.0",
- "react-native-reanimated": ">= 2.0.0"
- }
- },
- "node_modules/react-native-drawer-layout/node_modules/use-latest-callback": {
- "version": "0.2.4",
- "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.4.tgz",
- "integrity": "sha512-LS2s2n1usUUnDq4oVh1ca6JFX9uSqUncTfAm44WMg0v6TxL7POUTk1B044NH8TeLkFbNajIsgDHcgNpNzZucdg==",
- "peerDependencies": {
- "react": ">=16.8"
- }
- },
"node_modules/react-native-event-listeners": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/react-native-event-listeners/-/react-native-event-listeners-1.0.7.tgz",
diff --git a/package.json b/package.json
index d9796fc6a..e54c89987 100644
--- a/package.json
+++ b/package.json
@@ -65,7 +65,6 @@
"@react-native-picker/picker": "^2.11.1",
"@react-native-vector-icons/common": "^12.3.0",
"@react-navigation/bottom-tabs": "^7.4.6",
- "@react-navigation/drawer": "^7.5.7",
"@react-navigation/elements": "^2.6.3",
"@react-navigation/native": "^7.1.17",
"@react-navigation/native-stack": "^7.3.25",
diff --git a/src/components/App.js b/src/components/App.js
index 7bb2c1c08..b128d127c 100644
--- a/src/components/App.js
+++ b/src/components/App.js
@@ -1,7 +1,7 @@
// @flow
import { useNavigation } from "@react-navigation/native";
-import RootDrawerNavigator from "navigation/rootDrawerNavigator";
+import RootStackNavigator from "navigation/RootStackNavigator";
import type { Node } from "react";
import React, { useCallback } from "react";
import { log } from "sharedHelpers/logger";
@@ -80,7 +80,7 @@ const App = ( { children }: Props ): Node => {
- {children || }
+ {children || }
>
);
};
diff --git a/src/navigation/CustomDrawerContent.tsx b/src/navigation/CustomDrawerContent.tsx
deleted file mode 100644
index 0c023f43e..000000000
--- a/src/navigation/CustomDrawerContent.tsx
+++ /dev/null
@@ -1,348 +0,0 @@
-import { useNetInfo } from "@react-native-community/netinfo";
-import {
- DrawerContentScrollView,
- DrawerItem
-} from "@react-navigation/drawer";
-import { useQueryClient } from "@tanstack/react-query";
-import classnames from "classnames";
-import {
- signOut
-} from "components/LoginSignUp/AuthenticationService";
-import {
- Body1,
- Heading4,
- INatIcon,
- INatIconButton,
- List2, TextInputSheet,
- UserIcon,
- WarningSheet
-} from "components/SharedComponents";
-import { Pressable, View } from "components/styledComponents";
-import { RealmContext } from "providers/contexts";
-import React, { useCallback, useMemo, useState } from "react";
-import type { ViewStyle } from "react-native";
-import {
- Alert, Dimensions
-} from "react-native";
-import User from "realmModels/User";
-import { BREAKPOINTS } from "sharedHelpers/breakpoint";
-import { log } from "sharedHelpers/logger";
-import { useCurrentUser, useTranslation } from "sharedHooks";
-import useStore, { zustandStorage } from "stores/useStore";
-import colors from "styles/tailwindColors";
-
-const { useRealm } = RealmContext;
-
-const { width } = Dimensions.get( "screen" );
-
-function isDefaultMode( ) {
- return useStore.getState( ).layout.isDefaultMode === true;
-}
-
-const createDrawerStyle = ( isDark: boolean ) => ( {
- backgroundColor: isDark
- ? colors.darkModeGray
- : "white",
- borderTopRightRadius: 20,
- borderBottomRightRadius: 20,
- minHeight: "100%"
-} as const );
-
-interface Props {
- state: object;
- navigation: object;
- descriptors: object;
- colorScheme?: string;
-}
-
-const feedbackLogger = log.extend( "feedback" );
-
-function showOfflineAlert( t ) {
- Alert.alert( t( "You-are-offline" ), t( "Please-try-again-when-you-are-online" ) );
-}
-
-const CustomDrawerContent = ( {
- state, navigation, descriptors, colorScheme
-}: Props ) => {
- const isDebug = zustandStorage.getItem( "debugMode" ) === "true";
- const isDarkMode = colorScheme === "dark" && isDebug;
- const drawerScrollViewStyle = createDrawerStyle( isDarkMode );
- const realm = useRealm( );
- const queryClient = useQueryClient( );
- const currentUser = useCurrentUser( );
- const { t } = useTranslation( );
-
- const { isConnected } = useNetInfo( );
-
- const [showConfirm, setShowConfirm] = useState( false );
- const [showFeedback, setShowFeedback] = useState( false );
-
- const drawerItemStyle = useMemo( ( ) => ( {
- marginBottom: width <= BREAKPOINTS.lg
- ? -15
- : -5
- } as const ), [] );
-
- interface DrawerItem {
- label: string;
- navigation?: string;
- icon: string;
- color?: string;
- style?: ViewStyle;
- onPress?: ( ) => void;
- testID?: string;
- }
- const drawerItems = useMemo( ( ) => {
- const items: {
- [key: string]: DrawerItem;
- } = {
- projects: {
- label: t( "PROJECTS" ),
- navigation: "Projects",
- icon: "briefcase"
- },
- about: {
- label: t( "ABOUT" ),
- navigation: "About",
- icon: "inaturalist"
- },
- donate: {
- label: t( "DONATE" ),
- navigation: "Donate",
- icon: "heart"
- },
- help: {
- label: t( "HELP" ),
- navigation: "Help",
- icon: "help-circle"
- },
- settings: {
- testID: "settings",
- label: t( "SETTINGS" ),
- navigation: "Settings",
- icon: "gear"
- }
- };
- items.feedback = {
- label: t( "FEEDBACK" ),
- icon: "feedback",
- onPress: ( ) => {
- if ( isConnected ) {
- setShowFeedback( true );
- } else {
- showOfflineAlert( t );
- }
- }
- };
-
- if ( currentUser ) {
- items.logout = {
- label: t( "LOG-OUT" ),
- icon: "door-exit",
- style: {
- opacity: 0.5,
- display: "flex"
- },
- onPress: ( ) => setShowConfirm( true )
- };
- } else {
- items.login = {
- label: t( "LOG-IN" ),
- icon: "door-enter",
- color: colors.inatGreen,
- style: {
- display: "flex"
- },
- onPress: ( ) => {
- navigation.navigate( "LoginStackNavigator" );
- }
- };
- }
- if ( isDebug ) {
- items.debug = {
- label: "DEBUG",
- navigation: "Debug",
- icon: "triangle-exclamation",
- color: "deeppink"
- };
- }
- return items;
- }, [currentUser, isConnected, isDebug, navigation, t] );
-
- const onSignOut = async ( ) => {
- await signOut( { realm, clearRealm: true, queryClient } );
- setShowConfirm( false );
-
- // TODO might be necessary to restart the app at this point. We just
- // deleted the realm file on disk, but the RealmProvider may still have a
- // copy of realm in local state
- navigation.goBack( );
- };
-
- const renderIcon = useCallback( ( key: string ) => (
-
- ), [drawerItems, isDarkMode] );
-
- const renderLabel = useCallback( ( label: string ) => (
-
- {label}
-
- ), [isDarkMode] );
-
- const renderTopBanner = useCallback( ( ) => (
- {
- if ( !currentUser ) {
- navigation.navigate( "LoginStackNavigator" );
- } else {
- navigation.navigate( "TabNavigator", {
- screen: "ObservationsTab",
- params: {
- screen: "UserProfile",
- params: { userId: currentUser.id }
- }
- } );
- }
- }}
- >
- {currentUser
- ? (
-
- )
- : (
-
- ) }
-
-
- {currentUser
- ? currentUser?.login
- : t( "Log-in-to-iNaturalist" )}
-
- {currentUser && (
-
- {t( "X-Observations", { count: currentUser.observations_count } )}
-
- )}
-
-
- ), [currentUser, navigation, t, isDarkMode] );
-
- const renderDrawerItem = useCallback( ( key: string ) => (
-
- renderIcon( key )}
- label={() => renderLabel( drawerItems[key].label )}
- onPress={( ) => {
- if ( drawerItems[key].navigation ) {
- navigation.navigate( "TabNavigator", {
- screen: "ObservationsTab",
- params: {
- screen: drawerItems[key].navigation
- }
- } );
- }
- if ( drawerItems[key].onPress ) {
- drawerItems[key].onPress();
- }
- }}
- style={[drawerItemStyle, drawerItems[key].style]}
- />
-
- ), [
- drawerItemStyle,
- renderLabel,
- renderIcon,
- drawerItems,
- navigation
- ] );
-
- const submitFeedback = useCallback( ( text: string ) => {
- if ( !isConnected ) {
- showOfflineAlert( t );
- return false;
- }
- const mode = isDefaultMode( )
- ? "DEFAULT:"
- : "ADVANCED:";
- feedbackLogger.info( mode, text );
- Alert.alert( t( "Feedback-Submitted" ), t( "Thank-you-for-sharing-your-feedback" ) );
- setShowFeedback( false );
- return true;
- }, [isConnected, t] );
-
- return (
-
-
- {renderTopBanner( )}
-
- {Object.keys( drawerItems ).map( item => renderDrawerItem( item ) )}
-
-
- {showConfirm && (
- setShowConfirm( false )}
- headerText={t( "LOG-OUT--question" )}
- text={t( "Are-you-sure-you-want-to-log-out" )}
- handleSecondButtonPress={() => setShowConfirm( false )}
- secondButtonText={t( "CANCEL" )}
- confirm={onSignOut}
- buttonText={t( "LOG-OUT" )}
- />
- )}
- {showFeedback && (
- setShowFeedback( false )}
- headerText={t( "FEEDBACK" )}
- confirm={submitFeedback}
- description={t( "Thanks-for-using-any-suggestions" )}
- maxLength={1000}
- />
- )}
-
- );
-};
-
-export default CustomDrawerContent;
diff --git a/src/navigation/RootStackNavigator.tsx b/src/navigation/RootStackNavigator.tsx
new file mode 100644
index 000000000..434fc7254
--- /dev/null
+++ b/src/navigation/RootStackNavigator.tsx
@@ -0,0 +1,47 @@
+import { createNativeStackNavigator } from "@react-navigation/native-stack";
+import LoginStackNavigator from "navigation/StackNavigators/LoginStackNavigator";
+import NoBottomTabStackNavigator from "navigation/StackNavigators/NoBottomTabStackNavigator";
+import OnboardingStackNavigator from "navigation/StackNavigators/OnboardingStackNavigator";
+import * as React from "react";
+import { useOnboardingShown } from "sharedHelpers/installData";
+
+import BottomTabNavigator from "./BottomTabNavigator";
+
+const Stack = createNativeStackNavigator( );
+
+// DEVELOPERS: do you need to add any screens here? This is the RootStack.
+// All the rest of our screens live in:
+// NoBottomTabStackNavigator, TabStackNavigator, OnboardingStackNavigator, or LoginStackNavigator
+
+const RootStackNavigator = ( ) => {
+ const [onboardingShown] = useOnboardingShown( );
+
+ return (
+
+ {!onboardingShown
+ ? (
+
+ )
+ : (
+
+
+ )}
+
+
+
+ );
+};
+
+export default RootStackNavigator;
diff --git a/src/navigation/rootDrawerNavigator.js b/src/navigation/rootDrawerNavigator.js
deleted file mode 100644
index 36ce11e88..000000000
--- a/src/navigation/rootDrawerNavigator.js
+++ /dev/null
@@ -1,80 +0,0 @@
-// @flow
-
-import { createDrawerNavigator } from "@react-navigation/drawer";
-import {
- hideDrawerHeaderLeft, hideHeader
-} from "navigation/navigationOptions";
-import LoginStackNavigator from "navigation/StackNavigators/LoginStackNavigator";
-import NoBottomTabStackNavigator from "navigation/StackNavigators/NoBottomTabStackNavigator";
-import OnboardingStackNavigator from "navigation/StackNavigators/OnboardingStackNavigator";
-import type { Node } from "react";
-import * as React from "react";
-import { useColorScheme } from "react-native";
-import { useOnboardingShown } from "sharedHelpers/installData";
-
-import BottomTabNavigator from "./BottomTabNavigator";
-import CustomDrawerContent from "./CustomDrawerContent";
-
-const drawerOptions = {
- ...hideHeader,
- ...hideDrawerHeaderLeft,
- drawerType: "front",
- drawerStyle: {
- backgroundColor: "transparent"
- },
- swipeEnabled: false
-};
-
-const Drawer = createDrawerNavigator( );
-
-// DEVELOPERS: do you need to add any screens here? All the rest of our screens live in
-// NoBottomTabStackNavigator, TabStackNavigator, OnboardingStackNavigator, or LoginStackNavigator
-
-const RootDrawerNavigator = ( ): Node => {
- const [onboardingShown] = useOnboardingShown( );
- const colorScheme = useColorScheme( );
-
- const drawerRenderer = ( {
- state, navigation, descriptors
- } ) => (
-
- );
-
- return (
-
- {!onboardingShown
- ? (
-
- )
- : (
-
-
- )}
-
-
-
- );
-};
-
-export default RootDrawerNavigator;