@hed-hog/lms 0.0.361 → 0.0.364

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 (329) hide show
  1. package/dist/bitcode-wallet/bitcode-wallet.service.d.ts +65 -0
  2. package/dist/bitcode-wallet/bitcode-wallet.service.d.ts.map +1 -1
  3. package/dist/bitcode-wallet/bitcode-wallet.service.js +72 -0
  4. package/dist/bitcode-wallet/bitcode-wallet.service.js.map +1 -1
  5. package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.d.ts +8 -0
  6. package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.d.ts.map +1 -0
  7. package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.js +40 -0
  8. package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.js.map +1 -0
  9. package/dist/class-group/class-group.controller.d.ts +16 -16
  10. package/dist/class-group/class-group.service.d.ts +12 -12
  11. package/dist/course/course-audio-transcription.service.d.ts +3 -2
  12. package/dist/course/course-audio-transcription.service.d.ts.map +1 -1
  13. package/dist/course/course-audio-transcription.service.js +49 -8
  14. package/dist/course/course-audio-transcription.service.js.map +1 -1
  15. package/dist/course/course-lesson.controller.d.ts +4 -0
  16. package/dist/course/course-lesson.controller.d.ts.map +1 -1
  17. package/dist/course/course-lesson.controller.js +10 -0
  18. package/dist/course/course-lesson.controller.js.map +1 -1
  19. package/dist/course/course-structure.controller.d.ts +11 -4
  20. package/dist/course/course-structure.controller.d.ts.map +1 -1
  21. package/dist/course/course-structure.controller.js +14 -0
  22. package/dist/course/course-structure.controller.js.map +1 -1
  23. package/dist/course/course-structure.service.d.ts +15 -1
  24. package/dist/course/course-structure.service.d.ts.map +1 -1
  25. package/dist/course/course-structure.service.js +139 -4
  26. package/dist/course/course-structure.service.js.map +1 -1
  27. package/dist/course/course-video-conversion.service.d.ts +8 -0
  28. package/dist/course/course-video-conversion.service.d.ts.map +1 -1
  29. package/dist/course/course-video-conversion.service.js +87 -51
  30. package/dist/course/course-video-conversion.service.js.map +1 -1
  31. package/dist/course/course.controller.d.ts +73 -1
  32. package/dist/course/course.controller.d.ts.map +1 -1
  33. package/dist/course/course.controller.js +27 -3
  34. package/dist/course/course.controller.js.map +1 -1
  35. package/dist/course/course.module.d.ts.map +1 -1
  36. package/dist/course/course.module.js +2 -0
  37. package/dist/course/course.module.js.map +1 -1
  38. package/dist/course/course.service.d.ts +108 -4
  39. package/dist/course/course.service.d.ts.map +1 -1
  40. package/dist/course/course.service.js +631 -30
  41. package/dist/course/course.service.js.map +1 -1
  42. package/dist/course/dto/cleanup-course-storage.dto.d.ts +6 -0
  43. package/dist/course/dto/cleanup-course-storage.dto.d.ts.map +1 -0
  44. package/dist/course/dto/cleanup-course-storage.dto.js +33 -0
  45. package/dist/course/dto/cleanup-course-storage.dto.js.map +1 -0
  46. package/dist/course/dto/cleanup-upload-history.dto.d.ts +9 -0
  47. package/dist/course/dto/cleanup-upload-history.dto.d.ts.map +1 -0
  48. package/dist/course/dto/cleanup-upload-history.dto.js +36 -0
  49. package/dist/course/dto/cleanup-upload-history.dto.js.map +1 -0
  50. package/dist/course/dto/create-course-bulk-job.dto.d.ts +4 -0
  51. package/dist/course/dto/create-course-bulk-job.dto.d.ts.map +1 -0
  52. package/dist/course/dto/create-course-bulk-job.dto.js +21 -0
  53. package/dist/course/dto/create-course-bulk-job.dto.js.map +1 -0
  54. package/dist/course/lms-bulk-upload-automation.service.d.ts +39 -0
  55. package/dist/course/lms-bulk-upload-automation.service.d.ts.map +1 -0
  56. package/dist/course/lms-bulk-upload-automation.service.js +443 -0
  57. package/dist/course/lms-bulk-upload-automation.service.js.map +1 -0
  58. package/dist/course/lms-bulk-upload-infra.service.d.ts +31 -0
  59. package/dist/course/lms-bulk-upload-infra.service.d.ts.map +1 -0
  60. package/dist/course/lms-bulk-upload-infra.service.js +277 -0
  61. package/dist/course/lms-bulk-upload-infra.service.js.map +1 -0
  62. package/dist/course/lms-bulk-upload.constants.d.ts +4 -0
  63. package/dist/course/lms-bulk-upload.constants.d.ts.map +1 -0
  64. package/dist/course/lms-bulk-upload.constants.js +7 -0
  65. package/dist/course/lms-bulk-upload.constants.js.map +1 -0
  66. package/dist/course/lms-bulk-upload.controller.d.ts +116 -0
  67. package/dist/course/lms-bulk-upload.controller.d.ts.map +1 -1
  68. package/dist/course/lms-bulk-upload.controller.js +71 -2
  69. package/dist/course/lms-bulk-upload.controller.js.map +1 -1
  70. package/dist/course/lms-bulk-upload.service.d.ts +142 -3
  71. package/dist/course/lms-bulk-upload.service.d.ts.map +1 -1
  72. package/dist/course/lms-bulk-upload.service.js +606 -21
  73. package/dist/course/lms-bulk-upload.service.js.map +1 -1
  74. package/dist/course/lms-setting.controller.d.ts +4 -1
  75. package/dist/course/lms-setting.controller.d.ts.map +1 -1
  76. package/dist/course/lms-setting.controller.js +21 -6
  77. package/dist/course/lms-setting.controller.js.map +1 -1
  78. package/dist/enterprise/enterprise.controller.d.ts +20 -20
  79. package/dist/enterprise/enterprise.service.d.ts +20 -20
  80. package/dist/enterprise/training/training-admin.controller.d.ts +11 -11
  81. package/dist/enterprise/training/training-admin.service.d.ts +11 -11
  82. package/dist/enterprise/training/training-instructor.controller.d.ts +2 -2
  83. package/dist/enterprise/training/training-instructor.service.d.ts +2 -2
  84. package/dist/enterprise/training/training-student.controller.d.ts +1 -1
  85. package/dist/enterprise/training/training-student.service.d.ts +1 -1
  86. package/dist/enterprise/training/training-viewer.controller.d.ts +2 -2
  87. package/dist/evaluation/evaluation.controller.d.ts +8 -8
  88. package/dist/evaluation/evaluation.service.d.ts +8 -8
  89. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.d.ts +6 -0
  90. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.d.ts.map +1 -0
  91. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.js +34 -0
  92. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.js.map +1 -0
  93. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.d.ts +28 -0
  94. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.d.ts.map +1 -0
  95. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.js +123 -0
  96. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.js.map +1 -0
  97. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.d.ts +4 -0
  98. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.d.ts.map +1 -0
  99. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.js +22 -0
  100. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.js.map +1 -0
  101. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.d.ts +10 -0
  102. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.d.ts.map +1 -0
  103. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.js +52 -0
  104. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.js.map +1 -0
  105. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.d.ts +15 -0
  106. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.d.ts.map +1 -0
  107. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.js +86 -0
  108. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.js.map +1 -0
  109. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.d.ts +26 -0
  110. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.d.ts.map +1 -0
  111. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.js +304 -0
  112. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.js.map +1 -0
  113. package/dist/lesson-xp-map/lesson-xp-map.controller.d.ts +87 -0
  114. package/dist/lesson-xp-map/lesson-xp-map.controller.d.ts.map +1 -0
  115. package/dist/lesson-xp-map/lesson-xp-map.controller.js +185 -0
  116. package/dist/lesson-xp-map/lesson-xp-map.controller.js.map +1 -0
  117. package/dist/lesson-xp-map/lesson-xp-map.module.d.ts +3 -0
  118. package/dist/lesson-xp-map/lesson-xp-map.module.d.ts.map +1 -0
  119. package/dist/lesson-xp-map/lesson-xp-map.module.js +34 -0
  120. package/dist/lesson-xp-map/lesson-xp-map.module.js.map +1 -0
  121. package/dist/lesson-xp-map/lesson-xp-map.service.d.ts +84 -0
  122. package/dist/lesson-xp-map/lesson-xp-map.service.d.ts.map +1 -0
  123. package/dist/lesson-xp-map/lesson-xp-map.service.js +353 -0
  124. package/dist/lesson-xp-map/lesson-xp-map.service.js.map +1 -0
  125. package/dist/lesson-xp-map/lesson-xp-segment.controller.d.ts +10 -0
  126. package/dist/lesson-xp-map/lesson-xp-segment.controller.d.ts.map +1 -0
  127. package/dist/lesson-xp-map/lesson-xp-segment.controller.js +63 -0
  128. package/dist/lesson-xp-map/lesson-xp-segment.controller.js.map +1 -0
  129. package/dist/lesson-xp-map/lesson-xp-segment.service.d.ts +27 -0
  130. package/dist/lesson-xp-map/lesson-xp-segment.service.d.ts.map +1 -0
  131. package/dist/lesson-xp-map/lesson-xp-segment.service.js +194 -0
  132. package/dist/lesson-xp-map/lesson-xp-segment.service.js.map +1 -0
  133. package/dist/libraries/lms/tsconfig.tsbuildinfo +1 -0
  134. package/dist/lms.module.d.ts.map +1 -1
  135. package/dist/lms.module.js +17 -2
  136. package/dist/lms.module.js.map +1 -1
  137. package/dist/platforma/dto/update-profile.dto.d.ts +17 -0
  138. package/dist/platforma/dto/update-profile.dto.d.ts.map +1 -0
  139. package/dist/platforma/dto/update-profile.dto.js +87 -0
  140. package/dist/platforma/dto/update-profile.dto.js.map +1 -0
  141. package/dist/platforma/platforma.controller.d.ts +88 -1
  142. package/dist/platforma/platforma.controller.d.ts.map +1 -1
  143. package/dist/platforma/platforma.controller.js +85 -2
  144. package/dist/platforma/platforma.controller.js.map +1 -1
  145. package/dist/platforma/platforma.service.d.ts +27 -0
  146. package/dist/platforma/platforma.service.d.ts.map +1 -0
  147. package/dist/platforma/platforma.service.js +274 -0
  148. package/dist/platforma/platforma.service.js.map +1 -0
  149. package/dist/student-xp/student-xp.controller.d.ts +41 -0
  150. package/dist/student-xp/student-xp.controller.d.ts.map +1 -0
  151. package/dist/student-xp/student-xp.controller.js +114 -0
  152. package/dist/student-xp/student-xp.controller.js.map +1 -0
  153. package/dist/student-xp/student-xp.module.d.ts +3 -0
  154. package/dist/student-xp/student-xp.module.d.ts.map +1 -0
  155. package/dist/student-xp/student-xp.module.js +25 -0
  156. package/dist/student-xp/student-xp.module.js.map +1 -0
  157. package/dist/student-xp/student-xp.service.d.ts +65 -0
  158. package/dist/student-xp/student-xp.service.d.ts.map +1 -0
  159. package/dist/student-xp/student-xp.service.js +197 -0
  160. package/dist/student-xp/student-xp.service.js.map +1 -0
  161. package/dist/xp-catalog/dto/create-xp-area.dto.d.ts +12 -0
  162. package/dist/xp-catalog/dto/create-xp-area.dto.d.ts.map +1 -0
  163. package/dist/xp-catalog/dto/create-xp-area.dto.js +63 -0
  164. package/dist/xp-catalog/dto/create-xp-area.dto.js.map +1 -0
  165. package/dist/xp-catalog/dto/create-xp-learning-type.dto.d.ts +11 -0
  166. package/dist/xp-catalog/dto/create-xp-learning-type.dto.d.ts.map +1 -0
  167. package/dist/xp-catalog/dto/create-xp-learning-type.dto.js +57 -0
  168. package/dist/xp-catalog/dto/create-xp-learning-type.dto.js.map +1 -0
  169. package/dist/xp-catalog/dto/create-xp-skill.dto.d.ts +11 -0
  170. package/dist/xp-catalog/dto/create-xp-skill.dto.d.ts.map +1 -0
  171. package/dist/xp-catalog/dto/create-xp-skill.dto.js +57 -0
  172. package/dist/xp-catalog/dto/create-xp-skill.dto.js.map +1 -0
  173. package/dist/xp-catalog/dto/update-xp-area.dto.d.ts +12 -0
  174. package/dist/xp-catalog/dto/update-xp-area.dto.d.ts.map +1 -0
  175. package/dist/xp-catalog/dto/update-xp-area.dto.js +66 -0
  176. package/dist/xp-catalog/dto/update-xp-area.dto.js.map +1 -0
  177. package/dist/xp-catalog/dto/update-xp-learning-type.dto.d.ts +11 -0
  178. package/dist/xp-catalog/dto/update-xp-learning-type.dto.d.ts.map +1 -0
  179. package/dist/xp-catalog/dto/update-xp-learning-type.dto.js +60 -0
  180. package/dist/xp-catalog/dto/update-xp-learning-type.dto.js.map +1 -0
  181. package/dist/xp-catalog/dto/update-xp-skill.dto.d.ts +11 -0
  182. package/dist/xp-catalog/dto/update-xp-skill.dto.d.ts.map +1 -0
  183. package/dist/xp-catalog/dto/update-xp-skill.dto.js +60 -0
  184. package/dist/xp-catalog/dto/update-xp-skill.dto.js.map +1 -0
  185. package/dist/xp-catalog/xp-area.controller.d.ts +25 -0
  186. package/dist/xp-catalog/xp-area.controller.d.ts.map +1 -0
  187. package/dist/xp-catalog/xp-area.controller.js +105 -0
  188. package/dist/xp-catalog/xp-area.controller.js.map +1 -0
  189. package/dist/xp-catalog/xp-area.service.d.ts +35 -0
  190. package/dist/xp-catalog/xp-area.service.d.ts.map +1 -0
  191. package/dist/xp-catalog/xp-area.service.js +168 -0
  192. package/dist/xp-catalog/xp-area.service.js.map +1 -0
  193. package/dist/xp-catalog/xp-catalog.module.d.ts +3 -0
  194. package/dist/xp-catalog/xp-catalog.module.d.ts.map +1 -0
  195. package/dist/xp-catalog/xp-catalog.module.js +29 -0
  196. package/dist/xp-catalog/xp-catalog.module.js.map +1 -0
  197. package/dist/xp-catalog/xp-learning-type.controller.d.ts +20 -0
  198. package/dist/xp-catalog/xp-learning-type.controller.d.ts.map +1 -0
  199. package/dist/xp-catalog/xp-learning-type.controller.js +96 -0
  200. package/dist/xp-catalog/xp-learning-type.controller.js.map +1 -0
  201. package/dist/xp-catalog/xp-learning-type.service.d.ts +30 -0
  202. package/dist/xp-catalog/xp-learning-type.service.d.ts.map +1 -0
  203. package/dist/xp-catalog/xp-learning-type.service.js +146 -0
  204. package/dist/xp-catalog/xp-learning-type.service.js.map +1 -0
  205. package/dist/xp-catalog/xp-skill.controller.d.ts +26 -0
  206. package/dist/xp-catalog/xp-skill.controller.d.ts.map +1 -0
  207. package/dist/xp-catalog/xp-skill.controller.js +113 -0
  208. package/dist/xp-catalog/xp-skill.controller.js.map +1 -0
  209. package/dist/xp-catalog/xp-skill.service.d.ts +37 -0
  210. package/dist/xp-catalog/xp-skill.service.d.ts.map +1 -0
  211. package/dist/xp-catalog/xp-skill.service.js +174 -0
  212. package/dist/xp-catalog/xp-skill.service.js.map +1 -0
  213. package/hedhog/data/menu.yaml +101 -0
  214. package/hedhog/data/route.yaml +512 -0
  215. package/hedhog/data/setting_group.yaml +1 -1
  216. package/hedhog/data/xp_area.yaml +164 -0
  217. package/hedhog/data/xp_learning_type.yaml +131 -0
  218. package/hedhog/data/xp_skill.yaml +1834 -0
  219. package/hedhog/frontend/app/achievements/page.tsx.ejs +108 -118
  220. package/hedhog/frontend/app/bitcodes/page.tsx.ejs +22 -34
  221. package/hedhog/frontend/app/bulk-upload-sessions/page.tsx.ejs +1453 -0
  222. package/hedhog/frontend/app/certificates/models/page.tsx.ejs +21 -45
  223. package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +40 -74
  224. package/hedhog/frontend/app/classes/page.tsx.ejs +56 -85
  225. package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +3 -2
  226. package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +48 -5
  227. package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +4 -4
  228. package/hedhog/frontend/app/courses/[id]/structure/_components/course-operations-tab.tsx.ejs +19 -2
  229. package/hedhog/frontend/app/courses/[id]/structure/_components/course-overview-tab.tsx.ejs +1170 -0
  230. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +16 -0
  231. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +2 -0
  232. package/hedhog/frontend/app/courses/[id]/structure/_components/course-xp-overview-tab.tsx.ejs +623 -0
  233. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson-xp-tab.tsx.ejs +1458 -0
  234. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +55 -2
  235. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +442 -104
  236. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +296 -49
  237. package/hedhog/frontend/app/courses/[id]/structure/_components/sortable-tree-row.tsx.ejs +3 -0
  238. package/hedhog/frontend/app/courses/[id]/structure/_components/store.ts.ejs +1 -0
  239. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +101 -85
  240. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +21 -1
  241. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row.tsx.ejs +3 -0
  242. package/hedhog/frontend/app/courses/[id]/structure/_components/use-tree-display-settings.ts.ejs +7 -1
  243. package/hedhog/frontend/app/courses/[id]/structure/_components/xp-premium-pills.tsx.ejs +44 -0
  244. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-content-overview.ts.ejs +54 -0
  245. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +52 -0
  246. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-xp-overview.ts.ejs +76 -0
  247. package/hedhog/frontend/app/courses/[id]/structure/_data/use-lesson-xp-map.ts.ejs +128 -0
  248. package/hedhog/frontend/app/courses/[id]/structure/_data/use-transcription-segments.ts.ejs +30 -0
  249. package/hedhog/frontend/app/courses/[id]/structure/_utils/xp-color-config.ts.ejs +115 -0
  250. package/hedhog/frontend/app/courses/_components/CourseDeleteDialog.tsx.ejs +223 -0
  251. package/hedhog/frontend/app/courses/_components/CourseRowActions.tsx.ejs +89 -0
  252. package/hedhog/frontend/app/courses/page.tsx.ejs +400 -230
  253. package/hedhog/frontend/app/enterprise/page.tsx.ejs +39 -63
  254. package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +53 -77
  255. package/hedhog/frontend/app/exams/page.tsx.ejs +54 -90
  256. package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +23 -36
  257. package/hedhog/frontend/app/instructors/page.tsx.ejs +72 -81
  258. package/hedhog/frontend/app/paths/page.tsx.ejs +40 -68
  259. package/hedhog/frontend/app/training/page.tsx.ejs +40 -68
  260. package/hedhog/frontend/app/xp/areas/page.tsx.ejs +782 -0
  261. package/hedhog/frontend/app/xp/learning-types/page.tsx.ejs +690 -0
  262. package/hedhog/frontend/app/xp/skills/page.tsx.ejs +811 -0
  263. package/hedhog/frontend/messages/en.json +386 -3
  264. package/hedhog/frontend/messages/pt.json +386 -3
  265. package/hedhog/table/lesson_xp_map.yaml +50 -0
  266. package/hedhog/table/lesson_xp_segment.yaml +40 -0
  267. package/hedhog/table/lesson_xp_segment_area.yaml +24 -0
  268. package/hedhog/table/lesson_xp_segment_learning_type.yaml +24 -0
  269. package/hedhog/table/lesson_xp_segment_skill.yaml +24 -0
  270. package/hedhog/table/lms_bulk_upload_item.yaml +44 -0
  271. package/hedhog/table/lms_bulk_upload_session.yaml +42 -0
  272. package/hedhog/table/student_area_xp.yaml +30 -0
  273. package/hedhog/table/student_learning_type_xp.yaml +30 -0
  274. package/hedhog/table/student_skill_xp.yaml +30 -0
  275. package/hedhog/table/student_xp_event.yaml +34 -0
  276. package/hedhog/table/xp_area.yaml +39 -0
  277. package/hedhog/table/xp_learning_type.yaml +34 -0
  278. package/hedhog/table/xp_skill.yaml +39 -0
  279. package/package.json +8 -7
  280. package/src/bitcode-wallet/bitcode-wallet.service.ts +113 -0
  281. package/src/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.ts +32 -0
  282. package/src/course/course-audio-transcription.service.ts +58 -21
  283. package/src/course/course-lesson.controller.ts +6 -1
  284. package/src/course/course-structure.controller.ts +10 -0
  285. package/src/course/course-structure.service.ts +174 -1
  286. package/src/course/course-video-conversion.service.ts +113 -75
  287. package/src/course/course.controller.ts +22 -3
  288. package/src/course/course.module.ts +2 -0
  289. package/src/course/course.service.ts +847 -30
  290. package/src/course/dto/cleanup-course-storage.dto.ts +22 -0
  291. package/src/course/dto/cleanup-upload-history.dto.ts +26 -0
  292. package/src/course/dto/create-course-bulk-job.dto.ts +6 -0
  293. package/src/course/lms-bulk-upload-automation.service.ts +560 -0
  294. package/src/course/lms-bulk-upload-infra.service.ts +327 -0
  295. package/src/course/lms-bulk-upload.constants.ts +5 -0
  296. package/src/course/lms-bulk-upload.controller.ts +79 -3
  297. package/src/course/lms-bulk-upload.service.ts +1029 -204
  298. package/src/course/lms-setting.controller.ts +22 -6
  299. package/src/lesson-xp-map/dto/create-lesson-xp-map.dto.ts +17 -0
  300. package/src/lesson-xp-map/dto/create-lesson-xp-segment.dto.ts +102 -0
  301. package/src/lesson-xp-map/dto/review-lesson-xp-map.dto.ts +7 -0
  302. package/src/lesson-xp-map/dto/update-lesson-xp-map.dto.ts +36 -0
  303. package/src/lesson-xp-map/dto/update-lesson-xp-segment.dto.ts +78 -0
  304. package/src/lesson-xp-map/lesson-xp-ai-calculation.service.ts +396 -0
  305. package/src/lesson-xp-map/lesson-xp-map.controller.ts +116 -0
  306. package/src/lesson-xp-map/lesson-xp-map.module.ts +21 -0
  307. package/src/lesson-xp-map/lesson-xp-map.service.ts +442 -0
  308. package/src/lesson-xp-map/lesson-xp-segment.controller.ts +36 -0
  309. package/src/lesson-xp-map/lesson-xp-segment.service.ts +229 -0
  310. package/src/lms.module.ts +17 -2
  311. package/src/platforma/dto/update-profile.dto.ts +59 -0
  312. package/src/platforma/platforma.controller.ts +57 -2
  313. package/src/platforma/platforma.service.ts +268 -0
  314. package/src/student-xp/student-xp.controller.ts +76 -0
  315. package/src/student-xp/student-xp.module.ts +12 -0
  316. package/src/student-xp/student-xp.service.ts +236 -0
  317. package/src/xp-catalog/dto/create-xp-area.dto.ts +40 -0
  318. package/src/xp-catalog/dto/create-xp-learning-type.dto.ts +35 -0
  319. package/src/xp-catalog/dto/create-xp-skill.dto.ts +35 -0
  320. package/src/xp-catalog/dto/update-xp-area.dto.ts +43 -0
  321. package/src/xp-catalog/dto/update-xp-learning-type.dto.ts +38 -0
  322. package/src/xp-catalog/dto/update-xp-skill.dto.ts +38 -0
  323. package/src/xp-catalog/xp-area.controller.ts +64 -0
  324. package/src/xp-catalog/xp-area.service.ts +196 -0
  325. package/src/xp-catalog/xp-catalog.module.ts +16 -0
  326. package/src/xp-catalog/xp-learning-type.controller.ts +59 -0
  327. package/src/xp-catalog/xp-learning-type.service.ts +170 -0
  328. package/src/xp-catalog/xp-skill.controller.ts +71 -0
  329. package/src/xp-catalog/xp-skill.service.ts +205 -0
