From 4dd78837638e7b0265d3a5ad4e8c7c39538d28c1 Mon Sep 17 00:00:00 2001 From: isaacclad Date: Sat, 4 Jul 2026 01:00:28 +0000 Subject: [PATCH] Stop Chat and More from flashing on load in audio rooms. Bootstrap room-type flags from meet-config before Alpine paints, gate toolbar and banners server-side per room type, and hide Alpine toolbar items until init completes. Co-authored-by: Cursor --- resources/js/meet-room.js | 149 +++++++++++++++++------ resources/views/meet/room/show.blade.php | 31 +++-- tests/Feature/MeetWebTest.php | 2 + 3 files changed, 137 insertions(+), 45 deletions(-) diff --git a/resources/js/meet-room.js b/resources/js/meet-room.js index fd39a32..093f871 100644 --- a/resources/js/meet-room.js +++ b/resources/js/meet-room.js @@ -1,17 +1,92 @@ import Alpine from 'alpinejs'; import { ConnectionState, Room, RoomEvent, Track } from 'livekit-client'; -function readMeetBootState() { +function readMeetRoomBootState() { const el = document.getElementById('meet-config'); + if (!el) { + return {}; + } + + let presenterRefs = []; + let panels = []; + let sessionParticipants = []; + let roomHost = null; + + try { + presenterRefs = JSON.parse(el.dataset.presenterRefs || '[]'); + } catch { + presenterRefs = []; + } + + try { + panels = JSON.parse(el.dataset.panels || '[]'); + } catch { + panels = []; + } + + try { + sessionParticipants = JSON.parse(el.dataset.initialParticipants || '[]'); + } catch { + sessionParticipants = []; + } + + try { + roomHost = JSON.parse(el.dataset.roomHost || 'null'); + } catch { + roomHost = null; + } + + const audioOnly = el.dataset.audioOnly === '1'; + let stageLayout = el.dataset.stageLayout || 'plenary'; + const panelDiscussions = el.dataset.panelDiscussions === '1'; + + if (!panelDiscussions && stageLayout === 'panel') { + stageLayout = 'plenary'; + } + + const participantUuid = el.dataset.participant || ''; + const selfParticipant = sessionParticipants.find((person) => person.uuid === participantUuid); + return { - isRecording: el?.dataset.recordingActive === '1', - isLocked: el?.dataset.locked === '1', + isHost: el.dataset.isHost === '1', + canPublish: el.dataset.canPublish !== '0', + audioOnlyPublish: el.dataset.audioOnlyPublish === '1', + usesSpeakAccess: el.dataset.usesSpeakAccess === '1', + canManageSpeak: el.dataset.canManageSpeak === '1', + speakGranted: el.dataset.speakGranted === '1', + speakRequested: el.dataset.speakRequested === '1', + inBreakout: el.dataset.inBreakout === '1', + isWebinar: el.dataset.isWebinar === '1', + isConference: el.dataset.isConference === '1', + sessionNounLabel: el.dataset.sessionNoun || '', + isGreenRoom: el.dataset.isGreenRoom === '1', + audioOnly, + isSpace: el.dataset.isSpace === '1', + muteOnJoin: el.dataset.muteOnJoin === '1', + videoOffOnJoin: el.dataset.videoOffOnJoin === '1' || audioOnly, + isRecording: el.dataset.recordingActive === '1', + activeRecordingUuid: el.dataset.activeRecordingUuid || null, + isLocked: el.dataset.locked === '1', + watermark: el.dataset.watermark === '1', + liveCaptions: el.dataset.liveCaptions === '1', + displayName: el.dataset.displayName || '', + presenterRefs, + usesStageLayout: el.dataset.usesStageLayout === '1', + panelDiscussions, + stageLayout, + activePanelId: el.dataset.activePanelId || '', + spotlightSpeakerRef: el.dataset.spotlightSpeakerRef || '', + panels, + sessionParticipants, + roomHost, + waitingCount: sessionParticipants.filter((person) => person.status === 'waiting').length, + assignedBreakoutRoomId: selfParticipant?.breakout_room_id ?? null, }; } function meetRoom() { - const boot = readMeetBootState(); + const roomBoot = readMeetRoomBootState(); // LiveKit Room must stay outside Alpine's reactive proxy — wrapping it breaks // structuredClone inside the SDK during connect and media setup. let room = null; @@ -33,38 +108,43 @@ function meetRoom() { isMuted: true, isVideoOff: true, isScreenSharing: false, - isRecording: boot.isRecording, - isLocked: boot.isLocked, - isHost: false, - watermark: false, - liveCaptions: false, + isRecording: roomBoot.isRecording ?? false, + isLocked: roomBoot.isLocked ?? false, + isHost: roomBoot.isHost ?? false, + watermark: roomBoot.watermark ?? false, + liveCaptions: roomBoot.liveCaptions ?? false, + displayName: roomBoot.displayName ?? '', + canPublish: roomBoot.canPublish ?? true, + muteOnJoin: roomBoot.muteOnJoin ?? true, + videoOffOnJoin: roomBoot.videoOffOnJoin ?? false, + waitingCount: roomBoot.waitingCount ?? 0, + isWebinar: roomBoot.isWebinar ?? false, + isConference: roomBoot.isConference ?? false, + sessionNounLabel: roomBoot.sessionNounLabel ?? '', + isGreenRoom: roomBoot.isGreenRoom ?? false, + presenterRefs: roomBoot.presenterRefs ?? [], + audioOnly: roomBoot.audioOnly ?? false, + audioOnlyPublish: roomBoot.audioOnlyPublish ?? false, + usesSpeakAccess: roomBoot.usesSpeakAccess ?? false, + canManageSpeak: roomBoot.canManageSpeak ?? false, + speakGranted: roomBoot.speakGranted ?? false, + speakRequested: roomBoot.speakRequested ?? false, + isSpace: roomBoot.isSpace ?? false, + usesStageLayout: roomBoot.usesStageLayout ?? false, + panelDiscussions: roomBoot.panelDiscussions ?? false, + stageLayout: roomBoot.stageLayout ?? 'plenary', + panels: roomBoot.panels ?? [], + activePanelId: roomBoot.activePanelId ?? '', + spotlightSpeakerRef: roomBoot.spotlightSpeakerRef ?? '', + inBreakout: roomBoot.inBreakout ?? false, + assignedBreakoutRoomId: roomBoot.assignedBreakoutRoomId ?? null, + activeRecordingUuid: roomBoot.activeRecordingUuid ?? null, + sessionParticipants: roomBoot.sessionParticipants ?? [], + roomHost: roomBoot.roomHost ?? null, captionText: '', - displayName: '', - canPublish: true, - muteOnJoin: true, - videoOffOnJoin: false, audioPlaybackBlocked: false, needsMediaUnlock: false, - waitingCount: 0, - isWebinar: false, - isConference: false, - sessionNounLabel: '', - isGreenRoom: false, goingLive: false, - presenterRefs: [], - audioOnly: false, - audioOnlyPublish: false, - usesSpeakAccess: false, - canManageSpeak: false, - speakGranted: false, - speakRequested: false, - isSpace: false, - usesStageLayout: false, - panelDiscussions: false, - stageLayout: 'plenary', - panels: [], - activePanelId: '', - spotlightSpeakerRef: '', panelSetupOpen: false, savingStageLayout: false, _stageSnapshot: null, @@ -72,10 +152,8 @@ function meetRoom() { activePolls: [], breakoutBroadcast: '', breakoutBroadcastInput: '', - inBreakout: false, breakoutsActive: false, activeBreakouts: [], - assignedBreakoutRoomId: null, breakoutRoomName: '', breakoutClosesAt: '', sidebarPanel: null, @@ -87,15 +165,12 @@ function meetRoom() { breakoutModalOpen: false, breakoutCount: '4', endMeetingConfirmOpen: false, - activeRecordingUuid: null, joinUrl: '', passcode: '', roomTitle: '', connectionStatus: 'Connecting…', participants: [], - sessionParticipants: [], activeSpeakerIds: [], - roomHost: null, floatingReactions: [], reactionsInitialized: false, pollTimer: null, diff --git a/resources/views/meet/room/show.blade.php b/resources/views/meet/room/show.blade.php index 0f9a1a7..c1ef4e2 100644 --- a/resources/views/meet/room/show.blade.php +++ b/resources/views/meet/room/show.blade.php @@ -8,7 +8,8 @@ @include('partials.favicon') @vite(['resources/css/app.css', 'resources/js/meet-room.js']) @@ -211,6 +212,7 @@ + @if (($isConference ?? false) && ($isGreenRoom ?? false))
@@ -233,7 +235,9 @@
+ @endif + @if (($inBreakout ?? false) && ! ($isSpace ?? false))
@@ -242,7 +246,9 @@

+ @endif + @unless ($isSpace ?? false)
@@ -254,7 +260,9 @@ End breakouts
+ @endunless + @if (($usesStageLayout ?? false) && ! ($isGreenRoom ?? false) && ! ($inBreakout ?? false))
@@ -279,6 +287,7 @@ Change layout
+ @endif
@@ -372,6 +381,7 @@ You can speak — your microphone is available

+ @if (($isSpace ?? false) && ($speakRequested ?? false) && ! ($canPublish ?? true))
@@ -382,6 +392,7 @@ class="rounded-lg bg-indigo-800/80 px-3 py-1 text-xs font-medium text-indigo-100 hover:bg-indigo-800">Decline
+ @endif
@@ -438,8 +449,9 @@ title="React"> @include('meet.room.partials.meet-icon', ['icon' => 'react']) + @if ($isSpace ?? false) @if ($participant->isHost()) @endif + @else + @endif
+ @unless ($isSpace ?? false) - @unless ($isSpace ?? false) - @endunless + @endunless @if (($isSpace ?? false) && $participant->isHost())