» Make Pomodoro Web App in React » 2. Development » 2.6 Circles

Circles

A timer can be represented as a group of counting down numbers or, a circular progressbar1.

circular progressbars

Add a component file named components/Timer.jsx:

import React from "react";
import "./Timer.css";
import { formatTime } from "../util";
import { CircularProgressbar } from "react-circular-progressbar";
import "react-circular-progressbar/dist/styles.css";

const Timer = (props) => {
  const primaryColor = "coral";
  return (
    <div>
      {props.useCircle ? (
        <div className="circle-wrapper">
          <CircularProgressbar
            value={props.percentage}
            maxValue={1}
            text={formatTime(props.seconds)}
            styles={{
              path: {
                stroke: primaryColor,
              },
              trail: {
                stroke: "rgba(255, 255, 255, 0.5)",
              },
              text: {
                fill: "white",
              },
            }}
          />
        </div>
      ) : (
        <h1 className="timer">{formatTime(props.seconds)}</h1>
      )}
    </div>
  );
};

export default Timer;

Depends on the value of props.useCircle, it would show a circular progressbar or just a group of counting down numbers.

Timer's styles are listed in components/Timer.css:

.timer {
  font-size: 100px;
  margin-top: 2rem;
  margin-bottom: 2rem;
  font-family: monospace, "Courier New", Courier;
}

.circle-wrapper {
  width: 80%;
  margin: 1rem auto;
}

Update App.js to use this new component:

@@ -1,14 +1,14 @@
 import { useEffect, useRef, useState } from "react";
 import "./App.css";
-import { formatTime } from "./util";
 import Settings from "./components/Settings";
+import Timer from "./components/Timer";
 
 const POMODORO_SECONDS = 25 * 60;
 const BREAK_SECONDS = 5 * 60;
 const PHASE_POMODORO = 0;
 const PHASE_BREAK = 1;
 const DEFAULT_SETTING = {
-  useCircle: false,
+  useCircle: true,
   soundOn: true,
 };
 
@@ -63,6 +63,12 @@ function App() {
     }
   };
 
+  const calcPercentage = () => {
+    const duration =
+      phase === PHASE_POMODORO ? POMODORO_SECONDS : BREAK_SECONDS;
+    return seconds / duration;
+  };
+
   const pickPhase = (phase) => {
     const secBg = "secondary-bg";
     if (phase === PHASE_POMODORO) {
@@ -110,7 +116,11 @@ function App() {
         </span>
       </div>
       <div className="card">
-        <h1 className="timer">{formatTime(seconds)}</h1>
+        <Timer
+          seconds={seconds}
+          percentage={calcPercentage()}
+          useCircle={settings.useCircle}
+        />
         <div>
           <button

The circular progressbar timer looks like this:

Circular progressbar

Footnotes

  1. react-circular-progressbar, https://www.npmjs.com/package/react-circular-progressbar