diff --git a/api/src/Kurs.Platform.HttpApi.Host/Classroom/ClassroomHub.cs b/api/src/Kurs.Platform.HttpApi.Host/Classroom/ClassroomHub.cs index 486751dc..3a9bc5f4 100644 --- a/api/src/Kurs.Platform.HttpApi.Host/Classroom/ClassroomHub.cs +++ b/api/src/Kurs.Platform.HttpApi.Host/Classroom/ClassroomHub.cs @@ -83,6 +83,7 @@ public class ClassroomHub : Hub else { participant.UpdateConnectionId(Context.ConnectionId); + participant.IsActive = isActive; // Aktiflik durumunu güncelle await _participantRepository.UpdateAsync(participant, autoSave: true); } @@ -98,7 +99,6 @@ public class ClassroomHub : Hub await Groups.AddToGroupAsync(Context.ConnectionId, sessionId.ToString()); - // 🔑 Yeni katılana mevcut katılımcıları gönder // 🔑 Yeni katılana mevcut aktif katılımcıları gönder var existingParticipants = await _participantRepository.GetListAsync( x => x.SessionId == sessionId && x.IsActive @@ -119,7 +119,7 @@ public class ClassroomHub : Hub // 🔑 Grup üyelerine yeni katılanı öğretmen bilgisiyle bildir await Clients.Group(sessionId.ToString()) - .SendAsync("ParticipantJoined", userId, userName, isTeacher, true); + .SendAsync("ParticipantJoined", userId, userName, isTeacher, isActive); } [HubMethodName("LeaveClass")] @@ -369,6 +369,18 @@ public class ClassroomHub : Hub }); } + // 🔑 Participant’i pasife al + var participant = await _participantRepository.FirstOrDefaultAsync( + x => x.SessionId == sessionId && x.UserId == participantId + ); + if (participant != null) + { + participant.IsActive = false; + await _participantRepository.UpdateAsync(participant, autoSave: true); + } + + _logger.LogInformation("👢 Participant {ParticipantId} kicked from session {SessionId}", participantId, sessionId); + // Katılımcı çıkışını bildir await Clients.Group(sessionId.ToString()).SendAsync("ParticipantLeft", participantId); } @@ -476,6 +488,9 @@ public class ClassroomHub : Hub }); } + participant.IsActive = false; + await _participantRepository.UpdateAsync(participant, autoSave: true); + // 🔑 3. ParticipantLeft event’i await Clients.Group(participant.SessionId.ToString()) .SendAsync("ParticipantLeft", userId.Value); diff --git a/ui/src/views/classroom/RoomDetail.tsx b/ui/src/views/classroom/RoomDetail.tsx index 078116b8..568a3aa9 100644 --- a/ui/src/views/classroom/RoomDetail.tsx +++ b/ui/src/views/classroom/RoomDetail.tsx @@ -282,13 +282,16 @@ const RoomDetail: React.FC = () => { } // ✅ güncel listedeki öğretmen kontrolü - const teacherExists = updated.some((p) => p.isTeacher) + const teacherExists = updated.some((p) => p.isTeacher && p.isActive) + if (teacherExists) { ;(async () => { if (!webRTCServiceRef.current?.getPeerConnection(userId)) { await webRTCServiceRef.current?.createPeerConnection(userId) } - if (user.id < userId) { + + // sadece aktif katılımcılara offer başlat + if (isActive && user.id < userId) { const offer = await webRTCServiceRef.current!.createOffer(userId) await signalRServiceRef.current?.sendOffer(classSession.id, userId, offer) } @@ -324,7 +327,8 @@ const RoomDetail: React.FC = () => { } // ✅ güncel listede öğretmen var mı? - const teacherExists = updated.some((p) => p.isTeacher) + const teacherExists = updated.some((p) => p.isTeacher && p.isActive) + if (teacherExists) { ;(async () => { for (const participant of existing) { @@ -404,7 +408,7 @@ const RoomDetail: React.FC = () => { user.id, user.name, user.role === 'teacher', - true + true, ) } catch (error) { console.error('Failed to initialize services:', error) @@ -647,7 +651,7 @@ const RoomDetail: React.FC = () => { studentId, randomName, false, // öğrenci - true // aktif + true, // aktif ) }