Skip to content

Commit 65e2a22

Browse files
committed
fix: Replace usehooks-ts by @mantine/hooks to solve CSP error (#80)
The root cause of the issues was the `lodash.debounce` package, which uses `Function(‘return this’)()`, that was blocked by the Content Security Policy in firefox.
1 parent 9b2f207 commit 65e2a22

8 files changed

Lines changed: 27 additions & 46 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
},
3737
"dependencies": {
3838
"@base-ui/react": "^1.4.1",
39+
"@mantine/hooks": "^9.1.1",
3940
"@tanstack/query-async-storage-persister": "^5.100.5",
4041
"@tanstack/react-form": "^1.29.1",
4142
"@tanstack/react-query": "^5.100.5",
@@ -56,7 +57,6 @@
5657
"react-intl": "^10.1.3",
5758
"sonner": "^2.0.7",
5859
"tailwind-merge": "^3.5.0",
59-
"usehooks-ts": "^3.1.1",
6060
"zod": "^4.3.6"
6161
},
6262
"devDependencies": {

pnpm-lock.yaml

Lines changed: 12 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/issue/IssueSearch.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { createContext, PropsWithChildren, use, useEffect, useRef, useState } fr
99
import { useIntl } from "react-intl";
1010
import { z } from "zod";
1111
import { TIssue, TReference } from "../../api/redmine/types";
12-
import useDebounce from "../../hooks/useDebounce";
12+
import { useDebouncedValue } from "@mantine/hooks";
1313
import useHotKey from "../../hooks/useHotkey";
1414
import { useSettings } from "../../provider/SettingsProvider";
1515
import { Badge } from "../ui/badge";
@@ -65,7 +65,7 @@ const IssueSearchProvider = ({ children }: PropsWithChildren) => {
6565

6666
const [isSearchOpen, setIsSearchOpen] = useState(settings.style.displaySearchAlways);
6767
const [query, setQuery] = useState("");
68-
const debouncedQuery = useDebounce(query, 300);
68+
const [debouncedQuery] = useDebouncedValue(query, 300);
6969
const [inProject, setInProject] = useState<TReference | undefined>(undefined);
7070
const [focusTrigger, setFocusTrigger] = useState(0);
7171

src/components/timer/timer/TimerRoot.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { TIssue } from "@/api/redmine/types";
22
import { calculateTimerTotalElapsedTime, Timer } from "@/hooks/useTimers";
3+
import { useInterval } from "@mantine/hooks";
34
import { createContext, PropsWithChildren, use, useEffect, useEffectEvent, useState } from "react";
4-
import { useInterval } from "usehooks-ts";
55

66
type TimerContextType = {
77
timer: Timer;
@@ -25,7 +25,9 @@ export const TimerRoot = ({ timer, issue, children }: TimerRootProps) => {
2525
// eslint-disable-next-line react-hooks/set-state-in-effect
2626
useEffect(() => updateTimer(), [timer.elapsedTime, timer.activeSession]);
2727

28-
useInterval(() => setTotalElapsedTime(calculateTimerTotalElapsedTime(timer)), timer.activeSession ? 1000 : null);
28+
const interval = useInterval(() => setTotalElapsedTime(calculateTimerTotalElapsedTime(timer)), 1000);
29+
const manageInterval = useEffectEvent((active: boolean) => (active ? interval.start() : interval.stop()));
30+
useEffect(() => manageInterval(!!timer.activeSession), [timer.activeSession]);
2931

3032
const [isEditing, setIsEditing] = useState(false);
3133

src/components/timer/timer/TimerSessions.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { calculateActiveSessionElapsedTime } from "@/hooks/useTimers";
55
import { useTimerApi } from "@/provider/TimerApiProvider";
66
import { formatTimer } from "@/utils/date";
77
import { randomInt } from "@/utils/random";
8+
import { useInterval } from "@mantine/hooks";
89
import clsx from "clsx";
910
import { isToday } from "date-fns";
1011
import { ChevronDownIcon, ChevronUpIcon, TrashIcon } from "lucide-react";
11-
import { useMemo, useState } from "react";
12+
import { useEffect, useEffectEvent, useMemo, useState } from "react";
1213
import { useIntl } from "react-intl";
13-
import { useInterval } from "usehooks-ts";
1414
import { useTimerContext } from "./TimerRoot";
1515

1616
export const TimerSessions = () => {
@@ -66,7 +66,10 @@ const ActiveSessionElapsedTime = () => {
6666
const { timer } = useTimerContext();
6767

6868
const [elapsedTime, setElapsedTime] = useState(() => calculateActiveSessionElapsedTime(timer));
69-
useInterval(() => setElapsedTime(calculateActiveSessionElapsedTime(timer)), timer.activeSession ? 1000 : null);
69+
70+
const interval = useInterval(() => setElapsedTime(calculateActiveSessionElapsedTime(timer)), 1000);
71+
const manageInterval = useEffectEvent((active: boolean) => (active ? interval.start() : interval.stop()));
72+
useEffect(() => manageInterval(!!timer.activeSession), [timer.activeSession]);
7073

7174
return formatTimer(elapsedTime);
7275
};

src/hooks/useDebounce.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/routes/issues.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { randomInt } from "@/utils/random";
1313
import { createFileRoute } from "@tanstack/react-router";
1414
import { useDeferredValue, useMemo } from "react";
1515
import { FormattedMessage } from "react-intl";
16-
import { useMediaQuery } from "usehooks-ts";
16+
import { useMediaQuery } from "@mantine/hooks";
1717
import useRedmineIssuesSearch from "../api/redmine/hooks/useRedmineIssuesSearch";
1818
import Filter, { filterIssues, useFilter } from "../components/issue/Filter";
1919
import IssueSearch, { filterIssuesByLocalSearch, useIssueSearch } from "../components/issue/IssueSearch";

src/routes/timers.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { createFileRoute } from "@tanstack/react-router";
1111
import { SquareChartGanttIcon } from "lucide-react";
1212
import { useDeferredValue, useMemo } from "react";
1313
import { FormattedMessage } from "react-intl";
14-
import { useMediaQuery } from "usehooks-ts";
14+
import { useMediaQuery } from "@mantine/hooks";
1515
import TimersBadge from "../components/timer/TimersBadge";
1616
import useTimers from "../hooks/useTimers";
1717

0 commit comments

Comments
 (0)