From d8c4f39bd3e65216e717804b0ea0e53fa49de184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96zt=C3=BCrk?= Date: Sat, 30 Aug 2025 23:30:09 +0300 Subject: [PATCH] =?UTF-8?q?Classroom=20SignalR=20ve=20WebRtc=20g=C3=BCvenl?= =?UTF-8?q?ik=20d=C3=BCzenlemesi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../classroom/panels/ParticipantsPanel.tsx | 60 +++++++++++-------- ui/src/views/classroom/RoomDetail.tsx | 43 ++++++++++++- 2 files changed, 75 insertions(+), 28 deletions(-) diff --git a/ui/src/components/classroom/panels/ParticipantsPanel.tsx b/ui/src/components/classroom/panels/ParticipantsPanel.tsx index e9b9efd7..5330477d 100644 --- a/ui/src/components/classroom/panels/ParticipantsPanel.tsx +++ b/ui/src/components/classroom/panels/ParticipantsPanel.tsx @@ -18,6 +18,8 @@ interface ParticipantsPanelProps { attendanceRecords: ClassroomAttendanceDto[] onMuteParticipant: (participantId: string, isMuted: boolean, isTeacher: boolean) => void onKickParticipant: (participantId: string) => void + onApproveHandRaise: (participantId: string) => void + onDismissHandRaise: (participantId: string) => void onClose: () => void formatTime: (timestamp: string) => string formatDuration: (minutes: number) => string @@ -30,11 +32,16 @@ const ParticipantsPanel: React.FC = ({ onMuteParticipant, onKickParticipant, onClose, + onApproveHandRaise, + onDismissHandRaise, formatTime, formatDuration, }) => { const [activeTab, setActiveTab] = useState<'participants' | 'attendance'>('participants') + // El kaldıranları bul + const handRaised = participants.filter((p) => p.isHandRaised) + return (
{/* Header */} @@ -48,6 +55,19 @@ const ParticipantsPanel: React.FC = ({
+ {/* El kaldıranlar göstergesi */} + {user.role === 'teacher' && handRaised.length > 0 && ( +
+ + + {handRaised.length} kişi el kaldırdı: + + + {handRaised.map((p) => p.name).join(', ')} + +
+ )} + {/* Tab Navigation */}
{participant.name} - {/* Hand Raise Indicator */} - {participant.isHandRaised && ( - - )} + {/* Hand Raise Indicator & Teacher Control */} + {participant.isHandRaised && ( + user.role === 'teacher' && !participant.isTeacher ? ( + + ) : ( + + ) + )}
- {/* Hand Raise Controls (Teacher Only) */} - {user.role === 'teacher' && - !participant.isTeacher && - participant.isHandRaised && ( - <> - - - - )} + {/* Hand Raise Controls kaldırıldı, kontrol yukarıya taşındı */} {/* Mute / Unmute Button */} {user.role === 'teacher' && !participant.isTeacher && ( diff --git a/ui/src/views/classroom/RoomDetail.tsx b/ui/src/views/classroom/RoomDetail.tsx index 111824fc..94bdf2a5 100644 --- a/ui/src/views/classroom/RoomDetail.tsx +++ b/ui/src/views/classroom/RoomDetail.tsx @@ -83,6 +83,20 @@ const newClassSession: ClassroomDto = { } const RoomDetail: React.FC = () => { + // El kaldırma onayla/iptal fonksiyonları en başta tanımlanmalı + // (props olarak kullanılmadan önce) + const handleApproveHandRaise = async (participantId: string) => { + if (signalRServiceRef.current && user.role === 'teacher') { + await signalRServiceRef.current.approveHandRaise(classSession.id, participantId) + } + } + + const handleDismissHandRaise = async (participantId: string) => { + if (signalRServiceRef.current && user.role === 'teacher') { + await signalRServiceRef.current.dismissHandRaise(classSession.id, participantId) + } + } + const params = useParams() const navigate = useNavigate() const { user } = useStoreState((state) => state.auth) @@ -119,7 +133,7 @@ const RoomDetail: React.FC = () => { const [selectedRecipient, setSelectedRecipient] = useState<{ id: string; name: string } | null>( null, ) - const [dragOver, setDragOver] = useState(false) + const raisedHandsCount = participants.filter((p) => p.isHandRaised).length const fileInputRef = useRef(null) const messagesEndRef = useRef(null) const [classSettings, setClassSettings] = useState({ @@ -298,7 +312,7 @@ const RoomDetail: React.FC = () => { } // ✅ öğretmen ise her zaman offer başlatır - if (isTeacher || (isActive && user.id < userId)) { + if (isActive && user.id < userId) { const offer = await webRTCServiceRef.current!.createOffer(userId) await signalRServiceRef.current?.sendOffer(classSession.id, userId, offer) } @@ -724,6 +738,9 @@ const RoomDetail: React.FC = () => { return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] } + // ...existing code... + // ...existing code... + // --- yan panel fonksiyonu --- const renderSidePanel = () => { if (!activeSidePanel) return null @@ -754,12 +771,15 @@ const RoomDetail: React.FC = () => { attendanceRecords={attendanceRecords} onMuteParticipant={handleMuteParticipant} onKickParticipant={handleKickParticipant} + onApproveHandRaise={handleApproveHandRaise} + onDismissHandRaise={handleDismissHandRaise} onClose={() => setActiveSidePanel(null)} formatTime={formatTime} formatDuration={formatDuration} /> ) + // ...existing code... case 'documents': return ( { }} className={`flex items-center space-x-2 p-3 rounded-lg transition-all text-base ${activeSidePanel === 'participants' ? 'bg-blue-100 text-blue-700' : 'hover:bg-gray-100 text-gray-700'}`} > - Katılımcılar + + Katılımcılar + + {participants.length} + + {raisedHandsCount > 0 && ( + + {raisedHandsCount > 9 ? '9+' : raisedHandsCount} + + )} {/* Teacher Only Options */}