User:Alessia/pomodoro timer: Difference between revisions

From XPUB & Lens-Based wiki
No edit summary
No edit summary
Line 291: Line 291:
to test the app set timer.pomodoro to 1 temporaroly and click the start button. Refresh before continuing.
to test the app set timer.pomodoro to 1 temporaroly and click the start button. Refresh before continuing.


<big>'''Let's stop the timer'''</big>
<big>'''Let's stop the timer'''</big> <br>
<br>
to stop the timer when the stop button is clicked. It's the value of the data-action attribute on the button that allows to determine whether to start or stop the timer.
to stop the timer when the stop button is clicked. It's the value of the data-action attribute on the button that allows to determine whether to start or stop the timer.
<br>
<br>
Line 321: Line 322:
  function handleMode(event) {
  function handleMode(event) {
   const { mode } = event.target.dataset;
   const { mode } = event.target.dataset;
 
   if (!mode) return;
   if (!mode) return;
 
   switchMode(mode);
   switchMode(mode);
   stopTimer();
   stopTimer();

Revision as of 20:06, 23 December 2023



🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅🍅

I want to make my own pomodoro timer app. I'll study everything needed to understand how a timer works before, through javascript and python, then get into the app making with the aesthetic I want.

Pomodoro Timer with JavaScript

I am following this tutorial to get a little bit used to javascript as well:
https://freshman.tech/pomodoro-timer/

html, css, javascript. Needed: Git, Node.js, npm

basics

What is Git in simple terms?
Git, a version control system for software development, ensures developers can revert back to specific past versions of their work to see records of work completed and allows for streamlined collaboration by permitting changes made by multiple people to be merged into one location.

What is a version control system (VCS)?
a time machine for your files, an assistant tool to organise your work, collaborate with others, lets you travel back in time if things go wrong?

a Version control systems is a software tool that help software teams manage changes to source code over time. As development environments have accelerated, version control systems help software teams work faster and smarter. It records changes made to a code over time in a database called repository, there you can look at the project history. Without a version control system it could be mandatory to constantly store copied of the entire projects in various folders, manually merging...

Why should I use Git with my coding projects?
It's sort of a cloud for code. You don't have to necessarily use GIT. You might use Mercurial or Subversion as SCM/VCS...
In this case, Git is useful to clone the repository(?)

what is Node.js?
multitasking assistant, allows you to use javascript on the server side as well, not just the front-end part, the web browser. Scalability?
Node.js is a runtime environment for executing JavaScript on the server side, while Git is a version control system for tracking and managing changes in your codebase. Both tools play important roles in modern software development, with Node.js handling the server-side logic and Git managing version control and collaboration. Using them together can contribute to a more efficient and organized development process.

what is a nmp?

NPM is like an online store for JavaScript tools and libraries. These tools can be anything from small utility functions to entire frameworks that help you build web applications. When you're building a project using Node.js, you often rely on existing code written by others. NPM helps you easily find and install these pieces of code (packages) into your project. These packages are the dependencies your project needs to run.

difference between Git and npm?
Git is for tracking changes in your code, while NPM is for adding ready-made code components to your project.
what is Github?
It's the social network for Git. It hosts Git repositories online.


what does it mean markup?
In the web development contest "markup" refers to the practice of adding special symbols or codes to a document to provide information about the structure, formatting, or presentation of the content. These symbols or codes are often called "tags." The most common form of markup is HTML (Hypertext Markup Language), which is used to structure content on the web. HTML uses tags to define elements such as headings, paragraphs, links, images, and more. Markup is a way to add structure and meaning to content, allowing computers or other systems to interpret and display it in a specific way.

what is a browser-sync dependency?



clone the repository to your filesystem

git clone https://github.com/Freshman-tech/pomodoro-starter-files.git

cd into it in your terminal

cd pomodoro-starter-files 

run the following command to install the browser-sync dependency which is used to automatically refresh the browser once a file is changed

npm install 

start the app on http://localhost:3000 using:

npm start 

getting into the browser



Then interface of Freshman timer is quite simple. a progress bar + 3 buttons for the 3 modes of the application.Then the countdown timer and the start button.
As a tradition pomodoro session is 25 mins + short break 5 mins/ long break 15 mins after 4 consecutive session.
To create a timer variable follow:

main.js

const timer = {
  pomodoro: 25,
  shortBreak: 5,
  longBreak: 15,
  longBreakInterval: 4,
};

what is const? a keyword to declare a costant variable, cannot be changed.
so this is to get the variables

We need to update the countdown with the right amount of minutes and seconds. We need to create an event listener that detects a click on the buttons and a function to switch the mode of the timer appropriately.

what the hell is an event listener?
a function in JavaScript that waits for an event to occur then responds to it

main.js

const modeButtons = document.querySelector('#js-mode-buttons');
modeButtons.addEventListener('click', handleMode);

function handleMode(event) {
  const { mode } = event.target.dataset;

  if (!mode) return;

  switchMode(mode);
}

document refers to the entire HTML document

On this previous part we use event delegation to detect a click on any mode buttons.

what is an event delegation? technique where instead of attaching an event listener to each individual element, you attach a single event listener to a common ancestor (like a parent element) of multiple elements. This single event listener then handles events for all the elements inside that ancestor.

what's an ancestor in javascript? I'll go with a logical guess

The modeButtons variable points to the containing element and once a click is detected on the element, the handleMode() function is invoked. Within the handleMode() function, the value of the data-mode attribute is retrieved from the target element. If this attribute does not exist, it means that the target element was not one of the buttons and the function exits. Otherwise, a switchMode() function is invoked with the value of the data-mode attribute as its only argument.

Then create the switchMode() function just above handleMode()

main.js

function switchMode(mode) {
  timer.mode = mode;
  timer.remainingTime = {
    total: timer[mode] * 60,
    minutes: timer[mode],
    seconds: 0,
  };
document
    .querySelectorAll('button[data-mode]')
    .forEach(e => e.classList.remove('active'));
  document.querySelector(`[data-mode="${mode}"]`).classList.add('active');
  document.body.style.backgroundColor = `var(--${mode})`;

  updateClock();
}
 

switch statement: evaluates an expression. The value of the expression is then compared with the values of each case in the structure. If there is a match, the associated block of code is executed.
switchMode is a function that takes a 'mode' as an input.

switchMode usage

function switchMode(mode) {
  switch (mode) {
    case 'A':
      // Do something for mode A
      break;
    case 'B':
      // Do something for mode B
      break;
    default:
      // Do something if mode doesn't match A or B 
  }
} 

switchMode is a function that takes a mode as an input. Inside the function, there's a switch statement that checks the value of mode. If mode is 'A', it performs the actions specified for mode A. If mode is 'B', it performs the actions specified for mode B. If mode doesn't match either 'A' or 'B', it performs actions specified in the default case. SwitchMode is like a function that does different things based on the value of mode you give it. It's a way to handle different cases or scenarios in the code.
In this case the switchMode() adds two properties to the "timer" object. First a "mode" property to current mode which could be pomodoro, shortBreak or longBreak.
Then remainingTime set on the timer. remainingTime contains three properties: total (number of seconds remaining), set to the number of minutes of the current mode multiplied by 60. So if mode is shortBreak, total will be se to 300 (5*60).
minutes is the number of minutes for the mode (pomodoro-25 min)
seconds is always set to zero at the start of a session
querySelector is a method provided by the document object that allows you to find and select HTML elements on the page

querySelector('.example') - the example is the CSS selector, it's looking for an element with that class name

CSS selector: selectors allow you to target specific elements in an HTML document so that you can apply styling or perform other operations on them (element, class, ID, attribute, descendant, child)

let's move to css

styles.css
:root {
 --pomodoro: hsl(223, 25%, 40%);
 --shortBreak: hsl(48, 23%, 40%);
 --longBreak: hsl(105, 16%, 40%);
}


The updateClock() function extracts the value of the minutes and seconds properties on the remainingTime object and adds eros where necessary so that the number always has a width of two. For example, 8 seconds will become 08 seconds, but 12 minutes will be left as 12 minutes.

Let's start the timer next step: add the ability to start the timer and countdown to zero, declare an interval variable under timer (just after const timer on the first line)

main.js
let interval;

above updateClock() add startTimer():

main.js
function startTimer() {
 let { total } = timer.remainingTime;
 const endTime = Date.parse(new Date()) + total * 1000;
 interval = setInterval(function() {
   timer.remainingTime = getRemainingTime(endTime);
   updateClock();
   total = timer.remainingTime.total;
   if (total <= 0) {
     clearInterval(interval);
   }
 }, 1000);
}


Before being able to start the timer we need to get the exact time in the future when the timer will end, achieved by retrieving the timestamp of the current moment? (Date.parse(new Date())) which is in milliseconds, 1 second = 1000ms. This value is then stored in the endTime variable.
The interval variable is set to the setInterval() method which executes the callback function every 1000 milliseconds (1 second). This callback function references a getRemainingTime() function which should be created above startTimer
callback(data), callback funtion is a way to handle asynchtonous operations

main.js
function getRemainingTime(endTime) {
 const currentTime = Date.parse(new Date());
 const difference = endTime - currentTime;

 const total = Number.parseInt(difference / 1000, 10);
 const minutes = Number.parseInt((total / 60) % 60, 10);
 const seconds = Number.parseInt(total % 60, 10);

 return {
   total,
   minutes,
   seconds,
 };
}

The function above takes a timestamp argument and finds the difference between the current time and the end time in milliseconds.
This value is stored in the difference variable and used to compute the total number of seconds left by dividing by 1000. The result is converted to an integer in base 10 through the Number.parseInt() method and stored in the total variable.

The minutes variable contains the number of whole minutes left (if any) and seconds is the number of seconds left after whole minutes have been accounted for. For example, if total is 230 seconds, minutes will equal 3 and seconds will be 50.

-you should learn a little bit more about this part-
calling the startTimer() is needed once the start button is clicked. Add this above the modeButtons:

const mainButton = document.getElementById('js-btn');
mainButton.addEventListener('click', () => {
 const { action } = mainButton.dataset;
 if (action === 'start') {
   startTimer();
 }
});


We need to make a small modification to startTimer() so that the button text changes to “stop” and the button becomes depressed like a hardware button (add the mainButton part)

function startTimer() {
 let { total } = timer.remainingTime;
 const endTime = Date.parse(new Date()) + total * 1000;

 mainButton.dataset.action = 'stop';
 mainButton.textContent = 'stop';
 mainButton.classList.add('active');

 interval = setInterval(function() {
   timer.remainingTime = getRemainingTime(endTime);
   updateClock();

   total = timer.remainingTime.total;
   if (total <= 0) {
     clearInterval(interval);
   }
 }, 1000);
}


A final thing to do in this section is to ensure that the mode and remainingTime properties are set on the timer object on page load. To do so, we can execute the switchMode() property once the DOMContentLoaded event is fired. This ensures that the default mode for the timer is pomodoro and the contents of timer.remainingTime is set to the appropriate values for a pomodoro session. If the above snippet is not present, the program will crash with a TypeError if startTimer() is invoked because timer.remainingTime will not exist and we’re trying to access the value of the total property in that object on the first line of the function.
(I didn't understand this part). Add this at the end of main.js

document.addEventListener('DOMContentLoaded', () => {

 switchMode('pomodoro');

});

to test the app set timer.pomodoro to 1 temporaroly and click the start button. Refresh before continuing.

Let's stop the timer

to stop the timer when the stop button is clicked. It's the value of the data-action attribute on the button that allows to determine whether to start or stop the timer.
Then add a new stopTimer() below startTimer()

function stopTimer() {
 clearInterval(interval);

 mainButton.dataset.action = 'start';
 mainButton.textContent = 'start';
 mainButton.classList.remove('active');
}

clearInterval() cause the setInterval() triggered in startTimer() to be cancelled so that the countdown is paused.Then the value of the button's data-action attribute is changed to "start" and it is returned to its original form by removing the active class.
To execute stopTimer() when data-action is set to “stop”, modify the mainButton like this:

mainButton.addEventListener('click', () => {
 const { action } = mainButton.dataset;
 if (action === 'start') {
   startTimer();
 } else {
   stopTimer();
 }
});

Also needed to stop the timer when the mode is changed by clicking any of the three buttons above the countdown:

function handleMode(event) {
 const { mode } = event.target.dataset;

 if (!mode) return;

 switchMode(mode);
 stopTimer();
}