Off the back of a React Udemy course, which saw me create the React Burger Builder, I decided to dive straight in and create a “To Do” app using React.

I am well aware that “To Do” apps are a massive cliché in the development world, but doing this allowed me to focus on remembering all I’d learnt from the Udemy course instead of coming up with some new concept for an app. I also like to think that this project isn’t just your bog-standard “To Do” app, users can create their own accounts and all tasks are stored and managed online utilising storage and authentication via Firebase.

The final app is hosted on Netlify (as of August 2021) and can be accessed at https://formetodo.netlify.app/.

The code for “ForMeToDo” can be accessed at https://github.com/JonnyMars/for-me-to-do.

Design

I have a tendency to dive straight into development with only an idea in my head of how something should look, this can cause issues down the line. Creating a clear design before starting development allowed me to start thinking about how the different components would intertwine, and would also outline all expected functionality at the start, rather than bolting on core functionality at the end.

I mocked up some designs using Figma, I always knew I wanted to keep it simple and only allow users to have one ToDo list. Within this list, users should be able to add tasks, delete tasks and mark tasks as complete and uncomplete. The “completed” and “active” sections of the list are separate from each other, with the “completed” tasks being hidden behind an accordion by default. See an image of the design below...

Initial Figma design for the ForMeToDo app, showing a basic layout with a To Do list.

The only other element of the app that I mocked up within the design was a confirmation pop-up. I wanted to keep the list actions pretty streamlined, so the complete/uncomplete actions don’t require any confirmation because ultimately these actions are reversible. However, I wanted to have a confirmation message appear when a user clicked the delete button, as once a task is deleted there’s no undo function. Below is an image of the mock up for the task deletion confirmation pop-up...

Initial Figma design for the ForMeToDo app, showing the task delete confirmation message.

SASS Modules

