Chat ve Attandace özellikleri veritabanıından yükleniyor
This commit is contained in:
parent
cf3cb50e1a
commit
f3b953da4f
6 changed files with 104 additions and 64 deletions
|
|
@ -17,15 +17,18 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
|
|||
private readonly IRepository<Classroom, Guid> _classSessionRepository;
|
||||
private readonly IRepository<ClassroomParticipant, Guid> _participantRepository;
|
||||
private readonly IRepository<ClassroomAttandance, Guid> _attendanceRepository;
|
||||
private readonly IRepository<ClassroomChat, Guid> _chatRepository;
|
||||
|
||||
public ClassroomAppService(
|
||||
IRepository<Classroom, Guid> classSessionRepository,
|
||||
IRepository<ClassroomParticipant, Guid> participantRepository,
|
||||
IRepository<ClassroomAttandance, Guid> attendanceRepository)
|
||||
IRepository<ClassroomAttandance, Guid> attendanceRepository,
|
||||
IRepository<ClassroomChat, Guid> chatRepository)
|
||||
{
|
||||
_classSessionRepository = classSessionRepository;
|
||||
_participantRepository = participantRepository;
|
||||
_attendanceRepository = attendanceRepository;
|
||||
_chatRepository = chatRepository;
|
||||
}
|
||||
|
||||
public async Task<ClassroomDto> GetAsync(Guid id)
|
||||
|
|
@ -271,4 +274,37 @@ public class ClassroomAppService : PlatformAppService, IClassroomAppService
|
|||
|
||||
return ObjectMapper.Map<List<ClassroomAttandance>, List<ClassroomAttendanceDto>>(attendanceRecords);
|
||||
}
|
||||
|
||||
public async Task<List<ClassroomParticipantDto>> GetParticipantAsync(Guid sessionId)
|
||||
{
|
||||
var classSession = await _classSessionRepository.GetAsync(sessionId);
|
||||
|
||||
if (classSession.TeacherId != CurrentUser.Id)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Only the teacher can view participant");
|
||||
}
|
||||
|
||||
var participantRecords = await _participantRepository.GetListAsync(
|
||||
x => x.SessionId == sessionId
|
||||
);
|
||||
|
||||
return ObjectMapper.Map<List<ClassroomParticipant>, List<ClassroomParticipantDto>>(participantRecords);
|
||||
}
|
||||
|
||||
public async Task<List<ClassroomChatDto>> GetChatAsync(Guid sessionId)
|
||||
{
|
||||
var classSession = await _classSessionRepository.GetAsync(sessionId);
|
||||
|
||||
if (classSession.TeacherId != CurrentUser.Id)
|
||||
{
|
||||
throw new UnauthorizedAccessException("Only the teacher can view chat");
|
||||
}
|
||||
|
||||
var chatRecords = await _chatRepository.GetListAsync(
|
||||
x => x.SessionId == sessionId
|
||||
);
|
||||
|
||||
return ObjectMapper.Map<List<ClassroomChat>, List<ClassroomChatDto>>(chatRecords);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -144,6 +144,7 @@ export const ChatPanel: React.FC<ChatPanelProps> = ({
|
|||
</select>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Messages */}
|
||||
<div className="flex-1 overflow-y-auto p-4 space-y-3">
|
||||
{messages.length === 0 ? (
|
||||
|
|
|
|||
|
|
@ -66,12 +66,13 @@ export type messageType = 'public' | 'private' | 'announcement'
|
|||
|
||||
export interface ClassroomChatDto {
|
||||
id: string
|
||||
sessionId: string
|
||||
senderId: string
|
||||
senderName: string
|
||||
message: string
|
||||
timestamp: string
|
||||
isTeacher: boolean
|
||||
recipientId?: string // Özel mesaj için
|
||||
recipientId?: string
|
||||
recipientName?: string
|
||||
messageType: messageType
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
import { ClassroomDto, ClassroomFilterInputDto } from '@/proxy/classroom/models'
|
||||
import {
|
||||
ClassroomAttendanceDto,
|
||||
ClassroomChatDto,
|
||||
ClassroomDto,
|
||||
ClassroomFilterInputDto,
|
||||
ClassroomParticipantDto,
|
||||
} from '@/proxy/classroom/models'
|
||||
import apiService from './api.service'
|
||||
import { PagedAndSortedResultRequestDto, PagedResultDto } from '@/proxy'
|
||||
|
||||
|
|
@ -46,3 +52,21 @@ export const endClassroom = (id: string) =>
|
|||
method: 'PUT',
|
||||
url: `/api/app/classroom/${id}/end-class`,
|
||||
})
|
||||
|
||||
export const getClassroomAttandances = (id: string) =>
|
||||
apiService.fetchData<ClassroomAttendanceDto[]>({
|
||||
method: 'GET',
|
||||
url: `/api/app/classroom/attendance/${id}`,
|
||||
})
|
||||
|
||||
export const getClassroomParticipants = (id: string) =>
|
||||
apiService.fetchData<ClassroomParticipantDto[]>({
|
||||
method: 'GET',
|
||||
url: `/api/app/classroom/participant/${id}`,
|
||||
})
|
||||
|
||||
export const getClassroomChats = (id: string) =>
|
||||
apiService.fetchData<ClassroomChatDto[]>({
|
||||
method: 'GET',
|
||||
url: `/api/app/classroom/chat/${id}`,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import { useNavigate } from 'react-router-dom'
|
|||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import { Container } from '@/components/shared'
|
||||
|
||||
const Dashboard: React.FC = () => {
|
||||
const navigate = useNavigate()
|
||||
|
|
@ -31,7 +30,7 @@ const Dashboard: React.FC = () => {
|
|||
title={translate('::' + 'App.Classroom')}
|
||||
defaultTitle="Kurs Platform"
|
||||
></Helmet>
|
||||
<Container>
|
||||
<div className="flex items-center justify-center p-4">
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
|
|
@ -80,7 +79,7 @@ const Dashboard: React.FC = () => {
|
|||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
</Container>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,11 @@ import { ParticipantGrid } from '@/components/classroom/ParticipantGrid'
|
|||
import { ScreenSharePanel } from '@/components/classroom/Panels/ScreenSharePanel'
|
||||
import { KickParticipantModal } from '@/components/classroom/KickParticipantModal'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { getClassroomById } from '@/services/classroom.service'
|
||||
import {
|
||||
getClassroomAttandances,
|
||||
getClassroomById,
|
||||
getClassroomChats,
|
||||
} from '@/services/classroom.service'
|
||||
import { showDbDateAsIs } from '@/utils/dateUtils'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { endClassroom } from '@/services/classroom.service'
|
||||
|
|
@ -162,6 +166,22 @@ const RoomDetail: React.FC = () => {
|
|||
},
|
||||
]
|
||||
|
||||
const fetchClassAttendances = async () => {
|
||||
if (!params?.id) return
|
||||
const attResult = await getClassroomAttandances(params.id)
|
||||
if (attResult && attResult.data) {
|
||||
setAttendanceRecords(attResult.data)
|
||||
}
|
||||
}
|
||||
|
||||
const fetchClassChats = async () => {
|
||||
if (!params?.id) return
|
||||
const chatResult = await getClassroomChats(params.id)
|
||||
if (chatResult && chatResult.data) {
|
||||
setChatMessages(chatResult.data || [])
|
||||
}
|
||||
}
|
||||
|
||||
const fetchClassDetails = async () => {
|
||||
const classEntity = await getClassroomById(params?.id ?? '')
|
||||
if (classEntity) {
|
||||
|
|
@ -172,6 +192,8 @@ const RoomDetail: React.FC = () => {
|
|||
|
||||
useEffect(() => {
|
||||
fetchClassDetails()
|
||||
fetchClassChats()
|
||||
fetchClassAttendances()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -558,52 +580,6 @@ const RoomDetail: React.FC = () => {
|
|||
)
|
||||
}
|
||||
|
||||
// // Demo: Simulate student joining
|
||||
// const simulateStudentJoin = () => {
|
||||
// const studentNames = ['Ahmet Yılmaz', 'Fatma Demir', 'Mehmet Kaya', 'Ayşe Özkan', 'Ali Çelik']
|
||||
// const availableNames = studentNames.filter((name) => !participants.some((p) => p.name === name))
|
||||
|
||||
// if (availableNames.length === 0) {
|
||||
// alert('Tüm demo öğrenciler zaten sınıfta!')
|
||||
// return
|
||||
// }
|
||||
|
||||
// const randomName = availableNames[Math.floor(Math.random() * availableNames.length)]
|
||||
// const studentId = crypto.randomUUID()
|
||||
|
||||
// setParticipants((prev) => {
|
||||
// return [
|
||||
// ...prev,
|
||||
// {
|
||||
// id: studentId,
|
||||
// name: randomName,
|
||||
// isTeacher: false,
|
||||
// isAudioMuted: classSettings.autoMuteNewParticipants,
|
||||
// isVideoMuted: classSettings.defaultCameraState === 'off',
|
||||
// },
|
||||
// ]
|
||||
// })
|
||||
|
||||
// // Add attendance record
|
||||
// setAttendanceRecords((prev: any) => {
|
||||
// // Check if student already has an active attendance record
|
||||
// const existingRecord = prev.find((r: any) => r.studentId === studentId && !r.leaveTime)
|
||||
// if (existingRecord) return prev
|
||||
|
||||
// return [
|
||||
// ...prev,
|
||||
// {
|
||||
// id: crypto.randomUUID(),
|
||||
// sessionId: classSession.id,
|
||||
// studentId,
|
||||
// studentName: randomName,
|
||||
// joinTime: new Date().toISOString(),
|
||||
// totalDurationMinutes: 0,
|
||||
// },
|
||||
// ]
|
||||
// })
|
||||
// }
|
||||
|
||||
const handleSettingsChange = (newSettings: Partial<ClassroomSettingsDto>) => {
|
||||
setClassSettings((prev) => ({ ...prev, ...newSettings }))
|
||||
}
|
||||
|
|
@ -921,17 +897,20 @@ const RoomDetail: React.FC = () => {
|
|||
<FaUsers className="inline mr-1" size={14} />
|
||||
Katılımcılar
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setParticipantsActiveTab('attendance')}
|
||||
className={`flex-1 px-3 py-2 text-sm font-medium rounded-md transition-all ${
|
||||
participantsActiveTab === 'attendance'
|
||||
? 'bg-white text-blue-600 shadow-sm'
|
||||
: 'text-gray-600 hover:text-gray-900'
|
||||
}`}
|
||||
>
|
||||
<FaClipboardList className="inline mr-1" size={14} />
|
||||
Katılım Raporu
|
||||
</button>
|
||||
|
||||
{user.role === 'teacher' && (
|
||||
<button
|
||||
onClick={() => setParticipantsActiveTab('attendance')}
|
||||
className={`flex-1 px-3 py-2 text-sm font-medium rounded-md transition-all ${
|
||||
participantsActiveTab === 'attendance'
|
||||
? 'bg-white text-blue-600 shadow-sm'
|
||||
: 'text-gray-600 hover:text-gray-900'
|
||||
}`}
|
||||
>
|
||||
<FaClipboardList className="inline mr-1" size={14} />
|
||||
Katılım Raporu
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue