Classroom endpoints

This commit is contained in:
Sedat ÖZTÜRK 2025-08-26 17:57:09 +03:00
parent b1f82e2f91
commit 6365a0672f
9 changed files with 113 additions and 111 deletions

View file

@ -3924,21 +3924,21 @@
{
"key": "admin.classroom.dashboard",
"path": "/admin/classroom/dashboard",
"componentPath": "@/views/classroom/DashboardPage",
"componentPath": "@/views/classroom/Dashboard",
"routeType": "protected",
"authority": ["App.Classroom.Dashboard"]
},
{
"key": "admin.classroom.classes",
"path": "/admin/classroom/classes",
"componentPath": "@/views/classroom/ClassListPage",
"componentPath": "@/views/classroom/ClassList",
"routeType": "protected",
"authority": ["App.Classroom.List"]
},
{
"key": "admin.classroom.classroom",
"path": "/admin/classroom/room/:id",
"componentPath": "@/views/classroom/RoomPage",
"componentPath": "@/views/classroom/RoomDetail",
"routeType": "protected",
"authority": ["App.Classroom.RoomDetail"]
}

View file

@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812"
}, {
"url": "index.html",
"revision": "0.9qu602jrc3g"
"revision": "0.lcv915aoevo"
}], {});
workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

View file

@ -0,0 +1,54 @@
import { ClassroomDto } from '@/proxy/classroom/models'
import apiService from './api.service'
export const getClassroomById = (id: string) =>
apiService.fetchData<ClassroomDto>({
method: 'GET',
url: `/api/app/classroom`,
params: { id },
})
export const getClassrooms = () =>
apiService.fetchData<ClassroomDto[]>({
method: 'GET',
url: `/api/app/classroom`,
})
// export const getChartOptions = (chartCode: string) =>
// apiService.fetchData<ChartDto>({
// method: 'GET',
// url: `/api/app/charts/chart-options`,
// params: { chartCode },
// })
// export const getChartSelect = (chartCode: string, filter?: string) =>
// apiService.fetchData({
// method: 'GET',
// url: `/api/app/chart-select/select`,
// params: { chartCode, filter },
// })
// export const putCharts = (input: ChartEditDto) =>
// apiService.fetchData({
// method: 'PUT',
// url: `/api/app/charts/${input.id}`,
// data: input,
// })
// export const deleteChartJsonItem = (
// id: string,
// chartCode: string,
// index: number,
// fieldName: string,
// ) =>
// apiService.fetchData({
// method: 'DELETE',
// url: `/api/app/charts/chart-json-item?id=${id}&chartCode=${chartCode}&index=${index}&fieldName=${fieldName}`,
// })
// export const putChartJsonItem = (input: ChartJsonItemRowDto) =>
// apiService.fetchData({
// method: 'PUT',
// url: `/api/app/charts/chart-json-item`,
// data: input,
// })

