Online Food Ordering App (7)
Tags: express, node, react, reactnative
Published: 2021-03-05 18:38:52

*<span>Photo by <a href="https://unsplash.com/@abillion?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">abillion</a> on <a href="https://unsplash.com/s/photos/food-mobile-app?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></span>*

<br/>
Hi, Welcome to part 7 of this series.<br/>

Today, we are going to implement authentication on our front-end apps.<br/>
We are going to start with the admin web app then proceed with the mobile app.<br/><br/>

***
| Project Steps |
| ----------- |
| [1. Backend - Project Setup](https://dev.to/the22mastermind/online-food-ordering-app-1-594j) :heavy_check_mark: |
| [2. Backend - Authentication - Sign Up](https://dev.to/the22mastermind/online-food-ordering-app-2-28po) :heavy_check_mark: |
| [3. Backend - Authentication - Login & Logout](https://dev.to/the22mastermind/online-food-ordering-app-3-1g8h) :heavy_check_mark: |
| [4. Backend - Place Order](https://dev.to/the22mastermind/online-food-ordering-app-4-5dc5) :heavy_check_mark: |
| [5. Backend - View Orders List & View a Specific Order](https://dev.to/the22mastermind/online-food-ordering-app-5-24gg) :heavy_check_mark: |
| [6. Backend - Update Order]() :heavy_check_mark: |
| [7. Front-end - Authentication]() :pushpin: |
| [8. Front-end - Place Order, View Orders List, and View Order Details]() :fire: |

***

<br/>
Let us begin with the admin web app `(gourmet-admin)`.<br/><br/>

- Make sure the main branch is up to date with the remote main branch

- Create a new `ft-authentication` branch off the main branch

- In your terminal, run the following command to install the packages we are going to be using:
```
yarn add @material-ui/core @material-ui/icons @material-ui/lab axios cross-env history parcel parcel-bundler react-hook-form react-router-dom
```

- Install dev-dependencies:
```
yarn add -D axios-mock-adapter @babel/core @babel/preset-env @babel/preset-react
```

- Inside `src` directory create the following directories: `components, context, navigation, pages, and utils`.

- Inside `src/components` directory create the following directories: `CustomDrawer, FormButton, FormInput, Loader, Title, and ToastNotification`.<br/>

I have seen a lot of people who like to put their test files in a separate `__tests__` directory in the project root and it is totally fine. For me though, I like it when a test file is right next to the component it is supposed to test. I think it makes more sense this way.<br/>
That being said, we are going to be creating a component with its test file in the same directory.<br/>

Let's start with a title component that we will use throughout our app to display page titles or headings.

- Inside `src/components/Title` create two files: `Title.js` and `Title.test.js`

- Inside `Title.js` paste the following:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xo21pr557eyr1prq8bhz.png)
 
- Inside `Title.test.js` paste the following:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ageh3h33u9y59gvt6821.png)

Do not pay attention to that import of render and screen on the second line for now. We will implement `src/customRender.js` before running our tests.<br/>
Cool!<br/>

- Implement the remaining components like [here](https://github.com/the22mastermind/gourmet-admin/tree/ft-authentication/src/components)

Let us now create a reducer that we will use to update our authentication state.<br/>

- Create a `src/context/reducers/authReducer.js` and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wzhcj7ul3kx1axyujnmt.png)
 
- Create a `src/contenxt/AuthState.js` and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j6kzz7l4bakox4fypai5.png)

- Create a `src/utils/history.js` and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a1tnwg2ntyfbidghg6m8.png)

- Create a `src/context/theme.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r71ivad8xx6pghp39oab.png)

Before creating the navigation of our app, let us create the three pages we will need for the authentication feature namely `LoginPage`, `Dashboard`, and `NotFound`.<br/>

- Inside `src/pages` create the following directories: `Dashboard`, `LoginPage`, and `NotFound`

- Create a `src/pages/NotFound/NotFound.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2rvnnlyhi2mcmnc9lwf0.png)

- Create a `src/pages/Dashboard/index.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/05oebga13dxw60vp6ocp.png)
 
- Create a `src/pages/LoginPage/LoginPage.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tg6ig1t1c04toi268nau.png)

- Create a `src/utils/validations.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54urb58siv1btq0se3dv.png)
 
- Create a `src/utils/api.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/798bebcg819a1mo9n2mi.png)

Now we can create our routes and app navigation.<br/>

What we want to achieve is when a user (admin) visits our web app, he will land on our login page then when he logs in, he will be redirected to the dashboard.<br/>

Let us implement a wrapper route that we will use to render protected routes like the dashboard.<br/>

- Create a `src/navigation/ProtectedRoute.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iwsqx9jborei6mw7q0rp.png)

- Create a `src/navigation/Routes.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ettw00vn15sgwgfrnl0.png)

Now we need to wrap our routes with our AuthProvider so that our components can have access to our state and ThemeProvider to be able to use Material UI components.<br/>

- Create a `src/navigation/index.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ry8cpt7w9fgi5oi41lek.png)

Now we just need to hook this Providers component in our main App and we are good to go.<br/>

- Update `src/App.js` to look like the following:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p6wpi6gatie0b9i9bhck.png)

Let us now update our scripts in `package.json` and launch our app.<br/>

- Update `scripts` to look like the following:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dd9f757emzjm8jm8yfpb.png)

- Update `public/index.html` to look like the following:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/98js9xy69l4lhssqtcyc.png)

- Now run `yarn start --open` to tell Parcel to build our app and launch it at `http://localhost:1234`.<br/>

When the app launches it should look like the image below:
![localhost_1234_(Laptop with HiDPI screen)](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bf5gvikjb99gh4a5x518.png)
<br/>
Great!<br/>

Let us now take care of our tests.<br/>

- Update `scripts` in `package.json` to look like the following:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ywazdlkp5rhht61d8x50.png)

