2026-09-04 09:19:23 +02:00
|
|
|
import { useEffect, useState } from "react";
|
2026-09-09 12:43:11 +02:00
|
|
|
import { version } from "../version.js";
|
2026-09-04 09:19:23 +02:00
|
|
|
|
|
|
|
|
// De check loopt via de eigen backend (/api/update-check): de Gitea API stuurt
|
|
|
|
|
// geen CORS-headers, dus de browser mag die niet direct bevragen.
|
|
|
|
|
const POLL_MS = 30 * 60 * 1000; // periodiek opnieuw kijken
|
|
|
|
|
const MIN_GAP_MS = 5 * 60 * 1000; // niet vaker dan dit, ook niet bij focus
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Vergelijkt twee semver-strings. Een pre-release suffix (`-dev`) telt als
|
|
|
|
|
* lager dan dezelfde versie zonder suffix.
|
|
|
|
|
*/
|
|
|
|
|
export function isNieuwer(latest, huidig) {
|
|
|
|
|
const parse = (v) => {
|
|
|
|
|
const [core, pre] = String(v ?? "").replace(/^v/, "").split("-");
|
|
|
|
|
const n = core.split(".").map((x) => parseInt(x, 10) || 0);
|
|
|
|
|
return { n: [n[0] ?? 0, n[1] ?? 0, n[2] ?? 0], pre: pre || null };
|
|
|
|
|
};
|
|
|
|
|
const a = parse(latest), b = parse(huidig);
|
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
|
|
|
if (a.n[i] !== b.n[i]) return a.n[i] > b.n[i];
|
|
|
|
|
}
|
|
|
|
|
return !a.pre && !!b.pre;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Geeft de nieuwste release terug zodra die nieuwer is dan de draaiende versie,
|
|
|
|
|
* anders `null`. Vorm: { latest, naam, notes, url, publishedAt }.
|
|
|
|
|
*/
|
|
|
|
|
export function useUpdateCheck() {
|
|
|
|
|
const [update, setUpdate] = useState(null);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
// Dev-builds lopen per definitie voor op de laatste release — geen melding.
|
|
|
|
|
// Met ?updatecheck in de URL forceer je de check alsnog (voor testen).
|
|
|
|
|
const forceer = new URLSearchParams(window.location.search).has("updatecheck");
|
|
|
|
|
if (version.includes("-") && !forceer) return;
|
|
|
|
|
|
|
|
|
|
let gestopt = false;
|
|
|
|
|
let laatste = 0;
|
|
|
|
|
|
|
|
|
|
const check = async () => {
|
|
|
|
|
if (gestopt || Date.now() - laatste < MIN_GAP_MS) return;
|
|
|
|
|
laatste = Date.now();
|
|
|
|
|
try {
|
|
|
|
|
const res = await fetch("/api/update-check");
|
|
|
|
|
if (!res.ok || gestopt) return;
|
|
|
|
|
const rel = await res.json();
|
|
|
|
|
if (gestopt) return;
|
|
|
|
|
setUpdate(rel?.latest && isNieuwer(rel.latest, version) ? rel : null);
|
|
|
|
|
} catch {
|
|
|
|
|
// Backend onbereikbaar of offline: gewoon geen melding tonen.
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
check();
|
|
|
|
|
const iv = setInterval(check, POLL_MS);
|
|
|
|
|
window.addEventListener("focus", check);
|
|
|
|
|
return () => {
|
|
|
|
|
gestopt = true;
|
|
|
|
|
clearInterval(iv);
|
|
|
|
|
window.removeEventListener("focus", check);
|
|
|
|
|
};
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
return update;
|
|
|
|
|
}
|