@hed-hog/lms 0.0.304 → 0.0.305

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (462) hide show
  1. package/README.md +413 -401
  2. package/dist/certificate/certificate.controller.d.ts +90 -0
  3. package/dist/certificate/certificate.controller.d.ts.map +1 -0
  4. package/dist/certificate/certificate.controller.js +121 -0
  5. package/dist/certificate/certificate.controller.js.map +1 -0
  6. package/dist/certificate/certificate.module.d.ts +3 -0
  7. package/dist/certificate/certificate.module.d.ts.map +1 -0
  8. package/dist/certificate/certificate.module.js +26 -0
  9. package/dist/certificate/certificate.module.js.map +1 -0
  10. package/dist/certificate/certificate.service.d.ts +115 -0
  11. package/dist/certificate/certificate.service.d.ts.map +1 -0
  12. package/dist/certificate/certificate.service.js +343 -0
  13. package/dist/certificate/certificate.service.js.map +1 -0
  14. package/dist/certificate/dto/create-certificate-template.dto.d.ts +8 -0
  15. package/dist/certificate/dto/create-certificate-template.dto.d.ts.map +1 -0
  16. package/dist/certificate/dto/create-certificate-template.dto.js +44 -0
  17. package/dist/certificate/dto/create-certificate-template.dto.js.map +1 -0
  18. package/dist/certificate/dto/update-certificate-template.dto.d.ts +6 -0
  19. package/dist/certificate/dto/update-certificate-template.dto.d.ts.map +1 -0
  20. package/dist/certificate/dto/update-certificate-template.dto.js +9 -0
  21. package/dist/certificate/dto/update-certificate-template.dto.js.map +1 -0
  22. package/dist/class-group/class-group.controller.d.ts +305 -0
  23. package/dist/class-group/class-group.controller.d.ts.map +1 -0
  24. package/dist/class-group/class-group.controller.js +257 -0
  25. package/dist/class-group/class-group.controller.js.map +1 -0
  26. package/dist/class-group/class-group.module.d.ts +3 -0
  27. package/dist/class-group/class-group.module.d.ts.map +1 -0
  28. package/dist/class-group/class-group.module.js +25 -0
  29. package/dist/class-group/class-group.module.js.map +1 -0
  30. package/dist/class-group/class-group.service.d.ts +354 -0
  31. package/dist/class-group/class-group.service.d.ts.map +1 -0
  32. package/dist/class-group/class-group.service.js +1356 -0
  33. package/dist/class-group/class-group.service.js.map +1 -0
  34. package/dist/class-group/dto/create-class-group.dto.d.ts +33 -0
  35. package/dist/class-group/dto/create-class-group.dto.d.ts.map +1 -0
  36. package/dist/class-group/dto/create-class-group.dto.js +165 -0
  37. package/dist/class-group/dto/create-class-group.dto.js.map +1 -0
  38. package/dist/class-group/dto/create-session.dto.d.ts +22 -0
  39. package/dist/class-group/dto/create-session.dto.d.ts.map +1 -0
  40. package/dist/class-group/dto/create-session.dto.js +117 -0
  41. package/dist/class-group/dto/create-session.dto.js.map +1 -0
  42. package/dist/class-group/dto/enrollment.dto.d.ts +22 -0
  43. package/dist/class-group/dto/enrollment.dto.d.ts.map +1 -0
  44. package/dist/class-group/dto/enrollment.dto.js +89 -0
  45. package/dist/class-group/dto/enrollment.dto.js.map +1 -0
  46. package/dist/class-group/dto/update-class-group.dto.d.ts +6 -0
  47. package/dist/class-group/dto/update-class-group.dto.d.ts.map +1 -0
  48. package/dist/class-group/dto/update-class-group.dto.js +9 -0
  49. package/dist/class-group/dto/update-class-group.dto.js.map +1 -0
  50. package/dist/class-group/dto/update-session.dto.d.ts +7 -0
  51. package/dist/class-group/dto/update-session.dto.d.ts.map +1 -0
  52. package/dist/class-group/dto/update-session.dto.js +24 -0
  53. package/dist/class-group/dto/update-session.dto.js.map +1 -0
  54. package/dist/course/course-structure.controller.d.ts +127 -0
  55. package/dist/course/course-structure.controller.d.ts.map +1 -0
  56. package/dist/course/course-structure.controller.js +115 -0
  57. package/dist/course/course-structure.controller.js.map +1 -0
  58. package/dist/course/course-structure.service.d.ts +142 -0
  59. package/dist/course/course-structure.service.d.ts.map +1 -0
  60. package/dist/course/course-structure.service.js +445 -0
  61. package/dist/course/course-structure.service.js.map +1 -0
  62. package/dist/course/course.controller.d.ts +195 -0
  63. package/dist/course/course.controller.d.ts.map +1 -0
  64. package/dist/course/course.controller.js +104 -0
  65. package/dist/course/course.controller.js.map +1 -0
  66. package/dist/course/course.module.d.ts +3 -0
  67. package/dist/course/course.module.d.ts.map +1 -0
  68. package/dist/course/course.module.js +28 -0
  69. package/dist/course/course.module.js.map +1 -0
  70. package/dist/course/course.service.d.ts +215 -0
  71. package/dist/course/course.service.d.ts.map +1 -0
  72. package/dist/course/course.service.js +743 -0
  73. package/dist/course/course.service.js.map +1 -0
  74. package/dist/course/dto/create-course-structure-lesson.dto.d.ts +24 -0
  75. package/dist/course/dto/create-course-structure-lesson.dto.d.ts.map +1 -0
  76. package/dist/course/dto/create-course-structure-lesson.dto.js +118 -0
  77. package/dist/course/dto/create-course-structure-lesson.dto.js.map +1 -0
  78. package/dist/course/dto/create-course-structure-session.dto.d.ts +7 -0
  79. package/dist/course/dto/create-course-structure-session.dto.d.ts.map +1 -0
  80. package/dist/course/dto/create-course-structure-session.dto.js +40 -0
  81. package/dist/course/dto/create-course-structure-session.dto.js.map +1 -0
  82. package/dist/course/dto/create-course.dto.d.ts +26 -0
  83. package/dist/course/dto/create-course.dto.d.ts.map +1 -0
  84. package/dist/course/dto/create-course.dto.js +138 -0
  85. package/dist/course/dto/create-course.dto.js.map +1 -0
  86. package/dist/course/dto/update-course-structure-lesson.dto.d.ts +6 -0
  87. package/dist/course/dto/update-course-structure-lesson.dto.d.ts.map +1 -0
  88. package/dist/course/dto/update-course-structure-lesson.dto.js +9 -0
  89. package/dist/course/dto/update-course-structure-lesson.dto.js.map +1 -0
  90. package/dist/course/dto/update-course-structure-session.dto.d.ts +6 -0
  91. package/dist/course/dto/update-course-structure-session.dto.d.ts.map +1 -0
  92. package/dist/course/dto/update-course-structure-session.dto.js +9 -0
  93. package/dist/course/dto/update-course-structure-session.dto.js.map +1 -0
  94. package/dist/course/dto/update-course.dto.d.ts +6 -0
  95. package/dist/course/dto/update-course.dto.d.ts.map +1 -0
  96. package/dist/course/dto/update-course.dto.js +9 -0
  97. package/dist/course/dto/update-course.dto.js.map +1 -0
  98. package/dist/dashboard/dashboard.controller.d.ts +101 -0
  99. package/dist/dashboard/dashboard.controller.d.ts.map +1 -0
  100. package/dist/dashboard/dashboard.controller.js +40 -0
  101. package/dist/dashboard/dashboard.controller.js.map +1 -0
  102. package/dist/dashboard/dashboard.module.d.ts +3 -0
  103. package/dist/dashboard/dashboard.module.d.ts.map +1 -0
  104. package/dist/dashboard/dashboard.module.js +25 -0
  105. package/dist/dashboard/dashboard.module.js.map +1 -0
  106. package/dist/dashboard/dashboard.service.d.ts +130 -0
  107. package/dist/dashboard/dashboard.service.d.ts.map +1 -0
  108. package/dist/dashboard/dashboard.service.js +626 -0
  109. package/dist/dashboard/dashboard.service.js.map +1 -0
  110. package/dist/enterprise/dto/add-enterprise-class-group.dto.d.ts +4 -0
  111. package/dist/enterprise/dto/add-enterprise-class-group.dto.d.ts.map +1 -0
  112. package/dist/enterprise/dto/add-enterprise-class-group.dto.js +22 -0
  113. package/dist/enterprise/dto/add-enterprise-class-group.dto.js.map +1 -0
  114. package/dist/enterprise/dto/add-enterprise-course.dto.d.ts +5 -0
  115. package/dist/enterprise/dto/add-enterprise-course.dto.d.ts.map +1 -0
  116. package/dist/enterprise/dto/add-enterprise-course.dto.js +27 -0
  117. package/dist/enterprise/dto/add-enterprise-course.dto.js.map +1 -0
  118. package/dist/enterprise/dto/add-enterprise-lead.dto.d.ts +4 -0
  119. package/dist/enterprise/dto/add-enterprise-lead.dto.d.ts.map +1 -0
  120. package/dist/enterprise/dto/add-enterprise-lead.dto.js +22 -0
  121. package/dist/enterprise/dto/add-enterprise-lead.dto.js.map +1 -0
  122. package/dist/enterprise/dto/add-enterprise-student.dto.d.ts +5 -0
  123. package/dist/enterprise/dto/add-enterprise-student.dto.d.ts.map +1 -0
  124. package/dist/enterprise/dto/add-enterprise-student.dto.js +27 -0
  125. package/dist/enterprise/dto/add-enterprise-student.dto.js.map +1 -0
  126. package/dist/enterprise/dto/add-enterprise-user.dto.d.ts +7 -0
  127. package/dist/enterprise/dto/add-enterprise-user.dto.d.ts.map +1 -0
  128. package/dist/enterprise/dto/add-enterprise-user.dto.js +36 -0
  129. package/dist/enterprise/dto/add-enterprise-user.dto.js.map +1 -0
  130. package/dist/enterprise/dto/create-enterprise.dto.d.ts +10 -0
  131. package/dist/enterprise/dto/create-enterprise.dto.d.ts.map +1 -0
  132. package/dist/enterprise/dto/create-enterprise.dto.js +54 -0
  133. package/dist/enterprise/dto/create-enterprise.dto.js.map +1 -0
  134. package/dist/enterprise/dto/update-enterprise-student.dto.d.ts +4 -0
  135. package/dist/enterprise/dto/update-enterprise-student.dto.d.ts.map +1 -0
  136. package/dist/enterprise/dto/update-enterprise-student.dto.js +22 -0
  137. package/dist/enterprise/dto/update-enterprise-student.dto.js.map +1 -0
  138. package/dist/enterprise/dto/update-enterprise-user.dto.d.ts +5 -0
  139. package/dist/enterprise/dto/update-enterprise-user.dto.d.ts.map +1 -0
  140. package/dist/enterprise/dto/update-enterprise-user.dto.js +27 -0
  141. package/dist/enterprise/dto/update-enterprise-user.dto.js.map +1 -0
  142. package/dist/enterprise/dto/update-enterprise.dto.d.ts +6 -0
  143. package/dist/enterprise/dto/update-enterprise.dto.d.ts.map +1 -0
  144. package/dist/enterprise/dto/update-enterprise.dto.js +9 -0
  145. package/dist/enterprise/dto/update-enterprise.dto.js.map +1 -0
  146. package/dist/enterprise/enterprise.controller.d.ts +269 -0
  147. package/dist/enterprise/enterprise.controller.d.ts.map +1 -0
  148. package/dist/enterprise/enterprise.controller.js +311 -0
  149. package/dist/enterprise/enterprise.controller.js.map +1 -0
  150. package/dist/enterprise/enterprise.module.d.ts +3 -0
  151. package/dist/enterprise/enterprise.module.d.ts.map +1 -0
  152. package/dist/enterprise/enterprise.module.js +25 -0
  153. package/dist/enterprise/enterprise.module.js.map +1 -0
  154. package/dist/enterprise/enterprise.service.d.ts +282 -0
  155. package/dist/enterprise/enterprise.service.d.ts.map +1 -0
  156. package/dist/enterprise/enterprise.service.js +627 -0
  157. package/dist/enterprise/enterprise.service.js.map +1 -0
  158. package/dist/evaluation/evaluation.controller.d.ts +56 -0
  159. package/dist/evaluation/evaluation.controller.d.ts.map +1 -0
  160. package/dist/evaluation/evaluation.controller.js +76 -0
  161. package/dist/evaluation/evaluation.controller.js.map +1 -0
  162. package/dist/evaluation/evaluation.module.d.ts +3 -0
  163. package/dist/evaluation/evaluation.module.d.ts.map +1 -0
  164. package/dist/evaluation/evaluation.module.js +25 -0
  165. package/dist/evaluation/evaluation.module.js.map +1 -0
  166. package/dist/evaluation/evaluation.service.d.ts +67 -0
  167. package/dist/evaluation/evaluation.service.d.ts.map +1 -0
  168. package/dist/evaluation/evaluation.service.js +378 -0
  169. package/dist/evaluation/evaluation.service.js.map +1 -0
  170. package/dist/exam/dto/create-exam-question.dto.d.ts +25 -0
  171. package/dist/exam/dto/create-exam-question.dto.d.ts.map +1 -0
  172. package/dist/exam/dto/create-exam-question.dto.js +117 -0
  173. package/dist/exam/dto/create-exam-question.dto.js.map +1 -0
  174. package/dist/exam/dto/create-exam.dto.d.ts +11 -0
  175. package/dist/exam/dto/create-exam.dto.d.ts.map +1 -0
  176. package/dist/exam/dto/create-exam.dto.js +63 -0
  177. package/dist/exam/dto/create-exam.dto.js.map +1 -0
  178. package/dist/exam/dto/reorder-exam-questions.dto.d.ts +4 -0
  179. package/dist/exam/dto/reorder-exam-questions.dto.d.ts.map +1 -0
  180. package/dist/exam/dto/reorder-exam-questions.dto.js +23 -0
  181. package/dist/exam/dto/reorder-exam-questions.dto.js.map +1 -0
  182. package/dist/exam/dto/save-exam-attempt-answers.dto.d.ts +14 -0
  183. package/dist/exam/dto/save-exam-attempt-answers.dto.d.ts.map +1 -0
  184. package/dist/exam/dto/save-exam-attempt-answers.dto.js +68 -0
  185. package/dist/exam/dto/save-exam-attempt-answers.dto.js.map +1 -0
  186. package/dist/exam/dto/start-exam-attempt.dto.d.ts +4 -0
  187. package/dist/exam/dto/start-exam-attempt.dto.d.ts.map +1 -0
  188. package/dist/exam/dto/start-exam-attempt.dto.js +23 -0
  189. package/dist/exam/dto/start-exam-attempt.dto.js.map +1 -0
  190. package/dist/exam/dto/submit-exam-attempt.dto.d.ts +5 -0
  191. package/dist/exam/dto/submit-exam-attempt.dto.d.ts.map +1 -0
  192. package/dist/exam/dto/submit-exam-attempt.dto.js +23 -0
  193. package/dist/exam/dto/submit-exam-attempt.dto.js.map +1 -0
  194. package/dist/exam/dto/update-exam-question.dto.d.ts +6 -0
  195. package/dist/exam/dto/update-exam-question.dto.d.ts.map +1 -0
  196. package/dist/exam/dto/update-exam-question.dto.js +9 -0
  197. package/dist/exam/dto/update-exam-question.dto.js.map +1 -0
  198. package/dist/exam/dto/update-exam.dto.d.ts +6 -0
  199. package/dist/exam/dto/update-exam.dto.d.ts.map +1 -0
  200. package/dist/exam/dto/update-exam.dto.js +9 -0
  201. package/dist/exam/dto/update-exam.dto.js.map +1 -0
  202. package/dist/exam/exam-attempt.controller.d.ts +273 -0
  203. package/dist/exam/exam-attempt.controller.d.ts.map +1 -0
  204. package/dist/exam/exam-attempt.controller.js +84 -0
  205. package/dist/exam/exam-attempt.controller.js.map +1 -0
  206. package/dist/exam/exam-attempt.service.d.ts +302 -0
  207. package/dist/exam/exam-attempt.service.d.ts.map +1 -0
  208. package/dist/exam/exam-attempt.service.js +776 -0
  209. package/dist/exam/exam-attempt.service.js.map +1 -0
  210. package/dist/exam/exam.controller.d.ts +162 -0
  211. package/dist/exam/exam.controller.d.ts.map +1 -0
  212. package/dist/exam/exam.controller.js +158 -0
  213. package/dist/exam/exam.controller.js.map +1 -0
  214. package/dist/exam/exam.module.d.ts +3 -0
  215. package/dist/exam/exam.module.d.ts.map +1 -0
  216. package/dist/exam/exam.module.js +27 -0
  217. package/dist/exam/exam.module.js.map +1 -0
  218. package/dist/exam/exam.service.d.ts +179 -0
  219. package/dist/exam/exam.service.d.ts.map +1 -0
  220. package/dist/exam/exam.service.js +597 -0
  221. package/dist/exam/exam.service.js.map +1 -0
  222. package/dist/index.d.ts +28 -0
  223. package/dist/index.d.ts.map +1 -1
  224. package/dist/index.js +28 -0
  225. package/dist/index.js.map +1 -1
  226. package/dist/instructor/dto/create-instructor.dto.d.ts +10 -0
  227. package/dist/instructor/dto/create-instructor.dto.d.ts.map +1 -0
  228. package/dist/instructor/dto/create-instructor.dto.js +55 -0
  229. package/dist/instructor/dto/create-instructor.dto.js.map +1 -0
  230. package/dist/instructor/dto/update-instructor.dto.d.ts +9 -0
  231. package/dist/instructor/dto/update-instructor.dto.d.ts.map +1 -0
  232. package/dist/instructor/dto/update-instructor.dto.js +51 -0
  233. package/dist/instructor/dto/update-instructor.dto.js.map +1 -0
  234. package/dist/instructor/instructor.controller.d.ts +52 -0
  235. package/dist/instructor/instructor.controller.d.ts.map +1 -0
  236. package/dist/instructor/instructor.controller.js +98 -0
  237. package/dist/instructor/instructor.controller.js.map +1 -0
  238. package/dist/instructor/instructor.module.d.ts +3 -0
  239. package/dist/instructor/instructor.module.d.ts.map +1 -0
  240. package/dist/instructor/instructor.module.js +25 -0
  241. package/dist/instructor/instructor.module.js.map +1 -0
  242. package/dist/instructor/instructor.service.d.ts +79 -0
  243. package/dist/instructor/instructor.service.d.ts.map +1 -0
  244. package/dist/instructor/instructor.service.js +528 -0
  245. package/dist/instructor/instructor.service.js.map +1 -0
  246. package/dist/lms.module.d.ts.map +1 -1
  247. package/dist/lms.module.js +36 -4
  248. package/dist/lms.module.js.map +1 -1
  249. package/dist/reports/reports.controller.d.ts +69 -0
  250. package/dist/reports/reports.controller.d.ts.map +1 -0
  251. package/dist/reports/reports.controller.js +40 -0
  252. package/dist/reports/reports.controller.js.map +1 -0
  253. package/dist/reports/reports.module.d.ts +3 -0
  254. package/dist/reports/reports.module.d.ts.map +1 -0
  255. package/dist/reports/reports.module.js +25 -0
  256. package/dist/reports/reports.module.js.map +1 -0
  257. package/dist/reports/reports.service.d.ts +80 -0
  258. package/dist/reports/reports.service.d.ts.map +1 -0
  259. package/dist/reports/reports.service.js +366 -0
  260. package/dist/reports/reports.service.js.map +1 -0
  261. package/dist/training/dto/create-training.dto.d.ts +19 -0
  262. package/dist/training/dto/create-training.dto.d.ts.map +1 -0
  263. package/dist/training/dto/create-training.dto.js +98 -0
  264. package/dist/training/dto/create-training.dto.js.map +1 -0
  265. package/dist/training/dto/update-training.dto.d.ts +6 -0
  266. package/dist/training/dto/update-training.dto.d.ts.map +1 -0
  267. package/dist/training/dto/update-training.dto.js +9 -0
  268. package/dist/training/dto/update-training.dto.js.map +1 -0
  269. package/dist/training/training.controller.d.ts +195 -0
  270. package/dist/training/training.controller.d.ts.map +1 -0
  271. package/dist/training/training.controller.js +104 -0
  272. package/dist/training/training.controller.js.map +1 -0
  273. package/dist/training/training.module.d.ts +3 -0
  274. package/dist/training/training.module.d.ts.map +1 -0
  275. package/dist/training/training.module.js +25 -0
  276. package/dist/training/training.module.js.map +1 -0
  277. package/dist/training/training.service.d.ts +213 -0
  278. package/dist/training/training.service.d.ts.map +1 -0
  279. package/dist/training/training.service.js +497 -0
  280. package/dist/training/training.service.js.map +1 -0
  281. package/hedhog/data/dashboard.yaml +6 -0
  282. package/hedhog/data/dashboard_component.yaml +153 -0
  283. package/hedhog/data/dashboard_component_role.yaml +97 -0
  284. package/hedhog/data/dashboard_item.yaml +167 -0
  285. package/hedhog/data/dashboard_role.yaml +6 -0
  286. package/hedhog/data/instructor_qualification.yaml +16 -0
  287. package/hedhog/data/menu.yaml +129 -19
  288. package/hedhog/data/role.yaml +25 -1
  289. package/hedhog/data/route.yaml +867 -0
  290. package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +1992 -0
  291. package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +480 -0
  292. package/hedhog/frontend/app/_components/create-lms-instructor-sheet.tsx.ejs +591 -0
  293. package/hedhog/frontend/app/_components/create-lms-person-sheet.tsx.ejs +164 -0
  294. package/hedhog/frontend/app/_components/create-lms-student-person-sheet.tsx.ejs +120 -0
  295. package/hedhog/frontend/app/_components/lms-class-calendar.tsx.ejs +272 -0
  296. package/hedhog/frontend/app/_components/mobile-calendar.tsx.ejs +277 -0
  297. package/hedhog/frontend/app/_lib/editor/canvasInstance.ts.ejs +48 -0
  298. package/hedhog/frontend/app/_lib/editor/pctHelpers.ts.ejs +50 -0
  299. package/hedhog/frontend/app/_lib/editor/templateSerializer.ts.ejs +268 -0
  300. package/hedhog/frontend/app/_lib/editor/types.ts.ejs +94 -0
  301. package/hedhog/frontend/app/_lib/store/useTemplateStore.ts.ejs +284 -0
  302. package/hedhog/frontend/app/certificates/issued/page.tsx.ejs +638 -0
  303. package/hedhog/frontend/app/certificates/models/CanvasStage.tsx.ejs +916 -0
  304. package/hedhog/frontend/app/certificates/models/LeftPanel.tsx.ejs +200 -0
  305. package/hedhog/frontend/app/certificates/models/RightPanel.tsx.ejs +769 -0
  306. package/hedhog/frontend/app/certificates/models/TemplateEditorPage.tsx.ejs +104 -0
  307. package/hedhog/frontend/app/certificates/models/TopBar.tsx.ejs +354 -0
  308. package/hedhog/frontend/app/certificates/models/editor/page.tsx.ejs +5 -0
  309. package/hedhog/frontend/app/certificates/models/page.tsx.ejs +883 -0
  310. package/hedhog/frontend/app/classes/[id]/_components/event-summary-popover.tsx.ejs +279 -0
  311. package/hedhog/frontend/app/classes/[id]/_components/quick-create-session-popover.tsx.ejs +1027 -0
  312. package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +3130 -993
  313. package/hedhog/frontend/app/classes/page.tsx.ejs +2731 -759
  314. package/hedhog/frontend/app/courses/[id]/_components/CourseCertificateCard.tsx.ejs +80 -0
  315. package/hedhog/frontend/app/courses/[id]/_components/CourseClassificationCard.tsx.ejs +226 -0
  316. package/hedhog/frontend/app/courses/[id]/_components/CourseContentCard.tsx.ejs +71 -0
  317. package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +42 -0
  318. package/hedhog/frontend/app/courses/[id]/_components/CourseFlagsCard.tsx.ejs +111 -0
  319. package/hedhog/frontend/app/courses/[id]/_components/CourseMainInfoCard.tsx.ejs +113 -0
  320. package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +215 -0
  321. package/hedhog/frontend/app/courses/[id]/_components/CourseMultiEntityPicker.tsx.ejs +236 -0
  322. package/hedhog/frontend/app/courses/[id]/_components/CourseRelationsCard.tsx.ejs +141 -0
  323. package/hedhog/frontend/app/courses/[id]/_components/CourseSectionCard.tsx.ejs +57 -0
  324. package/hedhog/frontend/app/courses/[id]/_components/CourseSummaryCard.tsx.ejs +60 -0
  325. package/hedhog/frontend/app/courses/[id]/_components/course-edit-types.ts.ejs +33 -0
  326. package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +933 -1103
  327. package/hedhog/frontend/app/courses/[id]/structure/page.tsx.ejs +699 -117
  328. package/hedhog/frontend/app/courses/page.tsx.ejs +1018 -1042
  329. package/hedhog/frontend/app/enterprise/[id]/page.tsx.ejs +317 -0
  330. package/hedhog/frontend/app/enterprise/_components/enterprise-activity-panel.tsx.ejs +88 -0
  331. package/hedhog/frontend/app/enterprise/_components/enterprise-admin-create-sheet.tsx.ejs +318 -0
  332. package/hedhog/frontend/app/enterprise/_components/enterprise-administrators-tab.tsx.ejs +332 -0
  333. package/hedhog/frontend/app/enterprise/_components/enterprise-class-create-sheet.tsx.ejs +57 -0
  334. package/hedhog/frontend/app/enterprise/_components/enterprise-classes-tab.tsx.ejs +390 -0
  335. package/hedhog/frontend/app/enterprise/_components/enterprise-company-identity-card.tsx.ejs +112 -0
  336. package/hedhog/frontend/app/enterprise/_components/enterprise-course-create-sheet.tsx.ejs +183 -0
  337. package/hedhog/frontend/app/enterprise/_components/enterprise-courses-tab.tsx.ejs +363 -0
  338. package/hedhog/frontend/app/enterprise/_components/enterprise-detail-constants.ts.ejs +88 -0
  339. package/hedhog/frontend/app/enterprise/_components/enterprise-detail-sheet.tsx.ejs +548 -0
  340. package/hedhog/frontend/app/enterprise/_components/enterprise-detail-utils.ts.ejs +33 -0
  341. package/hedhog/frontend/app/enterprise/_components/enterprise-mocks.ts.ejs +266 -0
  342. package/hedhog/frontend/app/enterprise/_components/enterprise-person-picker.ts.ejs +31 -0
  343. package/hedhog/frontend/app/enterprise/_components/enterprise-progress-bar.tsx.ejs +21 -0
  344. package/hedhog/frontend/app/enterprise/_components/enterprise-related-tab.tsx.ejs +187 -0
  345. package/hedhog/frontend/app/enterprise/_components/enterprise-sheet.tsx.ejs +397 -0
  346. package/hedhog/frontend/app/enterprise/_components/enterprise-student-create-sheet.tsx.ejs +167 -0
  347. package/hedhog/frontend/app/enterprise/_components/enterprise-students-tab.tsx.ejs +267 -0
  348. package/hedhog/frontend/app/enterprise/_components/enterprise-system-user-picker.ts.ejs +42 -0
  349. package/hedhog/frontend/app/enterprise/_components/enterprise-types.ts.ejs +96 -0
  350. package/hedhog/frontend/app/enterprise/_components/enterprise-user-create-sheet.tsx.ejs +207 -0
  351. package/hedhog/frontend/app/enterprise/_components/enterprise-user-distribution-chart.tsx.ejs +149 -0
  352. package/hedhog/frontend/app/enterprise/page.tsx.ejs +596 -0
  353. package/hedhog/frontend/app/evaluations/page.tsx.ejs +1250 -0
  354. package/hedhog/frontend/app/exams/[id]/attempt/page.tsx.ejs +642 -196
  355. package/hedhog/frontend/app/exams/[id]/page.tsx.ejs +11 -0
  356. package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +1316 -436
  357. package/hedhog/frontend/app/exams/page.tsx.ejs +799 -546
  358. package/hedhog/frontend/app/layout.tsx.ejs +5 -0
  359. package/hedhog/frontend/app/page.tsx.ejs +5 -1222
  360. package/hedhog/frontend/app/reports/courses/page.tsx.ejs +843 -0
  361. package/hedhog/frontend/app/reports/dashboard/page.tsx.ejs +890 -0
  362. package/hedhog/frontend/app/reports/page.tsx.ejs +802 -808
  363. package/hedhog/frontend/app/reports/students/page.tsx.ejs +772 -0
  364. package/hedhog/frontend/app/training/page.tsx.ejs +1873 -628
  365. package/hedhog/frontend/messages/en.json +1606 -111
  366. package/hedhog/frontend/messages/pt.json +1636 -134
  367. package/hedhog/frontend/widgets/active-classes-kpi.tsx.ejs +74 -0
  368. package/hedhog/frontend/widgets/active-courses-kpi.tsx.ejs +74 -0
  369. package/hedhog/frontend/widgets/approval-rate-kpi.tsx.ejs +81 -0
  370. package/hedhog/frontend/widgets/category-distribution-chart.tsx.ejs +119 -0
  371. package/hedhog/frontend/widgets/class-calendar.tsx.ejs +440 -0
  372. package/hedhog/frontend/widgets/completion-rate-kpi.tsx.ejs +81 -0
  373. package/hedhog/frontend/widgets/engagement-chart.tsx.ejs +120 -0
  374. package/hedhog/frontend/widgets/footer-summary.tsx.ejs +80 -0
  375. package/hedhog/frontend/widgets/issued-certificates-kpi.tsx.ejs +74 -0
  376. package/hedhog/frontend/widgets/latest-enrollments.tsx.ejs +166 -0
  377. package/hedhog/frontend/widgets/student-growth-chart.tsx.ejs +89 -0
  378. package/hedhog/frontend/widgets/top-courses-chart.tsx.ejs +104 -0
  379. package/hedhog/frontend/widgets/total-students-kpi.tsx.ejs +78 -0
  380. package/hedhog/frontend/widgets/upcoming-classes.tsx.ejs +152 -0
  381. package/hedhog/table/course.yaml +28 -10
  382. package/hedhog/table/course_class_group.yaml +8 -0
  383. package/hedhog/table/course_class_session.yaml +33 -0
  384. package/hedhog/table/course_instructor.yaml +27 -0
  385. package/hedhog/table/enterprise.yaml +29 -0
  386. package/hedhog/table/enterprise_class_group.yaml +20 -0
  387. package/hedhog/table/enterprise_course.yaml +23 -0
  388. package/hedhog/table/enterprise_student.yaml +24 -0
  389. package/hedhog/table/enterprise_user.yaml +35 -0
  390. package/hedhog/table/instructor_qualification.yaml +26 -0
  391. package/hedhog/table/instructor_qualification_assignment.yaml +22 -0
  392. package/hedhog/table/question.yaml +6 -0
  393. package/package.json +7 -7
  394. package/src/certificate/certificate.controller.ts +83 -0
  395. package/src/certificate/certificate.module.ts +13 -0
  396. package/src/certificate/certificate.service.ts +413 -0
  397. package/src/certificate/dto/create-certificate-template.dto.ts +25 -0
  398. package/src/certificate/dto/update-certificate-template.dto.ts +6 -0
  399. package/src/class-group/class-group.controller.ts +189 -0
  400. package/src/class-group/class-group.module.ts +12 -0
  401. package/src/class-group/class-group.service.ts +1802 -0
  402. package/src/class-group/dto/create-class-group.dto.ts +139 -0
  403. package/src/class-group/dto/create-session.dto.ts +102 -0
  404. package/src/class-group/dto/enrollment.dto.ts +70 -0
  405. package/src/class-group/dto/update-class-group.dto.ts +4 -0
  406. package/src/class-group/dto/update-session.dto.ts +9 -0
  407. package/src/course/course-structure.controller.ts +85 -0
  408. package/src/course/course-structure.service.ts +525 -0
  409. package/src/course/course.controller.ts +69 -0
  410. package/src/course/course.module.ts +15 -0
  411. package/src/course/course.service.ts +920 -0
  412. package/src/course/dto/create-course-structure-lesson.dto.ts +97 -0
  413. package/src/course/dto/create-course-structure-session.dto.ts +22 -0
  414. package/src/course/dto/create-course.dto.ts +111 -0
  415. package/src/course/dto/update-course-structure-lesson.dto.ts +6 -0
  416. package/src/course/dto/update-course-structure-session.dto.ts +6 -0
  417. package/src/course/dto/update-course.dto.ts +4 -0
  418. package/src/dashboard/dashboard.controller.ts +14 -0
  419. package/src/dashboard/dashboard.module.ts +12 -0
  420. package/src/dashboard/dashboard.service.ts +726 -0
  421. package/src/enterprise/dto/add-enterprise-class-group.dto.ts +7 -0
  422. package/src/enterprise/dto/add-enterprise-course.dto.ts +11 -0
  423. package/src/enterprise/dto/add-enterprise-student.dto.ts +16 -0
  424. package/src/enterprise/dto/add-enterprise-user.dto.ts +23 -0
  425. package/src/enterprise/dto/create-enterprise.dto.ts +41 -0
  426. package/src/enterprise/dto/update-enterprise-student.dto.ts +7 -0
  427. package/src/enterprise/dto/update-enterprise-user.dto.ts +11 -0
  428. package/src/enterprise/dto/update-enterprise.dto.ts +4 -0
  429. package/src/enterprise/enterprise.controller.ts +233 -0
  430. package/src/enterprise/enterprise.module.ts +12 -0
  431. package/src/enterprise/enterprise.service.ts +712 -0
  432. package/src/evaluation/evaluation.controller.ts +44 -0
  433. package/src/evaluation/evaluation.module.ts +12 -0
  434. package/src/evaluation/evaluation.service.ts +394 -0
  435. package/src/exam/dto/create-exam-question.dto.ts +103 -0
  436. package/src/exam/dto/create-exam.dto.ts +41 -0
  437. package/src/exam/dto/reorder-exam-questions.dto.ts +8 -0
  438. package/src/exam/dto/save-exam-attempt-answers.dto.ts +55 -0
  439. package/src/exam/dto/start-exam-attempt.dto.ts +8 -0
  440. package/src/exam/dto/submit-exam-attempt.dto.ts +8 -0
  441. package/src/exam/dto/update-exam-question.dto.ts +4 -0
  442. package/src/exam/dto/update-exam.dto.ts +4 -0
  443. package/src/exam/exam-attempt.controller.ts +65 -0
  444. package/src/exam/exam-attempt.service.ts +1008 -0
  445. package/src/exam/exam.controller.ts +102 -0
  446. package/src/exam/exam.module.ts +14 -0
  447. package/src/exam/exam.service.ts +784 -0
  448. package/src/index.ts +29 -0
  449. package/src/instructor/dto/create-instructor.dto.ts +43 -0
  450. package/src/instructor/dto/update-instructor.dto.ts +38 -0
  451. package/src/instructor/instructor.controller.ts +73 -0
  452. package/src/instructor/instructor.module.ts +12 -0
  453. package/src/instructor/instructor.service.ts +646 -0
  454. package/src/lms.module.ts +36 -4
  455. package/src/reports/reports.controller.ts +14 -0
  456. package/src/reports/reports.module.ts +12 -0
  457. package/src/reports/reports.service.ts +485 -0
  458. package/src/training/dto/create-training.dto.ts +81 -0
  459. package/src/training/dto/update-training.dto.ts +4 -0
  460. package/src/training/training.controller.ts +68 -0
  461. package/src/training/training.module.ts +12 -0
  462. package/src/training/training.service.ts +574 -0