View file

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion'
import {
@ -11,24 +11,15 @@ import {
FaTrash,
FaEye,
} from 'react-icons/fa'
import { ClassroomDto } from '@/proxy/classroom/models'
import { initialScheduledClasses } from '@/proxy/classroom/data'
import { useStoreState } from '@/store/store'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { Container } from '@/components/shared'
import { getClassrooms } from '@/services/classroom.service'
interface ClassListProps {
onCreateClass: (classData: Partial<ClassroomDto>) => void
onJoinClass: (classSession: ClassroomDto) => void
onEditClass: (classId: string, classData: Partial<ClassroomDto>) => void
onDeleteClass: (classId: string) => void
}
export const ClassList: React.FC<ClassListProps> = ({
onCreateClass,
onJoinClass,
onEditClass,
onDeleteClass,
}) => {
const ClassList: React.FC = () => {
const navigate = useNavigate()
const { user } = useStoreState((state) => state.auth)
@ -106,7 +97,6 @@ export const ClassList: React.FC<ClassListProps> = ({
participantCount: 0,
}
onCreateClass(newClass)
setScheduledClasses((prev) => [...prev, newClass as ClassroomDto])
setShowCreateModal(false)
setFormData({
@ -145,7 +135,6 @@ export const ClassList: React.FC<ClassListProps> = ({
}
setScheduledClasses((prev) => prev.map((c) => (c.id === editingClass.id ? updatedClass : c)))
onEditClass(editingClass.id, formData)
setShowEditModal(false)
setEditingClass(null)
resetForm()
@ -155,7 +144,6 @@ export const ClassList: React.FC<ClassListProps> = ({
if (!deletingClass) return
setScheduledClasses((prev) => prev.filter((c) => c.id !== deletingClass.id))
onDeleteClass(deletingClass.id)
setShowDeleteModal(false)
setDeletingClass(null)
}
@ -221,7 +209,6 @@ export const ClassList: React.FC<ClassListProps> = ({
}
setScheduledClasses((prev) => prev.map((c) => (c.id === classSession.id ? updatedClass : c)))
onJoinClass(updatedClass)
// Sınıf başlatıldığında classroom ekranına yönlendir
if (updatedClass.id) {
navigate(ROUTES_ENUM.protected.admin.classroom.classroom.replace(':id', updatedClass.id))
@ -239,7 +226,7 @@ export const ClassList: React.FC<ClassListProps> = ({
}
return (
<div>
<Container>
{/* Main Content */}
<div className="mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* Stats Cards */}
@ -385,7 +372,6 @@ export const ClassList: React.FC<ClassListProps> = ({
user.role === 'teacher' && classSession.teacherId === user.id
? handleStartClass(classSession)
: (() => {
onJoinClass(classSession)
if (classSession.id)
navigate(
ROUTES_ENUM.protected.admin.classroom.classroom.replace(
@ -931,6 +917,8 @@ export const ClassList: React.FC<ClassListProps> = ({
</motion.div>
</div>
)}
</div>
</Container>
)
}
export default ClassList

View file

@ -1,18 +0,0 @@
import { ClassList } from '@/components/classroom/ClassList'
import { Container } from '@/components/shared'
import React from 'react'
const ClassListPage: React.FC = () => {
return (
<Container>
<ClassList
onCreateClass={() => {}}
onJoinClass={() => {}}
onEditClass={() => {}}
onDeleteClass={() => {}}
/>
</Container>
)
}
export default ClassListPage

View file

@ -1,11 +1,12 @@
import { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { RoleSelector } from './RoleSelector'
import { useClassroomLogic } from '@/utils/hooks/useClassroomLogic'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { Room } from './Room'
import { Container } from '@/components/shared'
import { RoleSelector } from '@/components/classroom/RoleSelector'
import RoomDetail from './RoomDetail'
export function Dashboard() {
const Dashboard: React.FC = () => {
const { roleState, currentClass, handleRoleSelect, handleLeaveClass } = useClassroomLogic()
const navigate = useNavigate()
@ -16,21 +17,13 @@ export function Dashboard() {
}
}, [roleState, navigate])
// Render edilecek içerik
const renderContent = () => {
switch (roleState) {
case 'role-selection':
return <RoleSelector onRoleSelect={handleRoleSelect} />
return (
<Container>
{roleState === 'role-selection' && <RoleSelector onRoleSelect={handleRoleSelect} />}
case 'classroom':
return currentClass ? (
<Room classSession={currentClass} onLeaveClass={handleLeaveClass} />
) : null
default:
return null
}
}
return renderContent()
{roleState === 'classroom' && currentClass && <RoomDetail />}
</Container>
)
}
export default Dashboard

View file

@ -1,13 +0,0 @@
import React from 'react'
import { Dashboard } from '@/components/classroom/Dashboard'
import { Container } from '@/components/shared'
const DashboardPage: React.FC = () => {
return (
<Container>
<Dashboard />
</Container>
)
}
export default DashboardPage

View file

@ -36,9 +36,6 @@ import {
FaUser,
FaBars,
} from 'react-icons/fa'
import { ParticipantGrid } from './ParticipantGrid'
import { KickParticipantModal } from './KickParticipantModal'
import { ScreenSharePanel } from './Panels/ScreenSharePanel'
import { SignalRService } from '@/services/classroom/signalr'
import { WebRTCService } from '@/services/classroom/webrtc'
import {
@ -52,11 +49,11 @@ import {
VideoLayoutDto,
} from '@/proxy/classroom/models'
import { useStoreState } from '@/store/store'
interface RoomProps {
classSession: ClassroomDto
onLeaveClass: () => void
}
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'
type SidePanelType =
| 'chat'
@ -67,8 +64,25 @@ type SidePanelType =
| 'settings'
| null
export const Room: React.FC<RoomProps> = ({ classSession, onLeaveClass }) => {
const newClassSession: ClassroomDto = {
id: '',
name: '',
teacherId: '',
teacherName: '',
startTime: '',
scheduledStartTime: '',
endTime: '',
isActive: false,
isScheduled: false,
participantCount: 0,
settings: undefined,
}
const RoomDetail: React.FC = () => {
const params = useParams()
const { user } = useStoreState((state) => state.auth)
const [classSession, setClassSession] = useState<ClassroomDto>(newClassSession)
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
const [participants, setParticipants] = useState<ClassParticipantDto[]>([])
const [localStream, setLocalStream] = useState<MediaStream>()
@ -152,7 +166,7 @@ export const Room: React.FC<RoomProps> = ({ classSession, onLeaveClass }) => {
// Apply class settings
useEffect(() => {
if (classSession.settings) {
if (classSession?.settings) {
setClassSettings(classSession.settings)
const selectedLayout =
layouts.find((l) => l.id === classSession.settings!.defaultLayout) || layouts[0]
@ -164,7 +178,7 @@ export const Room: React.FC<RoomProps> = ({ classSession, onLeaveClass }) => {
setIsVideoEnabled(classSession.settings.defaultCameraState === 'on')
}
}
}, [classSession.settings, user.role])
}, [classSession?.settings, user.role])
useEffect(() => {
scrollToBottom()
@ -176,6 +190,12 @@ export const Room: React.FC<RoomProps> = ({ classSession, onLeaveClass }) => {
const initializeServices = async () => {
try {
//ClassEntity
const classEntity = await getClassroomById(params?.id ?? '')
if (classEntity) {
setClassSession(classEntity.data)
}
// Initialize SignalR
signalRServiceRef.current = new SignalRService()
await signalRServiceRef.current.start()
@ -281,7 +301,6 @@ export const Room: React.FC<RoomProps> = ({ classSession, onLeaveClass }) => {
const handleLeaveCall = async () => {
await cleanup()
onLeaveClass()
}
const handleSendMessage = async (e: React.FormEvent) => {
@ -1770,7 +1789,7 @@ export const Room: React.FC<RoomProps> = ({ classSession, onLeaveClass }) => {
{/* Left Side - Meeting Info */}
<div className="flex items-center space-x-4 text-white absolute left-0">
<div className="flex items-center space-x-2">
<span className="text-sm font-medium truncate">{classSession.name}</span>
<span className="text-sm font-medium truncate">{classSession?.name}</span>
<div className="w-px h-4 bg-gray-600"></div>
<span className="text-sm text-gray-300">
{new Date().toLocaleTimeString('tr-TR', { hour: '2-digit', minute: '2-digit' })}
@ -1996,3 +2015,5 @@ export const Room: React.FC<RoomProps> = ({ classSession, onLeaveClass }) => {
</div>
)
}
export default RoomDetail

View file

@ -1,23 +0,0 @@
import { Room } from '@/components/classroom/Room'
import React from 'react'
const RoomPage: React.FC = () => {
return (
<Room
classSession={{
id: '',
name: '',
teacherId: '',
teacherName: '',
startTime: '',
scheduledStartTime: '',
isActive: false,
isScheduled: false,
participantCount: 0,
}}
onLeaveClass={() => {}}
/>
)
}
export default RoomPage