DEV Community

Cover image for Online Food Ordering App (7)
Bertrand Masabo
Bertrand Masabo

Posted on

Online Food Ordering App (7)

Photo by abillion on Unsplash



Hi, Welcome to part 7 of this series.

Today, we are going to implement authentication on our front-end apps.

We are going to start with the admin web app then proceed with the mobile app.





Let us begin with the admin web app (gourmet-admin).

  • 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
Enter fullscreen mode Exit fullscreen mode
  • Install dev-dependencies:
yarn add -D axios-mock-adapter @babel/core @babel/preset-env @babel/preset-react
Enter fullscreen mode Exit fullscreen mode
  • 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.

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.

That being said, we are going to be creating a component with its test file in the same directory.

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

  • Inside Title.test.js paste the following:
    image

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.

Cool!

  • Implement the remaining components like here

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

  • Create a src/context/reducers/authReducer.js and paste the following inside:
    image

  • Create a src/contenxt/AuthState.js and paste the following inside:
    image

  • Create a src/utils/history.js and paste the following inside:
    image

  • Create a src/context/theme.js file and paste the following inside:
    image

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.

  • 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

  • Create a src/pages/Dashboard/index.js file and paste the following inside:
    image

  • Create a src/pages/LoginPage/LoginPage.js file and paste the following inside:
    image

  • Create a src/utils/validations.js file and paste the following inside:
    image

  • Create a src/utils/api.js file and paste the following inside:
    image

Now we can create our routes and app navigation.

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.

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

  • Create a src/navigation/ProtectedRoute.js file and paste the following inside:
    image

  • Create a src/navigation/Routes.js file and paste the following inside:
    image

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.

  • Create a src/navigation/index.js file and paste the following inside: image

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

  • Update src/App.js to look like the following: image

Let us now update our scripts in package.json and launch our app.

  • Update scripts to look like the following:
    image

  • Update public/index.html to look like the following:
    image

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

When the app launches it should look like the image below:
localhost_1234_(Laptop with HiDPI screen)


Great!

Let us now take care of our tests.

  • Update scripts in package.json to look like the following:
    image

  • Create a src/customRender.js file and paste the following inside:
    image

Learn more about how this file is useful here.

  • Create a src/pages/LoginPage.test.js and paste the following inside: image

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.

  • 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.

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.

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

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

For reference, check out this branch


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

Let's do it.

  • 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
Enter fullscreen mode Exit fullscreen mode
  • Install additional dev-dependencies:
yarn add -D axios-mock-adapter
Enter fullscreen mode Exit fullscreen mode
  • 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

  • Create a new src/utils/storage.js file and paste the following inside:
    image

This code will help us to interact with the storage by using the AsyncStorage package to create, fetch, and delete data.

  • Create a new src/utils/validations.js and paste the following inside:
    image

  • Create a new src/utils/api.js file and paste the following code inside:
    image

Let us now create our context providers and consumers.

  • Create a new directory reducers in src/context/

  • Create a new src/context/reducers/AuthReducer.js file and paste the following code inside:
    image

  • Create a new src/context/reducers/AlertReducer.js file and paste the following code inside:
    image

  • Create a new src/context/AuthProvider.js file and paste the following code inside:
    image

  • Create a new src/context/AlertProvider.js file and paste the following code inside:
    image

  • Create a new src/context/theme.js file and paste the following code inside:
    image

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.

  • 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

  • Inside src/screens/SignupScreen/SignupScreen.test.js paste the following code:
    image

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

  • Inside src/screens/VerifyScreen/VerifyScreen.js paste the following code:
    image

  • Inside src/screens/VerifyScreen/VerifyScreen.test.js paste the following code:
    image

  • Inside src/screens/LoginScreen create two files: LoginScreen.js and LoginScreen.test.js

  • Inside src/screens/LoginScreen/LoginScreen.js paste the following code:
    image

  • Inside src/screens/LoginScreen/LoginScreen.test.js paste the following code:
    image

  • Inside src/screens/HomeScreen create two files: HomeScreen.js and HomeScreen.test.js

  • Inside src/screens/HomeScreen/HomeScreen.js paste the following code:
    image

  • Inside src/screens/HomeScreen/HomeScreen.test.js paste the following code:
    image

  • Create a new src/navigation/AuthStack.js file and paste the following code inside:
    image

  • Create a new src/navigation/HomeStack.js file and paste the following code inside:
    image

  • Create a new src/navigation/Routes.js file and paste the following code inside:
    image

  • Create a new src/navigation/__tests__ directory and inside create a Routes.test.js file with the following content:
    image

Now let us wrap our routes with the providers we created earlier and the React-Native-Paper provider.

  • Update src/App.js file to look like the following: image

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

Now run the tests again and they should pass.

If you get errors make sure jest.config.js, jest.setup.js, and setupFiles.js look like below and run tests again:
image

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

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.

For reference, check out this branch.

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)

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

Top comments (0)