|
24 | 24 | email?: string; // Add email for stable identification |
25 | 25 | } |
26 | 26 |
|
| 27 | + // Interface for room state |
| 28 | + interface RoomState { |
| 29 | + hostId: string | null; |
| 30 | + creationTime: number; |
| 31 | + } |
| 32 | +
|
27 | 33 | let roomId = page.params.roomId; |
28 | 34 | let isCompetitionActive = $state(false); |
29 | 35 | let participants = $state<Participant[]>([]); |
30 | 36 | let error = $state<string | null>(null); |
31 | 37 | let loading = $state(true); |
32 | 38 | let creatorId = $state<string | null>(null); |
33 | 39 | let roomCreationTime = $state<number>(Date.now()); // Track room creation time |
| 40 | + let roomState = $state<RoomState>({ hostId: null, creationTime: Date.now() }); |
34 | 41 |
|
35 | 42 | // Agora related variables - only need client and tracks |
36 | 43 | let agoraClient = $state<IAgoraRTCClient | null>(null); |
|
183 | 190 | console.log(`[AGORA] Removed user ${user.uid} from remoteUsers`); |
184 | 191 | } |
185 | 192 |
|
| 193 | + // Check if the host left |
| 194 | + const userIdStr = user.uid.toString(); |
| 195 | + const wasHost = participants.find((p) => p.userId === userIdStr && p.isHost); |
| 196 | +
|
186 | 197 | // Remove from participants |
187 | | - participants = participants.filter((p) => p.userId !== user.uid.toString()); |
| 198 | + participants = participants.filter((p) => p.userId !== userIdStr); |
188 | 199 | console.log( |
189 | 200 | `[AGORA] Removed user ${user.uid} from participants, remaining: ${participants.length}` |
190 | 201 | ); |
191 | 202 |
|
| 203 | + // If the host left, assign a new host |
| 204 | + if (wasHost && participants.length > 0) { |
| 205 | + // Select the participant who has been in the room the longest |
| 206 | + const oldestParticipant = participants[0]; |
| 207 | + oldestParticipant.isHost = true; |
| 208 | + roomState.hostId = oldestParticipant.userId; |
| 209 | +
|
| 210 | + // Update participants to trigger reactivity |
| 211 | + participants = [...participants]; |
| 212 | + console.log(`[AGORA] Host left, assigned ${oldestParticipant.name} as new host`); |
| 213 | + } |
| 214 | +
|
192 | 215 | updateRankings(); |
193 | 216 | }); |
194 | 217 |
|
|
252 | 275 | } |
253 | 276 | }); |
254 | 277 |
|
255 | | - // Determine host - first joiner or based on email if authentication is used |
256 | | - let isCurrentUserHost = false; |
| 278 | + // Improved host determination logic |
| 279 | + let shouldBeHost = false; |
257 | 280 | const userEmail = $session.data?.user?.email; |
258 | 281 |
|
259 | | - if (remoteUsersList.length === 0) { |
260 | | - // First user to join becomes host |
261 | | - isCurrentUserHost = true; |
262 | | - console.log(`[AGORA] No other users found, setting self as host`); |
263 | | - } else { |
264 | | - // Check participants to see if there's already a host |
265 | | - const existingHost = participants.find(p => p.isHost); |
266 | | -
|
267 | | - // If no host is set yet, the first authenticated user becomes host |
268 | | - if (!existingHost && userEmail) { |
269 | | - isCurrentUserHost = true; |
270 | | - console.log(`[AGORA] No host exists yet, setting authenticated user as host`); |
| 282 | + // Get existing host if any |
| 283 | + const existingHost = participants.find((p) => p.isHost); |
| 284 | +
|
| 285 | + if (!existingHost) { |
| 286 | + // No existing host found |
| 287 | + if (remoteUsersList.length === 0) { |
| 288 | + // First user in the room becomes host |
| 289 | + shouldBeHost = true; |
| 290 | + roomState.hostId = uid.toString(); |
| 291 | + roomState.creationTime = Date.now(); |
| 292 | + console.log(`[AGORA] First user in room, becoming host`); |
| 293 | + } else { |
| 294 | + // There are other users but no host yet (possible during initialization) |
| 295 | + // Wait a moment to check if any other user is claiming host status |
| 296 | + shouldBeHost = false; |
| 297 | + console.log(`[AGORA] Other users present but no host, waiting to determine host`); |
| 298 | +
|
| 299 | + // We'll check again after a delay to see if a host appeared |
| 300 | + setTimeout(() => { |
| 301 | + const delayedHostCheck = participants.find((p) => p.isHost); |
| 302 | + if (!delayedHostCheck && participants.length > 0) { |
| 303 | + // Still no host, make the first participant the host |
| 304 | + const firstParticipant = participants[0]; |
| 305 | + firstParticipant.isHost = true; |
| 306 | + roomState.hostId = firstParticipant.userId; |
| 307 | + participants = [...participants]; // Trigger reactivity |
| 308 | + console.log(`[AGORA] Assigned ${firstParticipant.name} as host after delay`); |
| 309 | + } |
| 310 | + }, 3000); |
271 | 311 | } |
| 312 | + } else { |
| 313 | + // Host already exists, respect that |
| 314 | + console.log(`[AGORA] Host already exists: ${existingHost.name}`); |
| 315 | + roomState.hostId = existingHost.userId; |
272 | 316 | } |
273 | 317 |
|
274 | 318 | // Add current user to participants |
275 | 319 | const userName = $session.data?.user?.name || `You (${uid})`; |
276 | 320 | participants = [ |
277 | | - ...participants |
278 | | - .filter((p) => p.userId !== uid.toString()) |
279 | | - .map((p) => ({ ...p })), |
| 321 | + ...participants.filter((p) => p.userId !== uid.toString()).map((p) => ({ ...p })), |
280 | 322 | { |
281 | 323 | userId: uid.toString(), |
282 | 324 | name: userName, |
283 | 325 | image: $session.data?.user?.image ?? undefined, |
284 | 326 | email: userEmail, |
285 | | - isHost: isCurrentUserHost |
| 327 | + isHost: shouldBeHost |
286 | 328 | } |
287 | 329 | ]; |
288 | 330 |
|
|
483 | 525 | // Determine if current user is host |
484 | 526 | let isHost = $derived(() => { |
485 | 527 | const currentUserId = agoraClient?.uid?.toString(); |
486 | | - const currentUserParticipant = participants.find(p => p.userId === currentUserId); |
487 | | - return !!currentUserParticipant?.isHost; |
| 528 | + // Check both the participant list and roomState to determine host status |
| 529 | + const isHostInParticipants = participants.some((p) => p.userId === currentUserId && p.isHost); |
| 530 | + const isHostInState = roomState.hostId === currentUserId; |
| 531 | + return isHostInParticipants || isHostInState; |
488 | 532 | }); |
489 | 533 | </script> |
490 | 534 |
|
|
0 commit comments