Classroom endpoints
This commit is contained in:
parent
b1f82e2f91
commit
6365a0672f
9 changed files with 113 additions and 111 deletions
|
|
@ -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"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"), {
|
||||
|
|
|
|||
54
ui/src/services/classroom.service.ts
Normal file
54
ui/src/services/classroom.service.ts
Normal 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,
|
||||
// })
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Loading…
Reference in a new issue