Timey: A Countdown Timer Web App

Mohebullah Mir
Strategio
Published in
7 min readNov 11, 2022
Empty high school classroom (courtesy of Mary Kate Lonergan)

I remember in my high school geometry class, the teacher would give a do-now (a warm-up task) to be completed in the first 10 minutes of the period. Well, being the nerd that I was (and still am), I would finish the task with plenty of time left. And since we would be obliterated by the teacher if we were caught talking, I would spend a lot of time just staring at the timer on the screen. Seconds would feel like minutes and minutes would feel like hours in the incredibly hostile and tense environment of that high school trigonometry class. The countless time spent staring at that stopwatch blew back to me this year as I was sitting around with nothing to do. I then knew what my next solo project would be, a timer app, one that hopefully wouldn’t be as boring as the one from class.

Building a foundation

Many engineers know that the most challenging part of creating a new application is the beginning for two reasons:

  1. Coming up with the right idea.
  2. Understanding how to convey that idea.

I got very lucky with the former in this case since the whole idea of the timer was an epiphany. The latter is more sophisticated because it will determine how complex the app will be. In my case, I had to determine which programming languages/tech stack I had to use and whether or not I wanted to replicate my idea exactly or have my creative twist. I decided to go along with the MERN stack (MongoDB, ExpressJS, ReactJs, NodeJS) because I had just learned it and wanted to get my hands dirty with it. And in terms of copying the idea exactly, I chose not to because I didn’t want to be as bored as I was in that math class!

Crafting the frontend

I tend to always start my projects off with the front end, once I have something tangible to look at, I get a better understanding of what I need to change or do to get to where I want. Since I went with React, I decided to break my front end down into a bunch of components. I won’t be going over every nook and cranny here, but the general structure of the React app. The first main component was createArea.jsx, this is essentially a menu that allows us to create a timer. You have to create an event title, choose a date from a calendar, specify a target time, choose an optional color for your timer, and click the plus sign to generate the timer and display it.

createArea component

As we can see in the gist above, this is a general overview of the return statement for our createArea component, I cut out a bunch of lines to save up space but it’s still taking a huge portion of the screen!

I used the useState() hook to store information about our event in this component. Event information would then be updated dynamically with each change in input calling the handleInput() function. Color is also a custom component I built solely for the purpose of customization, there are about 7 different colors to choose from, and the choice is updated dynamically thanks to the useState() hook again. Finally, we call the addEvent() function when we want to create the event, this adds the event object to an array that stores all our custom events. All the events are then mapped onto the screen to be viewed at once. Yes, that’s right, we can create as many timers as we want! They will all run simultaneously.

Since we briefly discussed what our App component consists of the createArea component and an array that stores all events which get mapped out to our display. We can move on to our next most important component, TimedEvent.jsx.

The TimedEvent component dictates what we want to display to our users and the actual logic behind the timer itself. The structure of our timer is quite simple, so we’ll get that out of the way first.

Timer structure

  1. An Event title.
  2. A custom background color.
  3. Time count (Days, Hours, Minutes, Seconds).
  4. An icon to delete the timer.
Timer component

Essentially, I’m pasting the info that was passed from the creation component onto the timer component. Details like the event title, background color, timer labels, and delete icon remain static, they won’t change for the duration of the component’s life. The only thing that needs to be dynamic is the time display itself, the seconds' timer will decrement with each passing second, the minutes' timer will decrement after each minute, and so on… To support this dynamic display, I have decided to incorporate a useState() hook again. The hook will store an object named countdown that contains the days, hours, minutes, and seconds left till the target date and time.

Generating the countdown time

The most important feature of the application itself is of course the logic. All I had to do was generate the current time using built-in Javascript functions and subtract the target time from the current time. This will output a result in milliseconds since the getTime() method generates time in milliseconds. After that, I just send the new time to the countdown object so the React hook can update itself. Finally, we just have to call the function repeatedly every second, to update the time accordingly.

Before you get too overwhelmed, let’s focus on the actual logic which can be seen in the top half of the function. As mentioned previously, I calculate the current time with the Javascript getTime() method and I subtract that from the target time now, which is not local to this function. After that, it’s just a bunch of arithmetic to convert milliseconds into the corresponding days, hours, minutes, and seconds.

There’s one thing you may be asking yourself, why didn’t you just subtract the time by one second each time the adjustDate() function is called, instead of recalculating the whole thing? Good eye, the main reason why I did this was to maintain consistency. If I were to subtract the time by one second with each function call, how would I ensure the time is accurate if the application were to time out or be revisited after a long period? Calculating the time with each function call will ensure the values remain consistent and correct no matter what disturbances were to occur. Perhaps there may be a more accurate approach with the former method by placing the current time in a useEffect() hook, but that’s a topic for some other time!

Repeating the call

Okay before you die of boredom, I just want to go over one more important detail, how I call the function to update the time. Initially, I was using the setTimeout(function(), delay) function to call my time adjuster every second, but this was quite disastrous. It turns out that setTimeout doesn’t do well with animation as it struggles with flickering and frame skips. I found a much better function requestAnimationFrame(), which produces high-quality animation and does not suffer from flickering or frame skips.

The backend

There was not much going on with the backend for this application as it is a frontend-intensive app that deals with animation and logic all executed on the front end. The main reason why I built a backend for this app was to maintain the persistence of data, I needed to store timer info so I could quit the application and not lose my data. This was achieved with MongoDB and Expressjs.

MongoDB schema

const timerSchema = new mongoose.Schema({
eventName:String,
eventDate:String,
eventTime:String,
color:String,
});
const Timer = mongoose.model("Timer",timerSchema);

So I used Mongo, a NoSQL document-based database to store information for my events. The information that went into the schema consisted of the event name, event date, event time, and color for the timer. This is pretty straightforward, every time I would need to fetch event data on page reload, I would use a useEffect() hook on the front end and fetch all the documents from the database via an API request.

//Fetching all timer data from the db and sending it as an array.
app.route("/timers")
.get((req,res)=>{
Timer.find({},(err,timers)=>{
if(err) res.send(err);
else{
res.json(timers);
}
})
})

And that is a broad overview of the functionality of Timey.

Brief demo of Timey functionality

The GitHub repository for the entire application can be found here:

Wow, if you made it this far then that means I haven’t bored you to death! Thank you for reading my article. Feel free to add a comment and follow me if you like the content.

--

--

Mohebullah Mir
Strategio

Software Engineer 💻 Avid Hiker 🌳 Fitness enthusiast 🏋️‍♀️