@hed-hog/lms 0.0.304 → 0.0.306

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 (458) 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-student.dto.d.ts +5 -0
  119. package/dist/enterprise/dto/add-enterprise-student.dto.d.ts.map +1 -0
  120. package/dist/enterprise/dto/add-enterprise-student.dto.js +27 -0
  121. package/dist/enterprise/dto/add-enterprise-student.dto.js.map +1 -0
  122. package/dist/enterprise/dto/add-enterprise-user.dto.d.ts +7 -0
  123. package/dist/enterprise/dto/add-enterprise-user.dto.d.ts.map +1 -0
  124. package/dist/enterprise/dto/add-enterprise-user.dto.js +36 -0
  125. package/dist/enterprise/dto/add-enterprise-user.dto.js.map +1 -0
  126. package/dist/enterprise/dto/create-enterprise.dto.d.ts +10 -0
  127. package/dist/enterprise/dto/create-enterprise.dto.d.ts.map +1 -0
  128. package/dist/enterprise/dto/create-enterprise.dto.js +54 -0
  129. package/dist/enterprise/dto/create-enterprise.dto.js.map +1 -0
  130. package/dist/enterprise/dto/update-enterprise-student.dto.d.ts +4 -0
  131. package/dist/enterprise/dto/update-enterprise-student.dto.d.ts.map +1 -0
  132. package/dist/enterprise/dto/update-enterprise-student.dto.js +22 -0
  133. package/dist/enterprise/dto/update-enterprise-student.dto.js.map +1 -0
  134. package/dist/enterprise/dto/update-enterprise-user.dto.d.ts +5 -0
  135. package/dist/enterprise/dto/update-enterprise-user.dto.d.ts.map +1 -0
  136. package/dist/enterprise/dto/update-enterprise-user.dto.js +27 -0
  137. package/dist/enterprise/dto/update-enterprise-user.dto.js.map +1 -0
  138. package/dist/enterprise/dto/update-enterprise.dto.d.ts +6 -0
  139. package/dist/enterprise/dto/update-enterprise.dto.d.ts.map +1 -0
  140. package/dist/enterprise/dto/update-enterprise.dto.js +9 -0
  141. package/dist/enterprise/dto/update-enterprise.dto.js.map +1 -0
  142. package/dist/enterprise/enterprise.controller.d.ts +269 -0
  143. package/dist/enterprise/enterprise.controller.d.ts.map +1 -0
  144. package/dist/enterprise/enterprise.controller.js +311 -0
  145. package/dist/enterprise/enterprise.controller.js.map +1 -0
  146. package/dist/enterprise/enterprise.module.d.ts +3 -0
  147. package/dist/enterprise/enterprise.module.d.ts.map +1 -0
  148. package/dist/enterprise/enterprise.module.js +25 -0
  149. package/dist/enterprise/enterprise.module.js.map +1 -0
  150. package/dist/enterprise/enterprise.service.d.ts +282 -0
  151. package/dist/enterprise/enterprise.service.d.ts.map +1 -0
  152. package/dist/enterprise/enterprise.service.js +627 -0
  153. package/dist/enterprise/enterprise.service.js.map +1 -0
  154. package/dist/evaluation/evaluation.controller.d.ts +56 -0
  155. package/dist/evaluation/evaluation.controller.d.ts.map +1 -0
  156. package/dist/evaluation/evaluation.controller.js +76 -0
  157. package/dist/evaluation/evaluation.controller.js.map +1 -0
  158. package/dist/evaluation/evaluation.module.d.ts +3 -0
  159. package/dist/evaluation/evaluation.module.d.ts.map +1 -0
  160. package/dist/evaluation/evaluation.module.js +25 -0
  161. package/dist/evaluation/evaluation.module.js.map +1 -0
  162. package/dist/evaluation/evaluation.service.d.ts +67 -0
  163. package/dist/evaluation/evaluation.service.d.ts.map +1 -0
  164. package/dist/evaluation/evaluation.service.js +378 -0
  165. package/dist/evaluation/evaluation.service.js.map +1 -0
  166. package/dist/exam/dto/create-exam-question.dto.d.ts +25 -0
  167. package/dist/exam/dto/create-exam-question.dto.d.ts.map +1 -0
  168. package/dist/exam/dto/create-exam-question.dto.js +117 -0
  169. package/dist/exam/dto/create-exam-question.dto.js.map +1 -0
  170. package/dist/exam/dto/create-exam.dto.d.ts +11 -0
  171. package/dist/exam/dto/create-exam.dto.d.ts.map +1 -0
  172. package/dist/exam/dto/create-exam.dto.js +63 -0
  173. package/dist/exam/dto/create-exam.dto.js.map +1 -0
  174. package/dist/exam/dto/reorder-exam-questions.dto.d.ts +4 -0
  175. package/dist/exam/dto/reorder-exam-questions.dto.d.ts.map +1 -0
  176. package/dist/exam/dto/reorder-exam-questions.dto.js +23 -0
  177. package/dist/exam/dto/reorder-exam-questions.dto.js.map +1 -0
  178. package/dist/exam/dto/save-exam-attempt-answers.dto.d.ts +14 -0
  179. package/dist/exam/dto/save-exam-attempt-answers.dto.d.ts.map +1 -0
  180. package/dist/exam/dto/save-exam-attempt-answers.dto.js +68 -0
  181. package/dist/exam/dto/save-exam-attempt-answers.dto.js.map +1 -0
  182. package/dist/exam/dto/start-exam-attempt.dto.d.ts +4 -0
  183. package/dist/exam/dto/start-exam-attempt.dto.d.ts.map +1 -0
  184. package/dist/exam/dto/start-exam-attempt.dto.js +23 -0
  185. package/dist/exam/dto/start-exam-attempt.dto.js.map +1 -0
  186. package/dist/exam/dto/submit-exam-attempt.dto.d.ts +5 -0
  187. package/dist/exam/dto/submit-exam-attempt.dto.d.ts.map +1 -0
  188. package/dist/exam/dto/submit-exam-attempt.dto.js +23 -0
  189. package/dist/exam/dto/submit-exam-attempt.dto.js.map +1 -0
  190. package/dist/exam/dto/update-exam-question.dto.d.ts +6 -0
  191. package/dist/exam/dto/update-exam-question.dto.d.ts.map +1 -0
  192. package/dist/exam/dto/update-exam-question.dto.js +9 -0
  193. package/dist/exam/dto/update-exam-question.dto.js.map +1 -0
  194. package/dist/exam/dto/update-exam.dto.d.ts +6 -0
  195. package/dist/exam/dto/update-exam.dto.d.ts.map +1 -0
  196. package/dist/exam/dto/update-exam.dto.js +9 -0
  197. package/dist/exam/dto/update-exam.dto.js.map +1 -0
  198. package/dist/exam/exam-attempt.controller.d.ts +273 -0
  199. package/dist/exam/exam-attempt.controller.d.ts.map +1 -0
  200. package/dist/exam/exam-attempt.controller.js +84 -0
  201. package/dist/exam/exam-attempt.controller.js.map +1 -0
  202. package/dist/exam/exam-attempt.service.d.ts +302 -0
  203. package/dist/exam/exam-attempt.service.d.ts.map +1 -0
  204. package/dist/exam/exam-attempt.service.js +776 -0
  205. package/dist/exam/exam-attempt.service.js.map +1 -0
  206. package/dist/exam/exam.controller.d.ts +162 -0
  207. package/dist/exam/exam.controller.d.ts.map +1 -0
  208. package/dist/exam/exam.controller.js +158 -0
  209. package/dist/exam/exam.controller.js.map +1 -0
  210. package/dist/exam/exam.module.d.ts +3 -0
  211. package/dist/exam/exam.module.d.ts.map +1 -0
  212. package/dist/exam/exam.module.js +27 -0
  213. package/dist/exam/exam.module.js.map +1 -0
  214. package/dist/exam/exam.service.d.ts +179 -0
  215. package/dist/exam/exam.service.d.ts.map +1 -0
  216. package/dist/exam/exam.service.js +597 -0
  217. package/dist/exam/exam.service.js.map +1 -0
  218. package/dist/index.d.ts +28 -0
  219. package/dist/index.d.ts.map +1 -1
  220. package/dist/index.js +28 -0
  221. package/dist/index.js.map +1 -1
  222. package/dist/instructor/dto/create-instructor.dto.d.ts +10 -0
  223. package/dist/instructor/dto/create-instructor.dto.d.ts.map +1 -0
  224. package/dist/instructor/dto/create-instructor.dto.js +55 -0
  225. package/dist/instructor/dto/create-instructor.dto.js.map +1 -0
  226. package/dist/instructor/dto/update-instructor.dto.d.ts +9 -0
  227. package/dist/instructor/dto/update-instructor.dto.d.ts.map +1 -0
  228. package/dist/instructor/dto/update-instructor.dto.js +51 -0
  229. package/dist/instructor/dto/update-instructor.dto.js.map +1 -0
  230. package/dist/instructor/instructor.controller.d.ts +52 -0
  231. package/dist/instructor/instructor.controller.d.ts.map +1 -0
  232. package/dist/instructor/instructor.controller.js +98 -0
  233. package/dist/instructor/instructor.controller.js.map +1 -0
  234. package/dist/instructor/instructor.module.d.ts +3 -0
  235. package/dist/instructor/instructor.module.d.ts.map +1 -0
  236. package/dist/instructor/instructor.module.js +25 -0
  237. package/dist/instructor/instructor.module.js.map +1 -0
  238. package/dist/instructor/instructor.service.d.ts +79 -0
  239. package/dist/instructor/instructor.service.d.ts.map +1 -0
  240. package/dist/instructor/instructor.service.js +528 -0
  241. package/dist/instructor/instructor.service.js.map +1 -0
  242. package/dist/lms.module.d.ts.map +1 -1
  243. package/dist/lms.module.js +36 -4
  244. package/dist/lms.module.js.map +1 -1
  245. package/dist/reports/reports.controller.d.ts +69 -0
  246. package/dist/reports/reports.controller.d.ts.map +1 -0
  247. package/dist/reports/reports.controller.js +40 -0
  248. package/dist/reports/reports.controller.js.map +1 -0
  249. package/dist/reports/reports.module.d.ts +3 -0
  250. package/dist/reports/reports.module.d.ts.map +1 -0
  251. package/dist/reports/reports.module.js +25 -0
  252. package/dist/reports/reports.module.js.map +1 -0
  253. package/dist/reports/reports.service.d.ts +80 -0
  254. package/dist/reports/reports.service.d.ts.map +1 -0
  255. package/dist/reports/reports.service.js +366 -0
  256. package/dist/reports/reports.service.js.map +1 -0
  257. package/dist/training/dto/create-training.dto.d.ts +19 -0
  258. package/dist/training/dto/create-training.dto.d.ts.map +1 -0
  259. package/dist/training/dto/create-training.dto.js +98 -0
  260. package/dist/training/dto/create-training.dto.js.map +1 -0
  261. package/dist/training/dto/update-training.dto.d.ts +6 -0
  262. package/dist/training/dto/update-training.dto.d.ts.map +1 -0
  263. package/dist/training/dto/update-training.dto.js +9 -0
  264. package/dist/training/dto/update-training.dto.js.map +1 -0
  265. package/dist/training/training.controller.d.ts +195 -0
  266. package/dist/training/training.controller.d.ts.map +1 -0
  267. package/dist/training/training.controller.js +104 -0
  268. package/dist/training/training.controller.js.map +1 -0
  269. package/dist/training/training.module.d.ts +3 -0
  270. package/dist/training/training.module.d.ts.map +1 -0
  271. package/dist/training/training.module.js +25 -0
  272. package/dist/training/training.module.js.map +1 -0
  273. package/dist/training/training.service.d.ts +213 -0
  274. package/dist/training/training.service.d.ts.map +1 -0
  275. package/dist/training/training.service.js +497 -0
  276. package/dist/training/training.service.js.map +1 -0
  277. package/hedhog/data/dashboard.yaml +6 -0
  278. package/hedhog/data/dashboard_component.yaml +153 -0
  279. package/hedhog/data/dashboard_component_role.yaml +97 -0
  280. package/hedhog/data/dashboard_item.yaml +167 -0
  281. package/hedhog/data/dashboard_role.yaml +6 -0
  282. package/hedhog/data/instructor_qualification.yaml +16 -0
  283. package/hedhog/data/menu.yaml +129 -19
  284. package/hedhog/data/role.yaml +25 -1
  285. package/hedhog/data/route.yaml +867 -0
  286. package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +1992 -0
  287. package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +480 -0
  288. package/hedhog/frontend/app/_components/create-lms-instructor-sheet.tsx.ejs +591 -0
  289. package/hedhog/frontend/app/_components/create-lms-person-sheet.tsx.ejs +164 -0
  290. package/hedhog/frontend/app/_components/create-lms-student-person-sheet.tsx.ejs +120 -0
  291. package/hedhog/frontend/app/_components/lms-class-calendar.tsx.ejs +272 -0
  292. package/hedhog/frontend/app/_components/mobile-calendar.tsx.ejs +277 -0
  293. package/hedhog/frontend/app/_lib/editor/canvasInstance.ts.ejs +48 -0
  294. package/hedhog/frontend/app/_lib/editor/pctHelpers.ts.ejs +50 -0
  295. package/hedhog/frontend/app/_lib/editor/templateSerializer.ts.ejs +268 -0
  296. package/hedhog/frontend/app/_lib/editor/types.ts.ejs +94 -0
  297. package/hedhog/frontend/app/_lib/store/useTemplateStore.ts.ejs +284 -0
  298. package/hedhog/frontend/app/certificates/issued/page.tsx.ejs +638 -0
  299. package/hedhog/frontend/app/certificates/models/CanvasStage.tsx.ejs +916 -0
  300. package/hedhog/frontend/app/certificates/models/LeftPanel.tsx.ejs +200 -0
  301. package/hedhog/frontend/app/certificates/models/RightPanel.tsx.ejs +769 -0
  302. package/hedhog/frontend/app/certificates/models/TemplateEditorPage.tsx.ejs +104 -0
  303. package/hedhog/frontend/app/certificates/models/TopBar.tsx.ejs +354 -0
  304. package/hedhog/frontend/app/certificates/models/editor/page.tsx.ejs +5 -0
  305. package/hedhog/frontend/app/certificates/models/page.tsx.ejs +883 -0
  306. package/hedhog/frontend/app/classes/[id]/_components/event-summary-popover.tsx.ejs +279 -0
  307. package/hedhog/frontend/app/classes/[id]/_components/quick-create-session-popover.tsx.ejs +1027 -0
  308. package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +3130 -993
  309. package/hedhog/frontend/app/classes/page.tsx.ejs +2731 -759
  310. package/hedhog/frontend/app/courses/[id]/_components/CourseCertificateCard.tsx.ejs +80 -0
  311. package/hedhog/frontend/app/courses/[id]/_components/CourseClassificationCard.tsx.ejs +226 -0
  312. package/hedhog/frontend/app/courses/[id]/_components/CourseContentCard.tsx.ejs +71 -0
  313. package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +42 -0
  314. package/hedhog/frontend/app/courses/[id]/_components/CourseFlagsCard.tsx.ejs +111 -0
  315. package/hedhog/frontend/app/courses/[id]/_components/CourseMainInfoCard.tsx.ejs +113 -0
  316. package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +215 -0
  317. package/hedhog/frontend/app/courses/[id]/_components/CourseMultiEntityPicker.tsx.ejs +236 -0
  318. package/hedhog/frontend/app/courses/[id]/_components/CourseRelationsCard.tsx.ejs +141 -0
  319. package/hedhog/frontend/app/courses/[id]/_components/CourseSectionCard.tsx.ejs +57 -0
  320. package/hedhog/frontend/app/courses/[id]/_components/CourseSummaryCard.tsx.ejs +60 -0
  321. package/hedhog/frontend/app/courses/[id]/_components/course-edit-types.ts.ejs +33 -0
  322. package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +933 -1103
  323. package/hedhog/frontend/app/courses/[id]/structure/page.tsx.ejs +699 -117
  324. package/hedhog/frontend/app/courses/page.tsx.ejs +1018 -1042
  325. package/hedhog/frontend/app/enterprise/[id]/page.tsx.ejs +317 -0
  326. package/hedhog/frontend/app/enterprise/_components/enterprise-activity-panel.tsx.ejs +88 -0
  327. package/hedhog/frontend/app/enterprise/_components/enterprise-admin-create-sheet.tsx.ejs +318 -0
  328. package/hedhog/frontend/app/enterprise/_components/enterprise-administrators-tab.tsx.ejs +332 -0
  329. package/hedhog/frontend/app/enterprise/_components/enterprise-class-create-sheet.tsx.ejs +58 -0
  330. package/hedhog/frontend/app/enterprise/_components/enterprise-classes-tab.tsx.ejs +390 -0
  331. package/hedhog/frontend/app/enterprise/_components/enterprise-company-identity-card.tsx.ejs +112 -0
  332. package/hedhog/frontend/app/enterprise/_components/enterprise-course-create-sheet.tsx.ejs +183 -0
  333. package/hedhog/frontend/app/enterprise/_components/enterprise-courses-tab.tsx.ejs +363 -0
  334. package/hedhog/frontend/app/enterprise/_components/enterprise-detail-constants.ts.ejs +88 -0
  335. package/hedhog/frontend/app/enterprise/_components/enterprise-detail-sheet.tsx.ejs +548 -0
  336. package/hedhog/frontend/app/enterprise/_components/enterprise-detail-utils.ts.ejs +33 -0
  337. package/hedhog/frontend/app/enterprise/_components/enterprise-mocks.ts.ejs +277 -0
  338. package/hedhog/frontend/app/enterprise/_components/enterprise-person-picker.ts.ejs +31 -0
  339. package/hedhog/frontend/app/enterprise/_components/enterprise-progress-bar.tsx.ejs +21 -0
  340. package/hedhog/frontend/app/enterprise/_components/enterprise-related-tab.tsx.ejs +224 -0
  341. package/hedhog/frontend/app/enterprise/_components/enterprise-sheet.tsx.ejs +397 -0
  342. package/hedhog/frontend/app/enterprise/_components/enterprise-student-create-sheet.tsx.ejs +167 -0
  343. package/hedhog/frontend/app/enterprise/_components/enterprise-students-tab.tsx.ejs +267 -0
  344. package/hedhog/frontend/app/enterprise/_components/enterprise-system-user-picker.ts.ejs +42 -0
  345. package/hedhog/frontend/app/enterprise/_components/enterprise-types.ts.ejs +96 -0
  346. package/hedhog/frontend/app/enterprise/_components/enterprise-user-create-sheet.tsx.ejs +207 -0
  347. package/hedhog/frontend/app/enterprise/_components/enterprise-user-distribution-chart.tsx.ejs +149 -0
  348. package/hedhog/frontend/app/enterprise/page.tsx.ejs +596 -0
  349. package/hedhog/frontend/app/evaluations/page.tsx.ejs +1250 -0
  350. package/hedhog/frontend/app/exams/[id]/attempt/page.tsx.ejs +642 -196
  351. package/hedhog/frontend/app/exams/[id]/page.tsx.ejs +11 -0
  352. package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +1316 -436
  353. package/hedhog/frontend/app/exams/page.tsx.ejs +799 -546
  354. package/hedhog/frontend/app/layout.tsx.ejs +5 -0
  355. package/hedhog/frontend/app/page.tsx.ejs +3 -1220
  356. package/hedhog/frontend/app/reports/courses/page.tsx.ejs +843 -0
  357. package/hedhog/frontend/app/reports/dashboard/page.tsx.ejs +890 -0
  358. package/hedhog/frontend/app/reports/page.tsx.ejs +802 -808
  359. package/hedhog/frontend/app/reports/students/page.tsx.ejs +772 -0
  360. package/hedhog/frontend/app/training/page.tsx.ejs +1873 -628
  361. package/hedhog/frontend/messages/en.json +1606 -111
  362. package/hedhog/frontend/messages/pt.json +1636 -134
  363. package/hedhog/frontend/widgets/active-classes-kpi.tsx.ejs +74 -0
  364. package/hedhog/frontend/widgets/active-courses-kpi.tsx.ejs +74 -0
  365. package/hedhog/frontend/widgets/approval-rate-kpi.tsx.ejs +81 -0
  366. package/hedhog/frontend/widgets/category-distribution-chart.tsx.ejs +119 -0
  367. package/hedhog/frontend/widgets/class-calendar.tsx.ejs +440 -0
  368. package/hedhog/frontend/widgets/completion-rate-kpi.tsx.ejs +81 -0
  369. package/hedhog/frontend/widgets/engagement-chart.tsx.ejs +120 -0
  370. package/hedhog/frontend/widgets/footer-summary.tsx.ejs +80 -0
  371. package/hedhog/frontend/widgets/issued-certificates-kpi.tsx.ejs +74 -0
  372. package/hedhog/frontend/widgets/latest-enrollments.tsx.ejs +166 -0
  373. package/hedhog/frontend/widgets/student-growth-chart.tsx.ejs +89 -0
  374. package/hedhog/frontend/widgets/top-courses-chart.tsx.ejs +104 -0
  375. package/hedhog/frontend/widgets/total-students-kpi.tsx.ejs +78 -0
  376. package/hedhog/frontend/widgets/upcoming-classes.tsx.ejs +152 -0
  377. package/hedhog/table/course.yaml +19 -1
  378. package/hedhog/table/course_class_group.yaml +8 -0
  379. package/hedhog/table/course_class_session.yaml +33 -0
  380. package/hedhog/table/course_instructor.yaml +27 -0
  381. package/hedhog/table/enterprise.yaml +29 -0
  382. package/hedhog/table/enterprise_class_group.yaml +20 -0
  383. package/hedhog/table/enterprise_course.yaml +23 -0
  384. package/hedhog/table/enterprise_student.yaml +24 -0
  385. package/hedhog/table/enterprise_user.yaml +35 -0
  386. package/hedhog/table/instructor_qualification.yaml +26 -0
  387. package/hedhog/table/instructor_qualification_assignment.yaml +22 -0
  388. package/hedhog/table/question.yaml +6 -0
  389. package/package.json +6 -6
  390. package/src/certificate/certificate.controller.ts +83 -0
  391. package/src/certificate/certificate.module.ts +13 -0
  392. package/src/certificate/certificate.service.ts +413 -0
  393. package/src/certificate/dto/create-certificate-template.dto.ts +25 -0
  394. package/src/certificate/dto/update-certificate-template.dto.ts +6 -0
  395. package/src/class-group/class-group.controller.ts +189 -0
  396. package/src/class-group/class-group.module.ts +12 -0
  397. package/src/class-group/class-group.service.ts +1802 -0
  398. package/src/class-group/dto/create-class-group.dto.ts +139 -0
  399. package/src/class-group/dto/create-session.dto.ts +102 -0
  400. package/src/class-group/dto/enrollment.dto.ts +70 -0
  401. package/src/class-group/dto/update-class-group.dto.ts +4 -0
  402. package/src/class-group/dto/update-session.dto.ts +9 -0
  403. package/src/course/course-structure.controller.ts +85 -0
  404. package/src/course/course-structure.service.ts +525 -0
  405. package/src/course/course.controller.ts +69 -0
  406. package/src/course/course.module.ts +15 -0
  407. package/src/course/course.service.ts +920 -0
  408. package/src/course/dto/create-course-structure-lesson.dto.ts +97 -0
  409. package/src/course/dto/create-course-structure-session.dto.ts +22 -0
  410. package/src/course/dto/create-course.dto.ts +111 -0
  411. package/src/course/dto/update-course-structure-lesson.dto.ts +6 -0
  412. package/src/course/dto/update-course-structure-session.dto.ts +6 -0
  413. package/src/course/dto/update-course.dto.ts +4 -0
  414. package/src/dashboard/dashboard.controller.ts +14 -0
  415. package/src/dashboard/dashboard.module.ts +12 -0
  416. package/src/dashboard/dashboard.service.ts +726 -0
  417. package/src/enterprise/dto/add-enterprise-class-group.dto.ts +7 -0
  418. package/src/enterprise/dto/add-enterprise-course.dto.ts +11 -0
  419. package/src/enterprise/dto/add-enterprise-student.dto.ts +16 -0
  420. package/src/enterprise/dto/add-enterprise-user.dto.ts +23 -0
  421. package/src/enterprise/dto/create-enterprise.dto.ts +41 -0
  422. package/src/enterprise/dto/update-enterprise-student.dto.ts +7 -0
  423. package/src/enterprise/dto/update-enterprise-user.dto.ts +11 -0
  424. package/src/enterprise/dto/update-enterprise.dto.ts +4 -0
  425. package/src/enterprise/enterprise.controller.ts +233 -0
  426. package/src/enterprise/enterprise.module.ts +12 -0
  427. package/src/enterprise/enterprise.service.ts +712 -0
  428. package/src/evaluation/evaluation.controller.ts +44 -0
  429. package/src/evaluation/evaluation.module.ts +12 -0
  430. package/src/evaluation/evaluation.service.ts +394 -0
  431. package/src/exam/dto/create-exam-question.dto.ts +103 -0
  432. package/src/exam/dto/create-exam.dto.ts +41 -0
  433. package/src/exam/dto/reorder-exam-questions.dto.ts +8 -0
  434. package/src/exam/dto/save-exam-attempt-answers.dto.ts +55 -0
  435. package/src/exam/dto/start-exam-attempt.dto.ts +8 -0
  436. package/src/exam/dto/submit-exam-attempt.dto.ts +8 -0
  437. package/src/exam/dto/update-exam-question.dto.ts +4 -0
  438. package/src/exam/dto/update-exam.dto.ts +4 -0
  439. package/src/exam/exam-attempt.controller.ts +65 -0
  440. package/src/exam/exam-attempt.service.ts +1008 -0
  441. package/src/exam/exam.controller.ts +102 -0
  442. package/src/exam/exam.module.ts +14 -0
  443. package/src/exam/exam.service.ts +784 -0
  444. package/src/index.ts +29 -0
  445. package/src/instructor/dto/create-instructor.dto.ts +43 -0
  446. package/src/instructor/dto/update-instructor.dto.ts +38 -0
  447. package/src/instructor/instructor.controller.ts +73 -0
  448. package/src/instructor/instructor.module.ts +12 -0
  449. package/src/instructor/instructor.service.ts +646 -0
  450. package/src/lms.module.ts +36 -4
  451. package/src/reports/reports.controller.ts +14 -0
  452. package/src/reports/reports.module.ts +12 -0
  453. package/src/reports/reports.service.ts +485 -0
  454. package/src/training/dto/create-training.dto.ts +81 -0
  455. package/src/training/dto/update-training.dto.ts +4 -0
  456. package/src/training/training.controller.ts +68 -0
  457. package/src/training/training.module.ts +12 -0
  458. package/src/training/training.service.ts +574 -0
