feat: Schocken - Testmodus Spieler-Switcher für Admin
This commit is contained in:
@@ -102,7 +102,15 @@ function sendPush(userId, title, message) {
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
const uid = req => req.user.id;
|
||||
const uid = req => {
|
||||
// Testmodus: Admin kann als anderen User agieren
|
||||
const testAs = req.headers['x-schocken-test-as'];
|
||||
if (testAs && req.user?.role === 'admin') {
|
||||
const testId = parseInt(testAs);
|
||||
if (!isNaN(testId)) return testId;
|
||||
}
|
||||
return req.user.id;
|
||||
};
|
||||
|
||||
// ── Alle Spiele des Users ─────────────────────────────────────────────────────
|
||||
router.get('/', authenticate, (req, res) => {
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { api, S } from '../lib.js';
|
||||
|
||||
// Testmodus: API-Call als anderer User (nur Admin, nur Schocken)
|
||||
async function apiAs(userId, path, opts = {}) {
|
||||
const token = localStorage.getItem('sk_token');
|
||||
const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` };
|
||||
if (userId) headers['X-Schocken-Test-As'] = String(userId);
|
||||
const res = await fetch(`/api${path}`, {
|
||||
method: opts.method || (opts.body ? 'POST' : 'GET'),
|
||||
headers,
|
||||
body: opts.body ? JSON.stringify(opts.body) : undefined,
|
||||
});
|
||||
if (!res.ok) { const e = await res.json().catch(()=>({error:'Fehler'})); throw new Error(e.error||'Fehler'); }
|
||||
return res.json();
|
||||
}
|
||||
|
||||
const MY_COLOR = '#4ecdc4';
|
||||
|
||||
function getMyId() {
|
||||
@@ -441,7 +455,7 @@ function GameList({ games, myId, onSelect, onNew }) {
|
||||
}
|
||||
|
||||
// ── Spielansicht ──────────────────────────────────────────────────────────────
|
||||
function GameView({ game, myId, onRefresh, toast }) {
|
||||
function GameView({ game, myId, onRefresh, toast, isAdmin=false, onSeatChange }) {
|
||||
const players = game.players;
|
||||
const chips = game.player_chips;
|
||||
const dl = game.drink_losses;
|
||||
@@ -483,6 +497,21 @@ function GameView({ game, myId, onRefresh, toast }) {
|
||||
<span style={{color:'rgba(255,255,255,0.4)',fontFamily:'monospace',fontSize:10}}>Runde {game.round_number}</span>
|
||||
</div>
|
||||
|
||||
{/* Testmodus-Switcher (nur Admin) */}
|
||||
{isAdmin && (
|
||||
<div style={{marginBottom:12,padding:'8px 12px',background:'rgba(245,158,11,0.08)',border:'1px solid rgba(245,158,11,0.25)',borderRadius:8}}>
|
||||
<div style={{color:'#f59e0b',fontFamily:'monospace',fontSize:10,letterSpacing:1,marginBottom:6}}>🧪 TESTMODUS — SPIELER WECHSELN</div>
|
||||
<div style={{display:'flex',gap:6,flexWrap:'wrap'}}>
|
||||
{players.map(p => (
|
||||
<button key={p.id} onClick={() => onSeatChange(p.id)}
|
||||
style={{...S.btn(myId===p.id?'#f59e0b':'#666666',true),fontSize:10}}>
|
||||
{p.username}{myId===p.id?' ✓':''}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Schockstock */}
|
||||
<Schockstock stock={game.stock} players={players} chips={chips}/>
|
||||
|
||||
@@ -544,8 +573,12 @@ export default function Schocken({ toast }) {
|
||||
const [game, setGame] = useState(null);
|
||||
const [showNew, setShowNew] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [testSeat, setTestSeat] = useState(null); // null = eigener Account, sonst userId
|
||||
|
||||
const myId = getMyId();
|
||||
const myRealId = getMyId();
|
||||
const isAdmin = getMyRole() === 'admin';
|
||||
// Im Testmodus: als anderen Spieler agieren
|
||||
const myId = (isAdmin && testSeat) ? testSeat : myRealId;
|
||||
|
||||
const loadGames = useCallback(async () => {
|
||||
try { setGames(await api('/tools/schocken')); }
|
||||
@@ -585,7 +618,7 @@ export default function Schocken({ toast }) {
|
||||
{!activeId
|
||||
? <GameList games={games} myId={myId} onSelect={setActiveId} onNew={()=>setShowNew(true)}/>
|
||||
: game && myId
|
||||
? <GameView game={game} myId={myId} onRefresh={loadGame} toast={toast}/>
|
||||
? <GameView game={game} myId={myId} onRefresh={loadGame} toast={toast} isAdmin={isAdmin} onSeatChange={id=>{setTestSeat(id);}} />
|
||||
: <div style={{color:'rgba(255,255,255,0.3)',fontFamily:'monospace',textAlign:'center',paddingTop:40}}>Lade…</div>
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user