MBO-Tech-IT-Webseite/components/admin/SessionTimeoutProvider.tsx

48 lines
1.7 KiB
TypeScript

"use client";
import { useEffect, useRef } from "react";
import { useRouter } from "next/navigation";
const INACTIVITY_TIMEOUT_MS = 2 * 60 * 60 * 1000;
const WARNING_BEFORE_LOGOUT_MS = 15 * 60 * 1000;
export function SessionTimeoutProvider({ children }: { children: React.ReactNode }) {
const router = useRouter();
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const warningTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const warningShownRef = useRef<boolean>(false);
function resetTimeout() {
if (timeoutRef.current) clearTimeout(timeoutRef.current);
if (warningTimeoutRef.current) clearTimeout(warningTimeoutRef.current);
warningShownRef.current = false;
warningTimeoutRef.current = setTimeout(() => {
if (!warningShownRef.current) {
warningShownRef.current = true;
alert("⚠️ Ihre Session läuft in 15 Minuten ab. Bitte klicken Sie auf eine Taste oder bewegen Sie die Maus, um weiterzuarbeiten.");
}
}, INACTIVITY_TIMEOUT_MS - WARNING_BEFORE_LOGOUT_MS);
timeoutRef.current = setTimeout(async () => {
await fetch("/api/admin/login", { method: "DELETE" });
router.push("/admin/login?session_expired=true");
}, INACTIVITY_TIMEOUT_MS);
}
useEffect(() => {
const events = ["mousedown", "keydown", "scroll", "touchstart"];
const handleActivity = () => resetTimeout();
events.forEach((e) => window.addEventListener(e, handleActivity));
resetTimeout();
return () => {
events.forEach((e) => window.removeEventListener(e, handleActivity));
if (timeoutRef.current) clearTimeout(timeoutRef.current);
if (warningTimeoutRef.current) clearTimeout(warningTimeoutRef.current);
};
}, [router]);
return <>{children}</>;
}