- Guard Disconnected/ConnectionStateChanged event handlers against stale rooms: old room events no longer nuke the new room's state (root cause of buttons failing, mute getting stuck, DUPLICATE_IDENTITY cascades) - Reset media state (isMuted/isCameraOn/isScreenSharing) on connect to prevent desync after reconnects - Add voiceStates to WS ready payload so users see who's in voice on page load - Wire VoiceControls buttons to check getActiveRoom() before SDK calls - Guard ChannelSidebar against re-joining the same voice channel - Switch LIVEKIT_URL to wss://nova.ddns.net/livekit for HTTPS secure context (required for getUserMedia in Safari)
58 lines
2.2 KiB
JavaScript
58 lines
2.2 KiB
JavaScript
import { create } from 'zustand';
|
|
export const useVoiceStore = create((set, get) => ({
|
|
voiceUsers: new Map(),
|
|
currentVoiceChannelId: null,
|
|
isMuted: false,
|
|
isDeafened: false,
|
|
isCameraOn: false,
|
|
isScreenSharing: false,
|
|
participants: [],
|
|
connectionError: null,
|
|
isLiveKitConnected: false,
|
|
setVoiceUsers: (channelId, userIds) => {
|
|
set((state) => {
|
|
const newMap = new Map(state.voiceUsers);
|
|
newMap.set(channelId, userIds);
|
|
return { voiceUsers: newMap };
|
|
});
|
|
},
|
|
addVoiceUser: (channelId, userId) => {
|
|
set((state) => {
|
|
const newMap = new Map(state.voiceUsers);
|
|
const current = newMap.get(channelId) ?? [];
|
|
if (!current.includes(userId)) {
|
|
newMap.set(channelId, [...current, userId]);
|
|
}
|
|
return { voiceUsers: newMap };
|
|
});
|
|
},
|
|
removeVoiceUser: (channelId, userId) => {
|
|
set((state) => {
|
|
const newMap = new Map(state.voiceUsers);
|
|
const current = newMap.get(channelId) ?? [];
|
|
newMap.set(channelId, current.filter(id => id !== userId));
|
|
return { voiceUsers: newMap };
|
|
});
|
|
},
|
|
setCurrentVoiceChannel: (channelId) => set({ currentVoiceChannelId: channelId }),
|
|
setParticipants: (participants) => set({ participants }),
|
|
setConnectionError: (error) => set({ connectionError: error }),
|
|
setIsLiveKitConnected: (connected) => set({ isLiveKitConnected: connected }),
|
|
toggleMic: () => set((state) => ({ isMuted: !state.isMuted })),
|
|
toggleDeafen: () => set((state) => ({ isDeafened: !state.isDeafened })),
|
|
toggleCamera: () => set((state) => ({ isCameraOn: !state.isCameraOn })),
|
|
toggleScreenShare: () => set((state) => ({ isScreenSharing: !state.isScreenSharing })),
|
|
getVoiceUsers: (channelId) => get().voiceUsers.get(channelId) ?? [],
|
|
reset: () => set({
|
|
voiceUsers: new Map(),
|
|
currentVoiceChannelId: null,
|
|
isMuted: false,
|
|
isDeafened: false,
|
|
isCameraOn: false,
|
|
isScreenSharing: false,
|
|
participants: [],
|
|
connectionError: null,
|
|
isLiveKitConnected: false,
|
|
}),
|
|
}));
|