Video Rooms düzenlemesi
This commit is contained in:
parent
bdc7f744aa
commit
cbd96fd8f2
7 changed files with 667 additions and 257 deletions
|
|
@ -3636,6 +3636,48 @@
|
||||||
"en": "Audit Logs",
|
"en": "Audit Logs",
|
||||||
"tr": "Audit Günlükleri"
|
"tr": "Audit Günlükleri"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.RoleSelector",
|
||||||
|
"en": "Please select your role",
|
||||||
|
"tr": "Lütfen rolünüzü seçin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.Host",
|
||||||
|
"en": "Host",
|
||||||
|
"tr": "Oda Sahibi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.HostDescription",
|
||||||
|
"en": "The host creates the room, starts the session, manages participants and views reports.",
|
||||||
|
"tr": "Odayı oluşturur, oturumu başlatır, katılımcıları yönetir ve raporları görüntüler."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.Participant",
|
||||||
|
"en": "Participant",
|
||||||
|
"tr": "Katılımcı"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.ParticipantDescription",
|
||||||
|
"en": "Joins active rooms and interacts with the host and other participants.",
|
||||||
|
"tr": "Aktif odalara katılır, oda sahibi ve diğer katılımcılarla etkileşim kurar."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.Observer",
|
||||||
|
"en": "Observer",
|
||||||
|
"tr": "İzleyici"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.ObserverDescription",
|
||||||
|
"en": "Joins active rooms and observes without interacting.",
|
||||||
|
"tr": "Aktif odalara katılır, ancak etkileşimde bulunmaz."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Videoroom",
|
"key": "App.Videoroom",
|
||||||
|
|
@ -3663,8 +3705,230 @@
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Videoroom.Planning",
|
"key": "App.Videoroom.Planning",
|
||||||
"en": "Video Room Planning",
|
"en": "Planning",
|
||||||
"tr": "Video Oda Planlama"
|
"tr": "Planlama"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.NewRoom",
|
||||||
|
"en": "New Room",
|
||||||
|
"tr": "Yeni Oda Oluştur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.TotalRooms",
|
||||||
|
"en": "Total Rooms",
|
||||||
|
"tr": "Toplam Oda"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.ActiveRooms",
|
||||||
|
"en": "Active Rooms",
|
||||||
|
"tr": "Aktif Oda"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.OpenRooms",
|
||||||
|
"en": "Open Rooms",
|
||||||
|
"tr": "Katılıma Açık"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.PassiveRooms",
|
||||||
|
"en": "Passive Rooms",
|
||||||
|
"tr": "Pasif Oda"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.TotalParticipants",
|
||||||
|
"en": "Total Participants",
|
||||||
|
"tr": "Toplam Katılımcı"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.RoomSettings",
|
||||||
|
"en": "Room Settings",
|
||||||
|
"tr": "Oda Ayarları"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.ParticipantPermissions",
|
||||||
|
"en": "Participant Permissions",
|
||||||
|
"tr": "Katılımcı İzinleri"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.AllowHandRaise",
|
||||||
|
"en": "Allow Hand Raise",
|
||||||
|
"tr": "Parmak Kaldırma İzni"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.AllowStudentChat",
|
||||||
|
"en": "Allow Student Chat",
|
||||||
|
"tr": "Öğrenci Sohbet İzni"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.AllowPrivateMessages",
|
||||||
|
"en": "Allow Private Messages",
|
||||||
|
"tr": "Özel Mesaj İzni"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.DefaultSettings",
|
||||||
|
"en": "Default Settings",
|
||||||
|
"tr": "Varsayılan Ayarlar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.AllowStudentScreenShare",
|
||||||
|
"en": "Allow Student Screen Share",
|
||||||
|
"tr": "Öğrenci Ekran Paylaşımı"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.MicrophoneMuted",
|
||||||
|
"en": "Microphone Muted",
|
||||||
|
"tr": "Mikrofon Kapalı"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.MicrophoneUnmuted",
|
||||||
|
"en": "Microphone Unmuted",
|
||||||
|
"tr": "Mikrofon Açık"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.DefaultMicrophoneState",
|
||||||
|
"en": "Microphone State",
|
||||||
|
"tr": "Mikrofon Durumu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.DefaultCameraState",
|
||||||
|
"en": "Camera State",
|
||||||
|
"tr": "Kamera Durumu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.CameraOn",
|
||||||
|
"en": "Camera On",
|
||||||
|
"tr": "Kamera Açık"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.DefaultLayout",
|
||||||
|
"en": "Default Layout",
|
||||||
|
"tr": "Varsayılan Layout"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.LayoutGridView",
|
||||||
|
"en": "Grid View",
|
||||||
|
"tr": "Izgara Görünümü"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.LayoutTeacherFocus",
|
||||||
|
"en": "Teacher Focus",
|
||||||
|
"tr": "Öğretmen Odaklı"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.LayoutPresentation",
|
||||||
|
"en": "Presentation",
|
||||||
|
"tr": "Sunum Modu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.LayoutSidebar",
|
||||||
|
"en": "Sidebar",
|
||||||
|
"tr": "Yan Panel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.DeleteRoom",
|
||||||
|
"en": "Delete Room",
|
||||||
|
"tr": "Odayı Sil"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.DeleteRoomWarning",
|
||||||
|
"en": "This action cannot be undone",
|
||||||
|
"tr": "Bu işlem geri alınamaz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.AutomaticallyMuteNewParticipants",
|
||||||
|
"en": "Automatically Mute New Participants",
|
||||||
|
"tr": "Yeni katılımcıları otomatik sustur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.Start",
|
||||||
|
"en": "Start",
|
||||||
|
"tr": "Başlat"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.Join",
|
||||||
|
"en": "Join",
|
||||||
|
"tr": "Katıl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.CreateRoom",
|
||||||
|
"en": "Create Room",
|
||||||
|
"tr": "Oda Oluştur"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.EditRoom",
|
||||||
|
"en": "Edit Room",
|
||||||
|
"tr": "Odayı Düzenle"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.SaveChanges",
|
||||||
|
"en": "Save Changes",
|
||||||
|
"tr": "Değişiklikleri Kaydet"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.CameraOff",
|
||||||
|
"en": "Camera Off",
|
||||||
|
"tr": "Kamera Kapalı"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Listform.ListformField.RoomName",
|
||||||
|
"en": "Room Name",
|
||||||
|
"tr": "Oda Adı"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Listform.ListformField.RoomNamePlaceholder",
|
||||||
|
"en": "E.g. Math 101 - Differential Equations",
|
||||||
|
"tr": "Örn: Matematik 101 - Diferansiyel Denklemler"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Listform.ListformField.DescriptionPlaceholder",
|
||||||
|
"en": "E.g. Brief description about the class...",
|
||||||
|
"tr": "Örn: Ders hakkında kısa açıklama..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Listform.ListformField.SubjectPlaceholder",
|
||||||
|
"en": "E.g. Math, Physics, Chemistry",
|
||||||
|
"tr": "Örn: Matematik, Fizik, Kimya"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Videoroom.NoScheduledRooms",
|
||||||
|
"en": "No Scheduled Rooms",
|
||||||
|
"tr": "Henüz programlanmış oda bulunmamaktadır."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
|
|
@ -6156,6 +6420,24 @@
|
||||||
"tr": "Anketler",
|
"tr": "Anketler",
|
||||||
"en": "Surveys"
|
"en": "Surveys"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Intranet.Events.EventComment",
|
||||||
|
"tr": "Henüz yorum yok. İlk yorumu sen yap!",
|
||||||
|
"en": "No comments yet. Be the first to comment!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Intranet.Events.Comments",
|
||||||
|
"tr": "Yorumlar",
|
||||||
|
"en": "Comments"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Intranet.Events.EventAttendance",
|
||||||
|
"tr": "Bir yorum yaz...",
|
||||||
|
"en": "Write a comment..."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Intranet.Events",
|
"key": "App.Intranet.Events",
|
||||||
|
|
@ -11958,6 +12240,18 @@
|
||||||
"tr": "Çalışıyor...",
|
"tr": "Çalışıyor...",
|
||||||
"en": "Running..."
|
"en": "Running..."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Platform.Intranet.SurveyModal.RequiredUserName",
|
||||||
|
"tr": "Bu anket isim belirtilerek doldurulmaktadır. Yanıtlarınız kaydedilecektir.",
|
||||||
|
"en": "This survey requires your name. Your responses will be recorded."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Platform.Intranet.SurveyModal.AnonymousNotice",
|
||||||
|
"tr": "Bu anket anonimdir. Kimlik bilgileriniz kaydedilmeyecektir.",
|
||||||
|
"en": "This survey is anonymous. Your identity will not be recorded."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Platform.Intranet.SurveyModal.RequiredField",
|
"key": "App.Platform.Intranet.SurveyModal.RequiredField",
|
||||||
|
|
@ -13706,6 +14000,12 @@
|
||||||
"en": "Duration",
|
"en": "Duration",
|
||||||
"tr": "Süre"
|
"tr": "Süre"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Listform.ListformField.Minutes",
|
||||||
|
"en": "Minutes",
|
||||||
|
"tr": "Dakika"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Listform.ListformField.ElementId",
|
"key": "App.Listform.ListformField.ElementId",
|
||||||
|
|
@ -15758,6 +16058,12 @@
|
||||||
"en": "Subject",
|
"en": "Subject",
|
||||||
"tr": "Konu"
|
"tr": "Konu"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "App.Listform.ListformField.StartDateTime",
|
||||||
|
"en": "Start Date and Time",
|
||||||
|
"tr": "Başlangıç Tarihi ve Saati"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "App.Listform.ListformField.SubmissionTime",
|
"key": "App.Listform.ListformField.SubmissionTime",
|
||||||
|
|
@ -18033,4 +18339,4 @@
|
||||||
"tr": "Başarıyla Kaydedildi"
|
"tr": "Başarıyla Kaydedildi"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1123,21 +1123,11 @@
|
||||||
"RequiredPermissionName": "App.Intranet.Events.Event",
|
"RequiredPermissionName": "App.Intranet.Events.Event",
|
||||||
"IsDisabled": false
|
"IsDisabled": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ParentCode": "App.Administration",
|
|
||||||
"Code": "App.Videoroom.Dashboard",
|
|
||||||
"DisplayName": "App.Videoroom.Dashboard",
|
|
||||||
"Order": 4,
|
|
||||||
"Url": "/admin/videoroom/dashboard",
|
|
||||||
"Icon": "FcVideoCall",
|
|
||||||
"RequiredPermissionName": "App.Videoroom.Dashboard",
|
|
||||||
"IsDisabled": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ParentCode": "App.Administration",
|
"ParentCode": "App.Administration",
|
||||||
"Code": "App.Administration.Restrictions",
|
"Code": "App.Administration.Restrictions",
|
||||||
"DisplayName": "App.Restrictions",
|
"DisplayName": "App.Restrictions",
|
||||||
"Order": 5,
|
"Order": 4,
|
||||||
"Url": null,
|
"Url": null,
|
||||||
"Icon": "FaLock",
|
"Icon": "FaLock",
|
||||||
"RequiredPermissionName": null,
|
"RequiredPermissionName": null,
|
||||||
|
|
@ -1167,7 +1157,7 @@
|
||||||
"ParentCode": "App.Administration",
|
"ParentCode": "App.Administration",
|
||||||
"Code": "Abp.Identity",
|
"Code": "Abp.Identity",
|
||||||
"DisplayName": "Abp.Identity",
|
"DisplayName": "Abp.Identity",
|
||||||
"Order": 6,
|
"Order": 5,
|
||||||
"Url": null,
|
"Url": null,
|
||||||
"Icon": "FcConferenceCall",
|
"Icon": "FcConferenceCall",
|
||||||
"RequiredPermissionName": null,
|
"RequiredPermissionName": null,
|
||||||
|
|
@ -1257,7 +1247,7 @@
|
||||||
"ParentCode": "App.Administration",
|
"ParentCode": "App.Administration",
|
||||||
"Code": "App.Reports.Management",
|
"Code": "App.Reports.Management",
|
||||||
"DisplayName": "App.Reports.Management",
|
"DisplayName": "App.Reports.Management",
|
||||||
"Order": 7,
|
"Order": 6,
|
||||||
"Url": null,
|
"Url": null,
|
||||||
"Icon": "FcDocument",
|
"Icon": "FcDocument",
|
||||||
"RequiredPermissionName": null,
|
"RequiredPermissionName": null,
|
||||||
|
|
@ -1283,6 +1273,16 @@
|
||||||
"RequiredPermissionName": "App.Reports.ReportTemplates",
|
"RequiredPermissionName": "App.Reports.ReportTemplates",
|
||||||
"IsDisabled": false
|
"IsDisabled": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ParentCode": "App.Administration",
|
||||||
|
"Code": "App.Videoroom.Dashboard",
|
||||||
|
"DisplayName": "App.Videoroom.Dashboard",
|
||||||
|
"Order": 7,
|
||||||
|
"Url": "/admin/videoroom/dashboard",
|
||||||
|
"Icon": "FcVideoCall",
|
||||||
|
"RequiredPermissionName": "App.Videoroom.Dashboard",
|
||||||
|
"IsDisabled": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ParentCode": "App.Administration",
|
"ParentCode": "App.Administration",
|
||||||
"Code": "App.Files",
|
"Code": "App.Files",
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import {
|
||||||
FaExclamationTriangle,
|
FaExclamationTriangle,
|
||||||
FaSearch,
|
FaSearch,
|
||||||
FaEdit,
|
FaEdit,
|
||||||
FaUser,
|
FaCalendarAlt,
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
import { FcAcceptDatabase } from 'react-icons/fc'
|
import { FcAcceptDatabase } from 'react-icons/fc'
|
||||||
import { deleteWizardFile, getWizardFiles } from '@/services/wizard.service'
|
import { deleteWizardFile, getWizardFiles } from '@/services/wizard.service'
|
||||||
|
|
@ -161,9 +161,12 @@ const WizardFileManager = () => {
|
||||||
|
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
{filteredFiles.length === 0 && !loading && (
|
{filteredFiles.length === 0 && !loading && (
|
||||||
<p className="text-xs text-gray-400 text-center py-4">
|
<div className="text-center py-12">
|
||||||
{translate('::App.Listforms.WizardNoFiles') || 'No wizard files found.'}
|
<FaCalendarAlt size={48} className="mx-auto text-gray-400 mb-4" />
|
||||||
</p>
|
<p className="text-sm text-gray-400 text-center py-4">
|
||||||
|
{translate('::App.Listforms.WizardNoFiles') || 'No wizard files found.'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{loading && (
|
{loading && (
|
||||||
|
|
@ -187,7 +190,9 @@ const WizardFileManager = () => {
|
||||||
{f.wizardName || f.fileName} <Badge content={f.defaultLayout} />
|
{f.wizardName || f.fileName} <Badge content={f.defaultLayout} />
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-gray-400 flex gap-3 mt-0.5">
|
<div className="text-xs text-gray-400 flex gap-3 mt-0.5">
|
||||||
<span className="truncate">{f.fileName} - {f.listFormCode}</span>
|
<span className="truncate">
|
||||||
|
{f.fileName} - {f.listFormCode}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { motion } from 'framer-motion'
|
import { motion } from 'framer-motion'
|
||||||
import { FaGraduationCap, FaUserCheck, FaEye } from 'react-icons/fa'
|
import { FaEye, FaUsers, FaCrown } from 'react-icons/fa'
|
||||||
import { useStoreActions, useStoreState } from '@/store/store'
|
import { useStoreActions, useStoreState } from '@/store/store'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
|
|
@ -36,7 +36,9 @@ const Dashboard: React.FC = () => {
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
className="text-center w-full max-w-4xl"
|
className="text-center w-full max-w-4xl"
|
||||||
>
|
>
|
||||||
<p className="text-lg sm:text-xl text-gray-600 mb-8 sm:mb-12">Lütfen rolünüzü seçin</p>
|
<p className="text-lg sm:text-xl text-gray-600 mb-8 sm:mb-12">
|
||||||
|
{translate('::' + 'App.Videoroom.RoleSelector')}
|
||||||
|
</p>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8">
|
||||||
<motion.button
|
<motion.button
|
||||||
|
|
@ -45,10 +47,12 @@ const Dashboard: React.FC = () => {
|
||||||
onClick={() => handleRoleSelect('teacher')}
|
onClick={() => handleRoleSelect('teacher')}
|
||||||
className="bg-white rounded-lg shadow-lg p-6 sm:p-8 hover:shadow-xl transition-all duration-300 border-2 border-transparent hover:border-blue-500"
|
className="bg-white rounded-lg shadow-lg p-6 sm:p-8 hover:shadow-xl transition-all duration-300 border-2 border-transparent hover:border-blue-500"
|
||||||
>
|
>
|
||||||
<FaGraduationCap size={48} className="mx-auto text-blue-600 mb-4 sm:mb-4" />
|
<FaCrown size={48} className="mx-auto text-blue-600 mb-4 sm:mb-4" />
|
||||||
<h2 className="text-xl sm:text-2xl font-bold text-gray-800 mb-2">Öğretmen</h2>
|
<h2 className="text-xl sm:text-2xl font-bold text-gray-800 mb-2">
|
||||||
|
{translate('::' + 'App.Videoroom.Host')}
|
||||||
|
</h2>
|
||||||
<p className="text-gray-600 text-sm sm:text-base">
|
<p className="text-gray-600 text-sm sm:text-base">
|
||||||
Ders başlatın, öğrencilerle iletişim kurun ve katılım raporlarını görün
|
{translate('::' + 'App.Videoroom.HostDescription')}
|
||||||
</p>
|
</p>
|
||||||
</motion.button>
|
</motion.button>
|
||||||
|
|
||||||
|
|
@ -58,10 +62,12 @@ const Dashboard: React.FC = () => {
|
||||||
onClick={() => handleRoleSelect('student')}
|
onClick={() => handleRoleSelect('student')}
|
||||||
className="bg-white rounded-lg shadow-lg p-6 sm:p-8 hover:shadow-xl transition-all duration-300 border-2 border-transparent hover:border-green-500"
|
className="bg-white rounded-lg shadow-lg p-6 sm:p-8 hover:shadow-xl transition-all duration-300 border-2 border-transparent hover:border-green-500"
|
||||||
>
|
>
|
||||||
<FaUserCheck size={48} className="mx-auto text-green-600 mb-4 sm:mb-4" />
|
<FaUsers size={48} className="mx-auto text-green-600 mb-4 sm:mb-4" />
|
||||||
<h2 className="text-xl sm:text-2xl font-bold text-gray-800 mb-2">Öğrenci</h2>
|
<h2 className="text-xl sm:text-2xl font-bold text-gray-800 mb-2">
|
||||||
|
{translate('::' + 'App.Videoroom.Participant')}
|
||||||
|
</h2>
|
||||||
<p className="text-gray-600 text-sm sm:text-base">
|
<p className="text-gray-600 text-sm sm:text-base">
|
||||||
Aktif derslere katılın, öğretmeniniz ve diğer öğrencilerle etkileşim kurun
|
{translate('::' + 'App.Videoroom.ParticipantDescription')}
|
||||||
</p>
|
</p>
|
||||||
</motion.button>
|
</motion.button>
|
||||||
|
|
||||||
|
|
@ -72,9 +78,11 @@ const Dashboard: React.FC = () => {
|
||||||
className="bg-white rounded-lg shadow-lg p-6 sm:p-8 hover:shadow-xl transition-all duration-300 border-2 border-transparent hover:border-purple-500 md:col-span-2 lg:col-span-1"
|
className="bg-white rounded-lg shadow-lg p-6 sm:p-8 hover:shadow-xl transition-all duration-300 border-2 border-transparent hover:border-purple-500 md:col-span-2 lg:col-span-1"
|
||||||
>
|
>
|
||||||
<FaEye size={48} className="mx-auto text-purple-600 mb-4 sm:mb-4" />
|
<FaEye size={48} className="mx-auto text-purple-600 mb-4 sm:mb-4" />
|
||||||
<h2 className="text-xl sm:text-2xl font-bold text-gray-800 mb-2">Gözlemci</h2>
|
<h2 className="text-xl sm:text-2xl font-bold text-gray-800 mb-2">
|
||||||
|
{translate('::' + 'App.Videoroom.Observer')}
|
||||||
|
</h2>
|
||||||
<p className="text-gray-600 text-sm sm:text-base">
|
<p className="text-gray-600 text-sm sm:text-base">
|
||||||
Sınıfı gözlemleyin, eğitim sürecini takip edin (ses/video paylaşımı yok)
|
{translate('::' + 'App.Videoroom.ObserverDescription')}
|
||||||
</p>
|
</p>
|
||||||
</motion.button>
|
</motion.button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import {
|
||||||
FaHourglassEnd,
|
FaHourglassEnd,
|
||||||
FaDoorOpen,
|
FaDoorOpen,
|
||||||
FaSearch,
|
FaSearch,
|
||||||
FaFilter,
|
|
||||||
} from 'react-icons/fa'
|
} from 'react-icons/fa'
|
||||||
|
|
||||||
import { useStoreState } from '@/store/store'
|
import { useStoreState } from '@/store/store'
|
||||||
|
|
@ -30,6 +29,9 @@ import {
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { VideoroomDto } from '@/proxy/videoroom/models'
|
import { VideoroomDto } from '@/proxy/videoroom/models'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import { Button, Input } from '@/components/ui'
|
||||||
|
import { FcVideoCall } from 'react-icons/fc'
|
||||||
|
|
||||||
export interface RoomProps {
|
export interface RoomProps {
|
||||||
status: string
|
status: string
|
||||||
|
|
@ -70,6 +72,7 @@ const RoomList: React.FC = () => {
|
||||||
}
|
}
|
||||||
const [videoList, setVideoist] = useState<VideoroomDto[]>([])
|
const [videoList, setVideoist] = useState<VideoroomDto[]>([])
|
||||||
const [videoroom, setVideoroom] = useState<VideoroomDto>(newClassEntity)
|
const [videoroom, setVideoroom] = useState<VideoroomDto>(newClassEntity)
|
||||||
|
const mode = useStoreState((state) => state.theme.mode)
|
||||||
|
|
||||||
const [showCreateModal, setShowCreateModal] = useState(false)
|
const [showCreateModal, setShowCreateModal] = useState(false)
|
||||||
const [showEditModal, setShowEditModal] = useState(false)
|
const [showEditModal, setShowEditModal] = useState(false)
|
||||||
|
|
@ -77,7 +80,6 @@ const RoomList: React.FC = () => {
|
||||||
|
|
||||||
// Filter/search state
|
// Filter/search state
|
||||||
const [searchTerm, setSearchTerm] = useState('')
|
const [searchTerm, setSearchTerm] = useState('')
|
||||||
const [statusFilter, setStatusFilter] = useState('')
|
|
||||||
|
|
||||||
const getVideoroomList = async (
|
const getVideoroomList = async (
|
||||||
skipCount = 0,
|
skipCount = 0,
|
||||||
|
|
@ -110,8 +112,8 @@ const RoomList: React.FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getVideoroomList(0, 1000, '', searchTerm, statusFilter)
|
getVideoroomList(0, 1000, '', searchTerm)
|
||||||
}, [searchTerm, statusFilter])
|
}, [searchTerm])
|
||||||
|
|
||||||
const handleCreateClass = async (e: React.FormEvent) => {
|
const handleCreateClass = async (e: React.FormEvent) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
@ -208,7 +210,9 @@ const RoomList: React.FC = () => {
|
||||||
className: 'bg-blue-100 text-blue-800',
|
className: 'bg-blue-100 text-blue-800',
|
||||||
showButtons: true,
|
showButtons: true,
|
||||||
title:
|
title:
|
||||||
user.role === 'teacher' && classSession.teacherId === user.id ? 'Dersi Başlat' : 'Katıl',
|
user.role === 'teacher' && classSession.teacherId === user.id
|
||||||
|
? translate('::App.Videoroom.Start')
|
||||||
|
: translate('::App.Videoroom.Join'),
|
||||||
classes:
|
classes:
|
||||||
user.role === 'teacher' && classSession.teacherId === user.id
|
user.role === 'teacher' && classSession.teacherId === user.id
|
||||||
? 'bg-green-600 text-white hover:bg-green-700'
|
? 'bg-green-600 text-white hover:bg-green-700'
|
||||||
|
|
@ -232,7 +236,9 @@ const RoomList: React.FC = () => {
|
||||||
className: 'bg-yellow-100 text-yellow-800',
|
className: 'bg-yellow-100 text-yellow-800',
|
||||||
showButtons: true,
|
showButtons: true,
|
||||||
title:
|
title:
|
||||||
user.role === 'teacher' && classSession.teacherId === user.id ? 'Sınıfa Git' : 'Katıl',
|
user.role === 'teacher' && classSession.teacherId === user.id
|
||||||
|
? translate('::App.Videoroom.Start')
|
||||||
|
: translate('::App.Videoroom.Join'),
|
||||||
classes:
|
classes:
|
||||||
user.role === 'teacher' && classSession.teacherId === user.id
|
user.role === 'teacher' && classSession.teacherId === user.id
|
||||||
? 'bg-green-600 text-white hover:bg-green-700'
|
? 'bg-green-600 text-white hover:bg-green-700'
|
||||||
|
|
@ -258,12 +264,50 @@ const RoomList: React.FC = () => {
|
||||||
<>
|
<>
|
||||||
<Helmet
|
<Helmet
|
||||||
titleTemplate="%s | Erp Platform"
|
titleTemplate="%s | Erp Platform"
|
||||||
title={translate('::' + 'App.Coordinator.Videoroom.List')}
|
title={translate('::' + 'App.Videoroom.List')}
|
||||||
defaultTitle="Erp Platform"
|
defaultTitle="Erp Platform"
|
||||||
></Helmet>
|
></Helmet>
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
|
{/* ── Header ─────────────────────────────────────────────── */}
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'flex items-center gap-2 pb-1 border-b',
|
||||||
|
mode === 'light' ? 'border-gray-200' : 'border-neutral-700',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<FcVideoCall size={24} />
|
||||||
|
<h4 className="text-sm font-medium">{translate('::App.Videoroom.List')}</h4>
|
||||||
|
|
||||||
|
<div className="flex gap-1 ml-auto items-center">
|
||||||
|
<div className="flex-1 relative">
|
||||||
|
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" />
|
||||||
|
<Input
|
||||||
|
size="sm"
|
||||||
|
type="text"
|
||||||
|
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
placeholder="Search..."
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{user.role === 'teacher' && (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="solid"
|
||||||
|
onClick={() => setShowCreateModal(true)}
|
||||||
|
className="flex items-center justify-center space-x-2 text-indigo-500 hover:bg-indigo-50 dark:hover:bg-indigo-900/20"
|
||||||
|
>
|
||||||
|
<FaPlus size={15} />
|
||||||
|
<span>{translate('::App.Videoroom.NewRoom')}</span>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Stats Cards */}
|
{/* Stats Cards */}
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-6 mb-3">
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-4 sm:gap-6 mt-4 mb-3">
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
|
@ -274,7 +318,9 @@ const RoomList: React.FC = () => {
|
||||||
<FaCalendarAlt className="text-blue-600" size={20} />
|
<FaCalendarAlt className="text-blue-600" size={20} />
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 sm:ml-4">
|
<div className="ml-3 sm:ml-4">
|
||||||
<p className="text-xs sm:text-sm font-medium text-gray-600">Toplam Sınıf</p>
|
<p className="text-xs sm:text-sm font-medium text-gray-600">
|
||||||
|
{translate('::App.Videoroom.TotalRooms')}
|
||||||
|
</p>
|
||||||
<p className="text-xl sm:text-2xl font-bold text-gray-900">
|
<p className="text-xl sm:text-2xl font-bold text-gray-900">
|
||||||
{widgets().totalCount}{' '}
|
{widgets().totalCount}{' '}
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -294,7 +340,9 @@ const RoomList: React.FC = () => {
|
||||||
<FaPlay className="text-green-600" size={20} />
|
<FaPlay className="text-green-600" size={20} />
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 sm:ml-4">
|
<div className="ml-3 sm:ml-4">
|
||||||
<p className="text-xs sm:text-sm font-medium text-gray-600">Aktif Sınıf</p>
|
<p className="text-xs sm:text-sm font-medium text-gray-600">
|
||||||
|
{translate('::App.Videoroom.ActiveRooms')}
|
||||||
|
</p>
|
||||||
<p className="text-xl sm:text-2xl font-bold text-gray-900">
|
<p className="text-xl sm:text-2xl font-bold text-gray-900">
|
||||||
{widgets().activeCount}
|
{widgets().activeCount}
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -314,7 +362,9 @@ const RoomList: React.FC = () => {
|
||||||
<FaDoorOpen className="text-blue-600" size={20} />
|
<FaDoorOpen className="text-blue-600" size={20} />
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 sm:ml-4">
|
<div className="ml-3 sm:ml-4">
|
||||||
<p className="text-xs sm:text-sm font-medium text-gray-600">Katılıma Açık</p>
|
<p className="text-xs sm:text-sm font-medium text-gray-600">
|
||||||
|
{translate('::App.Videoroom.OpenRooms')}
|
||||||
|
</p>
|
||||||
<p className="text-xl sm:text-2xl font-bold text-gray-900">{widgets().openCount}</p>
|
<p className="text-xl sm:text-2xl font-bold text-gray-900">{widgets().openCount}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -332,7 +382,9 @@ const RoomList: React.FC = () => {
|
||||||
<FaHourglassEnd className="text-gray-600" size={20} />
|
<FaHourglassEnd className="text-gray-600" size={20} />
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 sm:ml-4">
|
<div className="ml-3 sm:ml-4">
|
||||||
<p className="text-xs sm:text-sm font-medium text-gray-600">Pasif Sınıf</p>
|
<p className="text-xs sm:text-sm font-medium text-gray-600">
|
||||||
|
{translate('::App.Videoroom.PassiveRooms')}
|
||||||
|
</p>
|
||||||
<p className="text-xl sm:text-2xl font-bold text-gray-900">
|
<p className="text-xl sm:text-2xl font-bold text-gray-900">
|
||||||
{widgets().passiveCount}
|
{widgets().passiveCount}
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -352,7 +404,9 @@ const RoomList: React.FC = () => {
|
||||||
<FaUsers className="text-purple-600" size={20} />
|
<FaUsers className="text-purple-600" size={20} />
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 sm:ml-4">
|
<div className="ml-3 sm:ml-4">
|
||||||
<p className="text-xs sm:text-sm font-medium text-gray-600">Toplam Katılımcı</p>
|
<p className="text-xs sm:text-sm font-medium text-gray-600">
|
||||||
|
{translate('::App.Videoroom.TotalParticipants')}
|
||||||
|
</p>
|
||||||
<p className="text-xl sm:text-2xl font-bold text-gray-900">
|
<p className="text-xl sm:text-2xl font-bold text-gray-900">
|
||||||
{videoList.reduce((sum, c) => sum + c.participantCount, 0)}
|
{videoList.reduce((sum, c) => sum + c.participantCount, 0)}
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -361,188 +415,158 @@ const RoomList: React.FC = () => {
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Filter Bar */}
|
|
||||||
<div className="bg-white rounded-lg border border-slate-200 p-6 mb-6 shadow-sm">
|
|
||||||
<div className="flex flex-col lg:flex-row gap-4">
|
|
||||||
<div className="flex-1 relative">
|
|
||||||
<FaSearch className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-slate-400" />
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
||||||
placeholder="Search class"
|
|
||||||
value={searchTerm}
|
|
||||||
onChange={(e) => setSearchTerm(e.target.value)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<FaFilter className="w-5 h-5 text-slate-500" />
|
|
||||||
<select
|
|
||||||
className="ml-2 px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
||||||
value={statusFilter}
|
|
||||||
onChange={(e) => setStatusFilter(e.target.value)}
|
|
||||||
style={{ minWidth: 120 }}
|
|
||||||
>
|
|
||||||
<option value="">All Status</option>
|
|
||||||
<option value="Active">Aktif</option>
|
|
||||||
<option value="Open">Katılıma Açık</option>
|
|
||||||
<option value="Passive">Pasif</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Scheduled Classes */}
|
{/* Scheduled Classes */}
|
||||||
<div className="bg-white rounded-lg shadow-md">
|
<div className="bg-white rounded-lg shadow-md">
|
||||||
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 p-4 sm:px-6 border-b border-gray-200">
|
{videoList.length === 0 ? (
|
||||||
<h2 className="text-lg sm:text-xl font-semibold text-gray-900">Programlı Sınıflar</h2>
|
<div className="text-center py-12">
|
||||||
{user.role === 'teacher' && (
|
<FaCalendarAlt size={48} className="mx-auto text-gray-400 mb-4" />
|
||||||
<button
|
<p className="text-sm text-gray-400 text-center py-4">
|
||||||
onClick={() => setShowCreateModal(true)}
|
{translate('::App.Videoroom.NoScheduledRooms') ||
|
||||||
className="flex items-center justify-center space-x-2 bg-blue-600 text-white px-3 sm:px-6 py-2 rounded-lg hover:bg-blue-700 transition-colors sm:w-auto"
|
'No scheduled classes found. Please create a new class.'}
|
||||||
>
|
</p>
|
||||||
<FaPlus size={15} />
|
</div>
|
||||||
<span className="hidden sm:inline">Yeni Sınıf Oluştur</span>
|
) : (
|
||||||
<span className="sm:hidden">Yeni Sınıf</span>
|
<div className="grid gap-3">
|
||||||
</button>
|
{videoList.map((classSession, index) => {
|
||||||
)}
|
const { status, className, showButtons, title, classes, event } =
|
||||||
</div>
|
getClassProps(classSession)
|
||||||
<div className="p-4 sm:p-6">
|
const isActive = !classSession.actualStartTime && !classSession.actualEndTime
|
||||||
{videoList.length === 0 ? (
|
const isOpen = classSession.actualStartTime && !classSession.actualEndTime
|
||||||
<div className="text-center py-12">
|
const accentColor = isOpen
|
||||||
<FaCalendarAlt size={48} className="mx-auto text-gray-400 mb-4" />
|
? 'border-l-yellow-400'
|
||||||
<p className="text-gray-500">Henüz programlanmış sınıf bulunmamaktadır.</p>
|
: isActive
|
||||||
</div>
|
? 'border-l-blue-500'
|
||||||
) : (
|
: 'border-l-gray-300'
|
||||||
<div className="grid gap-4 sm:gap-6">
|
return (
|
||||||
{videoList.map((classSession, index) => {
|
<motion.div
|
||||||
const { status, className, showButtons, title, classes, event } =
|
key={classSession.id}
|
||||||
getClassProps(classSession)
|
initial={{ opacity: 0, y: 10 }}
|
||||||
return (
|
animate={{ opacity: 1, y: 0 }}
|
||||||
<motion.div
|
transition={{ delay: index * 0.05 }}
|
||||||
key={classSession.id}
|
className={`bg-white border border-gray-100 border-l-4 ${accentColor} rounded-xl shadow-sm hover:shadow-md transition-all duration-200`}
|
||||||
initial={{ opacity: 0, x: -20 }}
|
>
|
||||||
animate={{ opacity: 1, x: 0 }}
|
{/* Card Header */}
|
||||||
transition={{ delay: index * 0.1 }}
|
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 p-4 pb-3">
|
||||||
className="border border-gray-200 rounded-lg p-4 sm:p-6 hover:shadow-md transition-shadow"
|
<div className="flex flex-col gap-1 min-w-0">
|
||||||
>
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between">
|
<h3 className="text-sm font-semibold text-gray-900 truncate">
|
||||||
<div className="flex items-center space-x-3">
|
|
||||||
<h3 className="text-base sm:text-lg font-semibold text-gray-900 break-words">
|
|
||||||
{classSession.name}
|
{classSession.name}
|
||||||
</h3>
|
</h3>
|
||||||
<span
|
<span
|
||||||
className={`px-2 py-1 rounded-full text-xs font-medium ${className}`}
|
className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${className}`}
|
||||||
>
|
>
|
||||||
{status}
|
{status}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
{(classSession.subject || classSession.description) && (
|
||||||
{/* Sağ kısım: buton */}
|
<div className="flex flex-col gap-0.5">
|
||||||
{showButtons && (
|
{classSession.subject && (
|
||||||
<div className="flex space-x-2">
|
<span className="text-xs font-medium text-indigo-600">
|
||||||
{/* {user.role === 'teacher' && classSession.teacherId === user.id && ( */}
|
{classSession.subject}
|
||||||
{user.role === 'teacher' && (
|
</span>
|
||||||
<>
|
)}
|
||||||
<button
|
{classSession.description && (
|
||||||
onClick={() => handlePlanningClass(classSession)}
|
<p className="text-xs text-gray-400 line-clamp-1">
|
||||||
disabled={classSession.actualStartTime ? true : false}
|
{classSession.description}
|
||||||
className="flex px-3 sm:px-4 py-2 rounded-lg bg-yellow-600 text-white
|
</p>
|
||||||
hover:bg-yellow-700
|
|
||||||
disabled:bg-gray-400 disabled:cursor-not-allowed disabled:hover:bg-gray-400"
|
|
||||||
title="Sınıfı Planla"
|
|
||||||
>
|
|
||||||
<FaUsers size={14} />
|
|
||||||
Planlama
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={() => openEditModal(classSession)}
|
|
||||||
disabled={classSession.actualStartTime ? true : false}
|
|
||||||
className="flex px-3 sm:px-4 py-2 rounded-lg bg-blue-600 text-white
|
|
||||||
hover:bg-blue-700
|
|
||||||
disabled:bg-gray-400 disabled:cursor-not-allowed disabled:hover:bg-gray-400"
|
|
||||||
title="Sınıfı Düzenle"
|
|
||||||
>
|
|
||||||
<FaEdit size={14} />
|
|
||||||
Düzenle
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={() => openDeleteModal(classSession)}
|
|
||||||
disabled={classSession.actualStartTime ? true : false}
|
|
||||||
className="flex px-3 sm:px-4 py-2 rounded-lg bg-red-600 text-white
|
|
||||||
hover:bg-red-700
|
|
||||||
disabled:bg-gray-400 disabled:cursor-not-allowed disabled:hover:bg-gray-400"
|
|
||||||
title="Sınıfı Sil"
|
|
||||||
>
|
|
||||||
<FaTrash size={14} />
|
|
||||||
Sil
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<button
|
|
||||||
onClick={event}
|
|
||||||
disabled={status === 'Katılıma Açık' ? true : false}
|
|
||||||
className={`px-3 sm:px-4 py-2 rounded-lg transition-colors ${
|
|
||||||
classes
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{title}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4">
|
{/* Action Buttons */}
|
||||||
<p className="text-gray-600 text-sm sm:text-base">{classSession.subject}</p>
|
{showButtons && (
|
||||||
</div>
|
<div className="flex items-center gap-1.5 flex-shrink-0">
|
||||||
|
{user.role === 'teacher' && (
|
||||||
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4">
|
<>
|
||||||
<sub className="text-gray-500 mb-3 text-xs sm:text-sm">
|
<Button
|
||||||
{classSession.description}
|
size="sm"
|
||||||
</sub>
|
variant="solid"
|
||||||
</div>
|
color="red-600"
|
||||||
|
className="flex items-center gap-1"
|
||||||
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4">
|
onClick={() => handlePlanningClass(classSession)}
|
||||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 md:gap-3 w-full text-xs sm:text-sm text-gray-600">
|
disabled={!!classSession.actualStartTime}
|
||||||
<div className="col-span-1 flex items-center gap-2 p-1 rounded-lg">
|
title={translate('::App.Videoroom.Planning') || 'Planning'}
|
||||||
<FaCalendarAlt size={14} className="text-gray-500" />
|
>
|
||||||
<span className="truncate">
|
<FaUsers size={11} />
|
||||||
{showDbDateAsIs(classSession.scheduledStartTime)}
|
<span className="hidden sm:inline">
|
||||||
</span>
|
{translate('::App.Videoroom.Planning') || 'Planning'}
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-span-1 flex items-center gap-2 p-1 rounded-lg">
|
|
||||||
<FaClock size={14} className="text-gray-500" />
|
|
||||||
<span>{classSession.duration} dakika</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-span-1 flex items-center gap-2 p-1 rounded-lg">
|
|
||||||
{classSession.scheduledEndTime && (
|
|
||||||
<>
|
|
||||||
<FaEye size={14} className="text-gray-500" />
|
|
||||||
<span className="truncate">
|
|
||||||
{showDbDateAsIs(classSession.scheduledEndTime!)}
|
|
||||||
</span>
|
</span>
|
||||||
</>
|
</Button>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-span-1 flex items-center gap-2 p-1 rounded-lg">
|
<Button
|
||||||
<FaUsers size={14} className="text-gray-500" />
|
size="sm"
|
||||||
<span>
|
variant="solid"
|
||||||
{classSession.participantCount}/{classSession.maxParticipants}
|
color="orange-600"
|
||||||
</span>
|
className="flex items-center gap-1"
|
||||||
</div>
|
onClick={() => openEditModal(classSession)}
|
||||||
|
disabled={!!classSession.actualStartTime}
|
||||||
|
title={translate('::App.Platform.Edit')}
|
||||||
|
>
|
||||||
|
<FaEdit size={11} />
|
||||||
|
<span className="hidden sm:inline">
|
||||||
|
{translate('::App.Platform.Edit')}
|
||||||
|
</span>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="solid"
|
||||||
|
color="sky-800"
|
||||||
|
className="flex items-center gap-1"
|
||||||
|
onClick={() => openDeleteModal(classSession)}
|
||||||
|
disabled={!!classSession.actualStartTime}
|
||||||
|
title={translate('::App.Platform.Delete')}
|
||||||
|
>
|
||||||
|
<FaTrash size={11} />
|
||||||
|
<span className="hidden sm:inline">
|
||||||
|
{translate('::App.Platform.Delete')}
|
||||||
|
</span>
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="solid"
|
||||||
|
onClick={event}
|
||||||
|
className="flex items-center gap-1"
|
||||||
|
color="emerald-600"
|
||||||
|
disabled={status === 'Katılıma Açık' ? true : false}
|
||||||
|
>
|
||||||
|
<FaPlay size={10} />
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</motion.div>
|
</div>
|
||||||
)
|
|
||||||
})}
|
{/* Card Footer — Meta Info */}
|
||||||
</div>
|
<div className="flex flex-wrap items-center gap-x-4 gap-y-1 px-4 py-2.5 bg-gray-50 rounded-b-xl border-t border-gray-100 text-xs text-gray-500">
|
||||||
)}
|
<span className="flex items-center gap-1.5">
|
||||||
</div>
|
<FaCalendarAlt size={11} className="text-blue-400" />
|
||||||
|
{showDbDateAsIs(classSession.scheduledStartTime)}
|
||||||
|
</span>
|
||||||
|
<span className="flex items-center gap-1.5">
|
||||||
|
<FaClock size={11} className="text-purple-400" />
|
||||||
|
{classSession.duration} dk
|
||||||
|
</span>
|
||||||
|
{classSession.scheduledEndTime && (
|
||||||
|
<span className="flex items-center gap-1.5">
|
||||||
|
<FaEye size={11} className="text-green-400" />
|
||||||
|
{showDbDateAsIs(classSession.scheduledEndTime!)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span className="flex items-center gap-1.5">
|
||||||
|
<FaUsers size={11} className="text-indigo-400" />
|
||||||
|
{classSession.participantCount}/{classSession.maxParticipants}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Class Modal (Create/Edit) */}
|
{/* Class Modal (Create/Edit) */}
|
||||||
|
|
@ -555,7 +579,9 @@ const RoomList: React.FC = () => {
|
||||||
>
|
>
|
||||||
<div className="p-3 sm:p-3 border-b border-gray-200">
|
<div className="p-3 sm:p-3 border-b border-gray-200">
|
||||||
<h2 className="text-xl sm:text-2xl font-bold text-gray-900">
|
<h2 className="text-xl sm:text-2xl font-bold text-gray-900">
|
||||||
{showCreateModal ? 'Yeni Sınıf Oluştur' : 'Sınıfı Düzenle'}
|
{showCreateModal
|
||||||
|
? translate('::App.Videoroom.CreateRoom') || 'Yeni Sınıf Oluştur'
|
||||||
|
: translate('::App.Videoroom.EditRoom') || 'Sınıfı Düzenle'}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -565,7 +591,7 @@ const RoomList: React.FC = () => {
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Sınıf Adı *
|
{translate('::App.Listform.ListformField.RoomName') || 'Room Name'} *
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -574,38 +600,51 @@ const RoomList: React.FC = () => {
|
||||||
value={videoroom.name}
|
value={videoroom.name}
|
||||||
onChange={(e) => setVideoroom({ ...videoroom, name: e.target.value })}
|
onChange={(e) => setVideoroom({ ...videoroom, name: e.target.value })}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
placeholder="Örn: Matematik 101 - Diferansiyel Denklemler"
|
placeholder={
|
||||||
|
translate('::App.Listform.ListformField.RoomNamePlaceholder') ||
|
||||||
|
'Enter room name...'
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">Açıklama</label>
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
{translate('::App.Listform.ListformField.Description') || 'Description'}
|
||||||
|
</label>
|
||||||
<textarea
|
<textarea
|
||||||
value={videoroom.description}
|
value={videoroom.description}
|
||||||
onChange={(e) => setVideoroom({ ...videoroom, description: e.target.value })}
|
onChange={(e) => setVideoroom({ ...videoroom, description: e.target.value })}
|
||||||
rows={3}
|
rows={3}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
placeholder="Ders hakkında kısa açıklama..."
|
placeholder={
|
||||||
|
translate('::App.Listform.ListformField.DescriptionPlaceholder') ||
|
||||||
|
'Ders hakkında kısa açıklama...'
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Ders Konusu
|
{translate('::App.Listform.ListformField.Subject') || 'Subject'}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={videoroom.subject}
|
value={videoroom.subject}
|
||||||
onChange={(e) => setVideoroom({ ...videoroom, subject: e.target.value })}
|
onChange={(e) => setVideoroom({ ...videoroom, subject: e.target.value })}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
placeholder="Örn: Matematik, Fizik, Kimya"
|
placeholder={
|
||||||
|
translate('::App.Listform.ListformField.SubjectPlaceholder') ||
|
||||||
|
'E.g. Math, Physics, Chemistry'
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Başlangıç Tarihi ve Saati *
|
{translate('::App.Listform.ListformField.StartDateTime') ||
|
||||||
|
'Start Date and Time'}{' '}
|
||||||
|
*
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
|
|
@ -629,7 +668,8 @@ const RoomList: React.FC = () => {
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Süre (dakika)
|
{translate('::App.Listform.ListformField.Duration') || 'Duration'} (
|
||||||
|
{translate('::App.Listform.ListformField.Minutes') || 'minutes'})
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -648,7 +688,8 @@ const RoomList: React.FC = () => {
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
Maksimum Katılımcı
|
{translate('::App.Listform.ListformField.MaxParticipants') ||
|
||||||
|
'Maximum Participants'}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -668,11 +709,16 @@ const RoomList: React.FC = () => {
|
||||||
|
|
||||||
{/* Sınıf Ayarları */}
|
{/* Sınıf Ayarları */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-gray-800 mb-2">Sınıf Ayarları</h3>
|
<h3 className="text-lg font-semibold text-gray-800 mb-2">
|
||||||
|
{translate('::App.Videoroom.RoomSettings') || 'Sınıf Ayarları'}
|
||||||
|
</h3>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 sm:gap-6">
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 sm:gap-6">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<h4 className="font-medium text-gray-700">Katılımcı İzinleri</h4>{' '}
|
<h4 className="font-medium text-gray-700">
|
||||||
|
{translate('::App.Videoroom.ParticipantPermissions') ||
|
||||||
|
'Katılımcı İzinleri'}
|
||||||
|
</h4>{' '}
|
||||||
<label className="flex items-center space-x-3">
|
<label className="flex items-center space-x-3">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
|
@ -688,7 +734,9 @@ const RoomList: React.FC = () => {
|
||||||
}
|
}
|
||||||
className="rounded"
|
className="rounded"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm">Parmak kaldırma izni</span>
|
<span className="text-sm">
|
||||||
|
{translate('::App.Videoroom.AllowHandRaise') || 'Parmak kaldırma izni'}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center space-x-3">
|
<label className="flex items-center space-x-3">
|
||||||
<input
|
<input
|
||||||
|
|
@ -705,7 +753,9 @@ const RoomList: React.FC = () => {
|
||||||
}
|
}
|
||||||
className="rounded"
|
className="rounded"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm">Öğrenci sohbet izni</span>
|
<span className="text-sm">
|
||||||
|
{translate('::App.Videoroom.AllowStudentChat') || 'Öğrenci sohbet izni'}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center space-x-3">
|
<label className="flex items-center space-x-3">
|
||||||
<input
|
<input
|
||||||
|
|
@ -722,7 +772,9 @@ const RoomList: React.FC = () => {
|
||||||
}
|
}
|
||||||
className="rounded"
|
className="rounded"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm">Özel mesaj izni</span>
|
<span className="text-sm">
|
||||||
|
{translate('::App.Videoroom.AllowPrivateMessages') || 'Özel mesaj izni'}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center space-x-3">
|
<label className="flex items-center space-x-3">
|
||||||
<input
|
<input
|
||||||
|
|
@ -739,16 +791,22 @@ const RoomList: React.FC = () => {
|
||||||
}
|
}
|
||||||
className="rounded"
|
className="rounded"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm">Öğrenci ekran paylaşımı</span>
|
<span className="text-sm">
|
||||||
|
{translate('::App.Videoroom.AllowStudentScreenShare') ||
|
||||||
|
'Öğrenci ekran paylaşımı'}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<h4 className="font-medium text-gray-700">Varsayılan Ayarlar</h4>
|
<h4 className="font-medium text-gray-700">
|
||||||
|
{translate('::App.Videoroom.DefaultSettings') || 'Varsayılan Ayarlar'}
|
||||||
|
</h4>
|
||||||
|
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
Varsayılan mikrofon durumu
|
{translate('::App.Videoroom.DefaultMicrophoneState') ||
|
||||||
|
'Varsayılan mikrofon durumu'}
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
value={videoroom.settingsDto?.defaultMicrophoneState}
|
value={videoroom.settingsDto?.defaultMicrophoneState}
|
||||||
|
|
@ -763,14 +821,19 @@ const RoomList: React.FC = () => {
|
||||||
}
|
}
|
||||||
className="border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
className="border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
>
|
>
|
||||||
<option value="muted">Kapalı</option>
|
<option value="muted">
|
||||||
<option value="unmuted">Açık</option>
|
{translate('::App.Videoroom.MicrophoneMuted') || 'Kapalı'}
|
||||||
|
</option>
|
||||||
|
<option value="unmuted">
|
||||||
|
{translate('::App.Videoroom.MicrophoneUnmuted') || 'Açık'}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
Varsayılan kamera durumu
|
{translate('::App.Videoroom.DefaultCameraState') ||
|
||||||
|
'Varsayılan kamera durumu'}
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
value={videoroom.settingsDto?.defaultCameraState}
|
value={videoroom.settingsDto?.defaultCameraState}
|
||||||
|
|
@ -785,14 +848,18 @@ const RoomList: React.FC = () => {
|
||||||
}
|
}
|
||||||
className="border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
className="border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
>
|
>
|
||||||
<option value="on">Açık</option>
|
<option value="on">
|
||||||
<option value="off">Kapalı</option>
|
{translate('::App.Videoroom.CameraOn') || 'Açık'}
|
||||||
|
</option>
|
||||||
|
<option value="off">
|
||||||
|
{translate('::App.Videoroom.CameraOff') || 'Kapalı'}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
Varsayılan layout
|
{translate('::App.Videoroom.DefaultLayout') || 'Varsayılan layout'}
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
value={videoroom.settingsDto?.defaultLayout}
|
value={videoroom.settingsDto?.defaultLayout}
|
||||||
|
|
@ -807,10 +874,18 @@ const RoomList: React.FC = () => {
|
||||||
}
|
}
|
||||||
className="border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
className="border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
>
|
>
|
||||||
<option value="grid">Izgara Görünümü</option>
|
<option value="grid">
|
||||||
<option value="teacher-focus">Öğretmen Odaklı</option>
|
{translate('::App.Videoroom.LayoutGridView') || 'Izgara Görünümü'}
|
||||||
<option value="presentation">Sunum Modu</option>
|
</option>
|
||||||
<option value="sidebar">Yan Panel</option>
|
<option value="teacher-focus">
|
||||||
|
{translate('::App.Videoroom.LayoutTeacherFocus') || 'Öğretmen Odaklı'}
|
||||||
|
</option>
|
||||||
|
<option value="presentation">
|
||||||
|
{translate('::App.Videoroom.LayoutPresentation') || 'Sunum Modu'}
|
||||||
|
</option>
|
||||||
|
<option value="sidebar">
|
||||||
|
{translate('::App.Videoroom.LayoutSidebar') || 'Yan Panel'}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -829,7 +904,10 @@ const RoomList: React.FC = () => {
|
||||||
}
|
}
|
||||||
className="rounded"
|
className="rounded"
|
||||||
/>
|
/>
|
||||||
<span className="text-sm">Yeni katılımcıları otomatik sustur</span>
|
<span className="text-sm">
|
||||||
|
{translate('::App.Videoroom.AutomaticallyMuteNewParticipants') ||
|
||||||
|
'Yeni katılımcıları otomatik sustur'}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -849,15 +927,17 @@ const RoomList: React.FC = () => {
|
||||||
resetForm()
|
resetForm()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="px-6 py-3 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
className="px-3 py-1 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
||||||
>
|
>
|
||||||
İptal
|
{translate('::Cancel') || 'İptal'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
className="px-3 py-1 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||||
>
|
>
|
||||||
{showCreateModal ? 'Sınıf Oluştur' : 'Değişiklikleri Kaydet'}
|
{showCreateModal
|
||||||
|
? translate('::App.Videoroom.CreateRoom') || 'Sınıf Oluştur'
|
||||||
|
: translate('::App.Videoroom.SaveChanges') || 'Değişiklikleri Kaydet'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
@ -879,14 +959,18 @@ const RoomList: React.FC = () => {
|
||||||
<FaTrash className="text-red-600" size={24} />
|
<FaTrash className="text-red-600" size={24} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-gray-900">Sınıfı Sil</h3>
|
<h3 className="text-lg font-semibold text-gray-900">
|
||||||
<p className="text-sm text-gray-600">Bu işlem geri alınamaz</p>
|
{translate('::App.Videoroom.DeleteRoom') || 'Sınıfı Sil'}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-gray-600">
|
||||||
|
{translate('::App.Videoroom.DeleteRoomWarning') || 'Bu işlem geri alınamaz'}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-gray-700 mb-6">
|
<p className="text-gray-700 mb-6">
|
||||||
<strong>"{videoroom.name}"</strong> adlı sınıfı silmek istediğinizden emin
|
{translate('::DeleteConfirmation') ||
|
||||||
misiniz?
|
'Bu sınıfı silmek istediğinize emin misiniz?'}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div className="flex items-center justify-end space-x-4">
|
<div className="flex items-center justify-end space-x-4">
|
||||||
|
|
@ -897,13 +981,13 @@ const RoomList: React.FC = () => {
|
||||||
}}
|
}}
|
||||||
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
className="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
|
||||||
>
|
>
|
||||||
İptal
|
{translate('::App.Common.Cancel') || 'İptal'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleDeleteClass}
|
onClick={handleDeleteClass}
|
||||||
className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
|
className="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
|
||||||
>
|
>
|
||||||
Sil
|
{translate('::App.Platform.Delete') || 'Sil'}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import { AVATAR_URL } from '@/constants/app.constant'
|
||||||
import { intranetService } from '@/services/intranet.service'
|
import { intranetService } from '@/services/intranet.service'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
|
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
|
|
@ -41,6 +42,7 @@ const imgSrc = (img: string) => {
|
||||||
const EventModal: React.FC<EventModalProps> = ({ event, onClose }) => {
|
const EventModal: React.FC<EventModalProps> = ({ event, onClose }) => {
|
||||||
const currentLocale = useLocale()
|
const currentLocale = useLocale()
|
||||||
const photos = (event.photos || '').split('|').filter(Boolean)
|
const photos = (event.photos || '').split('|').filter(Boolean)
|
||||||
|
const { translate } = useLocalization()
|
||||||
|
|
||||||
// Photo slider state
|
// Photo slider state
|
||||||
const [activePhoto, setActivePhoto] = useState(0)
|
const [activePhoto, setActivePhoto] = useState(0)
|
||||||
|
|
@ -254,14 +256,14 @@ const EventModal: React.FC<EventModalProps> = ({ event, onClose }) => {
|
||||||
<div className="p-5">
|
<div className="p-5">
|
||||||
<h3 className="text-sm font-semibold text-gray-900 dark:text-white flex items-center gap-2 mb-4">
|
<h3 className="text-sm font-semibold text-gray-900 dark:text-white flex items-center gap-2 mb-4">
|
||||||
<FaCommentAlt className="w-4 h-4 text-green-500" />
|
<FaCommentAlt className="w-4 h-4 text-green-500" />
|
||||||
Yorumlar ({comments.length})
|
{translate('::App.Intranet.Events.Comments')} ({comments.length})
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{/* Comment List */}
|
{/* Comment List */}
|
||||||
<div className="space-y-4 mb-4 max-h-64 overflow-y-auto">
|
<div className="space-y-4 mb-4 max-h-64 overflow-y-auto">
|
||||||
{comments.length === 0 ? (
|
{comments.length === 0 ? (
|
||||||
<p className="text-sm text-gray-400 dark:text-gray-500 text-center py-6">
|
<p className="text-sm text-gray-400 dark:text-gray-500 text-center py-6">
|
||||||
Henüz yorum yok. İlk yorumu sen yap!
|
{translate('::App.Intranet.Events.EventComment')}
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
comments.map((comment) => (
|
comments.map((comment) => (
|
||||||
|
|
@ -298,9 +300,10 @@ const EventModal: React.FC<EventModalProps> = ({ event, onClose }) => {
|
||||||
<textarea
|
<textarea
|
||||||
ref={commentInputRef}
|
ref={commentInputRef}
|
||||||
value={commentText}
|
value={commentText}
|
||||||
|
autoFocus
|
||||||
onChange={(e) => setCommentText(e.target.value)}
|
onChange={(e) => setCommentText(e.target.value)}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
placeholder="Bir yorum yaz... (Enter ile gönder)"
|
placeholder={translate('::App.Intranet.Events.EventAttendance')}
|
||||||
rows={2}
|
rows={2}
|
||||||
className="flex-1 resize-none px-3 py-2 text-sm rounded-xl border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-green-500 transition-colors"
|
className="flex-1 resize-none px-3 py-2 text-sm rounded-xl border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-green-500 transition-colors"
|
||||||
/>
|
/>
|
||||||
|
|
@ -321,7 +324,7 @@ const EventModal: React.FC<EventModalProps> = ({ event, onClose }) => {
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="w-full px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors text-sm font-medium"
|
className="w-full px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-lg transition-colors text-sm font-medium"
|
||||||
>
|
>
|
||||||
Kapat
|
{translate('::App.Platform.Close')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ interface SurveyModalProps {
|
||||||
|
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit }) => {
|
const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit }) => {
|
||||||
const { translate } = useLocalization();
|
const { translate } = useLocalization()
|
||||||
const isUpdate = !!survey.myResponse
|
const isUpdate = !!survey.myResponse
|
||||||
|
|
||||||
const [answers, setAnswers] = useState<{ [questionId: string]: any }>(() => {
|
const [answers, setAnswers] = useState<{ [questionId: string]: any }>(() => {
|
||||||
|
|
@ -20,7 +20,7 @@ const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit })
|
||||||
survey.myResponse.answers.map((a) => [
|
survey.myResponse.answers.map((a) => [
|
||||||
a.questionId,
|
a.questionId,
|
||||||
a.questionType === 'rating' ? Number(a.value) : a.value,
|
a.questionType === 'rating' ? Number(a.value) : a.value,
|
||||||
])
|
]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
|
|
@ -48,7 +48,11 @@ const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit })
|
||||||
survey.questions.forEach((question) => {
|
survey.questions.forEach((question) => {
|
||||||
if (question.isRequired) {
|
if (question.isRequired) {
|
||||||
const val = answers[question.id]
|
const val = answers[question.id]
|
||||||
const isEmpty = val === undefined || val === null || val === '' || (question.type === 'rating' && Number(val) === 0)
|
const isEmpty =
|
||||||
|
val === undefined ||
|
||||||
|
val === null ||
|
||||||
|
val === '' ||
|
||||||
|
(question.type === 'rating' && Number(val) === 0)
|
||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
newErrors[question.id] = translate('::App.Platform.Intranet.SurveyModal.RequiredField')
|
newErrors[question.id] = translate('::App.Platform.Intranet.SurveyModal.RequiredField')
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +273,7 @@ const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit })
|
||||||
{!survey.isAnonymous && (
|
{!survey.isAnonymous && (
|
||||||
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-3">
|
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-3">
|
||||||
<p className="text-sm text-blue-700 dark:text-blue-300">
|
<p className="text-sm text-blue-700 dark:text-blue-300">
|
||||||
ℹ️ Bu anket isim belirtilerek doldurulmaktadır. Yanıtlarınız kaydedilecektir.
|
ℹ️ {translate('::App.Platform.Intranet.SurveyModal.RequiredUserName')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -277,7 +281,7 @@ const SurveyModal: React.FC<SurveyModalProps> = ({ survey, onClose, onSubmit })
|
||||||
{survey.isAnonymous && (
|
{survey.isAnonymous && (
|
||||||
<div className="bg-green-50 dark:bg-green-900/20 rounded-lg p-3">
|
<div className="bg-green-50 dark:bg-green-900/20 rounded-lg p-3">
|
||||||
<p className="text-sm text-green-700 dark:text-green-300">
|
<p className="text-sm text-green-700 dark:text-green-300">
|
||||||
✅ Bu anket anonimdir. Kimlik bilgileriniz kaydedilmeyecektir.
|
✅ {translate('::App.Platform.Intranet.SurveyModal.AnonymousNotice')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue