Files
MultiRoombaRover/webui/src/hooks/useDriverVideoModePolicy.js
T
2026-07-16 17:29:00 -04:00

48 lines
2.4 KiB
JavaScript

import { useMemo } from 'react';
import { useSessionSelector } from '../context/SessionContext.jsx';
import { useSharedClock } from './useSharedClock.js';
export function useDriverVideoModePolicy(roverId) {
const mode = useSessionSelector((state) => state.session?.mode || null);
const turnQueues = useSessionSelector((state) => state.session?.turnQueues ?? {});
const socketId = useSessionSelector((state) => state.session?.socketId || null);
const activeDrivers = useSessionSelector((state) => state.session?.activeDrivers ?? {});
const nonTurnSnapshotsActive = useSessionSelector(
(state) => Boolean(state.session?.bandwidthSavings?.nonTurnVideo?.snapshotsActive),
);
const isTurnsMode = mode === 'turns';
/*
This policy only switches preview/full video around a multi-second turn
boundary. A shared one-second clock is responsive enough for that UI policy
and avoids running a separate 250ms timer beside the TurnsOverlay countdown.
*/
const now = useSharedClock(1000, isTurnsMode);
const turnInfo = roverId ? turnQueues?.[roverId] || null : null;
const activeDriverId = roverId ? activeDrivers?.[roverId] || null : null;
const isActiveDriver = Boolean(socketId && activeDriverId === socketId);
const nextDriverId = useMemo(() => {
const queue = turnInfo?.queue || [];
if (!queue.length || !turnInfo?.current || queue.length <= 1) return null;
const idx = queue.findIndex((id) => id === turnInfo.current);
if (idx === -1) return queue[0] || null;
return queue[(idx + 1) % queue.length] || null;
}, [turnInfo]);
const isNextDriver = Boolean(socketId && nextDriverId === socketId);
const deadline = turnInfo?.deadline || null;
const msUntilTurn = deadline ? deadline - now : null;
/*
The server evaluates the global controllable-user threshold because that
same decision is enforced in socket video tokens and MediaMTX auth. This
hook only mirrors the active result so the browser does not request live
video when snapshots are already the authoritative non-turn outcome.
*/
const shouldUsePreviewByLoad = nonTurnSnapshotsActive && isTurnsMode;
const isPreSwitchWindow =
isTurnsMode && isNextDriver && msUntilTurn != null && msUntilTurn <= 5000 && msUntilTurn > 0;
const showNotTurnNotice = isTurnsMode && !isActiveDriver;
const forceSnapshotByTurnPolicy = showNotTurnNotice && !isPreSwitchWindow && shouldUsePreviewByLoad;
return forceSnapshotByTurnPolicy ? 'snapshot' : null;
}