analytica-frontend-lib 1.6.76 → 1.6.78

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 (473) hide show
  1. package/dist/AccessReportModal/index.js +4 -5
  2. package/dist/AccessReportModal/index.js.map +1 -1
  3. package/dist/AccessReportModal/index.mjs +3 -4
  4. package/dist/AccessibilityWidget/index.js +4 -5
  5. package/dist/AccessibilityWidget/index.js.map +1 -1
  6. package/dist/AccessibilityWidget/index.mjs +3 -4
  7. package/dist/Accordation/index.js +4 -4
  8. package/dist/Accordation/index.mjs +3 -3
  9. package/dist/ActivitiesHistory/index.js +48 -49
  10. package/dist/ActivitiesHistory/index.js.map +1 -1
  11. package/dist/ActivitiesHistory/index.mjs +47 -48
  12. package/dist/ActivityCardQuestionBanks/index.d.ts.map +1 -1
  13. package/dist/ActivityCardQuestionBanks/index.js +48 -49
  14. package/dist/ActivityCardQuestionBanks/index.js.map +1 -1
  15. package/dist/ActivityCardQuestionBanks/index.mjs +47 -48
  16. package/dist/ActivityCardQuestionPreview/index.js +48 -49
  17. package/dist/ActivityCardQuestionPreview/index.js.map +1 -1
  18. package/dist/ActivityCardQuestionPreview/index.mjs +47 -48
  19. package/dist/ActivityCreate/ActivityCreateContent/index.js +48 -49
  20. package/dist/ActivityCreate/ActivityCreateContent/index.js.map +1 -1
  21. package/dist/ActivityCreate/ActivityCreateContent/index.mjs +47 -48
  22. package/dist/ActivityCreate/index.js +48 -49
  23. package/dist/ActivityCreate/index.js.map +1 -1
  24. package/dist/ActivityCreate/index.mjs +47 -48
  25. package/dist/ActivityDetails/index.js +48 -49
  26. package/dist/ActivityDetails/index.js.map +1 -1
  27. package/dist/ActivityDetails/index.mjs +47 -48
  28. package/dist/ActivityFilters/index.js +48 -49
  29. package/dist/ActivityFilters/index.js.map +1 -1
  30. package/dist/ActivityFilters/index.mjs +47 -48
  31. package/dist/ActivityPageLayout/index.js +48 -49
  32. package/dist/ActivityPageLayout/index.js.map +1 -1
  33. package/dist/ActivityPageLayout/index.mjs +47 -48
  34. package/dist/ActivityPreview/index.js +48 -49
  35. package/dist/ActivityPreview/index.js.map +1 -1
  36. package/dist/ActivityPreview/index.mjs +47 -48
  37. package/dist/AlertDialog/index.d.ts.map +1 -1
  38. package/dist/AlertDialog/index.js +3 -3
  39. package/dist/AlertDialog/index.mjs +2 -2
  40. package/dist/AlertManager/index.js +48 -49
  41. package/dist/AlertManager/index.js.map +1 -1
  42. package/dist/AlertManager/index.mjs +47 -48
  43. package/dist/AlertManagerView/index.js +4 -5
  44. package/dist/AlertManagerView/index.js.map +1 -1
  45. package/dist/AlertManagerView/index.mjs +3 -4
  46. package/dist/AnnouncementModal/index.js +4 -5
  47. package/dist/AnnouncementModal/index.js.map +1 -1
  48. package/dist/AnnouncementModal/index.mjs +3 -4
  49. package/dist/AnnouncementsGate/index.js +5 -6
  50. package/dist/AnnouncementsGate/index.js.map +1 -1
  51. package/dist/AnnouncementsGate/index.mjs +4 -5
  52. package/dist/AnswerKeyModal/index.js +4 -5
  53. package/dist/AnswerKeyModal/index.js.map +1 -1
  54. package/dist/AnswerKeyModal/index.mjs +3 -4
  55. package/dist/AppHeader/index.js +8 -9
  56. package/dist/AppHeader/index.js.map +1 -1
  57. package/dist/AppHeader/index.mjs +7 -8
  58. package/dist/CalendarCard/index.js +6 -7
  59. package/dist/CalendarCard/index.js.map +1 -1
  60. package/dist/CalendarCard/index.mjs +5 -6
  61. package/dist/Card/index.d.ts.map +1 -1
  62. package/dist/Card/index.js +3 -3
  63. package/dist/Card/index.mjs +2 -2
  64. package/dist/Chat/index.js +4 -5
  65. package/dist/Chat/index.js.map +1 -1
  66. package/dist/Chat/index.mjs +3 -4
  67. package/dist/Chatbot/index.js +4 -5
  68. package/dist/Chatbot/index.js.map +1 -1
  69. package/dist/Chatbot/index.mjs +3 -4
  70. package/dist/CheckBoxGroup/index.js +48 -49
  71. package/dist/CheckBoxGroup/index.js.map +1 -1
  72. package/dist/CheckBoxGroup/index.mjs +47 -48
  73. package/dist/ComparatorChart/ComparatorView/index.js +4 -5
  74. package/dist/ComparatorChart/ComparatorView/index.js.map +1 -1
  75. package/dist/ComparatorChart/ComparatorView/index.mjs +3 -4
  76. package/dist/CorrectActivityModal/index.js +9 -10
  77. package/dist/CorrectActivityModal/index.js.map +1 -1
  78. package/dist/CorrectActivityModal/index.mjs +8 -9
  79. package/dist/DownloadButton/index.js +6 -7
  80. package/dist/DownloadButton/index.js.map +1 -1
  81. package/dist/DownloadButton/index.mjs +5 -6
  82. package/dist/DownloadModal/index.js +4 -5
  83. package/dist/DownloadModal/index.js.map +1 -1
  84. package/dist/DownloadModal/index.mjs +3 -4
  85. package/dist/DropdownMenu/index.js +4 -5
  86. package/dist/DropdownMenu/index.js.map +1 -1
  87. package/dist/DropdownMenu/index.mjs +3 -4
  88. package/dist/EnemClassroomStartModal/index.js +8 -9
  89. package/dist/EnemClassroomStartModal/index.js.map +1 -1
  90. package/dist/EnemClassroomStartModal/index.mjs +7 -8
  91. package/dist/EnemMoment/index.js +110 -94
  92. package/dist/EnemMoment/index.js.map +1 -1
  93. package/dist/EnemMoment/index.mjs +74 -58
  94. package/dist/EnemMoment/index.mjs.map +1 -1
  95. package/dist/EnemMomentStudentModal/index.js +62 -63
  96. package/dist/EnemMomentStudentModal/index.js.map +1 -1
  97. package/dist/EnemMomentStudentModal/index.mjs +48 -49
  98. package/dist/EnemMomentStudentModal/index.mjs.map +1 -1
  99. package/dist/EssayThemePicker/index.js +3 -3
  100. package/dist/EssayThemePicker/index.mjs +2 -2
  101. package/dist/ExamDetailsLayout/ExamDetailsPage/index.js +48 -49
  102. package/dist/ExamDetailsLayout/ExamDetailsPage/index.js.map +1 -1
  103. package/dist/ExamDetailsLayout/ExamDetailsPage/index.mjs +47 -48
  104. package/dist/ExamPageLayout/index.js +48 -49
  105. package/dist/ExamPageLayout/index.js.map +1 -1
  106. package/dist/ExamPageLayout/index.mjs +47 -48
  107. package/dist/Forum/index.js +6 -7
  108. package/dist/Forum/index.js.map +1 -1
  109. package/dist/Forum/index.mjs +5 -6
  110. package/dist/IconButton/index.js +2 -2
  111. package/dist/IconButton/index.mjs +1 -1
  112. package/dist/LessonCardPreview/index.js +48 -49
  113. package/dist/LessonCardPreview/index.js.map +1 -1
  114. package/dist/LessonCardPreview/index.mjs +47 -48
  115. package/dist/LessonMediaSections/index.js +48 -49
  116. package/dist/LessonMediaSections/index.js.map +1 -1
  117. package/dist/LessonMediaSections/index.mjs +47 -48
  118. package/dist/LessonsCatalog/index.js +48 -49
  119. package/dist/LessonsCatalog/index.js.map +1 -1
  120. package/dist/LessonsCatalog/index.mjs +47 -48
  121. package/dist/Modal/index.d.ts +11 -1
  122. package/dist/Modal/index.d.ts.map +1 -1
  123. package/dist/Modal/index.js +3 -4
  124. package/dist/Modal/index.js.map +1 -1
  125. package/dist/Modal/index.mjs +2 -3
  126. package/dist/MultiCheckSelect/index.js +5 -6
  127. package/dist/MultiCheckSelect/index.js.map +1 -1
  128. package/dist/MultiCheckSelect/index.mjs +4 -5
  129. package/dist/NotificationCard/index.js +6 -7
  130. package/dist/NotificationCard/index.js.map +1 -1
  131. package/dist/NotificationCard/index.mjs +5 -6
  132. package/dist/PerformanceReportModal/index.js +4 -5
  133. package/dist/PerformanceReportModal/index.js.map +1 -1
  134. package/dist/PerformanceReportModal/index.mjs +3 -4
  135. package/dist/PrintableUsersTable/index.js +48 -49
  136. package/dist/PrintableUsersTable/index.js.map +1 -1
  137. package/dist/PrintableUsersTable/index.mjs +47 -48
  138. package/dist/ProgressModal/index.js +4 -5
  139. package/dist/ProgressModal/index.js.map +1 -1
  140. package/dist/ProgressModal/index.mjs +3 -4
  141. package/dist/QuestionsPerformanceCard/index.js +49 -50
  142. package/dist/QuestionsPerformanceCard/index.js.map +1 -1
  143. package/dist/QuestionsPerformanceCard/index.mjs +48 -49
  144. package/dist/Quiz/QuizResult/index.js +4 -4
  145. package/dist/Quiz/QuizResult/index.mjs +3 -3
  146. package/dist/Quiz/index.d.ts.map +1 -1
  147. package/dist/Quiz/index.js +8 -9
  148. package/dist/Quiz/index.js.map +1 -1
  149. package/dist/Quiz/index.mjs +7 -8
  150. package/dist/QuizTimer/index.d.ts +12 -0
  151. package/dist/QuizTimer/index.d.ts.map +1 -1
  152. package/dist/QuizTimer/index.js +4 -2
  153. package/dist/QuizTimer/index.js.map +1 -1
  154. package/dist/QuizTimer/index.mjs +4 -2
  155. package/dist/RecommendedLessonCreate/index.js +48 -49
  156. package/dist/RecommendedLessonCreate/index.js.map +1 -1
  157. package/dist/RecommendedLessonCreate/index.mjs +47 -48
  158. package/dist/RecommendedLessonDetails/index.js +11 -12
  159. package/dist/RecommendedLessonDetails/index.js.map +1 -1
  160. package/dist/RecommendedLessonDetails/index.mjs +10 -11
  161. package/dist/RecommendedLessonsHistory/index.js +48 -49
  162. package/dist/RecommendedLessonsHistory/index.js.map +1 -1
  163. package/dist/RecommendedLessonsHistory/index.mjs +47 -48
  164. package/dist/ReportDetailModal/index.js +5 -6
  165. package/dist/ReportDetailModal/index.js.map +1 -1
  166. package/dist/ReportDetailModal/index.mjs +4 -5
  167. package/dist/RichEditor/index.js +6 -7
  168. package/dist/RichEditor/index.js.map +1 -1
  169. package/dist/RichEditor/index.mjs +5 -6
  170. package/dist/{RichEditorCore-62NIM7PC.js → RichEditorCore-6OT3VNJR.js} +15 -16
  171. package/dist/RichEditorCore-6OT3VNJR.js.map +1 -0
  172. package/dist/{RichEditorCore-CCO3SSSU.mjs → RichEditorCore-IF6JQHEO.mjs} +6 -7
  173. package/dist/{RichEditorCore-CCO3SSSU.mjs.map → RichEditorCore-IF6JQHEO.mjs.map} +1 -1
  174. package/dist/Search/index.js +5 -6
  175. package/dist/Search/index.js.map +1 -1
  176. package/dist/Search/index.mjs +4 -5
  177. package/dist/SendActivityModal/SendActivityModal.js +48 -49
  178. package/dist/SendActivityModal/SendActivityModal.js.map +1 -1
  179. package/dist/SendActivityModal/SendActivityModal.mjs +47 -48
  180. package/dist/SendActivityModal/index.js +48 -49
  181. package/dist/SendActivityModal/index.js.map +1 -1
  182. package/dist/SendActivityModal/index.mjs +47 -48
  183. package/dist/SendLessonModal/index.js +48 -49
  184. package/dist/SendLessonModal/index.js.map +1 -1
  185. package/dist/SendLessonModal/index.mjs +47 -48
  186. package/dist/SimulatedPerformance/SimulatedPerformanceView/index.js +48 -49
  187. package/dist/SimulatedPerformance/SimulatedPerformanceView/index.js.map +1 -1
  188. package/dist/SimulatedPerformance/SimulatedPerformanceView/index.mjs +47 -48
  189. package/dist/SimulatedPerformance/useSimulatedPerformance/index.js +6 -7
  190. package/dist/SimulatedPerformance/useSimulatedPerformance/index.js.map +1 -1
  191. package/dist/SimulatedPerformance/useSimulatedPerformance/index.mjs +5 -6
  192. package/dist/SimulatedStudentSimulationsModal/index.js +8 -9
  193. package/dist/SimulatedStudentSimulationsModal/index.js.map +1 -1
  194. package/dist/SimulatedStudentSimulationsModal/index.mjs +7 -8
  195. package/dist/SimulationSummaryCards/index.js +5 -5
  196. package/dist/SimulationSummaryCards/index.mjs +4 -4
  197. package/dist/SimulationsPage/index.js +48 -49
  198. package/dist/SimulationsPage/index.js.map +1 -1
  199. package/dist/SimulationsPage/index.mjs +47 -48
  200. package/dist/StudentLessonProgressModal/index.js +6 -7
  201. package/dist/StudentLessonProgressModal/index.js.map +1 -1
  202. package/dist/StudentLessonProgressModal/index.mjs +5 -6
  203. package/dist/StudentPerformanceDetailsModal/index.js +9 -10
  204. package/dist/StudentPerformanceDetailsModal/index.js.map +1 -1
  205. package/dist/StudentPerformanceDetailsModal/index.mjs +8 -9
  206. package/dist/Support/TicketModal/index.js +4 -5
  207. package/dist/Support/TicketModal/index.js.map +1 -1
  208. package/dist/Support/TicketModal/index.mjs +3 -4
  209. package/dist/Support/index.js +5 -6
  210. package/dist/Support/index.js.map +1 -1
  211. package/dist/Support/index.mjs +4 -5
  212. package/dist/TableProvider/index.js +48 -49
  213. package/dist/TableProvider/index.js.map +1 -1
  214. package/dist/TableProvider/index.mjs +47 -48
  215. package/dist/UnifiedDraftModelPage/index.js +48 -49
  216. package/dist/UnifiedDraftModelPage/index.js.map +1 -1
  217. package/dist/UnifiedDraftModelPage/index.mjs +47 -48
  218. package/dist/UnifiedHistoryPage/index.js +48 -49
  219. package/dist/UnifiedHistoryPage/index.js.map +1 -1
  220. package/dist/UnifiedHistoryPage/index.mjs +47 -48
  221. package/dist/VideoPlayer/index.js +7 -8
  222. package/dist/VideoPlayer/index.js.map +1 -1
  223. package/dist/VideoPlayer/index.mjs +6 -7
  224. package/dist/Whiteboard/index.js +4 -5
  225. package/dist/Whiteboard/index.js.map +1 -1
  226. package/dist/Whiteboard/index.mjs +3 -4
  227. package/dist/{chunk-EVBQNVQW.mjs → chunk-233FSBU7.mjs} +5 -5
  228. package/dist/{chunk-JU63EMZM.js → chunk-24DQFREC.js} +3 -3
  229. package/dist/{chunk-JU63EMZM.js.map → chunk-24DQFREC.js.map} +1 -1
  230. package/dist/{chunk-QFXSQKW3.mjs → chunk-254EBPMW.mjs} +22 -22
  231. package/dist/{chunk-QFXSQKW3.mjs.map → chunk-254EBPMW.mjs.map} +1 -1
  232. package/dist/{chunk-SFQVZ4KQ.js → chunk-2ETPIOCD.js} +3 -3
  233. package/dist/{chunk-SFQVZ4KQ.js.map → chunk-2ETPIOCD.js.map} +1 -1
  234. package/dist/{chunk-RCNIBRZY.js → chunk-2VTJ2PKF.js} +10 -10
  235. package/dist/{chunk-RCNIBRZY.js.map → chunk-2VTJ2PKF.js.map} +1 -1
  236. package/dist/{chunk-B35D5S4G.js → chunk-2ZMGNCMI.js} +6 -6
  237. package/dist/{chunk-B35D5S4G.js.map → chunk-2ZMGNCMI.js.map} +1 -1
  238. package/dist/{chunk-QEPKR6ZF.js → chunk-3KSRDIS2.js} +20 -20
  239. package/dist/{chunk-QEPKR6ZF.js.map → chunk-3KSRDIS2.js.map} +1 -1
  240. package/dist/{chunk-MUCV5ZWZ.mjs → chunk-3YF7H577.mjs} +15 -9
  241. package/dist/chunk-3YF7H577.mjs.map +1 -0
  242. package/dist/{chunk-MADPP2PW.mjs → chunk-3ZSI2KI5.mjs} +2 -2
  243. package/dist/{chunk-2W7PTFXS.mjs → chunk-42XKJV56.mjs} +2 -2
  244. package/dist/{chunk-M6TC6XRQ.mjs → chunk-55ESXRRM.mjs} +2 -2
  245. package/dist/{chunk-4MURAKPC.mjs → chunk-5DJVOLVX.mjs} +3 -3
  246. package/dist/{chunk-YVT7CT3G.mjs → chunk-5P6CBDZ6.mjs} +2 -2
  247. package/dist/{chunk-BHKTJCFD.js → chunk-5QUP5HKB.js} +3 -3
  248. package/dist/{chunk-BHKTJCFD.js.map → chunk-5QUP5HKB.js.map} +1 -1
  249. package/dist/{chunk-SFEU7BMY.mjs → chunk-5SFNRXZB.mjs} +2 -2
  250. package/dist/{chunk-6ALEXGAN.js → chunk-6U4AI5SE.js} +6 -6
  251. package/dist/{chunk-6ALEXGAN.js.map → chunk-6U4AI5SE.js.map} +1 -1
  252. package/dist/{chunk-KYY4U5SN.mjs → chunk-6Z5W5J44.mjs} +3 -3
  253. package/dist/{chunk-XOKBMLW3.js → chunk-7IGUYLSF.js} +3 -3
  254. package/dist/{chunk-XOKBMLW3.js.map → chunk-7IGUYLSF.js.map} +1 -1
  255. package/dist/{chunk-GVYGPJH3.mjs → chunk-AU5M2766.mjs} +2 -2
  256. package/dist/{chunk-2VODGC76.js → chunk-AVEMHDN2.js} +66 -44
  257. package/dist/chunk-AVEMHDN2.js.map +1 -0
  258. package/dist/{chunk-HIIOADV4.js → chunk-AZSRKBYS.js} +63 -71
  259. package/dist/chunk-AZSRKBYS.js.map +1 -0
  260. package/dist/{chunk-CY2VKNCB.js → chunk-BQIBVC6X.js} +5 -5
  261. package/dist/{chunk-CY2VKNCB.js.map → chunk-BQIBVC6X.js.map} +1 -1
  262. package/dist/{chunk-M77TQ5JJ.mjs → chunk-BU32E6BR.mjs} +4 -6
  263. package/dist/{chunk-M77TQ5JJ.mjs.map → chunk-BU32E6BR.mjs.map} +1 -1
  264. package/dist/{chunk-5CQVDUDO.js → chunk-BUNF5POU.js} +5 -5
  265. package/dist/{chunk-5CQVDUDO.js.map → chunk-BUNF5POU.js.map} +1 -1
  266. package/dist/{chunk-Z6UN4ZPW.mjs → chunk-BVHVYC7Q.mjs} +4 -4
  267. package/dist/{chunk-WJENEFDG.js → chunk-CAFVLHDV.js} +3 -3
  268. package/dist/{chunk-WJENEFDG.js.map → chunk-CAFVLHDV.js.map} +1 -1
  269. package/dist/{chunk-BVUPM6EY.js → chunk-CAQ2Q3ON.js} +2 -2
  270. package/dist/chunk-CAQ2Q3ON.js.map +1 -0
  271. package/dist/{chunk-QMPOGLAR.js → chunk-CIASXVWX.js} +3 -3
  272. package/dist/{chunk-QMPOGLAR.js.map → chunk-CIASXVWX.js.map} +1 -1
  273. package/dist/{chunk-APKEYUJ3.js → chunk-CIQLC2ZZ.js} +3 -3
  274. package/dist/{chunk-APKEYUJ3.js.map → chunk-CIQLC2ZZ.js.map} +1 -1
  275. package/dist/{chunk-36XPNLGQ.js → chunk-CW3FCWR4.js} +16 -16
  276. package/dist/{chunk-36XPNLGQ.js.map → chunk-CW3FCWR4.js.map} +1 -1
  277. package/dist/{chunk-J5VEAJN5.mjs → chunk-CWVUGZNK.mjs} +2 -2
  278. package/dist/{chunk-BCMDP6GK.mjs → chunk-DV3N2K3Y.mjs} +4 -4
  279. package/dist/{chunk-PP7SEERV.mjs → chunk-DXYSEBK3.mjs} +9 -3
  280. package/dist/chunk-DXYSEBK3.mjs.map +1 -0
  281. package/dist/{chunk-754M6HQ5.js → chunk-EJN4OP3D.js} +5 -5
  282. package/dist/{chunk-754M6HQ5.js.map → chunk-EJN4OP3D.js.map} +1 -1
  283. package/dist/{chunk-3IM2SBPO.js → chunk-F5K3HMKT.js} +4 -4
  284. package/dist/{chunk-3IM2SBPO.js.map → chunk-F5K3HMKT.js.map} +1 -1
  285. package/dist/{chunk-WMDSGVZ7.mjs → chunk-GCGSAS2Z.mjs} +48 -63
  286. package/dist/chunk-GCGSAS2Z.mjs.map +1 -0
  287. package/dist/{chunk-EXHGEJ4P.mjs → chunk-GKARHTZ2.mjs} +2 -2
  288. package/dist/{chunk-2VDCEEXB.js → chunk-GNKFBVW4.js} +3 -3
  289. package/dist/{chunk-2VDCEEXB.js.map → chunk-GNKFBVW4.js.map} +1 -1
  290. package/dist/{chunk-CDLOMECB.js → chunk-GTBPMNTJ.js} +3 -3
  291. package/dist/{chunk-CDLOMECB.js.map → chunk-GTBPMNTJ.js.map} +1 -1
  292. package/dist/{chunk-YQKAASWM.js → chunk-GXXDSBN2.js} +10 -4
  293. package/dist/chunk-GXXDSBN2.js.map +1 -0
  294. package/dist/{chunk-FASVPU6N.js → chunk-H3F4OCXC.js} +10 -10
  295. package/dist/{chunk-FASVPU6N.js.map → chunk-H3F4OCXC.js.map} +1 -1
  296. package/dist/{chunk-JCFN6KRS.mjs → chunk-HGWDB73S.mjs} +2 -2
  297. package/dist/{chunk-JXXMO7PY.mjs → chunk-HN5RW4C3.mjs} +3 -3
  298. package/dist/{chunk-I2A4EQPH.mjs → chunk-HQ2GXFK5.mjs} +6 -6
  299. package/dist/{chunk-BIPC6F6D.js → chunk-IDJ37MOU.js} +115 -115
  300. package/dist/{chunk-BIPC6F6D.js.map → chunk-IDJ37MOU.js.map} +1 -1
  301. package/dist/{chunk-TBJLNIOY.mjs → chunk-JBLYYTHN.mjs} +2 -2
  302. package/dist/{chunk-G4NK66PM.js → chunk-JTWXQ267.js} +24 -18
  303. package/dist/chunk-JTWXQ267.js.map +1 -0
  304. package/dist/{chunk-V6IC74KH.js → chunk-JXGLDRDC.js} +34 -34
  305. package/dist/{chunk-V6IC74KH.js.map → chunk-JXGLDRDC.js.map} +1 -1
  306. package/dist/{chunk-DDFIRQI5.mjs → chunk-K3E5VEBF.mjs} +56 -34
  307. package/dist/chunk-K3E5VEBF.mjs.map +1 -0
  308. package/dist/{chunk-MSBEWG26.js → chunk-K5O2IOI4.js} +8 -8
  309. package/dist/{chunk-MSBEWG26.js.map → chunk-K5O2IOI4.js.map} +1 -1
  310. package/dist/{chunk-SB5YGKXR.js → chunk-KBMLGQ5J.js} +49 -64
  311. package/dist/chunk-KBMLGQ5J.js.map +1 -0
  312. package/dist/chunk-KCZEKV7M.mjs +81 -0
  313. package/dist/chunk-KCZEKV7M.mjs.map +1 -0
  314. package/dist/{chunk-GRSN76BV.mjs → chunk-KH2R4STU.mjs} +3 -3
  315. package/dist/{chunk-7DQM34JT.js → chunk-KHYSXYPO.js} +23 -23
  316. package/dist/{chunk-7DQM34JT.js.map → chunk-KHYSXYPO.js.map} +1 -1
  317. package/dist/{chunk-V2YHMPRR.js → chunk-KJHBQQYJ.js} +5 -5
  318. package/dist/{chunk-V2YHMPRR.js.map → chunk-KJHBQQYJ.js.map} +1 -1
  319. package/dist/{chunk-ZF5NMQJZ.mjs → chunk-KUKLN3CK.mjs} +4 -4
  320. package/dist/{chunk-6AYB7CZH.js → chunk-KZQVGSR2.js} +2 -2
  321. package/dist/{chunk-6AYB7CZH.js.map → chunk-KZQVGSR2.js.map} +1 -1
  322. package/dist/{chunk-UAKRBNW2.mjs → chunk-L4T76OKM.mjs} +2 -2
  323. package/dist/{chunk-AUCXJ7LG.js → chunk-M3LQH7Y7.js} +3 -3
  324. package/dist/{chunk-AUCXJ7LG.js.map → chunk-M3LQH7Y7.js.map} +1 -1
  325. package/dist/{chunk-FQNJJH7F.js → chunk-MCXRKD56.js} +13 -13
  326. package/dist/{chunk-FQNJJH7F.js.map → chunk-MCXRKD56.js.map} +1 -1
  327. package/dist/{chunk-PY5WCBKN.mjs → chunk-MERKXOSI.mjs} +4 -4
  328. package/dist/{chunk-D3YDZF2G.js → chunk-N472HQPZ.js} +3 -3
  329. package/dist/{chunk-D3YDZF2G.js.map → chunk-N472HQPZ.js.map} +1 -1
  330. package/dist/{chunk-UPMYCGXR.js → chunk-N4K4X34Z.js} +4 -4
  331. package/dist/{chunk-UPMYCGXR.js.map → chunk-N4K4X34Z.js.map} +1 -1
  332. package/dist/{chunk-RU43UMEH.js → chunk-NFCNAFUK.js} +3 -3
  333. package/dist/{chunk-RU43UMEH.js.map → chunk-NFCNAFUK.js.map} +1 -1
  334. package/dist/{chunk-APCB5HWT.mjs → chunk-NLSDZJRR.mjs} +3 -3
  335. package/dist/{chunk-EWYIXCNF.mjs → chunk-NLUTNCLH.mjs} +5 -5
  336. package/dist/{chunk-OP4Q2KDS.mjs → chunk-NMKKMY5P.mjs} +2 -2
  337. package/dist/{chunk-WDPFO4II.mjs → chunk-NMPK336K.mjs} +2 -2
  338. package/dist/{chunk-X6BZ5IEV.mjs → chunk-NU7O6YKR.mjs} +2 -2
  339. package/dist/{chunk-ZABDSRX3.js → chunk-NUZ5K3CB.js} +4 -4
  340. package/dist/{chunk-ZABDSRX3.js.map → chunk-NUZ5K3CB.js.map} +1 -1
  341. package/dist/{chunk-N5ZGFYLA.js → chunk-NZX3BA62.js} +3 -3
  342. package/dist/{chunk-N5ZGFYLA.js.map → chunk-NZX3BA62.js.map} +1 -1
  343. package/dist/{chunk-2TLSEAL2.js → chunk-O4TRDWXJ.js} +3 -3
  344. package/dist/{chunk-2TLSEAL2.js.map → chunk-O4TRDWXJ.js.map} +1 -1
  345. package/dist/{chunk-CBI5F4ME.mjs → chunk-OMSSA4NO.mjs} +2 -2
  346. package/dist/{chunk-YGEEWLGJ.js → chunk-PKKXCX5B.js} +3 -3
  347. package/dist/{chunk-YGEEWLGJ.js.map → chunk-PKKXCX5B.js.map} +1 -1
  348. package/dist/{chunk-GYHD6QEA.mjs → chunk-PQGQ3EH5.mjs} +2 -2
  349. package/dist/{chunk-3LN5GQAC.js → chunk-Q6UIUYNF.js} +6 -8
  350. package/dist/chunk-Q6UIUYNF.js.map +1 -0
  351. package/dist/chunk-QLWBGM7H.js +81 -0
  352. package/dist/chunk-QLWBGM7H.js.map +1 -0
  353. package/dist/{chunk-IF5GW6ID.js → chunk-QZ5DCDZ2.js} +6 -6
  354. package/dist/{chunk-IF5GW6ID.js.map → chunk-QZ5DCDZ2.js.map} +1 -1
  355. package/dist/{chunk-LSUCENYD.mjs → chunk-RBKGHUSR.mjs} +2 -2
  356. package/dist/{chunk-PIZTI5SJ.js → chunk-RMCZ7C2C.js} +3 -3
  357. package/dist/{chunk-PIZTI5SJ.js.map → chunk-RMCZ7C2C.js.map} +1 -1
  358. package/dist/{chunk-LGQNMQOT.mjs → chunk-ROS5XGTQ.mjs} +2 -2
  359. package/dist/chunk-ROS5XGTQ.mjs.map +1 -0
  360. package/dist/{chunk-TEUERRDG.mjs → chunk-RV45XVXE.mjs} +2 -2
  361. package/dist/{chunk-FW6ZI2MC.mjs → chunk-UAFSWXN5.mjs} +2 -2
  362. package/dist/{chunk-QUGKQYAJ.mjs → chunk-ULVFVLFE.mjs} +4 -6
  363. package/dist/{chunk-QUGKQYAJ.mjs.map → chunk-ULVFVLFE.mjs.map} +1 -1
  364. package/dist/{chunk-ANLL2EIX.mjs → chunk-UWCGTH3U.mjs} +2 -2
  365. package/dist/{chunk-6R2LEEEP.mjs → chunk-UZF2D2GG.mjs} +2 -2
  366. package/dist/{chunk-62L3PMYE.mjs → chunk-V3OVMHZD.mjs} +2 -2
  367. package/dist/{chunk-UDITT3N3.mjs → chunk-V6ELDZ2B.mjs} +2 -2
  368. package/dist/{chunk-G7NUCBD3.js → chunk-VDPV24JJ.js} +3 -3
  369. package/dist/{chunk-G7NUCBD3.js.map → chunk-VDPV24JJ.js.map} +1 -1
  370. package/dist/{chunk-IJQOTS5O.mjs → chunk-VJUS3GC4.mjs} +2 -2
  371. package/dist/{chunk-ZUPP7R2K.js → chunk-W7BBVDBI.js} +17 -3
  372. package/dist/chunk-W7BBVDBI.js.map +1 -0
  373. package/dist/{chunk-EHQDQ5RV.js → chunk-XARMPXRN.js} +10 -12
  374. package/dist/chunk-XARMPXRN.js.map +1 -0
  375. package/dist/{chunk-MQEAEU6G.mjs → chunk-XGMRYNER.mjs} +2 -2
  376. package/dist/{chunk-MMQMVVD6.mjs → chunk-XLTD5J74.mjs} +3 -3
  377. package/dist/{chunk-L3ST5GUJ.js → chunk-XQUK7R7L.js} +17 -17
  378. package/dist/{chunk-L3ST5GUJ.js.map → chunk-XQUK7R7L.js.map} +1 -1
  379. package/dist/{chunk-OMBUOOMD.mjs → chunk-XYT542WD.mjs} +2 -2
  380. package/dist/{chunk-IZNABVXE.js → chunk-Y4IGIWP4.js} +3 -3
  381. package/dist/{chunk-IZNABVXE.js.map → chunk-Y4IGIWP4.js.map} +1 -1
  382. package/dist/{chunk-COWOGT7U.mjs → chunk-YZWFDSTC.mjs} +2 -2
  383. package/dist/{chunk-M2FN7CNS.mjs → chunk-Z4L2DWMX.mjs} +17 -3
  384. package/dist/chunk-Z4L2DWMX.mjs.map +1 -0
  385. package/dist/chunk-Z75J66LL.mjs +149 -0
  386. package/dist/chunk-Z75J66LL.mjs.map +1 -0
  387. package/dist/{chunk-CWIJ7RXR.js → chunk-ZHUFICW3.js} +3 -3
  388. package/dist/{chunk-CWIJ7RXR.js.map → chunk-ZHUFICW3.js.map} +1 -1
  389. package/dist/{chunk-Q5XGBTOY.js → chunk-ZNITTMV5.js} +3 -3
  390. package/dist/{chunk-Q5XGBTOY.js.map → chunk-ZNITTMV5.js.map} +1 -1
  391. package/dist/components/EnemMoment/HeaderFilters.d.ts +12 -1
  392. package/dist/components/EnemMoment/HeaderFilters.d.ts.map +1 -1
  393. package/dist/components/EnemMoment/types.d.ts +10 -1
  394. package/dist/components/EnemMoment/types.d.ts.map +1 -1
  395. package/dist/hooks/useAppContent/index.js +48 -49
  396. package/dist/hooks/useAppContent/index.js.map +1 -1
  397. package/dist/hooks/useAppContent/index.mjs +47 -48
  398. package/dist/hooks/useResizableColumns.d.ts +20 -9
  399. package/dist/hooks/useResizableColumns.d.ts.map +1 -1
  400. package/dist/hooks/useScreen/index.js +2 -2
  401. package/dist/hooks/useScreen/index.mjs +1 -1
  402. package/dist/index.js +48 -49
  403. package/dist/index.js.map +1 -1
  404. package/dist/index.mjs +47 -48
  405. package/dist/store/layoutPreferencesStore.d.ts +12 -24
  406. package/dist/store/layoutPreferencesStore.d.ts.map +1 -1
  407. package/package.json +1 -1
  408. package/dist/RichEditorCore-62NIM7PC.js.map +0 -1
  409. package/dist/chunk-2EDRPEYL.mjs +0 -157
  410. package/dist/chunk-2EDRPEYL.mjs.map +0 -1
  411. package/dist/chunk-2VODGC76.js.map +0 -1
  412. package/dist/chunk-3LN5GQAC.js.map +0 -1
  413. package/dist/chunk-BVUPM6EY.js.map +0 -1
  414. package/dist/chunk-CH6BWMSQ.js +0 -17
  415. package/dist/chunk-CH6BWMSQ.js.map +0 -1
  416. package/dist/chunk-DDFIRQI5.mjs.map +0 -1
  417. package/dist/chunk-EHQDQ5RV.js.map +0 -1
  418. package/dist/chunk-G4NK66PM.js.map +0 -1
  419. package/dist/chunk-HIIOADV4.js.map +0 -1
  420. package/dist/chunk-JSH3BQZ7.mjs +0 -17
  421. package/dist/chunk-JSH3BQZ7.mjs.map +0 -1
  422. package/dist/chunk-LGQNMQOT.mjs.map +0 -1
  423. package/dist/chunk-LMDAF6LA.mjs +0 -51
  424. package/dist/chunk-LMDAF6LA.mjs.map +0 -1
  425. package/dist/chunk-M2FN7CNS.mjs.map +0 -1
  426. package/dist/chunk-MUCV5ZWZ.mjs.map +0 -1
  427. package/dist/chunk-PJOBOBNJ.js +0 -51
  428. package/dist/chunk-PJOBOBNJ.js.map +0 -1
  429. package/dist/chunk-PP7SEERV.mjs.map +0 -1
  430. package/dist/chunk-SB5YGKXR.js.map +0 -1
  431. package/dist/chunk-WMDSGVZ7.mjs.map +0 -1
  432. package/dist/chunk-YQKAASWM.js.map +0 -1
  433. package/dist/chunk-ZUPP7R2K.js.map +0 -1
  434. /package/dist/{chunk-EVBQNVQW.mjs.map → chunk-233FSBU7.mjs.map} +0 -0
  435. /package/dist/{chunk-MADPP2PW.mjs.map → chunk-3ZSI2KI5.mjs.map} +0 -0
  436. /package/dist/{chunk-2W7PTFXS.mjs.map → chunk-42XKJV56.mjs.map} +0 -0
  437. /package/dist/{chunk-M6TC6XRQ.mjs.map → chunk-55ESXRRM.mjs.map} +0 -0
  438. /package/dist/{chunk-4MURAKPC.mjs.map → chunk-5DJVOLVX.mjs.map} +0 -0
  439. /package/dist/{chunk-YVT7CT3G.mjs.map → chunk-5P6CBDZ6.mjs.map} +0 -0
  440. /package/dist/{chunk-SFEU7BMY.mjs.map → chunk-5SFNRXZB.mjs.map} +0 -0
  441. /package/dist/{chunk-KYY4U5SN.mjs.map → chunk-6Z5W5J44.mjs.map} +0 -0
  442. /package/dist/{chunk-GVYGPJH3.mjs.map → chunk-AU5M2766.mjs.map} +0 -0
  443. /package/dist/{chunk-Z6UN4ZPW.mjs.map → chunk-BVHVYC7Q.mjs.map} +0 -0
  444. /package/dist/{chunk-J5VEAJN5.mjs.map → chunk-CWVUGZNK.mjs.map} +0 -0
  445. /package/dist/{chunk-BCMDP6GK.mjs.map → chunk-DV3N2K3Y.mjs.map} +0 -0
  446. /package/dist/{chunk-EXHGEJ4P.mjs.map → chunk-GKARHTZ2.mjs.map} +0 -0
  447. /package/dist/{chunk-JCFN6KRS.mjs.map → chunk-HGWDB73S.mjs.map} +0 -0
  448. /package/dist/{chunk-JXXMO7PY.mjs.map → chunk-HN5RW4C3.mjs.map} +0 -0
  449. /package/dist/{chunk-I2A4EQPH.mjs.map → chunk-HQ2GXFK5.mjs.map} +0 -0
  450. /package/dist/{chunk-TBJLNIOY.mjs.map → chunk-JBLYYTHN.mjs.map} +0 -0
  451. /package/dist/{chunk-GRSN76BV.mjs.map → chunk-KH2R4STU.mjs.map} +0 -0
  452. /package/dist/{chunk-ZF5NMQJZ.mjs.map → chunk-KUKLN3CK.mjs.map} +0 -0
  453. /package/dist/{chunk-UAKRBNW2.mjs.map → chunk-L4T76OKM.mjs.map} +0 -0
  454. /package/dist/{chunk-PY5WCBKN.mjs.map → chunk-MERKXOSI.mjs.map} +0 -0
  455. /package/dist/{chunk-APCB5HWT.mjs.map → chunk-NLSDZJRR.mjs.map} +0 -0
  456. /package/dist/{chunk-EWYIXCNF.mjs.map → chunk-NLUTNCLH.mjs.map} +0 -0
  457. /package/dist/{chunk-OP4Q2KDS.mjs.map → chunk-NMKKMY5P.mjs.map} +0 -0
  458. /package/dist/{chunk-WDPFO4II.mjs.map → chunk-NMPK336K.mjs.map} +0 -0
  459. /package/dist/{chunk-X6BZ5IEV.mjs.map → chunk-NU7O6YKR.mjs.map} +0 -0
  460. /package/dist/{chunk-CBI5F4ME.mjs.map → chunk-OMSSA4NO.mjs.map} +0 -0
  461. /package/dist/{chunk-GYHD6QEA.mjs.map → chunk-PQGQ3EH5.mjs.map} +0 -0
  462. /package/dist/{chunk-LSUCENYD.mjs.map → chunk-RBKGHUSR.mjs.map} +0 -0
  463. /package/dist/{chunk-TEUERRDG.mjs.map → chunk-RV45XVXE.mjs.map} +0 -0
  464. /package/dist/{chunk-FW6ZI2MC.mjs.map → chunk-UAFSWXN5.mjs.map} +0 -0
  465. /package/dist/{chunk-ANLL2EIX.mjs.map → chunk-UWCGTH3U.mjs.map} +0 -0
  466. /package/dist/{chunk-6R2LEEEP.mjs.map → chunk-UZF2D2GG.mjs.map} +0 -0
  467. /package/dist/{chunk-62L3PMYE.mjs.map → chunk-V3OVMHZD.mjs.map} +0 -0
  468. /package/dist/{chunk-UDITT3N3.mjs.map → chunk-V6ELDZ2B.mjs.map} +0 -0
  469. /package/dist/{chunk-IJQOTS5O.mjs.map → chunk-VJUS3GC4.mjs.map} +0 -0
  470. /package/dist/{chunk-MQEAEU6G.mjs.map → chunk-XGMRYNER.mjs.map} +0 -0
  471. /package/dist/{chunk-MMQMVVD6.mjs.map → chunk-XLTD5J74.mjs.map} +0 -0
  472. /package/dist/{chunk-OMBUOOMD.mjs.map → chunk-XYT542WD.mjs.map} +0 -0
  473. /package/dist/{chunk-COWOGT7U.mjs.map → chunk-YZWFDSTC.mjs.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Card/Card.tsx"],"sourcesContent":["import {\n forwardRef,\n Fragment,\n HTMLAttributes,\n ReactNode,\n useState,\n useRef,\n MouseEvent,\n ChangeEvent,\n KeyboardEvent,\n Ref,\n useEffect,\n} from 'react';\nimport Button from '../Button/Button';\nimport IconButton from '../IconButton/IconButton';\nimport Badge from '../Badge/Badge';\nimport ProgressBar from '../ProgressBar/ProgressBar';\nimport { CaretRightIcon } from '@phosphor-icons/react/dist/csr/CaretRight';\nimport { ChatCircleTextIcon } from '@phosphor-icons/react/dist/csr/ChatCircleText';\nimport { CheckCircleIcon } from '@phosphor-icons/react/dist/csr/CheckCircle';\nimport { ClockIcon } from '@phosphor-icons/react/dist/csr/Clock';\nimport { DotsThreeVerticalIcon } from '@phosphor-icons/react/dist/csr/DotsThreeVertical';\nimport { PlayIcon } from '@phosphor-icons/react/dist/csr/Play';\nimport { SpeakerHighIcon } from '@phosphor-icons/react/dist/csr/SpeakerHigh';\nimport { SpeakerLowIcon } from '@phosphor-icons/react/dist/csr/SpeakerLow';\nimport { SpeakerSimpleXIcon } from '@phosphor-icons/react/dist/csr/SpeakerSimpleX';\nimport { TrashIcon } from '@phosphor-icons/react/dist/csr/Trash';\nimport { XCircleIcon } from '@phosphor-icons/react/dist/csr/XCircle';\nimport Text from '../Text/Text';\nimport { cn } from '../../utils/utils';\nimport { useMediaVolumePreference } from '../../store/mediaPreferencesStore';\nimport IconRender from '../IconRender/IconRender';\nimport readingFluencyBird from '../../assets/img/readingFluencyBird.png';\n\n// Componente base reutilizável para todos os cards\ninterface CardBaseProps extends HTMLAttributes<HTMLDivElement> {\n children: ReactNode;\n variant?: 'default' | 'compact' | 'minimal';\n layout?: 'horizontal' | 'vertical';\n padding?: 'none' | 'small' | 'medium' | 'large';\n minHeight?: 'none' | 'small' | 'medium' | 'large';\n cursor?: 'default' | 'pointer';\n}\n\nconst CARD_BASE_CLASSES = {\n default: 'w-full bg-background border border-border-50 rounded-xl',\n compact: 'w-full bg-background border border-border-50 rounded-lg',\n minimal: 'w-full bg-background border border-border-100 rounded-md',\n};\n\nconst CARD_PADDING_CLASSES = {\n none: '',\n small: 'p-2',\n medium: 'p-4',\n large: 'p-6',\n};\n\nconst CARD_MIN_HEIGHT_CLASSES = {\n none: '',\n small: 'min-h-16',\n medium: 'min-h-20',\n large: 'min-h-24',\n};\n\nconst CARD_LAYOUT_CLASSES = {\n horizontal: 'flex flex-row',\n vertical: 'flex flex-col',\n};\n\nconst CARD_CURSOR_CLASSES = {\n default: '',\n pointer: 'cursor-pointer',\n};\n\nconst CardBase = forwardRef<HTMLDivElement, CardBaseProps>(\n (\n {\n children,\n variant = 'default',\n layout = 'horizontal',\n padding = 'medium',\n minHeight = 'medium',\n cursor = 'default',\n className = '',\n onClick,\n onKeyDown,\n ...props\n },\n ref\n ) => {\n const baseClasses = CARD_BASE_CLASSES[variant];\n const paddingClasses = CARD_PADDING_CLASSES[padding];\n const minHeightClasses = CARD_MIN_HEIGHT_CLASSES[minHeight];\n const layoutClasses = CARD_LAYOUT_CLASSES[layout];\n const cursorClasses = CARD_CURSOR_CLASSES[cursor];\n\n // Make cards with onClick focusable and keyboard accessible\n const isInteractive = !!onClick;\n const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (isInteractive && ['Enter', ' '].includes(e.key)) {\n e.preventDefault();\n (e.currentTarget as HTMLElement).click();\n }\n onKeyDown?.(e);\n };\n\n /*\n * Note: Using div with role=\"button\" instead of native <button> element.\n * Rationale:\n * - Card is a complex container component with multiple child elements\n * - Native button has layout/styling constraints incompatible with card design\n * - Full WCAG/ARIA compliance implemented: role, tabIndex, keyboard support\n */\n return (\n <div\n ref={ref}\n className={cn(\n baseClasses,\n paddingClasses,\n minHeightClasses,\n layoutClasses,\n cursorClasses,\n className\n )}\n onClick={onClick}\n onKeyDown={handleKeyDown}\n tabIndex={isInteractive ? 0 : undefined}\n role={isInteractive ? 'button' : undefined}\n {...props}\n >\n {children}\n </div>\n );\n }\n);\n\ninterface CardActivitiesResultsProps extends HTMLAttributes<HTMLDivElement> {\n icon: ReactNode;\n title: string;\n subTitle: string;\n header: string;\n description?: string;\n extended?: boolean;\n action?: 'warning' | 'success' | 'error' | 'info';\n /** Extra classes of the value line, e.g. a larger size */\n subTitleClassName?: string;\n}\n\nconst ACTION_CARD_CLASSES = {\n warning: 'bg-warning-background',\n success: 'bg-success-200',\n error: 'bg-error-100',\n info: 'bg-info-background',\n};\n\nconst ACTION_ICON_CLASSES = {\n warning: 'bg-warning-300 text-text',\n success: 'bg-indicator-positive text-text-950',\n error: 'bg-indicator-negative text-text',\n info: 'bg-info-500 text-text',\n};\n\nconst ACTION_SUBTITLE_CLASSES = {\n warning: 'text-warning-600',\n success: 'text-success-700',\n error: 'text-error-700',\n info: 'text-info-700',\n};\n\nconst ACTION_HEADER_CLASSES = {\n warning: 'text-warning-300',\n success: 'text-success-300',\n error: 'text-error-300',\n info: 'text-info-300',\n};\n\nconst CardActivitiesResults = forwardRef<\n HTMLDivElement,\n CardActivitiesResultsProps\n>(\n (\n {\n icon,\n title,\n subTitle,\n header,\n extended = false,\n action = 'success',\n description,\n className,\n subTitleClassName,\n ...props\n },\n ref\n ) => {\n const actionCardClasses = ACTION_CARD_CLASSES[action];\n const actionIconClasses = ACTION_ICON_CLASSES[action];\n const actionSubTitleClasses = ACTION_SUBTITLE_CLASSES[action];\n const actionHeaderClasses = ACTION_HEADER_CLASSES[action];\n\n return (\n <div\n ref={ref}\n className={cn(\n // `min-w-0` lets the card shrink inside a grid/flex track, so the\n // truncated texts below get a width to truncate against instead of\n // stretching the card past its column.\n 'w-full min-w-0 flex flex-col rounded-xl',\n extended && 'border border-border-50 bg-background',\n className\n )}\n {...props}\n >\n <div\n className={cn(\n 'flex flex-col gap-1 items-center justify-center p-4',\n actionCardClasses,\n // Without a description below, the coloured block is the whole\n // card: let it fill the height a stretching grid/flex track gives\n // the wrapper, so siblings in the same row end up the same height.\n extended ? 'rounded-t-xl' : 'flex-1 rounded-xl'\n )}\n >\n <span\n className={cn(\n 'size-7.5 rounded-full flex items-center justify-center',\n actionIconClasses\n )}\n >\n {icon}\n </span>\n\n <Text\n size=\"2xs\"\n weight=\"medium\"\n className=\"max-w-full text-center text-text-800 uppercase truncate\"\n >\n {title}\n </Text>\n\n <p\n className={cn(\n 'max-w-full text-center text-lg font-bold truncate',\n actionSubTitleClasses,\n subTitleClassName\n )}\n >\n {subTitle}\n </p>\n </div>\n\n {extended && (\n <div className=\"flex flex-col items-center gap-2.5 pb-9.5 pt-2.5\">\n <p\n className={cn(\n 'text-2xs font-medium uppercase truncate',\n actionHeaderClasses\n )}\n >\n {header}\n </p>\n <Badge size=\"large\" action=\"info\">\n {description}\n </Badge>\n </div>\n )}\n </div>\n );\n }\n);\n\ninterface CardQuestionProps extends HTMLAttributes<HTMLDivElement> {\n header: string;\n state?: 'done' | 'undone' | 'pending';\n onClickButton?: (valueButton?: unknown) => void;\n valueButton?: unknown;\n /**\n * Disables the action button while still showing that the lesson has a\n * questionnaire. Used when the viewer may see the content but must not\n * answer it (e.g. a teacher previewing a lesson, where answering would\n * create a questionnaire attempt tied to their own user).\n */\n disabled?: boolean;\n}\n\nconst CardQuestions = forwardRef<HTMLDivElement, CardQuestionProps>(\n (\n {\n header,\n state = 'undone',\n className,\n onClickButton,\n valueButton,\n disabled = false,\n ...props\n },\n ref\n ) => {\n const getStateConfig = () => {\n switch (state) {\n case 'done':\n return {\n label: 'Realizado',\n buttonLabel: 'Ver Resultado',\n badgeAction: 'success' as const,\n };\n case 'pending':\n return {\n label: 'Aguardando correção',\n buttonLabel: 'Ver Resultado',\n badgeAction: 'info' as const,\n };\n default:\n return {\n label: 'Não Realizado',\n buttonLabel: 'Responder',\n badgeAction: 'error' as const,\n };\n }\n };\n\n const { label, buttonLabel, badgeAction } = getStateConfig();\n\n return (\n <CardBase\n ref={ref}\n layout=\"horizontal\"\n padding=\"medium\"\n minHeight=\"medium\"\n className={cn('justify-between gap-4', className)}\n {...props}\n >\n <section className=\"flex flex-col gap-1 flex-1 min-w-0\">\n <p className=\"font-bold text-xs text-text-950 truncate\">{header}</p>\n\n <div className=\"flex flex-row gap-6 items-center\">\n <Badge size=\"medium\" variant=\"solid\" action={badgeAction}>\n {label}\n </Badge>\n </div>\n </section>\n\n <span className=\"flex-shrink-0\">\n <Button\n size=\"extra-small\"\n onClick={() => onClickButton?.(valueButton)}\n disabled={disabled}\n className=\"min-w-fit\"\n >\n {buttonLabel}\n </Button>\n </span>\n </CardBase>\n );\n }\n);\n\ninterface CardProgressProps extends HTMLAttributes<HTMLDivElement> {\n header: string;\n subhead?: string;\n initialDate?: string;\n endDate?: string;\n progress?: number;\n direction?: 'horizontal' | 'vertical';\n icon: ReactNode;\n color?: string;\n progressVariant?: 'blue' | 'green';\n showDates?: boolean;\n /**\n * Renders the progress bar and its percentage. Set to `false` for audiences\n * that have no progress of their own (e.g. a teacher previewing a lesson\n * catalogue), where a bar stuck at 0% would read as \"nothing done\" rather\n * than \"not applicable\". Only affects `direction=\"horizontal\"`; the vertical\n * layout never had a bar.\n */\n showProgress?: boolean;\n}\n\nconst CardProgress = forwardRef<HTMLDivElement, CardProgressProps>(\n (\n {\n header,\n subhead,\n initialDate,\n endDate,\n progress = 0,\n direction = 'horizontal',\n icon,\n color = '#B7DFFF',\n progressVariant = 'blue',\n showDates = true,\n showProgress = true,\n className,\n ...props\n },\n ref\n ) => {\n const isHorizontal = direction === 'horizontal';\n const contentComponent = {\n horizontal: (\n <>\n {showDates && (\n <div className=\"flex flex-row gap-6 items-center\">\n {initialDate && (\n <span className=\"flex flex-row gap-1 items-center text-2xs\">\n <p className=\"text-text-800 font-semibold\">Início</p>\n <p className=\"text-text-600\">{initialDate}</p>\n </span>\n )}\n {endDate && (\n <span className=\"flex flex-row gap-1 items-center text-2xs\">\n <p className=\"text-text-800 font-semibold\">Fim</p>\n <p className=\"text-text-600\">{endDate}</p>\n </span>\n )}\n </div>\n )}\n {showProgress && (\n <span className=\"grid grid-cols-[1fr_auto] items-center gap-2\">\n <ProgressBar\n size=\"small\"\n value={progress}\n variant={progressVariant}\n data-testid=\"progress-bar\"\n />\n\n <Text\n size=\"xs\"\n weight=\"medium\"\n className={cn(\n 'text-text-950 leading-none tracking-normal text-center flex-none'\n )}\n >\n {Math.round(progress)}%\n </Text>\n </span>\n )}\n </>\n ),\n vertical: <p className=\"text-sm text-text-800\">{subhead}</p>,\n };\n\n return (\n <CardBase\n ref={ref}\n layout={isHorizontal ? 'horizontal' : 'vertical'}\n padding=\"none\"\n minHeight=\"medium\"\n cursor=\"pointer\"\n className={cn(isHorizontal ? 'h-20' : '', className)}\n {...props}\n >\n <div\n className={cn(\n 'flex justify-center items-center [&>svg]:size-6 text-text-950',\n isHorizontal\n ? 'min-w-[80px] min-h-[80px] rounded-l-xl'\n : 'min-h-[50px] w-full rounded-t-xl',\n !color.startsWith('#') ? `${color}` : ''\n )}\n style={color.startsWith('#') ? { backgroundColor: color } : undefined}\n data-testid=\"icon-container\"\n >\n {icon}\n </div>\n\n <div\n className={cn(\n 'p-4 flex flex-col justify-between w-full h-full',\n !isHorizontal && 'gap-4'\n )}\n >\n <Text size=\"sm\" weight=\"bold\" className=\"text-text-950 truncate\">\n {header}\n </Text>\n {contentComponent[direction]}\n </div>\n </CardBase>\n );\n }\n);\n\ninterface CardTopicProps extends HTMLAttributes<HTMLDivElement> {\n header: string;\n subHead?: string[];\n progress?: number;\n showPercentage?: boolean;\n progressVariant?: 'blue' | 'green';\n /**\n * Renders the progress bar. Set to `false` for audiences that have no\n * progress of their own (e.g. a teacher previewing a lesson catalogue),\n * where a bar stuck at 0% would read as \"nothing done\" rather than \"not\n * applicable\".\n */\n showProgress?: boolean;\n}\n\nconst CardTopic = forwardRef<HTMLDivElement, CardTopicProps>(\n (\n {\n header,\n subHead,\n progress = 0,\n showPercentage = false,\n progressVariant = 'blue',\n showProgress = true,\n className = '',\n ...props\n },\n ref\n ) => {\n return (\n <CardBase\n ref={ref}\n layout=\"vertical\"\n padding=\"small\"\n minHeight=\"medium\"\n cursor=\"pointer\"\n className={cn('justify-center gap-2 py-2 px-4', className)}\n {...props}\n >\n {subHead && (\n <span className=\"text-text-600 text-2xs flex flex-row gap-1\">\n {subHead.map((text, index) => (\n <Fragment key={`${text} - ${index}`}>\n <p>{text}</p>\n {index < subHead.length - 1 && <p>•</p>}\n </Fragment>\n ))}\n </span>\n )}\n\n <p className=\"text-sm text-text-950 font-bold truncate\">{header}</p>\n\n {showProgress && (\n <span className=\"grid grid-cols-[1fr_auto] items-center gap-2\">\n <ProgressBar\n size=\"small\"\n value={progress}\n variant={progressVariant}\n data-testid=\"progress-bar\"\n />\n {showPercentage && (\n <Text\n size=\"xs\"\n weight=\"medium\"\n className={cn(\n 'text-text-950 leading-none tracking-normal text-center flex-none'\n )}\n >\n {Math.round(progress)}%\n </Text>\n )}\n </span>\n )}\n </CardBase>\n );\n }\n);\n\ninterface CardPerformanceProps extends HTMLAttributes<HTMLDivElement> {\n header: string;\n description?: string;\n progress?: number;\n labelProgress?: string;\n actionVariant?: 'button' | 'caret';\n progressVariant?: 'blue' | 'green';\n onClickButton?: (valueButton?: unknown) => void;\n valueButton?: unknown;\n}\n\nconst CardPerformance = forwardRef<HTMLDivElement, CardPerformanceProps>(\n (\n {\n header,\n progress,\n description = 'Sem dados ainda! Você ainda não fez um questionário neste assunto.',\n actionVariant = 'button',\n progressVariant = 'blue',\n labelProgress = '',\n className = '',\n onClickButton,\n valueButton,\n ...props\n },\n ref\n ) => {\n const hasProgress = progress !== undefined;\n\n return (\n <CardBase\n ref={ref}\n layout=\"horizontal\"\n padding=\"medium\"\n minHeight=\"none\"\n className={cn(\n actionVariant == 'caret' ? 'cursor-pointer' : '',\n className\n )}\n onClick={() => actionVariant == 'caret' && onClickButton?.(valueButton)}\n {...props}\n >\n <div className=\"w-full flex flex-col justify-between gap-2\">\n <div className=\"flex flex-row justify-between items-center gap-2\">\n <p className=\"text-lg font-bold text-text-950 truncate flex-1 min-w-0\">\n {header}\n </p>\n {actionVariant === 'button' && (\n <Button\n variant=\"outline\"\n size=\"extra-small\"\n onClick={() => onClickButton?.(valueButton)}\n className=\"min-w-fit flex-shrink-0\"\n >\n Ver Aula\n </Button>\n )}\n </div>\n\n <div className=\"w-full\">\n {hasProgress ? (\n <ProgressBar\n value={progress}\n label={`${progress}% ${labelProgress}`}\n // O label visível já começa com o percentual, então o nome\n // padrão da barra (\"85% : 85%\") anunciava o número duas vezes.\n accessibleLabel={`${labelProgress.trim() || 'Progresso'}: ${progress}%`}\n variant={progressVariant}\n />\n ) : (\n <p className=\"text-xs text-text-600 truncate\">{description}</p>\n )}\n </div>\n </div>\n\n {actionVariant == 'caret' && (\n <CaretRightIcon\n className=\"size-4.5 text-text-800 cursor-pointer\"\n data-testid=\"caret-icon\"\n />\n )}\n </CardBase>\n );\n }\n);\n\ninterface CardResultsProps extends HTMLAttributes<HTMLDivElement> {\n header: string;\n icon: string;\n correct_answers: number;\n incorrect_answers: number;\n direction?: 'row' | 'col';\n color?: string;\n}\n\nconst CardResults = forwardRef<HTMLDivElement, CardResultsProps>(\n (\n {\n header,\n correct_answers,\n incorrect_answers,\n icon,\n direction = 'col',\n color = '#B7DFFF',\n className,\n ...props\n },\n ref\n ) => {\n const isRow = direction == 'row';\n\n return (\n <CardBase\n ref={ref}\n layout=\"horizontal\"\n padding=\"none\"\n minHeight=\"medium\"\n className={cn('items-stretch cursor-pointer pr-4', className)}\n {...props}\n >\n <div\n className={cn(\n 'flex justify-center items-center [&>svg]:size-8 text-text-950 min-w-20 max-w-20 min-h-full rounded-l-xl'\n )}\n style={{\n backgroundColor: color,\n }}\n >\n <IconRender iconName={icon} color=\"currentColor\" size={20} />\n </div>\n\n <div className=\"w-full flex flex-row justify-between items-center\">\n <div\n className={cn(\n 'p-4 flex flex-wrap justify-between w-full h-full',\n isRow ? 'flex-row items-center gap-2' : 'flex-col'\n )}\n >\n <p className=\"text-sm font-bold text-text-950 flex-1\">{header}</p>\n <span className=\"flex flex-wrap flex-row gap-1 items-center\">\n <Badge\n action=\"success\"\n variant=\"solid\"\n size=\"large\"\n iconLeft={<CheckCircleIcon />}\n >\n {correct_answers} Corretas\n </Badge>\n\n <Badge\n action=\"error\"\n variant=\"solid\"\n size=\"large\"\n iconLeft={<XCircleIcon />}\n >\n {incorrect_answers} Incorretas\n </Badge>\n </span>\n </div>\n\n <CaretRightIcon className=\"min-w-6 min-h-6 text-text-800\" />\n </div>\n </CardBase>\n );\n }\n);\n\ninterface CardStatusProps extends HTMLAttributes<HTMLDivElement> {\n header: string;\n status?: 'correct' | 'incorrect' | 'unanswered' | 'pending';\n label?: string;\n}\n\nconst CardStatus = forwardRef<HTMLDivElement, CardStatusProps>(\n ({ header, className, status, label, ...props }, ref) => {\n const getLabelBadge = (status: CardStatusProps['status']) => {\n switch (status) {\n case 'correct':\n return 'Correta';\n case 'incorrect':\n return 'Incorreta';\n case 'unanswered':\n return 'Em branco';\n case 'pending':\n return 'Avaliação pendente';\n default:\n return 'Em branco';\n }\n };\n\n const getIconBadge = (status: CardStatusProps['status']) => {\n switch (status) {\n case 'correct':\n return <CheckCircleIcon />;\n case 'incorrect':\n return <XCircleIcon />;\n case 'pending':\n return <ClockIcon />;\n default:\n return <XCircleIcon />;\n }\n };\n\n const getActionBadge = (status: CardStatusProps['status']) => {\n switch (status) {\n case 'correct':\n return 'success';\n case 'incorrect':\n return 'error';\n case 'pending':\n return 'info';\n default:\n return 'info';\n }\n };\n\n return (\n <CardBase\n ref={ref}\n layout=\"horizontal\"\n padding=\"medium\"\n minHeight=\"medium\"\n className={cn('items-center cursor-pointer', className)}\n {...props}\n >\n <div className=\"flex justify-between w-full h-full flex-row items-center gap-2\">\n <p className=\"text-sm font-bold text-text-950 truncate flex-1 min-w-0\">\n {header}\n </p>\n <span className=\"flex flex-row gap-1 items-center flex-shrink-0\">\n {status && (\n <Badge\n action={getActionBadge(status)}\n variant=\"solid\"\n size=\"medium\"\n iconLeft={getIconBadge(status)}\n >\n {getLabelBadge(status)}\n </Badge>\n )}\n {label && <p className=\"text-sm text-text-800\">{label}</p>}\n </span>\n <CaretRightIcon\n aria-hidden=\"true\"\n className=\"min-w-6 min-h-6 text-text-800 cursor-pointer flex-shrink-0 ml-2\"\n />\n </div>\n </CardBase>\n );\n }\n);\n\ninterface CardSettingsProps extends HTMLAttributes<HTMLDivElement> {\n icon: ReactNode;\n header: string;\n}\n\nconst CardSettings = forwardRef<HTMLDivElement, CardSettingsProps>(\n ({ header, className, icon, ...props }, ref) => {\n return (\n <CardBase\n ref={ref}\n layout=\"horizontal\"\n padding=\"small\"\n minHeight=\"none\"\n className={cn(\n 'border-none items-center gap-2 text-text-700',\n className\n )}\n {...props}\n >\n <span className=\"[&>svg]:size-6\">{icon}</span>\n\n <p className=\"w-full text-sm truncate\">{header}</p>\n\n <CaretRightIcon size={24} className=\"cursor-pointer\" />\n </CardBase>\n );\n }\n);\n\ninterface CardSupportProps extends HTMLAttributes<HTMLDivElement> {\n header: string;\n direction?: 'row' | 'col';\n children: ReactNode;\n}\n\nconst CardSupport = forwardRef<HTMLDivElement, CardSupportProps>(\n ({ header, className, direction = 'col', children, ...props }, ref) => {\n return (\n <CardBase\n ref={ref}\n layout=\"horizontal\"\n padding=\"medium\"\n minHeight=\"none\"\n className={cn(\n 'border-none items-center gap-2 text-text-700',\n className\n )}\n {...props}\n >\n <div\n className={cn(\n 'w-full flex',\n direction == 'col' ? 'flex-col' : 'flex-row items-center'\n )}\n >\n <span className=\"w-full min-w-0\">\n <p className=\"text-sm text-text-950 font-bold truncate\">{header}</p>\n </span>\n <span className=\"flex flex-row gap-1\">{children}</span>\n </div>\n\n <CaretRightIcon className=\"text-text-800 cursor-pointer\" size={24} />\n </CardBase>\n );\n }\n);\n\ninterface CardForumProps<T = unknown> extends HTMLAttributes<HTMLDivElement> {\n title: string;\n content: string;\n comments: number;\n date: string;\n hour: string;\n onClickComments?: (value?: T) => void;\n valueComments?: T;\n onClickProfile?: (profile?: T) => void;\n valueProfile?: T;\n}\n\nconst CardForum = forwardRef<HTMLDivElement, CardForumProps>(\n (\n {\n title,\n content,\n comments,\n onClickComments,\n valueComments,\n onClickProfile,\n valueProfile,\n className = '',\n date,\n hour,\n ...props\n },\n ref\n ) => {\n return (\n <CardBase\n ref={ref}\n layout=\"horizontal\"\n padding=\"medium\"\n minHeight=\"none\"\n variant=\"minimal\"\n className={cn('w-auto h-auto gap-3', className)}\n {...props}\n >\n <button\n type=\"button\"\n aria-label=\"Ver perfil\"\n onClick={() => onClickProfile?.(valueProfile)}\n className=\"min-w-8 h-8 rounded-full bg-background-950\"\n />\n\n <div className=\"flex flex-col gap-2 flex-1 min-w-0\">\n <div className=\"flex flex-row gap-1 items-center flex-wrap\">\n <p className=\"text-xs font-semibold text-primary-700 truncate\">\n {title}\n </p>\n <p className=\"text-xs text-text-600\">\n • {date} • {hour}\n </p>\n </div>\n\n <p className=\"text-text-950 text-sm line-clamp-2 truncate\">\n {content}\n </p>\n\n <button\n type=\"button\"\n aria-label=\"Ver comentários\"\n onClick={() => onClickComments?.(valueComments)}\n className=\"text-text-600 flex flex-row gap-2 items-center\"\n >\n <ChatCircleTextIcon aria-hidden=\"true\" size={16} />\n <p className=\"text-xs\">{comments} respostas</p>\n </button>\n </div>\n </CardBase>\n );\n }\n);\n\ninterface CardAudioProps extends HTMLAttributes<HTMLDivElement> {\n src?: string;\n title?: string;\n onPlay?: () => void;\n onPause?: () => void;\n onEnded?: () => void;\n onAudioTimeUpdate?: (currentTime: number, duration: number) => void;\n loop?: boolean;\n preload?: 'none' | 'metadata' | 'auto';\n tracks?: Array<{\n kind: 'subtitles' | 'captions' | 'descriptions' | 'chapters' | 'metadata';\n src: string;\n srcLang: string;\n label: string;\n default?: boolean;\n }>;\n}\n\n/** Salto do avanço/retrocesso da barra de progresso pelo teclado. */\nconst AUDIO_SEEK_STEP_SECONDS = 5;\n\nconst AUDIO_SPEED_OPTIONS = [\n { speed: 1, label: '1x' },\n { speed: 1.5, label: '1.5x' },\n { speed: 2, label: '2x' },\n];\n\nconst CardAudio = forwardRef<HTMLDivElement, CardAudioProps>(\n (\n {\n src,\n title,\n onPlay,\n onPause,\n onEnded,\n onAudioTimeUpdate,\n loop = false,\n preload = 'metadata',\n tracks,\n className,\n ...props\n },\n ref\n ) => {\n const [isPlaying, setIsPlaying] = useState(false);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n // Mesmo store da videoaula: o volume escolhido em qualquer player vale\n // para o próximo, em vez de o podcast recomeçar sempre em 100%.\n const { volume, isMuted, setVolume, setIsMuted } =\n useMediaVolumePreference();\n const [showVolumeControl, setShowVolumeControl] = useState(false);\n const [showSpeedMenu, setShowSpeedMenu] = useState(false);\n const [playbackRate, setPlaybackRate] = useState(1);\n const audioRef = useRef<HTMLAudioElement>(null);\n const volumeControlRef = useRef<HTMLDivElement>(null);\n const speedMenuRef = useRef<HTMLDivElement>(null);\n // Gatilhos e conteúdo dos dois popups: o foco precisa entrar ao abrir e\n // voltar ao gatilho ao fechar, senão o teclado fica preso fora deles.\n const volumeButtonRef = useRef<HTMLButtonElement>(null);\n const volumeSliderRef = useRef<HTMLInputElement>(null);\n const speedButtonRef = useRef<HTMLButtonElement>(null);\n const speedMenuListRef = useRef<HTMLDivElement>(null);\n\n const formatTime = (time: number) => {\n // Transmissão ao vivo reporta duração `Infinity`, e antes dos metadados,\n // `NaN` — sem esta guarda a tela mostrava \"Infinity:NaN\".\n if (!Number.isFinite(time) || time < 0) return '0:00';\n\n const minutes = Math.floor(time / 60);\n const seconds = Math.floor(time % 60);\n return `${minutes}:${seconds.toString().padStart(2, '0')}`;\n };\n\n const handlePlayPause = () => {\n if (isPlaying) {\n audioRef.current?.pause();\n setIsPlaying(false);\n onPause?.();\n } else {\n // play() returns a promise that rejects (AbortError) when interrupted\n // by a pause() before playback starts; swallow it to avoid crashing.\n audioRef.current?.play()?.catch(() => {});\n setIsPlaying(true);\n onPlay?.();\n }\n };\n\n const handleTimeUpdate = () => {\n const current = audioRef.current?.currentTime ?? 0;\n const total = audioRef.current?.duration ?? 0;\n\n setCurrentTime(current);\n setDuration(total);\n onAudioTimeUpdate?.(current, total);\n };\n\n const handleLoadedMetadata = () => {\n setDuration(audioRef.current?.duration ?? 0);\n };\n\n const handleEnded = () => {\n setIsPlaying(false);\n setCurrentTime(0);\n onEnded?.();\n };\n\n /**\n * `audio.duration` vem `Infinity` em transmissão ao vivo e `NaN` antes dos\n * metadados — e o `?? 0` dos handlers não pega nenhum dos dois, porque só\n * trata `null`/`undefined`. O que é exibido e anunciado passa por aqui; o\n * valor cru segue indo para `seekTo`, senão saturar a duração em zero\n * prenderia o avanço de mídia ao vivo no início.\n */\n const hasKnownDuration = Number.isFinite(duration) && duration > 0;\n\n /** Move a reprodução para `time`, preso à faixa [0, duração]. */\n const seekTo = (time: number) => {\n const clamped = Math.min(Math.max(time, 0), duration);\n\n if (audioRef.current && Number.isFinite(clamped)) {\n audioRef.current.currentTime = clamped;\n setCurrentTime(clamped);\n }\n };\n\n const handleProgressClick = (e: MouseEvent<HTMLButtonElement>) => {\n const rect = e.currentTarget.getBoundingClientRect();\n const clickX = e.clientX - rect.left;\n\n seekTo((clickX / rect.width) * duration);\n };\n\n /**\n * Avanço e retrocesso pelo teclado. Antes, Enter e Espaço sintetizavam um\n * clique — que chega com `clientX` 0 e rebobinava o áudio para o início.\n */\n const handleProgressKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {\n const timeByKey: Record<string, number> = {\n ArrowRight: currentTime + AUDIO_SEEK_STEP_SECONDS,\n ArrowUp: currentTime + AUDIO_SEEK_STEP_SECONDS,\n ArrowLeft: currentTime - AUDIO_SEEK_STEP_SECONDS,\n ArrowDown: currentTime - AUDIO_SEEK_STEP_SECONDS,\n Home: 0,\n End: duration,\n };\n\n if (e.key in timeByKey) {\n e.preventDefault();\n seekTo(timeByKey[e.key]);\n }\n };\n\n // O card tem um único controle de áudio, então o mudo herdado da videoaula\n // aparece aqui como volume zero — em vez de um slider em 70% sem som.\n const displayVolume = isMuted ? 0 : volume;\n\n /**\n * Salva o volume escolhido. Como o slider é o único controle de áudio do\n * card, zerá-lo é o gesto de mudo, e sair do zero desfaz o mudo herdado.\n */\n const applyVolume = (newVolume: number) => {\n setVolume(newVolume);\n setIsMuted(newVolume === 0);\n };\n\n const handleVolumeChange = (e: ChangeEvent<HTMLInputElement>) => {\n applyVolume(Number.parseFloat(e.target.value));\n };\n\n const toggleVolumeControl = () => {\n setShowVolumeControl(!showVolumeControl);\n setShowSpeedMenu(false);\n };\n\n const toggleSpeedMenu = () => {\n setShowSpeedMenu(!showSpeedMenu);\n setShowVolumeControl(false);\n };\n\n const closeVolumeControl = () => {\n setShowVolumeControl(false);\n volumeButtonRef.current?.focus();\n };\n\n const closeSpeedMenu = () => {\n setShowSpeedMenu(false);\n speedButtonRef.current?.focus();\n };\n\n const handleVolumeKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n const stepUp = Math.min(1, Math.round((displayVolume + 0.1) * 10) / 10);\n const stepDown = Math.max(0, Math.round((displayVolume - 0.1) * 10) / 10);\n const volumeByKey: Record<string, number> = {\n ArrowUp: stepUp,\n ArrowRight: stepUp,\n ArrowDown: stepDown,\n ArrowLeft: stepDown,\n };\n\n if (e.key in volumeByKey) {\n e.preventDefault();\n applyVolume(volumeByKey[e.key]);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n closeVolumeControl();\n }\n };\n\n /** Navegação do menu de velocidade, no mesmo padrão da videoaula. */\n const handleSpeedMenuKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n closeSpeedMenu();\n return;\n }\n\n const items = [\n ...(speedMenuListRef.current?.querySelectorAll<HTMLButtonElement>(\n '[role=\"menuitemradio\"]'\n ) ?? []),\n ];\n if (items.length === 0) return;\n\n const currentIndex = items.indexOf(\n document.activeElement as HTMLButtonElement\n );\n const nextIndexByKey: Record<string, number> = {\n ArrowDown: (currentIndex + 1) % items.length,\n ArrowUp: (currentIndex - 1 + items.length) % items.length,\n Home: 0,\n End: items.length - 1,\n };\n\n if (e.key in nextIndexByKey) {\n e.preventDefault();\n items[nextIndexByKey[e.key]]?.focus();\n }\n };\n\n const handleSpeedChange = (speed: number) => {\n setPlaybackRate(speed);\n if (audioRef.current) {\n audioRef.current.playbackRate = speed;\n }\n closeSpeedMenu();\n };\n\n // Abrir um popup sem levar o foco deixa o conteúdo dele fora do alcance de\n // quem abriu pelo teclado — o Escape, inclusive, não teria onde ser ouvido.\n useEffect(() => {\n if (showVolumeControl) volumeSliderRef.current?.focus();\n }, [showVolumeControl]);\n\n useEffect(() => {\n if (!showSpeedMenu) return;\n\n const list = speedMenuListRef.current;\n const checked = list?.querySelector<HTMLButtonElement>(\n '[aria-checked=\"true\"]'\n );\n (\n checked ??\n list?.querySelector<HTMLButtonElement>('[role=\"menuitemradio\"]')\n )?.focus();\n }, [showSpeedMenu]);\n\n const getVolumeIcon = () => {\n if (displayVolume === 0) {\n return <SpeakerSimpleXIcon size={24} />;\n }\n if (displayVolume < 0.5) {\n return <SpeakerLowIcon size={24} />;\n }\n return <SpeakerHighIcon size={24} />;\n };\n\n // Aplica a preferência ao elemento no mount, ao trocar de faixa e quando\n // outro player altera o volume. Sem isso o `<audio>` sempre nasceria em 100%.\n useEffect(() => {\n const audio = audioRef.current;\n if (!audio) return;\n\n audio.volume = volume;\n audio.muted = isMuted;\n }, [volume, isMuted, src]);\n\n useEffect(() => {\n const handleClickOutside = (event: Event) => {\n if (\n volumeControlRef.current &&\n !volumeControlRef.current.contains(event.target as Node)\n ) {\n setShowVolumeControl(false);\n }\n if (\n speedMenuRef.current &&\n !speedMenuRef.current.contains(event.target as Node)\n ) {\n setShowSpeedMenu(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, []);\n\n /**\n * Rótulo do play/pause. O título entra nele pro botão se descrever sozinho:\n * quem chega ali pela navegação do leitor de tela, sem ter passado pelo nome\n * do grupo, ouvia só \"Reproduzir\" sem saber o quê.\n */\n const playPauseAction = isPlaying ? 'Pausar' : 'Reproduzir';\n const playPauseLabel = title\n ? `${playPauseAction} ${title}`\n : playPauseAction;\n\n return (\n <CardBase\n ref={ref}\n layout=\"horizontal\"\n padding=\"medium\"\n minHeight=\"none\"\n className={cn(\n 'flex flex-row w-auto h-14 items-center gap-2',\n className\n )}\n {...props}\n >\n {/* Audio element */}\n <audio\n ref={audioRef}\n src={src}\n loop={loop}\n preload={preload}\n onTimeUpdate={handleTimeUpdate}\n onLoadedMetadata={handleLoadedMetadata}\n onEnded={handleEnded}\n data-testid=\"audio-element\"\n // Sem `aria-label`: este `<audio>` não tem `controls`, então não há\n // nada pro leitor de tela fazer com ele — e o rótulo repetia o título\n // que o container já anuncia, aparecendo duas vezes na árvore (o caso\n // do card de podcast). Quem nomeia o conjunto é o consumidor, com um\n // `<section>` nomeada em volta (ver `LessonPodcastSection`).\n >\n {tracks ? (\n tracks.map((track) => (\n <track\n key={track.src}\n kind={track.kind}\n src={track.src}\n srcLang={track.srcLang}\n label={track.label}\n default={track.default}\n />\n ))\n ) : (\n <track\n kind=\"captions\"\n src=\"data:text/vtt;base64,\"\n srcLang=\"pt\"\n label=\"Sem legendas disponíveis\"\n />\n )}\n </audio>\n\n {/* Play/Pause Button */}\n <button\n type=\"button\"\n onClick={handlePlayPause}\n disabled={!src}\n className=\"cursor-pointer text-text-950 hover:text-primary-600 disabled:text-text-400 disabled:cursor-not-allowed\"\n aria-label={playPauseLabel}\n >\n {isPlaying ? (\n <div className=\"w-6 h-6 flex items-center justify-center\">\n <div className=\"flex gap-0.5\">\n <div className=\"w-1 h-4 bg-current rounded-sm\"></div>\n <div className=\"w-1 h-4 bg-current rounded-sm\"></div>\n </div>\n </div>\n ) : (\n <PlayIcon size={24} />\n )}\n </button>\n\n {/* Current Time */}\n <p className=\"text-text-800 text-md font-medium min-w-[2.5rem]\">\n {formatTime(currentTime)}\n </p>\n\n {/* Progress Bar */}\n <div className=\"flex-1 relative\" data-testid=\"progress-bar\">\n <button\n type=\"button\"\n className=\"w-full h-2 bg-border-100 rounded-full cursor-pointer\"\n onClick={handleProgressClick}\n onKeyDown={handleProgressKeyDown}\n // O papel nativo de botão não carrega posição nem duração: o leitor\n // anunciava só o rótulo, sem dizer em que ponto do áudio se está.\n role=\"slider\"\n aria-label=\"Barra de progresso do áudio\"\n aria-valuemin={0}\n aria-valuemax={hasKnownDuration ? Math.round(duration) : 0}\n aria-valuenow={hasKnownDuration ? Math.round(currentTime) : 0}\n // Sem duração conhecida, anuncia só o decorrido: dizer \"de 0:00\"\n // afirmaria um total que não existe.\n aria-valuetext={\n hasKnownDuration\n ? `${formatTime(currentTime)} de ${formatTime(duration)}`\n : formatTime(currentTime)\n }\n >\n <div\n className=\"h-full bg-primary-600 rounded-full transition-all duration-100\"\n style={{\n width:\n duration > 0 ? `${(currentTime / duration) * 100}%` : '0%',\n }}\n />\n </button>\n </div>\n\n {/* Duration */}\n <p className=\"text-text-800 text-md font-medium min-w-[2.5rem]\">\n {formatTime(duration)}\n </p>\n\n {/* Volume Control */}\n <div className=\"relative h-6\" ref={volumeControlRef}>\n <button\n ref={volumeButtonRef}\n type=\"button\"\n onClick={toggleVolumeControl}\n className=\"cursor-pointer text-text-950 hover:text-primary-600\"\n aria-label=\"Controle de volume\"\n aria-expanded={showVolumeControl}\n >\n <div className=\"w-6 h-6 flex items-center justify-center\">\n {getVolumeIcon()}\n </div>\n </button>\n\n {showVolumeControl && (\n // Era um <button> envolvendo o slider: além de HTML inválido, o\n // papel de botão achata os filhos, e o slider não chegava ao leitor.\n <div className=\"absolute bottom-full right-0 mb-2 p-2 bg-background border border-border-100 rounded-lg shadow-lg\">\n <input\n ref={volumeSliderRef}\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.1\"\n value={displayVolume}\n onChange={handleVolumeChange}\n onKeyDown={handleVolumeKeyDown}\n className=\"w-20 h-2 bg-border-100 rounded-lg appearance-none cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary-500\"\n style={{\n background: `linear-gradient(to right, #3b82f6 0%, #3b82f6 ${displayVolume * 100}%, #e5e7eb ${displayVolume * 100}%, #e5e7eb 100%)`,\n }}\n aria-label=\"Volume\"\n aria-valuenow={Math.round(displayVolume * 100)}\n aria-valuemin={0}\n aria-valuemax={100}\n // Sem isto o leitor fala o número cru — e aqui seria \"0,5\",\n // porque a faixa nativa vai de 0 a 1, não de 0 a 100.\n aria-valuetext={`${Math.round(displayVolume * 100)} por cento`}\n />\n </div>\n )}\n </div>\n\n {/* Menu Button */}\n <div className=\"relative h-6\" ref={speedMenuRef}>\n <button\n ref={speedButtonRef}\n type=\"button\"\n onClick={toggleSpeedMenu}\n className=\"cursor-pointer text-text-950 hover:text-primary-600\"\n aria-label=\"Opções de velocidade\"\n aria-haspopup=\"menu\"\n aria-expanded={showSpeedMenu}\n >\n <DotsThreeVerticalIcon size={24} />\n </button>\n\n {showSpeedMenu && (\n <div className=\"absolute bottom-full right-0 mb-2 p-2 bg-background border border-border-100 rounded-lg shadow-lg min-w-24 z-10\">\n <div\n ref={speedMenuListRef}\n role=\"menu\"\n aria-label=\"Velocidade de reprodução\"\n // Focável só por script: o foco vive nas velocidades\n tabIndex={-1}\n onKeyDown={handleSpeedMenuKeyDown}\n className=\"flex flex-col gap-1\"\n >\n {AUDIO_SPEED_OPTIONS.map(({ speed, label }) => (\n <button\n key={speed}\n type=\"button\"\n // A velocidade ativa só se distinguia pela cor de fundo:\n // `aria-checked` é o que a torna audível.\n role=\"menuitemradio\"\n aria-checked={playbackRate === speed}\n // Tabindex móvel: as setas andam entre as velocidades\n tabIndex={-1}\n onClick={() => handleSpeedChange(speed)}\n className={cn(\n 'px-3 py-1 text-sm text-left rounded hover:bg-border-50 transition-colors',\n playbackRate === speed\n ? 'bg-primary-950 text-secondary-100 font-medium'\n : 'text-text-950'\n )}\n >\n {label}\n </button>\n ))}\n </div>\n </div>\n )}\n </div>\n </CardBase>\n );\n }\n);\n\ninterface CardSimuladoProps extends HTMLAttributes<HTMLDivElement> {\n title: string;\n duration?: string;\n info: string;\n backgroundColor: 'enem' | 'prova' | 'simuladao' | 'vestibular';\n /**\n * Renders the card in a non-interactive \"coming soon\" state: greyed out,\n * not clickable, with an \"Em breve\" badge next to the title.\n */\n comingSoon?: boolean;\n /** Disables interaction (greyed out, not clickable) without a badge. */\n disabled?: boolean;\n}\n\nconst SIMULADO_BACKGROUND_CLASSES = {\n enem: 'bg-exam-1',\n prova: 'bg-exam-2',\n simuladao: 'bg-exam-3',\n vestibular: 'bg-exam-4',\n};\n\nconst CardSimulado = forwardRef<HTMLDivElement, CardSimuladoProps>(\n (\n {\n title,\n duration,\n info,\n backgroundColor,\n comingSoon = false,\n disabled = false,\n className,\n onClick,\n onKeyDown,\n ...props\n },\n ref\n ) => {\n const backgroundClass = SIMULADO_BACKGROUND_CLASSES[backgroundColor];\n const isInteractive = !comingSoon && !disabled;\n\n return (\n <CardBase\n ref={ref}\n layout=\"horizontal\"\n padding=\"medium\"\n minHeight=\"none\"\n cursor={isInteractive ? 'pointer' : 'default'}\n aria-disabled={isInteractive ? undefined : true}\n // Only forward handlers when interactive: CardBase derives tabIndex,\n // role=\"button\" and Enter/Space activation from the presence of onClick,\n // so a disabled/coming-soon card must not receive them.\n onClick={isInteractive ? onClick : undefined}\n onKeyDown={isInteractive ? onKeyDown : undefined}\n className={cn(\n backgroundClass,\n isInteractive\n ? 'hover:shadow-soft-shadow-2 transition-shadow duration-200'\n : 'opacity-60 pointer-events-none',\n className\n )}\n {...props}\n >\n <div className=\"flex justify-between items-center w-full gap-4\">\n <div className=\"flex flex-col gap-1 flex-1 min-w-0\">\n {comingSoon ? (\n <div className=\"flex items-center gap-2 min-w-0\">\n <Text\n size=\"lg\"\n weight=\"bold\"\n className=\"text-text-950 truncate\"\n >\n {title}\n </Text>\n <Badge\n size=\"small\"\n variant=\"solid\"\n action=\"info\"\n className=\"flex-shrink-0\"\n data-testid=\"badge-em-breve\"\n >\n Em breve\n </Badge>\n </div>\n ) : (\n <Text size=\"lg\" weight=\"bold\" className=\"text-text-950 truncate\">\n {title}\n </Text>\n )}\n\n <div className=\"flex items-center gap-4 text-text-700\">\n {duration && (\n <div className=\"flex items-center gap-1\">\n {/* Decorativo: a duração está no texto ao lado. O Phosphor não\n marca os ícones sozinho — sem `alt` ele nem emite\n `<title>`, então o leitor anunciava um gráfico sem nome. */}\n <ClockIcon\n size={16}\n className=\"flex-shrink-0\"\n aria-hidden=\"true\"\n />\n <Text size=\"sm\">{duration}</Text>\n </div>\n )}\n\n <Text size=\"sm\" className=\"truncate\">\n {info}\n </Text>\n </div>\n </div>\n\n {isInteractive && (\n <CaretRightIcon\n size={24}\n className=\"text-text-800 flex-shrink-0\"\n data-testid=\"caret-icon\"\n aria-hidden=\"true\"\n />\n )}\n </div>\n </CardBase>\n );\n }\n);\n\ninterface CardTestProps extends Omit<HTMLAttributes<HTMLElement>, 'onSelect'> {\n title: string;\n duration?: string;\n questionsCount?: number;\n additionalInfo?: string;\n selected?: boolean;\n onSelect?: (selected: boolean) => void;\n}\n\nconst CardTest = forwardRef<HTMLElement, CardTestProps>(\n (\n {\n title,\n duration,\n questionsCount,\n additionalInfo,\n selected = false,\n onSelect,\n className = '',\n ...props\n },\n ref\n ) => {\n const handleClick = () => {\n if (onSelect) {\n onSelect(!selected);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLElement>) => {\n if ((event.key === 'Enter' || event.key === ' ') && onSelect) {\n event.preventDefault();\n onSelect(!selected);\n }\n };\n\n const isSelectable = !!onSelect;\n const getQuestionsText = (count: number) => {\n const singular = count === 1 ? 'questão' : 'questões';\n return `${count} ${singular}`;\n };\n\n const displayInfo = questionsCount\n ? getQuestionsText(questionsCount)\n : additionalInfo || '';\n const baseClasses =\n 'flex flex-row items-center p-4 gap-2 w-full max-w-full bg-background shadow-soft-shadow-1 rounded-xl isolate border-0 text-left';\n const interactiveClasses = isSelectable\n ? 'cursor-pointer focus:outline-none focus:ring-2 focus:ring-primary-950 focus:ring-offset-2'\n : '';\n const selectedClasses = selected\n ? 'ring-2 ring-primary-950 ring-offset-2'\n : '';\n\n if (isSelectable) {\n return (\n <button\n ref={ref as Ref<HTMLButtonElement>}\n type=\"button\"\n className={cn(\n `${baseClasses} ${interactiveClasses} ${selectedClasses} ${className}`.trim()\n )}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n aria-pressed={selected}\n {...(props as HTMLAttributes<HTMLButtonElement>)}\n >\n <div className=\"flex flex-col justify-between gap-[27px] flex-grow min-h-[67px] w-full min-w-0\">\n <Text\n size=\"md\"\n weight=\"bold\"\n className=\"text-text-950 tracking-[0.2px] leading-[19px] truncate\"\n >\n {title}\n </Text>\n\n <div className=\"flex flex-row justify-start items-end gap-4 w-full\">\n {duration && (\n <div className=\"flex flex-row items-center gap-1 flex-shrink-0\">\n <ClockIcon\n size={16}\n className=\"text-text-700\"\n aria-hidden=\"true\"\n />\n <Text\n size=\"sm\"\n className=\"text-text-700 leading-[21px] whitespace-nowrap\"\n >\n {duration}\n </Text>\n </div>\n )}\n\n <Text\n size=\"sm\"\n className=\"text-text-700 leading-[21px] flex-grow truncate\"\n >\n {displayInfo}\n </Text>\n </div>\n </div>\n </button>\n );\n }\n\n return (\n <div\n ref={ref as Ref<HTMLDivElement>}\n className={cn(`${baseClasses} ${className}`.trim())}\n {...(props as HTMLAttributes<HTMLDivElement>)}\n >\n <div className=\"flex flex-col justify-between gap-[27px] flex-grow min-h-[67px] w-full min-w-0\">\n <Text\n size=\"md\"\n weight=\"bold\"\n className=\"text-text-950 tracking-[0.2px] leading-[19px] truncate\"\n >\n {title}\n </Text>\n\n <div className=\"flex flex-row justify-start items-end gap-4 w-full\">\n {duration && (\n <div className=\"flex flex-row items-center gap-1 flex-shrink-0\">\n <ClockIcon\n size={16}\n className=\"text-text-700\"\n aria-hidden=\"true\"\n />\n <Text\n size=\"sm\"\n className=\"text-text-700 leading-[21px] whitespace-nowrap\"\n >\n {duration}\n </Text>\n </div>\n )}\n\n <Text\n size=\"sm\"\n className=\"text-text-700 leading-[21px] flex-grow truncate min-w-0\"\n >\n {displayInfo}\n </Text>\n </div>\n </div>\n </div>\n );\n }\n);\n\ninterface SimulationItem {\n id: string;\n title: string;\n type: 'enem' | 'prova' | 'simulado' | 'vestibular';\n info: string;\n /**\n * Optional status badge (e.g. \"Em andamento\" / \"Concluído\"). When provided it\n * is rendered next to the type badge. `action` maps to the Badge color action.\n */\n statusBadge?: {\n label: string;\n action: 'success' | 'warning' | 'info' | 'error';\n };\n /**\n * True when the current user authored this simulation and may remove it.\n * Only then is the delete action rendered — a simulation assigned by a\n * teacher never gets one.\n */\n canDelete?: boolean;\n}\n\ninterface SimulationHistoryData {\n date: string;\n simulations: SimulationItem[];\n}\n\ninterface CardSimulationHistoryProps extends HTMLAttributes<HTMLDivElement> {\n data: SimulationHistoryData[];\n onSimulationClick?: (simulation: SimulationItem) => void;\n /**\n * Called when the delete action is triggered for a simulation. The action is\n * only rendered for items flagged with `canDelete`. Confirmation is the\n * caller's responsibility.\n */\n onDeleteClick?: (simulation: SimulationItem) => void;\n}\n\nconst SIMULATION_TYPE_STYLES = {\n enem: {\n background: 'bg-exam-1',\n badge: 'exam1' as const,\n text: 'Enem',\n },\n prova: {\n background: 'bg-exam-2',\n badge: 'exam2' as const,\n text: 'Prova',\n },\n simulado: {\n background: 'bg-exam-3',\n badge: 'exam3' as const,\n text: 'Simuladão',\n },\n vestibular: {\n background: 'bg-exam-4',\n badge: 'exam4' as const,\n text: 'Vestibular',\n },\n};\n\nconst CardSimulationHistory = forwardRef<\n HTMLDivElement,\n CardSimulationHistoryProps\n>(({ data, onSimulationClick, onDeleteClick, className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn('w-full max-w-[992px] h-auto', className)}\n {...props}\n >\n {/* Content */}\n <div className=\"flex flex-col gap-0\">\n {data.map((section, sectionIndex) => (\n <div key={section.date} className=\"flex flex-col\">\n {/* Seção com data */}\n <div\n className={cn(\n 'flex flex-row justify-center items-start px-4 py-6 gap-2 w-full bg-background',\n sectionIndex === 0 ? 'rounded-t-3xl' : ''\n )}\n >\n <Text\n size=\"xs\"\n weight=\"bold\"\n className=\"text-text-800 w-11 flex-shrink-0\"\n >\n {section.date}\n </Text>\n\n <div className=\"flex flex-col gap-2 flex-1\">\n {section.simulations.map((simulation) => {\n const typeStyles = SIMULATION_TYPE_STYLES[simulation.type];\n\n return (\n <CardBase\n key={simulation.id}\n layout=\"horizontal\"\n padding=\"medium\"\n minHeight=\"none\"\n cursor=\"pointer\"\n className={cn(\n `${typeStyles.background} rounded-xl hover:shadow-soft-shadow-2 \n transition-shadow duration-200 h-auto min-h-[61px]`\n )}\n onClick={() => onSimulationClick?.(simulation)}\n >\n <div className=\"flex justify-between items-center w-full gap-2\">\n <div className=\"flex flex-wrap flex-col justify-between sm:flex-row gap-2 flex-1 min-w-0\">\n <Text\n size=\"lg\"\n weight=\"bold\"\n className=\"text-text-950 truncate\"\n >\n {simulation.title}\n </Text>\n\n <div className=\"flex items-center gap-2\">\n <Badge\n variant=\"examsOutlined\"\n action={typeStyles.badge}\n size=\"medium\"\n >\n {typeStyles.text}\n </Badge>\n\n {simulation.statusBadge && (\n <Badge\n variant=\"outlined\"\n action={simulation.statusBadge.action}\n size=\"medium\"\n >\n {simulation.statusBadge.label}\n </Badge>\n )}\n\n <Text size=\"sm\" className=\"text-text-800 truncate\">\n {simulation.info}\n </Text>\n </div>\n </div>\n\n <div className=\"flex items-center gap-1 flex-shrink-0\">\n {simulation.canDelete && onDeleteClick && (\n <IconButton\n size=\"sm\"\n icon={<TrashIcon size={20} />}\n aria-label={`Excluir simulado ${simulation.title}`}\n data-testid={`delete-simulation-${simulation.id}`}\n // The whole CardBase is clickable, so the click\n // must not bubble up into onSimulationClick.\n onClick={(event) => {\n event.stopPropagation();\n onDeleteClick(simulation);\n }}\n />\n )}\n\n <CaretRightIcon\n size={24}\n className=\"text-text-800\"\n data-testid=\"caret-icon\"\n />\n </div>\n </div>\n </CardBase>\n );\n })}\n </div>\n </div>\n </div>\n ))}\n\n {/* Footer rounded */}\n {data.length > 0 && (\n <div className=\"w-full h-6 bg-background rounded-b-3xl\" />\n )}\n </div>\n </div>\n );\n});\n\n// ======================================================================\n// CardEssayHistory — histórico de redações agrupado por data\n// ======================================================================\n\nexport enum EssayStatus {\n DRAFT = 'DRAFT',\n SUBMITTED = 'SUBMITTED',\n CORRECTING = 'CORRECTING',\n CORRECTED = 'CORRECTED',\n ERROR = 'ERROR',\n}\n\nexport enum EssayReviewStatus {\n PENDING = 'PENDING',\n APPROVED = 'APPROVED',\n MODIFIED = 'MODIFIED',\n}\n\nexport interface EssayHistoryItem {\n id: string;\n /** Título exibido. Se null/undefined, o componente cai no `fallbackTitle` */\n title: string | null;\n /** Título fallback (ex: título do tema) quando `title` está vazio */\n fallbackTitle?: string;\n status: EssayStatus;\n /** Nota total (0..maxScore). null quando ainda não pontuou */\n totalScore: number | null;\n /** Status da revisão do professor */\n reviewStatus?: EssayReviewStatus | null;\n}\n\nexport interface EssayHistoryData {\n /** Label da data do grupo (ex: \"12 Fev\") */\n date: string;\n essays: EssayHistoryItem[];\n}\n\ninterface CardEssayHistoryProps extends HTMLAttributes<HTMLDivElement> {\n data: EssayHistoryData[];\n /** Nota máxima pra compor o label \"X de {maxScore}\". Default: 1000 */\n maxScore?: number;\n /** Callback ao clicar num item clicável (CORRECTED com score, ou ERROR) */\n onEssayClick?: (essay: EssayHistoryItem) => void;\n}\n\ntype EssayVisualState = {\n background: string;\n text: string;\n clickable: boolean;\n};\n\nconst resolveEssayVisualState = (\n essay: EssayHistoryItem,\n maxScore: number\n): EssayVisualState => {\n // If essay has a score, show it (regardless of status - covers professor review cases)\n if (essay.totalScore != null) {\n return {\n background: 'bg-subject-12',\n text: `${essay.totalScore} de ${maxScore}`,\n clickable: true,\n };\n }\n if (essay.status === EssayStatus.ERROR) {\n return {\n background: 'bg-tertiary-100',\n text: 'Erro na correção',\n clickable: true,\n };\n }\n if (\n essay.status === EssayStatus.CORRECTING ||\n essay.status === EssayStatus.SUBMITTED\n ) {\n return {\n background: 'bg-secondary-200',\n text: 'Gerando resultado...',\n clickable: false,\n };\n }\n if (essay.status === EssayStatus.DRAFT) {\n return {\n background: 'bg-secondary-200',\n text: 'Rascunho',\n clickable: false,\n };\n }\n return {\n background: 'bg-secondary-200',\n text: 'Sem nota ainda',\n clickable: false,\n };\n};\n\ntype ReviewBadgeConfig = {\n label: string;\n action: 'success' | 'info';\n} | null;\n\nconst resolveReviewBadge = (essay: EssayHistoryItem): ReviewBadgeConfig => {\n if (\n essay.reviewStatus === EssayReviewStatus.APPROVED ||\n essay.reviewStatus === EssayReviewStatus.MODIFIED\n ) {\n return { label: 'Revisado', action: 'success' };\n }\n\n if (\n essay.status === EssayStatus.CORRECTED &&\n essay.reviewStatus === EssayReviewStatus.PENDING\n ) {\n return { label: 'Corrigido por IA', action: 'info' };\n }\n\n return null;\n};\n\nconst CardEssayHistory = forwardRef<HTMLDivElement, CardEssayHistoryProps>(\n ({ data, maxScore = 1000, onEssayClick, className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn('w-full max-w-248 bg-background rounded-3xl', className)}\n {...props}\n >\n <div className=\"flex flex-col\">\n {data.map((section, sectionIndex) => (\n <div\n key={`${section.date}-${sectionIndex}`}\n className=\"flex flex-row items-start px-4 py-6 gap-2 w-full\"\n >\n <Text\n size=\"xs\"\n weight=\"bold\"\n className=\"text-text-800 w-11 shrink-0 pt-3\"\n >\n {section.date}\n </Text>\n\n <div className=\"flex flex-col gap-2 flex-1 min-w-0\">\n {section.essays.map((essay) => {\n const visual = resolveEssayVisualState(essay, maxScore);\n const isClickable = visual.clickable && !!onEssayClick;\n const label =\n essay.title ?? essay.fallbackTitle ?? 'Sem título';\n const reviewBadge = resolveReviewBadge(essay);\n\n return (\n <button\n key={essay.id}\n type=\"button\"\n disabled={!isClickable}\n onClick={() => isClickable && onEssayClick?.(essay)}\n aria-label={`${label} — ${visual.text}`}\n className={cn(\n visual.background,\n 'rounded-xl p-4 flex flex-row items-center justify-between gap-2 w-full transition-shadow duration-200',\n isClickable\n ? 'cursor-pointer hover:shadow-soft-shadow-2'\n : 'cursor-default'\n )}\n >\n <Text\n size=\"md\"\n weight=\"bold\"\n className=\"text-text-950 truncate text-left\"\n >\n {label}\n </Text>\n\n <div className=\"flex items-center gap-2 shrink-0\">\n {reviewBadge && (\n <Badge\n variant=\"solid\"\n action={reviewBadge.action}\n size=\"small\"\n >\n {reviewBadge.label}\n </Badge>\n )}\n <Text\n size=\"sm\"\n className=\"text-text-800 whitespace-nowrap\"\n >\n {visual.text}\n </Text>\n {isClickable && (\n <CaretRightIcon\n size={20}\n className=\"text-text-800 shrink-0\"\n />\n )}\n </div>\n </button>\n );\n })}\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n }\n);\n\n// ======================================================================\n// CardReadingFluency — card de atividade da variante Reading Fluency\n// ======================================================================\n\ntype CardReadingFluencyState = 'new' | 'coming-soon' | 'done';\n\ninterface CardReadingFluencyProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Estado do card:\n * - `new`: nova atividade (badge \"NOVA ATIVIDADE!\", clicável)\n * - `coming-soon`: em breve (opaco/desativado, borda tracejada, badge \"EM BREVE\")\n * - `done`: atividade concluída (check no canto, clicável)\n */\n state?: CardReadingFluencyState;\n /** Cor de fundo do card em hex (vinda do backend, igual aos subjects). */\n color?: string;\n /** Sobrescreve a imagem do passarinho (default: asset padrão do Reading Fluency). */\n image?: string;\n /** Texto alternativo/aria da imagem. */\n label?: string;\n /**\n * Legenda exibida abaixo do card (bold, xs, text-100). Omitida quando vazia.\n * Nome distinto de `title` para não colidir com o atributo HTML nativo\n * `title` (tooltip), que segue repassável via `...props`.\n */\n activityTitle?: string;\n}\n\n/**\n * Badge dos cards Reading Fluency. Dimensões e tipografia fixas da arte: 117×23,\n * radius 8px, px 8 / py 4, gap 8, texto Quicksand 700/12px. A cor de fundo\n * (preto com opacidade) varia por estado: 70% em \"nova atividade\", 30% em\n * \"em breve\".\n */\nconst PAPOLE_BADGE_CLASSES =\n 'flex items-center justify-center gap-2 w-[117px] h-[23px] rounded-lg px-2 py-1 text-[12px] font-bold text-white whitespace-nowrap';\n\nconst CardReadingFluency = forwardRef<HTMLDivElement, CardReadingFluencyProps>(\n (\n {\n state = 'new',\n // Scent color 2 (verde) do tema do aluno. Era o hex #a3d9b1 cravado, que\n // deixava o default do componente fora do tema.\n color = 'var(--color-scent-2)',\n image,\n label = 'Reading Fluency',\n activityTitle,\n className,\n onClick,\n onKeyDown,\n ...props\n },\n ref\n ) => {\n const isComingSoon = state === 'coming-soon';\n const isDone = state === 'done';\n const isInteractive = !isComingSoon;\n const isClickable = isInteractive && !!onClick;\n\n const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n if (isClickable && ['Enter', ' '].includes(e.key)) {\n e.preventDefault();\n (e.currentTarget as HTMLElement).click();\n }\n onKeyDown?.(e);\n };\n\n return (\n <div className=\"flex flex-col items-center gap-3\">\n <div\n ref={ref}\n className={cn(\n 'relative flex items-center justify-center w-[240px] h-[182px] rounded-2xl font-quicksand overflow-hidden',\n // Uma capa do banco preenche o card inteiro (full-bleed), então sem\n // padding. O asset padrão (passarinho) segue centralizado com respiro.\n image ? '' : 'px-[82px] py-[28px]',\n isClickable && 'cursor-pointer',\n isComingSoon &&\n 'pointer-events-none border-2 border-dashed border-border-300',\n className\n )}\n style={{ backgroundColor: color }}\n onClick={isInteractive ? onClick : undefined}\n onKeyDown={handleKeyDown}\n tabIndex={isClickable ? 0 : undefined}\n role={isClickable ? 'button' : undefined}\n aria-disabled={isComingSoon ? true : undefined}\n {...props}\n >\n <img\n src={image ?? readingFluencyBird}\n alt={label}\n draggable={false}\n className={cn(\n // Capa do banco de imagens: ocupa exatamente o tamanho do card\n // (240×182), recortando o excesso sem distorcer. O passarinho\n // padrão continua no tamanho original, centralizado.\n image\n ? 'absolute inset-0 w-full h-full object-cover select-none'\n : 'w-full h-auto select-none',\n isComingSoon && 'opacity-40'\n )}\n />\n\n {isDone && (\n <CheckCircleIcon\n weight=\"fill\"\n size={28}\n className=\"absolute top-3 right-3 text-background drop-shadow-sm\"\n data-testid=\"reading-fluency-check\"\n />\n )}\n\n {state === 'new' && (\n <span\n className={cn(\n 'absolute bottom-3 left-1/2 -translate-x-1/2 bg-black/70',\n PAPOLE_BADGE_CLASSES\n )}\n >\n NOVA ATIVIDADE!\n </span>\n )}\n\n {isComingSoon && (\n <span\n className={cn(\n 'absolute bottom-3 left-1/2 -translate-x-1/2 bg-black/30',\n PAPOLE_BADGE_CLASSES\n )}\n >\n EM BREVE\n </span>\n )}\n </div>\n\n {activityTitle && (\n <Text\n size=\"xs\"\n weight=\"bold\"\n color=\"text-text-100\"\n className=\"w-60 text-center font-quicksand uppercase\"\n >\n {activityTitle}\n </Text>\n )}\n </div>\n );\n }\n);\n\nexport {\n CardBase,\n CardActivitiesResults,\n CardQuestions,\n CardProgress,\n CardTopic,\n CardPerformance,\n CardResults,\n CardStatus,\n CardSettings,\n CardSupport,\n CardForum,\n CardAudio,\n CardSimulado,\n CardTest,\n CardSimulationHistory,\n CardEssayHistory,\n CardReadingFluency,\n};\n\nexport type { CardReadingFluencyProps, CardReadingFluencyState };\n"],"mappings":"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","names":["Fragment","status","EssayStatus","EssayReviewStatus"]}
@@ -1,9 +1,9 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunkXOKBMLW3js = require('./chunk-XOKBMLW3.js');
3
+ var _chunk7IGUYLSFjs = require('./chunk-7IGUYLSF.js');
4
4
 
5
5
 
6
- var _chunkBVUPM6EYjs = require('./chunk-BVUPM6EY.js');
6
+ var _chunkCAQ2Q3ONjs = require('./chunk-CAQ2Q3ON.js');
7
7
 
8
8
 
9
9
  var _chunkTN3AYOMVjs = require('./chunk-TN3AYOMV.js');
@@ -222,7 +222,7 @@ var DownloadButton = ({
222
222
  const suffix = availableCount > 1 ? "s" : "";
223
223
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkTN3AYOMVjs.cn.call(void 0, "flex items-center", className), children: [
224
224
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
225
- _chunkBVUPM6EYjs.IconButton_default,
225
+ _chunkCAQ2Q3ONjs.IconButton_default,
226
226
  {
227
227
  icon: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _DownloadSimple.DownloadSimpleIcon, { size: 24 }),
228
228
  onClick: handleDownload,
@@ -235,7 +235,7 @@ var DownloadButton = ({
235
235
  }
236
236
  ),
237
237
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
238
- _chunkXOKBMLW3js.ProgressModal_default,
238
+ _chunk7IGUYLSFjs.ProgressModal_default,
239
239
  {
240
240
  isOpen: isDownloading,
241
241
  onClose: () => {
@@ -251,4 +251,4 @@ var DownloadButton_default = DownloadButton;
251
251
 
252
252
 
253
253
  exports.DownloadButton_default = DownloadButton_default;
254
- //# sourceMappingURL=chunk-754M6HQ5.js.map
254
+ //# sourceMappingURL=chunk-EJN4OP3D.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-754M6HQ5.js","../src/components/DownloadButton/DownloadButton.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-754M6HQ5.js","sourcesContent":[null,"import { useCallback, useState } from 'react';\nimport { DownloadSimpleIcon } from '@phosphor-icons/react/dist/csr/DownloadSimple';\nimport IconButton from '../IconButton/IconButton';\nimport ProgressModal from '../ProgressModal/ProgressModal';\nimport { cn } from '../../utils/utils';\n\n/**\n * Download content interface for lesson materials\n */\nexport interface DownloadContent {\n /** Initial frame image URL */\n urlInitialFrame?: string;\n /** Final frame image URL */\n urlFinalFrame?: string;\n /** Podcast audio URL */\n urlPodcast?: string;\n /** Video URL */\n urlVideo?: string;\n}\n\n/**\n * Props for DownloadButton component\n */\nexport interface DownloadButtonProps {\n /** Content URLs to download */\n content: DownloadContent;\n /** Additional CSS classes */\n className?: string;\n /** Callback fired when download starts */\n onDownloadStart?: (contentType: string) => void;\n /** Callback fired when download completes */\n onDownloadComplete?: (contentType: string) => void;\n /** Callback fired when download fails */\n onDownloadError?: (contentType: string, error: Error) => void;\n /** Lesson title for download file naming */\n lessonTitle?: string;\n /** Whether the button is disabled */\n disabled?: boolean;\n}\n\n/** A single downloadable asset resolved from the lesson content */\ninterface DownloadItem {\n type: string;\n url: string;\n label: string;\n}\n\n/**\n * Minimal shape of the File System Access API we rely on.\n *\n * Typed locally because `showDirectoryPicker` is not in the DOM lib yet, and\n * because only Chromium ships it — every use goes through `supportsDirectoryPicker`.\n */\ninterface FileSystemWritable {\n write: (chunk: Uint8Array) => Promise<void>;\n close: () => Promise<void>;\n abort?: () => Promise<void>;\n}\n\ninterface FileSystemFileHandleLike {\n createWritable: () => Promise<FileSystemWritable>;\n}\n\ninterface FileSystemDirectoryHandleLike {\n getFileHandle: (\n name: string,\n options?: { create?: boolean }\n ) => Promise<FileSystemFileHandleLike>;\n}\n\ntype DirectoryPicker = (options?: {\n mode?: string;\n id?: string;\n}) => Promise<FileSystemDirectoryHandleLike>;\n\n/**\n * Whether the browser can stream downloads straight to a folder on disk.\n *\n * Chromium-based browsers ship the File System Access API; Safari and Firefox\n * do not, and fall back to plain per-file downloads.\n *\n * @returns Whether `showDirectoryPicker` is available\n */\nconst supportsDirectoryPicker = (): boolean =>\n typeof (globalThis as { showDirectoryPicker?: DirectoryPicker })\n .showDirectoryPicker === 'function';\n\n/**\n * Get file extension from URL\n * @param url - URL to extract extension from\n * @returns File extension or default\n */\nconst getFileExtension = (url: string): string => {\n try {\n const u = new URL(url, globalThis.location?.origin || 'http://localhost');\n url = u.pathname;\n } catch {\n // keep original url (likely relative)\n }\n const path = url.split(/[?#]/)[0];\n const dot = path.lastIndexOf('.');\n return dot > -1 ? path.slice(dot + 1).toLowerCase() : 'file';\n};\n\n/**\n * Slugify a lesson title for safe use in filenames\n * @param lessonTitle - Title of the lesson\n * @returns Sanitized slug\n */\nconst slugifyTitle = (lessonTitle: string): string =>\n lessonTitle\n .toLowerCase()\n .replaceAll(/[^a-z0-9\\s]/g, '')\n .replaceAll(/\\s+/g, '-')\n .substring(0, 50);\n\n/**\n * Generate the filename an asset is saved as\n * @param contentType - Type of content being downloaded\n * @param url - URL to get extension from\n * @param lessonTitle - Title of the lesson\n * @returns Generated filename\n */\nconst generateFilename = (\n contentType: string,\n url: string,\n lessonTitle: string = 'aula'\n): string =>\n `${slugifyTitle(lessonTitle)}-${contentType}.${getFileExtension(url)}`;\n\n/**\n * Read the byte size of a remote file without downloading it.\n *\n * Weights per-file progress against the real payload — a lesson video can be\n * hundreds of MB while the board frames are ~1MB, so counting files would make\n * the bar jump. Returns 0 when the server omits `content-length` or the request\n * fails, and callers then fall back to counting files.\n *\n * @param url - URL to probe\n * @returns Size in bytes, or 0 when unknown\n */\nconst getRemoteFileSize = async (url: string): Promise<number> => {\n try {\n const response = await fetch(url, { method: 'HEAD', mode: 'cors' });\n if (!response.ok) return 0;\n return Number(response.headers.get('content-length')) || 0;\n } catch {\n return 0;\n }\n};\n\n/**\n * Stream a remote file straight into a file on disk.\n *\n * Nothing is buffered in memory: each chunk is written to the file handle as it\n * arrives. This is what makes a ~900MB lesson video downloadable — holding it\n * in a Blob (and zipping it) exhausts the tab's memory and silently drops the\n * assets queued behind it.\n *\n * @param url - URL to download\n * @param dirHandle - Directory the user granted write access to\n * @param filename - Name to save the file as\n * @param onBytes - Called with the byte length of each chunk written\n */\nconst streamToDisk = async (\n url: string,\n dirHandle: FileSystemDirectoryHandleLike,\n filename: string,\n onBytes: (chunkSize: number) => void\n): Promise<void> => {\n const response = await fetch(url, { mode: 'cors' });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch file: ${response.status} ${response.statusText}`\n );\n }\n if (!response.body) {\n throw new Error('Response has no readable body');\n }\n\n const fileHandle = await dirHandle.getFileHandle(filename, { create: true });\n const writable = await fileHandle.createWritable();\n\n try {\n const reader = response.body.getReader();\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n await writable.write(value);\n onBytes(value.length);\n }\n\n await writable.close();\n } catch (error) {\n await writable.abort?.();\n throw error;\n }\n};\n\n/**\n * Save a file through a plain anchor click, letting the browser download it.\n *\n * Fallback for browsers without the File System Access API (Safari, Firefox).\n * Note the `download` attribute is ignored cross-origin, and the CDN does not\n * send `Content-Disposition: attachment`, so these browsers may open the asset\n * in a tab rather than save it. Fixing that properly means setting that header\n * on the CDN — it cannot be forced from the client.\n *\n * The browser streams the response to its own downloads folder, so memory is\n * not a concern — but it\n * cannot report progress, and firing several in a row is unreliable, which is\n * why the caller spaces them out.\n *\n * @param url - URL to download\n * @param filename - Suggested filename\n */\nconst triggerBrowserDownload = (url: string, filename: string): void => {\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.rel = 'noopener noreferrer';\n\n document.body.appendChild(link);\n link.click();\n link.remove();\n};\n\n/**\n * DownloadButton component for downloading lesson content\n *\n * Downloads every asset of a lesson (video, podcast and board frames), matching\n * the mobile app's \"baixar aula completa\". Where the browser supports it, the\n * user picks a folder and each file is streamed straight to disk with real\n * progress; elsewhere the browser downloads them one by one.\n *\n * @param props - DownloadButton component props\n * @returns Download button element\n */\nconst DownloadButton = ({\n content,\n className,\n onDownloadStart,\n onDownloadComplete,\n onDownloadError,\n lessonTitle = 'aula',\n disabled = false,\n}: DownloadButtonProps) => {\n const [isDownloading, setIsDownloading] = useState(false);\n const [progress, setProgress] = useState(0);\n\n /**\n * Check if URL is valid and not empty\n * @param url - URL to validate\n * @returns Whether URL is valid\n */\n const isValidUrl = useCallback((url?: string): boolean => {\n return Boolean(\n url && url.trim() !== '' && url !== 'undefined' && url !== 'null'\n );\n }, []);\n\n /**\n * Get available download content\n * @returns Array of available download items\n */\n const getAvailableContent = useCallback((): DownloadItem[] => {\n const downloads: DownloadItem[] = [];\n\n if (isValidUrl(content.urlVideo)) {\n downloads.push({ type: 'video', url: content.urlVideo!, label: 'Vídeo' });\n }\n\n if (isValidUrl(content.urlPodcast)) {\n downloads.push({\n type: 'podcast',\n url: content.urlPodcast!,\n label: 'Podcast',\n });\n }\n\n if (isValidUrl(content.urlInitialFrame)) {\n downloads.push({\n type: 'quadro-inicial',\n url: content.urlInitialFrame!,\n label: 'Quadro Inicial',\n });\n }\n\n if (isValidUrl(content.urlFinalFrame)) {\n downloads.push({\n type: 'quadro-final',\n url: content.urlFinalFrame!,\n label: 'Quadro Final',\n });\n }\n\n return downloads;\n }, [content, isValidUrl]);\n\n /**\n * Download every asset by streaming it into the folder the user picked.\n *\n * @param items - Assets to download\n * @param dirHandle - Directory the user granted write access to\n */\n const downloadToFolder = useCallback(\n async (items: DownloadItem[], dirHandle: FileSystemDirectoryHandleLike) => {\n const sizes = await Promise.all(\n items.map((item) => getRemoteFileSize(item.url))\n );\n const totalBytes = sizes.reduce((sum, size) => sum + size, 0);\n // No content-length anywhere: weight each file equally instead of by bytes.\n const weighByFile = totalBytes === 0;\n\n let downloadedBytes = 0;\n let succeeded = 0;\n\n for (const [index, item] of items.entries()) {\n try {\n onDownloadStart?.(item.type);\n\n await streamToDisk(\n item.url,\n dirHandle,\n generateFilename(item.type, item.url, lessonTitle),\n (chunkSize) => {\n downloadedBytes += chunkSize;\n if (!weighByFile) {\n setProgress(\n Math.min(99, Math.round((downloadedBytes / totalBytes) * 100))\n );\n }\n }\n );\n\n succeeded++;\n onDownloadComplete?.(item.type);\n } catch (error) {\n onDownloadError?.(\n item.type,\n error instanceof Error\n ? error\n : new Error(`Falha ao baixar ${item.label}`)\n );\n } finally {\n if (weighByFile) {\n setProgress(\n Math.min(99, Math.round(((index + 1) / items.length) * 100))\n );\n }\n }\n }\n\n if (succeeded === 0) {\n throw new Error('Nenhum conteúdo da aula pôde ser baixado');\n }\n\n setProgress(100);\n },\n [lessonTitle, onDownloadStart, onDownloadComplete, onDownloadError]\n );\n\n /**\n * Hand each asset to the browser's own downloader, one at a time.\n *\n * Used where the File System Access API is missing. Downloads are spaced out\n * because browsers throttle several programmatic downloads fired at once.\n *\n * @param items - Assets to download\n */\n const downloadViaBrowser = useCallback(\n async (items: DownloadItem[]) => {\n for (const [index, item] of items.entries()) {\n onDownloadStart?.(item.type);\n\n triggerBrowserDownload(\n item.url,\n generateFilename(item.type, item.url, lessonTitle)\n );\n\n onDownloadComplete?.(item.type);\n setProgress(Math.round(((index + 1) / items.length) * 100));\n\n if (index < items.length - 1) {\n await new Promise((resolve) => setTimeout(resolve, 800));\n }\n }\n },\n [lessonTitle, onDownloadStart, onDownloadComplete]\n );\n\n /**\n * Download every asset of the lesson.\n *\n * Prefers streaming to a user-picked folder, which is the only approach that\n * survives a large lesson video. Falls back to the browser's downloader when\n * the File System Access API is unavailable.\n */\n const handleDownload = useCallback(async () => {\n if (disabled || isDownloading) return;\n\n const availableContent = getAvailableContent();\n if (availableContent.length === 0) return;\n\n let dirHandle: FileSystemDirectoryHandleLike | null = null;\n\n if (supportsDirectoryPicker()) {\n try {\n const picker = (globalThis as { showDirectoryPicker?: DirectoryPicker })\n .showDirectoryPicker!;\n dirHandle = await picker({ mode: 'readwrite', id: 'aulas' });\n } catch {\n // The user dismissed the folder picker: abort quietly, nothing to report.\n return;\n }\n }\n\n setIsDownloading(true);\n setProgress(0);\n\n try {\n if (dirHandle) {\n await downloadToFolder(availableContent, dirHandle);\n } else {\n await downloadViaBrowser(availableContent);\n }\n } catch (error) {\n onDownloadError?.(\n 'aula',\n error instanceof Error\n ? error\n : new Error('Falha ao baixar o conteúdo da aula')\n );\n } finally {\n setIsDownloading(false);\n setProgress(0);\n }\n }, [\n disabled,\n isDownloading,\n getAvailableContent,\n downloadToFolder,\n downloadViaBrowser,\n onDownloadError,\n ]);\n\n // Don't render if no content is available\n const availableCount = getAvailableContent().length;\n\n if (availableCount === 0) {\n return null;\n }\n\n const suffix = availableCount > 1 ? 's' : '';\n\n return (\n <div className={cn('flex items-center', className)}>\n <IconButton\n icon={<DownloadSimpleIcon size={24} />}\n onClick={handleDownload}\n disabled={disabled || isDownloading}\n aria-label={\n isDownloading\n ? 'Baixando conteúdo...'\n : `Baixar conteúdo da aula (${availableCount} arquivo${suffix})`\n }\n className={cn(\n '!bg-transparent hover:!bg-black/10 transition-colors',\n isDownloading && 'opacity-60 cursor-not-allowed'\n )}\n />\n\n <ProgressModal\n isOpen={isDownloading}\n onClose={() => {}}\n message=\"Baixando conteúdo da aula...\"\n progress={progress}\n />\n </div>\n );\n};\n\nexport default DownloadButton;\n"]}
1
+ {"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-EJN4OP3D.js","../src/components/DownloadButton/DownloadButton.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-EJN4OP3D.js","sourcesContent":[null,"import { useCallback, useState } from 'react';\nimport { DownloadSimpleIcon } from '@phosphor-icons/react/dist/csr/DownloadSimple';\nimport IconButton from '../IconButton/IconButton';\nimport ProgressModal from '../ProgressModal/ProgressModal';\nimport { cn } from '../../utils/utils';\n\n/**\n * Download content interface for lesson materials\n */\nexport interface DownloadContent {\n /** Initial frame image URL */\n urlInitialFrame?: string;\n /** Final frame image URL */\n urlFinalFrame?: string;\n /** Podcast audio URL */\n urlPodcast?: string;\n /** Video URL */\n urlVideo?: string;\n}\n\n/**\n * Props for DownloadButton component\n */\nexport interface DownloadButtonProps {\n /** Content URLs to download */\n content: DownloadContent;\n /** Additional CSS classes */\n className?: string;\n /** Callback fired when download starts */\n onDownloadStart?: (contentType: string) => void;\n /** Callback fired when download completes */\n onDownloadComplete?: (contentType: string) => void;\n /** Callback fired when download fails */\n onDownloadError?: (contentType: string, error: Error) => void;\n /** Lesson title for download file naming */\n lessonTitle?: string;\n /** Whether the button is disabled */\n disabled?: boolean;\n}\n\n/** A single downloadable asset resolved from the lesson content */\ninterface DownloadItem {\n type: string;\n url: string;\n label: string;\n}\n\n/**\n * Minimal shape of the File System Access API we rely on.\n *\n * Typed locally because `showDirectoryPicker` is not in the DOM lib yet, and\n * because only Chromium ships it — every use goes through `supportsDirectoryPicker`.\n */\ninterface FileSystemWritable {\n write: (chunk: Uint8Array) => Promise<void>;\n close: () => Promise<void>;\n abort?: () => Promise<void>;\n}\n\ninterface FileSystemFileHandleLike {\n createWritable: () => Promise<FileSystemWritable>;\n}\n\ninterface FileSystemDirectoryHandleLike {\n getFileHandle: (\n name: string,\n options?: { create?: boolean }\n ) => Promise<FileSystemFileHandleLike>;\n}\n\ntype DirectoryPicker = (options?: {\n mode?: string;\n id?: string;\n}) => Promise<FileSystemDirectoryHandleLike>;\n\n/**\n * Whether the browser can stream downloads straight to a folder on disk.\n *\n * Chromium-based browsers ship the File System Access API; Safari and Firefox\n * do not, and fall back to plain per-file downloads.\n *\n * @returns Whether `showDirectoryPicker` is available\n */\nconst supportsDirectoryPicker = (): boolean =>\n typeof (globalThis as { showDirectoryPicker?: DirectoryPicker })\n .showDirectoryPicker === 'function';\n\n/**\n * Get file extension from URL\n * @param url - URL to extract extension from\n * @returns File extension or default\n */\nconst getFileExtension = (url: string): string => {\n try {\n const u = new URL(url, globalThis.location?.origin || 'http://localhost');\n url = u.pathname;\n } catch {\n // keep original url (likely relative)\n }\n const path = url.split(/[?#]/)[0];\n const dot = path.lastIndexOf('.');\n return dot > -1 ? path.slice(dot + 1).toLowerCase() : 'file';\n};\n\n/**\n * Slugify a lesson title for safe use in filenames\n * @param lessonTitle - Title of the lesson\n * @returns Sanitized slug\n */\nconst slugifyTitle = (lessonTitle: string): string =>\n lessonTitle\n .toLowerCase()\n .replaceAll(/[^a-z0-9\\s]/g, '')\n .replaceAll(/\\s+/g, '-')\n .substring(0, 50);\n\n/**\n * Generate the filename an asset is saved as\n * @param contentType - Type of content being downloaded\n * @param url - URL to get extension from\n * @param lessonTitle - Title of the lesson\n * @returns Generated filename\n */\nconst generateFilename = (\n contentType: string,\n url: string,\n lessonTitle: string = 'aula'\n): string =>\n `${slugifyTitle(lessonTitle)}-${contentType}.${getFileExtension(url)}`;\n\n/**\n * Read the byte size of a remote file without downloading it.\n *\n * Weights per-file progress against the real payload — a lesson video can be\n * hundreds of MB while the board frames are ~1MB, so counting files would make\n * the bar jump. Returns 0 when the server omits `content-length` or the request\n * fails, and callers then fall back to counting files.\n *\n * @param url - URL to probe\n * @returns Size in bytes, or 0 when unknown\n */\nconst getRemoteFileSize = async (url: string): Promise<number> => {\n try {\n const response = await fetch(url, { method: 'HEAD', mode: 'cors' });\n if (!response.ok) return 0;\n return Number(response.headers.get('content-length')) || 0;\n } catch {\n return 0;\n }\n};\n\n/**\n * Stream a remote file straight into a file on disk.\n *\n * Nothing is buffered in memory: each chunk is written to the file handle as it\n * arrives. This is what makes a ~900MB lesson video downloadable — holding it\n * in a Blob (and zipping it) exhausts the tab's memory and silently drops the\n * assets queued behind it.\n *\n * @param url - URL to download\n * @param dirHandle - Directory the user granted write access to\n * @param filename - Name to save the file as\n * @param onBytes - Called with the byte length of each chunk written\n */\nconst streamToDisk = async (\n url: string,\n dirHandle: FileSystemDirectoryHandleLike,\n filename: string,\n onBytes: (chunkSize: number) => void\n): Promise<void> => {\n const response = await fetch(url, { mode: 'cors' });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch file: ${response.status} ${response.statusText}`\n );\n }\n if (!response.body) {\n throw new Error('Response has no readable body');\n }\n\n const fileHandle = await dirHandle.getFileHandle(filename, { create: true });\n const writable = await fileHandle.createWritable();\n\n try {\n const reader = response.body.getReader();\n\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n await writable.write(value);\n onBytes(value.length);\n }\n\n await writable.close();\n } catch (error) {\n await writable.abort?.();\n throw error;\n }\n};\n\n/**\n * Save a file through a plain anchor click, letting the browser download it.\n *\n * Fallback for browsers without the File System Access API (Safari, Firefox).\n * Note the `download` attribute is ignored cross-origin, and the CDN does not\n * send `Content-Disposition: attachment`, so these browsers may open the asset\n * in a tab rather than save it. Fixing that properly means setting that header\n * on the CDN — it cannot be forced from the client.\n *\n * The browser streams the response to its own downloads folder, so memory is\n * not a concern — but it\n * cannot report progress, and firing several in a row is unreliable, which is\n * why the caller spaces them out.\n *\n * @param url - URL to download\n * @param filename - Suggested filename\n */\nconst triggerBrowserDownload = (url: string, filename: string): void => {\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.rel = 'noopener noreferrer';\n\n document.body.appendChild(link);\n link.click();\n link.remove();\n};\n\n/**\n * DownloadButton component for downloading lesson content\n *\n * Downloads every asset of a lesson (video, podcast and board frames), matching\n * the mobile app's \"baixar aula completa\". Where the browser supports it, the\n * user picks a folder and each file is streamed straight to disk with real\n * progress; elsewhere the browser downloads them one by one.\n *\n * @param props - DownloadButton component props\n * @returns Download button element\n */\nconst DownloadButton = ({\n content,\n className,\n onDownloadStart,\n onDownloadComplete,\n onDownloadError,\n lessonTitle = 'aula',\n disabled = false,\n}: DownloadButtonProps) => {\n const [isDownloading, setIsDownloading] = useState(false);\n const [progress, setProgress] = useState(0);\n\n /**\n * Check if URL is valid and not empty\n * @param url - URL to validate\n * @returns Whether URL is valid\n */\n const isValidUrl = useCallback((url?: string): boolean => {\n return Boolean(\n url && url.trim() !== '' && url !== 'undefined' && url !== 'null'\n );\n }, []);\n\n /**\n * Get available download content\n * @returns Array of available download items\n */\n const getAvailableContent = useCallback((): DownloadItem[] => {\n const downloads: DownloadItem[] = [];\n\n if (isValidUrl(content.urlVideo)) {\n downloads.push({ type: 'video', url: content.urlVideo!, label: 'Vídeo' });\n }\n\n if (isValidUrl(content.urlPodcast)) {\n downloads.push({\n type: 'podcast',\n url: content.urlPodcast!,\n label: 'Podcast',\n });\n }\n\n if (isValidUrl(content.urlInitialFrame)) {\n downloads.push({\n type: 'quadro-inicial',\n url: content.urlInitialFrame!,\n label: 'Quadro Inicial',\n });\n }\n\n if (isValidUrl(content.urlFinalFrame)) {\n downloads.push({\n type: 'quadro-final',\n url: content.urlFinalFrame!,\n label: 'Quadro Final',\n });\n }\n\n return downloads;\n }, [content, isValidUrl]);\n\n /**\n * Download every asset by streaming it into the folder the user picked.\n *\n * @param items - Assets to download\n * @param dirHandle - Directory the user granted write access to\n */\n const downloadToFolder = useCallback(\n async (items: DownloadItem[], dirHandle: FileSystemDirectoryHandleLike) => {\n const sizes = await Promise.all(\n items.map((item) => getRemoteFileSize(item.url))\n );\n const totalBytes = sizes.reduce((sum, size) => sum + size, 0);\n // No content-length anywhere: weight each file equally instead of by bytes.\n const weighByFile = totalBytes === 0;\n\n let downloadedBytes = 0;\n let succeeded = 0;\n\n for (const [index, item] of items.entries()) {\n try {\n onDownloadStart?.(item.type);\n\n await streamToDisk(\n item.url,\n dirHandle,\n generateFilename(item.type, item.url, lessonTitle),\n (chunkSize) => {\n downloadedBytes += chunkSize;\n if (!weighByFile) {\n setProgress(\n Math.min(99, Math.round((downloadedBytes / totalBytes) * 100))\n );\n }\n }\n );\n\n succeeded++;\n onDownloadComplete?.(item.type);\n } catch (error) {\n onDownloadError?.(\n item.type,\n error instanceof Error\n ? error\n : new Error(`Falha ao baixar ${item.label}`)\n );\n } finally {\n if (weighByFile) {\n setProgress(\n Math.min(99, Math.round(((index + 1) / items.length) * 100))\n );\n }\n }\n }\n\n if (succeeded === 0) {\n throw new Error('Nenhum conteúdo da aula pôde ser baixado');\n }\n\n setProgress(100);\n },\n [lessonTitle, onDownloadStart, onDownloadComplete, onDownloadError]\n );\n\n /**\n * Hand each asset to the browser's own downloader, one at a time.\n *\n * Used where the File System Access API is missing. Downloads are spaced out\n * because browsers throttle several programmatic downloads fired at once.\n *\n * @param items - Assets to download\n */\n const downloadViaBrowser = useCallback(\n async (items: DownloadItem[]) => {\n for (const [index, item] of items.entries()) {\n onDownloadStart?.(item.type);\n\n triggerBrowserDownload(\n item.url,\n generateFilename(item.type, item.url, lessonTitle)\n );\n\n onDownloadComplete?.(item.type);\n setProgress(Math.round(((index + 1) / items.length) * 100));\n\n if (index < items.length - 1) {\n await new Promise((resolve) => setTimeout(resolve, 800));\n }\n }\n },\n [lessonTitle, onDownloadStart, onDownloadComplete]\n );\n\n /**\n * Download every asset of the lesson.\n *\n * Prefers streaming to a user-picked folder, which is the only approach that\n * survives a large lesson video. Falls back to the browser's downloader when\n * the File System Access API is unavailable.\n */\n const handleDownload = useCallback(async () => {\n if (disabled || isDownloading) return;\n\n const availableContent = getAvailableContent();\n if (availableContent.length === 0) return;\n\n let dirHandle: FileSystemDirectoryHandleLike | null = null;\n\n if (supportsDirectoryPicker()) {\n try {\n const picker = (globalThis as { showDirectoryPicker?: DirectoryPicker })\n .showDirectoryPicker!;\n dirHandle = await picker({ mode: 'readwrite', id: 'aulas' });\n } catch {\n // The user dismissed the folder picker: abort quietly, nothing to report.\n return;\n }\n }\n\n setIsDownloading(true);\n setProgress(0);\n\n try {\n if (dirHandle) {\n await downloadToFolder(availableContent, dirHandle);\n } else {\n await downloadViaBrowser(availableContent);\n }\n } catch (error) {\n onDownloadError?.(\n 'aula',\n error instanceof Error\n ? error\n : new Error('Falha ao baixar o conteúdo da aula')\n );\n } finally {\n setIsDownloading(false);\n setProgress(0);\n }\n }, [\n disabled,\n isDownloading,\n getAvailableContent,\n downloadToFolder,\n downloadViaBrowser,\n onDownloadError,\n ]);\n\n // Don't render if no content is available\n const availableCount = getAvailableContent().length;\n\n if (availableCount === 0) {\n return null;\n }\n\n const suffix = availableCount > 1 ? 's' : '';\n\n return (\n <div className={cn('flex items-center', className)}>\n <IconButton\n icon={<DownloadSimpleIcon size={24} />}\n onClick={handleDownload}\n disabled={disabled || isDownloading}\n aria-label={\n isDownloading\n ? 'Baixando conteúdo...'\n : `Baixar conteúdo da aula (${availableCount} arquivo${suffix})`\n }\n className={cn(\n '!bg-transparent hover:!bg-black/10 transition-colors',\n isDownloading && 'opacity-60 cursor-not-allowed'\n )}\n />\n\n <ProgressModal\n isOpen={isDownloading}\n onClose={() => {}}\n message=\"Baixando conteúdo da aula...\"\n progress={progress}\n />\n </div>\n );\n};\n\nexport default DownloadButton;\n"]}
@@ -17,7 +17,7 @@ var _chunkBJMKBBN3js = require('./chunk-BJMKBBN3.js');
17
17
  var _chunkWWXDXIV7js = require('./chunk-WWXDXIV7.js');
18
18
 
19
19
 
20
- var _chunkG4NK66PMjs = require('./chunk-G4NK66PM.js');
20
+ var _chunkJTWXQ267js = require('./chunk-JTWXQ267.js');
21
21
 
22
22
 
23
23
  var _chunkXN2HPVVHjs = require('./chunk-XN2HPVVH.js');
@@ -136,7 +136,7 @@ var TicketModal = ({
136
136
  }, [isOpen, fetchAnswers]);
137
137
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
138
138
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
139
- _chunkG4NK66PMjs.Modal_default,
139
+ _chunkJTWXQ267js.Modal_default,
140
140
  {
141
141
  isOpen,
142
142
  onClose,
@@ -392,7 +392,7 @@ var TicketModal = ({
392
392
  }
393
393
  ),
394
394
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
395
- _chunkG4NK66PMjs.Modal_default,
395
+ _chunkJTWXQ267js.Modal_default,
396
396
  {
397
397
  isOpen: showCloseConfirmation,
398
398
  onClose: () => setShowCloseConfirmation(false),
@@ -434,4 +434,4 @@ var TicketModal = ({
434
434
 
435
435
 
436
436
  exports.getCategoryIcon = getCategoryIcon; exports.TicketModal = TicketModal;
437
- //# sourceMappingURL=chunk-3IM2SBPO.js.map
437
+ //# sourceMappingURL=chunk-F5K3HMKT.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-3IM2SBPO.js","../src/components/Support/components/TicketModal.tsx","../src/components/Support/utils/supportUtils.tsx"],"names":["jsx"],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-3IM2SBPO.js","sourcesContent":[null,"import { useState, useEffect, useCallback } from 'react';\nimport dayjs from 'dayjs';\nimport 'dayjs/locale/pt-br';\nimport Badge from '../../Badge/Badge';\nimport Button from '../../Button/Button';\nimport Divider from '../../Divider/Divider';\nimport Modal from '../../Modal/Modal';\nimport Text from '../../Text/Text';\nimport TextArea from '../../TextArea/TextArea';\nimport { SkeletonText } from '../../Skeleton/Skeleton';\nimport {\n SupportTicket,\n SupportStatus,\n SupportAnswerAPI,\n GetSupportAnswersResponse,\n SubmitSupportAnswerRequest,\n SubmitSupportAnswerResponse,\n getStatusBadgeAction,\n getStatusText,\n getCategoryText,\n SupportApiClient,\n} from '../../../types/support';\nimport { getCategoryIcon } from '../utils/supportUtils';\n\ndayjs.locale('pt-br');\n\n// Skeleton component for answer loading\nconst AnswerSkeleton = () => (\n <div className=\"bg-background p-4 space-y-6 rounded-xl\">\n {/* Date skeleton */}\n <div className=\"flex items-center space-x-6\">\n <SkeletonText width=\"80px\" height={16} />\n <SkeletonText width=\"200px\" height={16} />\n </div>\n\n <Divider />\n\n {/* Answer content skeleton */}\n <div className=\"flex items-start space-x-6\">\n <SkeletonText width=\"80px\" height={16} />\n <div className=\"flex-1 space-y-2\">\n <SkeletonText width=\"100%\" height={16} />\n <SkeletonText width=\"80%\" height={16} />\n <SkeletonText width=\"60%\" height={16} />\n </div>\n </div>\n </div>\n);\n\nexport interface TicketModalProps {\n ticket: SupportTicket;\n isOpen: boolean;\n onClose: () => void;\n onTicketClose?: (ticketId: string) => void;\n /** API client instance for making requests */\n apiClient: SupportApiClient;\n /** Current user ID */\n userId?: string;\n}\n\nexport const TicketModal = ({\n ticket,\n isOpen,\n onClose,\n onTicketClose,\n apiClient,\n userId,\n}: TicketModalProps) => {\n const [showCloseConfirmation, setShowCloseConfirmation] = useState(false);\n const [responseText, setResponseText] = useState('');\n const [answers, setAnswers] = useState<SupportAnswerAPI[]>([]);\n const [isSubmittingAnswer, setIsSubmittingAnswer] = useState(false);\n const [isLoadingAnswers, setIsLoadingAnswers] = useState(false);\n\n const handleCloseTicket = () => {\n onTicketClose?.(ticket.id);\n setShowCloseConfirmation(false);\n onClose();\n };\n\n // Fetch support answers\n const fetchAnswers = useCallback(async () => {\n if (!ticket.id || ticket.status !== SupportStatus.RESPONDIDO) return;\n\n setIsLoadingAnswers(true);\n try {\n const response = await apiClient.get<GetSupportAnswersResponse>(\n `/support/answer/${ticket.id}`\n );\n setAnswers(response.data.data || []);\n } catch (error) {\n console.error('Erro ao buscar respostas:', error);\n setAnswers([]);\n } finally {\n setIsLoadingAnswers(false);\n }\n }, [ticket.id, ticket.status, apiClient]);\n\n // Submit user answer\n const handleSubmitAnswer = async () => {\n if (!responseText.trim() || !userId || !ticket.id) {\n return;\n }\n\n setIsSubmittingAnswer(true);\n try {\n const requestData: SubmitSupportAnswerRequest = {\n userId: userId,\n supportId: ticket.id,\n answer: responseText.trim(),\n };\n\n await apiClient.post<SubmitSupportAnswerResponse>(\n '/support/answer',\n requestData\n );\n\n // Clear response text\n setResponseText('');\n\n // Refresh answers list\n await fetchAnswers();\n } catch (error) {\n console.error('Erro ao enviar resposta:', error);\n } finally {\n setIsSubmittingAnswer(false);\n }\n };\n\n const canCloseTicket = ticket.status !== SupportStatus.ENCERRADO;\n\n // Limpar o texto e carregar respostas quando o modal for aberto\n useEffect(() => {\n if (isOpen) {\n setResponseText('');\n (async () => {\n await fetchAnswers();\n })().catch((error) => {\n console.error('Erro ao carregar respostas:', error);\n });\n } else {\n setAnswers([]);\n }\n }, [isOpen, fetchAnswers]);\n\n return (\n <>\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={`Pedido: ${ticket.title}`}\n size=\"lg\"\n hideCloseButton={false}\n closeOnEscape={true}\n data-testid=\"ticket-modal\"\n >\n <div className=\"flex flex-col h-full max-h-[80vh]\">\n {/* Header com botão Encerrar Pedido */}\n <div className=\"flex justify-between items-center mb-3\">\n <Text size=\"md\" weight=\"bold\" className=\"text-text-950\">\n Detalhes\n </Text>\n {canCloseTicket && (\n <Button\n variant=\"outline\"\n size=\"small\"\n action=\"negative\"\n onClick={() => setShowCloseConfirmation(true)}\n >\n Encerrar Pedido\n </Button>\n )}\n </div>\n\n {/* Conteúdo com scroll */}\n <div className=\"flex-1 overflow-y-auto pr-2 space-y-6\">\n <div className=\"bg-background p-4 space-y-6 rounded-xl\">\n {/* ID */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n ID\n </Text>\n <Text size=\"md\" weight=\"normal\" className=\"text-text-600\">\n {ticket.id}\n </Text>\n </div>\n\n {/* Aberto em */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Aberto em\n </Text>\n <Text size=\"md\" weight=\"normal\" className=\"text-text-600\">\n {dayjs(ticket.createdAt).format('DD MMMM YYYY, [às] HH[h]')}\n </Text>\n </div>\n\n {/* Status */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Status\n </Text>\n <Badge\n variant=\"solid\"\n size=\"small\"\n action={getStatusBadgeAction(ticket.status)}\n className=\"w-fit\"\n >\n {getStatusText(ticket.status)}\n </Badge>\n </div>\n\n {/* Tipo */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Tipo\n </Text>\n <Badge\n variant=\"solid\"\n size=\"small\"\n action=\"muted\"\n className=\"w-fit\"\n >\n {getCategoryIcon(ticket.category)}\n {getCategoryText(ticket.category)}\n </Badge>\n </div>\n\n <Divider />\n\n {/* Descrição */}\n <div className=\"flex items-start space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Descrição\n </Text>\n {ticket.description && (\n <Text size=\"md\" weight=\"normal\" className=\"text-text-600\">\n {ticket.description}\n </Text>\n )}\n </div>\n </div>\n\n {/* Seção de resposta (quando há respostas do suporte ou carregando) */}\n {ticket.status === SupportStatus.RESPONDIDO && isLoadingAnswers && (\n <>\n <Text size=\"md\" weight=\"bold\" className=\"text-text-950 my-6\">\n Resposta de Suporte Técnico\n </Text>\n <AnswerSkeleton />\n </>\n )}\n\n {/* Seção de resposta (quando há respostas do suporte) */}\n {!isLoadingAnswers &&\n answers.some((answer) => answer.userId !== userId) && (\n <>\n <Text size=\"md\" weight=\"bold\" className=\"text-text-950 my-6\">\n Resposta de Suporte Técnico\n </Text>\n\n {answers\n .filter((answer) => answer.userId !== userId)\n .sort(\n (a, b) =>\n new Date(b.createdAt).getTime() -\n new Date(a.createdAt).getTime()\n )\n .slice(0, 1)\n .map((answer) => (\n <div\n key={answer.id}\n className=\"bg-background p-4 space-y-6 rounded-xl\"\n >\n {/* Recebido em */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Recebido\n </Text>\n <Text\n size=\"md\"\n weight=\"normal\"\n className=\"text-text-600\"\n >\n {dayjs(answer.createdAt).format(\n 'DD MMMM YYYY, [às] HH[h]'\n )}\n </Text>\n </div>\n\n <Divider />\n\n {/* Resposta */}\n <div className=\"flex items-start space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Resposta\n </Text>\n <Text\n size=\"md\"\n weight=\"normal\"\n className=\"text-text-600\"\n >\n {answer.answer}\n </Text>\n </div>\n </div>\n ))}\n </>\n )}\n\n {/* Seção de resposta do usuário */}\n {!isLoadingAnswers &&\n answers.some((answer) => answer.userId === userId) && (\n <>\n <Text size=\"md\" weight=\"bold\" className=\"text-text-950 my-6\">\n Resposta enviada\n </Text>\n\n {answers\n .filter((answer) => answer.userId === userId)\n .sort(\n (a, b) =>\n new Date(b.createdAt).getTime() -\n new Date(a.createdAt).getTime()\n )\n .slice(0, 1)\n .map((answer) => (\n <div\n key={answer.id}\n className=\"bg-background p-4 space-y-6 rounded-xl\"\n >\n {/* Enviada em */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Enviada\n </Text>\n <Text\n size=\"md\"\n weight=\"normal\"\n className=\"text-text-600\"\n >\n {dayjs(answer.createdAt).format(\n 'DD MMMM YYYY, [às] HH[h]'\n )}\n </Text>\n </div>\n\n <Divider />\n\n {/* Resposta */}\n <div className=\"flex items-start space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Resposta\n </Text>\n <Text\n size=\"md\"\n weight=\"normal\"\n className=\"text-text-600\"\n >\n {answer.answer}\n </Text>\n </div>\n </div>\n ))}\n </>\n )}\n\n {/* Seção Responder */}\n {!isLoadingAnswers &&\n answers.some((answer) => answer.userId !== userId) && (\n <>\n <Text size=\"lg\" weight=\"bold\" className=\"text-text-950 my-6\">\n Responder\n </Text>\n\n <div className=\"space-y-4\">\n <TextArea\n placeholder=\"Detalhe o problema aqui.\"\n rows={4}\n className=\"w-full\"\n value={responseText}\n onChange={(e) => setResponseText(e.target.value)}\n />\n\n {responseText.trim().length > 0 && (\n <div className=\"flex justify-end\">\n <Button\n variant=\"solid\"\n size=\"medium\"\n onClick={handleSubmitAnswer}\n disabled={isSubmittingAnswer}\n >\n {isSubmittingAnswer ? 'Enviando...' : 'Enviar'}\n </Button>\n </div>\n )}\n </div>\n </>\n )}\n </div>\n </div>\n </Modal>\n\n {/* Modal de confirmação de encerramento */}\n <Modal\n isOpen={showCloseConfirmation}\n onClose={() => setShowCloseConfirmation(false)}\n title=\"Encerrar pedido?\"\n size=\"md\"\n hideCloseButton={false}\n closeOnEscape={true}\n data-testid=\"close-ticket-modal\"\n >\n <div className=\"space-y-6\">\n <Text size=\"sm\" weight=\"normal\" className=\"text-text-700\">\n Ao encerrar este pedido, ele será fechado e não poderá mais ser\n atualizado.\n </Text>\n\n <div className=\"flex gap-3 justify-end\">\n <Button\n variant=\"outline\"\n size=\"medium\"\n onClick={() => setShowCloseConfirmation(false)}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n size=\"medium\"\n action=\"negative\"\n onClick={handleCloseTicket}\n >\n Encerrar\n </Button>\n </div>\n </div>\n </Modal>\n </>\n );\n};\n","import { KeyIcon, BugIcon, InfoIcon } from '@phosphor-icons/react';\nimport React from 'react';\nimport { SupportCategory } from '../../../types/support';\n\nexport const getCategoryIcon = (\n category: SupportCategory | null,\n size = 16\n): React.ReactNode => {\n if (!category) return null;\n switch (category) {\n case SupportCategory.ACESSO:\n return <KeyIcon size={size} />;\n case SupportCategory.TECNICO:\n return <BugIcon size={size} />;\n case SupportCategory.OUTROS:\n return <InfoIcon size={size} />;\n default:\n return <InfoIcon size={size} />;\n }\n};\n"]}
1
+ {"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-F5K3HMKT.js","../src/components/Support/components/TicketModal.tsx","../src/components/Support/utils/supportUtils.tsx"],"names":["jsx"],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-F5K3HMKT.js","sourcesContent":[null,"import { useState, useEffect, useCallback } from 'react';\nimport dayjs from 'dayjs';\nimport 'dayjs/locale/pt-br';\nimport Badge from '../../Badge/Badge';\nimport Button from '../../Button/Button';\nimport Divider from '../../Divider/Divider';\nimport Modal from '../../Modal/Modal';\nimport Text from '../../Text/Text';\nimport TextArea from '../../TextArea/TextArea';\nimport { SkeletonText } from '../../Skeleton/Skeleton';\nimport {\n SupportTicket,\n SupportStatus,\n SupportAnswerAPI,\n GetSupportAnswersResponse,\n SubmitSupportAnswerRequest,\n SubmitSupportAnswerResponse,\n getStatusBadgeAction,\n getStatusText,\n getCategoryText,\n SupportApiClient,\n} from '../../../types/support';\nimport { getCategoryIcon } from '../utils/supportUtils';\n\ndayjs.locale('pt-br');\n\n// Skeleton component for answer loading\nconst AnswerSkeleton = () => (\n <div className=\"bg-background p-4 space-y-6 rounded-xl\">\n {/* Date skeleton */}\n <div className=\"flex items-center space-x-6\">\n <SkeletonText width=\"80px\" height={16} />\n <SkeletonText width=\"200px\" height={16} />\n </div>\n\n <Divider />\n\n {/* Answer content skeleton */}\n <div className=\"flex items-start space-x-6\">\n <SkeletonText width=\"80px\" height={16} />\n <div className=\"flex-1 space-y-2\">\n <SkeletonText width=\"100%\" height={16} />\n <SkeletonText width=\"80%\" height={16} />\n <SkeletonText width=\"60%\" height={16} />\n </div>\n </div>\n </div>\n);\n\nexport interface TicketModalProps {\n ticket: SupportTicket;\n isOpen: boolean;\n onClose: () => void;\n onTicketClose?: (ticketId: string) => void;\n /** API client instance for making requests */\n apiClient: SupportApiClient;\n /** Current user ID */\n userId?: string;\n}\n\nexport const TicketModal = ({\n ticket,\n isOpen,\n onClose,\n onTicketClose,\n apiClient,\n userId,\n}: TicketModalProps) => {\n const [showCloseConfirmation, setShowCloseConfirmation] = useState(false);\n const [responseText, setResponseText] = useState('');\n const [answers, setAnswers] = useState<SupportAnswerAPI[]>([]);\n const [isSubmittingAnswer, setIsSubmittingAnswer] = useState(false);\n const [isLoadingAnswers, setIsLoadingAnswers] = useState(false);\n\n const handleCloseTicket = () => {\n onTicketClose?.(ticket.id);\n setShowCloseConfirmation(false);\n onClose();\n };\n\n // Fetch support answers\n const fetchAnswers = useCallback(async () => {\n if (!ticket.id || ticket.status !== SupportStatus.RESPONDIDO) return;\n\n setIsLoadingAnswers(true);\n try {\n const response = await apiClient.get<GetSupportAnswersResponse>(\n `/support/answer/${ticket.id}`\n );\n setAnswers(response.data.data || []);\n } catch (error) {\n console.error('Erro ao buscar respostas:', error);\n setAnswers([]);\n } finally {\n setIsLoadingAnswers(false);\n }\n }, [ticket.id, ticket.status, apiClient]);\n\n // Submit user answer\n const handleSubmitAnswer = async () => {\n if (!responseText.trim() || !userId || !ticket.id) {\n return;\n }\n\n setIsSubmittingAnswer(true);\n try {\n const requestData: SubmitSupportAnswerRequest = {\n userId: userId,\n supportId: ticket.id,\n answer: responseText.trim(),\n };\n\n await apiClient.post<SubmitSupportAnswerResponse>(\n '/support/answer',\n requestData\n );\n\n // Clear response text\n setResponseText('');\n\n // Refresh answers list\n await fetchAnswers();\n } catch (error) {\n console.error('Erro ao enviar resposta:', error);\n } finally {\n setIsSubmittingAnswer(false);\n }\n };\n\n const canCloseTicket = ticket.status !== SupportStatus.ENCERRADO;\n\n // Limpar o texto e carregar respostas quando o modal for aberto\n useEffect(() => {\n if (isOpen) {\n setResponseText('');\n (async () => {\n await fetchAnswers();\n })().catch((error) => {\n console.error('Erro ao carregar respostas:', error);\n });\n } else {\n setAnswers([]);\n }\n }, [isOpen, fetchAnswers]);\n\n return (\n <>\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={`Pedido: ${ticket.title}`}\n size=\"lg\"\n hideCloseButton={false}\n closeOnEscape={true}\n data-testid=\"ticket-modal\"\n >\n <div className=\"flex flex-col h-full max-h-[80vh]\">\n {/* Header com botão Encerrar Pedido */}\n <div className=\"flex justify-between items-center mb-3\">\n <Text size=\"md\" weight=\"bold\" className=\"text-text-950\">\n Detalhes\n </Text>\n {canCloseTicket && (\n <Button\n variant=\"outline\"\n size=\"small\"\n action=\"negative\"\n onClick={() => setShowCloseConfirmation(true)}\n >\n Encerrar Pedido\n </Button>\n )}\n </div>\n\n {/* Conteúdo com scroll */}\n <div className=\"flex-1 overflow-y-auto pr-2 space-y-6\">\n <div className=\"bg-background p-4 space-y-6 rounded-xl\">\n {/* ID */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n ID\n </Text>\n <Text size=\"md\" weight=\"normal\" className=\"text-text-600\">\n {ticket.id}\n </Text>\n </div>\n\n {/* Aberto em */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Aberto em\n </Text>\n <Text size=\"md\" weight=\"normal\" className=\"text-text-600\">\n {dayjs(ticket.createdAt).format('DD MMMM YYYY, [às] HH[h]')}\n </Text>\n </div>\n\n {/* Status */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Status\n </Text>\n <Badge\n variant=\"solid\"\n size=\"small\"\n action={getStatusBadgeAction(ticket.status)}\n className=\"w-fit\"\n >\n {getStatusText(ticket.status)}\n </Badge>\n </div>\n\n {/* Tipo */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Tipo\n </Text>\n <Badge\n variant=\"solid\"\n size=\"small\"\n action=\"muted\"\n className=\"w-fit\"\n >\n {getCategoryIcon(ticket.category)}\n {getCategoryText(ticket.category)}\n </Badge>\n </div>\n\n <Divider />\n\n {/* Descrição */}\n <div className=\"flex items-start space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Descrição\n </Text>\n {ticket.description && (\n <Text size=\"md\" weight=\"normal\" className=\"text-text-600\">\n {ticket.description}\n </Text>\n )}\n </div>\n </div>\n\n {/* Seção de resposta (quando há respostas do suporte ou carregando) */}\n {ticket.status === SupportStatus.RESPONDIDO && isLoadingAnswers && (\n <>\n <Text size=\"md\" weight=\"bold\" className=\"text-text-950 my-6\">\n Resposta de Suporte Técnico\n </Text>\n <AnswerSkeleton />\n </>\n )}\n\n {/* Seção de resposta (quando há respostas do suporte) */}\n {!isLoadingAnswers &&\n answers.some((answer) => answer.userId !== userId) && (\n <>\n <Text size=\"md\" weight=\"bold\" className=\"text-text-950 my-6\">\n Resposta de Suporte Técnico\n </Text>\n\n {answers\n .filter((answer) => answer.userId !== userId)\n .sort(\n (a, b) =>\n new Date(b.createdAt).getTime() -\n new Date(a.createdAt).getTime()\n )\n .slice(0, 1)\n .map((answer) => (\n <div\n key={answer.id}\n className=\"bg-background p-4 space-y-6 rounded-xl\"\n >\n {/* Recebido em */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Recebido\n </Text>\n <Text\n size=\"md\"\n weight=\"normal\"\n className=\"text-text-600\"\n >\n {dayjs(answer.createdAt).format(\n 'DD MMMM YYYY, [às] HH[h]'\n )}\n </Text>\n </div>\n\n <Divider />\n\n {/* Resposta */}\n <div className=\"flex items-start space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Resposta\n </Text>\n <Text\n size=\"md\"\n weight=\"normal\"\n className=\"text-text-600\"\n >\n {answer.answer}\n </Text>\n </div>\n </div>\n ))}\n </>\n )}\n\n {/* Seção de resposta do usuário */}\n {!isLoadingAnswers &&\n answers.some((answer) => answer.userId === userId) && (\n <>\n <Text size=\"md\" weight=\"bold\" className=\"text-text-950 my-6\">\n Resposta enviada\n </Text>\n\n {answers\n .filter((answer) => answer.userId === userId)\n .sort(\n (a, b) =>\n new Date(b.createdAt).getTime() -\n new Date(a.createdAt).getTime()\n )\n .slice(0, 1)\n .map((answer) => (\n <div\n key={answer.id}\n className=\"bg-background p-4 space-y-6 rounded-xl\"\n >\n {/* Enviada em */}\n <div className=\"flex items-center space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Enviada\n </Text>\n <Text\n size=\"md\"\n weight=\"normal\"\n className=\"text-text-600\"\n >\n {dayjs(answer.createdAt).format(\n 'DD MMMM YYYY, [às] HH[h]'\n )}\n </Text>\n </div>\n\n <Divider />\n\n {/* Resposta */}\n <div className=\"flex items-start space-x-6\">\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-700 w-20\"\n >\n Resposta\n </Text>\n <Text\n size=\"md\"\n weight=\"normal\"\n className=\"text-text-600\"\n >\n {answer.answer}\n </Text>\n </div>\n </div>\n ))}\n </>\n )}\n\n {/* Seção Responder */}\n {!isLoadingAnswers &&\n answers.some((answer) => answer.userId !== userId) && (\n <>\n <Text size=\"lg\" weight=\"bold\" className=\"text-text-950 my-6\">\n Responder\n </Text>\n\n <div className=\"space-y-4\">\n <TextArea\n placeholder=\"Detalhe o problema aqui.\"\n rows={4}\n className=\"w-full\"\n value={responseText}\n onChange={(e) => setResponseText(e.target.value)}\n />\n\n {responseText.trim().length > 0 && (\n <div className=\"flex justify-end\">\n <Button\n variant=\"solid\"\n size=\"medium\"\n onClick={handleSubmitAnswer}\n disabled={isSubmittingAnswer}\n >\n {isSubmittingAnswer ? 'Enviando...' : 'Enviar'}\n </Button>\n </div>\n )}\n </div>\n </>\n )}\n </div>\n </div>\n </Modal>\n\n {/* Modal de confirmação de encerramento */}\n <Modal\n isOpen={showCloseConfirmation}\n onClose={() => setShowCloseConfirmation(false)}\n title=\"Encerrar pedido?\"\n size=\"md\"\n hideCloseButton={false}\n closeOnEscape={true}\n data-testid=\"close-ticket-modal\"\n >\n <div className=\"space-y-6\">\n <Text size=\"sm\" weight=\"normal\" className=\"text-text-700\">\n Ao encerrar este pedido, ele será fechado e não poderá mais ser\n atualizado.\n </Text>\n\n <div className=\"flex gap-3 justify-end\">\n <Button\n variant=\"outline\"\n size=\"medium\"\n onClick={() => setShowCloseConfirmation(false)}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n size=\"medium\"\n action=\"negative\"\n onClick={handleCloseTicket}\n >\n Encerrar\n </Button>\n </div>\n </div>\n </Modal>\n </>\n );\n};\n","import { KeyIcon, BugIcon, InfoIcon } from '@phosphor-icons/react';\nimport React from 'react';\nimport { SupportCategory } from '../../../types/support';\n\nexport const getCategoryIcon = (\n category: SupportCategory | null,\n size = 16\n): React.ReactNode => {\n if (!category) return null;\n switch (category) {\n case SupportCategory.ACESSO:\n return <KeyIcon size={size} />;\n case SupportCategory.TECNICO:\n return <BugIcon size={size} />;\n case SupportCategory.OUTROS:\n return <InfoIcon size={size} />;\n default:\n return <InfoIcon size={size} />;\n }\n};\n"]}