HandRaise kısımları ayrı bir tab üzerinden yönetilmiyor
This commit is contained in:
parent
df415dd04d
commit
823ee98384
4 changed files with 80 additions and 149 deletions
|
|
@ -327,7 +327,7 @@ public class ClassroomHub : Hub
|
||||||
}
|
}
|
||||||
|
|
||||||
[HubMethodName("ApproveHandRaise")]
|
[HubMethodName("ApproveHandRaise")]
|
||||||
public async Task ApproveHandRaiseAsync(Guid sessionId, Guid handRaiseId, Guid studentId)
|
public async Task ApproveHandRaiseAsync(Guid sessionId, Guid studentId)
|
||||||
{
|
{
|
||||||
// 🔑 Öğrencinin parmak kaldırma durumunu sıfırla
|
// 🔑 Öğrencinin parmak kaldırma durumunu sıfırla
|
||||||
var participant = await _participantRepository.FirstOrDefaultAsync(
|
var participant = await _participantRepository.FirstOrDefaultAsync(
|
||||||
|
|
@ -340,11 +340,11 @@ public class ClassroomHub : Hub
|
||||||
await _participantRepository.UpdateAsync(participant, autoSave: true);
|
await _participantRepository.UpdateAsync(participant, autoSave: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Clients.Group(sessionId.ToString()).SendAsync("HandRaiseDismissed", handRaiseId);
|
await Clients.Group(sessionId.ToString()).SendAsync("HandRaiseDismissed", new { studentId });
|
||||||
}
|
}
|
||||||
|
|
||||||
[HubMethodName("DismissHandRaise")]
|
[HubMethodName("DismissHandRaise")]
|
||||||
public async Task DismissHandRaiseAsync(Guid sessionId, Guid handRaiseId, Guid studentId)
|
public async Task DismissHandRaiseAsync(Guid sessionId, Guid studentId)
|
||||||
{
|
{
|
||||||
// 🔑 Participant'ı bul ve elini indir
|
// 🔑 Participant'ı bul ve elini indir
|
||||||
var participant = await _participantRepository.FirstOrDefaultAsync(
|
var participant = await _participantRepository.FirstOrDefaultAsync(
|
||||||
|
|
@ -357,7 +357,7 @@ public class ClassroomHub : Hub
|
||||||
await _participantRepository.UpdateAsync(participant, autoSave: true);
|
await _participantRepository.UpdateAsync(participant, autoSave: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Clients.Group(sessionId.ToString()).SendAsync("HandRaiseDismissed", handRaiseId);
|
await Clients.Group(sessionId.ToString()).SendAsync("HandRaiseDismissed", new { studentId });
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnDisconnectedAsync(Exception exception)
|
public override async Task OnDisconnectedAsync(Exception exception)
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ export interface ClassroomParticipantDto {
|
||||||
isObserver?: boolean
|
isObserver?: boolean
|
||||||
isAudioMuted?: boolean
|
isAudioMuted?: boolean
|
||||||
isVideoMuted?: boolean
|
isVideoMuted?: boolean
|
||||||
|
isHandRaised?: boolean
|
||||||
stream?: MediaStream
|
stream?: MediaStream
|
||||||
screenStream?: MediaStream
|
screenStream?: MediaStream
|
||||||
isScreenSharing?: boolean
|
isScreenSharing?: boolean
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ export class SignalRService {
|
||||||
private onParticipantLeft?: (userId: string) => void
|
private onParticipantLeft?: (userId: string) => void
|
||||||
private onChatMessage?: (message: ClassroomChatDto) => void
|
private onChatMessage?: (message: ClassroomChatDto) => void
|
||||||
private onParticipantMuted?: (userId: string, isMuted: boolean) => void
|
private onParticipantMuted?: (userId: string, isMuted: boolean) => void
|
||||||
private onHandRaiseReceived?: (handRaise: HandRaiseDto) => void
|
private onHandRaiseReceived?: (studentId: string) => void
|
||||||
private onHandRaiseDismissed?: (handRaiseId: string) => void
|
private onHandRaiseDismissed?: (studentId: string) => void
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const { auth } = store.getState()
|
const { auth } = store.getState()
|
||||||
|
|
@ -52,12 +52,14 @@ export class SignalRService {
|
||||||
this.onParticipantMuted?.(userId, isMuted)
|
this.onParticipantMuted?.(userId, isMuted)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.connection.on('HandRaiseReceived', (handRaise: HandRaiseDto) => {
|
this.connection.on('HandRaiseReceived', (payload: any) => {
|
||||||
this.onHandRaiseReceived?.(handRaise)
|
// payload = { handRaiseId, studentId, studentName, ... }
|
||||||
|
this.onHandRaiseReceived?.(payload.studentId)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.connection.on('HandRaiseDismissed', (handRaiseId: string) => {
|
this.connection.on('HandRaiseDismissed', (payload: any) => {
|
||||||
this.onHandRaiseDismissed?.(handRaiseId)
|
// payload = { handRaiseId, studentId }
|
||||||
|
this.onHandRaiseDismissed?.(payload.studentId)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.connection.onreconnected(() => {
|
this.connection.onreconnected(() => {
|
||||||
|
|
@ -135,6 +137,7 @@ export class SignalRService {
|
||||||
console.log('Error starting SignalR connection simulating chat message from', senderName)
|
console.log('Error starting SignalR connection simulating chat message from', senderName)
|
||||||
const chatMessage: ClassroomChatDto = {
|
const chatMessage: ClassroomChatDto = {
|
||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
|
sessionId,
|
||||||
senderId,
|
senderId,
|
||||||
senderName,
|
senderName,
|
||||||
message,
|
message,
|
||||||
|
|
@ -181,6 +184,7 @@ export class SignalRService {
|
||||||
)
|
)
|
||||||
const chatMessage: ClassroomChatDto = {
|
const chatMessage: ClassroomChatDto = {
|
||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
|
sessionId,
|
||||||
senderId,
|
senderId,
|
||||||
senderName,
|
senderName,
|
||||||
message,
|
message,
|
||||||
|
|
@ -224,6 +228,7 @@ export class SignalRService {
|
||||||
console.log('Error starting SignalR connection simulating announcement from', senderName)
|
console.log('Error starting SignalR connection simulating announcement from', senderName)
|
||||||
const chatMessage: ClassroomChatDto = {
|
const chatMessage: ClassroomChatDto = {
|
||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
|
sessionId,
|
||||||
senderId,
|
senderId,
|
||||||
senderName,
|
senderName,
|
||||||
message,
|
message,
|
||||||
|
|
@ -285,7 +290,7 @@ export class SignalRService {
|
||||||
isActive: true,
|
isActive: true,
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.onHandRaiseReceived?.(handRaise)
|
this.onHandRaiseReceived?.(studentId)
|
||||||
}, 100)
|
}, 100)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -313,33 +318,33 @@ export class SignalRService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async approveHandRaise(sessionId: string, handRaiseId: string): Promise<void> {
|
async approveHandRaise(sessionId: string, studentId: string): Promise<void> {
|
||||||
if (!this.isConnected) {
|
if (!this.isConnected) {
|
||||||
console.log('Error starting SignalR connection simulating hand raise approval')
|
console.log('Simulating hand raise approval for student', studentId)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.onHandRaiseDismissed?.(handRaiseId)
|
this.onHandRaiseDismissed?.(studentId)
|
||||||
}, 100)
|
}, 100)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.connection.invoke('ApproveHandRaise', sessionId, handRaiseId)
|
await this.connection.invoke('ApproveHandRaise', sessionId, studentId)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error approving hand raise:', error)
|
console.error('Error approving hand raise:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async dismissHandRaise(sessionId: string, handRaiseId: string): Promise<void> {
|
async dismissHandRaise(sessionId: string, studentId: string): Promise<void> {
|
||||||
if (!this.isConnected) {
|
if (!this.isConnected) {
|
||||||
console.log('Error starting SignalR connection simulating hand raise dismissal')
|
console.log('Simulating hand raise dismissal for student', studentId)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.onHandRaiseDismissed?.(handRaiseId)
|
this.onHandRaiseDismissed?.(studentId)
|
||||||
}, 100)
|
}, 100)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.connection.invoke('DismissHandRaise', sessionId, handRaiseId)
|
await this.connection.invoke('DismissHandRaise', sessionId, studentId)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error dismissing hand raise:', error)
|
console.error('Error dismissing hand raise:', error)
|
||||||
}
|
}
|
||||||
|
|
@ -365,11 +370,11 @@ export class SignalRService {
|
||||||
this.onParticipantMuted = callback
|
this.onParticipantMuted = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
setHandRaiseReceivedHandler(callback: (handRaise: HandRaiseDto) => void) {
|
setHandRaiseReceivedHandler(callback: (studentId: string) => void) {
|
||||||
this.onHandRaiseReceived = callback
|
this.onHandRaiseReceived = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
setHandRaiseDismissedHandler(callback: (handRaiseId: string) => void) {
|
setHandRaiseDismissedHandler(callback: (studentId: string) => void) {
|
||||||
this.onHandRaiseDismissed = callback
|
this.onHandRaiseDismissed = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import {
|
||||||
FaClipboardList,
|
FaClipboardList,
|
||||||
FaLayerGroup,
|
FaLayerGroup,
|
||||||
FaWrench,
|
FaWrench,
|
||||||
FaCheck,
|
|
||||||
FaUserTimes,
|
FaUserTimes,
|
||||||
FaDownload,
|
FaDownload,
|
||||||
FaTrash,
|
FaTrash,
|
||||||
|
|
@ -35,6 +34,7 @@ import {
|
||||||
FaBullhorn,
|
FaBullhorn,
|
||||||
FaUser,
|
FaUser,
|
||||||
FaBars,
|
FaBars,
|
||||||
|
FaCheck,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import { SignalRService } from '@/services/classroom/signalr'
|
import { SignalRService } from '@/services/classroom/signalr'
|
||||||
import { WebRTCService } from '@/services/classroom/webrtc'
|
import { WebRTCService } from '@/services/classroom/webrtc'
|
||||||
|
|
@ -45,7 +45,6 @@ import {
|
||||||
ClassroomParticipantDto,
|
ClassroomParticipantDto,
|
||||||
ClassroomDto,
|
ClassroomDto,
|
||||||
ClassroomSettingsDto,
|
ClassroomSettingsDto,
|
||||||
HandRaiseDto,
|
|
||||||
VideoLayoutDto,
|
VideoLayoutDto,
|
||||||
} from '@/proxy/classroom/models'
|
} from '@/proxy/classroom/models'
|
||||||
import { useStoreState } from '@/store/store'
|
import { useStoreState } from '@/store/store'
|
||||||
|
|
@ -108,7 +107,6 @@ const RoomDetail: React.FC = () => {
|
||||||
description: 'Tüm katılımcılar eşit boyutta görünür',
|
description: 'Tüm katılımcılar eşit boyutta görünür',
|
||||||
})
|
})
|
||||||
const [focusedParticipant, setFocusedParticipant] = useState<string>()
|
const [focusedParticipant, setFocusedParticipant] = useState<string>()
|
||||||
const [handRaises, setHandRaises] = useState<HandRaiseDto[]>([])
|
|
||||||
const [hasRaisedHand, setHasRaisedHand] = useState(false)
|
const [hasRaisedHand, setHasRaisedHand] = useState(false)
|
||||||
const [isAllMuted, setIsAllMuted] = useState(false)
|
const [isAllMuted, setIsAllMuted] = useState(false)
|
||||||
const [kickingParticipant, setKickingParticipant] = useState<{ id: string; name: string } | null>(
|
const [kickingParticipant, setKickingParticipant] = useState<{ id: string; name: string } | null>(
|
||||||
|
|
@ -301,14 +299,21 @@ const RoomDetail: React.FC = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Hand raise events
|
// Hand raise events
|
||||||
signalRServiceRef.current.setHandRaiseReceivedHandler?.((handRaise) => {
|
signalRServiceRef.current.setHandRaiseReceivedHandler((studentId) => {
|
||||||
setHandRaises((prev) => [...prev, handRaise])
|
setParticipants((prev) =>
|
||||||
|
prev.map((p) => (p.id === studentId ? { ...p, isHandRaised: true } : p)),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
signalRServiceRef.current.setHandRaiseDismissedHandler?.((handRaiseId) => {
|
signalRServiceRef.current.setHandRaiseDismissedHandler((studentId) => {
|
||||||
setHandRaises((prev) =>
|
setParticipants((prev) =>
|
||||||
prev.map((hr) => (hr.id === handRaiseId ? { ...hr, isActive: false } : hr)),
|
prev.map((p) => (p.id === studentId ? { ...p, isHandRaised: false } : p)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 👇 kendi state’ini de sıfırla
|
||||||
|
if (studentId === user.id) {
|
||||||
|
setHasRaisedHand(false)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Join the class
|
// Join the class
|
||||||
|
|
@ -440,24 +445,6 @@ const RoomDetail: React.FC = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleApproveHandRaise = async (handRaiseId: string) => {
|
|
||||||
if (signalRServiceRef.current && user.role === 'teacher') {
|
|
||||||
await signalRServiceRef.current.approveHandRaise(classSession.id, handRaiseId)
|
|
||||||
setHandRaises((prev) =>
|
|
||||||
prev.map((hr) => (hr.id === handRaiseId ? { ...hr, isActive: false } : hr)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleDismissHandRaise = async (handRaiseId: string) => {
|
|
||||||
if (signalRServiceRef.current && user.role === 'teacher') {
|
|
||||||
await signalRServiceRef.current.dismissHandRaise(classSession.id, handRaiseId)
|
|
||||||
setHandRaises((prev) =>
|
|
||||||
prev.map((hr) => (hr.id === handRaiseId ? { ...hr, isActive: false } : hr)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleKickParticipant = async (participantId: string) => {
|
const handleKickParticipant = async (participantId: string) => {
|
||||||
if (signalRServiceRef.current && user.role === 'teacher') {
|
if (signalRServiceRef.current && user.role === 'teacher') {
|
||||||
await signalRServiceRef.current.kickParticipant(classSession.id, participantId)
|
await signalRServiceRef.current.kickParticipant(classSession.id, participantId)
|
||||||
|
|
@ -995,8 +982,48 @@ const RoomDetail: React.FC = () => {
|
||||||
>
|
>
|
||||||
{participant.name}
|
{participant.name}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
{/* 👋 Parmak kaldırma göstergesi */}
|
||||||
|
{participant.isHandRaised && (
|
||||||
|
<FaHandPaper
|
||||||
|
className="text-yellow-600 ml-2"
|
||||||
|
title="Parmak kaldırdı"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-1">
|
<div className="flex items-center space-x-1">
|
||||||
|
{/* 🎓 Öğretmen için el kaldırma kontrolü */}
|
||||||
|
{user.role === 'teacher' &&
|
||||||
|
!participant.isTeacher &&
|
||||||
|
participant.isHandRaised && (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
signalRServiceRef.current?.approveHandRaise(
|
||||||
|
classSession.id,
|
||||||
|
participant.id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className="p-1 text-green-600 hover:bg-green-50 rounded transition-colors"
|
||||||
|
title="El kaldırmayı onayla"
|
||||||
|
>
|
||||||
|
<FaCheck size={12} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
signalRServiceRef.current?.dismissHandRaise(
|
||||||
|
classSession.id,
|
||||||
|
participant.id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className="p-1 text-red-600 hover:bg-red-50 rounded transition-colors"
|
||||||
|
title="El kaldırmayı reddet"
|
||||||
|
>
|
||||||
|
<FaTimes size={12} />
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Ses aç/kapat butonu */}
|
{/* Ses aç/kapat butonu */}
|
||||||
{user.role === 'teacher' && !participant.isTeacher && (
|
{user.role === 'teacher' && !participant.isTeacher && (
|
||||||
<button
|
<button
|
||||||
|
|
@ -1195,76 +1222,6 @@ const RoomDetail: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
case 'handraises': {
|
|
||||||
const activeHandRaises = handRaises.filter((hr) => hr.isActive)
|
|
||||||
return (
|
|
||||||
<div className="h-full bg-white flex flex-col">
|
|
||||||
<div className="p-4 border-b border-gray-200">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<h3 className="text-lg font-semibold text-gray-900">
|
|
||||||
Parmak Kaldıranlar ({activeHandRaises.length})
|
|
||||||
</h3>
|
|
||||||
<button onClick={() => setActiveSidePanel(null)}>
|
|
||||||
<FaTimes className="text-gray-500" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex-1 overflow-y-auto p-4">
|
|
||||||
{activeHandRaises.length === 0 ? (
|
|
||||||
<div className="text-center py-8 text-gray-500">
|
|
||||||
<FaHandPaper size={32} className="mx-auto mb-4 text-gray-300" />
|
|
||||||
<p className="text-sm text-gray-600">
|
|
||||||
Şu anda parmak kaldıran öğrenci bulunmamaktadır.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="space-y-3">
|
|
||||||
{activeHandRaises.map((handRaise) => (
|
|
||||||
<div
|
|
||||||
key={handRaise.id}
|
|
||||||
className="flex items-center justify-between p-3 bg-yellow-50 border border-yellow-200 rounded-lg"
|
|
||||||
>
|
|
||||||
<div className="flex items-center space-x-3">
|
|
||||||
<FaHandPaper className="text-yellow-600" size={16} />
|
|
||||||
<div>
|
|
||||||
<h4 className="font-medium text-gray-800 text-sm">
|
|
||||||
{handRaise.studentName}
|
|
||||||
</h4>
|
|
||||||
<p className="text-xs text-gray-600">
|
|
||||||
{formatTime(handRaise.timestamp)} •{' '}
|
|
||||||
{getTimeSince(handRaise.timestamp)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{user.role === 'teacher' && (
|
|
||||||
<div className="flex space-x-1">
|
|
||||||
<button
|
|
||||||
onClick={() => handleApproveHandRaise(handRaise.id)}
|
|
||||||
className="flex items-center space-x-1 px-2 py-1 bg-green-600 text-white rounded text-xs hover:bg-green-700 transition-colors"
|
|
||||||
>
|
|
||||||
<FaCheck size={10} />
|
|
||||||
<span>Onayla</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => handleDismissHandRaise(handRaise.id)}
|
|
||||||
className="flex items-center space-x-1 px-2 py-1 bg-red-600 text-white rounded text-xs hover:bg-red-700 transition-colors"
|
|
||||||
>
|
|
||||||
<FaTimes size={10} />
|
|
||||||
<span>Reddet</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'layout':
|
case 'layout':
|
||||||
return (
|
return (
|
||||||
<div className="h-full bg-white flex flex-col text-gray-900">
|
<div className="h-full bg-white flex flex-col text-gray-900">
|
||||||
|
|
@ -1744,20 +1701,6 @@ const RoomDetail: React.FC = () => {
|
||||||
>
|
>
|
||||||
<FaFile /> <span>Dokümanlar</span>
|
<FaFile /> <span>Dokümanlar</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
setMobileMenuOpen(false)
|
|
||||||
setTimeout(() => toggleSidePanel('handraises'), 200)
|
|
||||||
}}
|
|
||||||
className={`flex items-center space-x-2 p-3 rounded-lg transition-all text-base ${activeSidePanel === 'handraises' ? 'bg-blue-100 text-blue-700' : 'hover:bg-gray-100 text-gray-700'}`}
|
|
||||||
>
|
|
||||||
<FaHandPaper /> <span>Parmak Kaldıranlar</span>
|
|
||||||
{handRaises.filter((hr) => hr.isActive).length > 0 && (
|
|
||||||
<span className="ml-auto bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center">
|
|
||||||
{handRaises.filter((hr) => hr.isActive).length}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setMobileMenuOpen(false)
|
setMobileMenuOpen(false)
|
||||||
|
|
@ -1984,24 +1927,6 @@ const RoomDetail: React.FC = () => {
|
||||||
<FaFile size={14} />
|
<FaFile size={14} />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Hand Raises Button */}
|
|
||||||
<button
|
|
||||||
onClick={() => toggleSidePanel('handraises')}
|
|
||||||
className={`p-2 rounded-lg transition-all relative ${
|
|
||||||
activeSidePanel === 'handraises'
|
|
||||||
? 'bg-blue-600 text-white'
|
|
||||||
: 'bg-gray-700 hover:bg-gray-600 text-white'
|
|
||||||
}`}
|
|
||||||
title="Parmak Kaldıranlar"
|
|
||||||
>
|
|
||||||
<FaHandPaper size={14} />
|
|
||||||
{handRaises.filter((hr) => hr.isActive).length > 0 && (
|
|
||||||
<span className="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-4 h-4 flex items-center justify-center text-[10px]">
|
|
||||||
{handRaises.filter((hr) => hr.isActive).length}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{/* Mute All Button */}
|
{/* Mute All Button */}
|
||||||
<button
|
<button
|
||||||
onClick={handleMuteAll}
|
onClick={handleMuteAll}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue