Initial commit: thbd-portal, duplicated from elmi-portal
Rebranded for Thunderbird Portal (THBD): numbering prefix EL->TH, all "ELMI"/"ЭЛМИ" UI strings genericized, ELMI's real contract templates and company legal/bank details removed (not applicable to this company), fresh VAPID keypair and encryption key, fresh single-migration schema history. Same architecture as elmi-portal: Web Push notifications, unread-chat app badge, cookie-session auth. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gh2UXUQUVBWroWEnn1FLFG
This commit is contained in:
commit
579528edf7
197 files changed
+25022
No files matched your search
@@ -0,0 +1,25 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
|
||||
const INTERVAL_MS = 20_000;
|
||||
|
||||
/** Держит lastSeenAt свежим, пока вкладка открыта и видима — "онлайн" на клиенте вычисляется как lastSeenAt моложе ~30с. */
|
||||
export function PresenceHeartbeat() {
|
||||
useEffect(() => {
|
||||
function ping() {
|
||||
if (document.visibilityState === "visible") {
|
||||
fetch("/api/presence/heartbeat", { method: "POST" }).catch(() => {});
|
||||
}
|
||||
}
|
||||
ping();
|
||||
const interval = setInterval(ping, INTERVAL_MS);
|
||||
document.addEventListener("visibilitychange", ping);
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
document.removeEventListener("visibilitychange", ping);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in new issue
Block a user