// Queue Target Row
// Purpose: Renders the shared queue-row visual language used by rover queues and PTZ.
// Scope: Owns row chrome, queue chips, timer labels, and row/button event plumbing;
// callers still own target-specific permission checks and request actions.
import RoverLabel from '../RoverLabel/index.jsx';
import RoverHelpOverlay from '../RoverHelpOverlay/index.jsx';
function classNames(...values) {
return values.filter(Boolean).join(' ');
}
function roleColors(role) {
switch (role) {
case 'admin':
case 'lockdown':
return 'text-amber-300';
case 'spectator':
return 'text-slate-400';
default:
return 'text-sky-300';
}
}
export function QueueUserChips({
targetId,
turn,
selfId = null,
}) {
const { queue = [], currentId, nextId } = turn || {};
if (!queue?.length) {
return
No queue.
;
}
return (
{queue.map((user, idx) => {
const { socketId } = user;
const isCurrent = socketId === currentId;
const isNext = Boolean(nextId && socketId === nextId && !isCurrent);
/*
These classes intentionally mirror the original rover queue styling.
PTZ feeds the same current/next model into this component, so the user
does not have to learn a different visual vocabulary for camera turns.
*/
const highlightClass = isCurrent
? 'bg-sky-600 text-white ring-2 ring-amber-300'
: isNext
? 'bg-emerald-700/60 text-emerald-100 ring-1 ring-emerald-300/70'
: 'bg-slate-800 text-slate-200';
return (
{user.name}{socketId === selfId ? ' (you)' : ''}
{isCurrent && now }
{isNext && next }
);
})}
);
}
export default function QueueTargetRow({
target,
turn,
selfId = null,
canClick = false,
pending = false,
locked = false,
lockedBlocked = false,
privateOpen = false,
buttonLabel = '',
batteryLabel = '',
batteryClassName = 'text-slate-400',
timerLabel = '',
thumbnailUrl = '',
onRequest,
showAction = true,
}) {
const targetId = String(target?.id || '');
const targetLabel = target?.label || target?.name || targetId;
return (
{
/*
The whole row is a large target because queue selection is one of the
main touch/click actions on the page. The caller still decides whether
clicking is currently allowed, so disabled PTZ and locked rover states
cannot accidentally request control through the shared renderer.
*/
if (!canClick) return;
onRequest?.(targetId);
}}
>
{thumbnailUrl ? (
) : null}
{target?.description ? (
{target.description}
) : null}
{timerLabel ? (
{timerLabel}
) : null}
{batteryLabel ? (
{batteryLabel}
) : null}
{showAction ? (
{
/*
Stop propagation so button clicks do not double-fire the row
request. This keeps mouse, touch, and keyboard activation on the
explicit button consistent with clicking the row background.
*/
event.stopPropagation();
onRequest?.(targetId);
}}
disabled={pending || lockedBlocked || !canClick}
className={classNames(
'button-dark disabled:opacity-40',
locked && 'bg-red-600/70 text-white hover:bg-red-600',
)}
>
{buttonLabel}
) : null}
{/* Queue rows use the exact overlay component as the large video and
display surfaces; its measured font automatically adapts to this box. */}
);
}