- Create a `src/customRender.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jpzdf76t61hf5xc3cv45.png)

Learn more about how this file is useful [here](https://testing-library.com/docs/react-testing-library/setup).<br/>

- Create a `src/pages/LoginPage.test.js` and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/drsv7jpjhsm590ny09u8.png)

In this file we are testing if the page renders correctly, validation errors then we mock HTTP requests to our API to test scenarios such as when there is a network issue, when the user trying to login does not exist or when the user exists but he/she is not an admin and finally we test a successful login.<br/>

- Run `yarn test` to run the unit and integration tests with Jest. When the test runner finishes you should see each test file's status and the test coverage.<br/>

At the moment I have 96% coverage which is not bad. You could use the coverage table to investigate the uncovered lines and write either unit tests or integration tests to cover them and increase coverage.<br/>

Now we can commit our changes to GitHub and open a PR to trigger a build on CircleCI.<br/>

If all goes well, go ahead and merge the PR and we can proceed with the mobile app.<br/><br/>

For reference, check out this [branch](https://github.com/the22mastermind/gourmet-admin/tree/ft-authentication)<br/>

***

For our mobile app we need to implement sign up on top of login and logout.<br/>

Let's do it.<br/>

- Switch to the `Gourmet` project directory that we created in the previous post and make sure the main branch is up to date with its remote

- Create a new `ft-authentication` branch off the main branch

- Install dependencies by running:
```
yarn add @react-native-async-storage/async-storage @react-navigation/native @react-navigation/stack @react-native-community/masked-view react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-screens react-native-paper react-native-vector-icons react-hook-form axios prop-types
```

- Install additional dev-dependencies:
```
yarn add -D axios-mock-adapter
```

- Inside `src` create the following directories: `components, context, navigation, screens, and utils` and in each directory create a component file and its test file like [here](https://github.com/the22mastermind/gourmet/tree/ft-authentication/src/components)

- Create a new `src/utils/storage.js` file and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6i7g50nk3w2jwewbeh8j.png)

This code will help us to interact with the storage by using the [AsyncStorage](https://react-native-async-storage.github.io/async-storage/docs/usage) package to create, fetch, and delete data.<br/>

- Create a new `src/utils/validations.js` and paste the following inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tfdni0ex4t1pje0qnanp.png)
 
- Create a new `src/utils/api.js` file and paste the following code inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c4ybt9hbem1iwngucs4s.png)
 
Let us now create our context providers and consumers.<br/>

- Create a new directory `reducers` in `src/context/`

- Create a new `src/context/reducers/AuthReducer.js` file and paste the following code inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/afq02mzx8bqg3k7h5odt.png)
 
- Create a new `src/context/reducers/AlertReducer.js` file and paste the following code inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z4kv23mh7ckv4dpks4ie.png)

- Create a new `src/context/AuthProvider.js` file and paste the following code inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6mcw51fi5f51ddw4ezhi.png)
 
- Create a new `src/context/AlertProvider.js` file and paste the following code inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3bj0on51btpiu6n589f.png)

- Create a new `src/context/theme.js` file and paste the following code inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uj4s0po06lk9un7rb8tj.png)

Now we can create the first screens of our app. We are going to create a `signup screen, verify screen, login screen, and home screen`. The `home screen` will only be visible to logged in users. Let us first create the screens then we can separate them in `AustStack` and `HomeStack`.<br/>

- Inside `src/screens` create the following directories: `HomeScreen`, `LoginScreen`, `SignupScreen`, and `VerifyScreen`

- Inside `src/screens/SignupScreen` create two files: `SignupScreen.js` and `SignupScreen.test.js`

- Inside `src/screens/SignupScreen/SignupScreen.js` paste the following code:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7eku6hhzfj9put9c2ffp.png)
 
- Inside `src/screens/SignupScreen/SignupScreen.test.js` paste the following code:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dmkufymrobr3ulvrzy87.png)

- Inside `src/screens/VerifyScreen` create two files: `VerifyScreen.js` and `VerifyScreen.test.js`

- Inside `src/screens/VerifyScreen/VerifyScreen.js` paste the following code:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fmpph8cu9a022ax2kevu.png)

- Inside `src/screens/VerifyScreen/VerifyScreen.test.js` paste the following code:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sebtm62yvhvri7ztpymu.png)
 
- Inside `src/screens/LoginScreen` create two files: `LoginScreen.js` and `LoginScreen.test.js`

- Inside `src/screens/LoginScreen/LoginScreen.js` paste the following code:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2a9v8r2aqtqq8d71ake4.png)

- Inside `src/screens/LoginScreen/LoginScreen.test.js` paste the following code:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02m8usgjvean0dcehe3g.png)
 
- Inside `src/screens/HomeScreen` create two files: `HomeScreen.js` and `HomeScreen.test.js`

- Inside `src/screens/HomeScreen/HomeScreen.js` paste the following code:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g434vocmlkgu5vschsog.png)
 
- Inside `src/screens/HomeScreen/HomeScreen.test.js` paste the following code:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tyk8rxu8orirqlkvn5za.png)
 
- Create a new `src/navigation/AuthStack.js` file and paste the following code inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5aa77bgomdhrfux65trh.png)

- Create a new `src/navigation/HomeStack.js` file and paste the following code inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ynrxgwummwdnegswnu8.png)

- Create a new `src/navigation/Routes.js` file and paste the following code inside:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2x6yul2qln6a8o0f9at4.png)

- Create a new `src/navigation/__tests__` directory and inside create a `Routes.test.js` file with the following content:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0la24dasmdmg8bjxlfd6.png)
 
Now let us wrap our routes with the providers we created earlier and the React-Native-Paper provider.<br/>

- Update `src/App.js` file to look like the following:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k4ajh3nergz5lc6qz1by.png)

If we were to run our tests they would fail because we haven't yet wrapped our providers around components and screens in the test environment. To do so, update `test-utils.js` to look like the following:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aqedszpw5bj5rf5zfnfb.png)

Now run the tests again and they should pass.<br/>

If you get errors make sure `jest.config.js, jest.setup.js, and setupFiles.js` look like below and run tests again:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gf9tz5r3lc4u0a09yfmv.png)

 
Alternatively, you can run the app on your emulator or physical device to test that everything works as it should.<br/>

That's it for today! Push the authentication branch to GitHub, open a PR, wait for the `Continuous Integration` workflow to succeed then merge the PR.<br/>

For reference, check out [this branch](https://github.com/the22mastermind/gourmet).<br/><br/>

In the next post, we will wrap up this series with the following features:

1. Place order (mobile app)
2. View orders list (mobile app and admin web app)
3. View single order details (mobile app and admin web app)<br/>

Thank you for your time. See you in the next post!