From 962c0bd911c3fd8bbd68c7ad953e504839c3cc81 Mon Sep 17 00:00:00 2001 From: robert Date: Sun, 25 May 2025 23:28:36 -0400 Subject: [PATCH] more slight changes. --- src/App.js | 226 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 144 insertions(+), 82 deletions(-) diff --git a/src/App.js b/src/App.js index 19877c8..c60d3e2 100644 --- a/src/App.js +++ b/src/App.js @@ -1,8 +1,8 @@ -import React, { useState, useEffect, useRef } from 'react'; // Added useRef +import React, { useState, useEffect, useRef } from 'react'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, onAuthStateChanged, signInWithCustomToken } from 'firebase/auth'; -import { getFirestore, doc, setDoc, addDoc, getDoc, getDocs, collection, onSnapshot, updateDoc, deleteDoc, query, writeBatch } from 'firebase/firestore'; // Removed where as it's not used -import { ArrowLeft, PlusCircle, Users, Swords, Shield, Trash2, Eye, Edit3, Save, XCircle, ChevronsUpDown, ChevronDown, ChevronUp, UserCheck, UserX, HeartCrack, HeartPulse, Zap, Share2, Copy as CopyIcon } from 'lucide-react'; +import { getFirestore, doc, setDoc, addDoc, getDoc, getDocs, collection, onSnapshot, updateDoc, deleteDoc, query, writeBatch } from 'firebase/firestore'; +import { ArrowLeft, PlusCircle, Users, Swords, Shield, Trash2, Eye, Edit3, Save, XCircle, ChevronsUpDown, ChevronDown, ChevronUp, UserCheck, UserX, HeartCrack, HeartPulse, Zap, Share2, Copy as CopyIcon, Image as ImageIcon, EyeOff } from 'lucide-react'; // --- Firebase Configuration --- const firebaseConfig = { @@ -24,7 +24,6 @@ const missingKeys = requiredFirebaseConfigKeys.filter(key => !firebaseConfig[key if (missingKeys.length > 0) { console.error(`CRITICAL: Missing Firebase config values from environment variables: ${missingKeys.join(', ')}`); console.error("Firebase cannot be initialized. Please ensure all REACT_APP_FIREBASE_... variables are set in your .env.local file and accessible during the build."); - // Fallback: Render a message or allow app to break if Firebase is critical } else { try { app = initializeApp(firebaseConfig); @@ -32,11 +31,9 @@ if (missingKeys.length > 0) { auth = getAuth(app); } catch (error) { console.error("Error initializing Firebase:", error); - // Handle initialization error, perhaps by setting db and auth to null or showing an error UI } } - // --- Firestore Paths --- const APP_ID = process.env.REACT_APP_TRACKER_APP_ID || 'ttrpg-initiative-tracker-default'; const PUBLIC_DATA_PATH = `artifacts/${APP_ID}/public/data`; @@ -60,10 +57,10 @@ function App() { const [directDisplayParams, setDirectDisplayParams] = useState(null); useEffect(() => { - if (!auth) { // Check if Firebase auth was initialized + if (!auth) { setError("Firebase Auth not initialized. Check your Firebase configuration."); setIsLoading(false); - setIsAuthReady(false); // Explicitly set auth not ready + setIsAuthReady(false); return; } const handleHashChange = () => { @@ -109,7 +106,7 @@ function App() { }; }, []); - if (!db || !auth) { // If Firebase failed to init + if (!db || !auth) { return (

Configuration Error