When it came to the styling for the entire project, I decided to use SASS modules (https://create-react-app.dev/docs/adding-a-css-modules-stylesheet/). During the aforementioned React course, the instructor took us through multiple ways of styling your React projects, using methods such as CSS modules, Styled Components and inline styles.

For this project I opted to take the CSS modules one step further by using SASS modules. I am already really familiar with working with CSS modules and SASS independently, so combining the two proved a really easy learning curve. The power of SASS allowed me to create mixins for things such as media queries, to ensure that they remain consistent across all of my components and routes.

Firebase Auth

I needed a way to allow each user to be able to create their own account and manage ONLY their own tasks. To do this, I used the Firebase Auth REST API. Using the Firebase Auth API allowed me to get and store unique auth tokens that I could then use to authenticate requests to the storage API, so that users can only read, write and delete their own data.

I stored the authentication data using the React Context API. The Context API provides a way to pass data through the component tree without having to pass data to components manually at entry level. This was really useful as it meant that I could access the auth status and auth methods (login, signup, logout etc..) from pretty much anywhere within the app.

Firebase Storage

For storing any tasks that a user creates, I used a Firebase Realtime Database. Using this database is really easy, you can simply read, write and delete data using their REST API.

To manage all things tasks, I created a Custom React Hook. The “useTasks” hook contained everything needed to get, add, update and delete tasks. Using a hook to do this meant that I could access this functionality from pretty much any component, and it keeps my components clean and easy to manage.

Within the Realtime Database, I was able to set “Security Rules”. These security rules allowed me to do 2 important things:

  • Only allow users to access their own data, using the Firebase authentication mentioned previously.
  • Validate any data coming in, to ensure that it matches the desired formatting. For example, enforcing the task character limit of 60 characters and only allowing task statuses to be “completed” or “active”.

The security rules use a JavaScript-like syntax and JSON structure. You can see the rules I set up for my database below.

{
  "rules": {
    "tasks": {
      "$user_id": {
        ".read": "auth.uid === $user_id",
        ".write": "auth.uid === $user_id",
        "$task_id": {
          "title": {
            ".validate": "newData.isString() && newData.val().length < 61"
          },
          "status": {
            ".validate": "newData.isString() && ( newData.val() === 'completed' || newData.val() === 'active' )"
          }
        }
      }
    }
  }
}

Page - Login/Signup

ForMeToDo mainly consists of 2 “pages”. The one that a new user will see when they first visit the site is the Login/Signup page. This page contains two forms, one for an existing user to login and another for a new user to create an account.

Login or Signup page auth forms

Both forms require only an email and password for a user to login or sign up. The signup form also requires a user to tick a checkbox to agree to the app’s privacy policy before they can successfully create a new account. Both forms, and the fields within the forms, have appropriate input validation with any errors that occur when logging in/signing up appearing within a pop-up message.

Page - Tasks

Once a user is set up with an account, they can then access the Tasks page. This is where they can manage their own tasks.

A new user's tasks page, with no tasks created

New tasks can be created using an input box which is limited to only allow tasks to be 60 characters long, the current character count can be seen once a user starts typing. To add the task the user can simply press enter and the changes should appear within the list.

A new user in the process of creating a task.

Once a new user has added a few tasks, they can be seen within the task list located underneath the new task input. Within each task, a user can mark a task as “completed” or delete said task. These options are inline, and are signified by a green tick icon or a red cross icon respectively.

Tasks page with 4 active tasks

If a user marks a task as completed, it will be visible within an accordion element. Expanding the “Completed Tasks” accordion will show the user all of the tasks that have been marked as completed. The tasks within the “Completed Tasks” section can be marked as “active” and be returned to the active tasks list, or it can be deleted. These options are also inline, and are signified by a blue arrow icon pointing upwards or a red cross icon respectively.

Tasks page with 2 active tasks and 2 completed tasks

If a user attempts to delete a task, a confirmation pop-up will appear. Within this pop-up a user can confirm the delete action or cancel it. The deletion of tasks is the only step that requires a confirmation, as it might be annoying to have to re-create a task if you delete it by accident.

Pop-up confirmation asking user to confirm or cancel

The task list is completely responsive, with all items resizing easily based on the size of the browser. The only item that required some changes based on screen size is the task actions. When on smaller screen sizes, a blue ellipses (...) icon replaces any task actions. Clicking this icon reveals the available actions and allows the user to interact with them. This was implemented to allow users to see as many tasks as possible, even when on devices with small screens.

Side by side view, showing the process of carrying out an action on a task on mobile screen sizes

Page - Privacy Policy

As ForMeToDo requires a user to sign up using an email address and password, and I plan on publishing this app for a limited time to showcase it, I thought it would be a good idea to put together a small privacy policy.

The privacy policy was a free basic template generated by GetTerms.io.

I created a new container within React to add the privacy policy HTML. The likelihood is that nobody will ever visit this page, making it pretty pointless to make every user have to download this content every time they load the app. For this reason, I loaded the privacy policy container/component lazily. I did this using the React.lazy function and React Suspense.

What would I add to this app?

As with most projects any developer works on, something else comes up or catches their eye and the current project falls by the wayside. This has definitely happened with this project. This project has coincided with Summer here in the UK, which came with multiple easings of the COVID-19 restrictions. This means I’ve been spending more time outdoors with friends, instead of being sat inside coding.

For this reason, other things have popped up that I want to take a look at or work on, but I thought this app was worth sharing. As a result of this, it means that ForMeToDo is somewhat incomplete, but here are some things I’d add next if I were to spend more time on it (or if I ever revisit it in the future).

  • Add a “Forgot Your Password” feature, as currently there is no way for a user to retrieve or reset their password.
  • Add a landing or homepage with a summary of the app and what it’s about, rather than just cutting to the chase and redirecting any users to the Login/Sign Up page.
  • Allow users to create multiple lists and manage them individually.
  • I would try to rework the Auth refresh token functionality, I ended up having a battle with this and I still don’t think it’s working as it should.

Overall I’m happy with the outcome of this project and what I managed to put together mostly from memory, following the completion of a guided React course.