Classroom Çıkan kişinin adını yazdık

This commit is contained in:
Sedat ÖZTÜRK 2025-09-01 09:57:54 +03:00
parent 9db84f137e
commit 0d2e3f715c
4 changed files with 65 additions and 54 deletions

View file

@ -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>
);
};
)
}

View file

@ -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"
>

View file

@ -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
}

View file

@ -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) {