@hed-hog/lms 0.0.361 → 0.0.365

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 (434) hide show
  1. package/dist/bitcode-wallet/bitcode-wallet.service.d.ts +66 -0
  2. package/dist/bitcode-wallet/bitcode-wallet.service.d.ts.map +1 -1
  3. package/dist/bitcode-wallet/bitcode-wallet.service.js +91 -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-export-scorm12-worker.service.d.ts +21 -0
  16. package/dist/course/course-export-scorm12-worker.service.d.ts.map +1 -0
  17. package/dist/course/course-export-scorm12-worker.service.js +109 -0
  18. package/dist/course/course-export-scorm12-worker.service.js.map +1 -0
  19. package/dist/course/course-export-scorm12.service.d.ts +42 -0
  20. package/dist/course/course-export-scorm12.service.d.ts.map +1 -0
  21. package/dist/course/course-export-scorm12.service.js +628 -0
  22. package/dist/course/course-export-scorm12.service.js.map +1 -0
  23. package/dist/course/course-export.service.d.ts +84 -0
  24. package/dist/course/course-export.service.d.ts.map +1 -0
  25. package/dist/course/course-export.service.js +237 -0
  26. package/dist/course/course-export.service.js.map +1 -0
  27. package/dist/course/course-lesson.controller.d.ts +4 -0
  28. package/dist/course/course-lesson.controller.d.ts.map +1 -1
  29. package/dist/course/course-lesson.controller.js +10 -0
  30. package/dist/course/course-lesson.controller.js.map +1 -1
  31. package/dist/course/course-structure.controller.d.ts +24 -9
  32. package/dist/course/course-structure.controller.d.ts.map +1 -1
  33. package/dist/course/course-structure.controller.js +30 -3
  34. package/dist/course/course-structure.controller.js.map +1 -1
  35. package/dist/course/course-structure.service.d.ts +25 -3
  36. package/dist/course/course-structure.service.d.ts.map +1 -1
  37. package/dist/course/course-structure.service.js +234 -24
  38. package/dist/course/course-structure.service.js.map +1 -1
  39. package/dist/course/course-video-conversion.service.d.ts +8 -0
  40. package/dist/course/course-video-conversion.service.d.ts.map +1 -1
  41. package/dist/course/course-video-conversion.service.js +87 -51
  42. package/dist/course/course-video-conversion.service.js.map +1 -1
  43. package/dist/course/course-video-hls.service.d.ts +57 -0
  44. package/dist/course/course-video-hls.service.d.ts.map +1 -0
  45. package/dist/course/course-video-hls.service.js +767 -0
  46. package/dist/course/course-video-hls.service.js.map +1 -0
  47. package/dist/course/course.controller.d.ts +115 -11
  48. package/dist/course/course.controller.d.ts.map +1 -1
  49. package/dist/course/course.controller.js +66 -28
  50. package/dist/course/course.controller.js.map +1 -1
  51. package/dist/course/course.mcp-tools.js +1 -1
  52. package/dist/course/course.mcp-tools.js.map +1 -1
  53. package/dist/course/course.module.d.ts.map +1 -1
  54. package/dist/course/course.module.js +13 -0
  55. package/dist/course/course.module.js.map +1 -1
  56. package/dist/course/course.service.d.ts +112 -11
  57. package/dist/course/course.service.d.ts.map +1 -1
  58. package/dist/course/course.service.js +682 -72
  59. package/dist/course/course.service.js.map +1 -1
  60. package/dist/course/dto/cleanup-course-storage.dto.d.ts +6 -0
  61. package/dist/course/dto/cleanup-course-storage.dto.d.ts.map +1 -0
  62. package/dist/course/dto/cleanup-course-storage.dto.js +34 -0
  63. package/dist/course/dto/cleanup-course-storage.dto.js.map +1 -0
  64. package/dist/course/dto/cleanup-upload-history.dto.d.ts +9 -0
  65. package/dist/course/dto/cleanup-upload-history.dto.d.ts.map +1 -0
  66. package/dist/course/dto/cleanup-upload-history.dto.js +36 -0
  67. package/dist/course/dto/cleanup-upload-history.dto.js.map +1 -0
  68. package/dist/course/dto/create-course-bulk-job.dto.d.ts +5 -0
  69. package/dist/course/dto/create-course-bulk-job.dto.d.ts.map +1 -0
  70. package/dist/course/dto/create-course-bulk-job.dto.js +26 -0
  71. package/dist/course/dto/create-course-bulk-job.dto.js.map +1 -0
  72. package/dist/course/dto/create-course-export.dto.d.ts +14 -0
  73. package/dist/course/dto/create-course-export.dto.d.ts.map +1 -0
  74. package/dist/course/dto/create-course-export.dto.js +71 -0
  75. package/dist/course/dto/create-course-export.dto.js.map +1 -0
  76. package/dist/course/dto/create-course-structure-lesson.dto.d.ts +2 -2
  77. package/dist/course/dto/create-course-structure-lesson.dto.d.ts.map +1 -1
  78. package/dist/course/dto/create-course-structure-lesson.dto.js +3 -2
  79. package/dist/course/dto/create-course-structure-lesson.dto.js.map +1 -1
  80. package/dist/course/lms-bulk-upload-automation.service.d.ts +54 -0
  81. package/dist/course/lms-bulk-upload-automation.service.d.ts.map +1 -0
  82. package/dist/course/lms-bulk-upload-automation.service.js +537 -0
  83. package/dist/course/lms-bulk-upload-automation.service.js.map +1 -0
  84. package/dist/course/lms-bulk-upload-infra.service.d.ts +32 -0
  85. package/dist/course/lms-bulk-upload-infra.service.d.ts.map +1 -0
  86. package/dist/course/lms-bulk-upload-infra.service.js +301 -0
  87. package/dist/course/lms-bulk-upload-infra.service.js.map +1 -0
  88. package/dist/course/lms-bulk-upload.constants.d.ts +4 -0
  89. package/dist/course/lms-bulk-upload.constants.d.ts.map +1 -0
  90. package/dist/course/lms-bulk-upload.constants.js +7 -0
  91. package/dist/course/lms-bulk-upload.constants.js.map +1 -0
  92. package/dist/course/lms-bulk-upload.controller.d.ts +144 -1
  93. package/dist/course/lms-bulk-upload.controller.d.ts.map +1 -1
  94. package/dist/course/lms-bulk-upload.controller.js +114 -4
  95. package/dist/course/lms-bulk-upload.controller.js.map +1 -1
  96. package/dist/course/lms-bulk-upload.service.d.ts +153 -3
  97. package/dist/course/lms-bulk-upload.service.d.ts.map +1 -1
  98. package/dist/course/lms-bulk-upload.service.js +659 -21
  99. package/dist/course/lms-bulk-upload.service.js.map +1 -1
  100. package/dist/course/lms-setting.controller.d.ts +6 -2
  101. package/dist/course/lms-setting.controller.d.ts.map +1 -1
  102. package/dist/course/lms-setting.controller.js +25 -8
  103. package/dist/course/lms-setting.controller.js.map +1 -1
  104. package/dist/course/scorm12-schemas.d.ts +4 -0
  105. package/dist/course/scorm12-schemas.d.ts.map +1 -0
  106. package/dist/course/scorm12-schemas.js +9 -0
  107. package/dist/course/scorm12-schemas.js.map +1 -0
  108. package/dist/enterprise/enterprise.controller.d.ts +20 -20
  109. package/dist/enterprise/enterprise.service.d.ts +20 -20
  110. package/dist/enterprise/training/training-admin.controller.d.ts +11 -11
  111. package/dist/enterprise/training/training-admin.service.d.ts +11 -11
  112. package/dist/enterprise/training/training-instructor.controller.d.ts +2 -2
  113. package/dist/enterprise/training/training-instructor.service.d.ts +2 -2
  114. package/dist/enterprise/training/training-student.controller.d.ts +1 -1
  115. package/dist/enterprise/training/training-student.service.d.ts +52 -1
  116. package/dist/enterprise/training/training-student.service.d.ts.map +1 -1
  117. package/dist/enterprise/training/training-student.service.js +217 -4
  118. package/dist/enterprise/training/training-student.service.js.map +1 -1
  119. package/dist/enterprise/training/training-viewer.controller.d.ts +2 -2
  120. package/dist/evaluation/evaluation.controller.d.ts +8 -8
  121. package/dist/evaluation/evaluation.service.d.ts +26 -8
  122. package/dist/evaluation/evaluation.service.d.ts.map +1 -1
  123. package/dist/evaluation/evaluation.service.js +125 -0
  124. package/dist/evaluation/evaluation.service.js.map +1 -1
  125. package/dist/exam/dto/create-standalone-question.dto.d.ts +12 -0
  126. package/dist/exam/dto/create-standalone-question.dto.d.ts.map +1 -0
  127. package/dist/exam/dto/create-standalone-question.dto.js +70 -0
  128. package/dist/exam/dto/create-standalone-question.dto.js.map +1 -0
  129. package/dist/exam/exam.module.d.ts.map +1 -1
  130. package/dist/exam/exam.module.js +2 -1
  131. package/dist/exam/exam.module.js.map +1 -1
  132. package/dist/exam/exam.service.d.ts +21 -0
  133. package/dist/exam/exam.service.d.ts.map +1 -1
  134. package/dist/exam/exam.service.js +80 -0
  135. package/dist/exam/exam.service.js.map +1 -1
  136. package/dist/exam/question.controller.d.ts +27 -0
  137. package/dist/exam/question.controller.d.ts.map +1 -0
  138. package/dist/exam/question.controller.js +53 -0
  139. package/dist/exam/question.controller.js.map +1 -0
  140. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.d.ts +6 -0
  141. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.d.ts.map +1 -0
  142. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.js +34 -0
  143. package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.js.map +1 -0
  144. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.d.ts +28 -0
  145. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.d.ts.map +1 -0
  146. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.js +123 -0
  147. package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.js.map +1 -0
  148. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.d.ts +4 -0
  149. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.d.ts.map +1 -0
  150. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.js +22 -0
  151. package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.js.map +1 -0
  152. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.d.ts +10 -0
  153. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.d.ts.map +1 -0
  154. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.js +52 -0
  155. package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.js.map +1 -0
  156. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.d.ts +15 -0
  157. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.d.ts.map +1 -0
  158. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.js +86 -0
  159. package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.js.map +1 -0
  160. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.d.ts +30 -0
  161. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.d.ts.map +1 -0
  162. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.js +440 -0
  163. package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.js.map +1 -0
  164. package/dist/lesson-xp-map/lesson-xp-map.controller.d.ts +87 -0
  165. package/dist/lesson-xp-map/lesson-xp-map.controller.d.ts.map +1 -0
  166. package/dist/lesson-xp-map/lesson-xp-map.controller.js +185 -0
  167. package/dist/lesson-xp-map/lesson-xp-map.controller.js.map +1 -0
  168. package/dist/lesson-xp-map/lesson-xp-map.module.d.ts +3 -0
  169. package/dist/lesson-xp-map/lesson-xp-map.module.d.ts.map +1 -0
  170. package/dist/lesson-xp-map/lesson-xp-map.module.js +34 -0
  171. package/dist/lesson-xp-map/lesson-xp-map.module.js.map +1 -0
  172. package/dist/lesson-xp-map/lesson-xp-map.service.d.ts +84 -0
  173. package/dist/lesson-xp-map/lesson-xp-map.service.d.ts.map +1 -0
  174. package/dist/lesson-xp-map/lesson-xp-map.service.js +353 -0
  175. package/dist/lesson-xp-map/lesson-xp-map.service.js.map +1 -0
  176. package/dist/lesson-xp-map/lesson-xp-segment.controller.d.ts +10 -0
  177. package/dist/lesson-xp-map/lesson-xp-segment.controller.d.ts.map +1 -0
  178. package/dist/lesson-xp-map/lesson-xp-segment.controller.js +63 -0
  179. package/dist/lesson-xp-map/lesson-xp-segment.controller.js.map +1 -0
  180. package/dist/lesson-xp-map/lesson-xp-segment.service.d.ts +27 -0
  181. package/dist/lesson-xp-map/lesson-xp-segment.service.d.ts.map +1 -0
  182. package/dist/lesson-xp-map/lesson-xp-segment.service.js +194 -0
  183. package/dist/lesson-xp-map/lesson-xp-segment.service.js.map +1 -0
  184. package/dist/libraries/lms/tsconfig.tsbuildinfo +1 -0
  185. package/dist/lms-commerce-access.subscriber.d.ts +11 -0
  186. package/dist/lms-commerce-access.subscriber.d.ts.map +1 -0
  187. package/dist/lms-commerce-access.subscriber.js +74 -0
  188. package/dist/lms-commerce-access.subscriber.js.map +1 -0
  189. package/dist/lms.module.d.ts.map +1 -1
  190. package/dist/lms.module.js +21 -5
  191. package/dist/lms.module.js.map +1 -1
  192. package/dist/platforma/dto/update-profile.dto.d.ts +17 -0
  193. package/dist/platforma/dto/update-profile.dto.d.ts.map +1 -0
  194. package/dist/platforma/dto/update-profile.dto.js +87 -0
  195. package/dist/platforma/dto/update-profile.dto.js.map +1 -0
  196. package/dist/platforma/platforma-video.service.d.ts +39 -0
  197. package/dist/platforma/platforma-video.service.d.ts.map +1 -0
  198. package/dist/platforma/platforma-video.service.js +301 -0
  199. package/dist/platforma/platforma-video.service.js.map +1 -0
  200. package/dist/platforma/platforma.controller.d.ts +182 -1
  201. package/dist/platforma/platforma.controller.d.ts.map +1 -1
  202. package/dist/platforma/platforma.controller.js +243 -2
  203. package/dist/platforma/platforma.controller.js.map +1 -1
  204. package/dist/platforma/platforma.service.d.ts +27 -0
  205. package/dist/platforma/platforma.service.d.ts.map +1 -0
  206. package/dist/platforma/platforma.service.js +274 -0
  207. package/dist/platforma/platforma.service.js.map +1 -0
  208. package/dist/student-xp/dto/grant-skill-card-xp.dto.d.ts +5 -0
  209. package/dist/student-xp/dto/grant-skill-card-xp.dto.d.ts.map +1 -0
  210. package/dist/student-xp/dto/grant-skill-card-xp.dto.js +26 -0
  211. package/dist/student-xp/dto/grant-skill-card-xp.dto.js.map +1 -0
  212. package/dist/student-xp/student-xp.controller.d.ts +56 -0
  213. package/dist/student-xp/student-xp.controller.d.ts.map +1 -0
  214. package/dist/student-xp/student-xp.controller.js +138 -0
  215. package/dist/student-xp/student-xp.controller.js.map +1 -0
  216. package/dist/student-xp/student-xp.module.d.ts +3 -0
  217. package/dist/student-xp/student-xp.module.d.ts.map +1 -0
  218. package/dist/student-xp/student-xp.module.js +25 -0
  219. package/dist/student-xp/student-xp.module.js.map +1 -0
  220. package/dist/student-xp/student-xp.service.d.ts +81 -0
  221. package/dist/student-xp/student-xp.service.d.ts.map +1 -0
  222. package/dist/student-xp/student-xp.service.js +247 -0
  223. package/dist/student-xp/student-xp.service.js.map +1 -0
  224. package/dist/xp-catalog/dto/create-xp-area.dto.d.ts +12 -0
  225. package/dist/xp-catalog/dto/create-xp-area.dto.d.ts.map +1 -0
  226. package/dist/xp-catalog/dto/create-xp-area.dto.js +63 -0
  227. package/dist/xp-catalog/dto/create-xp-area.dto.js.map +1 -0
  228. package/dist/xp-catalog/dto/create-xp-learning-type.dto.d.ts +11 -0
  229. package/dist/xp-catalog/dto/create-xp-learning-type.dto.d.ts.map +1 -0
  230. package/dist/xp-catalog/dto/create-xp-learning-type.dto.js +57 -0
  231. package/dist/xp-catalog/dto/create-xp-learning-type.dto.js.map +1 -0
  232. package/dist/xp-catalog/dto/create-xp-skill.dto.d.ts +11 -0
  233. package/dist/xp-catalog/dto/create-xp-skill.dto.d.ts.map +1 -0
  234. package/dist/xp-catalog/dto/create-xp-skill.dto.js +57 -0
  235. package/dist/xp-catalog/dto/create-xp-skill.dto.js.map +1 -0
  236. package/dist/xp-catalog/dto/update-xp-area.dto.d.ts +12 -0
  237. package/dist/xp-catalog/dto/update-xp-area.dto.d.ts.map +1 -0
  238. package/dist/xp-catalog/dto/update-xp-area.dto.js +66 -0
  239. package/dist/xp-catalog/dto/update-xp-area.dto.js.map +1 -0
  240. package/dist/xp-catalog/dto/update-xp-learning-type.dto.d.ts +11 -0
  241. package/dist/xp-catalog/dto/update-xp-learning-type.dto.d.ts.map +1 -0
  242. package/dist/xp-catalog/dto/update-xp-learning-type.dto.js +60 -0
  243. package/dist/xp-catalog/dto/update-xp-learning-type.dto.js.map +1 -0
  244. package/dist/xp-catalog/dto/update-xp-skill.dto.d.ts +11 -0
  245. package/dist/xp-catalog/dto/update-xp-skill.dto.d.ts.map +1 -0
  246. package/dist/xp-catalog/dto/update-xp-skill.dto.js +60 -0
  247. package/dist/xp-catalog/dto/update-xp-skill.dto.js.map +1 -0
  248. package/dist/xp-catalog/xp-area.controller.d.ts +25 -0
  249. package/dist/xp-catalog/xp-area.controller.d.ts.map +1 -0
  250. package/dist/xp-catalog/xp-area.controller.js +105 -0
  251. package/dist/xp-catalog/xp-area.controller.js.map +1 -0
  252. package/dist/xp-catalog/xp-area.service.d.ts +35 -0
  253. package/dist/xp-catalog/xp-area.service.d.ts.map +1 -0
  254. package/dist/xp-catalog/xp-area.service.js +168 -0
  255. package/dist/xp-catalog/xp-area.service.js.map +1 -0
  256. package/dist/xp-catalog/xp-catalog.module.d.ts +3 -0
  257. package/dist/xp-catalog/xp-catalog.module.d.ts.map +1 -0
  258. package/dist/xp-catalog/xp-catalog.module.js +29 -0
  259. package/dist/xp-catalog/xp-catalog.module.js.map +1 -0
  260. package/dist/xp-catalog/xp-learning-type.controller.d.ts +20 -0
  261. package/dist/xp-catalog/xp-learning-type.controller.d.ts.map +1 -0
  262. package/dist/xp-catalog/xp-learning-type.controller.js +96 -0
  263. package/dist/xp-catalog/xp-learning-type.controller.js.map +1 -0
  264. package/dist/xp-catalog/xp-learning-type.service.d.ts +30 -0
  265. package/dist/xp-catalog/xp-learning-type.service.d.ts.map +1 -0
  266. package/dist/xp-catalog/xp-learning-type.service.js +146 -0
  267. package/dist/xp-catalog/xp-learning-type.service.js.map +1 -0
  268. package/dist/xp-catalog/xp-skill.controller.d.ts +26 -0
  269. package/dist/xp-catalog/xp-skill.controller.d.ts.map +1 -0
  270. package/dist/xp-catalog/xp-skill.controller.js +113 -0
  271. package/dist/xp-catalog/xp-skill.controller.js.map +1 -0
  272. package/dist/xp-catalog/xp-skill.service.d.ts +37 -0
  273. package/dist/xp-catalog/xp-skill.service.d.ts.map +1 -0
  274. package/dist/xp-catalog/xp-skill.service.js +174 -0
  275. package/dist/xp-catalog/xp-skill.service.js.map +1 -0
  276. package/hedhog/data/evaluation_topic.yaml +17 -0
  277. package/hedhog/data/menu.yaml +91 -7
  278. package/hedhog/data/queue_definition.yaml +48 -0
  279. package/hedhog/data/route.yaml +511 -29
  280. package/hedhog/data/setting_group.yaml +20 -20
  281. package/hedhog/data/xp_area.yaml +164 -0
  282. package/hedhog/data/xp_learning_type.yaml +131 -0
  283. package/hedhog/data/xp_skill.yaml +1834 -0
  284. package/hedhog/frontend/app/achievements/page.tsx.ejs +108 -118
  285. package/hedhog/frontend/app/bitcodes/page.tsx.ejs +22 -34
  286. package/hedhog/frontend/app/bulk-upload-sessions/page.tsx.ejs +1749 -0
  287. package/hedhog/frontend/app/certificates/models/page.tsx.ejs +21 -45
  288. package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +40 -74
  289. package/hedhog/frontend/app/classes/page.tsx.ejs +56 -85
  290. package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +3 -2
  291. package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +48 -5
  292. package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +73 -8
  293. package/hedhog/frontend/app/courses/[id]/structure/_components/course-export-sheet.tsx.ejs +420 -0
  294. package/hedhog/frontend/app/courses/[id]/structure/_components/course-exports-tab.tsx.ejs +308 -0
  295. package/hedhog/frontend/app/courses/[id]/structure/_components/course-operations-tab.tsx.ejs +19 -2
  296. package/hedhog/frontend/app/courses/[id]/structure/_components/course-overview-tab.tsx.ejs +1172 -0
  297. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +16 -0
  298. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +2 -0
  299. package/hedhog/frontend/app/courses/[id]/structure/_components/course-xp-overview-tab.tsx.ejs +623 -0
  300. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson-xp-tab.tsx.ejs +1458 -0
  301. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +87 -46
  302. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-panel.tsx.ejs +8 -3
  303. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-session.tsx.ejs +31 -8
  304. package/hedhog/frontend/app/courses/[id]/structure/_components/drag-overlay.tsx.ejs +16 -9
  305. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +618 -480
  306. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +672 -737
  307. package/hedhog/frontend/app/courses/[id]/structure/_components/mock-data.ts.ejs +1 -2
  308. package/hedhog/frontend/app/courses/[id]/structure/_components/sortable-tree-row.tsx.ejs +3 -0
  309. package/hedhog/frontend/app/courses/[id]/structure/_components/store.ts.ejs +1 -0
  310. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +101 -85
  311. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +24 -10
  312. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row.tsx.ejs +3 -0
  313. package/hedhog/frontend/app/courses/[id]/structure/_components/types.ts.ejs +1 -1
  314. package/hedhog/frontend/app/courses/[id]/structure/_components/use-tree-display-settings.ts.ejs +7 -1
  315. package/hedhog/frontend/app/courses/[id]/structure/_components/xp-premium-pills.tsx.ejs +44 -0
  316. package/hedhog/frontend/app/courses/[id]/structure/_data/adapters/course-structure.adapter.ts.ejs +6 -10
  317. package/hedhog/frontend/app/courses/[id]/structure/_data/services/course-structure.service.ts.ejs +49 -0
  318. package/hedhog/frontend/app/courses/[id]/structure/_data/types/api-course.types.ts.ejs +4 -3
  319. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-content-overview.ts.ejs +53 -0
  320. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-exports.ts.ejs +106 -0
  321. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +80 -1
  322. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-xp-overview.ts.ejs +76 -0
  323. package/hedhog/frontend/app/courses/[id]/structure/_data/use-lesson-xp-map.ts.ejs +128 -0
  324. package/hedhog/frontend/app/courses/[id]/structure/_data/use-lms-settings-query.ts.ejs +0 -2
  325. package/hedhog/frontend/app/courses/[id]/structure/_data/use-transcription-segments.ts.ejs +30 -0
  326. package/hedhog/frontend/app/courses/[id]/structure/_utils/xp-color-config.ts.ejs +115 -0
  327. package/hedhog/frontend/app/courses/_components/CourseDeleteDialog.tsx.ejs +223 -0
  328. package/hedhog/frontend/app/courses/_components/CourseRowActions.tsx.ejs +89 -0
  329. package/hedhog/frontend/app/courses/page.tsx.ejs +445 -230
  330. package/hedhog/frontend/app/enterprise/page.tsx.ejs +39 -63
  331. package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +53 -77
  332. package/hedhog/frontend/app/exams/page.tsx.ejs +54 -90
  333. package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +23 -36
  334. package/hedhog/frontend/app/instructors/page.tsx.ejs +72 -81
  335. package/hedhog/frontend/app/paths/page.tsx.ejs +40 -68
  336. package/hedhog/frontend/app/training/page.tsx.ejs +40 -68
  337. package/hedhog/frontend/app/xp/areas/page.tsx.ejs +782 -0
  338. package/hedhog/frontend/app/xp/learning-types/page.tsx.ejs +690 -0
  339. package/hedhog/frontend/app/xp/skills/page.tsx.ejs +811 -0
  340. package/hedhog/frontend/messages/en.json +412 -31
  341. package/hedhog/frontend/messages/pt.json +412 -31
  342. package/hedhog/table/course_export.yaml +62 -0
  343. package/hedhog/table/lesson_xp_map.yaml +50 -0
  344. package/hedhog/table/lesson_xp_segment.yaml +40 -0
  345. package/hedhog/table/lesson_xp_segment_area.yaml +24 -0
  346. package/hedhog/table/lesson_xp_segment_learning_type.yaml +24 -0
  347. package/hedhog/table/lesson_xp_segment_skill.yaml +24 -0
  348. package/hedhog/table/lms_bulk_upload_item.yaml +44 -0
  349. package/hedhog/table/lms_bulk_upload_session.yaml +42 -0
  350. package/hedhog/table/student_area_xp.yaml +30 -0
  351. package/hedhog/table/student_learning_type_xp.yaml +30 -0
  352. package/hedhog/table/student_skill_xp.yaml +30 -0
  353. package/hedhog/table/student_xp_event.yaml +34 -0
  354. package/hedhog/table/xp_area.yaml +39 -0
  355. package/hedhog/table/xp_learning_type.yaml +34 -0
  356. package/hedhog/table/xp_skill.yaml +39 -0
  357. package/package.json +13 -8
  358. package/src/bitcode-wallet/bitcode-wallet.service.ts +152 -0
  359. package/src/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.ts +32 -0
  360. package/src/course/course-audio-transcription.service.ts +58 -21
  361. package/src/course/course-export-scorm12-worker.service.ts +124 -0
  362. package/src/course/course-export-scorm12.service.ts +668 -0
  363. package/src/course/course-export.service.ts +280 -0
  364. package/src/course/course-lesson.controller.ts +6 -1
  365. package/src/course/course-structure.controller.ts +23 -1
  366. package/src/course/course-structure.service.ts +273 -7
  367. package/src/course/course-video-conversion.service.ts +113 -75
  368. package/src/course/course-video-hls.service.ts +946 -0
  369. package/src/course/course.controller.ts +54 -21
  370. package/src/course/course.mcp-tools.ts +1 -1
  371. package/src/course/course.module.ts +13 -0
  372. package/src/course/course.service.ts +906 -76
  373. package/src/course/dto/cleanup-course-storage.dto.ts +23 -0
  374. package/src/course/dto/cleanup-upload-history.dto.ts +26 -0
  375. package/src/course/dto/create-course-bulk-job.dto.ts +10 -0
  376. package/src/course/dto/create-course-export.dto.ts +56 -0
  377. package/src/course/dto/create-course-structure-lesson.dto.ts +4 -3
  378. package/src/course/lms-bulk-upload-automation.service.ts +707 -0
  379. package/src/course/lms-bulk-upload-infra.service.ts +360 -0
  380. package/src/course/lms-bulk-upload.constants.ts +5 -0
  381. package/src/course/lms-bulk-upload.controller.ts +110 -4
  382. package/src/course/lms-bulk-upload.service.ts +1092 -204
  383. package/src/course/lms-setting.controller.ts +26 -8
  384. package/src/course/scorm12-schemas.ts +9 -0
  385. package/src/enterprise/training/training-student.service.ts +221 -2
  386. package/src/evaluation/evaluation.service.ts +123 -0
  387. package/src/exam/dto/create-standalone-question.dto.ts +66 -0
  388. package/src/exam/exam.module.ts +2 -1
  389. package/src/exam/exam.service.ts +86 -0
  390. package/src/exam/question.controller.ts +28 -0
  391. package/src/lesson-xp-map/dto/create-lesson-xp-map.dto.ts +17 -0
  392. package/src/lesson-xp-map/dto/create-lesson-xp-segment.dto.ts +102 -0
  393. package/src/lesson-xp-map/dto/review-lesson-xp-map.dto.ts +7 -0
  394. package/src/lesson-xp-map/dto/update-lesson-xp-map.dto.ts +36 -0
  395. package/src/lesson-xp-map/dto/update-lesson-xp-segment.dto.ts +78 -0
  396. package/src/lesson-xp-map/lesson-xp-ai-calculation.service.ts +570 -0
  397. package/src/lesson-xp-map/lesson-xp-map.controller.ts +116 -0
  398. package/src/lesson-xp-map/lesson-xp-map.module.ts +21 -0
  399. package/src/lesson-xp-map/lesson-xp-map.service.ts +442 -0
  400. package/src/lesson-xp-map/lesson-xp-segment.controller.ts +36 -0
  401. package/src/lesson-xp-map/lesson-xp-segment.service.ts +229 -0
  402. package/src/lms-commerce-access.subscriber.ts +88 -0
  403. package/src/lms.module.ts +21 -5
  404. package/src/platforma/dto/update-profile.dto.ts +59 -0
  405. package/src/platforma/platforma-video.service.ts +346 -0
  406. package/src/platforma/platforma.controller.ts +152 -3
  407. package/src/platforma/platforma.service.ts +268 -0
  408. package/src/student-xp/dto/grant-skill-card-xp.dto.ts +10 -0
  409. package/src/student-xp/student-xp.controller.ts +92 -0
  410. package/src/student-xp/student-xp.module.ts +12 -0
  411. package/src/student-xp/student-xp.service.ts +318 -0
  412. package/src/xp-catalog/dto/create-xp-area.dto.ts +40 -0
  413. package/src/xp-catalog/dto/create-xp-learning-type.dto.ts +35 -0
  414. package/src/xp-catalog/dto/create-xp-skill.dto.ts +35 -0
  415. package/src/xp-catalog/dto/update-xp-area.dto.ts +43 -0
  416. package/src/xp-catalog/dto/update-xp-learning-type.dto.ts +38 -0
  417. package/src/xp-catalog/dto/update-xp-skill.dto.ts +38 -0
  418. package/src/xp-catalog/xp-area.controller.ts +64 -0
  419. package/src/xp-catalog/xp-area.service.ts +196 -0
  420. package/src/xp-catalog/xp-catalog.module.ts +16 -0
  421. package/src/xp-catalog/xp-learning-type.controller.ts +59 -0
  422. package/src/xp-catalog/xp-learning-type.service.ts +170 -0
  423. package/src/xp-catalog/xp-skill.controller.ts +71 -0
  424. package/src/xp-catalog/xp-skill.service.ts +205 -0
  425. package/hedhog/data/video_resolution_profile.yaml +0 -7
  426. package/hedhog/frontend/app/video-resolution-profiles/page.tsx.ejs +0 -607
  427. package/hedhog/table/course_video_resolution_profile.yaml +0 -22
  428. package/hedhog/table/video_resolution_profile.yaml +0 -18
  429. package/src/video-resolution-profile/dto/create-video-resolution-profile.dto.ts +0 -16
  430. package/src/video-resolution-profile/dto/update-video-resolution-profile.dto.ts +0 -16
  431. package/src/video-resolution-profile/video-resolution-profile.controller.ts +0 -62
  432. package/src/video-resolution-profile/video-resolution-profile.mcp-tools.ts +0 -128
  433. package/src/video-resolution-profile/video-resolution-profile.module.ts +0 -13
  434. package/src/video-resolution-profile/video-resolution-profile.service.ts +0 -117
