feat: admin auto-solve button for quick level testing

- Add adminMode toggle in AdminPanel (green "Admin ON/OFF" button)
- Pass adminMode through GameApp → PuzzleView
- Show purple "🛠 Resolver" button in puzzle toolbar when admin is active
- Auto-solve gives 3 stars instantly and shows completion overlay
- Lets admin skip through all 96 levels for rapid testing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jose Luis
2026-03-21 03:15:31 +01:00
parent 1e3652f3b0
commit be66d9a7cf
4 changed files with 36 additions and 2 deletions

View File

@@ -5,7 +5,7 @@
import React, { useState } from 'react';
import { loadProgress, saveProgress, resetProgress } from './gameState.js';
export default function AdminPanel({ worlds, onClose }) {
export default function AdminPanel({ worlds, onClose, adminMode, onToggleAdmin }) {
const [, refresh] = useState(0);
const p = loadProgress();
const totalStars = Object.values(p.completedLevels).reduce((s, l) => s + (l.stars || 0), 0);
@@ -63,6 +63,12 @@ export default function AdminPanel({ worlds, onClose }) {
</div>
<div className="admin-actions">
<button
className={`admin-action-btn ${adminMode ? 'active' : ''}`}
onClick={onToggleAdmin}
>
{adminMode ? '🛠 Admin ON' : '🛠 Admin OFF'}
</button>
<button className="admin-action-btn gold" onClick={giveAllStars}> Todo</button>
<button className="admin-action-btn danger" onClick={handleReset}>Reset Progreso</button>
</div>

View File

@@ -23,6 +23,7 @@ export default function GameApp({ onSwitchToSandbox }) {
const [currentLevelIndex, setCurrentLevelIndex] = useState(0);
const [currentWorld, setCurrentWorld] = useState(null);
const [showAdmin, setShowAdmin] = useState(false);
const [adminMode, setAdminMode] = useState(false);
const handleSelectLevel = useCallback((level, world) => {
const idx = world.levels.findIndex(l => l.id === level.id);
@@ -67,6 +68,7 @@ export default function GameApp({ onSwitchToSandbox }) {
worldLevels={currentWorld.levels}
onBack={handleBack}
onNextLevel={handleNextLevel}
adminMode={adminMode}
/>
);
}
@@ -82,6 +84,8 @@ export default function GameApp({ onSwitchToSandbox }) {
<AdminPanel
worlds={allWorlds}
onClose={() => setShowAdmin(false)}
adminMode={adminMode}
onToggleAdmin={() => setAdminMode(a => !a)}
/>
)}
</>

View File

@@ -9,7 +9,7 @@ import LevelComplete from './LevelComplete.jsx';
import { completeLevel, saveLevelPatch, getLevelPatch, markHintUsed, wasHintUsed } from './gameState.js';
import { playLevelComplete, playFail, playHint, playEngineStart, playEngineStop, playNav } from '../engine/uiSounds.js';
export default function PuzzleView({ level, levelIndex, worldLevels, onBack, onNextLevel }) {
export default function PuzzleView({ level, levelIndex, worldLevels, onBack, onNextLevel, adminMode }) {
const [, forceUpdate] = useState(0);
const containerRef = useRef(null);
const portPositions = useRef({});
@@ -285,6 +285,17 @@ export default function PuzzleView({ level, levelIndex, worldLevels, onBack, onN
}
};
// Admin auto-solve — gives 3 stars instantly
const handleAutoSolve = () => {
const checks = level.checks.map(check => ({
...check,
passed: true,
}));
completeLevel(level.id, 3);
setResult({ stars: 3, checks, hintPenalty: false });
playLevelComplete();
};
const isLastLevel = levelIndex >= worldLevels.length - 1;
return (
@@ -312,6 +323,11 @@ export default function PuzzleView({ level, levelIndex, worldLevels, onBack, onN
<button className="gm-btn check" onClick={handleCheck}>
Comprobar
</button>
{adminMode && (
<button className="gm-btn admin-solve" onClick={handleAutoSolve} title="Admin: resolver nivel">
🛠 Resolver
</button>
)}
</div>
</div>

View File

@@ -715,9 +715,17 @@ html, body, #root {
}
.admin-action-btn.gold { border-color: var(--yellow); color: var(--yellow); }
.admin-action-btn.gold:hover { background: var(--yellow); color: var(--bg); }
.admin-action-btn.active { border-color: var(--green); color: var(--green); background: rgba(68, 255, 136, 0.1); }
.admin-action-btn.active:hover { background: var(--green); color: var(--bg); }
.admin-action-btn.danger { border-color: var(--red); color: var(--red); }
.admin-action-btn.danger:hover { background: var(--red); color: #fff; }
/* Admin auto-solve button in puzzle bar */
.gm-btn.admin-solve {
background: rgba(170, 85, 255, 0.15); border-color: var(--purple); color: var(--purple);
}
.gm-btn.admin-solve:hover { background: var(--purple); color: #fff; }
.admin-world { margin-bottom: 16px; }
.admin-world-header {
display: flex; align-items: center; gap: 8px;