Login

Lost your password?
Don't have an account? Sign Up

Creating a Simple Pomodoro Web App — A Beginner’s Guide


Creating a Simple Pomodoro Web App — A Beginner’s Guide

In our overly connected, notification-filled world, attention seems to be a currency, one that is too easily wasted and yet as equally difficult to attain. Having been a learner all of my life, I can attest that the biggest roadblock to my progress in any learning area is distraction. After all, there always seem to be endless cat videos waiting to be indulged, photos of acquaintances to scroll past, emails to glimpse, notification bells to click, you get the drill… What had helped my brain overcome the curse of divided attention brought on by this incessant technological noise is a simple time management technique by the name of Pomodoro, credited to Francesco Cirillo. The process roughly looks something like this: 1) Choose a task, 2) set a timer to 25 minutes, 3) dedicate those 25 minutes to focus on the task and the task only, 4) take a brief break, 5) rinse and repeat.

When I started learning how to code not too long ago, I knew that a simple app that makes use of the Pomodoro technique was on my list of things to attempt. The process of creating this app taught me a lot on how to manipulate the document object model, how to recognize events and create dynamic changes on the browser, all without a page refresh. Check out a brief demo of the app below!

https://medium.com/media/f04612df0afc510959c10873c28e1200/href

The styling of the app is credited to the talented Donat Pllana. While styling is so important in making your app presentable and user-friendly, for the sake of time, I will only be guiding you through how I created the functionality. You can access this app’s CodePen here. Feel free to follow along!

The Planning Process: User Stories

To start, I brainstormed user stories, which are simple descriptions of my app’s features from the perspective of a user. As a user, I want to…

  1. Be able to go to the app’s page and see displayed several options of focus minutes to choose from
  2. See a countdown timer displayed after clicking on a focus minute option
  3. Be able to cancel my focus session
  4. Be rewarded with a random inspirational music video when I successfully completed my focus session
  5. Have the option of either completing another focus session or to take a 5-minute break

The Starting HTML: See the Minute Options

My index.html file, to start, looks like this:

<html>
<head>
<meta charset="UTF-8">
<title>Time to Time</title>
<script defer src="index.js"></script>

<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="main-header">
<h1>Time to Time</h1>
</div>
<div id="description">
<p>Time to Time makes use of Francesco Cirillo's <a href="https://francescocirillo.com/pages/pomodoro-technique">Pomodoro technique</a> to help you focus on tasks at hand: Choose a task, set the timer, work on the task, take a short break.
</p>
</div>

<div id="countdown-container"></div>
<div id="cancel-container" hidden> 
<button id="cancel-button">Cancel</button>
</div>
<div id="video-container">
</div>

<div id="selection-container">
<p id="instruction">Select Focus Minutes:</p>
<div id="time-buttons-container">
<button class="minute-button set-time" id="0.05">25</button>
<button class="minute-button set-time" id="50">50</button>
<button class="minute-button set-time" id="75">75</button>
<button class="minute-button set-time" id="100">100</button>
</div>

<span class="take-break set-time" id="5" hidden>Take a Five-Minute Break</span>
</div>
</body>
</html>

Want to read this story later? Save it in Journal.

I created elements to house the following items: a main header with the app’s name, a description, a countdown, a cancel button, a video, focus minute buttons, and a take-a-break option. I assigned unique ID’s to each element to easily refer back to them later and also wrapped them in <div> containers to make for easier styling. As a default, I hid the cancel button and the option to “take a break”. I made sure to add “defer” when linking to my index.js file to ensure that the HTML loads first before any JS code is ran.

The ID of each minute button and the take-break span is set to the corresponding minute. The ID will be passed into a function later that is responsible for setting the appropriate starting time. I initially set the ID of minute button 25 to “0.05”, to avoid waiting a whole 25 minutes each time in order to test my app.

Right now the user could see the following:

User Story 1: Completed.

See a Countdown Timer Displayed

When a user clicks on a focus minute option, a countdown timer should display, starting at that specified minute. To make this happened, I made use of event delegation. First I created variables and assigned to them stable elements I selected from the DOM, this makes it so that I can easily refer back to them later in my code.

// Assigning to variables stable elements
const mainHeader = document.querySelector("#main-header"),
description = document.querySelector("#description"),
countdownContainer = document.querySelector("#countdown-container"),
cancelContainer = document.querySelector("#cancel-container"),
cancelButton = document.querySelector("#cancel-button"),
videoContainer = document.querySelector("#video-container"),
selectionContainer = document.querySelector("#selection-container"),
instruction = document.querySelector("#instruction"),
timeButtonsContainer = document.querySelector("#time-buttons-container"),
takeBreak = document.querySelector(".take-break");

Next, I added an event listener to the selectionContainer, calling a function called renderCountdown(). Effectively, I am telling the browser that if the thing I clicked on in the selectionContainer happens to be an element with a class called “set-time”, to start the countdown.

