mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
add turns queue to user list panel
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
|
||||
import { useSession } from '../context/SessionContext.jsx';
|
||||
import { useSettingsNamespace } from '../settings/index.js';
|
||||
import { useSocket } from '../context/SocketContext.jsx';
|
||||
@@ -35,6 +35,9 @@ export default function UserListPanel() {
|
||||
const canSetNickname = session?.role !== 'spectator';
|
||||
const users = session?.users ?? [];
|
||||
const selfId = session?.socketId || null;
|
||||
const isTurnsMode = session?.mode === 'turns';
|
||||
const turnQueues = session?.turnQueues || {};
|
||||
const roster = session?.roster || [];
|
||||
|
||||
useEffect(() => {
|
||||
setNicknameInput(value.nickname || '');
|
||||
@@ -75,6 +78,23 @@ export default function UserListPanel() {
|
||||
[selfId, users],
|
||||
);
|
||||
|
||||
const rosterName = useCallback(
|
||||
(roverId) => roster.find((r) => String(r.id) === String(roverId))?.name || roverId,
|
||||
[roster],
|
||||
);
|
||||
|
||||
const lookupUser = useCallback(
|
||||
(socketId) => users.find((u) => u.socketId === socketId) || { socketId, nickname: null, role: null },
|
||||
[users],
|
||||
);
|
||||
|
||||
const secondsRemaining = useCallback((deadline) => {
|
||||
if (!deadline) return null;
|
||||
const ms = deadline - Date.now();
|
||||
if (ms <= 0) return 0;
|
||||
return Math.ceil(ms / 1000);
|
||||
}, []);
|
||||
|
||||
async function handleSave(event) {
|
||||
event.preventDefault();
|
||||
if (!canSetNickname) return;
|
||||
@@ -113,11 +133,61 @@ export default function UserListPanel() {
|
||||
|
||||
<div className="space-y-0.5">
|
||||
<div className="flex items-center justify-between text-sm text-slate-400">
|
||||
<span>Users</span>
|
||||
<span className="text-xs text-slate-500">{sorted.length}</span>
|
||||
<span>{isTurnsMode ? 'Turn queues' : 'Users'}</span>
|
||||
<span className="text-xs text-slate-500">
|
||||
{isTurnsMode ? Object.keys(turnQueues || {}).length : sorted.length}
|
||||
</span>
|
||||
</div>
|
||||
<div className="surface h-48 overflow-y-auto space-y-0.25">
|
||||
{sorted.length === 0 ? (
|
||||
{isTurnsMode ? (
|
||||
Object.keys(turnQueues || {}).length === 0 ? (
|
||||
<p className="text-sm text-slate-500">No turn queues yet.</p>
|
||||
) : (
|
||||
Object.entries(turnQueues).map(([roverId, info]) => {
|
||||
const queue = info?.queue || [];
|
||||
const deadline = info?.deadline || null;
|
||||
const remaining = secondsRemaining(deadline);
|
||||
return (
|
||||
<div key={roverId} className="surface-muted flex flex-col gap-0.25 text-sm">
|
||||
<div className="flex items-center gap-1">
|
||||
<p className="font-semibold text-slate-200">{rosterName(roverId)}</p>
|
||||
{remaining != null && (
|
||||
<span className="rounded bg-slate-800 px-1 text-[0.7rem]">
|
||||
{remaining}s left
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{queue.length === 0 ? (
|
||||
<p className="text-[0.75rem] text-slate-500">No drivers queued.</p>
|
||||
) : (
|
||||
<div className="flex flex-wrap items-center gap-1">
|
||||
{queue.map((socketId, idx) => {
|
||||
const user = lookupUser(socketId);
|
||||
const isCurrent = socketId === info?.current;
|
||||
const isAdmin =
|
||||
user.role === 'admin' || user.role === 'lockdown' || user.role === 'lockdown-admin';
|
||||
return (
|
||||
<span
|
||||
key={`${roverId}-${socketId}-${idx}`}
|
||||
className={`flex items-center gap-0.5 rounded px-1 text-[0.8rem] ${
|
||||
isCurrent ? 'bg-sky-700 text-white' : 'bg-slate-800 text-slate-200'
|
||||
}`}
|
||||
>
|
||||
<span className={`${roleColors(user.role)} font-semibold`}>
|
||||
{formatLabel(user, selfId)}
|
||||
</span>
|
||||
{isAdmin && <span className="text-[0.7rem] text-amber-200">★</span>}
|
||||
{isCurrent && <span className="text-[0.7rem] text-slate-200">now</span>}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
)
|
||||
) : sorted.length === 0 ? (
|
||||
<p className="text-sm text-slate-500">Waiting for users…</p>
|
||||
) : (
|
||||
sorted.map((user) => {
|
||||
|
||||
Reference in New Issue
Block a user