diff --git a/src/components/MissionTab.jsx b/src/components/MissionTab.jsx index 0f11d01..dcca053 100644 --- a/src/components/MissionTab.jsx +++ b/src/components/MissionTab.jsx @@ -168,6 +168,10 @@ export default function MissionTab({ authedPlayer }) { const [showMissionReport, setShowMissionReport] = useState(false); const [outcomeNotes, setOutcomeNotes] = useState(''); + // Scene editor + const [editingScene, setEditingScene] = useState(false); + const [sceneEdit, setSceneEdit] = useState(null); + // ─── Data loading ─────────────────────────────────────────────── const loadMissions = useCallback(async function loadMissions() { @@ -624,6 +628,80 @@ export default function MissionTab({ authedPlayer }) { await saveProgress(activeMission.current_scene, nextScenes); } + // ─── Scene editor helpers ──────────────────────────────────────── + + function openSceneEdit() { + if (!currentScene) return; + setSceneEdit({ + title: currentScene.title || currentScene.name || '', + type: currentScene.type || 'combat', + description: currentScene.description || currentScene.briefing || currentScene.summary || '', + checks: (Array.isArray(currentScene.checks) ? currentScene.checks : []).map(c => ({ ...c })), + enemies: (Array.isArray(currentScene.enemies) ? currentScene.enemies : []).map(e => ({ ...e })), + objectives: (Array.isArray(currentScene.objectives) ? currentScene.objectives : []).join('\n'), + complications: (Array.isArray(currentScene.complications) ? currentScene.complications : []).join('\n'), + }); + setEditingScene(true); + } + + async function saveSceneEdit() { + if (!sceneEdit) return; + const toArr = (str) => str.split('\n').map(s => s.trim()).filter(Boolean); + await patchScene({ + title: sceneEdit.title.trim() || undefined, + name: sceneEdit.title.trim() || undefined, + type: sceneEdit.type, + description: sceneEdit.description, + briefing: sceneEdit.description, + checks: sceneEdit.checks, + enemies: sceneEdit.enemies, + objectives: toArr(sceneEdit.objectives), + complications: toArr(sceneEdit.complications), + }); + setEditingScene(false); + setSceneEdit(null); + } + + function seField(field, value) { + setSceneEdit(prev => ({ ...prev, [field]: value })); + } + + function seCheck(i, field, value) { + setSceneEdit(prev => { + const checks = prev.checks.map((c, idx) => idx === i ? { ...c, [field]: value } : c); + return { ...prev, checks }; + }); + } + + function addCheck() { + setSceneEdit(prev => ({ + ...prev, + checks: [...prev.checks, { name: 'New Check', skill: 'Awareness', characteristic: 'Per', target: 45, modifier: 0, reward: '' }], + })); + } + + function removeCheck(i) { + setSceneEdit(prev => ({ ...prev, checks: prev.checks.filter((_, idx) => idx !== i) })); + } + + function seEnemy(i, field, value) { + setSceneEdit(prev => { + const enemies = prev.enemies.map((e, idx) => idx === i ? { ...e, [field]: value } : e); + return { ...prev, enemies }; + }); + } + + function addEnemy() { + setSceneEdit(prev => ({ + ...prev, + enemies: [...prev.enemies, { name: 'Enemy', wounds: 10, bs: 45, ws: 45, damage: '1d10+4', ap: 0 }], + })); + } + + function removeEnemy(i) { + setSceneEdit(prev => ({ ...prev, enemies: prev.enemies.filter((_, idx) => idx !== i) })); + } + // ─── Render ────────────────────────────────────────────────────── if (!authedPlayer) { @@ -1334,11 +1412,19 @@ export default function MissionTab({ authedPlayer }) {

Scene Secrets

- {playPrompt && ( - - )} + {playPrompt && ( + + )} +
{/* #2 — reveal scene toggle */} @@ -1511,6 +1597,196 @@ export default function MissionTab({ authedPlayer }) { + + {/* Scene Editor */} + {editingScene && sceneEdit && ( +
+
+

Edit Scene

+
+ + +
+
+ + {/* Title + Type */} +
+
+ + seField('title', e.target.value)} + className="w-full rounded border border-slate-600 bg-slate-900 px-3 py-2 text-sm text-slate-100" + /> +
+
+ + +
+
+ + {/* Description */} +
+ +