@@ -0,0 +1,413 @@
1
+ import { PrismaService } from '@hed-hog/api-prisma';
2
+ import { FileService } from '@hed-hog/core';
3
+ import {
4
+ BadRequestException,
5
+ Injectable,
6
+ NotFoundException,
7
+ } from '@nestjs/common';
8
+ import { CreateCertificateTemplateDto } from './dto/create-certificate-template.dto';
9
+ import { UpdateCertificateTemplateDto } from './dto/update-certificate-template.dto';
10
+
11
+ type CertificateTemplateStatus = 'draft' | 'active' | 'inactive';
12
+ type CertificateType = 'course' | 'exam' | 'course_class_group' | 'learning_path';
13
+
14
+ type ListIssuedCertificatesParams = {
15
+ page?: number;
16
+ pageSize?: number;
17
+ search?: string;
18
+ type?: string;
19
+ };
20
+
21
+ type ListCertificateTemplatesParams = {
22
+ page?: number;
23
+ pageSize?: number;
24
+ search?: string;
25
+ status?: string;
26
+ };
27
+
28
+ @Injectable()
29
+ export class LmsCertificateService {
30
+ constructor(
31
+ private readonly prisma: PrismaService,
32
+ private readonly fileService: FileService,
33
+ ) {}
34
+
35
+ async uploadTemplateBackgroundImage(file: any) {
36
+ if (!file) {
37
+ throw new BadRequestException('Background image file is required');
38
+ }
39
+
40
+ if (!String(file.mimetype || '').startsWith('image/')) {
41
+ throw new BadRequestException('Only image files are allowed');
42
+ }
43
+
44
+ const uploaded = await this.fileService.upload(
45
+ 'lms/certificates/templates/backgrounds',
46
+ file,
47
+ );
48
+
49
+ return {
50
+ id: uploaded.id,
51
+ filename: uploaded.filename,
52
+ // Expose an HTTP-openable URL so admin can render immediately.
53
+ url: `/file/open/${uploaded.id}`,
54
+ storagePath: uploaded.path,
55
+ size: uploaded.size,
56
+ mimetypeId: uploaded.mimetype_id,
57
+ };
58
+ }
59
+
60
+ async listTemplates(params: ListCertificateTemplatesParams) {
61
+ const page = Math.max(Number(params.page) || 1, 1);
62
+ const pageSize = Math.max(Number(params.pageSize) || 12, 1);
63
+ const skip = (page - 1) * pageSize;
64
+
65
+ const where: Record<string, any> = {};
66
+
67
+ if (params.search?.trim()) {
68
+ const search = params.search.trim();
69
+ where.OR = [
70
+ { name: { contains: search, mode: 'insensitive' } },
71
+ { slug: { contains: search, mode: 'insensitive' } },
72
+ { description: { contains: search, mode: 'insensitive' } },
73
+ ];
74
+ }
75
+
76
+ const status = this.normalizeTemplateStatus(params.status);
77
+ if (status) {
78
+ where.status = status;
79
+ }
80
+
81
+ const [templates, total] = await Promise.all([
82
+ this.prisma.certificate_template.findMany({
83
+ skip,
84
+ take: pageSize,
85
+ where,
86
+ orderBy: [{ updated_at: 'desc' }, { id: 'desc' }],
87
+ }),
88
+ this.prisma.certificate_template.count({ where }),
89
+ ]);
90
+
91
+ return {
92
+ total,
93
+ page,
94
+ pageSize,
95
+ lastPage: Math.max(1, Math.ceil(total / pageSize)),
96
+ data: templates.map((template) => this.mapTemplate(template)),
97
+ };
98
+ }
99
+
100
+ async getTemplateById(id: number) {
101
+ const template = await this.prisma.certificate_template.findUnique({
102
+ where: { id },
103
+ });
104
+
105
+ if (!template) {
106
+ throw new NotFoundException('Certificate template not found');
107
+ }
108
+
109
+ return this.mapTemplate(template);
110
+ }
111
+
112
+ async createTemplate(dto: CreateCertificateTemplateDto) {
113
+ const payload = this.prepareTemplatePayload(
114
+ dto
115
+ ) as Record<string, any>;
116
+ payload.slug = await this.resolveUniqueTemplateSlug(payload.slug || payload.name);
117
+
118
+ const template = await this.prisma.certificate_template.create({
119
+ data: payload as any,
120
+ });
121
+
122
+ return this.mapTemplate(template);
123
+ }
124
+
125
+ async updateTemplate(id: number, dto: UpdateCertificateTemplateDto) {
126
+ await this.ensureTemplateExists(id);
127
+
128
+ const payload = this.prepareTemplatePayload(dto, true);
129
+
130
+ const template = await this.prisma.certificate_template.update({
131
+ where: { id },
132
+ data: payload,
133
+ });
134
+
135
+ return this.mapTemplate(template);
136
+ }
137
+
138
+ async deleteTemplate(id: number) {
139
+ await this.ensureTemplateExists(id);
140
+
141
+ try {
142
+ await this.prisma.certificate_template.delete({
143
+ where: { id },
144
+ });
145
+ } catch {
146
+ throw new BadRequestException('Certificate template cannot be removed');
147
+ }
148
+
149
+ return { success: true };
150
+ }
151
+
152
+ async listIssued(params: ListIssuedCertificatesParams) {
153
+ const page = Math.max(Number(params.page) || 1, 1);
154
+ const pageSize = Math.max(Number(params.pageSize) || 12, 1);
155
+ const skip = (page - 1) * pageSize;
156
+
157
+ const where: Record<string, any> = {};
158
+ const type = this.normalizeType(params.type);
159
+
160
+ if (type) {
161
+ where.certificate_type = type;
162
+ }
163
+
164
+ if (params.search?.trim()) {
165
+ const search = params.search.trim();
166
+ where.OR = [
167
+ { student_name: { contains: search, mode: 'insensitive' } },
168
+ { course_name: { contains: search, mode: 'insensitive' } },
169
+ { verification_code: { contains: search, mode: 'insensitive' } },
170
+ {
171
+ certificate_template: {
172
+ name: { contains: search, mode: 'insensitive' },
173
+ },
174
+ },
175
+ ];
176
+ }
177
+
178
+ const [certificates, total] = await Promise.all([
179
+ this.prisma.certificate.findMany({
180
+ skip,
181
+ take: pageSize,
182
+ where,
183
+ orderBy: [{ issued_at: 'desc' }, { id: 'desc' }],
184
+ include: {
185
+ certificate_template: {
186
+ select: {
187
+ id: true,
188
+ name: true,
189
+ status: true,
190
+ },
191
+ },
192
+ course: {
193
+ select: {
194
+ id: true,
195
+ title: true,
196
+ primary_color: true,
197
+ },
198
+ },
199
+ exam: {
200
+ select: {
201
+ id: true,
202
+ title: true,
203
+ },
204
+ },
205
+ course_class_group: {
206
+ select: {
207
+ id: true,
208
+ title: true,
209
+ },
210
+ },
211
+ learning_path: {
212
+ select: {
213
+ id: true,
214
+ title: true,
215
+ primary_color: true,
216
+ },
217
+ },
218
+ person: {
219
+ select: {
220
+ id: true,
221
+ name: true,
222
+ },
223
+ },
224
+ },
225
+ }),
226
+ this.prisma.certificate.count({ where }),
227
+ ]);
228
+
229
+ return {
230
+ total,
231
+ page,
232
+ pageSize,
233
+ lastPage: Math.max(1, Math.ceil(total / pageSize)),
234
+ data: certificates.map((certificate) => this.mapIssuedCertificate(certificate)),
235
+ };
236
+ }
237
+
238
+ private mapIssuedCertificate(certificate: any) {
239
+ return {
240
+ id: certificate.id,
241
+ studentId: certificate.student_id,
242
+ studentName: certificate.person?.name ?? certificate.student_name,
243
+ courseName: certificate.course?.title ?? certificate.course_name,
244
+ templateId: certificate.certificate_template_id,
245
+ templateName: certificate.certificate_template?.name ?? '',
246
+ templateStatus: certificate.certificate_template?.status ?? null,
247
+ certificateType: certificate.certificate_type,
248
+ workloadHours: certificate.workload_hours ?? 0,
249
+ issuedAt: certificate.issued_at,
250
+ completedAt: certificate.completed_at,
251
+ finalScore: certificate.final_score,
252
+ verificationCode: certificate.verification_code,
253
+ verificationUrl: certificate.verification_url,
254
+ pdfUrl: certificate.pdf_url,
255
+ sourceTitle:
256
+ certificate.course_class_group?.title ??
257
+ certificate.learning_path?.title ??
258
+ certificate.exam?.title ??
259
+ certificate.course?.title ??
260
+ certificate.course_name,
261
+ primaryColor:
262
+ certificate.course?.primary_color ??
263
+ certificate.learning_path?.primary_color ??
264
+ null,
265
+ };
266
+ }
267
+
268
+ private mapTemplate(template: any) {
269
+ return {
270
+ id: template.id,
271
+ name: template.name,
272
+ slug: template.slug,
273
+ description: template.description,
274
+ templateContent: template.template_content,
275
+ status: template.status,
276
+ createdAt: template.created_at,
277
+ updatedAt: template.updated_at,
278
+ };
279
+ }
280
+
281
+ private normalizeTemplateStatus(value?: string) {
282
+ if (!value || value === 'all') {
283
+ return undefined;
284
+ }
285
+
286
+ const normalized = value.trim().toLowerCase();
287
+ const allowed: CertificateTemplateStatus[] = [
288
+ 'draft',
289
+ 'active',
290
+ 'inactive',
291
+ ];
292
+
293
+ if (!allowed.includes(normalized as CertificateTemplateStatus)) {
294
+ throw new BadRequestException('Invalid template status');
295
+ }
296
+
297
+ return normalized as CertificateTemplateStatus;
298
+ }
299
+
300
+ private prepareTemplatePayload(
301
+ dto: CreateCertificateTemplateDto | UpdateCertificateTemplateDto,
302
+ partial = false,
303
+ ) {
304
+ const payload: Record<string, any> = {
305
+ name: dto.name?.trim() ?? '',
306
+ slug: dto.slug?.trim() ?? '',
307
+ description: dto.description?.trim() || null,
308
+ template_content: dto.templateContent ?? '',
309
+ status: (dto.status as CertificateTemplateStatus) ?? 'draft',
310
+ };
311
+
312
+ if (!partial) {
313
+ this.validateTemplateContent(payload.template_content);
314
+ return payload;
315
+ }
316
+
317
+ const partialPayload: Record<string, any> = {};
318
+
319
+ if (dto.name !== undefined) {
320
+ partialPayload.name = dto.name.trim();
321
+ }
322
+ if (dto.slug !== undefined) {
323
+ partialPayload.slug = dto.slug.trim();
324
+ }
325
+ if (dto.description !== undefined) {
326
+ partialPayload.description = dto.description.trim() || null;
327
+ }
328
+ if (dto.templateContent !== undefined) {
329
+ this.validateTemplateContent(dto.templateContent);
330
+ partialPayload.template_content = dto.templateContent;
331
+ }
332
+ if (dto.status !== undefined) {
333
+ partialPayload.status = dto.status as CertificateTemplateStatus;
334
+ }
335
+
336
+ return partialPayload;
337
+ }
338
+
339
+ private validateTemplateContent(value: string) {
340
+ try {
341
+ JSON.parse(value);
342
+ } catch {
343
+ throw new BadRequestException('templateContent must be valid JSON');
344
+ }
345
+ }
346
+
347
+ private async resolveUniqueTemplateSlug(value: string) {
348
+ const normalizedBase = this.slugify(value) || 'template';
349
+ let candidate = normalizedBase;
350
+ let counter = 2;
351
+
352
+ while (await this.hasTemplateSlug(candidate)) {
353
+ const suffix = `-${counter}`;
354
+ const maxBaseLength = Math.max(1, 255 - suffix.length);
355
+ candidate = `${normalizedBase.slice(0, maxBaseLength)}${suffix}`;
356
+ counter += 1;
357
+ }
358
+
359
+ return candidate;
360
+ }
361
+
362
+ private async hasTemplateSlug(slug: string) {
363
+ const count = await this.prisma.certificate_template.count({
364
+ where: { slug },
365
+ });
366
+
367
+ return count > 0;
368
+ }
369
+
370
+ private slugify(value: string) {
371
+ const normalized = value
372
+ .normalize('NFD')
373
+ .replace(/[\u0300-\u036f]/g, '')
374
+ .toLowerCase()
375
+ .replace(/[^a-z0-9\s-]/g, '')
376
+ .trim()
377
+ .replace(/\s+/g, '-')
378
+ .replace(/-+/g, '-')
379
+ .replace(/^-+|-+$/g, '');
380
+
381
+ return normalized.slice(0, 255);
382
+ }
383
+
384
+ private async ensureTemplateExists(id: number) {
385
+ const count = await this.prisma.certificate_template.count({
386
+ where: { id },
387
+ });
388
+
389
+ if (!count) {
390
+ throw new NotFoundException('Certificate template not found');
391
+ }
392
+ }
393
+
394
+ private normalizeType(value?: string) {
395
+ if (!value || value === 'all') {
396
+ return undefined;
397
+ }
398
+
399
+ const normalized = value.trim().toLowerCase();
400
+ const allowed: CertificateType[] = [
401
+ 'course',
402
+ 'exam',
403
+ 'course_class_group',
404
+ 'learning_path',
405
+ ];
406
+
407
+ if (!allowed.includes(normalized as CertificateType)) {
408
+ throw new BadRequestException('Invalid certificate type');
409
+ }
410
+
411
+ return normalized as CertificateType;
412
+ }
413
+ }
@@ -0,0 +1,25 @@
1
+ import { IsEnum, IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator';
2
+
3
+ export class CreateCertificateTemplateDto {
4
+ @IsString()
5
+ @IsNotEmpty()
6
+ @MaxLength(255)
7
+ name: string;
8
+
9
+ @IsString()
10
+ @IsOptional()
11
+ @MaxLength(255)
12
+ slug?: string;
13
+
14
+ @IsString()
15
+ @IsOptional()
16
+ description?: string;
17
+
18
+ @IsString()
19
+ @IsNotEmpty()
20
+ templateContent: string;
21
+
22
+ @IsEnum(['draft', 'active', 'inactive'])
23
+ @IsOptional()
24
+ status?: 'draft' | 'active' | 'inactive';
25
+ }
@@ -0,0 +1,6 @@
1
+ import { PartialType } from '@nestjs/mapped-types';
2
+ import { CreateCertificateTemplateDto } from './create-certificate-template.dto';
3
+
4
+ export class UpdateCertificateTemplateDto extends PartialType(
5
+ CreateCertificateTemplateDto,
6
+ ) {}
@@ -0,0 +1,189 @@
1
+ import { Role } from '@hed-hog/api';
2
+ import {
3
+ Body,
4
+ Controller,
5
+ Delete,
6
+ Get,
7
+ Param,
8
+ ParseIntPipe,
9
+ Patch,
10
+ Post,
11
+ Query,
12
+ } from '@nestjs/common';
13
+ import { ClassGroupService } from './class-group.service';
14
+ import { CreateClassGroupDto } from './dto/create-class-group.dto';
15
+ import { CreateSessionDto } from './dto/create-session.dto';
16
+ import {
17
+ CreateStudentAndEnrollDto,
18
+ EnrollStudentDto,
19
+ SaveAttendanceDto,
20
+ UpdateStudentProfileDto,
21
+ } from './dto/enrollment.dto';
22
+ import { UpdateClassGroupDto } from './dto/update-class-group.dto';
23
+ import { UpdateSessionDto } from './dto/update-session.dto';
24
+
25
+ @Role()
26
+ @Controller('lms/classes')
27
+ export class ClassGroupController {
28
+ constructor(private readonly classGroupService: ClassGroupService) {}
29
+
30
+ @Get()
31
+ list(
32
+ @Query('page') page?: string,
33
+ @Query('pageSize') pageSize?: string,
34
+ @Query('search') search?: string,
35
+ @Query('status') status?: string,
36
+ @Query('deliveryMode') deliveryMode?: string,
37
+ @Query('courseId') courseId?: string,
38
+ ) {
39
+ return this.classGroupService.list({
40
+ page: page ? Number(page) : 1,
41
+ pageSize: pageSize ? Number(pageSize) : 12,
42
+ search,
43
+ status,
44
+ deliveryMode,
45
+ courseId: courseId ? Number(courseId) : undefined,
46
+ });
47
+ }
48
+
49
+ @Get('stats')
50
+ stats() {
51
+ return this.classGroupService.stats();
52
+ }
53
+
54
+ @Get(':id')
55
+ getById(@Param('id', ParseIntPipe) id: number) {
56
+ return this.classGroupService.getById(id);
57
+ }
58
+
59
+ @Post()
60
+ create(@Body() dto: CreateClassGroupDto) {
61
+ return this.classGroupService.create(dto);
62
+ }
63
+
64
+ @Patch(':id')
65
+ update(
66
+ @Param('id', ParseIntPipe) id: number,
67
+ @Body() dto: UpdateClassGroupDto,
68
+ ) {
69
+ return this.classGroupService.update(id, dto);
70
+ }
71
+
72
+ @Delete(':id')
73
+ remove(@Param('id', ParseIntPipe) id: number) {
74
+ return this.classGroupService.remove(id);
75
+ }
76
+
77
+ // ── People search ───────────────────────────────────────────────────────────
78
+
79
+ @Get(':id/people/search')
80
+ searchPeople(
81
+ @Param('id', ParseIntPipe) id: number,
82
+ @Query('q') q?: string,
83
+ ) {
84
+ return this.classGroupService.searchPeople(q ?? '', id);
85
+ }
86
+
87
+ // ── Students (enrollments) ──────────────────────────────────────────────────
88
+
89
+ @Get(':id/students')
90
+ listStudents(
91
+ @Param('id', ParseIntPipe) id: number,
92
+ @Query('search') search?: string,
93
+ ) {
94
+ return this.classGroupService.listStudents(id, search);
95
+ }
96
+
97
+ @Post(':id/students')
98
+ enrollStudent(
99
+ @Param('id', ParseIntPipe) id: number,
100
+ @Body() dto: EnrollStudentDto,
101
+ ) {
102
+ return this.classGroupService.enrollStudent(id, dto.personId);
103
+ }
104
+
105
+ @Post(':id/students/create')
106
+ createAndEnrollStudent(
107
+ @Param('id', ParseIntPipe) id: number,
108
+ @Body() dto: CreateStudentAndEnrollDto,
109
+ ) {
110
+ return this.classGroupService.createAndEnrollStudent(id, dto);
111
+ }
112
+
113
+ @Get(':id/students/:personId')
114
+ getStudentProfile(
115
+ @Param('id', ParseIntPipe) id: number,
116
+ @Param('personId', ParseIntPipe) personId: number,
117
+ ) {
118
+ return this.classGroupService.getStudentProfile(id, personId);
119
+ }
120
+
121
+ @Patch(':id/students/:personId')
122
+ updateStudentProfile(
123
+ @Param('id', ParseIntPipe) id: number,
124
+ @Param('personId', ParseIntPipe) personId: number,
125
+ @Body() dto: UpdateStudentProfileDto,
126
+ ) {
127
+ return this.classGroupService.updateStudentProfile(id, personId, dto);
128
+ }
129
+
130
+ @Delete(':id/students/:personId')
131
+ removeStudent(
132
+ @Param('id', ParseIntPipe) id: number,
133
+ @Param('personId', ParseIntPipe) personId: number,
134
+ ) {
135
+ return this.classGroupService.removeStudent(id, personId);
136
+ }
137
+
138
+ // ── Sessions ────────────────────────────────────────────────────────────────
139
+
140
+ @Get(':id/sessions')
141
+ listSessions(@Param('id', ParseIntPipe) id: number) {
142
+ return this.classGroupService.listSessions(id);
143
+ }
144
+
145
+ @Post(':id/sessions')
146
+ createSession(
147
+ @Param('id', ParseIntPipe) id: number,
148
+ @Body() dto: CreateSessionDto,
149
+ ) {
150
+ return this.classGroupService.createSession(id, dto);
151
+ }
152
+
153
+ @Patch(':id/sessions/:sessionId')
154
+ updateSession(
155
+ @Param('id', ParseIntPipe) id: number,
156
+ @Param('sessionId', ParseIntPipe) sessionId: number,
157
+ @Body() dto: UpdateSessionDto,
158
+ ) {
159
+ return this.classGroupService.updateSession(id, sessionId, dto);
160
+ }
161
+
162
+ @Delete(':id/sessions/:sessionId')
163
+ deleteSession(
164
+ @Param('id', ParseIntPipe) id: number,
165
+ @Param('sessionId', ParseIntPipe) sessionId: number,
166
+ @Query('scope') scope?: 'single' | 'series',
167
+ ) {
168
+ return this.classGroupService.deleteSession(id, sessionId, scope);
169
+ }
170
+
171
+ // ── Attendance ──────────────────────────────────────────────────────────────
172
+
173
+ @Get(':id/sessions/:sessionId/attendance')
174
+ getAttendance(
175
+ @Param('id', ParseIntPipe) id: number,
176
+ @Param('sessionId', ParseIntPipe) sessionId: number,
177
+ ) {
178
+ return this.classGroupService.getAttendance(id, sessionId);
179
+ }
180
+
181
+ @Post(':id/sessions/:sessionId/attendance')
182
+ saveAttendance(
183
+ @Param('id', ParseIntPipe) id: number,
184
+ @Param('sessionId', ParseIntPipe) sessionId: number,
185
+ @Body() dto: SaveAttendanceDto,
186
+ ) {
187
+ return this.classGroupService.saveAttendance(id, sessionId, dto.attendance);
188
+ }
189
+ }
@@ -0,0 +1,12 @@
1
+ import { PrismaModule } from '@hed-hog/api-prisma';
2
+ import { forwardRef, Module } from '@nestjs/common';
3
+ import { ClassGroupController } from './class-group.controller';
4
+ import { ClassGroupService } from './class-group.service';
5
+
6
+ @Module({
7
+ imports: [forwardRef(() => PrismaModule)],
8
+ controllers: [ClassGroupController],
9
+ providers: [ClassGroupService],
10
+ exports: [forwardRef(() => ClassGroupService)],
11
+ })
12
+ export class ClassGroupModule {}