diff --git a/src/App.js b/src/App.js index 7ee76e2..63fbbf4 100644 --- a/src/App.js +++ b/src/App.js @@ -1993,7 +1993,7 @@ function InitiativeControls({ campaignId, encounter, encounterPath }) { // ENCOUNTER MANAGER COMPONENT // ============================================================================ -function EncounterManager({ campaignId, initialActiveEncounterId, campaignCharacters }) { +function EncounterManager({ campaignId, initialActiveEncounterId, campaignCharacters, encounterStartedRef, encounterActiveRef }) { const { showToast } = useUIFeedback(); const { data: encountersData, isLoading: isLoadingEncounters } = useFirestoreCollection( campaignId ? getPath.encounters(campaignId) : null @@ -2130,6 +2130,15 @@ function EncounterManager({ campaignId, initialActiveEncounterId, campaignCharac const selectedEncounter = encounters?.find(e => e.id === selectedEncounterId); + useEffect(() => { + if (encounterStartedRef) { + encounterStartedRef.current = !!(selectedEncounter && selectedEncounter.isStarted && !selectedEncounter.isPaused); + } + if (encounterActiveRef) { + encounterActiveRef.current = !!(selectedEncounter && selectedEncounter.isStarted); + } + }, [selectedEncounter, encounterStartedRef, encounterActiveRef]); + if (isLoadingEncounters && campaignId) { return
Loading encounters...
; } @@ -2166,9 +2175,9 @@ function EncounterManager({ campaignId, initialActiveEncounterId, campaignCharac >- Participants: {encounter.participants?.length || 0} + {encounter.createdAt && `${new Date(encounter.createdAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false })} ยท `}Participants: {encounter.participants?.length || 0}
{isLive && ( @@ -2265,6 +2274,19 @@ function AdminView({ userId }) { const [campaignsWithDetails, setCampaignsWithDetails] = useState([]); const [selectedCampaignId, setSelectedCampaignId] = useState(null); + const encounterStartedRef = useRef(false); + const encounterActiveRef = useRef(false); + const manualSelectRef = useRef(false); + const prevDisplayCampaignRef = useRef(null); + + // External display change (replay/other DM) = clear manual override, allow follow. + useEffect(() => { + const cur = initialActiveInfo?.activeCampaignId || null; + if (cur !== prevDisplayCampaignRef.current) { + manualSelectRef.current = false; + prevDisplayCampaignRef.current = cur; + } + }, [initialActiveInfo]); const [showCreateModal, setShowCreateModal] = useState(false); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [itemToDelete, setItemToDelete] = useState(null); @@ -2324,10 +2346,15 @@ function AdminView({ userId }) { }, [campaignsData]); useEffect(() => { + // Skip follow only if user manually selected AND display hasn't changed. + // (external display change clears manualSelectRef via prevDisplay effect) + if (manualSelectRef.current && selectedCampaignId !== initialActiveInfo?.activeCampaignId) return; if ( initialActiveInfo && initialActiveInfo.activeCampaignId && - campaignsWithDetails.length > 0 + campaignsWithDetails.length > 0 && + !encounterStartedRef.current && + !encounterActiveRef.current ) { const campaignExists = campaignsWithDetails.some(c => c.id === initialActiveInfo.activeCampaignId); if (campaignExists && selectedCampaignId !== initialActiveInfo.activeCampaignId) { @@ -2500,7 +2527,14 @@ function AdminView({ userId }) { return (