react-hooks/purity

This commit is contained in:
shamoon
2026-08-21 12:33:35 -07:00
parent 014ffa86f1
commit 424cfd8574
9 changed files with 64 additions and 7 deletions
-1
View File
@@ -75,7 +75,6 @@ export default defineConfig([
"react-hooks/immutability": "off",
"react-hooks/incompatible-library": "off",
"react-hooks/preserve-manual-memoization": "off",
"react-hooks/purity": "off",
"react-hooks/refs": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/set-state-in-effect": "off",
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><circle cx="5" cy="5" r="4"/></svg>

After

Width:  |  Height:  |  Size: 96 B

+14
View File
@@ -0,0 +1,14 @@
import { useEffect, useState } from "react";
const MINUTE = 60_000;
export default function useCurrentTime(refreshInterval = MINUTE) {
const [currentTime, setCurrentTime] = useState(Date.now);
useEffect(() => {
const interval = setInterval(() => setCurrentTime(Date.now()), refreshInterval);
return () => clearInterval(interval);
}, [refreshInterval]);
return currentTime;
}
+32
View File
@@ -0,0 +1,32 @@
// @vitest-environment jsdom
import { act, render, screen } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import useCurrentTime from "./use-current-time";
function CurrentTime({ refreshInterval }) {
return <span>{useCurrentTime(refreshInterval)}</span>;
}
describe("utils/hooks/use-current-time", () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(1_000);
});
afterEach(() => {
vi.useRealTimers();
});
it("updates at the requested interval", () => {
render(<CurrentTime refreshInterval={5_000} />);
expect(screen.getByText("1000")).toBeInTheDocument();
act(() => {
vi.advanceTimersByTime(5_000);
});
expect(screen.getByText("6000")).toBeInTheDocument();
});
});
+5 -1
View File
@@ -2,10 +2,14 @@ import Block from "components/services/widget/block";
import Container from "components/services/widget/container";
import { useTranslation } from "next-i18next/pages";
import useCurrentTime from "utils/hooks/use-current-time";
import useWidgetAPI from "utils/proxy/use-widget-api";
const DAY = 24 * 60 * 60 * 1000;
export default function Component({ service }) {
const { t } = useTranslation();
const currentTime = useCurrentTime();
const { widget } = service;
const isV2 = widget.version === 2;
@@ -45,7 +49,7 @@ export default function Component({ service }) {
switch (widget.version) {
// v1 is default
default:
const yesterday = new Date(Date.now()).setHours(-24);
const yesterday = currentTime - DAY;
loginsLast24H = loginsData.reduce(
(total, current) => (current.x_cord >= yesterday ? total + current.y_cord : total),
0,
+2 -1
View File
@@ -71,7 +71,8 @@ describe("widgets/authentik/component", () => {
it("computes v1 login/failed counts for entries within the last 24h window", () => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-01-02T00:00:00Z"));
// Use midday so a mistaken previous-midnight cutoff would include the 25-hour-old entries.
vi.setSystemTime(new Date("2026-01-02T12:00:00Z"));
const now = Date.now();
const oneHourAgo = now - 60 * 60 * 1000;
@@ -3,7 +3,7 @@ export default function Tooltip({ active, payload, formatter }) {
return (
<div className="bg-theme-800/80 rounded-md text-theme-200 px-2 py-0">
{payload.map((pld, id) => (
<div key={Math.random()} className="first-of-type:pt-0 pt-0.5">
<div key={`${pld.dataKey ?? pld.name ?? "series"}-${id}`} className="first-of-type:pt-0 pt-0.5">
<div>
{formatter(pld.value)} {payload[id].name}
</div>
@@ -2,16 +2,18 @@ import Block from "components/services/widget/block";
import Container from "components/services/widget/container";
import { useTranslation } from "next-i18next/pages";
import useCurrentTime from "utils/hooks/use-current-time";
import useWidgetAPI from "utils/proxy/use-widget-api";
export default function Component({ service }) {
const { t } = useTranslation();
const currentTime = useCurrentTime();
const { widget } = service;
const taskQueryParams = {
errors: true,
limit: 100,
since: Math.floor(Date.now() / 1000) - 24 * 60 * 60,
since: Math.floor(currentTime / 1000) - 24 * 60 * 60,
};
const { data: datastoreData, error: datastoreError } = useWidgetAPI(widget, "status/datastore-usage");
+6 -2
View File
@@ -2,10 +2,14 @@ import Block from "components/services/widget/block";
import Container from "components/services/widget/container";
import { useTranslation } from "next-i18next/pages";
import useCurrentTime from "utils/hooks/use-current-time";
import useWidgetAPI from "utils/proxy/use-widget-api";
const WEEK = 7 * 24 * 60 * 60 * 1000;
export default function Component({ service }) {
const { t } = useTranslation();
const currentTime = useCurrentTime();
const { widget } = service;
const version = widget.version ?? 1;
@@ -32,10 +36,10 @@ export default function Component({ service }) {
const projects = projectsData.filter((project) => project.id > 0); // saved filters have id < 0
const oneWeekFromNow = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
const oneWeekFromNow = new Date(currentTime + WEEK);
const tasksWithDueDate = tasksData.filter((task) => !task.dueDateIsDefault);
const tasks7d = tasksWithDueDate.filter((task) => new Date(task.dueDate) <= oneWeekFromNow);
const tasksOverdue = tasksWithDueDate.filter((task) => new Date(task.dueDate) <= new Date(Date.now()));
const tasksOverdue = tasksWithDueDate.filter((task) => new Date(task.dueDate) <= new Date(currentTime));
const tasksInProgress = tasksData.filter((task) => task.inProgress);
return (