fix(deferred): close frontend UI/UX tails from the hygiene sweep

- player YB2: keepalive pagehide beacon (api.saveProgressBeacon) so the resume
  position isn't lost on F5/close within 5s of the last checkpoint (mirrors Plex).
- player YB4: bound consecutive unplayable items in auto-advance so an
  auto-advancing/loop=all queue can't spin over a run of dead videos.
- downloads B6 (client): localise structured quota/edit errors centrally in
  api.req() via localizeDetail() + Intl.NumberFormat (fixes HU/DE + decimal sep);
  + 3-locale download error strings.
- channels FB1: focusChannelToken bump so re-clicking the same channel re-seeds
  the search box; FB2: syncSubs invalidates feed/feed-count (set can change now).
- config CB2: reseed the ConfigPanel draft on a key-set dataVersion + explicit
  post-save token, so a mid-edit refetch can't clobber an in-progress edit.
- config AB3 (UI): a blank allow_empty field stores "" instead of resetting.
- admin SB2/SC2: confirm + success toast on demo-whitelist remove and deny-invite
  (+ trilingual strings); SC1: disable only the acted-on row (pendingId), not all;
  SB3: pause the 1s scheduler countdown ticker while the tab is hidden.
- messages CT4: only invalidate conversations/unread when the incoming-message
  count actually changed, not on every 20s poll; MB3 (client): react to the live
  unread ping (onUnread → invalidate); MC3: extract e2ee installKey (setup/unlock);
  CC2: hoist POLL_MS to messaging.ts; MB4: document the reload-scoped socket.
This commit is contained in:
npeter83 2026-07-12 05:59:25 +02:00
parent 4e80e2b39b
commit f0198f2e0a
19 changed files with 302 additions and 45 deletions

View file

@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
import { useQueryClient } from "@tanstack/react-query";
import { ChevronDown, ChevronUp, X } from "lucide-react";
import { closeChat, initDock, notifyIncoming, toggleMinimize, useDockChats, type DockChat } from "../lib/chatDock";
import { onMessage } from "../lib/messagesSocket";
import { onMessage, onUnread } from "../lib/messagesSocket";
import * as e2ee from "../lib/e2ee";
import Avatar from "./Avatar";
import ChatThread from "./ChatThread";
@ -39,6 +39,16 @@ export default function ChatDock({ meId }: { meId: number }) {
[qc, meId]
);
// Live badge sync: another tab/device read a thread → refresh this tab's unread count + list.
useEffect(
() =>
onUnread(() => {
qc.invalidateQueries({ queryKey: ["message-unread"] });
qc.invalidateQueries({ queryKey: ["conversations"] });
}),
[qc]
);
if (chats.length === 0) return null;
return (
<div className="fixed bottom-0 right-0 z-40 flex flex-row-reverse items-end gap-3 p-4 pointer-events-none">