In this tutorial we are going to create a Pomodoro Clock to help you track the time you spend working on different tasks.

 

The Result

pomodoro clock gif

You can see a live demo of this project Here

 

The Task

These are the user stories for this Pomodoro Clock:

  • [ ] User can start / pause / stop a timer
  • [ ] User can edit the title of a task
  • [ ] User can see a list of the completed pomodoro sessions
  • [ ] User can customize the duration of each work / break session

Now that we know what we want to achieve with this Pomodoro Clock, let's start building a simple HTML structure.

 


book banner

Get my ebook on Amazon and Leanpub

 

Play and Pause a timer

We will start by creating a simple HTML structure to display a timer and add buttons to start, pause and stop it.

 <div id="pomodoro-container">
  <div id="pomodoro-clock">
    <div id="pomodoro-timer"></div>
    <div id="pomodoro-clock-actions">
      <button id="pomodoro-start">Start</button>
      <button id="pomodoro-pause">Pause</button>
      <button id="pomodoro-stop">Stop</button>
    </div>
  </div>
</div>

Now that we have a basic structure let's start working on our toggleClock function in the script.js file.

This function will be called by all three buttons and will either start, pause or stop the timer.

First, let's attach an event listener to our buttons:

const pomodoroTimer = document.querySelector('#pomodoro-timer');

const startButton = document.querySelector('#pomodoro-start');
const pauseButton = document.querySelector('#pomodoro-pause');
const stopButton = document.querySelector('#pomodoro-stop');

// START
startButton.addEventListener('click', () => {
  toggleClock();
})

// PAUSE
pauseButton.addEventListener('click', () => {
  toggleClock();
})

// STOP
stopButton.addEventListener('click', () => {
  toggleClock(true);
})

We stored each of our buttons in a variable and attached event listeners to them.
As you can see, for the stopButton we are passing an argument in the toggleClock function. You will see why in a moment.

In order to know whether we need to play or pause the timer, we need an additional variable which we'll call isClockRunning which by default will be bind to false.

let isClockRunning = false;

We will need a few more variables to complete our initial set:

// in seconds = 25 mins
let workSessionDuration = 1500;
let currentTimeLeftInSession = 1500;

// in seconds = 5 mins;
let breakSessionDuration = 300;

Now let's start writing our toggleClock function.

 const toggleClock = (reset) => {
  if (reset) {
    // STOP THE TIMER
  } else {
    if (isClockRunning === true) {
      // PAUSE THE TIMER
      isClockRunning = false;
    } else {
      // START THE TIMER
      isClockRunning = true;
    }
  }
}

toggleClock takes one argument, reset which gets passed only when we are stopping the timer, otherwise we will look at the value of the variable isClockRunning to see whether we need to play or pause the timer.

We will leverage the built-in method setInterval to track our timer.

Inside of the else statement, right below isClockRunning = true we can write:

clockTimer = setInterval(() => {
    // decrease time left / increase time spent
    currentTimeLeftInSession--;
}, 1000)

What this does, is decrease our session time by 1 every second.

We want to be able to pause this timer when we click the pause button so go ahead and add this code to the toggleClock function right above isClockRunning = false :

clearInterval(clockTimer);

This will clear the timer that we set when we click the play button.

 

Create a function to format and display the time

The last step for this initial milestone will be to display the timer in our page.

To do that we will create a function called displayCurrentTimeLeftInSession which will get called every second from our timer.

First, let's add this line right under currentTimeLeftInSession--; so that our setInterval looks like this

clockTimer = setInterval(() => {
  currentTimeLeftInSession--;
  displayCurrentTimeLeftInSession();
}, 1000);

Now, under our toggleClock function, let's create a new one:

const displayCurrentTimeLeftInSession = () => {
  const secondsLeft = currentTimeLeftInSession;
  let result = '';
  const seconds = secondsLeft % 60;
  const minutes = parseInt(secondsLeft / 60) % 60;
  let hours = parseInt(secondsLeft / 3600);
  // add leading zeroes if it's less than 10
  function addLeadingZeroes(time) {
    return time < 10 ? `0${time}` : time
  }
  if (hours > 0) result += `${hours}:`
  result += `${addLeadingZeroes(minutes)}:${addLeadingZeroes(seconds)}`
  pomodoroTimer.innerText = result.toString();
}

Wow, I bet you got caught off-guard by this function but don't worry, it's not as complicate as it seems.

Since we are storing our timer in seconds, we need a way to format it so that the user can see minutes and seconds and not just seconds.

The symbol % is called the remainder and you can read more about it here.

What it does is return the left over of the division of the first and second operand.

Example:

const x = 70;
x % 60;
// 10

Now image that x is our secondsLeft. 70 seconds essentially means 1 minute and 10 seconds.

As you can see, by using % 60 we get the seconds to display.

The next step is to get how many minutes are left in our timer and we do that like this:

const minutes = parseInt(secondsLeft / 60) % 60;

This will return us 1.

The last step is to count the hours like so:

let hours = parseInt(secondsLeft / 3600);

3600 is the amount of seconds in one hour.

A proper clock should display time in this format: "07:08" so we need to have a way to add leading zeroes when the minutes or seconds are less than 10.

function addLeadingZeroes(time) {
  return time < 10 ? `0${time}` : time
}

This syntax may be confusing for a beginner but this is what is called a ternary operator and it is actually very simple and easy to use.

return time < 10 ? `0${time}` : time

Everytime before the '?' is what gets evaluated, in this case "is time less than 10?" and the first part in between the '?' and the ':' is what will return if the answer is YES whie the code after the ':' is what returns for a NO answer.

In plain text: "If time is less than 10, return time with a zero in front of it (eg: 09 instead of 9) and if time is more than 10, just return it".

The last part of the code simply creates a string by interpolating hours (if any), minutes and seconds together.

if (hours > 0) result += `${hours}:`
result += `${addLeadingZeroes(minutes)}:${addLeadingZeroes(seconds)}`

If you don't know what ${} means, you can read more about string interpolation here.

In short, it allows us to write both variables and plain text together without having to constantly add strings to each other with a plus sign.

Once we have our nicely formatted string representing the time left in our timer, it's time to add it to our page with this simple line of code:

pomodoroTimer.innerText = result;

You can continue reading this tutorial at this link