Introduction
I was trying to search my some free tool that can these 2 things.
- Run the Timer with Given minutes
- 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;
Top comments (0)