Classroom Çıkan kişinin adını yazdık
This commit is contained in:
parent
9db84f137e
commit
0d2e3f715c
4 changed files with 65 additions and 54 deletions
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { FaUserTimes, FaExclamationTriangle } from 'react-icons/fa';
|
||||
import React from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import { FaUserTimes, FaExclamationTriangle } from 'react-icons/fa'
|
||||
|
||||
interface KickParticipantModalProps {
|
||||
participant: { id: string; name: string } | null;
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onConfirm: (participantId: string) => void;
|
||||
participant: { id: string; name: string } | null
|
||||
isOpen: boolean
|
||||
onClose: () => void
|
||||
onConfirm: (participantId: string, participantName: string) => void
|
||||
}
|
||||
|
||||
export const KickParticipantModal: React.FC<KickParticipantModalProps> = ({
|
||||
|
|
@ -15,12 +15,12 @@ export const KickParticipantModal: React.FC<KickParticipantModalProps> = ({
|
|||
onClose,
|
||||
onConfirm,
|
||||
}) => {
|
||||
if (!isOpen || !participant) return null;
|
||||
if (!isOpen || !participant) return null
|
||||
|
||||
const handleConfirm = () => {
|
||||
onConfirm(participant.id);
|
||||
onClose();
|
||||
};
|
||||
onConfirm(participant.id, participant.name)
|
||||
onClose()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
|
|
@ -39,10 +39,11 @@ export const KickParticipantModal: React.FC<KickParticipantModalProps> = ({
|
|||
<p className="text-sm text-gray-600">Bu işlem geri alınamaz</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="mb-6">
|
||||
<p className="text-gray-700 mb-2">
|
||||
<strong>"{participant.name}"</strong> adlı katılımcıyı sınıftan çıkarmak istediğinizden emin misiniz?
|
||||
<strong>"{participant.name}"</strong> adlı katılımcıyı sınıftan çıkarmak
|
||||
istediğinizden emin misiniz?
|
||||
</p>
|
||||
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-3">
|
||||
<div className="flex items-start">
|
||||
|
|
@ -58,7 +59,7 @@ export const KickParticipantModal: React.FC<KickParticipantModalProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="flex items-center justify-end space-x-4">
|
||||
<button
|
||||
onClick={onClose}
|
||||
|
|
@ -77,5 +78,5 @@ export const KickParticipantModal: React.FC<KickParticipantModalProps> = ({
|
|||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ interface ParticipantsPanelProps {
|
|||
participants: ClassroomParticipantDto[]
|
||||
attendanceRecords: ClassroomAttendanceDto[]
|
||||
onMuteParticipant: (participantId: string, isMuted: boolean, isTeacher: boolean) => void
|
||||
onKickParticipant: (participantId: string) => void
|
||||
onKickParticipant: (participantId: string, participantName: string) => void
|
||||
onApproveHandRaise: (participantId: string) => void
|
||||
onDismissHandRaise: (participantId: string) => void
|
||||
onClose: () => void
|
||||
|
|
@ -129,20 +129,19 @@ const ParticipantsPanel: React.FC<ParticipantsPanelProps> = ({
|
|||
</div>
|
||||
<span className="text-gray-900">{participant.name}</span>
|
||||
|
||||
{/* Hand Raise Indicator & Teacher Control */}
|
||||
{participant.isHandRaised && (
|
||||
user.role === 'teacher' && !participant.isTeacher ? (
|
||||
<button
|
||||
onClick={() => onDismissHandRaise(participant.id)}
|
||||
className="ml-2 p-1 rounded bg-yellow-100 hover:bg-yellow-200"
|
||||
title="El kaldırmayı kaldır"
|
||||
>
|
||||
<FaHandPaper className="text-yellow-600" />
|
||||
</button>
|
||||
) : (
|
||||
<FaHandPaper className="text-yellow-600 ml-2" title="Parmak kaldırdı" />
|
||||
)
|
||||
)}
|
||||
{/* Hand Raise Indicator & Teacher Control */}
|
||||
{participant.isHandRaised &&
|
||||
(user.role === 'teacher' && !participant.isTeacher ? (
|
||||
<button
|
||||
onClick={() => onDismissHandRaise(participant.id)}
|
||||
className="ml-2 p-1 rounded bg-yellow-100 hover:bg-yellow-200"
|
||||
title="El kaldırmayı kaldır"
|
||||
>
|
||||
<FaHandPaper className="text-yellow-600" />
|
||||
</button>
|
||||
) : (
|
||||
<FaHandPaper className="text-yellow-600 ml-2" title="Parmak kaldırdı" />
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-1">
|
||||
|
|
@ -177,7 +176,7 @@ const ParticipantsPanel: React.FC<ParticipantsPanelProps> = ({
|
|||
{/* Kick Button (Teacher Only) */}
|
||||
{user.role === 'teacher' && !participant.isTeacher && (
|
||||
<button
|
||||
onClick={() => onKickParticipant(participant.id)}
|
||||
onClick={() => onKickParticipant(participant.id, participant.name)}
|
||||
className="p-1 text-red-600 hover:bg-red-50 rounded transition-colors"
|
||||
title="Sınıftan Çıkar"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
import {
|
||||
ClassroomAttendanceDto,
|
||||
ClassroomChatDto,
|
||||
HandRaiseDto,
|
||||
} from '@/proxy/classroom/models'
|
||||
import { ClassroomAttendanceDto, ClassroomChatDto, HandRaiseDto } from '@/proxy/classroom/models'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import { store } from '@/store/store'
|
||||
import * as signalR from '@microsoft/signalr'
|
||||
|
|
@ -22,7 +18,11 @@ export class SignalRService {
|
|||
isTeacher: boolean,
|
||||
isActive: boolean,
|
||||
) => void
|
||||
private onParticipantLeft?: (payload: { userId: string; sessionId: string }) => void
|
||||
private onParticipantLeft?: (payload: {
|
||||
userId: string
|
||||
sessionId: string
|
||||
userName: string
|
||||
}) => void
|
||||
private onChatMessage?: (message: ClassroomChatDto) => void
|
||||
private onParticipantMuted?: (userId: string, isMuted: boolean) => void
|
||||
private onHandRaiseReceived?: (studentId: string) => void
|
||||
|
|
@ -59,9 +59,12 @@ export class SignalRService {
|
|||
},
|
||||
)
|
||||
|
||||
this.connection.on('ParticipantLeft', (payload: { userId: string; sessionId: string }) => {
|
||||
this.onParticipantLeft?.(payload)
|
||||
})
|
||||
this.connection.on(
|
||||
'ParticipantLeft',
|
||||
(payload: { userId: string; sessionId: string; userName: string }) => {
|
||||
this.onParticipantLeft?.(payload)
|
||||
},
|
||||
)
|
||||
|
||||
this.connection.on('ChatMessage', (message: any) => {
|
||||
this.onChatMessage?.(message)
|
||||
|
|
@ -178,6 +181,7 @@ export class SignalRService {
|
|||
this.onParticipantLeft?.({
|
||||
userId: store.getState().auth.user.id,
|
||||
sessionId: this.currentSessionId,
|
||||
userName: store.getState().auth.user.name,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +245,7 @@ export class SignalRService {
|
|||
const { auth } = store.getState()
|
||||
|
||||
if (!this.isConnected) {
|
||||
this.onParticipantLeft?.({ userId: auth.user.id, sessionId })
|
||||
this.onParticipantLeft?.({ userId: auth.user.id, sessionId, userName: auth.user.name })
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -422,10 +426,10 @@ export class SignalRService {
|
|||
}
|
||||
}
|
||||
|
||||
async kickParticipant(sessionId: string, participantId: string): Promise<void> {
|
||||
async kickParticipant(sessionId: string, participantId: string, userName: string): Promise<void> {
|
||||
if (!this.isConnected) {
|
||||
setTimeout(() => {
|
||||
this.onParticipantLeft?.({ userId: participantId, sessionId })
|
||||
this.onParticipantLeft?.({ userId: participantId, sessionId, userName })
|
||||
}, 100)
|
||||
return
|
||||
}
|
||||
|
|
@ -502,7 +506,9 @@ export class SignalRService {
|
|||
this.onParticipantJoined = callback
|
||||
}
|
||||
|
||||
setParticipantLeaveHandler(callback: (payload: { userId: string; sessionId: string }) => void) {
|
||||
setParticipantLeaveHandler(
|
||||
callback: (payload: { userId: string; sessionId: string; userName: string }) => void,
|
||||
) {
|
||||
this.onParticipantLeft = callback
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -363,14 +363,15 @@ const RoomDetail: React.FC = () => {
|
|||
localStream?.getTracks().forEach((t) => t.stop())
|
||||
})
|
||||
|
||||
signalRServiceRef.current.setParticipantLeaveHandler(({ userId, sessionId }) => {
|
||||
signalRServiceRef.current.setParticipantLeaveHandler(({ userId, sessionId, userName }) => {
|
||||
if (userId !== user.id) {
|
||||
const leftUser = participants.find((p) => p.id === userId)
|
||||
const leftName = leftUser ? leftUser.name : 'Bilinmeyen'
|
||||
|
||||
toast.push(<Notification title={`Katılımcı ayrıldı: ${leftName}`} type="warning" />, {
|
||||
placement: 'top-center',
|
||||
})
|
||||
toast.push(
|
||||
<Notification
|
||||
title={`Katılımcı ayrıldı: ${userName ?? 'Bilinmeyen'}`}
|
||||
type="warning"
|
||||
/>,
|
||||
{ placement: 'top-center' },
|
||||
)
|
||||
}
|
||||
|
||||
// peer connection’ı kapat
|
||||
|
|
@ -584,10 +585,14 @@ const RoomDetail: React.FC = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleKickParticipant = async (participantId: string) => {
|
||||
const handleKickParticipant = async (participantId: string, participantName: string) => {
|
||||
if (signalRServiceRef.current && user.role === 'teacher') {
|
||||
try {
|
||||
await signalRServiceRef.current.kickParticipant(classSession.id, participantId)
|
||||
await signalRServiceRef.current.kickParticipant(
|
||||
classSession.id,
|
||||
participantId,
|
||||
participantName,
|
||||
)
|
||||
setAttendanceRecords((prev) =>
|
||||
prev.map((r) => {
|
||||
if (r.studentId === participantId && !r.leaveTime) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue