DEV Community

Ankit malik
Ankit malik

Posted on

Created my own timer with Wakeup Screen in React

Introduction

I was trying to search my some free tool that can these 2 things.

  1. Run the Timer with Given minutes
  2. Keep Screen WakeUp when timer is

This time helps me to stay focus and time-bound any task which I want perform. For ex - I want to write this article in 1 hour then it helps me to stay focused during that 1 hour and remaining time helps me to stay motivated.

I wasn't able to find any such tool which free. There are many tools which have timer like Pomodoro etc. But for wake-up screen feature come with paid subscription. I don't need any analytics like how time for any particular day I was focused like that.

So, I decided to build it by myself in React and use wake-up screen api of browser to leverage the wake-up functionality.

This is deployed here - we can use it free of cost.
https://react-app-ankit.web.app/timer

Sample Code

Here is the sample Code for react with Typescript

import React, { useState, useEffect, useRef } from "react"; import { useWakeLock } from "react-screen-wake-lock"; import { Container, Typography, TextField, Button, Box } from "@mui/material"; const TimerWithWakeLock: React.FC = () => { const [inputMinutes, setInputMinutes] = useState<string>("10"); const [remainingSeconds, setRemainingSeconds] = useState<number | null>(null); const [running, setRunning] = useState<string | null>(null); const intervalRef = useRef<NodeJS.Timeout | null>(null); const { isSupported, released, request: requestWakeCall, release: releaseWakeCall } = useWakeLock(); const startTimer = () => { const totalSeconds = parseInt(inputMinutes) * 60; if (isNaN(totalSeconds) || totalSeconds <= 0) return; setRemainingSeconds(totalSeconds); setRunning("started"); requestWakeCall(); }; const stopTimer = () => { setRunning(null); setRemainingSeconds(null); if (intervalRef.current) clearInterval(intervalRef.current); releaseWakeCall(); }; const resumeTimer = () => { // setRemainingSeconds(remainingSeconds); setRunning("resumed"); requestWakeCall(); }; const pauseTimer = () => { setRunning("paused"); if (intervalRef.current) clearInterval(intervalRef.current); releaseWakeCall(); }; useEffect(() => { if ( (running === "started" || running === "resumed") && remainingSeconds !== null) { intervalRef.current = setInterval(() => { setRemainingSeconds((prev) => { if (prev !== null && prev > 0) { return prev - 1; } else { const audio = new Audio("/beep2.mp3"); audio.play(); stopTimer(); return 0; } }); }, 1000); } return () => { if (intervalRef.current) clearInterval(intervalRef.current); }; }, [running]); const formatTime = (totalSeconds: number) => { const minutes = Math.floor(totalSeconds / 60) .toString() .padStart(2, "0"); const seconds = (totalSeconds % 60).toString().padStart(2, "0"); return `${minutes}:${seconds}`; }; return ( <Container className="min-h-screen flex flex-col items-center justify-center bg-gray-900 text-white p-4" maxWidth="xs" > <Typography variant="h3" className="text-yellow-400">  Timer </Typography>  {!isSupported && ( <Typography color="error" className="text-sm"> Wake Lock API not supported in this browser </Typography>  )} {!running && ( <Box sx={{ m: 3 }} className="flex flex-col items-center gap-2"> <TextField type="number" value={inputMinutes} onChange={(e) => setInputMinutes(e.target.value)} label="Enter minutes" variant="outlined" className="w-full" aria-label="Input minutes for the timer" /> <Button onClick={startTimer} variant="contained" color="primary" className="bg-green-600 hover:bg-green-700" aria-label="Start the timer" > Start </Button>  </Box>  )} {running && ( <Box sx={{ flex: "flex", flexDirection: "column", alignItems: "", gap: "4" }}> <Typography variant="h1" className="text-6xl text-green-400"> {formatTime(remainingSeconds ?? 0)} </Typography>  <Button onClick={stopTimer} variant="contained" color="primary" className="bg-red-600 hover:bg-red-700" aria-label="Stop the timer" > Stop </Button>  <Button onClick={() => { if (running !== "paused") { pauseTimer(); } else if (remainingSeconds !== null) { resumeTimer(); } }} variant="contained" color="primary" className="bg-red-600 hover:bg-red-700" sx={{ m: 2 }} aria-label={running === "paused" ? "Resume the timer" : "Pause the timer"} > {running === "paused" ? "Resume" : "Pause"} </Button>  <Typography variant="body2" className="text-sm text-gray-400"> Wake Lock Active: {released ? "No" : "Yes"} </Typography>  <Button onClick={() => { released ? requestWakeCall() : releaseWakeCall(); }} variant="contained" color="secondary" className="bg-blue-600 hover:bg-blue-700" aria-label={released ? "Request wake lock" : "Release wake lock"} > {released ? "Request Wake Lock" : "Release Wake Lock"} </Button>  </Box>  )} </Container>  ); }; export default TimerWithWakeLock; 
Enter fullscreen mode Exit fullscreen mode

ScreenShots

Time when stopped

timer when running

Top comments (0)