@@ -19,15 +19,10 @@ import {
19
19
  DialogHeader,
20
20
  DialogTitle,
21
21
  } from '@/components/ui/dialog';
22
- import {
23
- DropdownMenu,
24
- DropdownMenuContent,
25
- DropdownMenuItem,
26
- DropdownMenuSeparator,
27
- DropdownMenuTrigger,
28
- } from '@/components/ui/dropdown-menu';
22
+ import { IconActionGroup } from '@/components/ui/icon-action-group';
29
23
  import { Input } from '@/components/ui/input';
30
24
  import { KpiCardsGrid, type KpiCardItem } from '@/components/ui/kpi-cards-grid';
25
+ import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
31
26
  import {
32
27
  Select,
33
28
  SelectContent,
@@ -42,9 +37,9 @@ import {
42
37
  SheetHeader,
43
38
  SheetTitle,
44
39
  } from '@/components/ui/sheet';
45
- import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
46
40
  import { Skeleton } from '@/components/ui/skeleton';
47
41
  import { Textarea } from '@/components/ui/textarea';
42
+ import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
48
43
  import { useApp, useQuery } from '@hed-hog/next-app-provider';
49
44
  import { zodResolver } from '@hookform/resolvers/zod';
50
45
  import {
@@ -56,14 +51,12 @@ import {
56
51
  FilePlus2,
57
52
  Files,
58
53
  Loader2,
59
- MoreHorizontal,
60
54
  Pencil,
61
55
  Trash2,
62
56
  } from 'lucide-react';
63
57
  import { useLocale, useTranslations } from 'next-intl';
64
58
  import { useRouter } from 'next/navigation';
65
59
  import { useEffect, useMemo, useRef, useState } from 'react';
66
- import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
67
60
  import { Controller, useForm } from 'react-hook-form';
68
61
  import { toast } from 'sonner';
69
62
  import { z } from 'zod';
@@ -621,41 +614,24 @@ export default function ModelsPage() {
621
614
  <CardContent className="space-y-4 p-5">
622
615
  <div className="flex items-start justify-between gap-2">
623
616
  {renderStatusBadge(template.status)}
624
- <div
625
- className="flex items-center gap-1"
626
- onClick={(e) => e.stopPropagation()}
627
- >
628
- <DropdownMenu>
629
- <DropdownMenuTrigger asChild>
630
- <Button
631
- type="button"
632
- variant="ghost"
633
- size="icon"
634
- className="size-8"
635
- aria-label={t('cards.actions.menuLabel')}
636
- >
637
- <MoreHorizontal className="size-4" />
638
- </Button>
639
- </DropdownMenuTrigger>
640
- <DropdownMenuContent align="end" className="w-48">
641
- <DropdownMenuItem
642
- onClick={() => openEditSheet(template)}
643
- >
644
- <Pencil className="mr-2 size-4" />
645
- {t('cards.actions.editTemplate')}
646
- </DropdownMenuItem>
647
- <DropdownMenuSeparator />
648
- <DropdownMenuItem
649
- className="text-destructive focus:text-destructive"
650
- onClick={() => onDeleteTemplate(template)}
651
- disabled={deletingTemplateId === template.id}
652
- >
653
- <Trash2 className="mr-2 size-4" />
654
- {t('cards.actions.deleteTemplate')}
655
- </DropdownMenuItem>
656
- </DropdownMenuContent>
657
- </DropdownMenu>
658
- </div>
617
+ <IconActionGroup
618
+ actions={[
619
+ {
620
+ key: 'edit',
621
+ label: t('cards.actions.editTemplate'),
622
+ icon: <Pencil className="size-4" />,
623
+ onClick: () => openEditSheet(template),
624
+ },
625
+ {
626
+ key: 'delete',
627
+ label: t('cards.actions.deleteTemplate'),
628
+ icon: <Trash2 className="size-4" />,
629
+ onClick: () => onDeleteTemplate(template),
630
+ destructive: true,
631
+ disabled: deletingTemplateId === template.id,
632
+ },
633
+ ]}
634
+ />
659
635
  </div>
660
636
 
661
637
  <div className="space-y-1">
@@ -30,14 +30,8 @@ import {
30
30
  DialogHeader,
31
31
  DialogTitle,
32
32
  } from '@/components/ui/dialog';
33
- import {
34
- DropdownMenu,
35
- DropdownMenuContent,
36
- DropdownMenuItem,
37
- DropdownMenuSeparator,
38
- DropdownMenuTrigger,
39
- } from '@/components/ui/dropdown-menu';
40
33
  import { Field, FieldError, FieldLabel } from '@/components/ui/field';
34
+ import { IconActionGroup } from '@/components/ui/icon-action-group';
41
35
  import { Input } from '@/components/ui/input';
42
36
  import { KpiCardsGrid, type KpiCardItem } from '@/components/ui/kpi-cards-grid';
43
37
  import {
@@ -45,6 +39,7 @@ import {
45
39
  PopoverContent,
46
40
  PopoverTrigger,
47
41
  } from '@/components/ui/popover';
42
+ import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
48
43
  import {
49
44
  Select,
50
45
  SelectContent,
@@ -59,7 +54,6 @@ import {
59
54
  SheetHeader,
60
55
  SheetTitle,
61
56
  } from '@/components/ui/sheet';
62
- import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
63
57
  import { Skeleton } from '@/components/ui/skeleton';
64
58
  import { Switch } from '@/components/ui/switch';
65
59
  import {
@@ -118,7 +112,6 @@ import {
118
112
  Loader2,
119
113
  MapPin,
120
114
  Monitor,
121
- MoreHorizontal,
122
115
  Paperclip,
123
116
  Pencil,
124
117
  Plus,
@@ -3018,41 +3011,26 @@ export default function TurmaDetalhePage() {
3018
3011
 
3019
3012
  {/* Ações */}
3020
3013
  <TableCell>
3021
- <DropdownMenu>
3022
- <DropdownMenuTrigger asChild>
3023
- <Button
3024
- variant="ghost"
3025
- size="icon"
3026
- className="size-7"
3027
- onClick={(e) => e.stopPropagation()}
3028
- >
3029
- <MoreHorizontal className="size-4" />
3030
- </Button>
3031
- </DropdownMenuTrigger>
3032
- <DropdownMenuContent align="end">
3033
- <DropdownMenuItem
3034
- onClick={(e) => {
3035
- e.stopPropagation();
3036
- openAulaSheet(aula);
3037
- }}
3038
- >
3039
- <Pencil className="mr-2 size-4" />
3040
- Editar
3041
- </DropdownMenuItem>
3042
- <DropdownMenuSeparator />
3043
- <DropdownMenuItem
3044
- className="text-destructive focus:text-destructive"
3045
- onClick={(e) => {
3046
- e.stopPropagation();
3014
+ <IconActionGroup
3015
+ actions={[
3016
+ {
3017
+ key: 'edit-lesson',
3018
+ label: 'Editar',
3019
+ icon: <Pencil className="size-4" />,
3020
+ onClick: () => openAulaSheet(aula),
3021
+ },
3022
+ {
3023
+ key: 'delete-lesson',
3024
+ label: 'Remover',
3025
+ icon: <Trash2 className="size-4" />,
3026
+ onClick: () => {
3047
3027
  setAulaToDelete(aula);
3048
3028
  setDeleteAulaDialogOpen(true);
3049
- }}
3050
- >
3051
- <Trash2 className="mr-2 size-4" />
3052
- Remover
3053
- </DropdownMenuItem>
3054
- </DropdownMenuContent>
3055
- </DropdownMenu>
3029
+ },
3030
+ destructive: true,
3031
+ },
3032
+ ]}
3033
+ />
3056
3034
  </TableCell>
3057
3035
  </TableRow>
3058
3036
  );
@@ -3392,41 +3370,29 @@ export default function TurmaDetalhePage() {
3392
3370
  {aluno.status}
3393
3371
  </Badge>
3394
3372
  </div>
3395
- <DropdownMenu>
3396
- <DropdownMenuTrigger asChild>
3397
- <Button
3398
- variant="ghost"
3399
- size="icon"
3400
- className="size-8 shrink-0 opacity-0 group-hover:opacity-100"
3401
- onClick={(e) => e.stopPropagation()}
3402
- >
3403
- <MoreHorizontal className="size-4" />
3404
- </Button>
3405
- </DropdownMenuTrigger>
3406
- <DropdownMenuContent align="end">
3407
- <DropdownMenuItem
3408
- onClick={(e) => {
3409
- e.stopPropagation();
3373
+ <IconActionGroup
3374
+ className="opacity-0 transition-opacity group-hover:opacity-100"
3375
+ actions={[
3376
+ {
3377
+ key: 'view-profile',
3378
+ label: t('students.menu.viewProfile'),
3379
+ icon: <Eye className="size-4" />,
3380
+ onClick: () => {
3410
3381
  void openStudentProfile(aluno.id);
3411
- }}
3412
- >
3413
- <Eye className="mr-2 size-4" />
3414
- {t('students.menu.viewProfile')}
3415
- </DropdownMenuItem>
3416
- <DropdownMenuSeparator />
3417
- <DropdownMenuItem
3418
- className="text-destructive"
3419
- onClick={(e) => {
3420
- e.stopPropagation();
3382
+ },
3383
+ },
3384
+ {
3385
+ key: 'remove-from-class',
3386
+ label: t('students.menu.removeFromClass'),
3387
+ icon: <UserMinus className="size-4" />,
3388
+ onClick: () => {
3421
3389
  setAlunoToRemove(aluno);
3422
3390
  setRemoveAlunoDialogOpen(true);
3423
- }}
3424
- >
3425
- <UserMinus className="mr-2 size-4" />
3426
- {t('students.menu.removeFromClass')}
3427
- </DropdownMenuItem>
3428
- </DropdownMenuContent>
3429
- </DropdownMenu>
3391
+ },
3392
+ destructive: true,
3393
+ },
3394
+ ]}
3395
+ />
3430
3396
  </div>
3431
3397
  );
3432
3398
  })}
@@ -20,13 +20,7 @@ import {
20
20
  DialogHeader,
21
21
  DialogTitle,
22
22
  } from '@/components/ui/dialog';
23
- import {
24
- DropdownMenu,
25
- DropdownMenuContent,
26
- DropdownMenuItem,
27
- DropdownMenuSeparator,
28
- DropdownMenuTrigger,
29
- } from '@/components/ui/dropdown-menu';
23
+ import { IconActionGroup } from '@/components/ui/icon-action-group';
30
24
  import { KpiCardsGrid, type KpiCardItem } from '@/components/ui/kpi-cards-grid';
31
25
  import { Skeleton } from '@/components/ui/skeleton';
32
26
  import {
@@ -52,7 +46,6 @@ import {
52
46
  Loader2,
53
47
  MapPin,
54
48
  Monitor,
55
- MoreHorizontal,
56
49
  Pencil,
57
50
  Plus,
58
51
  Trash2,
@@ -531,8 +524,8 @@ export default function TurmasPage() {
531
524
  filtroTipoInput !== 'todos' ||
532
525
  filtroCursoInput !== 'todos';
533
526
 
534
- function openDeleteDialog(turma: Turma, e: React.MouseEvent) {
535
- e.stopPropagation();
527
+ function openDeleteDialog(turma: Turma, e?: React.MouseEvent) {
528
+ e?.stopPropagation();
536
529
  setTurmaToDelete(turma);
537
530
  setDeleteDialogOpen(true);
538
531
  }
@@ -902,44 +895,31 @@ export default function TurmasPage() {
902
895
  <h3 className="line-clamp-2 font-semibold leading-snug text-foreground">
903
896
  {turma.curso}
904
897
  </h3>
905
- <DropdownMenu>
906
- <DropdownMenuTrigger asChild>
907
- <Button
908
- variant="ghost"
909
- size="icon"
910
- className="size-8 shrink-0 -mr-2 -mt-1"
911
- onClick={(e) => e.stopPropagation()}
912
- aria-label={t('cards.actions.label')}
913
- >
914
- <MoreHorizontal className="size-4" />
915
- </Button>
916
- </DropdownMenuTrigger>
917
- <DropdownMenuContent align="end" className="w-48">
918
- <DropdownMenuItem
919
- onClick={(e) => {
920
- e.stopPropagation();
921
- router.push(`/lms/classes/${turma.id}`);
922
- }}
923
- >
924
- <Eye className="mr-2 size-4" />{' '}
925
- {t('cards.actions.viewDetails')}
926
- </DropdownMenuItem>
927
- <DropdownMenuItem
928
- onClick={(e) => openEditSheet(turma, e)}
929
- >
930
- <Pencil className="mr-2 size-4" />{' '}
931
- {t('cards.actions.edit')}
932
- </DropdownMenuItem>
933
- <DropdownMenuSeparator />
934
- <DropdownMenuItem
935
- className="text-destructive focus:text-destructive"
936
- onClick={(e) => openDeleteDialog(turma, e)}
937
- >
938
- <Trash2 className="mr-2 size-4" />{' '}
939
- {t('cards.actions.delete')}
940
- </DropdownMenuItem>
941
- </DropdownMenuContent>
942
- </DropdownMenu>
898
+ <IconActionGroup
899
+ className="-mr-2 -mt-1 ml-auto"
900
+ actions={[
901
+ {
902
+ key: 'view',
903
+ label: t('cards.actions.viewDetails'),
904
+ icon: <Eye className="size-4" />,
905
+ onClick: () =>
906
+ router.push(`/lms/classes/${turma.id}`),
907
+ },
908
+ {
909
+ key: 'edit',
910
+ label: t('cards.actions.edit'),
911
+ icon: <Pencil className="size-4" />,
912
+ onClick: () => openEditSheet(turma),
913
+ },
914
+ {
915
+ key: 'delete',
916
+ label: t('cards.actions.delete'),
917
+ icon: <Trash2 className="size-4" />,
918
+ onClick: () => openDeleteDialog(turma),
919
+ destructive: true,
920
+ },
921
+ ]}
922
+ />
943
923
  </div>
944
924
  <div className="mt-1 flex items-center gap-1.5 text-xs text-muted-foreground">
945
925
  <code className="rounded bg-muted px-1.5 py-0.5 font-mono text-[10px]">
@@ -952,7 +932,9 @@ export default function TurmasPage() {
952
932
  alt={turma.professor}
953
933
  className="size-4 rounded-full object-cover"
954
934
  onError={(e) => {
955
- (e.currentTarget as HTMLImageElement).style.display = 'none';
935
+ (
936
+ e.currentTarget as HTMLImageElement
937
+ ).style.display = 'none';
956
938
  }}
957
939
  />
958
940
  ) : (
@@ -1132,42 +1114,31 @@ export default function TurmasPage() {
1132
1114
  {turma.matriculados}
1133
1115
  </TableCell>
1134
1116
  <TableCell onClick={(e) => e.stopPropagation()}>
1135
- <DropdownMenu>
1136
- <DropdownMenuTrigger asChild>
1137
- <Button
1138
- variant="ghost"
1139
- size="icon"
1140
- className="ml-auto size-8"
1141
- aria-label={t('cards.actions.label')}
1142
- >
1143
- <MoreHorizontal className="size-4" />
1144
- </Button>
1145
- </DropdownMenuTrigger>
1146
- <DropdownMenuContent align="end" className="w-48">
1147
- <DropdownMenuItem
1148
- onClick={() =>
1149
- router.push(`/lms/classes/${turma.id}`)
1150
- }
1151
- >
1152
- <Eye className="mr-2 size-4" />{' '}
1153
- {t('cards.actions.viewDetails')}
1154
- </DropdownMenuItem>
1155
- <DropdownMenuItem
1156
- onClick={() => openEditSheet(turma)}
1157
- >
1158
- <Pencil className="mr-2 size-4" />{' '}
1159
- {t('cards.actions.edit')}
1160
- </DropdownMenuItem>
1161
- <DropdownMenuSeparator />
1162
- <DropdownMenuItem
1163
- className="text-destructive focus:text-destructive"
1164
- onClick={(e) => openDeleteDialog(turma, e)}
1165
- >
1166
- <Trash2 className="mr-2 size-4" />{' '}
1167
- {t('cards.actions.delete')}
1168
- </DropdownMenuItem>
1169
- </DropdownMenuContent>
1170
- </DropdownMenu>
1117
+ <IconActionGroup
1118
+ className="ml-auto"
1119
+ actions={[
1120
+ {
1121
+ key: 'view',
1122
+ label: t('cards.actions.viewDetails'),
1123
+ icon: <Eye className="size-4" />,
1124
+ onClick: () =>
1125
+ router.push(`/lms/classes/${turma.id}`),
1126
+ },
1127
+ {
1128
+ key: 'edit',
1129
+ label: t('cards.actions.edit'),
1130
+ icon: <Pencil className="size-4" />,
1131
+ onClick: () => openEditSheet(turma),
1132
+ },
1133
+ {
1134
+ key: 'delete',
1135
+ label: t('cards.actions.delete'),
1136
+ icon: <Trash2 className="size-4" />,
1137
+ onClick: () => openDeleteDialog(turma),
1138
+ destructive: true,
1139
+ },
1140
+ ]}
1141
+ />
1171
1142
  </TableCell>
1172
1143
  </TableRow>
1173
1144
  );
@@ -45,8 +45,9 @@ export function CourseDangerZoneCard({
45
45
  </Button>
46
46
  </TooltipTrigger>
47
47
  <TooltipContent side="top" className="max-w-60 text-xs">
48
- Remove o curso, turmas, matrículas e certificados vinculados
49
- permanentemente.
48
+ Arquive o curso antes da exclusão. O processo remove em background o
49
+ curso e os arquivos relacionados, com progresso no sino de
50
+ notificações.
50
51
  </TooltipContent>
51
52
  </Tooltip>
52
53
  </TooltipProvider>
@@ -1,4 +1,6 @@
1
1
  import { Button } from '@/components/ui/button';
2
+ import { FileTypeIcon } from '@/components/file-type-icon';
3
+ import Image from 'next/image';
2
4
  import {
3
5
  Tooltip,
4
6
  TooltipContent,
@@ -21,6 +23,8 @@ import type { TranslationFn } from './course-edit-types';
21
23
  type MediaFile = {
22
24
  id: number;
23
25
  name: string;
26
+ size?: number | null;
27
+ mimeType?: string | null;
24
28
  };
25
29
 
26
30
  type ImageTypeSpec = {
@@ -53,6 +57,26 @@ function MediaRow({
53
57
  }: MediaRowProps) {
54
58
  const inputRef = useRef<HTMLInputElement>(null);
55
59
 
60
+ function formatFileSize(bytes?: number | null) {
61
+ if (bytes == null || Number.isNaN(bytes)) return null;
62
+ if (bytes < 1024) return `${bytes} B`;
63
+
64
+ const units = ['KB', 'MB', 'GB', 'TB'];
65
+ let value = bytes / 1024;
66
+ let unitIndex = 0;
67
+
68
+ while (value >= 1024 && unitIndex < units.length - 1) {
69
+ value /= 1024;
70
+ unitIndex += 1;
71
+ }
72
+
73
+ const fractionDigits = value >= 10 ? 0 : 1;
74
+ return `${value.toFixed(fractionDigits)} ${units[unitIndex]}`;
75
+ }
76
+
77
+ const fileSizeLabel = formatFileSize(file?.size);
78
+ const fileTypeLabel = file?.mimeType?.trim() || null;
79
+
56
80
  const specParts: string[] = [];
57
81
  if (imageType?.suggestedWidth && imageType?.suggestedHeight) {
58
82
  specParts.push(
@@ -86,10 +110,13 @@ function MediaRow({
86
110
 
87
111
  <div className="relative h-40 w-full overflow-hidden rounded-xl border border-border/70 bg-muted/30">
88
112
  {preview ? (
89
- <img
113
+ <Image
90
114
  src={preview}
91
115
  alt={label}
92
- className="h-full w-full object-contain"
116
+ fill
117
+ sizes="100vw"
118
+ className="object-contain"
119
+ unoptimized
93
120
  />
94
121
  ) : (
95
122
  <div className="flex h-full flex-col items-center justify-center gap-2 text-center">
@@ -104,9 +131,25 @@ function MediaRow({
104
131
  )}
105
132
  </div>
106
133
 
107
- {specText ? (
108
- <p className="text-[11px] text-muted-foreground/70">{specText}</p>
109
- ) : null}
134
+ <div className="space-y-1">
135
+ {file ? (
136
+ <div className="flex items-center gap-2 text-[11px] text-muted-foreground/70">
137
+ <FileTypeIcon
138
+ filename={file.name}
139
+ mimeType={file.mimeType ?? undefined}
140
+ size={14}
141
+ />
142
+ <span className="truncate">
143
+ Atual: {fileSizeLabel ?? 'tamanho desconhecido'}
144
+ {fileTypeLabel ? ` · ${fileTypeLabel}` : ''}
145
+ </span>
146
+ </div>
147
+ ) : null}
148
+
149
+ {specText ? (
150
+ <p className="text-[11px] text-muted-foreground/70">{specText}</p>
151
+ ) : null}
152
+ </div>
110
153
 
111
154
  <div className="flex items-center justify-end gap-1">
112
155
  <TooltipProvider>
@@ -249,7 +249,7 @@ export default function CourseStructurePage({ params }: Props) {
249
249
  <div className="flex flex-col items-center justify-center h-full gap-3 p-4 text-center">
250
250
  <AlertCircle className="size-8 text-destructive" />
251
251
  <p className="text-sm text-muted-foreground">
252
- Não foi possível carregar a estrutura do curso.
252
+ {t('error.loadFailed')}
253
253
  </p>
254
254
  <Button
255
255
  variant="outline"
@@ -258,7 +258,7 @@ export default function CourseStructurePage({ params }: Props) {
258
258
  className="gap-2"
259
259
  >
260
260
  <RefreshCw className="size-3.5" />
261
- Tentar novamente
261
+ {t('error.tryAgain')}
262
262
  </Button>
263
263
  </div>
264
264
  ) : (
@@ -327,7 +327,7 @@ export default function CourseStructurePage({ params }: Props) {
327
327
  <div className="flex flex-col items-center justify-center h-full gap-3 p-4 text-center">
328
328
  <AlertCircle className="size-8 text-destructive" />
329
329
  <p className="text-sm text-muted-foreground">
330
- Não foi possível carregar a estrutura do curso.
330
+ {t('error.loadFailed')}
331
331
  </p>
332
332
  <Button
333
333
  variant="outline"
@@ -336,7 +336,7 @@ export default function CourseStructurePage({ params }: Props) {
336
336
  className="gap-2"
337
337
  >
338
338
  <RefreshCw className="size-3.5" />
339
- Tentar novamente
339
+ {t('error.tryAgain')}
340
340
  </Button>
341
341
  </div>
342
342
  ) : (
@@ -14,6 +14,7 @@ import {
14
14
  SelectValue,
15
15
  } from '@/components/ui/select';
16
16
  import { Separator } from '@/components/ui/separator';
17
+ import { Skeleton } from '@/components/ui/skeleton';
17
18
  import { cn } from '@/lib/utils';
18
19
  import { useApp, useQuery } from '@hed-hog/next-app-provider';
19
20
  import { useMutation, useQueryClient } from '@tanstack/react-query';
@@ -199,8 +200,24 @@ export function CourseOperationsTab({ courseId }: Props) {
199
200
 
200
201
  if (isLoadingConfig) {
201
202
  return (
202
- <div className="flex items-center justify-center py-10">
203
- <Loader2 className="size-5 animate-spin text-muted-foreground" />
203
+ <div className="flex flex-col gap-5 p-1">
204
+ <div className="flex flex-col gap-1.5">
205
+ <Skeleton className="h-3 w-28" />
206
+ <Skeleton className="h-9 w-full" />
207
+ </div>
208
+ <div className="flex flex-col gap-2">
209
+ <Skeleton className="h-3 w-24" />
210
+ {[1, 2, 3].map((i) => (
211
+ <div key={i} className="flex items-center gap-2">
212
+ <Skeleton className="size-4 rounded-full shrink-0" />
213
+ <Skeleton className="h-3 w-40" />
214
+ </div>
215
+ ))}
216
+ </div>
217
+ <div className="flex flex-col gap-1.5">
218
+ <Skeleton className="h-3 w-32" />
219
+ <Skeleton className="h-9 w-full" />
220
+ </div>
204
221
  </div>
205
222
  );
206
223
  }