selectionContainer.addEventListener("click", renderCountdown);
function renderCountdown(evt) {
   if (evt.target.classList.contains("set-time")) {
videoContainer.innerHTML = "";
      hideElements(description, selectionContainer, videoContainer);
unhideElements(countdownContainer, cancelContainer);
      const minutesChosen = parseFloat(evt.target.id);
      startCountdown(minutesChosen);
}
}

With the use of helper functions hideElements() and unhideElements(), I can easily display what I want the user to see. These functions make use of rest parameters, which allows you to pass in an unknown number of arguments.

function hideElements(...elems) {
elems.forEach((elem) => (elem.hidden = true));
}
function unhideElements(...elems) {
elems.forEach((elem) => (elem.hidden = false));
}

Next comes the meat of the app’s functionality, startCountdown() takes in a minute variable in form of an integer and display in the countdownContainer a changing countdown clock.

function startCountdown(minutesChosen) {
// Calculate total time in seconds, the second display value, and the minute display value
  let totalTimeInSeconds = minutesChosen * 60;
// Set the countdown to run every 1000 ms (1 second); run this function every second
  let setCountDownInterval = setInterval(function () {
let displaySeconds = totalTimeInSeconds % 60;
let displayMinutes = Math.floor(totalTimeInSeconds / 60);
// Add a zero in front of displaySeconds if it is single digit
displaySeconds =
displaySeconds < 10 ? "0" + displaySeconds : displaySeconds;
// Add the time to the countdown container
countdownContainer.innerHTML = `${displayMinutes} : ${displaySeconds}`;

// Decrement the totalTimeInSeconds
totalTimeInSeconds--;
// If the time reaches 0, then stop the countdown, and render video
if (totalTimeInSeconds < 0) {
clearInterval(setCountDownInterval);
renderVideo();
}
// If the cancel button is clicked, then render back to start
cancelButton.addEventListener("click", (evt) => {
clearInterval(setCountDownInterval);
renderBackToStart();
});
}, 1000);
}

First, I wrote the logic that will display the appropriate countdown time, making use of setInterval(), which essentially will run any callback function you pass into it for a specified number of millisecond (in this case, we tell it to make the totalTimeInSeconds goes down by 1 for each 1 second that passed). The user now sees this:

User Story 2: Completed. Next, two options present: if the timer reaches 0 and if the user clicks the “Cancel” button. In either cases, the countdown interval should stop and either a music video should render or the user is taken back to the start.

Cancel the Session

If the user cancels the session, the function renderBackToStart() is called, this function once more makes use of helpers hideElements() and unhideElements() to make it so that the user sees the following displayed once again:

function renderBackToStart() {
hideElements(countdownContainer, cancelContainer, videoContainer, takeBreak);
unhideElements(description, selectionContainer, timeButtonsContainer);
}

User Story 3: Completed.

What Doesn’t Kill You Make You Stronger

If the user successfully completes the session, we call the renderVideo() function which takes a random video URL (with specified start time and autoplay parameters attached) from an array of URLs, and attach that to the videoContainer using iframe. Yes, one of the songs is beloved Kelly Clarkson’s Stronger. How’s that for a boost of congratulatory motivation?

This function also makes use of hideElement() and unhideElement() to display options for the user to either start another session or take a 5 minute break.

function renderVideo() {
hideElements(countdownContainer, cancelContainer);
unhideElements(videoContainer, selectionContainer, takeBreak);
// Take a random video URL and display and autoplay the video
const songURLs = [
"https://www.youtube.com/embed/4Z-P7qOFcDk?rel=0&start=137&autoplay=1",
"https://www.youtube.com/embed/KybAvaM3b90?rel=0&start=8&autoplay=1",
"https://www.youtube.com/embed/W5HIisdWzvY?rel=0&start=39&autoplay=1",
"https://www.youtube.com/embed/-H2Bjyw6AS8?rel=0&start=93&autoplay=1",
];
const randomIdx = Math.floor(Math.random() * songURLs.length);
videoContainer.innerHTML = `
<iframe width="560" height="315" src=${songURLs[randomIdx]} frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
`;
}

What the user sees:

User Stories 4 and 5: Completed. Boom and boom.

Through working on this app, I learned: 1) to manipulate the DOM through use of .querySelector().addEventListener(), .setInterval(), among other methods, 2) to create helper functions and as much as possible to delegate a single responsibility to each function, 3) to use ES6 syntax such as rest parameters and arrow function syntax. I also learned that Baby Shark (Trap Remix) is super addictive.

Thanks for reading ’til the end. I hope this was helpful. Any comments, feedbacks, or criticisms are welcomed!

Here is to continual learning despite distractions in our way! 🥂

📝 Save this story in Journal.

👩‍💻 Wake up every Sunday morning to the week’s most noteworthy stories in Tech waiting in your inbox. Read the Noteworthy in Tech newsletter.


Creating a Simple Pomodoro Web App — A Beginner’s Guide was originally published in Noteworthy – The Journal Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.



Source link

https://avasta.ch

Leave a Comment

Your email address will not be published. Required fields are marked *

*
*