diff --git a/apps/frontend/app/lib/hooks.ts b/apps/frontend/app/lib/hooks.ts
index 8faebb98b5..d747511e3c 100644
--- a/apps/frontend/app/lib/hooks.ts
+++ b/apps/frontend/app/lib/hooks.ts
@@ -1,6 +1,7 @@
import type Umami from "@bitprojects/umami-logger-typescript";
import { $path } from "@ignisda/remix-routes";
import { useComputedColorScheme, useMantineTheme } from "@mantine/core";
+import { useForceUpdate } from "@mantine/hooks";
import {
useNavigate,
useRouteLoaderData,
@@ -11,6 +12,7 @@ import type { EntityLot } from "@ryot/generated/graphql/backend/graphql";
import { useQuery } from "@tanstack/react-query";
import Cookies from "js-cookie";
import type { FormEvent } from "react";
+import { useInterval } from "usehooks-ts";
import {
CurrentWorkoutKey,
getMetadataDetailsQuery,
@@ -170,3 +172,8 @@ export const useApplicationEvents = () => {
addToCollection,
};
};
+
+export const forceUpdateEverySecond = () => {
+ const forceUpdate = useForceUpdate();
+ useInterval(forceUpdate, 1000);
+};
diff --git a/apps/frontend/app/routes/_dashboard.fitness.$action.tsx b/apps/frontend/app/routes/_dashboard.fitness.$action.tsx
index e1e3229c46..1e4b364644 100644
--- a/apps/frontend/app/routes/_dashboard.fitness.$action.tsx
+++ b/apps/frontend/app/routes/_dashboard.fitness.$action.tsx
@@ -36,7 +36,6 @@ import {
useDebouncedState,
useDidUpdate,
useDisclosure,
- useInterval,
useListState,
useToggle,
} from "@mantine/hooks";
@@ -78,7 +77,7 @@ import { Howl } from "howler";
import { produce } from "immer";
import { RESET } from "jotai/utils";
import Cookies from "js-cookie";
-import { useRef, useState } from "react";
+import { useRef } from "react";
import Webcam from "react-webcam";
import { ClientOnly } from "remix-utils/client-only";
import { namedAction } from "remix-utils/named-action";
@@ -100,6 +99,7 @@ import {
queryFactory,
} from "~/lib/generals";
import {
+ forceUpdateEverySecond,
useApplicationEvents,
useCoreDetails,
useUserPreferences,
@@ -120,6 +120,7 @@ import {
redirectWithToast,
serverGqlService,
} from "~/lib/utilities.server";
+import { useInterval } from "usehooks-ts";
const workoutCookieName = CurrentWorkoutKey;
const defaultTimerLocalStorageKey = "DefaultExerciseRestTimer";
@@ -190,7 +191,6 @@ export default function Page() {
const events = useApplicationEvents();
const [parent] = useAutoAnimate();
const navigate = useNavigate();
- const [_t, setTime] = useState(0);
const [currentWorkout, setCurrentWorkout] = useCurrentWorkout();
const playCompleteTimerSound = () => {
const sound = new Howl({ src: ["/timer-completed.mp3"] });
@@ -211,22 +211,17 @@ export default function Page() {
const [_, setMeasurementsDrawerOpen] = useMeasurementsDrawerOpen();
const [currentTimer, setCurrentTimer] = useTimerAtom();
- useInterval(
- () => {
- setTime((s) => s + 1);
- const timeRemaining = currentTimer?.endAt.diff(dayjsLib(), "second");
- if (timeRemaining && timeRemaining <= 3) {
- if (navigator.vibrate) navigator.vibrate(200);
- if (timeRemaining <= 1) {
- playCompleteTimerSound();
- timerDrawerClose();
- stopTimer();
- }
+ useInterval(() => {
+ const timeRemaining = currentTimer?.endAt.diff(dayjsLib(), "second");
+ if (timeRemaining && timeRemaining <= 3) {
+ if (navigator.vibrate) navigator.vibrate(200);
+ if (timeRemaining <= 1) {
+ playCompleteTimerSound();
+ timerDrawerClose();
+ stopTimer();
}
- },
- 1000,
- { autoInvoke: true },
- );
+ }
+ }, 1000);
const startTimer = (
duration: number,
@@ -347,11 +342,7 @@ export default function Page() {
onClick={timerDrawerToggle}
style={isCreatingTemplate ? { display: "none" } : undefined}
>
- {currentTimer
- ? dayjsLib
- .duration(currentTimer.endAt.diff(dayjsLib()))
- .format("m:ss")
- : "Timer"}
+
{currentWorkout.exercises.length > 1 ? (
<>
@@ -511,7 +502,17 @@ const offsetDate = (startTime?: string) => {
return now.diff(dayjsLib(startTime), "seconds");
};
+const RestTimer = () => {
+ forceUpdateEverySecond();
+ const [currentTimer] = useTimerAtom();
+
+ return currentTimer
+ ? dayjsLib.duration(currentTimer.endAt.diff(dayjsLib())).format("m:ss")
+ : "Timer";
+};
+
const DurationTimer = () => {
+ forceUpdateEverySecond();
const [currentWorkout] = useCurrentWorkout();
const seconds = offsetDate(currentWorkout?.startTime);
const { isCreatingTemplate } = useLoaderData();
@@ -1362,6 +1363,7 @@ const TimerDrawer = (props: {
stopTimer: () => void;
startTimer: (duration: number) => void;
}) => {
+ forceUpdateEverySecond();
const [currentTimer, setCurrentTimer] = useTimerAtom();
return (
diff --git a/apps/frontend/package.json b/apps/frontend/package.json
index a6c7283b03..d808b11324 100644
--- a/apps/frontend/package.json
+++ b/apps/frontend/package.json
@@ -73,6 +73,7 @@
"postcss-simple-vars": "7.0.1",
"ts-essentials": "10.0.1",
"typescript-plugin-css-modules": "5.1.0",
+ "usehooks-ts": "3.1.0",
"vite": "5.3.4",
"vite-tsconfig-paths": "4.3.2"
},
diff --git a/yarn.lock b/yarn.lock
index 232dc9b69e..2514e68f46 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3538,6 +3538,7 @@ __metadata:
ts-pattern: "npm:5.2.0"
typescript-plugin-css-modules: "npm:5.1.0"
ufo: "npm:1.5.4"
+ usehooks-ts: "npm:3.1.0"
uuid: "npm:10.0.0"
vite: "npm:5.3.4"
vite-tsconfig-paths: "npm:4.3.2"
@@ -12013,6 +12014,17 @@ __metadata:
languageName: node
linkType: hard
+"usehooks-ts@npm:3.1.0":
+ version: 3.1.0
+ resolution: "usehooks-ts@npm:3.1.0"
+ dependencies:
+ lodash.debounce: "npm:^4.0.8"
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18
+ checksum: 10/6aef8affd3c053a3040b7421816dab85eb21601c5203496a705bafc32eb973fb519a2b0ddda527962e361d248f3a1c49df130620efe871c8f89e897451ed1cc7
+ languageName: node
+ linkType: hard
+
"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1":
version: 1.0.2
resolution: "util-deprecate@npm:1.0.2"