diff --git a/src/App.js b/src/App.js index f0d65f6..3bdbca4 100644 --- a/src/App.js +++ b/src/App.js @@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef, useMemo } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, onAuthStateChanged, signInWithCustomToken } from 'firebase/auth'; import { getFirestore, doc, setDoc, getDoc, getDocs, collection, onSnapshot, updateDoc, deleteDoc, query, writeBatch } from 'firebase/firestore'; -import { PlusCircle, Users, Swords, Trash2, Eye, Edit3, Save, XCircle, ChevronsUpDown, UserCheck, UserX, HeartCrack, HeartPulse, Zap, EyeOff, ExternalLink, AlertTriangle, Play as PlayIcon, Pause as PauseIcon, SkipForward as SkipForwardIcon, StopCircle as StopCircleIcon, Users2 } from 'lucide-react'; // Added Users2 for Add All +import { PlusCircle, Users, Swords, Trash2, Eye, Edit3, Save, XCircle, ChevronsUpDown, UserCheck, UserX, HeartCrack, HeartPulse, Zap, EyeOff, ExternalLink, AlertTriangle, Play as PlayIcon, Pause as PauseIcon, SkipForward as SkipForwardIcon, StopCircle as StopCircleIcon, Users2, Dices } from 'lucide-react'; // --- Firebase Configuration --- const firebaseConfig = { @@ -48,6 +48,7 @@ const getActiveDisplayDocPath = () => `${PUBLIC_DATA_PATH}/activeDisplay/status` // --- Helper Functions --- const generateId = () => crypto.randomUUID(); +const rollD20 = () => Math.floor(Math.random() * 20) + 1; // --- Custom Hooks for Firestore --- function useFirestoreDocument(docPath) { @@ -213,7 +214,7 @@ function App() { {!isAuthReady && !error &&
Authenticating...
} ); @@ -376,35 +377,48 @@ function CreateCampaignForm({ onCreate, onCancel }) { function CharacterManager({ campaignId, campaignCharacters }) { const [characterName, setCharacterName] = useState(''); - const [defaultMaxHp, setDefaultMaxHp] = useState(10); // New state for default HP - const [editingCharacter, setEditingCharacter] = useState(null); // { id, name, defaultMaxHp } + const [defaultMaxHp, setDefaultMaxHp] = useState(10); + const [defaultInitMod, setDefaultInitMod] = useState(0); + const [editingCharacter, setEditingCharacter] = useState(null); const [showDeleteCharConfirm, setShowDeleteCharConfirm] = useState(false); const [itemToDelete, setItemToDelete] = useState(null); const handleAddCharacter = async () => { if (!db ||!characterName.trim() || !campaignId) return; const hp = parseInt(defaultMaxHp, 10); + const initMod = parseInt(defaultInitMod, 10); if (isNaN(hp) || hp <= 0) { - alert("Please enter a valid positive number for Default Max HP."); // TODO: Replace with better notification + alert("Please enter a valid positive number for Default Max HP."); return; } - const newCharacter = { id: generateId(), name: characterName.trim(), defaultMaxHp: hp }; + if (isNaN(initMod)) { + alert("Please enter a valid number for Default Initiative Modifier."); + return; + } + const newCharacter = { id: generateId(), name: characterName.trim(), defaultMaxHp: hp, defaultInitMod: initMod }; try { await updateDoc(doc(db, getCampaignDocPath(campaignId)), { players: [...campaignCharacters, newCharacter] }); setCharacterName(''); - setDefaultMaxHp(10); // Reset default HP input + setDefaultMaxHp(10); + setDefaultInitMod(0); } catch (err) { console.error("Error adding character:", err); } }; - const handleUpdateCharacter = async (characterId, newName, newDefaultMaxHp) => { + const handleUpdateCharacter = async (characterId, newName, newDefaultMaxHp, newDefaultInitMod) => { if (!db ||!newName.trim() || !campaignId) return; const hp = parseInt(newDefaultMaxHp, 10); + const initMod = parseInt(newDefaultInitMod, 10); if (isNaN(hp) || hp <= 0) { - alert("Please enter a valid positive number for Default Max HP."); // TODO: Replace with better notification - setEditingCharacter(null); // Close edit mode on invalid input + alert("Please enter a valid positive number for Default Max HP."); + setEditingCharacter(null); return; } - const updatedCharacters = campaignCharacters.map(c => c.id === characterId ? { ...c, name: newName.trim(), defaultMaxHp: hp } : c); + if (isNaN(initMod)) { + alert("Please enter a valid number for Default Initiative Modifier."); + setEditingCharacter(null); + return; + } + const updatedCharacters = campaignCharacters.map(c => c.id === characterId ? { ...c, name: newName.trim(), defaultMaxHp: hp, defaultInitMod: initMod } : c); try { await updateDoc(doc(db, getCampaignDocPath(campaignId)), { players: updatedCharacters }); setEditingCharacter(null); @@ -424,33 +438,38 @@ function CharacterManager({ campaignId, campaignCharacters }) { <>