@@ -9,14 +9,16 @@ import {
9
9
  ResizablePanel,
10
10
  ResizablePanelGroup,
11
11
  } from '@/components/ui/resizable';
12
- import { Sheet, SheetHeader, SheetTitle } from '@/components/ui/sheet';
13
12
  import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
13
+ import { Sheet, SheetHeader, SheetTitle } from '@/components/ui/sheet';
14
14
  import { useIsMobile } from '@/hooks/use-mobile';
15
15
  import { useApp, useQuery } from '@hed-hog/next-app-provider';
16
16
  import { useIsMutating, useQueryClient } from '@tanstack/react-query';
17
17
  import { AlertCircle, Menu, RefreshCw } from 'lucide-react';
18
18
  import { useTranslations } from 'next-intl';
19
+ import { useRouter, useSearchParams } from 'next/navigation';
19
20
 
21
+ import { useLmsRealtimeRefresh } from '../../_lib/hooks/use-lms-realtime-refresh';
20
22
  import { ConfirmDialog } from './structure/_components/confirm-dialog';
21
23
  import { CourseTreePanel } from './structure/_components/course-tree-panel';
22
24
  import { CourseTreeSkeleton } from './structure/_components/course-tree-skeleton';
@@ -37,7 +39,6 @@ import {
37
39
  usePasteSessionsMutation,
38
40
  } from './structure/_data/use-course-structure-mutations';
