mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 09:31:20 -04:00
barcode gamings
This commit is contained in:
@@ -65,6 +65,28 @@ function StatGrid({ stats }) {
|
||||
);
|
||||
}
|
||||
|
||||
function ParticipantsBlock({ participants }) {
|
||||
const knownParticipants = Array.isArray(participants) ? participants : [];
|
||||
// Participants are server-owned because rover scans, identity lookup, and
|
||||
// score eligibility all happen outside this panel. The UI only formats the
|
||||
// current round list so users can tell whether their rover was counted.
|
||||
const displayNames = knownParticipants
|
||||
.map((participant) => participant?.nickname || participant?.roverId)
|
||||
.filter(Boolean);
|
||||
|
||||
return (
|
||||
<div className="min-w-0 border border-neutral-700 px-2 py-1.5">
|
||||
<p className="text-sm font-semibold text-neutral-400">Participants</p>
|
||||
<p className="font-mono text-2xl font-semibold leading-tight text-neutral-50">
|
||||
{knownParticipants.length}
|
||||
</p>
|
||||
<p className="truncate text-sm leading-tight text-neutral-300">
|
||||
{displayNames.length ? displayNames.join(', ') : 'Scan rover to join'}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CounterList({ title, entries }) {
|
||||
if (!Array.isArray(entries) || !entries.length) return null;
|
||||
return (
|
||||
@@ -120,11 +142,15 @@ export default function BarcodeGamesPanel() {
|
||||
const [pendingGameId, setPendingGameId] = useState(null);
|
||||
const activeGame = state.activeGame;
|
||||
const display = activeGame?.display || {};
|
||||
const votingDisabled = state.phase === 'starting' || state.phase === 'running';
|
||||
// Voting should stop once the shared game system has moved past selection.
|
||||
// The joining phase is included because it is still part of starting the
|
||||
// selected game, even though game rules are not running until the countdown.
|
||||
const votingDisabled = state.phase === 'joining' || state.phase === 'starting' || state.phase === 'running';
|
||||
const timerEndsAt = display.timer?.endsAt;
|
||||
const now = useClock(Number.isFinite(timerEndsAt));
|
||||
const timerText = formatTimer(timerEndsAt, now);
|
||||
const games = useMemo(() => (Array.isArray(state.games) ? state.games : []), [state.games]);
|
||||
const participants = Array.isArray(state.participants) ? state.participants : [];
|
||||
|
||||
const handleVote = async (gameId) => {
|
||||
setPendingGameId(gameId);
|
||||
@@ -148,23 +174,29 @@ export default function BarcodeGamesPanel() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
<section className="space-y-1 border-t border-neutral-700 pt-1.5">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<section className="space-y-2 border-t border-neutral-700 pt-2">
|
||||
<div className="grid items-start gap-2 lg:grid-cols-[minmax(0,1fr)_15rem_15rem]">
|
||||
<div className="min-w-0">
|
||||
<p className="text-xs font-semibold text-neutral-400">{display.title || activeGame?.title || 'No game active'}</p>
|
||||
<p className="break-words text-lg font-semibold leading-tight text-neutral-50">
|
||||
<p className="break-words text-2xl font-bold leading-tight text-neutral-50">
|
||||
{display.title || activeGame?.title || 'No game active'}
|
||||
</p>
|
||||
<p className="mt-0.5 break-words text-lg font-semibold leading-tight text-neutral-200">
|
||||
{display.primary || 'Vote for a game to start'}
|
||||
</p>
|
||||
{display.secondary ? (
|
||||
<p className="mt-0.5 break-words text-sm leading-snug text-neutral-300">{display.secondary}</p>
|
||||
<p className="mt-1 break-words text-base leading-snug text-neutral-300">{display.secondary}</p>
|
||||
) : null}
|
||||
</div>
|
||||
{timerText ? (
|
||||
<div className="shrink-0 text-right">
|
||||
<p className="text-[0.68rem] text-neutral-400">{display.timer?.label || 'Time'}</p>
|
||||
<p className="font-mono text-base font-semibold text-neutral-50">{timerText}</p>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="border border-neutral-700 px-2 py-1.5 text-left lg:text-right">
|
||||
<p className="text-sm font-semibold text-neutral-400">{display.timer?.label || 'Time'}</p>
|
||||
<p className="font-mono text-2xl font-semibold leading-tight text-neutral-50">
|
||||
{timerText || '--'}
|
||||
</p>
|
||||
<p className="text-sm leading-tight text-neutral-500">
|
||||
{timerText ? 'active timer' : 'no timer'}
|
||||
</p>
|
||||
</div>
|
||||
<ParticipantsBlock participants={participants} />
|
||||
</div>
|
||||
<StatGrid stats={display.stats} />
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user