diff --git a/src/Home.tsx b/src/Home.tsx index 0c5a9ba..8059380 100644 --- a/src/Home.tsx +++ b/src/Home.tsx @@ -9,23 +9,14 @@ // defined by the Mozilla Public License, v. 2.0. // import { AppNav, Footer } from "./components/AppNav.tsx"; -import { Container, Row, Col, Image, Card } from "react-bootstrap"; +import { Container, Row, Col, Card } from "react-bootstrap"; import { atom, useAtomValue } from "jotai"; -import { atomWithQuery } from "jotai-tanstack-query"; +import { createQueryAtom } from "./utils/query.ts"; import { DiagnosticsCard } from "./components/DiagnosticsCard.tsx"; -const statusStringQuery = async () => { - const resp = await fetch("api/status"); - if (!resp.ok) { - throw new Error("Network response was not ok"); - } - return resp.json(); -}; -const statusStringQueryAtom = atomWithQuery(() => ({ - queryKey: ["status_string"], - queryFn: statusStringQuery, - refetchInterval: 500, // 0.5s -})); +const statusStringQueryAtom = createQueryAtom("status_string", "api/status", { + refetchInterval: 500, +}); const statusStringAtom = atom((get) => { const response = get(statusStringQueryAtom); if (response.isPending || response.isError || !response.data.status) { @@ -34,18 +25,9 @@ const statusStringAtom = atom((get) => { return response.data.message; }); -const uptimeQuery = async () => { - const resp = await fetch("api/uptime"); - if (!resp.ok) { - throw new Error("Network response was not ok"); - } - return resp.json(); -}; -const uptimeQueryAtom = atomWithQuery(() => ({ - queryKey: ["uptime"], - queryFn: uptimeQuery, - refetchInterval: 1000, // 1s -})); +const uptimeQueryAtom = createQueryAtom("api/uptime", { + refetchInterval: 1000, +}); const uptimeAtom = atom((get) => { const response = get(uptimeQueryAtom); if (response.isPending || response.isError) { diff --git a/src/Version.tsx b/src/Version.tsx index 66e5522..21ec85e 100644 --- a/src/Version.tsx +++ b/src/Version.tsx @@ -11,21 +11,10 @@ import { AppNav, Footer } from "./components/AppNav.tsx"; import { Container, Row, Col, Card } from "react-bootstrap"; import { atom, useAtomValue } from "jotai"; -import { atomWithQuery } from "jotai-tanstack-query"; +import { createQueryAtom } from "./utils/query.ts"; import YAML from "yaml"; -const versionQueryFn = async () => { - const resp = await fetch("api/build_info"); - if (!resp.ok) { - throw new Error("Network response was not ok"); - } - return resp.json(); -}; - -const versionQueryAtom = atomWithQuery(() => ({ - queryKey: ["version"], - queryFn: versionQueryFn, -})); +const versionQueryAtom = createQueryAtom("api/build_info"); const versionAtom = atom((get) => { const version = get(versionQueryAtom); diff --git a/src/Video.tsx b/src/Video.tsx index 5e363c6..2df3953 100644 --- a/src/Video.tsx +++ b/src/Video.tsx @@ -9,23 +9,12 @@ // defined by the Mozilla Public License, v. 2.0. // import { AppNav, Footer } from "./components/AppNav.tsx"; -import { Container, Row, Col, Image, Card } from "react-bootstrap"; +import { Container, Row, Col, Card } from "react-bootstrap"; import { MediaMtxPlayer } from "./external/MediaMtxPlayer.tsx"; import { atom, useAtomValue } from "jotai"; -import { atomWithQuery } from "jotai-tanstack-query"; +import { createQueryAtom } from "./utils/query.ts"; -const tokenQuery = async () => { - const resp = await fetch("api/mediamtx/login"); - if (!resp.ok) { - throw new Error("Network response was not ok."); - } - return resp.json(); -}; -const tokenQueryAtom = atomWithQuery(() => ({ - queryKey: ["token"], - rety: true, - queryFn: tokenQuery, -})); +const tokenQueryAtom = createQueryAtom("api/mediamtx/login", { retry: true }); const tokenAtom = atom((get) => { const response = get(tokenQueryAtom); if (response.isPending || response.isError) { diff --git a/src/components/DiagnosticsCard.tsx b/src/components/DiagnosticsCard.tsx index c355a24..e6dfdd9 100644 --- a/src/components/DiagnosticsCard.tsx +++ b/src/components/DiagnosticsCard.tsx @@ -8,20 +8,11 @@ import { } from "react-bootstrap-icons"; import { Container, Row, Col, Table, Card } from "react-bootstrap"; import { atom, useAtomValue } from "jotai"; -import { atomWithQuery } from "jotai-tanstack-query"; +import { createQueryAtom } from "../utils/query.ts"; -const diagQueryFn = async () => { - const resp = await fetch("api/diagnostics"); - if (!resp.ok) { - throw new Error("Network response was not ok"); - } - return resp.json(); -}; - -const diagQueryAtom = atomWithQuery(() => ({ - queryKey: ["diagnostics"], - queryFn: diagQueryFn, -})); +const diagQueryAtom = createQueryAtom("api/diagnostics", { + refetchInterval: 1000, +}); const diagAtom = atom((get) => { const diag = get(diagQueryAtom); diff --git a/src/utils/query.ts b/src/utils/query.ts new file mode 100644 index 0000000..5250f64 --- /dev/null +++ b/src/utils/query.ts @@ -0,0 +1,33 @@ +// +// Copyright 2026 James Pace +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. +// +// This Source Code Form is "Incompatible With Secondary Licenses", as +// defined by the Mozilla Public License, v. 2.0. +// + +import { atomWithQuery } from "jotai-tanstack-query"; + +export async function fetchJson(url: string): Promise { + const resp = await fetch(url); + if (!resp.ok) { + throw new Error(`Network response was not ok: ${resp.statusText}`); + } + return resp.json(); +} + +interface CreateQueryAtomOptions { + refetchInterval?: number; + retry?: boolean; +} + +export function createQueryAtom(url: string, options?: CreateQueryAtomOptions) { + return atomWithQuery(() => ({ + queryKey: [url], + queryFn: () => fetchJson(url), + ...options, + })); +}