Files
Cs2-Mapveto/client/src/components/TeamCard.jsx
T
mregosar f64da5ac86 Lobby: Einladungslinks unter dem jeweiligen Team
Der Organisator sieht Code, Link, Kopieren und Neuer Code jetzt unten in der Team-Karte. Im Bereich Einladungen bleiben Zuschauer-, Stream- und Organisator-Links.
2026-11-01 20:09:35 +01:00

67 lines
3.0 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { TeamInvite } from './OrganizerPanel.jsx';
export default function TeamCard({ team, side, state, viewer, isOrg, act, busy }) {
const isOwnTeam = viewer.team === side;
const inLobby = state.status === 'lobby';
const me = team.players.find((p) => p.isYou);
const emptySlots = Math.max(0, team.teamSize - team.players.length);
const canManageCaptain = isOrg || (viewer.isCaptain && isOwnTeam);
const { readiness } = team;
return (
<section className={`team-card team-${side} ${readiness.ready ? 'is-ready' : ''}`} aria-label={`Team ${team.name}`}>
<header>
<h2>{team.name}</h2>
<span className={`ready-state ${readiness.ready ? 'on' : ''}`}>
{readiness.ready ? 'Bereit' : `${readiness.count}/${team.teamSize}`}
</span>
</header>
<ul className="roster">
{team.players.map((p) => (
<li key={p.id} className={`${p.isYou ? 'is-you' : ''}`}>
<span className={`presence ${p.online ? 'on' : ''}`} title={p.online ? 'Online' : 'Offline'} />
<span className="nick">
{p.nickname}
{p.isYou && <small> (du)</small>}
</span>
{p.isCaptain && <span className="captain" title="Captain – führt das Veto">Captain</span>}
{inLobby && <span className={`ready-dot ${p.ready ? 'on' : ''}`}>{p.ready ? 'bereit' : 'wartet'}</span>}
{(canManageCaptain && !p.isCaptain) || (isOrg && inLobby && !p.isYou) ? (
<span className="row-actions">
{canManageCaptain && !p.isCaptain && (
<button className="link-btn" disabled={!!busy} onClick={() => act('captain', { playerId: p.id }, `${p.nickname} ist jetzt Captain`)}>
Zum Captain machen
</button>
)}
{isOrg && inLobby && !p.isYou && (
<button className="link-btn danger" disabled={!!busy} onClick={() => act('kick', { playerId: p.id }, `${p.nickname} entfernt`)}>
Entfernen
</button>
)}
</span>
) : null}
</li>
))}
{Array.from({ length: emptySlots }, (_, i) => (
<li key={`empty-${i}`} className="slot-empty">Freier Platz</li>
))}
</ul>
{me && inLobby && (
<div className="team-actions">
<button className={`btn ${me.ready ? '' : 'btn-primary'}`} disabled={!!busy}
onClick={() => act('ready', { ready: !me.ready })}>
{me.ready ? 'Doch nicht bereit' : 'Ich bin bereit'}
</button>
<button className="link-btn" disabled={!!busy}
onClick={() => window.confirm('Lobby wirklich verlassen?') && act('leave', null, 'Du hast das Team verlassen')}>
Team verlassen
</button>
</div>
)}
{inLobby && !readiness.enough && <p className="small muted">Es fehlen noch {team.teamSize - readiness.count} Spieler.</p>}
{isOrg && state.organizer && <TeamInvite state={state} side={side} act={act} busy={busy} />}
</section>
);
}