@@ -132,48 +129,37 @@ function App() { ); } + const goToAdminView = () => { + setViewMode('admin'); + setDirectDisplayParams(null); + window.location.hash = ''; + }; + return (
{!directDisplayParams && (
-

TTRPG Initiative Tracker

+

+ TTRPG Initiative Tracker +

{userId && UID: {userId}} - {/* Show Admin View button only if not in display mode */} - {viewMode !== 'display' && ( - - )} - {/* Show Player Display button only if not in admin mode (or always if header is visible and it's the only option left) */} - {viewMode !== 'admin' && ( - - )} - {/* Simpler toggle: always show both if header is visible and style the active one */} - {/* The above logic is slightly off for two buttons always present. Let's fix: */} - {/* Corrected Header Buttons for Toggling */} -
@@ -186,11 +172,11 @@ function App() { )} {!directDisplayParams && viewMode === 'admin' && isAuthReady && userId && } {!directDisplayParams && viewMode === 'display' && isAuthReady && } - {!isAuthReady && !error &&

Authenticating...

} {/* Show auth message only if no other error */} + {!isAuthReady && !error &&

Authenticating...

} {!directDisplayParams && (
- TTRPG Initiative Tracker v0.1.13 + TTRPG Initiative Tracker v0.1.15
)}
@@ -205,7 +191,7 @@ function AdminView({ userId }) { const [initialActiveInfo, setInitialActiveInfo] = useState(null); useEffect(() => { - if (!db) return; // Guard against Firebase not initialized + if (!db) return; const campaignsCollectionRef = collection(db, CAMPAIGNS_COLLECTION); const q = query(campaignsCollectionRef); const unsubscribeCampaigns = onSnapshot(q, (snapshot) => { @@ -239,12 +225,16 @@ function AdminView({ userId }) { }, [initialActiveInfo, campaigns, selectedCampaignId]); - const handleCreateCampaign = async (name) => { + const handleCreateCampaign = async (name, backgroundUrl) => { if (!db || !name.trim()) return; const newCampaignId = generateId(); try { await setDoc(doc(db, CAMPAIGNS_COLLECTION, newCampaignId), { - name: name.trim(), ownerId: userId, createdAt: new Date().toISOString(), players: [], + name: name.trim(), + playerDisplayBackgroundUrl: backgroundUrl.trim() || '', + ownerId: userId, + createdAt: new Date().toISOString(), + players: [], }); setShowCreateCampaignModal(false); setSelectedCampaignId(newCampaignId); @@ -292,6 +282,7 @@ function AdminView({ userId }) { >

{campaign.name}

ID: {campaign.id}

+ {campaign.playerDisplayBackgroundUrl && } @@ -470,9 +472,27 @@ function EncounterManager({ campaignId, initialActiveEncounterId, campaignCharac const handleSetEncounterAsActiveDisplay = async (encounterId) => { if (!db) return; try { - await setDoc(doc(db, ACTIVE_DISPLAY_DOC), { activeCampaignId: campaignId, activeEncounterId: encounterId }, { merge: true }); - console.log("Encounter set as active for DM's main display!"); - } catch (err) { console.error("Error setting active display:", err); } + const currentActiveCampaign = activeDisplayInfo?.activeCampaignId; + const currentActiveEncounter = activeDisplayInfo?.activeEncounterId; + + if (currentActiveCampaign === campaignId && currentActiveEncounter === encounterId) { + // Currently active, so toggle off + await updateDoc(doc(db, ACTIVE_DISPLAY_DOC), { + activeCampaignId: null, + activeEncounterId: null, + }); + console.log("Encounter display toggled OFF for DM."); + } else { + // Not active or different encounter, so set this one as active + await setDoc(doc(db, ACTIVE_DISPLAY_DOC), { + activeCampaignId: campaignId, + activeEncounterId: encounterId, + }, { merge: true }); + console.log("Encounter set as active for DM's main display!"); + } + } catch (err) { + console.error("Error toggling active display:", err); + } }; const handleCopyToClipboard = (encounterId) => { @@ -504,7 +524,13 @@ function EncounterManager({ campaignId, initialActiveEncounterId, campaignCharac {isDmActiveDisplay && LIVE ON DM DISPLAY}
- + {copiedLinkEncounterId === encounter.id && Copied!} @@ -727,7 +753,7 @@ function ParticipantManager({ encounter, encounterPath, campaignCharacters }) {