39
41
  import { useCourseStructureQuery } from './structure/_data/use-course-structure-query';
40
- import { useLmsRealtimeRefresh } from '../../_lib/hooks/use-lms-realtime-refresh';
41
42
 
42
43
  interface Props {
43
44
  params: Promise<{ id: string }>;
@@ -60,6 +61,8 @@ export default function CourseStructurePage({ params }: Props) {
60
61
  const isMobile = useIsMobile();
61
62
  const { request } = useApp();
62
63
  const queryClient = useQueryClient();
64
+ const router = useRouter();
65
+ const searchParams = useSearchParams();
63
66
 
64
67
  const { data: courseSummary } = useQuery<ApiCourseSummary>({
65
68
  queryKey: ['lms-course-detail', id],
@@ -85,6 +88,10 @@ export default function CourseStructurePage({ params }: Props) {
85
88
 
86
89
  const setStructureFromApi = useStructureStore((s) => s.setStructureFromApi);
87
90
  const setCourseId = useStructureStore((s) => s.setCourseId);
91
+ const selectItem = useStructureStore((s) => s.selectItem);
92
+
93
+ const restoredFromUrl = useRef(false);
94
+ const suppressNextSyncRef = useRef(false);
88
95
 
89
96
  useEffect(() => {
90
97
  setCourseId(id);
@@ -126,6 +133,31 @@ export default function CourseStructurePage({ params }: Props) {
126
133
  sessions: apiSessions,
127
134
  lessons: apiLessons,
128
135
  });
136
+
137
+ if (!restoredFromUrl.current) {
138
+ restoredFromUrl.current = true;
139
+ const sel = searchParams.get('sel');
140
+ const type = searchParams.get('type') as
141
+ | 'course'
142
+ | 'session'
143
+ | 'lesson'
144
+ | null;
145
+ if (
146
+ sel &&
147
+ (type === 'course' || type === 'session' || type === 'lesson')
148
+ ) {
149
+ const exists =
150
+ type === 'course'
151
+ ? mergedCourse?.id === sel
152
+ : type === 'session'
153
+ ? apiSessions.some((s) => s.id === sel)
154
+ : apiLessons.some((l) => l.id === sel);
155
+ if (exists) {
156
+ suppressNextSyncRef.current = true;
157
+ selectItem(sel, type);
158
+ }
159
+ }
160
+ }
129
161
  }
130
162
  }, [
131
163
  apiCourse,
@@ -159,6 +191,33 @@ export default function CourseStructurePage({ params }: Props) {
159
191
  const copiedType = useStructureStore((s) => s.copiedType);
160
192
  const copiedIds = useStructureStore((s) => s.copiedIds);
161
193
 
194
+ // ── URL sync: selection → URL ──────────────────────────────────────────────
195
+ useEffect(() => {
196
+ if (!restoredFromUrl.current) return;
197
+ if (suppressNextSyncRef.current) {
198
+ suppressNextSyncRef.current = false;
199
+ return;
200
+ }
201
+ const params = new URLSearchParams(searchParams.toString());
202
+ if (activeItemId && activeItemType) {
203
+ params.set('sel', activeItemId);
204
+ params.set('type', activeItemType);
205
+ }
206
+ params.delete('tab');
207
+ router.replace(`?${params.toString()}`, { scroll: false });
208
+ }, [activeItemId, activeItemType]); // eslint-disable-line react-hooks/exhaustive-deps
209
+
210
+ const handleTabChange = useCallback(
211
+ (tab: string) => {
212
+ const params = new URLSearchParams(searchParams.toString());
213
+ params.set('tab', tab);
214
+ router.replace(`?${params.toString()}`, { scroll: false });
215
+ },
216
+ [router, searchParams]
217
+ );
218
+
219
+ const defaultTab = searchParams.get('tab') ?? undefined;
220
+
162
221
  useCourseStructureShortcuts({
163
222
  searchRef,
164
223
  detailPanelRef,
@@ -249,7 +308,7 @@ export default function CourseStructurePage({ params }: Props) {
249
308
  <div className="flex flex-col items-center justify-center h-full gap-3 p-4 text-center">
250
309
  <AlertCircle className="size-8 text-destructive" />
251
310
  <p className="text-sm text-muted-foreground">
252
- Não foi possível carregar a estrutura do curso.
311
+ {t('error.loadFailed')}
253
312
  </p>
254
313
  <Button
255
314
  variant="outline"
@@ -258,7 +317,7 @@ export default function CourseStructurePage({ params }: Props) {
258
317
  className="gap-2"
259
318
  >
260
319
  <RefreshCw className="size-3.5" />
261
- Tentar novamente
320
+ {t('error.tryAgain')}
262
321
  </Button>
263
322
  </div>
264
323
  ) : (
@@ -277,7 +336,10 @@ export default function CourseStructurePage({ params }: Props) {
277
336
  className="flex flex-col h-full min-h-0"
278
337
  >
279
338
  <div className="h-full min-h-0">
280
- <DetailPanel />
339
+ <DetailPanel
340
+ defaultTab={defaultTab}
341
+ onTabChange={handleTabChange}
342
+ />
281
343
  </div>
282
344
  </div>
283
345
  </ResizablePanel>
@@ -305,7 +367,10 @@ export default function CourseStructurePage({ params }: Props) {
305
367
  className="flex-1 min-h-0 border rounded-lg overflow-hidden"
306
368
  >
307
369
  <div className="h-full min-h-0">
308
- <DetailPanel />
370
+ <DetailPanel
371
+ defaultTab={defaultTab}
372
+ onTabChange={handleTabChange}
373
+ />
309
374
  </div>
310
375
  </div>
311
376
 
@@ -327,7 +392,7 @@ export default function CourseStructurePage({ params }: Props) {
327
392
  <div className="flex flex-col items-center justify-center h-full gap-3 p-4 text-center">
328
393
  <AlertCircle className="size-8 text-destructive" />
329
394
  <p className="text-sm text-muted-foreground">
330
- Não foi possível carregar a estrutura do curso.
395
+ {t('error.loadFailed')}
331
396
  </p>
332
397
  <Button
333
398
  variant="outline"
@@ -336,7 +401,7 @@ export default function CourseStructurePage({ params }: Props) {
336
401
  className="gap-2"
337
402
  >
338
403
  <RefreshCw className="size-3.5" />
339
- Tentar novamente
404
+ {t('error.tryAgain')}
340
405
  </Button>
341
406
  </div>
342
407
  ) : (
@@ -0,0 +1,420 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+ import { toast } from 'sonner';
5
+ import {
6
+ AlignLeft,
7
+ AlignRight,
8
+ Download,
9
+ FileArchive,
10
+ Info,
11
+ Loader2,
12
+ Monitor,
13
+ Moon,
14
+ PieChart,
15
+ Sun,
16
+ Type,
17
+ } from 'lucide-react';
18
+ import { cn } from '@/lib/utils';
19
+ import { Alert, AlertDescription } from '@/components/ui/alert';
20
+ import { Badge } from '@/components/ui/badge';
21
+ import { Button } from '@/components/ui/button';
22
+ import { Label } from '@/components/ui/label';
23
+ import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
24
+ import {
25
+ Sheet,
26
+ SheetDescription,
27
+ SheetFooter,
28
+ SheetHeader,
29
+ SheetTitle,
30
+ } from '@/components/ui/sheet';
31
+ import {
32
+ ScormVisualSettings,
33
+ useCreateCourseExportMutation,
34
+ } from '../_data/use-course-exports';
35
+
36
+ // ── Color presets ────────────────────────────────────────────
37
+ const PRESET_COLORS = [
38
+ '#2563eb',
39
+ '#4338ca',
40
+ '#7c3aed',
41
+ '#e11d48',
42
+ '#ea580c',
43
+ '#059669',
44
+ '#0891b2',
45
+ '#475569',
46
+ ];
47
+
48
+ const DEFAULT_VISUAL: Required<ScormVisualSettings> = {
49
+ primaryColor: '#2563eb',
50
+ fontFamily: 'system',
51
+ fontSize: 'md',
52
+ sidebarWidth: 280,
53
+ sidebarPosition: 'left',
54
+ progressStyle: 'bar',
55
+ sidebarTheme: 'light',
56
+ };
57
+
58
+ // ── Segmented control ────────────────────────────────────────
59
+ type SegOption<T extends string> = {
60
+ label: string;
61
+ value: T;
62
+ icon?: React.ReactNode;
63
+ };
64
+
65
+ function Seg<T extends string>({
66
+ value,
67
+ onChange,
68
+ options,
69
+ }: {
70
+ value: T;
71
+ onChange: (v: T) => void;
72
+ options: SegOption<T>[];
73
+ }) {
74
+ return (
75
+ <div className="flex rounded-md border overflow-hidden bg-background">
76
+ {options.map((opt, i) => (
77
+ <button
78
+ key={opt.value}
79
+ type="button"
80
+ onClick={() => onChange(opt.value)}
81
+ className={cn(
82
+ 'flex items-center gap-1.5 flex-1 justify-center px-2.5 py-1.5 text-xs font-medium transition-colors',
83
+ i < options.length - 1 && 'border-r',
84
+ value === opt.value
85
+ ? 'bg-primary text-primary-foreground'
86
+ : 'text-muted-foreground hover:bg-muted/60',
87
+ )}
88
+ >
89
+ {opt.icon}
90
+ {opt.label}
91
+ </button>
92
+ ))}
93
+ </div>
94
+ );
95
+ }
96
+
97
+ // ── Props ─────────────────────────────────────────────────────
98
+ interface CourseExportSheetProps {
99
+ open: boolean;
100
+ onOpenChange: (open: boolean) => void;
101
+ courseId: string;
102
+ sessionCount: number;
103
+ videoLessonCount: number;
104
+ estimatedSizeMb?: number | null;
105
+ }
106
+
107
+ function formatMb(mb: number): string {
108
+ if (mb >= 1024) return `${(mb / 1024).toFixed(1)} GB`;
109
+ return `${mb.toFixed(0)} MB`;
110
+ }
111
+
112
+ // ── Component ─────────────────────────────────────────────────
113
+ export function CourseExportSheet({
114
+ open,
115
+ onOpenChange,
116
+ courseId,
117
+ sessionCount,
118
+ videoLessonCount,
119
+ estimatedSizeMb,
120
+ }: CourseExportSheetProps) {
121
+ const [visual, setVisual] = useState<Required<ScormVisualSettings>>(DEFAULT_VISUAL);
122
+ const createExport = useCreateCourseExportMutation(courseId);
123
+
124
+ const setV = <K extends keyof ScormVisualSettings>(
125
+ key: K,
126
+ value: Required<ScormVisualSettings>[K],
127
+ ) => setVisual((prev) => ({ ...prev, [key]: value }));
128
+
129
+ const handleConfirm = async () => {
130
+ try {
131
+ await createExport.mutateAsync({
132
+ format: 'scorm_1_2',
133
+ visualSettings: visual,
134
+ });
135
+ onOpenChange(false);
136
+ toast.success(
137
+ 'Exportação SCORM 1.2 iniciada. Acompanhe o progresso nas notificações.',
138
+ );
139
+ } catch {
140
+ toast.error('Erro ao iniciar exportação. Tente novamente.');
141
+ }
142
+ };
143
+
144
+ return (
145
+ <Sheet open={open} onOpenChange={onOpenChange}>
146
+ <ResizableSheetContent
147
+ sheetId="lms-course-export-scorm12-sheet"
148
+ defaultWidth={540}
149
+ minWidth={420}
150
+ maxWidth={780}
151
+ >
152
+ <SheetHeader>
153
+ <SheetTitle className="flex items-center gap-2">
154
+ <FileArchive className="size-4" />
155
+ Exportar para SCORM 1.2
156
+ </SheetTitle>
157
+ <SheetDescription>
158
+ Gera um pacote SCORM 1.2 com as aulas de vídeo do curso. O
159
+ processamento é feito em background.
160
+ </SheetDescription>
161
+ </SheetHeader>
162
+
163
+ <div className="flex flex-col gap-4 px-4 py-4">
164
+
165
+ {/* ── Stats ── */}
166
+ <div className="rounded-lg border bg-muted/30 p-3 flex flex-col gap-2">
167
+ <p className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
168
+ Conteúdo a exportar
169
+ </p>
170
+ <div className="flex flex-wrap gap-2">
171
+ <Badge variant="secondary">
172
+ {sessionCount} {sessionCount === 1 ? 'sessão' : 'sessões'}
173
+ </Badge>
174
+ <Badge variant="secondary">
175
+ {videoLessonCount}{' '}
176
+ {videoLessonCount === 1 ? 'aula de vídeo' : 'aulas de vídeo'}
177
+ </Badge>
178
+ {estimatedSizeMb != null && (
179
+ <Badge variant="outline">~{formatMb(estimatedSizeMb)}</Badge>
180
+ )}
181
+ </div>
182
+ {videoLessonCount === 0 && (
183
+ <p className="text-xs text-destructive mt-1">
184
+ Este curso não possui aulas de vídeo. Não é possível gerar o
185
+ pacote SCORM.
186
+ </p>
187
+ )}
188
+ </div>
189
+
190
+ {estimatedSizeMb != null && estimatedSizeMb > 500 && (
191
+ <Alert>
192
+ <Info className="size-4" />
193
+ <AlertDescription className="text-xs">
194
+ O pacote gerado pode ter aproximadamente{' '}
195
+ <strong>{formatMb(estimatedSizeMb)}</strong>. Certifique-se que
196
+ seu LMS suporta pacotes desse tamanho.
197
+ </AlertDescription>
198
+ </Alert>
199
+ )}
200
+
201
+ {/* ── Appearance ── */}
202
+ <div className="rounded-lg border overflow-hidden">
203
+ <div className="flex items-center gap-2 px-3 py-2.5 border-b bg-muted/20">
204
+ <Monitor className="size-4 text-muted-foreground" />
205
+ <span className="text-sm font-medium">Personalizar aparência</span>
206
+ </div>
207
+
208
+ <div className="px-3 pt-3 pb-4 flex flex-col gap-4">
209
+
210
+ {/* Primary color */}
211
+ <div className="flex flex-col gap-2">
212
+ <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">
213
+ Cor Principal
214
+ </Label>
215
+ <div className="flex flex-wrap items-center gap-2">
216
+ {PRESET_COLORS.map((c) => (
217
+ <button
218
+ key={c}
219
+ type="button"
220
+ onClick={() => setV('primaryColor', c)}
221
+ title={c}
222
+ className={cn(
223
+ 'w-7 h-7 rounded-full border-2 transition-all hover:scale-110 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring',
224
+ visual.primaryColor === c
225
+ ? 'border-foreground ring-2 ring-offset-1 ring-foreground/30 scale-110'
226
+ : 'border-transparent',
227
+ )}
228
+ style={{ background: c }}
229
+ />
230
+ ))}
231
+ {/* Custom color picker */}
232
+ <label className="cursor-pointer" title="Cor personalizada">
233
+ <input
234
+ type="color"
235
+ value={visual.primaryColor}
236
+ onChange={(e) => setV('primaryColor', e.target.value)}
237
+ className="sr-only"
238
+ />
239
+ <div
240
+ className={cn(
241
+ 'w-7 h-7 rounded-full border-2 border-dashed transition-all hover:scale-110',
242
+ !PRESET_COLORS.includes(visual.primaryColor)
243
+ ? 'border-foreground ring-2 ring-offset-1 ring-foreground/30 scale-110'
244
+ : 'border-muted-foreground/50',
245
+ )}
246
+ style={{ background: visual.primaryColor }}
247
+ />
248
+ </label>
249
+ </div>
250
+ <div className="flex items-center gap-1.5">
251
+ <div
252
+ className="w-3 h-3 rounded-sm border border-border/60 shrink-0"
253
+ style={{ background: visual.primaryColor }}
254
+ />
255
+ <span className="text-xs font-mono text-muted-foreground">
256
+ {visual.primaryColor.toUpperCase()}
257
+ </span>
258
+ </div>
259
+ </div>
260
+
261
+ {/* Font family */}
262
+ <div className="flex flex-col gap-2">
263
+ <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide flex items-center gap-1.5">
264
+ <Type className="size-3" />
265
+ Fonte
266
+ </Label>
267
+ <Seg
268
+ value={visual.fontFamily as 'system' | 'humanist' | 'serif' | 'mono'}
269
+ onChange={(v) => setV('fontFamily', v)}
270
+ options={[
271
+ { label: 'Sistema', value: 'system' as const },
272
+ { label: 'Humanista', value: 'humanist' as const },
273
+ { label: 'Serifada', value: 'serif' as const },
274
+ { label: 'Mono', value: 'mono' as const },
275
+ ]}
276
+ />
277
+ </div>
278
+
279
+ {/* Font size + Sidebar width */}
280
+ <div className="grid grid-cols-2 gap-3">
281
+ <div className="flex flex-col gap-2">
282
+ <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">
283
+ Tamanho da fonte
284
+ </Label>
285
+ <Seg
286
+ value={visual.fontSize as 'sm' | 'md' | 'lg'}
287
+ onChange={(v) => setV('fontSize', v)}
288
+ options={[
289
+ { label: 'Peq.', value: 'sm' as const },
290
+ { label: 'Méd.', value: 'md' as const },
291
+ { label: 'Grd.', value: 'lg' as const },
292
+ ]}
293
+ />
294
+ </div>
295
+ <div className="flex flex-col gap-2">
296
+ <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">
297
+ Largura do painel —{' '}
298
+ <span className="text-foreground font-normal normal-case">
299
+ {visual.sidebarWidth}px
300
+ </span>
301
+ </Label>
302
+ <div className="flex items-center gap-2 pt-1">
303
+ <span className="text-xs text-muted-foreground">200</span>
304
+ <input
305
+ type="range"
306
+ min={200}
307
+ max={420}
308
+ step={10}
309
+ value={visual.sidebarWidth}
310
+ onChange={(e) => setV('sidebarWidth', Number(e.target.value))}
311
+ className="flex-1 h-1.5 rounded-full cursor-pointer accent-primary"
312
+ />
313
+ <span className="text-xs text-muted-foreground">420</span>
314
+ </div>
315
+ </div>
316
+ </div>
317
+
318
+ {/* Sidebar position + Progress style */}
319
+ <div className="grid grid-cols-2 gap-3">
320
+ <div className="flex flex-col gap-2">
321
+ <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">
322
+ Posição do painel
323
+ </Label>
324
+ <Seg
325
+ value={visual.sidebarPosition as 'left' | 'right'}
326
+ onChange={(v) => setV('sidebarPosition', v)}
327
+ options={[
328
+ {
329
+ label: 'Esq.',
330
+ value: 'left' as const,
331
+ icon: <AlignLeft className="size-3" />,
332
+ },
333
+ {
334
+ label: 'Dir.',
335
+ value: 'right' as const,
336
+ icon: <AlignRight className="size-3" />,
337
+ },
338
+ ]}
339
+ />
340
+ </div>
341
+ <div className="flex flex-col gap-2">
342
+ <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">
343
+ Indicador de progresso
344
+ </Label>
345
+ <Seg
346
+ value={visual.progressStyle as 'bar' | 'pie'}
347
+ onChange={(v) => setV('progressStyle', v)}
348
+ options={[
349
+ { label: 'Barra', value: 'bar' as const },
350
+ {
351
+ label: 'Pizza',
352
+ value: 'pie' as const,
353
+ icon: <PieChart className="size-3" />,
354
+ },
355
+ ]}
356
+ />
357
+ </div>
358
+ </div>
359
+
360
+ {/* Sidebar theme */}
361
+ <div className="flex flex-col gap-2">
362
+ <Label className="text-xs font-semibold text-muted-foreground uppercase tracking-wide">
363
+ Tema do painel
364
+ </Label>
365
+ <Seg
366
+ value={visual.sidebarTheme as 'light' | 'dark'}
367
+ onChange={(v) => setV('sidebarTheme', v)}
368
+ options={[
369
+ {
370
+ label: 'Claro',
371
+ value: 'light' as const,
372
+ icon: <Sun className="size-3" />,
373
+ },
374
+ {
375
+ label: 'Escuro',
376
+ value: 'dark' as const,
377
+ icon: <Moon className="size-3" />,
378
+ },
379
+ ]}
380
+ />
381
+ </div>
382
+ </div>
383
+ </div>
384
+
385
+ {/* ── Info ── */}
386
+ <div className="rounded-lg border bg-muted/20 p-3">
387
+ <p className="text-xs text-muted-foreground">
388
+ <strong>Padrão SCORM 1.2</strong> — Compatível com a maioria dos
389
+ sistemas de gestão de aprendizagem (LMS). Os arquivos de vídeo são
390
+ incluídos no pacote e o progresso de cada aula é rastreado
391
+ automaticamente.
392
+ </p>
393
+ </div>
394
+ </div>
395
+
396
+ <SheetFooter>
397
+ <Button
398
+ variant="outline"
399
+ onClick={() => onOpenChange(false)}
400
+ disabled={createExport.isPending}
401
+ >
402
+ Cancelar
403
+ </Button>
404
+ <Button
405
+ onClick={handleConfirm}
406
+ disabled={createExport.isPending || videoLessonCount === 0}
407
+ className="gap-2"
408
+ >
409
+ {createExport.isPending ? (
410
+ <Loader2 className="size-4 animate-spin" />
411
+ ) : (
412
+ <Download className="size-4" />
413
+ )}
414
+ Exportar SCORM 1.2
415
+ </Button>
416
+ </SheetFooter>
417
+ </ResizableSheetContent>
418
+ </Sheet>
419
+ );
420
+ }