Organisator kann im selben Browser selbst mitspielen

Ein Aufrufer darf Organisator- und Spieler-Zugang kombinieren
(Authorization + X-Player-Token). Berechtigungen prüfen jetzt einzelne
Merkmale statt einer Rangstufe. In der Lobby gibt es „Selbst mitspielen?“,
Teamlinks funktionieren auch im Organisator-Browser. Online-Status wird
direkt nach dem Beitritt aktualisiert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
SPP UserandClaude Opus 5.5 committed 2026-10-25 17:53:39 +01:00
1 parent 470b12f232
commit 4152f9c0a6
15 files changed
+248 -59

No files matched your search

+13 -4
View File
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { Link, useNavigate, useParams } from 'react-router-dom';
import { api } from '../lib/api.js';
import { getAccess, setAccess } from '../lib/session.js';
import { getAccess, setAccess, setPlayerToken } from '../lib/session.js';
function useCode() {
const { code } = useParams();
@@ -13,6 +13,12 @@ function useCode() {
return { code, info, error };
}
function alreadyPlayer(access) {
if (!access) return false;
if (access.kind === 'organizer') return Boolean(access.playerToken);
return access.kind === 'player';
}
export function JoinPage() {
const { code, info, error } = useCode();
const navigate = useNavigate();
@@ -24,8 +30,8 @@ export function JoinPage() {
useEffect(() => {
if (!info) return;
if (info.access === 'spectator') navigate(`/watch/${code}`, { replace: true });
// Schon beigetreten? Dann direkt zur Lobby.
else if (getAccess(info.matchId)) navigate(`/m/${info.matchId}`, { replace: true });
// Schon als Spieler dabei? Dann direkt zur Lobby. Organisator ohne Team und Zuschauer dürfen beitreten.
else if (alreadyPlayer(getAccess(info.matchId))) navigate(`/m/${info.matchId}`, { replace: true });
}, [info, code, navigate]);
if (error) return <AccessError message={error} />;
@@ -37,7 +43,10 @@ export function JoinPage() {
setSubmitError(null);
try {
const res = await api(`/matches/${info.matchId}/join`, { method: 'POST', body: { code, nickname, steamId } });
setAccess(info.matchId, { token: res.playerToken, kind: 'player' });
const existing = getAccess(info.matchId);
// Der Organisator behält seinen Zugang und bekommt den Spieler-Zugang dazu.
if (existing?.kind === 'organizer') setPlayerToken(info.matchId, res.playerToken);
else setAccess(info.matchId, { token: res.playerToken, kind: 'player' });
navigate(`/m/${info.matchId}`);
} catch (err) {
setSubmitError(err.message);