# Navigation

NOTE

This documentation is the same for both the customer and clerk applications.

# Overview

React Navigation 5 offers a completely new API based on components rather than JSON-serializable objects.

# Relevant files

AppNavigator.js

navigation/stack_navigators

DrawerContent.js

# Existing stacks

Currently, the following stacks exist:

  • AppStack (AppNavigator.js): Screens accessible within the app, as provided by drawer tabs

  • AuthStack (stack_navigators/AuthStack.js): Deals with authorization screens like sign up and login

Customer app only

  • NewsStack (stack_navigators/NewsStack.js): Currently unused

  • ResourcesStack (stack_navigators/ResourcesStack.js): Points to the resources screen, accessible via the drawer

  • StoresStack (stack_navigators/StoresStack.js): Screens related to store lookup, such as the map screen, store list, products screen (per-store basis), and store details screen (per-store basis)

# Flow diagrams

# Customer app flow

Auth Flow Drawer

# Clerk app flow

ClerkFlow

# Adding a new stack

TIP

Refer to documentation on adding a new stack (opens new window)

Create a new file under stack_navigators .

import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';
import { Platform } from 'react-native'; // for config
import NewScreen from '{new screen path name here}';

const NewStack = createStackNavigator();

export default function NewStackNavigator() {
  return (
    <NewStack.Navigator
      screenOptions={{
        drawerLabel: 'New Screen',
        headerShown: false,
        cardStyle: { backgroundColor: Colors.lightest },
        config,
      }}>
      <NewStack.Screen name="NewStuff" component={NewScreen} />
    </NewStack.Navigator>
  );
}

# screenOptions

drawerLabel: The label that you want to appear on the drawer in the app, if applicable (i.e. you will be adding this stack to the DrawerNavigator)

headerShown: prevents default header from being displayed in app, should set to false for style consistency purposes

config: Add this to your stack files.

const config = Platform.select({
  web: { headerMode: 'screen' },
  default: {
    headerMode: 'none',
  },
});

# NewStack.Screen

name: What you will refer to your screen as when navigating between screens in the app

component: The name of the screen component being rendered

# Adding a new screen

  1. Create a new screen component (i.e. NewScreen)
  2. Import screen to corresponding stack navigator and pass in as screen component under the stack

NOTE

We've had a lot of issues with class components conflicting with our need to use hooks (i.e. useEffect or useFocusEffect), so it would be best to make a functional component from the get-go and avoid using deprecated methods like componentWillReceiveProps in classes

# Adding a tab to the drawer (hamburger menu)

No actual edits need to be made to the HamburgerButton when changing the drawer. The drawer relies on React Navigation + Drawer, so all the button does is call toggleDrawer.

Import and pass in your new screen or stack to the DrawerNavigator

<Drawer.Screen
  name="New"
  component={NewStackNavigator}
  options={{ title: 'New Screen', swipeEnabled: false }}
/>

NOTE

name : how we will reference the stack or screen when navigating within the app, if necessary to define

title: string that can be used as a fallback for headerTitle (docs (opens new window)), NOT to be confused with drawerLabel (we don't really need this if we don't have a header)

Styling for the drawer can be found in DrawerContent.js.

TIP

The external links in the hamburger menu can be modified without updating the code by updating the redirect URL of the short-links. See this table for a reference on the existing links in the hamburger menus.

These links are basically hardcoded and not passed in as props from the DrawerNavigator to DrawerContent. To add functional buttons (such as the LogOut button), add a styled TouchableOpacity and have it and call a function in onPress.

<TouchableOpacity
  style={{ padding: 16 }}
  onPress={() => action()}>
  <Title>New Link</Title>
</TouchableOpacity>

Refer to "Report Issue" and "Log Out" buttons for more details in DrawerContent.

This is an example from StoreCard.js upon clicking the search bar to navigate to StoresList:

navigation.navigate('Stores', {
  currentStore: store,
})

The first argument, 'Stores', is the name of the screen you want to navigate to.

The second argument refers to props we want to pass in between components. In a class component, this is accessible via this.props.route.params.

const store = this.props.route.params;

In a functional component, this is accessible via the component parameter route.

const store = route.params;

For more details on parameters in components, visit this doc (opens new window).

In a functional component, you can use the useNavigation() hook.

const navigation = useNavigation();

You can also pass navigation to a functional component as a parameter.

In classes, you can get navigation through props.

<NavButtonContainer onPress={() => this.props.navigation.goBack()}>