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