@@ -1,1222 +1,5 @@
1
- 'use client';
2
-
3
- import { Page, PageHeader } from '@/components/entity-list';
4
- import { Avatar, AvatarFallback } from '@/components/ui/avatar';
5
- import { Badge } from '@/components/ui/badge';
6
- import { Button } from '@/components/ui/button';
7
- import {
8
- Card,
9
- CardContent,
10
- CardDescription,
11
- CardHeader,
12
- CardTitle,
13
- } from '@/components/ui/card';
14
- import { Skeleton } from '@/components/ui/skeleton';
15
- import {
16
- Table,
17
- TableBody,
18
- TableCell,
19
- TableHead,
20
- TableHeader,
21
- TableRow,
22
- } from '@/components/ui/table';
23
- import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
24
- import {
25
- addDays,
26
- format,
27
- getDay,
28
- parse,
29
- setHours,
30
- setMinutes,
31
- startOfWeek,
32
- } from 'date-fns';
33
- import { ptBR } from 'date-fns/locale/pt-BR';
34
- import { motion, type Variants } from 'framer-motion';
35
- import {
36
- Award,
37
- BarChart3,
38
- BookOpen,
39
- CalendarDays,
40
- CheckCircle2,
41
- ChevronLeft,
42
- ChevronRight,
43
- FileCheck,
44
- GraduationCap,
45
- LayoutDashboard,
46
- Percent,
47
- TrendingDown,
48
- TrendingUp,
49
- Users,
50
- } from 'lucide-react';
51
- import { useTranslations } from 'next-intl';
52
- import { usePathname } from 'next/navigation';
53
- import { useCallback, useEffect, useMemo, useState } from 'react';
54
- import { Calendar, dateFnsLocalizer, type View } from 'react-big-calendar';
55
- import 'react-big-calendar/lib/css/react-big-calendar.css';
56
- import {
57
- Area,
58
- AreaChart,
59
- Bar,
60
- BarChart,
61
- CartesianGrid,
62
- Cell,
63
- Line,
64
- LineChart,
65
- Pie,
66
- PieChart,
67
- ResponsiveContainer,
68
- Tooltip,
69
- XAxis,
70
- YAxis,
71
- } from 'recharts';
72
-
73
- // ── Navigation ─────────────────────────────────────────────────────────────────
74
-
75
- const NAV_ITEMS = [
76
- { label: 'Dashboard', href: '/', icon: LayoutDashboard },
77
- { label: 'Cursos', href: '/cursos', icon: BookOpen },
78
- { label: 'Turmas', href: '/turmas', icon: Users },
79
- { label: 'Exames', href: '/exames', icon: FileCheck },
80
- { label: 'Formacoes', href: '/formacoes', icon: GraduationCap },
81
- { label: 'Relatorios', href: '/relatorios', icon: BarChart3 },
82
- ];
83
-
84
- // ── Big Calendar localizer ─────────────────────────────────────────────────────
85
-
86
- const locales = { 'pt-BR': ptBR };
87
-
88
- const localizer = dateFnsLocalizer({
89
- format,
90
- parse,
91
- startOfWeek: () => startOfWeek(new Date(), { weekStartsOn: 1 }),
92
- getDay,
93
- locales,
94
- });
95
-
96
- // ── Mock Data ──────────────────────────────────────────────────────────────────
97
-
98
- const growthData = [
99
- { mes: 'Jul', alunos: 1820 },
100
- { mes: 'Ago', alunos: 1950 },
101
- { mes: 'Set', alunos: 2100 },
102
- { mes: 'Out', alunos: 2280 },
103
- { mes: 'Nov', alunos: 2540 },
104
- { mes: 'Dez', alunos: 2690 },
105
- { mes: 'Jan', alunos: 2847 },
106
- ];
107
-
108
- const engagementData = [
109
- { semana: 'S1', acessos: 820, videoAssistidos: 340, exercicios: 150 },
110
- { semana: 'S2', acessos: 950, videoAssistidos: 420, exercicios: 200 },
111
- { semana: 'S3', acessos: 870, videoAssistidos: 380, exercicios: 180 },
112
- { semana: 'S4', acessos: 1100, videoAssistidos: 510, exercicios: 260 },
113
- { semana: 'S5', acessos: 1250, videoAssistidos: 580, exercicios: 310 },
114
- { semana: 'S6', acessos: 1180, videoAssistidos: 540, exercicios: 290 },
115
- { semana: 'S7', acessos: 1350, videoAssistidos: 620, exercicios: 350 },
116
- { semana: 'S8', acessos: 1420, videoAssistidos: 680, exercicios: 380 },
117
- ];
118
-
119
- const topCoursesData = [
120
- { curso: 'React Avancado', acessos: 847 },
121
- { curso: 'Python IA', acessos: 723 },
122
- { curso: 'UX Design', acessos: 651 },
123
- { curso: 'Node.js API', acessos: 582 },
124
- { curso: 'Data Science', acessos: 498 },
125
- { curso: 'Flutter', acessos: 412 },
126
- ];
127
-
128
- const categoryDistribution = [
129
- { nome: 'Tecnologia', valor: 38 },
130
- { nome: 'Design', valor: 22 },
131
- { nome: 'Gestao', valor: 18 },
132
- { nome: 'Marketing', valor: 14 },
133
- { nome: 'Outros', valor: 8 },
134
- ];
135
-
136
- const PIE_COLORS = [
137
- 'oklch(0.205 0 0)',
138
- 'oklch(0.45 0 0)',
139
- 'oklch(0.60 0 0)',
140
- 'oklch(0.75 0 0)',
141
- 'oklch(0.87 0 0)',
142
- ];
143
-
144
- const today = new Date();
145
-
146
- function genCalendarEvents() {
147
- const turmas = [
148
- { nome: 'React Avancado - T01', cor: 'oklch(0.205 0 0)' },
149
- { nome: 'Python IA - T02', cor: 'oklch(0.45 0 0)' },
150
- { nome: 'UX Design - T01', cor: 'oklch(0.60 0 0)' },
151
- { nome: 'Node.js API - T03', cor: 'oklch(0.35 0 0)' },
152
- { nome: 'Data Science - T01', cor: 'oklch(0.50 0 0)' },
153
- ];
154
- const events: {
155
- title: string;
156
- start: Date;
157
- end: Date;
158
- resource: { cor: string };
159
- }[] = [];
160
- for (let d = -14; d <= 30; d++) {
161
- const dia = addDays(today, d);
162
- const dayOfWeek = dia.getDay();
163
- if (dayOfWeek === 0 || dayOfWeek === 6) continue;
164
- const numAulas = dayOfWeek % 2 === 0 ? 3 : 2;
165
- for (let a = 0; a < numAulas; a++) {
166
- const turma = turmas[(d + 14 + a) % turmas.length]!;
167
- const horaInicio = 8 + a * 3;
168
- events.push({
169
- title: turma.nome,
170
- start: setMinutes(setHours(dia, horaInicio), 0),
171
- end: setMinutes(setHours(dia, horaInicio + 2), 0),
172
- resource: { cor: turma.cor },
173
- });
174
- }
175
- }
176
- return events;
177
- }
178
-
179
- const enrollments = [
180
- {
181
- id: 1,
182
- aluno: 'Ana Costa',
183
- email: 'ana.costa@email.com',
184
- curso: 'React Avancado',
185
- data: '01/03/2026',
186
- status: 'Confirmada',
187
- },
188
- {
189
- id: 2,
190
- aluno: 'Bruno Silva',
191
- email: 'bruno.s@email.com',
192
- curso: 'Python IA',
193
- data: '28/02/2026',
194
- status: 'Confirmada',
195
- },
196
- {
197
- id: 3,
198
- aluno: 'Carla Santos',
199
- email: 'carla.s@email.com',
200
- curso: 'UX Design',
201
- data: '28/02/2026',
202
- status: 'Pendente',
203
- },
204
- {
205
- id: 4,
206
- aluno: 'Daniel Rocha',
207
- email: 'daniel.r@email.com',
208
- curso: 'Node.js API',
209
- data: '27/02/2026',
210
- status: 'Confirmada',
211
- },
212
- {
213
- id: 5,
214
- aluno: 'Elena Martins',
215
- email: 'elena.m@email.com',
216
- curso: 'Data Science',
217
- data: '27/02/2026',
218
- status: 'Confirmada',
219
- },
220
- {
221
- id: 6,
222
- aluno: 'Fabio Lima',
223
- email: 'fabio.l@email.com',
224
- curso: 'Flutter',
225
- data: '26/02/2026',
226
- status: 'Pendente',
227
- },
228
- {
229
- id: 7,
230
- aluno: 'Gisele Alves',
231
- email: 'gisele.a@email.com',
232
- curso: 'React Avancado',
233
- data: '26/02/2026',
234
- status: 'Confirmada',
235
- },
236
- {
237
- id: 8,
238
- aluno: 'Hugo Pereira',
239
- email: 'hugo.p@email.com',
240
- curso: 'Python IA',
241
- data: '25/02/2026',
242
- status: 'Confirmada',
243
- },
244
- {
245
- id: 9,
246
- aluno: 'Isabela Nunes',
247
- email: 'isabela.n@email.com',
248
- curso: 'UX Design',
249
- data: '25/02/2026',
250
- status: 'Cancelada',
251
- },
252
- {
253
- id: 10,
254
- aluno: 'Joao Mendes',
255
- email: 'joao.m@email.com',
256
- curso: 'Data Science',
257
- data: '24/02/2026',
258
- status: 'Confirmada',
259
- },
260
- {
261
- id: 11,
262
- aluno: 'Karen Oliveira',
263
- email: 'karen.o@email.com',
264
- curso: 'Node.js API',
265
- data: '24/02/2026',
266
- status: 'Confirmada',
267
- },
268
- {
269
- id: 12,
270
- aluno: 'Lucas Ferreira',
271
- email: 'lucas.f@email.com',
272
- curso: 'Flutter',
273
- data: '23/02/2026',
274
- status: 'Pendente',
275
- },
276
- ];
277
-
278
- const nextClasses = [
279
- {
280
- id: 1,
281
- turma: 'React Avancado - T01',
282
- disciplina: 'Hooks Avancados',
283
- professor: 'Prof. Marcos',
284
- data: '02/03/2026',
285
- horario: '08:00 - 10:00',
286
- },
287
- {
288
- id: 2,
289
- turma: 'Python IA - T02',
290
- disciplina: 'Redes Neurais',
291
- professor: 'Prof. Lucia',
292
- data: '02/03/2026',
293
- horario: '10:30 - 12:30',
294
- },
295
- {
296
- id: 3,
297
- turma: 'UX Design - T01',
298
- disciplina: 'Prototipagem',
299
- professor: 'Prof. Renata',
300
- data: '02/03/2026',
301
- horario: '14:00 - 16:00',
302
- },
303
- {
304
- id: 4,
305
- turma: 'Node.js API - T03',
306
- disciplina: 'Auth & JWT',
307
- professor: 'Prof. Andre',
308
- data: '03/03/2026',
309
- horario: '08:00 - 10:00',
310
- },
311
- {
312
- id: 5,
313
- turma: 'Data Science - T01',
314
- disciplina: 'Visualizacao',
315
- professor: 'Prof. Paulo',
316
- data: '03/03/2026',
317
- horario: '10:30 - 12:30',
318
- },
319
- {
320
- id: 6,
321
- turma: 'React Avancado - T01',
322
- disciplina: 'Context API',
323
- professor: 'Prof. Marcos',
324
- data: '04/03/2026',
325
- horario: '08:00 - 10:00',
326
- },
327
- {
328
- id: 7,
329
- turma: 'Python IA - T02',
330
- disciplina: 'CNN',
331
- professor: 'Prof. Lucia',
332
- data: '04/03/2026',
333
- horario: '10:30 - 12:30',
334
- },
335
- {
336
- id: 8,
337
- turma: 'Flutter - T01',
338
- disciplina: 'Widgets',
339
- professor: 'Prof. Thiago',
340
- data: '05/03/2026',
341
- horario: '14:00 - 16:00',
342
- },
343
- {
344
- id: 9,
345
- turma: 'UX Design - T01',
346
- disciplina: 'Testes A/B',
347
- professor: 'Prof. Renata',
348
- data: '05/03/2026',
349
- horario: '08:00 - 10:00',
350
- },
351
- {
352
- id: 10,
353
- turma: 'Node.js API - T03',
354
- disciplina: 'WebSockets',
355
- professor: 'Prof. Andre',
356
- data: '06/03/2026',
357
- horario: '08:00 - 10:00',
358
- },
359
- ];
360
-
361
- // ── Helpers ────────────────────────────────────────────────────────────────────
362
-
363
- const ITEMS_PER_PAGE = 5;
364
-
365
- function getInitials(name: string) {
366
- return name
367
- .split(' ')
368
- .map((n) => n[0])
369
- .join('')
370
- .toUpperCase()
371
- .slice(0, 2);
372
- }
373
-
374
- function statusColor(status: string) {
375
- if (status === 'Confirmada') return 'bg-emerald-100 text-emerald-700';
376
- if (status === 'Pendente') return 'bg-amber-100 text-amber-700';
377
- return 'bg-red-100 text-red-700';
378
- }
379
-
380
- // ── Chart Tooltip Style ────────────────────────────────────────────────────────
381
-
382
- const chartTooltipStyle = {
383
- backgroundColor: 'hsl(var(--card))',
384
- border: '1px solid hsl(var(--border))',
385
- borderRadius: '8px',
386
- fontSize: '12px',
387
- boxShadow: '0 4px 6px -1px rgba(0,0,0,0.1)',
388
- };
389
-
390
- // ── Container Animations ───────────────────────────────────────────────────────
391
-
392
- const stagger = {
393
- hidden: {},
394
- show: { transition: { staggerChildren: 0.08 } },
395
- };
396
-
397
- const fadeUp: Variants = {
398
- hidden: { opacity: 0, y: 16 },
399
- show: { opacity: 1, y: 0, transition: { duration: 0.35, ease: 'easeOut' } },
400
- };
401
-
402
- // ── Component ──────────────────────────────────────────────────────────────────
403
-
404
- export default function DashboardPage() {
405
- const t = useTranslations('lms.DashboardPage');
406
-
407
- const pathname = usePathname();
408
- const [loading, setLoading] = useState(true);
409
- const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
410
-
411
- // Calendar
412
- const [calendarView, setCalendarView] = useState<View>('month');
413
- const [calendarDate, setCalendarDate] = useState(today);
414
- const calendarEvents = useMemo(() => genCalendarEvents(), []);
415
-
416
- // Table pagination
417
- const [enrollPage, setEnrollPage] = useState(1);
418
- const [classesPage, setClassesPage] = useState(1);
419
-
420
- useEffect(() => {
421
- const timer = setTimeout(() => setLoading(false), 1000);
422
- return () => clearTimeout(timer);
423
- }, []);
424
-
425
- const enrollTotalPages = Math.ceil(enrollments.length / ITEMS_PER_PAGE);
426
- const pagedEnrollments = enrollments.slice(
427
- (enrollPage - 1) * ITEMS_PER_PAGE,
428
- enrollPage * ITEMS_PER_PAGE
429
- );
430
-
431
- const classesTotalPages = Math.ceil(nextClasses.length / ITEMS_PER_PAGE);
432
- const pagedClasses = nextClasses.slice(
433
- (classesPage - 1) * ITEMS_PER_PAGE,
434
- classesPage * ITEMS_PER_PAGE
435
- );
436
-
437
- const eventStyleGetter = useCallback(
438
- (event: { resource?: { cor?: string } }) => ({
439
- style: {
440
- backgroundColor: event.resource?.cor ?? 'oklch(0.205 0 0)',
441
- border: 'none',
442
- borderRadius: '4px',
443
- color: '#fff',
444
- fontSize: '0.75rem',
445
- padding: '2px 6px',
446
- },
447
- }),
448
- []
449
- );
450
-
451
- const calendarMessages = useMemo(
452
- () => ({
453
- today: 'Hoje',
454
- previous: 'Anterior',
455
- next: 'Proximo',
456
- month: 'Mes',
457
- week: 'Semana',
458
- day: 'Dia',
459
- agenda: 'Agenda',
460
- date: 'Data',
461
- time: 'Hora',
462
- event: 'Evento',
463
- noEventsInRange: 'Sem aulas neste periodo.',
464
- showMore: (count: number) => `+${count} mais`,
465
- }),
466
- []
467
- );
468
-
469
- const kpis = [
470
- {
471
- titulo: 'Total de Alunos',
472
- valor: '2.847',
473
- variacao: '+12.5%',
474
- positivo: true,
475
- icone: Users,
476
- descricao: 'vs. mes anterior',
477
- },
478
- {
479
- titulo: 'Cursos Ativos',
480
- valor: '48',
481
- variacao: '+3',
482
- positivo: true,
483
- icone: BookOpen,
484
- descricao: 'novos este mes',
485
- },
486
- {
487
- titulo: 'Turmas Ativas',
488
- valor: '24',
489
- variacao: '+5',
490
- positivo: true,
491
- icone: CalendarDays,
492
- descricao: 'em andamento',
493
- },
494
- {
495
- titulo: 'Certificados Emitidos',
496
- valor: '1.203',
497
- variacao: '+87',
498
- positivo: true,
499
- icone: Award,
500
- descricao: 'este mes',
501
- },
502
- {
503
- titulo: 'Taxa de Conclusao',
504
- valor: '78.3%',
505
- variacao: '+2.1%',
506
- positivo: true,
507
- icone: CheckCircle2,
508
- descricao: 'media geral',
509
- },
510
- {
511
- titulo: 'Taxa de Aprovacao',
512
- valor: '84.7%',
513
- variacao: '-0.8%',
514
- positivo: false,
515
- icone: Percent,
516
- descricao: 'nos exames',
517
- },
518
- ];
519
-
520
- return (
521
- <Page>
522
- <PageHeader
523
- title={t('title')}
524
- description={t('description')}
525
- breadcrumbs={[
526
- {
527
- label: t('breadcrumbs.home'),
528
- href: '/',
529
- },
530
- {
531
- label: t('breadcrumbs.lms'),
532
- },
533
- ]}
534
- />
535
-
536
- {/* ── Main Content ──────────────────────────────────────────────────── */}
537
-
538
- <motion.div initial="hidden" animate="show" variants={stagger}>
539
- {/* ── KPIs ────────────────────────────────────────────────────────── */}
540
- <div className="mb-8 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-6">
541
- {kpis.map((kpi, i) => (
542
- <motion.div key={kpi.titulo} variants={fadeUp}>
543
- {loading ? (
544
- <Card>
545
- <CardContent className="p-5">
546
- <Skeleton className="mb-3 h-4 w-24" />
547
- <Skeleton className="mb-2 h-8 w-20" />
548
- <Skeleton className="h-3 w-32" />
549
- </CardContent>
550
- </Card>
551
- ) : (
552
- <motion.div
553
- whileHover={{ y: -2 }}
554
- transition={{ duration: 0.2 }}
555
- >
556
- <Card className="transition-shadow hover:shadow-md">
557
- <CardContent className="p-5">
558
- <div className="flex items-center justify-between">
559
- <p className="text-xs font-medium text-muted-foreground">
560
- {kpi.titulo}
561
- </p>
562
- <div className="flex size-8 items-center justify-center rounded-lg bg-muted">
563
- <kpi.icone className="size-4 text-muted-foreground" />
564
- </div>
565
- </div>
566
- <p className="mt-2 text-2xl font-bold tracking-tight">
567
- {kpi.valor}
568
- </p>
569
- <div className="mt-1.5 flex items-center gap-1.5">
570
- {kpi.positivo ? (
571
- <span className="flex items-center gap-0.5 rounded-full bg-emerald-50 px-1.5 py-0.5 text-[11px] font-semibold text-emerald-700">
572
- <TrendingUp className="size-3" />
573
- {kpi.variacao}
574
- </span>
575
- ) : (
576
- <span className="flex items-center gap-0.5 rounded-full bg-red-50 px-1.5 py-0.5 text-[11px] font-semibold text-red-600">
577
- <TrendingDown className="size-3" />
578
- {kpi.variacao}
579
- </span>
580
- )}
581
- <span className="text-[11px] text-muted-foreground">
582
- {kpi.descricao}
583
- </span>
584
- </div>
585
- </CardContent>
586
- </Card>
587
- </motion.div>
588
- )}
589
- </motion.div>
590
- ))}
591
- </div>
592
-
593
- {/* ── Charts Row 1 ────────────────────────────────────────────────── */}
594
- <div className="mb-8 grid grid-cols-1 gap-4 lg:grid-cols-7">
595
- {/* Line chart - Crescimento de alunos */}
596
- <motion.div className="lg:col-span-4" variants={fadeUp}>
597
- {loading ? (
598
- <Card>
599
- <CardContent className="p-6">
600
- <Skeleton className="mb-4 h-5 w-48" />
601
- <Skeleton className="h-[300px] w-full" />
602
- </CardContent>
603
- </Card>
604
- ) : (
605
- <Card>
606
- <CardHeader className="pb-2">
607
- <CardTitle className="text-sm font-semibold">
608
- Crescimento de Alunos
609
- </CardTitle>
610
- <CardDescription>
611
- Evolucao mensal do total de matriculas
612
- </CardDescription>
613
- </CardHeader>
614
- <CardContent>
615
- <ResponsiveContainer width="100%" height={300}>
616
- <LineChart data={growthData}>
617
- <CartesianGrid
618
- strokeDasharray="3 3"
619
- stroke="hsl(var(--border))"
620
- />
621
- <XAxis
622
- dataKey="mes"
623
- fontSize={12}
624
- tickLine={false}
625
- axisLine={false}
626
- />
627
- <YAxis fontSize={12} tickLine={false} axisLine={false} />
628
- <Tooltip contentStyle={chartTooltipStyle} />
629
- <Line
630
- type="monotone"
631
- dataKey="alunos"
632
- stroke="oklch(0.205 0 0)"
633
- strokeWidth={2.5}
634
- dot={{
635
- r: 4,
636
- fill: 'oklch(0.205 0 0)',
637
- strokeWidth: 2,
638
- stroke: '#fff',
639
- }}
640
- activeDot={{ r: 6 }}
641
- name="Alunos"
642
- />
643
- </LineChart>
644
- </ResponsiveContainer>
645
- </CardContent>
646
- </Card>
647
- )}
648
- </motion.div>
649
-
650
- {/* Area chart - Engajamento */}
651
- <motion.div className="lg:col-span-3" variants={fadeUp}>
652
- {loading ? (
653
- <Card>
654
- <CardContent className="p-6">
655
- <Skeleton className="mb-4 h-5 w-40" />
656
- <Skeleton className="h-[300px] w-full" />
657
- </CardContent>
658
- </Card>
659
- ) : (
660
- <Card>
661
- <CardHeader className="pb-2">
662
- <CardTitle className="text-sm font-semibold">
663
- Engajamento
664
- </CardTitle>
665
- <CardDescription>
666
- Acessos, videos e exercicios por semana
667
- </CardDescription>
668
- </CardHeader>
669
- <CardContent>
670
- <ResponsiveContainer width="100%" height={300}>
671
- <AreaChart data={engagementData}>
672
- <defs>
673
- <linearGradient
674
- id="colorAcessos"
675
- x1="0"
676
- y1="0"
677
- x2="0"
678
- y2="1"
679
- >
680
- <stop
681
- offset="5%"
682
- stopColor="oklch(0.205 0 0)"
683
- stopOpacity={0.15}
684
- />
685
- <stop
686
- offset="95%"
687
- stopColor="oklch(0.205 0 0)"
688
- stopOpacity={0}
689
- />
690
- </linearGradient>
691
- <linearGradient
692
- id="colorVideos"
693
- x1="0"
694
- y1="0"
695
- x2="0"
696
- y2="1"
697
- >
698
- <stop
699
- offset="5%"
700
- stopColor="oklch(0.55 0 0)"
701
- stopOpacity={0.15}
702
- />
703
- <stop
704
- offset="95%"
705
- stopColor="oklch(0.55 0 0)"
706
- stopOpacity={0}
707
- />
708
- </linearGradient>
709
- </defs>
710
- <CartesianGrid
711
- strokeDasharray="3 3"
712
- stroke="hsl(var(--border))"
713
- />
714
- <XAxis
715
- dataKey="semana"
716
- fontSize={12}
717
- tickLine={false}
718
- axisLine={false}
719
- />
720
- <YAxis fontSize={12} tickLine={false} axisLine={false} />
721
- <Tooltip contentStyle={chartTooltipStyle} />
722
- <Area
723
- type="monotone"
724
- dataKey="acessos"
725
- stroke="oklch(0.205 0 0)"
726
- strokeWidth={2}
727
- fill="url(#colorAcessos)"
728
- name="Acessos"
729
- />
730
- <Area
731
- type="monotone"
732
- dataKey="videoAssistidos"
733
- stroke="oklch(0.55 0 0)"
734
- strokeWidth={2}
735
- fill="url(#colorVideos)"
736
- name="Videos"
737
- />
738
- <Area
739
- type="monotone"
740
- dataKey="exercicios"
741
- stroke="oklch(0.75 0 0)"
742
- strokeWidth={1.5}
743
- fill="none"
744
- name="Exercicios"
745
- />
746
- </AreaChart>
747
- </ResponsiveContainer>
748
- </CardContent>
749
- </Card>
750
- )}
751
- </motion.div>
752
- </div>
753
-
754
- {/* ── Charts Row 2 ────────────────────────────────────────────────── */}
755
- <div className="mb-8 grid grid-cols-1 gap-4 lg:grid-cols-7">
756
- {/* Bar chart - Cursos mais acessados */}
757
- <motion.div className="lg:col-span-4" variants={fadeUp}>
758
- {loading ? (
759
- <Card>
760
- <CardContent className="p-6">
761
- <Skeleton className="mb-4 h-5 w-48" />
762
- <Skeleton className="h-[300px] w-full" />
763
- </CardContent>
764
- </Card>
765
- ) : (
766
- <Card>
767
- <CardHeader className="pb-2">
768
- <CardTitle className="text-sm font-semibold">
769
- Cursos Mais Acessados
770
- </CardTitle>
771
- <CardDescription>
772
- Ranking por numero de acessos este mes
773
- </CardDescription>
774
- </CardHeader>
775
- <CardContent>
776
- <ResponsiveContainer width="100%" height={300}>
777
- <BarChart data={topCoursesData} layout="vertical">
778
- <CartesianGrid
779
- strokeDasharray="3 3"
780
- stroke="hsl(var(--border))"
781
- horizontal={false}
782
- />
783
- <XAxis
784
- type="number"
785
- fontSize={12}
786
- tickLine={false}
787
- axisLine={false}
788
- />
789
- <YAxis
790
- type="category"
791
- dataKey="curso"
792
- fontSize={12}
793
- tickLine={false}
794
- axisLine={false}
795
- width={110}
796
- />
797
- <Tooltip contentStyle={chartTooltipStyle} />
798
- <Bar
799
- dataKey="acessos"
800
- fill="oklch(0.205 0 0)"
801
- radius={[0, 4, 4, 0]}
802
- name="Acessos"
803
- barSize={24}
804
- />
805
- </BarChart>
806
- </ResponsiveContainer>
807
- </CardContent>
808
- </Card>
809
- )}
810
- </motion.div>
811
-
812
- {/* Pie chart - Distribuicao por categoria */}
813
- <motion.div className="lg:col-span-3" variants={fadeUp}>
814
- {loading ? (
815
- <Card>
816
- <CardContent className="p-6">
817
- <Skeleton className="mb-4 h-5 w-48" />
818
- <Skeleton className="mx-auto h-[220px] w-[220px] rounded-full" />
819
- </CardContent>
820
- </Card>
821
- ) : (
822
- <Card>
823
- <CardHeader className="pb-2">
824
- <CardTitle className="text-sm font-semibold">
825
- Distribuicao por Categoria
826
- </CardTitle>
827
- <CardDescription>
828
- Percentual de cursos ativos por area
829
- </CardDescription>
830
- </CardHeader>
831
- <CardContent className="flex flex-col items-center">
832
- <ResponsiveContainer width="100%" height={220}>
833
- <PieChart>
834
- <Pie
835
- data={categoryDistribution}
836
- cx="50%"
837
- cy="50%"
838
- innerRadius={55}
839
- outerRadius={85}
840
- dataKey="valor"
841
- nameKey="nome"
842
- strokeWidth={3}
843
- stroke="hsl(var(--background))"
844
- >
845
- {categoryDistribution.map((_, index) => (
846
- <Cell
847
- key={`cell-${index}`}
848
- fill={PIE_COLORS[index]}
849
- />
850
- ))}
851
- </Pie>
852
- <Tooltip
853
- contentStyle={chartTooltipStyle}
854
- formatter={(value: number) => [
855
- `${value}%`,
856
- 'Percentual',
857
- ]}
858
- />
859
- </PieChart>
860
- </ResponsiveContainer>
861
- <div className="mt-3 flex flex-wrap justify-center gap-x-4 gap-y-2">
862
- {categoryDistribution.map((item, i) => (
863
- <div
864
- key={item.nome}
865
- className="flex items-center gap-1.5 text-xs"
866
- >
867
- <span
868
- className="inline-block size-2.5 rounded-full"
869
- style={{ backgroundColor: PIE_COLORS[i] }}
870
- />
871
- <span className="text-muted-foreground">
872
- {item.nome} ({item.valor}%)
873
- </span>
874
- </div>
875
- ))}
876
- </div>
877
- </CardContent>
878
- </Card>
879
- )}
880
- </motion.div>
881
- </div>
882
-
883
- {/* ── Calendar ────────────────────────────────────────────────────── */}
884
- <motion.div className="mb-8" variants={fadeUp}>
885
- {loading ? (
886
- <Card>
887
- <CardContent className="p-6">
888
- <Skeleton className="mb-4 h-5 w-40" />
889
- <Skeleton className="h-[500px] w-full rounded-lg" />
890
- </CardContent>
891
- </Card>
892
- ) : (
893
- <Card>
894
- <CardHeader className="pb-2">
895
- <CardTitle className="text-sm font-semibold">
896
- Calendario Global de Aulas
897
- </CardTitle>
898
- <CardDescription>
899
- Todas as aulas de todas as turmas
900
- </CardDescription>
901
- </CardHeader>
902
- <CardContent>
903
- <div className="h-[520px] lg:h-[580px]">
904
- <Calendar
905
- localizer={localizer}
906
- events={calendarEvents}
907
- startAccessor="start"
908
- endAccessor="end"
909
- view={calendarView}
910
- onView={(v) => setCalendarView(v)}
911
- date={calendarDate}
912
- onNavigate={(d) => setCalendarDate(d)}
913
- views={['month', 'week']}
914
- messages={calendarMessages}
915
- eventPropGetter={eventStyleGetter}
916
- culture="pt-BR"
917
- popup
918
- style={{ height: '100%' }}
919
- />
920
- </div>
921
- </CardContent>
922
- </Card>
923
- )}
924
- </motion.div>
925
-
926
- {/* ── Tables ──────────────────────────────────────────────────────── */}
927
- <motion.div className="mb-8" variants={fadeUp}>
928
- <Tabs defaultValue="matriculas">
929
- <TabsList className="mb-4">
930
- <TabsTrigger value="matriculas">Ultimas Matriculas</TabsTrigger>
931
- <TabsTrigger value="aulas">Proximas Aulas</TabsTrigger>
932
- </TabsList>
933
-
934
- {/* ─ Tab: Matriculas ─ */}
935
- <TabsContent value="matriculas">
936
- {loading ? (
937
- <Card>
938
- <CardContent className="p-6">
939
- {Array.from({ length: 5 }).map((_, i) => (
940
- <div key={i} className="mb-4 flex items-center gap-4">
941
- <Skeleton className="size-10 rounded-full" />
942
- <div className="flex-1">
943
- <Skeleton className="mb-2 h-4 w-40" />
944
- <Skeleton className="h-3 w-24" />
945
- </div>
946
- <Skeleton className="h-6 w-20" />
947
- </div>
948
- ))}
949
- </CardContent>
950
- </Card>
951
- ) : (
952
- <Card>
953
- <CardHeader className="pb-2">
954
- <CardTitle className="text-sm font-semibold">
955
- Ultimas Matriculas
956
- </CardTitle>
957
- <CardDescription>
958
- {enrollments.length} matriculas recentes
959
- </CardDescription>
960
- </CardHeader>
961
- <CardContent>
962
- <div className="overflow-x-auto">
963
- <Table>
964
- <TableHeader>
965
- <TableRow>
966
- <TableHead>Aluno</TableHead>
967
- <TableHead className="hidden sm:table-cell">
968
- Email
969
- </TableHead>
970
- <TableHead>Curso</TableHead>
971
- <TableHead className="hidden md:table-cell">
972
- Data
973
- </TableHead>
974
- <TableHead>Status</TableHead>
975
- </TableRow>
976
- </TableHeader>
977
- <TableBody>
978
- {pagedEnrollments.map((m) => (
979
- <TableRow key={m.id}>
980
- <TableCell>
981
- <div className="flex items-center gap-2.5">
982
- <Avatar className="size-8">
983
- <AvatarFallback className="bg-foreground text-[10px] font-medium text-background">
984
- {getInitials(m.aluno)}
985
- </AvatarFallback>
986
- </Avatar>
987
- <span className="font-medium">{m.aluno}</span>
988
- </div>
989
- </TableCell>
990
- <TableCell className="hidden text-muted-foreground sm:table-cell">
991
- {m.email}
992
- </TableCell>
993
- <TableCell>{m.curso}</TableCell>
994
- <TableCell className="hidden text-muted-foreground md:table-cell">
995
- {m.data}
996
- </TableCell>
997
- <TableCell>
998
- <span
999
- className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-semibold ${statusColor(m.status)}`}
1000
- >
1001
- {m.status}
1002
- </span>
1003
- </TableCell>
1004
- </TableRow>
1005
- ))}
1006
- </TableBody>
1007
- </Table>
1008
- </div>
1009
-
1010
- {/* Pagination */}
1011
- <div className="mt-4 flex items-center justify-between border-t pt-4">
1012
- <p className="text-xs text-muted-foreground">
1013
- Mostrando {(enrollPage - 1) * ITEMS_PER_PAGE + 1} -{' '}
1014
- {Math.min(
1015
- enrollPage * ITEMS_PER_PAGE,
1016
- enrollments.length
1017
- )}{' '}
1018
- de {enrollments.length}
1019
- </p>
1020
- <div className="flex items-center gap-1">
1021
- <Button
1022
- variant="outline"
1023
- size="icon"
1024
- className="size-8"
1025
- disabled={enrollPage === 1}
1026
- onClick={() => setEnrollPage((p) => p - 1)}
1027
- aria-label="Pagina anterior"
1028
- >
1029
- <ChevronLeft className="size-4" />
1030
- </Button>
1031
- {Array.from({ length: enrollTotalPages }).map(
1032
- (_, i) => (
1033
- <Button
1034
- key={i}
1035
- variant={
1036
- enrollPage === i + 1 ? 'default' : 'outline'
1037
- }
1038
- size="icon"
1039
- className="size-8 text-xs"
1040
- onClick={() => setEnrollPage(i + 1)}
1041
- >
1042
- {i + 1}
1043
- </Button>
1044
- )
1045
- )}
1046
- <Button
1047
- variant="outline"
1048
- size="icon"
1049
- className="size-8"
1050
- disabled={enrollPage === enrollTotalPages}
1051
- onClick={() => setEnrollPage((p) => p + 1)}
1052
- aria-label="Proxima pagina"
1053
- >
1054
- <ChevronRight className="size-4" />
1055
- </Button>
1056
- </div>
1057
- </div>
1058
- </CardContent>
1059
- </Card>
1060
- )}
1061
- </TabsContent>
1062
-
1063
- {/* ─ Tab: Proximas Aulas ─ */}
1064
- <TabsContent value="aulas">
1065
- {loading ? (
1066
- <Card>
1067
- <CardContent className="p-6">
1068
- {Array.from({ length: 5 }).map((_, i) => (
1069
- <div key={i} className="mb-4 flex items-center gap-4">
1070
- <Skeleton className="size-8 rounded-lg" />
1071
- <div className="flex-1">
1072
- <Skeleton className="mb-2 h-4 w-48" />
1073
- <Skeleton className="h-3 w-32" />
1074
- </div>
1075
- <Skeleton className="h-6 w-28" />
1076
- </div>
1077
- ))}
1078
- </CardContent>
1079
- </Card>
1080
- ) : (
1081
- <Card>
1082
- <CardHeader className="pb-2">
1083
- <CardTitle className="text-sm font-semibold">
1084
- Proximas Aulas
1085
- </CardTitle>
1086
- <CardDescription>
1087
- Agenda das proximas aulas programadas
1088
- </CardDescription>
1089
- </CardHeader>
1090
- <CardContent>
1091
- <div className="overflow-x-auto">
1092
- <Table>
1093
- <TableHeader>
1094
- <TableRow>
1095
- <TableHead>Turma</TableHead>
1096
- <TableHead>Disciplina</TableHead>
1097
- <TableHead className="hidden sm:table-cell">
1098
- Professor
1099
- </TableHead>
1100
- <TableHead>Data</TableHead>
1101
- <TableHead className="hidden md:table-cell">
1102
- Horario
1103
- </TableHead>
1104
- </TableRow>
1105
- </TableHeader>
1106
- <TableBody>
1107
- {pagedClasses.map((aula) => (
1108
- <TableRow key={aula.id}>
1109
- <TableCell>
1110
- <div className="flex items-center gap-2">
1111
- <div className="flex size-8 items-center justify-center rounded-lg bg-muted">
1112
- <BookOpen className="size-3.5 text-muted-foreground" />
1113
- </div>
1114
- <span className="font-medium">
1115
- {aula.turma}
1116
- </span>
1117
- </div>
1118
- </TableCell>
1119
- <TableCell>{aula.disciplina}</TableCell>
1120
- <TableCell className="hidden text-muted-foreground sm:table-cell">
1121
- {aula.professor}
1122
- </TableCell>
1123
- <TableCell>
1124
- <Badge
1125
- variant="outline"
1126
- className="text-xs font-normal"
1127
- >
1128
- {aula.data}
1129
- </Badge>
1130
- </TableCell>
1131
- <TableCell className="hidden text-muted-foreground md:table-cell">
1132
- {aula.horario}
1133
- </TableCell>
1134
- </TableRow>
1135
- ))}
1136
- </TableBody>
1137
- </Table>
1138
- </div>
1139
-
1140
- {/* Pagination */}
1141
- <div className="mt-4 flex items-center justify-between border-t pt-4">
1142
- <p className="text-xs text-muted-foreground">
1143
- Mostrando {(classesPage - 1) * ITEMS_PER_PAGE + 1} -{' '}
1144
- {Math.min(
1145
- classesPage * ITEMS_PER_PAGE,
1146
- nextClasses.length
1147
- )}{' '}
1148
- de {nextClasses.length}
1149
- </p>
1150
- <div className="flex items-center gap-1">
1151
- <Button
1152
- variant="outline"
1153
- size="icon"
1154
- className="size-8"
1155
- disabled={classesPage === 1}
1156
- onClick={() => setClassesPage((p) => p - 1)}
1157
- aria-label="Pagina anterior"
1158
- >
1159
- <ChevronLeft className="size-4" />
1160
- </Button>
1161
- {Array.from({ length: classesTotalPages }).map(
1162
- (_, i) => (
1163
- <Button
1164
- key={i}
1165
- variant={
1166
- classesPage === i + 1 ? 'default' : 'outline'
1167
- }
1168
- size="icon"
1169
- className="size-8 text-xs"
1170
- onClick={() => setClassesPage(i + 1)}
1171
- >
1172
- {i + 1}
1173
- </Button>
1174
- )
1175
- )}
1176
- <Button
1177
- variant="outline"
1178
- size="icon"
1179
- className="size-8"
1180
- disabled={classesPage === classesTotalPages}
1181
- onClick={() => setClassesPage((p) => p + 1)}
1182
- aria-label="Proxima pagina"
1183
- >
1184
- <ChevronRight className="size-4" />
1185
- </Button>
1186
- </div>
1187
- </div>
1188
- </CardContent>
1189
- </Card>
1190
- )}
1191
- </TabsContent>
1192
- </Tabs>
1193
- </motion.div>
1194
-
1195
- {/* ── Footer status ──────────────────────────────────────────────── */}
1196
- {!loading && (
1197
- <motion.div variants={fadeUp}>
1198
- <Card>
1199
- <CardContent className="flex flex-wrap items-center justify-between gap-4 p-4">
1200
- <div className="flex items-center gap-2.5">
1201
- <Badge
1202
- variant="secondary"
1203
- className="gap-1.5 text-xs font-medium"
1204
- >
1205
- <span className="inline-block size-2 rounded-full bg-emerald-500" />
1206
- Sistema Operacional
1207
- </Badge>
1208
- </div>
1209
- <div className="flex flex-wrap gap-x-6 gap-y-1 text-xs text-muted-foreground">
1210
- <span>24 turmas ativas</span>
1211
- <span>48 cursos publicados</span>
1212
- <span>2.847 alunos matriculados</span>
1213
- <span>1.203 certificados</span>
1214
- </div>
1215
- </CardContent>
1216
- </Card>
1217
- </motion.div>
1218
- )}
1219
- </motion.div>
1220
- </Page>
1221
- );
1222
- }
1
+ import { redirect } from 'next/navigation';
2
+
3
+ export default function LmsPage() {
4
+ redirect('/lms/courses');
5
+ }