analytica-frontend-lib 1.7.21 → 1.7.23

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 (384) hide show
  1. package/dist/AccessReportModal/index.js +3 -3
  2. package/dist/AccessReportModal/index.mjs +2 -2
  3. package/dist/ActivitiesHistory/index.js +49 -49
  4. package/dist/ActivitiesHistory/index.mjs +48 -48
  5. package/dist/ActivityCardQuestionBanks/index.js +49 -49
  6. package/dist/ActivityCardQuestionBanks/index.mjs +48 -48
  7. package/dist/ActivityCardQuestionPreview/index.js +49 -49
  8. package/dist/ActivityCardQuestionPreview/index.mjs +48 -48
  9. package/dist/ActivityCreate/ActivityCreateContent/index.js +49 -49
  10. package/dist/ActivityCreate/ActivityCreateContent/index.mjs +48 -48
  11. package/dist/ActivityCreate/index.js +49 -49
  12. package/dist/ActivityCreate/index.mjs +48 -48
  13. package/dist/ActivityDetails/index.js +49 -49
  14. package/dist/ActivityDetails/index.mjs +48 -48
  15. package/dist/ActivityFilters/index.js +49 -49
  16. package/dist/ActivityFilters/index.mjs +48 -48
  17. package/dist/ActivityPageLayout/index.js +49 -49
  18. package/dist/ActivityPageLayout/index.mjs +48 -48
  19. package/dist/ActivityPreview/index.js +49 -49
  20. package/dist/ActivityPreview/index.mjs +48 -48
  21. package/dist/AlertManager/index.js +49 -49
  22. package/dist/AlertManager/index.mjs +48 -48
  23. package/dist/AlertManagerView/index.js +3 -3
  24. package/dist/AlertManagerView/index.mjs +2 -2
  25. package/dist/AnnouncementModal/index.js +3 -3
  26. package/dist/AnnouncementModal/index.mjs +2 -2
  27. package/dist/AnnouncementsGate/index.js +4 -4
  28. package/dist/AnnouncementsGate/index.mjs +3 -3
  29. package/dist/AnswerKeyModal/index.js +3 -3
  30. package/dist/AnswerKeyModal/index.mjs +2 -2
  31. package/dist/AppHeader/index.js +6 -6
  32. package/dist/AppHeader/index.mjs +5 -5
  33. package/dist/CalendarCard/index.js +4 -4
  34. package/dist/CalendarCard/index.mjs +3 -3
  35. package/dist/Chat/index.js +3 -3
  36. package/dist/Chat/index.mjs +2 -2
  37. package/dist/CheckBox/index.d.ts.map +1 -1
  38. package/dist/CheckBox/index.js +2 -2
  39. package/dist/CheckBox/index.mjs +1 -1
  40. package/dist/CheckBoxGroup/index.js +49 -49
  41. package/dist/CheckBoxGroup/index.mjs +48 -48
  42. package/dist/ComparatorChart/ComparatorView/index.js +3 -3
  43. package/dist/ComparatorChart/ComparatorView/index.mjs +2 -2
  44. package/dist/CorrectActivityModal/index.js +7 -7
  45. package/dist/CorrectActivityModal/index.mjs +6 -6
  46. package/dist/DownloadButton/index.js +4 -4
  47. package/dist/DownloadButton/index.mjs +3 -3
  48. package/dist/DownloadModal/index.js +3 -3
  49. package/dist/DownloadModal/index.mjs +2 -2
  50. package/dist/DropdownMenu/index.js +3 -3
  51. package/dist/DropdownMenu/index.mjs +2 -2
  52. package/dist/EnemClassroomStartModal/index.d.ts.map +1 -1
  53. package/dist/EnemClassroomStartModal/index.js +7 -7
  54. package/dist/EnemClassroomStartModal/index.mjs +6 -6
  55. package/dist/EnemMoment/index.js +57 -57
  56. package/dist/EnemMoment/index.mjs +51 -51
  57. package/dist/EnemMomentStudentModal/index.js +50 -50
  58. package/dist/EnemMomentStudentModal/index.mjs +48 -48
  59. package/dist/ExamDetailsLayout/ExamDetailsPage/index.js +49 -49
  60. package/dist/ExamDetailsLayout/ExamDetailsPage/index.mjs +48 -48
  61. package/dist/ExamPageLayout/index.js +49 -49
  62. package/dist/ExamPageLayout/index.mjs +48 -48
  63. package/dist/Forum/index.js +5 -5
  64. package/dist/Forum/index.mjs +4 -4
  65. package/dist/KnowledgePerformanceCard/index.js +51 -51
  66. package/dist/KnowledgePerformanceCard/index.mjs +50 -50
  67. package/dist/LessonCardPreview/index.js +49 -49
  68. package/dist/LessonCardPreview/index.mjs +48 -48
  69. package/dist/LessonMediaSections/index.js +49 -49
  70. package/dist/LessonMediaSections/index.mjs +48 -48
  71. package/dist/LessonsCatalog/index.js +49 -49
  72. package/dist/LessonsCatalog/index.mjs +48 -48
  73. package/dist/Modal/index.d.ts.map +1 -1
  74. package/dist/Modal/index.js +2 -2
  75. package/dist/Modal/index.mjs +1 -1
  76. package/dist/MultiCheckSelect/index.js +5 -5
  77. package/dist/MultiCheckSelect/index.mjs +4 -4
  78. package/dist/MultiSearchSelect/index.js +3 -3
  79. package/dist/MultiSearchSelect/index.mjs +2 -2
  80. package/dist/MultipleChoice/index.js +3 -3
  81. package/dist/MultipleChoice/index.mjs +2 -2
  82. package/dist/NotificationCard/index.js +4 -4
  83. package/dist/NotificationCard/index.mjs +3 -3
  84. package/dist/PerformanceReportModal/index.js +3 -3
  85. package/dist/PerformanceReportModal/index.mjs +2 -2
  86. package/dist/PrintableUsersTable/index.js +49 -49
  87. package/dist/PrintableUsersTable/index.mjs +48 -48
  88. package/dist/ProgressModal/index.js +3 -3
  89. package/dist/ProgressModal/index.mjs +2 -2
  90. package/dist/QuestionsPerformanceCard/index.js +50 -50
  91. package/dist/QuestionsPerformanceCard/index.mjs +49 -49
  92. package/dist/Quiz/index.js +6 -6
  93. package/dist/Quiz/index.mjs +5 -5
  94. package/dist/RecommendedLessonCreate/index.js +49 -49
  95. package/dist/RecommendedLessonCreate/index.mjs +48 -48
  96. package/dist/RecommendedLessonDetails/index.js +7 -7
  97. package/dist/RecommendedLessonDetails/index.mjs +6 -6
  98. package/dist/RecommendedLessonsHistory/index.js +49 -49
  99. package/dist/RecommendedLessonsHistory/index.mjs +48 -48
  100. package/dist/ReportDetailModal/index.js +4 -4
  101. package/dist/ReportDetailModal/index.mjs +3 -3
  102. package/dist/RichEditor/index.js +5 -5
  103. package/dist/RichEditor/index.mjs +4 -4
  104. package/dist/{RichEditorCore-6MTYSSKS.mjs → RichEditorCore-2S5YUAOI.mjs} +5 -5
  105. package/dist/{RichEditorCore-KDARBEK4.js → RichEditorCore-N7A2445B.js} +16 -16
  106. package/dist/{RichEditorCore-KDARBEK4.js.map → RichEditorCore-N7A2445B.js.map} +1 -1
  107. package/dist/Search/index.js +4 -4
  108. package/dist/Search/index.mjs +3 -3
  109. package/dist/SendActivityModal/SendActivityModal.js +49 -49
  110. package/dist/SendActivityModal/SendActivityModal.mjs +48 -48
  111. package/dist/SendActivityModal/index.js +49 -49
  112. package/dist/SendActivityModal/index.mjs +48 -48
  113. package/dist/SendLessonModal/index.js +49 -49
  114. package/dist/SendLessonModal/index.mjs +48 -48
  115. package/dist/SimulatedPerformance/SimulatedPerformanceView/index.js +49 -49
  116. package/dist/SimulatedPerformance/SimulatedPerformanceView/index.mjs +48 -48
  117. package/dist/SimulatedPerformance/useSimulatedPerformance/index.js +5 -5
  118. package/dist/SimulatedPerformance/useSimulatedPerformance/index.mjs +4 -4
  119. package/dist/SimulatedStudentSimulationsModal/index.js +6 -6
  120. package/dist/SimulatedStudentSimulationsModal/index.mjs +5 -5
  121. package/dist/SimulationsPage/index.js +49 -49
  122. package/dist/SimulationsPage/index.mjs +48 -48
  123. package/dist/StudentLessonProgressModal/index.js +3 -3
  124. package/dist/StudentLessonProgressModal/index.mjs +2 -2
  125. package/dist/StudentPerformanceDetailsModal/index.js +5 -5
  126. package/dist/StudentPerformanceDetailsModal/index.mjs +4 -4
  127. package/dist/Support/TicketModal/index.js +3 -3
  128. package/dist/Support/TicketModal/index.mjs +2 -2
  129. package/dist/Support/index.js +4 -4
  130. package/dist/Support/index.mjs +3 -3
  131. package/dist/SupportChatComposer/index.js +3 -3
  132. package/dist/SupportChatComposer/index.mjs +2 -2
  133. package/dist/SupportChatEvent/index.js +3 -3
  134. package/dist/SupportChatEvent/index.mjs +2 -2
  135. package/dist/SupportChatMessage/index.js +3 -3
  136. package/dist/SupportChatMessage/index.mjs +2 -2
  137. package/dist/SupportChatWidget/index.js +3 -3
  138. package/dist/SupportChatWidget/index.mjs +2 -2
  139. package/dist/SupportConcludeModal/index.js +4 -4
  140. package/dist/SupportConcludeModal/index.mjs +3 -3
  141. package/dist/SupportConversationHeader/index.js +4 -4
  142. package/dist/SupportConversationHeader/index.mjs +3 -3
  143. package/dist/SupportConversationMessages/index.js +5 -5
  144. package/dist/SupportConversationMessages/index.mjs +4 -4
  145. package/dist/SupportTicketConversation/index.js +12 -12
  146. package/dist/SupportTicketConversation/index.mjs +11 -11
  147. package/dist/TableProvider/index.js +49 -49
  148. package/dist/TableProvider/index.mjs +48 -48
  149. package/dist/UnifiedDraftModelPage/index.js +49 -49
  150. package/dist/UnifiedDraftModelPage/index.mjs +48 -48
  151. package/dist/UnifiedHistoryPage/index.js +49 -49
  152. package/dist/UnifiedHistoryPage/index.mjs +48 -48
  153. package/dist/VideoPlayer/index.js +5 -5
  154. package/dist/VideoPlayer/index.mjs +4 -4
  155. package/dist/Whiteboard/index.js +3 -3
  156. package/dist/Whiteboard/index.mjs +2 -2
  157. package/dist/{chunk-B6QOBHZM.mjs → chunk-24BEZK43.mjs} +2 -2
  158. package/dist/{chunk-CYSODZGX.js → chunk-27Y6V3GM.js} +169 -66
  159. package/dist/chunk-27Y6V3GM.js.map +1 -0
  160. package/dist/{chunk-OQTXTDSK.mjs → chunk-2OJ3QSLU.mjs} +3 -3
  161. package/dist/{chunk-VDUO65VK.mjs → chunk-3EGJJDIM.mjs} +2 -2
  162. package/dist/{chunk-VDUO65VK.mjs.map → chunk-3EGJJDIM.mjs.map} +1 -1
  163. package/dist/{chunk-4OUBPEVS.mjs → chunk-3HKLGNUE.mjs} +3 -3
  164. package/dist/{chunk-YA7XLH7D.js → chunk-3MFACEZ2.js} +3 -3
  165. package/dist/{chunk-YA7XLH7D.js.map → chunk-3MFACEZ2.js.map} +1 -1
  166. package/dist/{chunk-IHBWJM4C.mjs → chunk-3Q7RJKUP.mjs} +2 -2
  167. package/dist/{chunk-PY6WD6SB.mjs → chunk-3WRB4WCD.mjs} +4 -4
  168. package/dist/{chunk-4RHCBMMP.js → chunk-46VHAL4S.js} +3 -3
  169. package/dist/{chunk-4RHCBMMP.js.map → chunk-46VHAL4S.js.map} +1 -1
  170. package/dist/{chunk-POT3ALY3.js → chunk-5DINXU6W.js} +1 -1
  171. package/dist/{chunk-POT3ALY3.js.map → chunk-5DINXU6W.js.map} +1 -1
  172. package/dist/{chunk-L52NFNFK.mjs → chunk-5VC4BK65.mjs} +3 -3
  173. package/dist/{chunk-B67RLIUM.js → chunk-72D7G6YQ.js} +3 -3
  174. package/dist/{chunk-B67RLIUM.js.map → chunk-72D7G6YQ.js.map} +1 -1
  175. package/dist/{chunk-C65DG2RI.mjs → chunk-7FSBWUOM.mjs} +2 -2
  176. package/dist/{chunk-QWMFWYII.js → chunk-7IZNLARX.js} +3 -3
  177. package/dist/{chunk-QWMFWYII.js.map → chunk-7IZNLARX.js.map} +1 -1
  178. package/dist/{chunk-ZCBT2BUZ.js → chunk-7RFHXFFV.js} +13 -13
  179. package/dist/{chunk-ZCBT2BUZ.js.map → chunk-7RFHXFFV.js.map} +1 -1
  180. package/dist/{chunk-EMWX6IKP.js → chunk-7VJP5D26.js} +13 -13
  181. package/dist/{chunk-EMWX6IKP.js.map → chunk-7VJP5D26.js.map} +1 -1
  182. package/dist/{chunk-HCQJR5CE.mjs → chunk-7ZWEBNFB.mjs} +2 -2
  183. package/dist/{chunk-3RHNJUXU.mjs → chunk-ACSEJOW6.mjs} +2 -2
  184. package/dist/{chunk-WQZHUW7C.mjs → chunk-ANFHLSDB.mjs} +3 -3
  185. package/dist/{chunk-H6NQOLQY.mjs → chunk-ANFLWCVD.mjs} +2 -2
  186. package/dist/{chunk-BKBDQXZX.js → chunk-AOYPUZRO.js} +3 -3
  187. package/dist/{chunk-BKBDQXZX.js.map → chunk-AOYPUZRO.js.map} +1 -1
  188. package/dist/{chunk-5WS6IENQ.mjs → chunk-AU2HLQDJ.mjs} +2 -2
  189. package/dist/{chunk-P6FX3NT6.mjs → chunk-AZGDHAP5.mjs} +2 -2
  190. package/dist/{chunk-NCGO7FPB.js → chunk-AZKNYREH.js} +8 -8
  191. package/dist/{chunk-NCGO7FPB.js.map → chunk-AZKNYREH.js.map} +1 -1
  192. package/dist/{chunk-R6MTPYYW.js → chunk-AZTBNERQ.js} +3 -3
  193. package/dist/{chunk-R6MTPYYW.js.map → chunk-AZTBNERQ.js.map} +1 -1
  194. package/dist/{chunk-NPB2JTYC.mjs → chunk-BO3QVQ37.mjs} +4 -4
  195. package/dist/{chunk-2WI4Q2I2.mjs → chunk-BPMWRFSI.mjs} +4 -4
  196. package/dist/{chunk-TEW33GLR.mjs → chunk-BXN3VO6I.mjs} +2 -2
  197. package/dist/{chunk-7ZB3YHF2.mjs → chunk-C6LC5LD5.mjs} +1 -1
  198. package/dist/{chunk-7ZB3YHF2.mjs.map → chunk-C6LC5LD5.mjs.map} +1 -1
  199. package/dist/{chunk-5HONWYQA.js → chunk-C7ILTLT5.js} +3 -3
  200. package/dist/{chunk-5HONWYQA.js.map → chunk-C7ILTLT5.js.map} +1 -1
  201. package/dist/{chunk-OES54VU6.mjs → chunk-CFV2OZ3P.mjs} +116 -13
  202. package/dist/chunk-CFV2OZ3P.mjs.map +1 -0
  203. package/dist/{chunk-4OVIHZ3I.js → chunk-CGXWWPEA.js} +6 -6
  204. package/dist/{chunk-4OVIHZ3I.js.map → chunk-CGXWWPEA.js.map} +1 -1
  205. package/dist/{chunk-MNU45FM3.js → chunk-COT4KW3H.js} +2 -2
  206. package/dist/{chunk-MNU45FM3.js.map → chunk-COT4KW3H.js.map} +1 -1
  207. package/dist/{chunk-JDQUXG75.js → chunk-CVDNCU6L.js} +3 -3
  208. package/dist/{chunk-JDQUXG75.js.map → chunk-CVDNCU6L.js.map} +1 -1
  209. package/dist/{chunk-HBZHWSMZ.mjs → chunk-D46PJSQ7.mjs} +13 -13
  210. package/dist/{chunk-ARYIJ4RU.js → chunk-DDORKDQO.js} +3 -3
  211. package/dist/{chunk-ARYIJ4RU.js.map → chunk-DDORKDQO.js.map} +1 -1
  212. package/dist/{chunk-7YQTDJFA.js → chunk-DKXSR2V3.js} +3 -3
  213. package/dist/{chunk-7YQTDJFA.js.map → chunk-DKXSR2V3.js.map} +1 -1
  214. package/dist/{chunk-I6EAPPBL.mjs → chunk-DZMYIOKZ.mjs} +5 -5
  215. package/dist/{chunk-SKM7NFPY.js → chunk-EPXAFJVW.js} +6 -6
  216. package/dist/{chunk-SKM7NFPY.js.map → chunk-EPXAFJVW.js.map} +1 -1
  217. package/dist/{chunk-AYYMS23L.js → chunk-ESIQ2GB4.js} +7 -7
  218. package/dist/{chunk-AYYMS23L.js.map → chunk-ESIQ2GB4.js.map} +1 -1
  219. package/dist/{chunk-NU2WNYOD.js → chunk-EW7HGUFV.js} +87 -87
  220. package/dist/{chunk-NU2WNYOD.js.map → chunk-EW7HGUFV.js.map} +1 -1
  221. package/dist/{chunk-I4QGQMXI.mjs → chunk-EXYXZFNK.mjs} +2 -2
  222. package/dist/{chunk-RBJAO57A.js → chunk-FAAR4XC5.js} +3 -3
  223. package/dist/{chunk-RBJAO57A.js.map → chunk-FAAR4XC5.js.map} +1 -1
  224. package/dist/{chunk-N2VNE3ON.js → chunk-FDTDJDZI.js} +13 -13
  225. package/dist/{chunk-N2VNE3ON.js.map → chunk-FDTDJDZI.js.map} +1 -1
  226. package/dist/{chunk-SU5Q64TW.mjs → chunk-FVCTKS33.mjs} +6 -5
  227. package/dist/chunk-FVCTKS33.mjs.map +1 -0
  228. package/dist/{chunk-AVHZHWI3.js → chunk-GBIFSFWJ.js} +15 -15
  229. package/dist/{chunk-AVHZHWI3.js.map → chunk-GBIFSFWJ.js.map} +1 -1
  230. package/dist/{chunk-KSUPPAKH.js → chunk-GIQSHTB5.js} +9 -9
  231. package/dist/{chunk-KSUPPAKH.js.map → chunk-GIQSHTB5.js.map} +1 -1
  232. package/dist/{chunk-4QBKD4JN.js → chunk-GUUJYGXF.js} +3 -3
  233. package/dist/{chunk-4QBKD4JN.js.map → chunk-GUUJYGXF.js.map} +1 -1
  234. package/dist/{chunk-M4O46VDY.mjs → chunk-GX2PKLN2.mjs} +2 -2
  235. package/dist/{chunk-5BUTINIM.mjs → chunk-HLVLSWKD.mjs} +3 -3
  236. package/dist/{chunk-FU23WOTY.js → chunk-HSV5VZ4Z.js} +6 -6
  237. package/dist/{chunk-FU23WOTY.js.map → chunk-HSV5VZ4Z.js.map} +1 -1
  238. package/dist/{chunk-MMS2ELDK.mjs → chunk-IIQCS3A2.mjs} +2 -2
  239. package/dist/{chunk-NKWLCZUZ.mjs → chunk-JGGUMHM6.mjs} +2 -2
  240. package/dist/{chunk-HT2GREFH.js → chunk-JLD46DL7.js} +11 -11
  241. package/dist/{chunk-HT2GREFH.js.map → chunk-JLD46DL7.js.map} +1 -1
  242. package/dist/{chunk-NVL5TKWD.mjs → chunk-JYFLOQYT.mjs} +2 -2
  243. package/dist/{chunk-DWGDEUEW.mjs → chunk-KG563P7F.mjs} +5 -5
  244. package/dist/{chunk-TCIC5556.mjs → chunk-KH4TEDGD.mjs} +2 -2
  245. package/dist/{chunk-23PAYKWB.js → chunk-KM27ZDHZ.js} +2 -2
  246. package/dist/{chunk-23PAYKWB.js.map → chunk-KM27ZDHZ.js.map} +1 -1
  247. package/dist/{chunk-XZUMD3CB.mjs → chunk-LODDYDTP.mjs} +2 -2
  248. package/dist/{chunk-XZUMD3CB.mjs.map → chunk-LODDYDTP.mjs.map} +1 -1
  249. package/dist/{chunk-E6CGJBID.mjs → chunk-LUHKMY56.mjs} +2 -2
  250. package/dist/{chunk-TVLEUNKE.mjs → chunk-LZP5VZCO.mjs} +2 -2
  251. package/dist/{chunk-EHNEBXS7.mjs → chunk-M6DXZ2FM.mjs} +2 -2
  252. package/dist/{chunk-B4C5DWAP.mjs → chunk-MMMJDO75.mjs} +2 -2
  253. package/dist/{chunk-AFCWMJQO.js → chunk-MOUPNP53.js} +3 -3
  254. package/dist/{chunk-AFCWMJQO.js.map → chunk-MOUPNP53.js.map} +1 -1
  255. package/dist/{chunk-36KFIZ43.js → chunk-MYPUZ6EG.js} +3 -3
  256. package/dist/{chunk-36KFIZ43.js.map → chunk-MYPUZ6EG.js.map} +1 -1
  257. package/dist/{chunk-6JHIKIPA.js → chunk-NUGLTWEA.js} +23 -23
  258. package/dist/{chunk-6JHIKIPA.js.map → chunk-NUGLTWEA.js.map} +1 -1
  259. package/dist/{chunk-KWXOYHYK.mjs → chunk-P7MORXSE.mjs} +2 -2
  260. package/dist/{chunk-YG4IZ5Q3.mjs → chunk-Q2OSEROT.mjs} +2 -2
  261. package/dist/{chunk-L5SXG6T6.mjs → chunk-QQKOHKO2.mjs} +3 -3
  262. package/dist/{chunk-SADSJ2MV.js → chunk-QVGUYPXO.js} +3 -3
  263. package/dist/{chunk-SADSJ2MV.js.map → chunk-QVGUYPXO.js.map} +1 -1
  264. package/dist/{chunk-K45PTE7F.mjs → chunk-RBKQXT73.mjs} +4 -4
  265. package/dist/{chunk-JZFISWTP.js → chunk-RIN2IN7E.js} +2 -2
  266. package/dist/{chunk-JZFISWTP.js.map → chunk-RIN2IN7E.js.map} +1 -1
  267. package/dist/{chunk-BXLAOYAG.mjs → chunk-RIUVPTG7.mjs} +2 -2
  268. package/dist/{chunk-QVB54LBS.mjs → chunk-RNZGX6MX.mjs} +3 -3
  269. package/dist/{chunk-VSVLIRO2.js → chunk-RXEU77VN.js} +15 -15
  270. package/dist/{chunk-VSVLIRO2.js.map → chunk-RXEU77VN.js.map} +1 -1
  271. package/dist/{chunk-ZRIYCU2V.js → chunk-S2BZPPAI.js} +5 -5
  272. package/dist/{chunk-ZRIYCU2V.js.map → chunk-S2BZPPAI.js.map} +1 -1
  273. package/dist/{chunk-MES2BP4T.mjs → chunk-SGL5IUCV.mjs} +2 -2
  274. package/dist/{chunk-7LS5UQCQ.mjs → chunk-STKUPDHG.mjs} +2 -2
  275. package/dist/{chunk-PPYCCT2K.js → chunk-SWDVSCQJ.js} +9 -8
  276. package/dist/chunk-SWDVSCQJ.js.map +1 -0
  277. package/dist/{chunk-JCA76TCX.mjs → chunk-SZKLJOTN.mjs} +2 -2
  278. package/dist/{chunk-F5WR6XZZ.js → chunk-T73HPYF2.js} +3 -3
  279. package/dist/{chunk-F5WR6XZZ.js.map → chunk-T73HPYF2.js.map} +1 -1
  280. package/dist/{chunk-ZB6HDDE4.js → chunk-TQO37PVW.js} +14 -14
  281. package/dist/{chunk-ZB6HDDE4.js.map → chunk-TQO37PVW.js.map} +1 -1
  282. package/dist/{chunk-VKQ5AJDT.mjs → chunk-UENZQF2Y.mjs} +2 -2
  283. package/dist/{chunk-DCG7EUBC.js → chunk-UWLW5YVB.js} +6 -6
  284. package/dist/{chunk-DCG7EUBC.js.map → chunk-UWLW5YVB.js.map} +1 -1
  285. package/dist/{chunk-37AJ2GVO.mjs → chunk-UXJIZDXQ.mjs} +2 -2
  286. package/dist/{chunk-PLLPFCN3.js → chunk-UXMDPRAI.js} +14 -14
  287. package/dist/{chunk-PLLPFCN3.js.map → chunk-UXMDPRAI.js.map} +1 -1
  288. package/dist/{chunk-7BOTKRY6.mjs → chunk-V55DG5B4.mjs} +2 -2
  289. package/dist/{chunk-YRTIDZTN.js → chunk-VHEDMUAW.js} +4 -4
  290. package/dist/{chunk-YRTIDZTN.js.map → chunk-VHEDMUAW.js.map} +1 -1
  291. package/dist/{chunk-4RD55E4R.js → chunk-VWLWSO4J.js} +3 -3
  292. package/dist/{chunk-4RD55E4R.js.map → chunk-VWLWSO4J.js.map} +1 -1
  293. package/dist/{chunk-VJQIKFMG.mjs → chunk-W3CWEZDB.mjs} +3 -3
  294. package/dist/{chunk-JM6SLU7D.js → chunk-W7NNH4VY.js} +6 -6
  295. package/dist/{chunk-JM6SLU7D.js.map → chunk-W7NNH4VY.js.map} +1 -1
  296. package/dist/{chunk-VQ7MSYIH.js → chunk-WUN5NHZE.js} +4 -4
  297. package/dist/{chunk-VQ7MSYIH.js.map → chunk-WUN5NHZE.js.map} +1 -1
  298. package/dist/{chunk-AAU7ABJN.js → chunk-WWTRSQ3X.js} +3 -3
  299. package/dist/{chunk-AAU7ABJN.js.map → chunk-WWTRSQ3X.js.map} +1 -1
  300. package/dist/{chunk-BR6D2TGF.js → chunk-WZOA2PVJ.js} +3 -3
  301. package/dist/{chunk-BR6D2TGF.js.map → chunk-WZOA2PVJ.js.map} +1 -1
  302. package/dist/{chunk-TZKR5Z4J.mjs → chunk-XJF2F36N.mjs} +2 -2
  303. package/dist/{chunk-P6ACVNQK.mjs → chunk-YD2XBEKO.mjs} +2 -2
  304. package/dist/{chunk-LMXWIPGR.js → chunk-YWPLHFAK.js} +3 -3
  305. package/dist/{chunk-LMXWIPGR.js.map → chunk-YWPLHFAK.js.map} +1 -1
  306. package/dist/{chunk-DCEWWHV5.mjs → chunk-Z3HGYPH7.mjs} +2 -2
  307. package/dist/{chunk-Q3PKW6TH.js → chunk-ZCV3HWI2.js} +6 -6
  308. package/dist/{chunk-Q3PKW6TH.js.map → chunk-ZCV3HWI2.js.map} +1 -1
  309. package/dist/{chunk-OSA3YVDZ.mjs → chunk-ZF46DCAC.mjs} +2 -2
  310. package/dist/{chunk-5T6IDXSB.js → chunk-ZO2GA23I.js} +3 -3
  311. package/dist/{chunk-5T6IDXSB.js.map → chunk-ZO2GA23I.js.map} +1 -1
  312. package/dist/{chunk-ZN3763VZ.js → chunk-ZQLW4EJB.js} +9 -9
  313. package/dist/{chunk-ZN3763VZ.js.map → chunk-ZQLW4EJB.js.map} +1 -1
  314. package/dist/{chunk-CM5R4SPF.js → chunk-ZQQJTO6T.js} +3 -3
  315. package/dist/{chunk-CM5R4SPF.js.map → chunk-ZQQJTO6T.js.map} +1 -1
  316. package/dist/{chunk-SEL4QDCO.js → chunk-ZSXSAE3D.js} +3 -3
  317. package/dist/{chunk-SEL4QDCO.js.map → chunk-ZSXSAE3D.js.map} +1 -1
  318. package/dist/components/SupportChatWidget/guestSupportChatAdapter.d.ts +6 -1
  319. package/dist/components/SupportChatWidget/guestSupportChatAdapter.d.ts.map +1 -1
  320. package/dist/hooks/useAppContent/index.js +49 -49
  321. package/dist/hooks/useAppContent/index.mjs +48 -48
  322. package/dist/hooks/useSupportChat.d.ts +2 -0
  323. package/dist/hooks/useSupportChat.d.ts.map +1 -1
  324. package/dist/index.js +49 -49
  325. package/dist/index.mjs +48 -48
  326. package/dist/types/supportChat/index.d.ts +14 -0
  327. package/dist/types/supportChat/index.d.ts.map +1 -1
  328. package/dist/types/supportChat/index.js +2 -2
  329. package/dist/types/supportChat/index.mjs +1 -1
  330. package/dist/types/supportChat.d.ts +14 -0
  331. package/dist/types/supportChat.d.ts.map +1 -1
  332. package/package.json +1 -1
  333. package/dist/chunk-CYSODZGX.js.map +0 -1
  334. package/dist/chunk-OES54VU6.mjs.map +0 -1
  335. package/dist/chunk-PPYCCT2K.js.map +0 -1
  336. package/dist/chunk-SU5Q64TW.mjs.map +0 -1
  337. /package/dist/{RichEditorCore-6MTYSSKS.mjs.map → RichEditorCore-2S5YUAOI.mjs.map} +0 -0
  338. /package/dist/{chunk-B6QOBHZM.mjs.map → chunk-24BEZK43.mjs.map} +0 -0
  339. /package/dist/{chunk-OQTXTDSK.mjs.map → chunk-2OJ3QSLU.mjs.map} +0 -0
  340. /package/dist/{chunk-4OUBPEVS.mjs.map → chunk-3HKLGNUE.mjs.map} +0 -0
  341. /package/dist/{chunk-IHBWJM4C.mjs.map → chunk-3Q7RJKUP.mjs.map} +0 -0
  342. /package/dist/{chunk-PY6WD6SB.mjs.map → chunk-3WRB4WCD.mjs.map} +0 -0
  343. /package/dist/{chunk-L52NFNFK.mjs.map → chunk-5VC4BK65.mjs.map} +0 -0
  344. /package/dist/{chunk-C65DG2RI.mjs.map → chunk-7FSBWUOM.mjs.map} +0 -0
  345. /package/dist/{chunk-HCQJR5CE.mjs.map → chunk-7ZWEBNFB.mjs.map} +0 -0
  346. /package/dist/{chunk-3RHNJUXU.mjs.map → chunk-ACSEJOW6.mjs.map} +0 -0
  347. /package/dist/{chunk-WQZHUW7C.mjs.map → chunk-ANFHLSDB.mjs.map} +0 -0
  348. /package/dist/{chunk-H6NQOLQY.mjs.map → chunk-ANFLWCVD.mjs.map} +0 -0
  349. /package/dist/{chunk-5WS6IENQ.mjs.map → chunk-AU2HLQDJ.mjs.map} +0 -0
  350. /package/dist/{chunk-P6FX3NT6.mjs.map → chunk-AZGDHAP5.mjs.map} +0 -0
  351. /package/dist/{chunk-NPB2JTYC.mjs.map → chunk-BO3QVQ37.mjs.map} +0 -0
  352. /package/dist/{chunk-2WI4Q2I2.mjs.map → chunk-BPMWRFSI.mjs.map} +0 -0
  353. /package/dist/{chunk-TEW33GLR.mjs.map → chunk-BXN3VO6I.mjs.map} +0 -0
  354. /package/dist/{chunk-HBZHWSMZ.mjs.map → chunk-D46PJSQ7.mjs.map} +0 -0
  355. /package/dist/{chunk-I6EAPPBL.mjs.map → chunk-DZMYIOKZ.mjs.map} +0 -0
  356. /package/dist/{chunk-I4QGQMXI.mjs.map → chunk-EXYXZFNK.mjs.map} +0 -0
  357. /package/dist/{chunk-M4O46VDY.mjs.map → chunk-GX2PKLN2.mjs.map} +0 -0
  358. /package/dist/{chunk-5BUTINIM.mjs.map → chunk-HLVLSWKD.mjs.map} +0 -0
  359. /package/dist/{chunk-MMS2ELDK.mjs.map → chunk-IIQCS3A2.mjs.map} +0 -0
  360. /package/dist/{chunk-NKWLCZUZ.mjs.map → chunk-JGGUMHM6.mjs.map} +0 -0
  361. /package/dist/{chunk-NVL5TKWD.mjs.map → chunk-JYFLOQYT.mjs.map} +0 -0
  362. /package/dist/{chunk-DWGDEUEW.mjs.map → chunk-KG563P7F.mjs.map} +0 -0
  363. /package/dist/{chunk-TCIC5556.mjs.map → chunk-KH4TEDGD.mjs.map} +0 -0
  364. /package/dist/{chunk-E6CGJBID.mjs.map → chunk-LUHKMY56.mjs.map} +0 -0
  365. /package/dist/{chunk-TVLEUNKE.mjs.map → chunk-LZP5VZCO.mjs.map} +0 -0
  366. /package/dist/{chunk-EHNEBXS7.mjs.map → chunk-M6DXZ2FM.mjs.map} +0 -0
  367. /package/dist/{chunk-B4C5DWAP.mjs.map → chunk-MMMJDO75.mjs.map} +0 -0
  368. /package/dist/{chunk-KWXOYHYK.mjs.map → chunk-P7MORXSE.mjs.map} +0 -0
  369. /package/dist/{chunk-YG4IZ5Q3.mjs.map → chunk-Q2OSEROT.mjs.map} +0 -0
  370. /package/dist/{chunk-L5SXG6T6.mjs.map → chunk-QQKOHKO2.mjs.map} +0 -0
  371. /package/dist/{chunk-K45PTE7F.mjs.map → chunk-RBKQXT73.mjs.map} +0 -0
  372. /package/dist/{chunk-BXLAOYAG.mjs.map → chunk-RIUVPTG7.mjs.map} +0 -0
  373. /package/dist/{chunk-QVB54LBS.mjs.map → chunk-RNZGX6MX.mjs.map} +0 -0
  374. /package/dist/{chunk-MES2BP4T.mjs.map → chunk-SGL5IUCV.mjs.map} +0 -0
  375. /package/dist/{chunk-7LS5UQCQ.mjs.map → chunk-STKUPDHG.mjs.map} +0 -0
  376. /package/dist/{chunk-JCA76TCX.mjs.map → chunk-SZKLJOTN.mjs.map} +0 -0
  377. /package/dist/{chunk-VKQ5AJDT.mjs.map → chunk-UENZQF2Y.mjs.map} +0 -0
  378. /package/dist/{chunk-37AJ2GVO.mjs.map → chunk-UXJIZDXQ.mjs.map} +0 -0
  379. /package/dist/{chunk-7BOTKRY6.mjs.map → chunk-V55DG5B4.mjs.map} +0 -0
  380. /package/dist/{chunk-VJQIKFMG.mjs.map → chunk-W3CWEZDB.mjs.map} +0 -0
  381. /package/dist/{chunk-TZKR5Z4J.mjs.map → chunk-XJF2F36N.mjs.map} +0 -0
  382. /package/dist/{chunk-P6ACVNQK.mjs.map → chunk-YD2XBEKO.mjs.map} +0 -0
  383. /package/dist/{chunk-DCEWWHV5.mjs.map → chunk-Z3HGYPH7.mjs.map} +0 -0
  384. /package/dist/{chunk-OSA3YVDZ.mjs.map → chunk-ZF46DCAC.mjs.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-N2VNE3ON.js","../src/components/Forum/Forum.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-N2VNE3ON.js","sourcesContent":[null,"import { useState, useEffect, useCallback } from 'react';\nimport {\n CaretLeftIcon,\n ChatCircleTextIcon,\n CheckIcon,\n DotsThreeVerticalIcon,\n ImageIcon,\n PencilSimpleIcon,\n TrashIcon,\n} from '@phosphor-icons/react';\nimport Text from '../Text/Text';\nimport Button from '../Button/Button';\nimport Input from '../Input/Input';\nimport TextArea from '../TextArea/TextArea';\nimport Modal from '../Modal/Modal';\nimport Radio from '../Radio/Radio';\nimport DropdownMenu, {\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n} from '../DropdownMenu/DropdownMenu';\nimport { RichEditor } from '../RichEditor/RichEditor';\nimport ImageUpload from '../ImageUpload/ImageUpload';\nimport { SkeletonList, SkeletonCard } from '../Skeleton/Skeleton';\nimport { stripHtml, sanitizeHtmlForDisplay } from '../HtmlMathRenderer';\nimport { cn } from '../../utils/utils';\nimport { getInitials } from '../../utils/getInitials';\nimport type { ForumApiClient, ForumTopic, ForumReply } from '../../types/forum';\nimport { PROFILE_ROLES } from '../../types/chat';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst MONTHS_PT = [\n 'Janeiro',\n 'Fevereiro',\n 'Março',\n 'Abril',\n 'Maio',\n 'Junho',\n 'Julho',\n 'Agosto',\n 'Setembro',\n 'Outubro',\n 'Novembro',\n 'Dezembro',\n];\n\nfunction formatForumDate(isoDate: string): string {\n const d = new Date(isoDate);\n const day = d.getDate();\n const month = MONTHS_PT[d.getMonth()];\n const year = d.getFullYear();\n const hours = d.getHours();\n const minutes = d.getMinutes().toString().padStart(2, '0');\n return `${day} ${month} ${year} • ${hours}:${minutes}`;\n}\n\nfunction formatReplyCount(count: number): string {\n if (count === 1) return '1 resposta';\n return `${count} respostas`;\n}\n\n// ---------------------------------------------------------------------------\n// Sub-components\n// ---------------------------------------------------------------------------\n\ninterface AuthorAvatarProps {\n readonly name: string;\n readonly photoUrl: string | null;\n}\n\nfunction AuthorAvatar({ name, photoUrl }: AuthorAvatarProps) {\n if (photoUrl) {\n return (\n <img\n src={photoUrl}\n alt={name}\n className=\"w-8 h-8 rounded-full object-cover shrink-0\"\n />\n );\n }\n return (\n <div className=\"w-8 h-8 rounded-full bg-primary-600 flex items-center justify-center shrink-0\">\n <Text size=\"xs\" weight=\"semibold\" color=\"text-white\">\n {getInitials(name)}\n </Text>\n </div>\n );\n}\n\ninterface AuthorMetaProps {\n readonly authorName: string;\n readonly authorPhoto: string | null;\n readonly createdAt: string;\n}\n\nfunction AuthorMeta({ authorName, authorPhoto, createdAt }: AuthorMetaProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <AuthorAvatar name={authorName} photoUrl={authorPhoto} />\n <div className=\"flex items-center gap-1\">\n <Text size=\"xs\" weight=\"semibold\" color=\"text-primary-700\">\n Postado por {authorName}\n </Text>\n <Text size=\"xs\" color=\"text-text-600\">\n • {formatForumDate(createdAt)}\n </Text>\n </div>\n </div>\n );\n}\n\ninterface PostActionsMenuProps {\n readonly onEdit: () => void;\n readonly onDelete: () => void;\n}\n\nfunction PostActionsMenu({ onEdit, onDelete }: PostActionsMenuProps) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-label=\"Abrir ações do post\"\n className=\"p-1 rounded hover:bg-background-100 transition-colors shrink-0\"\n >\n <DotsThreeVerticalIcon size={20} className=\"text-text-600\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n iconLeft={<PencilSimpleIcon size={16} />}\n onClick={onEdit}\n >\n Editar\n </DropdownMenuItem>\n <DropdownMenuItem iconLeft={<TrashIcon size={16} />} onClick={onDelete}>\n Deletar\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\ninterface PostContentModalProps {\n readonly isOpen: boolean;\n readonly title: string;\n readonly submitLabel: string;\n readonly content: string;\n readonly imageUrl: string | undefined;\n readonly isSubmitting: boolean;\n readonly onContentChange: (value: string) => void;\n readonly onClose: () => void;\n readonly onSubmit: () => void;\n readonly onUploadImage?: (file: File) => Promise<string>;\n readonly onImageUploaded: (url: string) => void;\n readonly maxLength: number;\n /** Use RichEditor with toolbar instead of plain TextArea */\n readonly richText?: boolean;\n /** Show \"Este fórum vale nota no boletim?\" question (professor only) */\n readonly showGradeQuestion?: boolean;\n readonly countsForGrade?: boolean;\n readonly onCountsForGradeChange?: (value: boolean) => void;\n}\n\nfunction PostContentModal({\n isOpen,\n title,\n submitLabel,\n content,\n imageUrl,\n isSubmitting,\n onContentChange,\n onClose,\n onSubmit,\n onUploadImage,\n onImageUploaded,\n maxLength,\n richText = false,\n showGradeQuestion = false,\n countsForGrade,\n onCountsForGradeChange,\n}: PostContentModalProps) {\n const handleImageSelect = useCallback(\n async (file: File) => {\n if (!onUploadImage) return;\n try {\n const url = await onUploadImage(file);\n onImageUploaded(url);\n } catch {\n // silently fail — consuming app should handle upload errors\n }\n },\n [onUploadImage, onImageUploaded]\n );\n\n // Determine if content is effectively empty or exceeds the limit\n const plainTextContent = richText ? stripHtml(content) : content;\n const isContentEmpty = !plainTextContent.trim();\n const exceedsMaxLength = plainTextContent.trim().length > maxLength;\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={title}\n size=\"md\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={onClose}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n disabled={isContentEmpty || exceedsMaxLength || isSubmitting}\n onClick={onSubmit}\n >\n {submitLabel}\n </Button>\n </div>\n }\n >\n <div className=\"flex flex-col gap-3\">\n {richText ? (\n // key forces remount (and thus reset) whenever the modal opens/closes\n <RichEditor\n key={String(isOpen)}\n content={content}\n onChange={(data) => onContentChange(data.html)}\n placeholder=\"Escreva o conteúdo do seu post aqui.\"\n />\n ) : (\n <TextArea\n placeholder=\"Escreva o conteúdo do seu post aqui.\"\n value={content}\n onChange={(e) => onContentChange(e.target.value)}\n autoResize\n minHeight={120}\n maxLength={maxLength}\n />\n )}\n\n <ImageUpload\n variant=\"compact\"\n onFileSelect={handleImageSelect}\n onRemoveFile={() => onImageUploaded('')}\n buttonIcon={<ImageIcon size={16} />}\n />\n {imageUrl && (\n <img\n src={imageUrl}\n alt=\"Preview da imagem\"\n className=\"max-h-40 rounded-lg object-contain\"\n />\n )}\n\n {showGradeQuestion && (\n <div className=\"flex flex-col gap-2\">\n <Text size=\"sm\" weight=\"medium\">\n Este fórum vale nota no boletim?\n </Text>\n <div className=\"flex items-center gap-4\">\n <Radio\n name=\"countsForGrade\"\n value=\"yes\"\n label=\"Sim\"\n size=\"small\"\n checked={countsForGrade === true}\n onChange={() => onCountsForGradeChange?.(true)}\n />\n <Radio\n name=\"countsForGrade\"\n value=\"no\"\n label=\"Não\"\n size=\"small\"\n checked={countsForGrade === false}\n onChange={() => onCountsForGradeChange?.(false)}\n />\n </div>\n </div>\n )}\n </div>\n </Modal>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Skeleton\n// ---------------------------------------------------------------------------\n\nfunction TopicListSkeleton() {\n return (\n <SkeletonList items={3} showAvatar showTitle showDescription lines={2} />\n );\n}\n\nfunction TopicDetailSkeleton() {\n return (\n <SkeletonCard\n showAvatar\n showTitle\n showDescription\n showActions={false}\n lines={2}\n />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component\n// ---------------------------------------------------------------------------\n\nexport type ForumProps = {\n /** API client with forum CRUD methods */\n readonly apiClient: ForumApiClient;\n /** Current user's userInstitutionId — used to identify own posts */\n readonly currentUserId: string;\n /** User role — enables professor-specific features (e.g. grade question on create) */\n readonly userRole?: PROFILE_ROLES.STUDENT | PROFILE_ROLES.TEACHER;\n /** Forum page title */\n readonly title?: string;\n /** Forum page subtitle */\n readonly subtitle?: string;\n /** Callback to upload an image file and return its hosted URL */\n readonly onUploadImage?: (file: File) => Promise<string>;\n /**\n * Callback to evaluate a reply (teacher only).\n * If provided, an \"Avaliar\" button appears on each reply when the topic counts for grade.\n */\n readonly onEvaluateReply?: (replyId: string, grade: number) => Promise<void>;\n /** Additional CSS classes */\n readonly className?: string;\n};\n\nexport function Forum({\n apiClient,\n currentUserId,\n userRole = PROFILE_ROLES.STUDENT,\n title = 'Fórum',\n subtitle = 'Espaço para troca de conhecimento',\n onUploadImage,\n onEvaluateReply,\n className,\n}: ForumProps) {\n const isTeacher = userRole === PROFILE_ROLES.TEACHER;\n const [view, setView] = useState<'list' | 'detail'>('list');\n const [topics, setTopics] = useState<ForumTopic[]>([]);\n const [isLoadingTopics, setIsLoadingTopics] = useState(false);\n const [selectedTopic, setSelectedTopic] = useState<ForumTopic | null>(null);\n const [replies, setReplies] = useState<ForumReply[]>([]);\n const [isLoadingTopic, setIsLoadingTopic] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n // Create post modal state\n const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);\n const [createContent, setCreateContent] = useState('');\n const [createImageUrl, setCreateImageUrl] = useState<string | undefined>();\n const [createCountsForGrade, setCreateCountsForGrade] = useState<\n boolean | undefined\n >();\n\n // Reply modal state\n const [isReplyModalOpen, setIsReplyModalOpen] = useState(false);\n const [replyContent, setReplyContent] = useState('');\n const [replyImageUrl, setReplyImageUrl] = useState<string | undefined>();\n\n // Edit topic modal state\n const [editingTopic, setEditingTopic] = useState<ForumTopic | null>(null);\n const [editTopicContent, setEditTopicContent] = useState('');\n const [editTopicImageUrl, setEditTopicImageUrl] = useState<\n string | undefined\n >();\n\n // Edit reply modal state\n const [editingReply, setEditingReply] = useState<ForumReply | null>(null);\n const [editReplyContent, setEditReplyContent] = useState('');\n const [editReplyImageUrl, setEditReplyImageUrl] = useState<\n string | undefined\n >();\n\n // Evaluate reply modal state (teacher only)\n const [evaluatingReplyId, setEvaluatingReplyId] = useState<string | null>(\n null\n );\n const [gradeValue, setGradeValue] = useState<number | null>(null);\n const [isEditingGrade, setIsEditingGrade] = useState(false);\n\n // Delete confirmation state\n const [pendingDelete, setPendingDelete] = useState<\n { type: 'topic'; id: string } | { type: 'reply'; id: string } | null\n >(null);\n\n const fetchTopics = useCallback(async () => {\n setIsLoadingTopics(true);\n try {\n const response = await apiClient.getTopics({ limit: 50 });\n setTopics(response.topics);\n } finally {\n setIsLoadingTopics(false);\n }\n }, [apiClient]);\n\n const fetchTopic = useCallback(\n async (topicId: string) => {\n setIsLoadingTopic(true);\n try {\n const response = await apiClient.getTopic(topicId);\n setSelectedTopic(response.topic);\n setReplies(response.replies);\n } finally {\n setIsLoadingTopic(false);\n }\n },\n [apiClient]\n );\n\n useEffect(() => {\n fetchTopics();\n }, [fetchTopics]);\n\n const handleTopicClick = useCallback(\n (topic: ForumTopic) => {\n setSelectedTopic(topic);\n setView('detail');\n fetchTopic(topic.id);\n },\n [fetchTopic]\n );\n\n const handleBack = useCallback(() => {\n setView('list');\n setSelectedTopic(null);\n setReplies([]);\n fetchTopics();\n }, [fetchTopics]);\n\n // Create topic\n const handleCloseCreateModal = useCallback(() => {\n setIsCreateModalOpen(false);\n setCreateContent('');\n setCreateImageUrl(undefined);\n setCreateCountsForGrade(undefined);\n }, []);\n\n const handleCreateTopic = useCallback(async () => {\n if (!createContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.createTopic({\n content: createContent.trim(),\n ...(createImageUrl && { imageUrl: createImageUrl }),\n ...(isTeacher &&\n createCountsForGrade !== undefined && {\n countsForGrade: createCountsForGrade,\n }),\n });\n handleCloseCreateModal();\n await fetchTopics();\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n createContent,\n createImageUrl,\n createCountsForGrade,\n isTeacher,\n handleCloseCreateModal,\n fetchTopics,\n ]);\n\n // Edit topic\n const handleOpenEditTopic = useCallback((topic: ForumTopic) => {\n setEditingTopic(topic);\n setEditTopicContent(topic.content);\n setEditTopicImageUrl(topic.imageUrl ?? undefined);\n }, []);\n\n const handleCloseEditTopic = useCallback(() => {\n setEditingTopic(null);\n setEditTopicContent('');\n setEditTopicImageUrl(undefined);\n }, []);\n\n const handleEditTopic = useCallback(async () => {\n if (!editingTopic || !editTopicContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.updateTopic(editingTopic.id, {\n content: editTopicContent.trim(),\n imageUrl: editTopicImageUrl ?? null,\n });\n handleCloseEditTopic();\n if (view === 'list') {\n await fetchTopics();\n } else {\n await fetchTopic(editingTopic.id);\n }\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n editingTopic,\n editTopicContent,\n editTopicImageUrl,\n handleCloseEditTopic,\n view,\n fetchTopics,\n fetchTopic,\n ]);\n\n const handleDeleteTopic = useCallback(\n async (topicId: string) => {\n setIsSubmitting(true);\n try {\n await apiClient.deleteTopic(topicId);\n if (view === 'detail') {\n handleBack();\n } else {\n await fetchTopics();\n }\n } finally {\n setIsSubmitting(false);\n setPendingDelete(null);\n }\n },\n [apiClient, view, handleBack, fetchTopics]\n );\n\n // Reply\n const handleCloseReplyModal = useCallback(() => {\n setIsReplyModalOpen(false);\n setReplyContent('');\n setReplyImageUrl(undefined);\n }, []);\n\n const handleCreateReply = useCallback(async () => {\n if (!selectedTopic || !replyContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.createReply(selectedTopic.id, {\n content: replyContent.trim(),\n ...(replyImageUrl && { imageUrl: replyImageUrl }),\n });\n handleCloseReplyModal();\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n selectedTopic,\n replyContent,\n replyImageUrl,\n handleCloseReplyModal,\n fetchTopic,\n ]);\n\n // Edit reply\n const handleOpenEditReply = useCallback((reply: ForumReply) => {\n setEditingReply(reply);\n setEditReplyContent(reply.content);\n setEditReplyImageUrl(reply.imageUrl ?? undefined);\n }, []);\n\n const handleCloseEditReply = useCallback(() => {\n setEditingReply(null);\n setEditReplyContent('');\n setEditReplyImageUrl(undefined);\n }, []);\n\n const handleEditReply = useCallback(async () => {\n if (!editingReply || !editReplyContent.trim() || !selectedTopic) return;\n setIsSubmitting(true);\n try {\n await apiClient.updateReply(editingReply.id, {\n content: editReplyContent.trim(),\n imageUrl: editReplyImageUrl ?? null,\n });\n handleCloseEditReply();\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n editingReply,\n editReplyContent,\n editReplyImageUrl,\n handleCloseEditReply,\n selectedTopic,\n fetchTopic,\n ]);\n\n const handleDeleteReply = useCallback(\n async (replyId: string) => {\n if (!selectedTopic) return;\n setIsSubmitting(true);\n try {\n await apiClient.deleteReply(replyId);\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n setPendingDelete(null);\n }\n },\n [apiClient, selectedTopic, fetchTopic]\n );\n\n const handleCloseEvaluateModal = useCallback(() => {\n setEvaluatingReplyId(null);\n setGradeValue(null);\n setIsEditingGrade(false);\n }, []);\n\n const handleOpenEvaluate = useCallback((reply: ForumReply) => {\n setEvaluatingReplyId(reply.id);\n setGradeValue(null);\n setIsEditingGrade(false);\n }, []);\n\n const handleOpenEditGrade = useCallback((reply: ForumReply) => {\n setEvaluatingReplyId(reply.id);\n setGradeValue(reply.grade ?? null);\n setIsEditingGrade(true);\n }, []);\n\n const isValidGrade =\n gradeValue !== null &&\n Number.isInteger(gradeValue) &&\n gradeValue >= 0 &&\n gradeValue <= 10;\n\n const handleSubmitEvaluation = useCallback(async () => {\n if (!evaluatingReplyId || !isValidGrade || !onEvaluateReply) return;\n setIsSubmitting(true);\n try {\n await onEvaluateReply(evaluatingReplyId, gradeValue);\n // Optimistically update grade in local state\n setReplies((prev) =>\n prev.map((r) =>\n r.id === evaluatingReplyId ? { ...r, grade: gradeValue } : r\n )\n );\n handleCloseEvaluateModal();\n } finally {\n setIsSubmitting(false);\n }\n }, [\n evaluatingReplyId,\n gradeValue,\n isValidGrade,\n onEvaluateReply,\n handleCloseEvaluateModal,\n ]);\n\n const handleConfirmDelete = useCallback(async () => {\n if (!pendingDelete) return;\n if (pendingDelete.type === 'topic') {\n await handleDeleteTopic(pendingDelete.id);\n } else {\n await handleDeleteReply(pendingDelete.id);\n }\n }, [pendingDelete, handleDeleteTopic, handleDeleteReply]);\n\n /* ---- Extracted render blocks (avoids nested ternaries — SonarQube) ---- */\n\n const topicListContent = (() => {\n if (isLoadingTopics) return <TopicListSkeleton />;\n\n if (topics.length === 0) {\n return (\n <div className=\"flex items-center justify-center py-16 border border-border-200 rounded-lg\">\n <Text size=\"md\" color=\"text-text-500\">\n Nenhum tópico ainda. Seja o primeiro a criar um post!\n </Text>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col gap-4\">\n {topics.map((topic) => (\n <div\n key={topic.id}\n className=\"flex items-start bg-white border border-border-100 rounded-lg pt-4 pr-2 pb-4 pl-2 shadow-sm\"\n >\n {/* Clickable content area */}\n <button\n type=\"button\"\n className=\"flex flex-col gap-3 flex-1 min-w-0 text-left hover:opacity-90 transition-opacity\"\n onClick={() => handleTopicClick(topic)}\n >\n <AuthorMeta\n authorName={topic.authorName}\n authorPhoto={topic.authorPhoto}\n createdAt={topic.createdAt}\n />\n <Text size=\"sm\" className=\"leading-normal line-clamp-3 ml-10\">\n {stripHtml(topic.content)}\n </Text>\n <div className=\"flex items-center gap-1 text-text-600 ml-10\">\n <ChatCircleTextIcon size={16} />\n <Text size=\"xs\">{formatReplyCount(topic.replyCount)}</Text>\n </div>\n </button>\n\n {/* Actions menu — only for own posts */}\n {topic.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditTopic(topic)}\n onDelete={() =>\n setPendingDelete({ type: 'topic', id: topic.id })\n }\n />\n )}\n </div>\n ))}\n </div>\n );\n })();\n\n const topicDetailContent = (() => {\n if (isLoadingTopic) return <TopicDetailSkeleton />;\n\n if (!selectedTopic) return null;\n\n return (\n <>\n {/* Original post */}\n <div className=\"flex items-start gap-2\">\n <div className=\"flex flex-col gap-3 flex-1 min-w-0\">\n <AuthorMeta\n authorName={selectedTopic.authorName}\n authorPhoto={selectedTopic.authorPhoto}\n createdAt={selectedTopic.createdAt}\n />\n <div\n className=\"text-sm text-text-950 leading-normal ml-10 prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtmlForDisplay(selectedTopic.content),\n }}\n />\n {selectedTopic.imageUrl && (\n <img\n src={selectedTopic.imageUrl}\n alt=\"Imagem do post\"\n className=\"ml-10 max-w-lg rounded-lg\"\n />\n )}\n </div>\n {selectedTopic.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditTopic(selectedTopic)}\n onDelete={() =>\n setPendingDelete({ type: 'topic', id: selectedTopic.id })\n }\n />\n )}\n </div>\n\n {/* Replies header */}\n <div className=\"flex items-center justify-between\">\n <Text size=\"sm\" color=\"text-text-600\">\n {formatReplyCount(selectedTopic.replyCount)}\n </Text>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n onClick={() => setIsReplyModalOpen(true)}\n >\n Responder\n </Button>\n </div>\n\n {/* Replies list */}\n {replies.length > 0 && (\n <div className=\"flex flex-col divide-y divide-border-200\">\n {replies.map((reply) => (\n <div key={reply.id} className=\"flex items-start gap-2 py-4\">\n <div className=\"flex flex-col gap-3 flex-1 min-w-0\">\n <AuthorMeta\n authorName={reply.authorName}\n authorPhoto={reply.authorPhoto}\n createdAt={reply.createdAt}\n />\n <div\n className=\"text-sm text-text-950 leading-normal ml-10 prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtmlForDisplay(reply.content),\n }}\n />\n {reply.imageUrl && (\n <img\n src={reply.imageUrl}\n alt=\"Imagem da resposta\"\n className=\"ml-10 max-w-lg rounded-lg\"\n />\n )}\n {isTeacher &&\n selectedTopic?.countsForGrade &&\n onEvaluateReply &&\n (reply.grade == null ? (\n /* Not yet graded — show Avaliar button */\n <button\n type=\"button\"\n className=\"flex items-center gap-1.5 text-text-600 text-sm hover:text-text-950 transition-colors w-fit ml-10\"\n onClick={() => handleOpenEvaluate(reply)}\n >\n <CheckIcon size={16} />\n Avaliar\n </button>\n ) : (\n /* Grade already set — teacher sees it with edit pencil */\n <div className=\"flex items-center gap-1.5 ml-10\">\n <Text size=\"sm\" color=\"text-text-600\">\n Nota {reply.grade}\n </Text>\n <button\n type=\"button\"\n className=\"text-text-600 hover:text-text-950 transition-colors\"\n onClick={() => handleOpenEditGrade(reply)}\n >\n <PencilSimpleIcon size={14} />\n </button>\n </div>\n ))}\n {!isTeacher &&\n reply.grade != null &&\n reply.userInstitutionId === currentUserId &&\n selectedTopic?.countsForGrade && (\n <Text size=\"sm\" color=\"text-text-600\" className=\"ml-10\">\n Nota {reply.grade}\n </Text>\n )}\n </div>\n {reply.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditReply(reply)}\n onDelete={() =>\n setPendingDelete({ type: 'reply', id: reply.id })\n }\n />\n )}\n </div>\n ))}\n </div>\n )}\n </>\n );\n })();\n\n return (\n <div className={cn('flex flex-col gap-4', className)}>\n {view === 'list' ? (\n <>\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <Text as=\"h1\" size=\"2xl\" weight=\"bold\" color=\"text-text-950\">\n {title}\n </Text>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n onClick={() => setIsCreateModalOpen(true)}\n >\n Criar post\n </Button>\n </div>\n\n {/* Subtitle + topic list */}\n <div className=\"flex flex-col gap-3\">\n <Text as=\"h2\" size=\"lg\" weight=\"semibold\" color=\"text-text-950\">\n {subtitle}\n </Text>\n\n {topicListContent}\n </div>\n </>\n ) : (\n /* Detail view */\n <>\n <button\n type=\"button\"\n className=\"flex items-center gap-2 hover:opacity-80 transition-opacity w-fit\"\n onClick={handleBack}\n >\n <CaretLeftIcon size={24} className=\"text-text-950\" />\n <Text size=\"2xl\" weight=\"bold\">\n Voltar\n </Text>\n </button>\n\n {topicDetailContent}\n </>\n )}\n\n {/* Create post modal */}\n <PostContentModal\n isOpen={isCreateModalOpen}\n title=\"Criar post\"\n submitLabel=\"Criar post\"\n content={createContent}\n imageUrl={createImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setCreateContent}\n onClose={handleCloseCreateModal}\n onSubmit={handleCreateTopic}\n onUploadImage={onUploadImage}\n onImageUploaded={setCreateImageUrl}\n maxLength={10000}\n richText\n showGradeQuestion={isTeacher}\n countsForGrade={createCountsForGrade}\n onCountsForGradeChange={setCreateCountsForGrade}\n />\n\n {/* Reply modal */}\n <PostContentModal\n isOpen={isReplyModalOpen}\n title=\"Responder\"\n submitLabel=\"Responder\"\n content={replyContent}\n imageUrl={replyImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setReplyContent}\n onClose={handleCloseReplyModal}\n onSubmit={handleCreateReply}\n onUploadImage={onUploadImage}\n onImageUploaded={setReplyImageUrl}\n maxLength={5000}\n richText\n />\n\n {/* Edit topic modal */}\n <PostContentModal\n isOpen={!!editingTopic}\n title=\"Editar\"\n submitLabel=\"Salvar\"\n content={editTopicContent}\n imageUrl={editTopicImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setEditTopicContent}\n onClose={handleCloseEditTopic}\n onSubmit={handleEditTopic}\n onUploadImage={onUploadImage}\n onImageUploaded={setEditTopicImageUrl}\n maxLength={10000}\n richText\n />\n\n {/* Edit reply modal */}\n <PostContentModal\n isOpen={!!editingReply}\n title=\"Editar\"\n submitLabel=\"Salvar\"\n content={editReplyContent}\n imageUrl={editReplyImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setEditReplyContent}\n onClose={handleCloseEditReply}\n onSubmit={handleEditReply}\n onUploadImage={onUploadImage}\n onImageUploaded={setEditReplyImageUrl}\n maxLength={5000}\n richText\n />\n\n {/* Evaluate / edit grade modal (teacher only) */}\n <Modal\n isOpen={!!evaluatingReplyId}\n onClose={handleCloseEvaluateModal}\n title={\n isEditingGrade\n ? 'Edite a nota da atividade'\n : 'Defina a nota da atividade'\n }\n size=\"md\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={handleCloseEvaluateModal}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n disabled={!isValidGrade || isSubmitting}\n onClick={handleSubmitEvaluation}\n >\n {isEditingGrade ? 'Salvar' : 'Avaliar'}\n </Button>\n </div>\n }\n >\n <Input\n type=\"number\"\n min={0}\n max={10}\n step={1}\n placeholder=\"Nota (0-10)\"\n value={gradeValue ?? ''}\n onChange={(e) => {\n const val = e.target.value;\n const parsed = Number(val);\n setGradeValue(val === '' || Number.isNaN(parsed) ? null : parsed);\n }}\n />\n </Modal>\n\n {/* Delete confirmation modal */}\n <Modal\n isOpen={!!pendingDelete}\n onClose={() => setPendingDelete(null)}\n title=\"Deseja deletar post?\"\n size=\"sm\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={() => setPendingDelete(null)}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"negative\"\n size=\"medium\"\n disabled={isSubmitting}\n onClick={handleConfirmDelete}\n >\n Deletar\n </Button>\n </div>\n }\n >\n <Text size=\"md\" color=\"text-text-600\">\n Essa ação é permanente e não poderá ser desfeita.\n </Text>\n </Modal>\n </div>\n );\n}\n\nexport default Forum;\n"]}
1
+ {"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-FDTDJDZI.js","../src/components/Forum/Forum.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-FDTDJDZI.js","sourcesContent":[null,"import { useState, useEffect, useCallback } from 'react';\nimport {\n CaretLeftIcon,\n ChatCircleTextIcon,\n CheckIcon,\n DotsThreeVerticalIcon,\n ImageIcon,\n PencilSimpleIcon,\n TrashIcon,\n} from '@phosphor-icons/react';\nimport Text from '../Text/Text';\nimport Button from '../Button/Button';\nimport Input from '../Input/Input';\nimport TextArea from '../TextArea/TextArea';\nimport Modal from '../Modal/Modal';\nimport Radio from '../Radio/Radio';\nimport DropdownMenu, {\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n} from '../DropdownMenu/DropdownMenu';\nimport { RichEditor } from '../RichEditor/RichEditor';\nimport ImageUpload from '../ImageUpload/ImageUpload';\nimport { SkeletonList, SkeletonCard } from '../Skeleton/Skeleton';\nimport { stripHtml, sanitizeHtmlForDisplay } from '../HtmlMathRenderer';\nimport { cn } from '../../utils/utils';\nimport { getInitials } from '../../utils/getInitials';\nimport type { ForumApiClient, ForumTopic, ForumReply } from '../../types/forum';\nimport { PROFILE_ROLES } from '../../types/chat';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst MONTHS_PT = [\n 'Janeiro',\n 'Fevereiro',\n 'Março',\n 'Abril',\n 'Maio',\n 'Junho',\n 'Julho',\n 'Agosto',\n 'Setembro',\n 'Outubro',\n 'Novembro',\n 'Dezembro',\n];\n\nfunction formatForumDate(isoDate: string): string {\n const d = new Date(isoDate);\n const day = d.getDate();\n const month = MONTHS_PT[d.getMonth()];\n const year = d.getFullYear();\n const hours = d.getHours();\n const minutes = d.getMinutes().toString().padStart(2, '0');\n return `${day} ${month} ${year} • ${hours}:${minutes}`;\n}\n\nfunction formatReplyCount(count: number): string {\n if (count === 1) return '1 resposta';\n return `${count} respostas`;\n}\n\n// ---------------------------------------------------------------------------\n// Sub-components\n// ---------------------------------------------------------------------------\n\ninterface AuthorAvatarProps {\n readonly name: string;\n readonly photoUrl: string | null;\n}\n\nfunction AuthorAvatar({ name, photoUrl }: AuthorAvatarProps) {\n if (photoUrl) {\n return (\n <img\n src={photoUrl}\n alt={name}\n className=\"w-8 h-8 rounded-full object-cover shrink-0\"\n />\n );\n }\n return (\n <div className=\"w-8 h-8 rounded-full bg-primary-600 flex items-center justify-center shrink-0\">\n <Text size=\"xs\" weight=\"semibold\" color=\"text-white\">\n {getInitials(name)}\n </Text>\n </div>\n );\n}\n\ninterface AuthorMetaProps {\n readonly authorName: string;\n readonly authorPhoto: string | null;\n readonly createdAt: string;\n}\n\nfunction AuthorMeta({ authorName, authorPhoto, createdAt }: AuthorMetaProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <AuthorAvatar name={authorName} photoUrl={authorPhoto} />\n <div className=\"flex items-center gap-1\">\n <Text size=\"xs\" weight=\"semibold\" color=\"text-primary-700\">\n Postado por {authorName}\n </Text>\n <Text size=\"xs\" color=\"text-text-600\">\n • {formatForumDate(createdAt)}\n </Text>\n </div>\n </div>\n );\n}\n\ninterface PostActionsMenuProps {\n readonly onEdit: () => void;\n readonly onDelete: () => void;\n}\n\nfunction PostActionsMenu({ onEdit, onDelete }: PostActionsMenuProps) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-label=\"Abrir ações do post\"\n className=\"p-1 rounded hover:bg-background-100 transition-colors shrink-0\"\n >\n <DotsThreeVerticalIcon size={20} className=\"text-text-600\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n iconLeft={<PencilSimpleIcon size={16} />}\n onClick={onEdit}\n >\n Editar\n </DropdownMenuItem>\n <DropdownMenuItem iconLeft={<TrashIcon size={16} />} onClick={onDelete}>\n Deletar\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\ninterface PostContentModalProps {\n readonly isOpen: boolean;\n readonly title: string;\n readonly submitLabel: string;\n readonly content: string;\n readonly imageUrl: string | undefined;\n readonly isSubmitting: boolean;\n readonly onContentChange: (value: string) => void;\n readonly onClose: () => void;\n readonly onSubmit: () => void;\n readonly onUploadImage?: (file: File) => Promise<string>;\n readonly onImageUploaded: (url: string) => void;\n readonly maxLength: number;\n /** Use RichEditor with toolbar instead of plain TextArea */\n readonly richText?: boolean;\n /** Show \"Este fórum vale nota no boletim?\" question (professor only) */\n readonly showGradeQuestion?: boolean;\n readonly countsForGrade?: boolean;\n readonly onCountsForGradeChange?: (value: boolean) => void;\n}\n\nfunction PostContentModal({\n isOpen,\n title,\n submitLabel,\n content,\n imageUrl,\n isSubmitting,\n onContentChange,\n onClose,\n onSubmit,\n onUploadImage,\n onImageUploaded,\n maxLength,\n richText = false,\n showGradeQuestion = false,\n countsForGrade,\n onCountsForGradeChange,\n}: PostContentModalProps) {\n const handleImageSelect = useCallback(\n async (file: File) => {\n if (!onUploadImage) return;\n try {\n const url = await onUploadImage(file);\n onImageUploaded(url);\n } catch {\n // silently fail — consuming app should handle upload errors\n }\n },\n [onUploadImage, onImageUploaded]\n );\n\n // Determine if content is effectively empty or exceeds the limit\n const plainTextContent = richText ? stripHtml(content) : content;\n const isContentEmpty = !plainTextContent.trim();\n const exceedsMaxLength = plainTextContent.trim().length > maxLength;\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={title}\n size=\"md\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={onClose}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n disabled={isContentEmpty || exceedsMaxLength || isSubmitting}\n onClick={onSubmit}\n >\n {submitLabel}\n </Button>\n </div>\n }\n >\n <div className=\"flex flex-col gap-3\">\n {richText ? (\n // key forces remount (and thus reset) whenever the modal opens/closes\n <RichEditor\n key={String(isOpen)}\n content={content}\n onChange={(data) => onContentChange(data.html)}\n placeholder=\"Escreva o conteúdo do seu post aqui.\"\n />\n ) : (\n <TextArea\n placeholder=\"Escreva o conteúdo do seu post aqui.\"\n value={content}\n onChange={(e) => onContentChange(e.target.value)}\n autoResize\n minHeight={120}\n maxLength={maxLength}\n />\n )}\n\n <ImageUpload\n variant=\"compact\"\n onFileSelect={handleImageSelect}\n onRemoveFile={() => onImageUploaded('')}\n buttonIcon={<ImageIcon size={16} />}\n />\n {imageUrl && (\n <img\n src={imageUrl}\n alt=\"Preview da imagem\"\n className=\"max-h-40 rounded-lg object-contain\"\n />\n )}\n\n {showGradeQuestion && (\n <div className=\"flex flex-col gap-2\">\n <Text size=\"sm\" weight=\"medium\">\n Este fórum vale nota no boletim?\n </Text>\n <div className=\"flex items-center gap-4\">\n <Radio\n name=\"countsForGrade\"\n value=\"yes\"\n label=\"Sim\"\n size=\"small\"\n checked={countsForGrade === true}\n onChange={() => onCountsForGradeChange?.(true)}\n />\n <Radio\n name=\"countsForGrade\"\n value=\"no\"\n label=\"Não\"\n size=\"small\"\n checked={countsForGrade === false}\n onChange={() => onCountsForGradeChange?.(false)}\n />\n </div>\n </div>\n )}\n </div>\n </Modal>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Skeleton\n// ---------------------------------------------------------------------------\n\nfunction TopicListSkeleton() {\n return (\n <SkeletonList items={3} showAvatar showTitle showDescription lines={2} />\n );\n}\n\nfunction TopicDetailSkeleton() {\n return (\n <SkeletonCard\n showAvatar\n showTitle\n showDescription\n showActions={false}\n lines={2}\n />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component\n// ---------------------------------------------------------------------------\n\nexport type ForumProps = {\n /** API client with forum CRUD methods */\n readonly apiClient: ForumApiClient;\n /** Current user's userInstitutionId — used to identify own posts */\n readonly currentUserId: string;\n /** User role — enables professor-specific features (e.g. grade question on create) */\n readonly userRole?: PROFILE_ROLES.STUDENT | PROFILE_ROLES.TEACHER;\n /** Forum page title */\n readonly title?: string;\n /** Forum page subtitle */\n readonly subtitle?: string;\n /** Callback to upload an image file and return its hosted URL */\n readonly onUploadImage?: (file: File) => Promise<string>;\n /**\n * Callback to evaluate a reply (teacher only).\n * If provided, an \"Avaliar\" button appears on each reply when the topic counts for grade.\n */\n readonly onEvaluateReply?: (replyId: string, grade: number) => Promise<void>;\n /** Additional CSS classes */\n readonly className?: string;\n};\n\nexport function Forum({\n apiClient,\n currentUserId,\n userRole = PROFILE_ROLES.STUDENT,\n title = 'Fórum',\n subtitle = 'Espaço para troca de conhecimento',\n onUploadImage,\n onEvaluateReply,\n className,\n}: ForumProps) {\n const isTeacher = userRole === PROFILE_ROLES.TEACHER;\n const [view, setView] = useState<'list' | 'detail'>('list');\n const [topics, setTopics] = useState<ForumTopic[]>([]);\n const [isLoadingTopics, setIsLoadingTopics] = useState(false);\n const [selectedTopic, setSelectedTopic] = useState<ForumTopic | null>(null);\n const [replies, setReplies] = useState<ForumReply[]>([]);\n const [isLoadingTopic, setIsLoadingTopic] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n // Create post modal state\n const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);\n const [createContent, setCreateContent] = useState('');\n const [createImageUrl, setCreateImageUrl] = useState<string | undefined>();\n const [createCountsForGrade, setCreateCountsForGrade] = useState<\n boolean | undefined\n >();\n\n // Reply modal state\n const [isReplyModalOpen, setIsReplyModalOpen] = useState(false);\n const [replyContent, setReplyContent] = useState('');\n const [replyImageUrl, setReplyImageUrl] = useState<string | undefined>();\n\n // Edit topic modal state\n const [editingTopic, setEditingTopic] = useState<ForumTopic | null>(null);\n const [editTopicContent, setEditTopicContent] = useState('');\n const [editTopicImageUrl, setEditTopicImageUrl] = useState<\n string | undefined\n >();\n\n // Edit reply modal state\n const [editingReply, setEditingReply] = useState<ForumReply | null>(null);\n const [editReplyContent, setEditReplyContent] = useState('');\n const [editReplyImageUrl, setEditReplyImageUrl] = useState<\n string | undefined\n >();\n\n // Evaluate reply modal state (teacher only)\n const [evaluatingReplyId, setEvaluatingReplyId] = useState<string | null>(\n null\n );\n const [gradeValue, setGradeValue] = useState<number | null>(null);\n const [isEditingGrade, setIsEditingGrade] = useState(false);\n\n // Delete confirmation state\n const [pendingDelete, setPendingDelete] = useState<\n { type: 'topic'; id: string } | { type: 'reply'; id: string } | null\n >(null);\n\n const fetchTopics = useCallback(async () => {\n setIsLoadingTopics(true);\n try {\n const response = await apiClient.getTopics({ limit: 50 });\n setTopics(response.topics);\n } finally {\n setIsLoadingTopics(false);\n }\n }, [apiClient]);\n\n const fetchTopic = useCallback(\n async (topicId: string) => {\n setIsLoadingTopic(true);\n try {\n const response = await apiClient.getTopic(topicId);\n setSelectedTopic(response.topic);\n setReplies(response.replies);\n } finally {\n setIsLoadingTopic(false);\n }\n },\n [apiClient]\n );\n\n useEffect(() => {\n fetchTopics();\n }, [fetchTopics]);\n\n const handleTopicClick = useCallback(\n (topic: ForumTopic) => {\n setSelectedTopic(topic);\n setView('detail');\n fetchTopic(topic.id);\n },\n [fetchTopic]\n );\n\n const handleBack = useCallback(() => {\n setView('list');\n setSelectedTopic(null);\n setReplies([]);\n fetchTopics();\n }, [fetchTopics]);\n\n // Create topic\n const handleCloseCreateModal = useCallback(() => {\n setIsCreateModalOpen(false);\n setCreateContent('');\n setCreateImageUrl(undefined);\n setCreateCountsForGrade(undefined);\n }, []);\n\n const handleCreateTopic = useCallback(async () => {\n if (!createContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.createTopic({\n content: createContent.trim(),\n ...(createImageUrl && { imageUrl: createImageUrl }),\n ...(isTeacher &&\n createCountsForGrade !== undefined && {\n countsForGrade: createCountsForGrade,\n }),\n });\n handleCloseCreateModal();\n await fetchTopics();\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n createContent,\n createImageUrl,\n createCountsForGrade,\n isTeacher,\n handleCloseCreateModal,\n fetchTopics,\n ]);\n\n // Edit topic\n const handleOpenEditTopic = useCallback((topic: ForumTopic) => {\n setEditingTopic(topic);\n setEditTopicContent(topic.content);\n setEditTopicImageUrl(topic.imageUrl ?? undefined);\n }, []);\n\n const handleCloseEditTopic = useCallback(() => {\n setEditingTopic(null);\n setEditTopicContent('');\n setEditTopicImageUrl(undefined);\n }, []);\n\n const handleEditTopic = useCallback(async () => {\n if (!editingTopic || !editTopicContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.updateTopic(editingTopic.id, {\n content: editTopicContent.trim(),\n imageUrl: editTopicImageUrl ?? null,\n });\n handleCloseEditTopic();\n if (view === 'list') {\n await fetchTopics();\n } else {\n await fetchTopic(editingTopic.id);\n }\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n editingTopic,\n editTopicContent,\n editTopicImageUrl,\n handleCloseEditTopic,\n view,\n fetchTopics,\n fetchTopic,\n ]);\n\n const handleDeleteTopic = useCallback(\n async (topicId: string) => {\n setIsSubmitting(true);\n try {\n await apiClient.deleteTopic(topicId);\n if (view === 'detail') {\n handleBack();\n } else {\n await fetchTopics();\n }\n } finally {\n setIsSubmitting(false);\n setPendingDelete(null);\n }\n },\n [apiClient, view, handleBack, fetchTopics]\n );\n\n // Reply\n const handleCloseReplyModal = useCallback(() => {\n setIsReplyModalOpen(false);\n setReplyContent('');\n setReplyImageUrl(undefined);\n }, []);\n\n const handleCreateReply = useCallback(async () => {\n if (!selectedTopic || !replyContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.createReply(selectedTopic.id, {\n content: replyContent.trim(),\n ...(replyImageUrl && { imageUrl: replyImageUrl }),\n });\n handleCloseReplyModal();\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n selectedTopic,\n replyContent,\n replyImageUrl,\n handleCloseReplyModal,\n fetchTopic,\n ]);\n\n // Edit reply\n const handleOpenEditReply = useCallback((reply: ForumReply) => {\n setEditingReply(reply);\n setEditReplyContent(reply.content);\n setEditReplyImageUrl(reply.imageUrl ?? undefined);\n }, []);\n\n const handleCloseEditReply = useCallback(() => {\n setEditingReply(null);\n setEditReplyContent('');\n setEditReplyImageUrl(undefined);\n }, []);\n\n const handleEditReply = useCallback(async () => {\n if (!editingReply || !editReplyContent.trim() || !selectedTopic) return;\n setIsSubmitting(true);\n try {\n await apiClient.updateReply(editingReply.id, {\n content: editReplyContent.trim(),\n imageUrl: editReplyImageUrl ?? null,\n });\n handleCloseEditReply();\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n editingReply,\n editReplyContent,\n editReplyImageUrl,\n handleCloseEditReply,\n selectedTopic,\n fetchTopic,\n ]);\n\n const handleDeleteReply = useCallback(\n async (replyId: string) => {\n if (!selectedTopic) return;\n setIsSubmitting(true);\n try {\n await apiClient.deleteReply(replyId);\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n setPendingDelete(null);\n }\n },\n [apiClient, selectedTopic, fetchTopic]\n );\n\n const handleCloseEvaluateModal = useCallback(() => {\n setEvaluatingReplyId(null);\n setGradeValue(null);\n setIsEditingGrade(false);\n }, []);\n\n const handleOpenEvaluate = useCallback((reply: ForumReply) => {\n setEvaluatingReplyId(reply.id);\n setGradeValue(null);\n setIsEditingGrade(false);\n }, []);\n\n const handleOpenEditGrade = useCallback((reply: ForumReply) => {\n setEvaluatingReplyId(reply.id);\n setGradeValue(reply.grade ?? null);\n setIsEditingGrade(true);\n }, []);\n\n const isValidGrade =\n gradeValue !== null &&\n Number.isInteger(gradeValue) &&\n gradeValue >= 0 &&\n gradeValue <= 10;\n\n const handleSubmitEvaluation = useCallback(async () => {\n if (!evaluatingReplyId || !isValidGrade || !onEvaluateReply) return;\n setIsSubmitting(true);\n try {\n await onEvaluateReply(evaluatingReplyId, gradeValue);\n // Optimistically update grade in local state\n setReplies((prev) =>\n prev.map((r) =>\n r.id === evaluatingReplyId ? { ...r, grade: gradeValue } : r\n )\n );\n handleCloseEvaluateModal();\n } finally {\n setIsSubmitting(false);\n }\n }, [\n evaluatingReplyId,\n gradeValue,\n isValidGrade,\n onEvaluateReply,\n handleCloseEvaluateModal,\n ]);\n\n const handleConfirmDelete = useCallback(async () => {\n if (!pendingDelete) return;\n if (pendingDelete.type === 'topic') {\n await handleDeleteTopic(pendingDelete.id);\n } else {\n await handleDeleteReply(pendingDelete.id);\n }\n }, [pendingDelete, handleDeleteTopic, handleDeleteReply]);\n\n /* ---- Extracted render blocks (avoids nested ternaries — SonarQube) ---- */\n\n const topicListContent = (() => {\n if (isLoadingTopics) return <TopicListSkeleton />;\n\n if (topics.length === 0) {\n return (\n <div className=\"flex items-center justify-center py-16 border border-border-200 rounded-lg\">\n <Text size=\"md\" color=\"text-text-500\">\n Nenhum tópico ainda. Seja o primeiro a criar um post!\n </Text>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col gap-4\">\n {topics.map((topic) => (\n <div\n key={topic.id}\n className=\"flex items-start bg-white border border-border-100 rounded-lg pt-4 pr-2 pb-4 pl-2 shadow-sm\"\n >\n {/* Clickable content area */}\n <button\n type=\"button\"\n className=\"flex flex-col gap-3 flex-1 min-w-0 text-left hover:opacity-90 transition-opacity\"\n onClick={() => handleTopicClick(topic)}\n >\n <AuthorMeta\n authorName={topic.authorName}\n authorPhoto={topic.authorPhoto}\n createdAt={topic.createdAt}\n />\n <Text size=\"sm\" className=\"leading-normal line-clamp-3 ml-10\">\n {stripHtml(topic.content)}\n </Text>\n <div className=\"flex items-center gap-1 text-text-600 ml-10\">\n <ChatCircleTextIcon size={16} />\n <Text size=\"xs\">{formatReplyCount(topic.replyCount)}</Text>\n </div>\n </button>\n\n {/* Actions menu — only for own posts */}\n {topic.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditTopic(topic)}\n onDelete={() =>\n setPendingDelete({ type: 'topic', id: topic.id })\n }\n />\n )}\n </div>\n ))}\n </div>\n );\n })();\n\n const topicDetailContent = (() => {\n if (isLoadingTopic) return <TopicDetailSkeleton />;\n\n if (!selectedTopic) return null;\n\n return (\n <>\n {/* Original post */}\n <div className=\"flex items-start gap-2\">\n <div className=\"flex flex-col gap-3 flex-1 min-w-0\">\n <AuthorMeta\n authorName={selectedTopic.authorName}\n authorPhoto={selectedTopic.authorPhoto}\n createdAt={selectedTopic.createdAt}\n />\n <div\n className=\"text-sm text-text-950 leading-normal ml-10 prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtmlForDisplay(selectedTopic.content),\n }}\n />\n {selectedTopic.imageUrl && (\n <img\n src={selectedTopic.imageUrl}\n alt=\"Imagem do post\"\n className=\"ml-10 max-w-lg rounded-lg\"\n />\n )}\n </div>\n {selectedTopic.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditTopic(selectedTopic)}\n onDelete={() =>\n setPendingDelete({ type: 'topic', id: selectedTopic.id })\n }\n />\n )}\n </div>\n\n {/* Replies header */}\n <div className=\"flex items-center justify-between\">\n <Text size=\"sm\" color=\"text-text-600\">\n {formatReplyCount(selectedTopic.replyCount)}\n </Text>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n onClick={() => setIsReplyModalOpen(true)}\n >\n Responder\n </Button>\n </div>\n\n {/* Replies list */}\n {replies.length > 0 && (\n <div className=\"flex flex-col divide-y divide-border-200\">\n {replies.map((reply) => (\n <div key={reply.id} className=\"flex items-start gap-2 py-4\">\n <div className=\"flex flex-col gap-3 flex-1 min-w-0\">\n <AuthorMeta\n authorName={reply.authorName}\n authorPhoto={reply.authorPhoto}\n createdAt={reply.createdAt}\n />\n <div\n className=\"text-sm text-text-950 leading-normal ml-10 prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtmlForDisplay(reply.content),\n }}\n />\n {reply.imageUrl && (\n <img\n src={reply.imageUrl}\n alt=\"Imagem da resposta\"\n className=\"ml-10 max-w-lg rounded-lg\"\n />\n )}\n {isTeacher &&\n selectedTopic?.countsForGrade &&\n onEvaluateReply &&\n (reply.grade == null ? (\n /* Not yet graded — show Avaliar button */\n <button\n type=\"button\"\n className=\"flex items-center gap-1.5 text-text-600 text-sm hover:text-text-950 transition-colors w-fit ml-10\"\n onClick={() => handleOpenEvaluate(reply)}\n >\n <CheckIcon size={16} />\n Avaliar\n </button>\n ) : (\n /* Grade already set — teacher sees it with edit pencil */\n <div className=\"flex items-center gap-1.5 ml-10\">\n <Text size=\"sm\" color=\"text-text-600\">\n Nota {reply.grade}\n </Text>\n <button\n type=\"button\"\n className=\"text-text-600 hover:text-text-950 transition-colors\"\n onClick={() => handleOpenEditGrade(reply)}\n >\n <PencilSimpleIcon size={14} />\n </button>\n </div>\n ))}\n {!isTeacher &&\n reply.grade != null &&\n reply.userInstitutionId === currentUserId &&\n selectedTopic?.countsForGrade && (\n <Text size=\"sm\" color=\"text-text-600\" className=\"ml-10\">\n Nota {reply.grade}\n </Text>\n )}\n </div>\n {reply.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditReply(reply)}\n onDelete={() =>\n setPendingDelete({ type: 'reply', id: reply.id })\n }\n />\n )}\n </div>\n ))}\n </div>\n )}\n </>\n );\n })();\n\n return (\n <div className={cn('flex flex-col gap-4', className)}>\n {view === 'list' ? (\n <>\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <Text as=\"h1\" size=\"2xl\" weight=\"bold\" color=\"text-text-950\">\n {title}\n </Text>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n onClick={() => setIsCreateModalOpen(true)}\n >\n Criar post\n </Button>\n </div>\n\n {/* Subtitle + topic list */}\n <div className=\"flex flex-col gap-3\">\n <Text as=\"h2\" size=\"lg\" weight=\"semibold\" color=\"text-text-950\">\n {subtitle}\n </Text>\n\n {topicListContent}\n </div>\n </>\n ) : (\n /* Detail view */\n <>\n <button\n type=\"button\"\n className=\"flex items-center gap-2 hover:opacity-80 transition-opacity w-fit\"\n onClick={handleBack}\n >\n <CaretLeftIcon size={24} className=\"text-text-950\" />\n <Text size=\"2xl\" weight=\"bold\">\n Voltar\n </Text>\n </button>\n\n {topicDetailContent}\n </>\n )}\n\n {/* Create post modal */}\n <PostContentModal\n isOpen={isCreateModalOpen}\n title=\"Criar post\"\n submitLabel=\"Criar post\"\n content={createContent}\n imageUrl={createImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setCreateContent}\n onClose={handleCloseCreateModal}\n onSubmit={handleCreateTopic}\n onUploadImage={onUploadImage}\n onImageUploaded={setCreateImageUrl}\n maxLength={10000}\n richText\n showGradeQuestion={isTeacher}\n countsForGrade={createCountsForGrade}\n onCountsForGradeChange={setCreateCountsForGrade}\n />\n\n {/* Reply modal */}\n <PostContentModal\n isOpen={isReplyModalOpen}\n title=\"Responder\"\n submitLabel=\"Responder\"\n content={replyContent}\n imageUrl={replyImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setReplyContent}\n onClose={handleCloseReplyModal}\n onSubmit={handleCreateReply}\n onUploadImage={onUploadImage}\n onImageUploaded={setReplyImageUrl}\n maxLength={5000}\n richText\n />\n\n {/* Edit topic modal */}\n <PostContentModal\n isOpen={!!editingTopic}\n title=\"Editar\"\n submitLabel=\"Salvar\"\n content={editTopicContent}\n imageUrl={editTopicImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setEditTopicContent}\n onClose={handleCloseEditTopic}\n onSubmit={handleEditTopic}\n onUploadImage={onUploadImage}\n onImageUploaded={setEditTopicImageUrl}\n maxLength={10000}\n richText\n />\n\n {/* Edit reply modal */}\n <PostContentModal\n isOpen={!!editingReply}\n title=\"Editar\"\n submitLabel=\"Salvar\"\n content={editReplyContent}\n imageUrl={editReplyImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setEditReplyContent}\n onClose={handleCloseEditReply}\n onSubmit={handleEditReply}\n onUploadImage={onUploadImage}\n onImageUploaded={setEditReplyImageUrl}\n maxLength={5000}\n richText\n />\n\n {/* Evaluate / edit grade modal (teacher only) */}\n <Modal\n isOpen={!!evaluatingReplyId}\n onClose={handleCloseEvaluateModal}\n title={\n isEditingGrade\n ? 'Edite a nota da atividade'\n : 'Defina a nota da atividade'\n }\n size=\"md\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={handleCloseEvaluateModal}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n disabled={!isValidGrade || isSubmitting}\n onClick={handleSubmitEvaluation}\n >\n {isEditingGrade ? 'Salvar' : 'Avaliar'}\n </Button>\n </div>\n }\n >\n <Input\n type=\"number\"\n min={0}\n max={10}\n step={1}\n placeholder=\"Nota (0-10)\"\n value={gradeValue ?? ''}\n onChange={(e) => {\n const val = e.target.value;\n const parsed = Number(val);\n setGradeValue(val === '' || Number.isNaN(parsed) ? null : parsed);\n }}\n />\n </Modal>\n\n {/* Delete confirmation modal */}\n <Modal\n isOpen={!!pendingDelete}\n onClose={() => setPendingDelete(null)}\n title=\"Deseja deletar post?\"\n size=\"sm\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={() => setPendingDelete(null)}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"negative\"\n size=\"medium\"\n disabled={isSubmitting}\n onClick={handleConfirmDelete}\n >\n Deletar\n </Button>\n </div>\n }\n >\n <Text size=\"md\" color=\"text-text-600\">\n Essa ação é permanente e não poderá ser desfeita.\n </Text>\n </Modal>\n </div>\n );\n}\n\nexport default Forum;\n"]}
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-VJYQ54ZX.mjs";
5
5
  import {
6
6
  VideoPlayer_default
7
- } from "./chunk-5WS6IENQ.mjs";
7
+ } from "./chunk-AU2HLQDJ.mjs";
8
8
  import {
9
9
  Stepper_default
10
10
  } from "./chunk-4QZWLI7Q.mjs";
@@ -13,10 +13,10 @@ import {
13
13
  } from "./chunk-ZRBIE5ZM.mjs";
14
14
  import {
15
15
  CheckBox_default
16
- } from "./chunk-VDUO65VK.mjs";
16
+ } from "./chunk-3EGJJDIM.mjs";
17
17
  import {
18
18
  Modal_default
19
- } from "./chunk-XZUMD3CB.mjs";
19
+ } from "./chunk-LODDYDTP.mjs";
20
20
  import {
21
21
  Button_default
22
22
  } from "./chunk-ZQZBOTZJ.mjs";
@@ -96,7 +96,8 @@ var OptionCard = ({
96
96
  {
97
97
  className: cn(
98
98
  CARD_CLASSES,
99
- "flex flex-row items-center gap-3 px-4 py-3.5",
99
+ // `relative` keeps the `sr-only` radio inside the card; see CheckBox
100
+ "relative flex flex-row items-center gap-3 px-4 py-3.5",
100
101
  "cursor-pointer transition-colors hover:bg-background-100",
101
102
  "focus-within:ring-2 focus-within:ring-indicator-info",
102
103
  checked && "border-primary-700 ring-1 ring-primary-700"
@@ -513,4 +514,4 @@ var EnemClassroomStartModal_default = EnemClassroomStartModal;
513
514
  export {
514
515
  EnemClassroomStartModal_default
515
516
  };
516
- //# sourceMappingURL=chunk-SU5Q64TW.mjs.map
517
+ //# sourceMappingURL=chunk-FVCTKS33.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/EnemClassroomStartModal/EnemClassroomStartModal.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState, ChangeEvent } from 'react';\nimport Modal from '../Modal/Modal';\nimport Stepper from '../Stepper/Stepper';\nimport Button from '../Button/Button';\nimport Input from '../Input/Input';\nimport CheckBox from '../CheckBox/CheckBox';\nimport Text from '../Text/Text';\nimport VideoPlayer from '../VideoPlayer/VideoPlayer';\nimport { CaretLeftIcon } from '@phosphor-icons/react/dist/csr/CaretLeft';\nimport { CaretRightIcon } from '@phosphor-icons/react/dist/csr/CaretRight';\nimport { CheckIcon } from '@phosphor-icons/react/dist/csr/Check';\nimport { cn } from '../../utils/utils';\nimport warningClassroomIcon from '../../assets/img/enemClassroom/warning-classroom.png';\nimport warningTimerIcon from '../../assets/img/enemClassroom/warning-timer.png';\nimport warningIrreversibleIcon from '../../assets/img/enemClassroom/warning-irreversible.png';\nimport flagEnglish from '../../assets/img/enemClassroom/flag-english.png';\nimport flagSpanish from '../../assets/img/enemClassroom/flag-spanish.png';\nimport surveyCourseIllustration from '../../assets/img/enemClassroom/survey-course.svg';\nimport surveyUniversityIllustration from '../../assets/img/enemClassroom/survey-university.png';\nimport {\n ENEM_CLASSROOM_LANGUAGE,\n ENEM_CLASSROOM_LANGUAGE_LABELS,\n type EnemClassroomExam,\n type EnemClassroomLanguage,\n type EnemClassroomStartPayload,\n type EnemClassroomStudentTexts,\n type EnemClassroomSurveyQuestion,\n} from '../../types/enemClassroom';\n\n/** Title shared by every step, as in the design. */\n/**\n * The three warnings of the introduction step. The exam only counts when\n * taken in class, so they are shown before anything else. The first one is\n * the backoffice's to write (`studentTexts`); the other two are fixed.\n *\n * @param texts - The exam's texts\n * @returns The warnings in order\n */\nconst buildIntroWarnings = (texts: EnemClassroomStudentTexts) => [\n {\n icon: warningClassroomIcon,\n title: texts.introWarningTitle,\n description: texts.introWarningText,\n },\n {\n icon: warningTimerIcon,\n title: 'O cronômetro liga na hora',\n description:\n 'Assim que clicar em começar, o tempo já corre e não para, mesmo se fechar o navegador.',\n },\n {\n icon: warningIrreversibleIcon,\n title: 'Não tem como desfazer',\n description:\n 'Iniciar fora do horário estabelecido pelo seu professor em sala de aula pode atrapalhar seu resultado!',\n },\n];\n\n/** Flag shown next to each language, as in the design. */\nconst LANGUAGE_FLAGS: Record<EnemClassroomLanguage, string> = {\n [ENEM_CLASSROOM_LANGUAGE.INGLES]: flagEnglish,\n [ENEM_CLASSROOM_LANGUAGE.ESPANHOL]: flagSpanish,\n};\n\n/**\n * Illustration of each survey step, in the order the steps are asked: the\n * course question, then the university one.\n *\n * Fixed here rather than sent by the backoffice, so it is keyed by position —\n * reordering the questions there moves the illustration with the position,\n * not with the question. A question past the end simply gets none.\n */\nconst SURVEY_ILLUSTRATIONS = [\n surveyCourseIllustration,\n surveyUniversityIllustration,\n] as const;\n\n/**\n * The white card the warnings and the options sit on. Same vocabulary as\n * SelectionButton, so the modal reads like the rest of the design system\n * against the modal's `secondary-50` background.\n */\nconst CARD_CLASSES =\n 'rounded-xl border border-border-50 bg-background shadow-soft-shadow-1';\n\n/**\n * Gradiente da identidade da simulação em sala de aula — os mesmos tons do\n * card do painel do aluno. Não sai dos tokens de tema porque é a marca da\n * prova, não a da instituição.\n *\n * Literal, e não `bg-gradient-to-r from-… to-…`: o Tailwind v4 interpola\n * `in oklab`, o que muda os tons do meio em relação ao sRGB do design.\n *\n * `border-0` porque o `solid/primary` do Button traz `border-primary-950`, que\n * o gradiente não cobre — ele só troca o fundo. Zerar a largura, em vez de\n * pintar a borda de transparente, também neutraliza as cores de hover e\n * active, que voltariam a aparecer.\n */\nconst GRADIENT_CTA_CLASSES =\n 'bg-[linear-gradient(270deg,#B21FF6_0%,#F95493_100%)] border-0 hover:opacity-90 transition-opacity';\n\n/**\n * One selectable option: a card carrying an optional icon and a label.\n *\n * The radio control itself is visually hidden — in the design the card's own\n * border carries the selection. The native input stays in the tree so the\n * options remain a real radio group: arrow keys move between them and screen\n * readers announce \"1 of 2\", which a set of toggle buttons would not.\n */\nconst OptionCard = ({\n name,\n value,\n label,\n iconSrc,\n checked,\n onSelect,\n testId,\n}: {\n name: string;\n value: string;\n label: string;\n iconSrc?: string;\n checked: boolean;\n onSelect: () => void;\n testId?: string;\n}) => (\n <label\n className={cn(\n CARD_CLASSES,\n // `relative` keeps the `sr-only` radio inside the card; see CheckBox\n 'relative flex flex-row items-center gap-3 px-4 py-3.5',\n 'cursor-pointer transition-colors hover:bg-background-100',\n 'focus-within:ring-2 focus-within:ring-indicator-info',\n checked && 'border-primary-700 ring-1 ring-primary-700'\n )}\n >\n <input\n type=\"radio\"\n name={name}\n value={value}\n checked={checked}\n onChange={onSelect}\n className=\"sr-only\"\n data-testid={testId}\n />\n {iconSrc && (\n <img src={iconSrc} alt=\"\" aria-hidden className=\"w-6 h-6 flex-shrink-0\" />\n )}\n <Text size=\"sm\" weight=\"semibold\" className=\"text-text-900\">\n {label}\n </Text>\n </label>\n);\n\n/**\n * How a survey question was answered. The student either writes an answer or\n * ticks \"ainda estou pensando\" — the tick clears and disables the field, so\n * the two never disagree.\n */\ninterface SurveyAnswerDraft {\n skipped: boolean;\n text: string;\n}\n\n/**\n * One line of the summary: the step's name over what the student answered.\n */\nconst SummaryRow = ({ label, value }: { label: string; value: string }) => (\n <div className=\"flex flex-col rounded-lg bg-primary-50 px-3 py-2\">\n <Text as=\"dt\" size=\"sm\" weight=\"bold\" className=\"text-primary-800\">\n {label}\n </Text>\n <Text as=\"dd\" size=\"sm\" className=\"text-text-600\">\n {value}\n </Text>\n </div>\n);\n\n/** The introduction is always first; the first choice comes right after it. */\nconst INTRO_STEP = 0;\nconst FIRST_CHOICE_STEP = 1;\n\n/** One screen of the flow. Which ones exist depends on the exam. */\ntype FlowStep =\n | { kind: 'intro' }\n | { kind: 'language' }\n | { kind: 'survey'; question: EnemClassroomSurveyQuestion; index: number }\n | { kind: 'summary' };\n\nexport interface EnemClassroomStartModalProps {\n isOpen: boolean;\n onClose: () => void;\n exam: EnemClassroomExam;\n /** Called with everything the start endpoint needs. */\n onStart: (payload: EnemClassroomStartPayload) => void;\n /** Disables the final button while the start request is in flight. */\n isStarting?: boolean;\n}\n\n/**\n * Whether a survey draft is complete: skipped, or answered with some text.\n */\nconst isSurveyAnswerComplete = (draft: SurveyAnswerDraft | undefined) =>\n draft?.skipped === true || (draft?.text.trim().length ?? 0) > 0;\n\n/**\n * The text shown for a survey answer on the summary screen.\n */\nconst describeSurveyAnswer = (\n question: EnemClassroomSurveyQuestion,\n draft: SurveyAnswerDraft | undefined\n) => (draft && !draft.skipped ? draft.text.trim() : question.skipLabel);\n\n/**\n * Start flow of the in-classroom ENEM simulation.\n *\n * Steps, in order: introduction (video + warnings), foreign language — only\n * when the exam offers the choice —, one step per survey question, and a\n * summary the student confirms before the exam opens. The stepper only lists\n * the steps that carry a choice; the summary is a screen of its own, as in\n * the design.\n *\n * Presentational: it collects the choices and hands them to `onStart`; the\n * caller talks to the API.\n *\n * @example\n * ```tsx\n * <EnemClassroomStartModal\n * isOpen={open}\n * onClose={() => setOpen(false)}\n * exam={exam}\n * onStart={(payload) => start(exam.id, payload)}\n * />\n * ```\n */\nconst EnemClassroomStartModal = ({\n isOpen,\n onClose,\n exam,\n onStart,\n isStarting = false,\n}: EnemClassroomStartModalProps) => {\n const surveyQuestions = useMemo(\n () => [...exam.surveyQuestions].sort((a, b) => a.position - b.position),\n [exam.surveyQuestions]\n );\n // The screens this exam has: no language step on an exam without the\n // choice, so the student goes from the warnings straight to the survey.\n const steps = useMemo<FlowStep[]>(\n () => [\n { kind: 'intro' },\n ...(exam.languageChoice ? [{ kind: 'language' } as const] : []),\n ...surveyQuestions.map((question, index) => ({\n kind: 'survey' as const,\n question,\n index,\n })),\n { kind: 'summary' },\n ],\n [exam.languageChoice, surveyQuestions]\n );\n const summaryStep = steps.length - 1;\n\n const [step, setStep] = useState(INTRO_STEP);\n const [language, setLanguage] = useState<EnemClassroomLanguage | null>(null);\n const [answers, setAnswers] = useState<Record<string, SurveyAnswerDraft>>({});\n\n // Every opening starts from the introduction with nothing filled in — and\n // so does a different exam handed in while the modal is open, whose steps\n // and questions are not the ones the answers were given to.\n useEffect(() => {\n if (isOpen) {\n setStep(INTRO_STEP);\n setLanguage(null);\n setAnswers({});\n }\n }, [isOpen, exam.id]);\n\n const stepperSteps = useMemo(\n () =>\n steps\n .filter((flowStep) => flowStep.kind !== 'summary')\n .map((flowStep) => {\n if (flowStep.kind === 'intro') {\n return {\n id: 'intro',\n label: 'Introdução',\n state: 'pending' as const,\n };\n }\n if (flowStep.kind === 'language') {\n return {\n id: 'language',\n label: 'Língua estrangeira',\n state: 'pending' as const,\n };\n }\n return {\n id: flowStep.question.id,\n label: flowStep.question.stepLabel,\n state: 'pending' as const,\n };\n }),\n [steps]\n );\n\n const currentStep = steps[step] ?? steps[INTRO_STEP];\n const currentQuestion =\n currentStep.kind === 'survey' ? currentStep.question : null;\n\n const canGoNext =\n currentStep.kind === 'language'\n ? language !== null\n : currentQuestion !== null &&\n isSurveyAnswerComplete(answers[currentQuestion.id]);\n\n const updateAnswer = useCallback(\n (questionId: string, patch: Partial<SurveyAnswerDraft>) => {\n setAnswers((prev) => {\n const current = prev[questionId] ?? { skipped: false, text: '' };\n return { ...prev, [questionId]: { ...current, ...patch } };\n });\n },\n []\n );\n\n const handleStart = useCallback(() => {\n // The language is only a choice on an exam that offers one.\n if (exam.languageChoice && !language) return;\n onStart({\n language: exam.languageChoice ? language : null,\n surveyAnswers: surveyQuestions.map((question) => {\n const draft = answers[question.id];\n const text = draft && !draft.skipped ? draft.text.trim() : '';\n return { questionId: question.id, answer: text || null };\n }),\n });\n }, [exam.languageChoice, language, surveyQuestions, answers, onStart]);\n\n const renderIntroStep = () => (\n <div className=\"flex flex-col gap-6\" data-testid=\"enem-classroom-intro\">\n {exam.videoUrl && (\n <Text\n size=\"md\"\n weight=\"semibold\"\n className=\"text-text-950\"\n data-testid=\"enem-classroom-intro-video-text\"\n >\n {exam.studentTexts.introVideoText}\n </Text>\n )}\n {exam.videoUrl && (\n <VideoPlayer\n src={exam.videoUrl}\n title={exam.title}\n // O desenho mostra só o vídeo: o nome da prova já está no título do\n // modal. O `title` fica para rotular o player nos leitores de tela.\n hideHeader\n className=\"w-full rounded-xl overflow-hidden\"\n autoSave={false}\n />\n )}\n\n <div className=\"flex flex-col gap-4\">\n <Text size=\"lg\" weight=\"bold\" className=\"text-text-950\">\n {exam.studentTexts.introHeading}\n </Text>\n {buildIntroWarnings(exam.studentTexts).map(\n ({ icon, title, description }) => (\n <div\n key={title}\n className={cn(\n CARD_CLASSES,\n 'flex flex-row gap-4 items-start p-4'\n )}\n >\n <img\n src={icon}\n alt=\"\"\n aria-hidden\n className=\"flex-shrink-0 w-10 h-10\"\n />\n <div className=\"flex flex-col gap-1\">\n <Text size=\"md\" weight=\"bold\" className=\"text-text-950\">\n {title}\n </Text>\n <Text size=\"sm\" className=\"text-text-600\">\n {description}\n </Text>\n </div>\n </div>\n )\n )}\n </div>\n </div>\n );\n\n const renderLanguageStep = () => (\n <div className=\"flex flex-col gap-4\" data-testid=\"enem-classroom-language\">\n <Text\n id=\"enem-classroom-language-prompt\"\n size=\"lg\"\n weight=\"bold\"\n className=\"text-text-950\"\n >\n Qual língua estrangeira você vai usar na simulação?\n </Text>\n <div\n role=\"radiogroup\"\n aria-labelledby=\"enem-classroom-language-prompt\"\n className=\"flex flex-col gap-4\"\n >\n {Object.values(ENEM_CLASSROOM_LANGUAGE).map((value) => (\n <OptionCard\n key={value}\n name=\"enem-classroom-language\"\n value={value}\n label={ENEM_CLASSROOM_LANGUAGE_LABELS[value]}\n iconSrc={LANGUAGE_FLAGS[value]}\n checked={language === value}\n onSelect={() => setLanguage(value)}\n testId={`enem-classroom-language-${value.toLowerCase()}`}\n />\n ))}\n </div>\n </div>\n );\n\n const renderSurveyStep = (\n question: EnemClassroomSurveyQuestion,\n index: number\n ) => {\n const draft = answers[question.id];\n const illustration = SURVEY_ILLUSTRATIONS[index];\n // The two ways of answering disable each other, so they can never\n // contradict — and either one on its own releases the step.\n const hasText = (draft?.text.trim().length ?? 0) > 0;\n const isSkipped = draft?.skipped === true;\n return (\n <div\n className=\"flex flex-col gap-4\"\n data-testid={`enem-classroom-survey-${question.id}`}\n >\n {illustration && (\n <img\n src={illustration}\n alt=\"\"\n aria-hidden\n className=\"w-[220px] max-w-full self-center\"\n data-testid=\"enem-classroom-survey-illustration\"\n />\n )}\n <Text\n id={`enem-classroom-survey-prompt-${question.id}`}\n size=\"lg\"\n weight=\"bold\"\n className=\"text-text-950\"\n >\n {question.prompt}\n </Text>\n <div className=\"flex flex-col gap-2\">\n <Text\n as=\"label\"\n htmlFor={`enem-classroom-survey-input-${question.id}`}\n size=\"sm\"\n className=\"text-text-600\"\n >\n {question.inputLabel}\n </Text>\n <Input\n id={`enem-classroom-survey-input-${question.id}`}\n variant=\"rounded\"\n placeholder={question.inputPlaceholder}\n value={draft?.text ?? ''}\n maxLength={255}\n disabled={isSkipped}\n onChange={(event: ChangeEvent<HTMLInputElement>) =>\n updateAnswer(question.id, { text: event.target.value })\n }\n data-testid=\"enem-classroom-survey-input\"\n />\n </div>\n\n <CheckBox\n label={question.skipLabel}\n checked={isSkipped}\n disabled={hasText}\n onChange={(event: ChangeEvent<HTMLInputElement>) =>\n updateAnswer(question.id, { skipped: event.target.checked })\n }\n data-testid=\"enem-classroom-survey-skip\"\n />\n </div>\n );\n };\n\n const renderSummaryStep = () => (\n <div\n className=\"flex flex-col items-center gap-6 text-center\"\n data-testid=\"enem-classroom-summary\"\n >\n <span className=\"flex items-center justify-center w-14 h-14 rounded-full bg-success-200 text-success-950\">\n <CheckIcon size={24} aria-hidden />\n </span>\n <div className=\"flex flex-col gap-2\">\n <Text size=\"xl\" weight=\"bold\" className=\"text-text-950\">\n Boa sorte!\n </Text>\n <Text size=\"sm\" className=\"text-text-600\">\n O seu simulado ENEM já vai começar e o cronômetro vai iniciar. Respire\n fundo e dê o seu melhor!\n </Text>\n </div>\n\n <div\n className={cn(CARD_CLASSES, 'flex flex-col gap-3 w-full text-left p-4')}\n >\n <Text size=\"sm\" weight=\"bold\" className=\"text-text-950\">\n Suas respostas\n </Text>\n <dl className=\"flex flex-col gap-2\">\n {exam.languageChoice && (\n <SummaryRow\n label=\"Idioma\"\n value={language ? ENEM_CLASSROOM_LANGUAGE_LABELS[language] : '—'}\n />\n )}\n {surveyQuestions.map((question) => (\n <SummaryRow\n key={question.id}\n label={question.stepLabel}\n value={describeSurveyAnswer(question, answers[question.id])}\n />\n ))}\n </dl>\n <Button\n size=\"medium\"\n variant=\"outline\"\n action=\"primary\"\n className=\"self-center\"\n disabled={isStarting}\n onClick={() => setStep(FIRST_CHOICE_STEP)}\n data-testid=\"enem-classroom-review\"\n >\n Revisar minhas respostas\n </Button>\n </div>\n </div>\n );\n\n const renderStepContent = () => {\n if (currentStep.kind === 'intro') return renderIntroStep();\n if (currentStep.kind === 'language') return renderLanguageStep();\n if (currentStep.kind === 'survey')\n return renderSurveyStep(currentStep.question, currentStep.index);\n return renderSummaryStep();\n };\n\n const showNavigation = step >= FIRST_CHOICE_STEP && step < summaryStep;\n const showStepper = step < summaryStep;\n\n /*\n * O rodapé do Modal não rola, e é lá que o desenho quer o botão: na\n * introdução ele leva o CTA; nos passos de escolha, a navegação.\n */\n /**\n * O rodapé do Modal não rola, e é onde o desenho quer o botão de cada passo:\n * o CTA na introdução, a navegação nos passos de escolha e o de iniciar no\n * resumo. O \"Revisar minhas respostas\" fica de fora de propósito — ele mora\n * dentro do card de respostas.\n * @returns O rodapé do passo atual, ou nada quando ele não tem botão\n */\n const renderFooter = () => {\n if (currentStep.kind === 'intro') {\n return (\n <Button\n size=\"large\"\n variant=\"solid\"\n action=\"primary\"\n className={cn('w-full', GRADIENT_CTA_CLASSES)}\n onClick={() => setStep(FIRST_CHOICE_STEP)}\n data-testid=\"enem-classroom-intro-continue\"\n >\n Estou em sala. Quero começar!\n </Button>\n );\n }\n\n if (currentStep.kind === 'summary') {\n return (\n <Button\n size=\"large\"\n variant=\"solid\"\n action=\"primary\"\n className={cn('w-full', GRADIENT_CTA_CLASSES)}\n disabled={isStarting}\n onClick={handleStart}\n data-testid=\"enem-classroom-start\"\n >\n Iniciar a prova!\n </Button>\n );\n }\n\n return showNavigation ? (\n <div className=\"flex flex-row justify-end gap-2 w-full\">\n <Button\n size=\"medium\"\n variant=\"outline\"\n action=\"primary\"\n iconLeft={<CaretLeftIcon size={16} aria-hidden />}\n onClick={() => setStep((current) => current - 1)}\n data-testid=\"enem-classroom-previous\"\n >\n Anterior\n </Button>\n <Button\n size=\"medium\"\n variant=\"solid\"\n action=\"primary\"\n iconRight={<CaretRightIcon size={16} aria-hidden />}\n disabled={!canGoNext}\n onClick={() => setStep((current) => current + 1)}\n data-testid=\"enem-classroom-next\"\n >\n Próximo\n </Button>\n </div>\n ) : undefined;\n };\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n /*\n * A tela de resumo abre com o header vazio, só o X — quem dá o título\n * ali é o \"Boa sorte!\". O texto continua no <h2>, apenas oculto: o\n * `aria-labelledby` do Modal aponta pra ele, e um h2 vazio deixaria o\n * dialog sem nome acessível.\n */\n title={\n showStepper ? exam.title : <span className=\"sr-only\">{exam.title}</span>\n }\n size=\"lg\"\n footer={renderFooter()}\n /*\n * A rolagem sai do Modal e vai para o miolo: título e stepper ficam\n * parados em cima, o rodapé embaixo, e só o conteúdo entre eles corre.\n */\n contentClassName=\"flex flex-col overflow-hidden\"\n >\n <div className=\"flex flex-col gap-6 flex-1 min-h-0\">\n {showStepper && (\n <Stepper\n steps={stepperSteps}\n currentStep={step}\n size=\"small\"\n className=\"flex-none\"\n />\n )}\n <div className=\"flex-1 min-h-0 overflow-y-auto\">\n {renderStepContent()}\n </div>\n </div>\n </Modal>\n );\n};\n\nexport default EnemClassroomStartModal;\n"],"mappings":"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","names":[]}
@@ -6,10 +6,10 @@ var _chunkQYQTHJC2js = require('./chunk-QYQTHJC2.js');
6
6
  var _chunkZPUXEJOQjs = require('./chunk-ZPUXEJOQ.js');
7
7
 
8
8
 
9
- var _chunkAYYMS23Ljs = require('./chunk-AYYMS23L.js');
9
+ var _chunkESIQ2GB4js = require('./chunk-ESIQ2GB4.js');
10
10
 
11
11
 
12
- var _chunkZCBT2BUZjs = require('./chunk-ZCBT2BUZ.js');
12
+ var _chunk7RFHXFFVjs = require('./chunk-7RFHXFFV.js');
13
13
 
14
14
 
15
15
  var _chunkAN62GXF5js = require('./chunk-AN62GXF5.js');
@@ -29,7 +29,7 @@ var _chunkCAQ2Q3ONjs = require('./chunk-CAQ2Q3ON.js');
29
29
 
30
30
 
31
31
 
32
- var _chunkRBJAO57Ajs = require('./chunk-RBJAO57A.js');
32
+ var _chunkFAAR4XC5js = require('./chunk-FAAR4XC5.js');
33
33
 
34
34
 
35
35
  var _chunkANT66KVKjs = require('./chunk-ANT66KVK.js');
@@ -163,7 +163,7 @@ var AppHeader = ({
163
163
  }
164
164
  ),
165
165
  showCalendar && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "lg:hidden", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
166
- _chunkAYYMS23Ljs.CalendarCard_default,
166
+ _chunkESIQ2GB4js.CalendarCard_default,
167
167
  {
168
168
  content: calendarContent,
169
169
  isOpen: _nullishCoalesce(_nullishCoalesce(calendarOpen, () => ( activeStates.calendar)), () => ( false)),
@@ -171,7 +171,7 @@ var AppHeader = ({
171
171
  }
172
172
  ) }),
173
173
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
174
- _chunkZCBT2BUZjs.NotificationCard_default,
174
+ _chunk7RFHXFFVjs.NotificationCard_default,
175
175
  {
176
176
  mode: "center",
177
177
  isActive: activeStates.notifications,
@@ -214,7 +214,7 @@ var AppHeader = ({
214
214
  }
215
215
  ),
216
216
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
217
- _chunkRBJAO57Ajs.DropdownMenu_default,
217
+ _chunkFAAR4XC5js.DropdownMenu_default,
218
218
  {
219
219
  onOpenChange: (open) => {
220
220
  _chunkTN3AYOMVjs.syncDropdownState.call(void 0,
@@ -226,7 +226,7 @@ var AppHeader = ({
226
226
  },
227
227
  children: [
228
228
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
229
- _chunkRBJAO57Ajs.DropdownMenuTrigger,
229
+ _chunkFAAR4XC5js.DropdownMenuTrigger,
230
230
  {
231
231
  className: "text-primary cursor-pointer",
232
232
  asChild: true,
@@ -248,7 +248,7 @@ var AppHeader = ({
248
248
  }
249
249
  ),
250
250
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
251
- _chunkRBJAO57Ajs.DropdownMenuContent,
251
+ _chunkFAAR4XC5js.DropdownMenuContent,
252
252
  {
253
253
  className: profileDropdownWidth,
254
254
  side: "bottom",
@@ -256,7 +256,7 @@ var AppHeader = ({
256
256
  align: "end",
257
257
  children: [
258
258
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
259
- _chunkRBJAO57Ajs.ProfileMenuHeader,
259
+ _chunkFAAR4XC5js.ProfileMenuHeader,
260
260
  {
261
261
  className: isMobile ? "min-w-0" : void 0,
262
262
  name: displayName,
@@ -265,16 +265,16 @@ var AppHeader = ({
265
265
  }
266
266
  ),
267
267
  showProfileInfo && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
268
- _chunkRBJAO57Ajs.ProfileMenuInfo,
268
+ _chunkFAAR4XC5js.ProfileMenuInfo,
269
269
  {
270
270
  schoolName: _nullishCoalesce(_optionalChain([sessionInfo, 'optionalAccess', _11 => _11.schoolName]), () => ( "")),
271
271
  classYearName: _nullishCoalesce(_optionalChain([sessionInfo, 'optionalAccess', _12 => _12.className]), () => ( "")),
272
272
  schoolYearName: _nullishCoalesce(_optionalChain([sessionInfo, 'optionalAccess', _13 => _13.schoolYearName]), () => ( ""))
273
273
  }
274
274
  ),
275
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkRBJAO57Ajs.ProfileMenuSection, { children: [
275
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkFAAR4XC5js.ProfileMenuSection, { children: [
276
276
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
277
- _chunkRBJAO57Ajs.DropdownMenuItem,
277
+ _chunkFAAR4XC5js.DropdownMenuItem,
278
278
  {
279
279
  variant: "profile",
280
280
  iconLeft: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _User.UserIcon, {}),
@@ -283,9 +283,9 @@ var AppHeader = ({
283
283
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkANT66KVKjs.Text_default, { size: "md", color: "text-text-700", children: "Meus dados" })
284
284
  }
285
285
  ),
286
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRBJAO57Ajs.ProfileToggleTheme, {})
286
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkFAAR4XC5js.ProfileToggleTheme, {})
287
287
  ] }),
288
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRBJAO57Ajs.ProfileMenuFooter, { onClick: onLogout })
288
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkFAAR4XC5js.ProfileMenuFooter, { onClick: onLogout })
289
289
  ]
290
290
  }
291
291
  )
@@ -307,4 +307,4 @@ var AppHeader_default = AppHeader;
307
307
 
308
308
 
309
309
  exports.AppHeader = AppHeader; exports.AppHeader_default = AppHeader_default;
310
- //# sourceMappingURL=chunk-AVHZHWI3.js.map
310
+ //# sourceMappingURL=chunk-GBIFSFWJ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-AVHZHWI3.js","../src/components/AppHeader/AppHeader.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-AVHZHWI3.js","sourcesContent":[null,"import type { ReactNode } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport { CaretRightIcon } from '@phosphor-icons/react/dist/csr/CaretRight';\nimport { UserIcon as UserPhosphorIcon } from '@phosphor-icons/react/dist/csr/User';\n\nimport { BrandingLogo } from '../BrandingLogo/BrandingLogo';\nimport CalendarCard from '../CalendarCard/CalendarCard';\nimport IconButton from '../IconButton/IconButton';\nimport DropdownMenu, {\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n ProfileMenuFooter,\n ProfileMenuHeader,\n ProfileMenuInfo,\n ProfileMenuSection,\n ProfileToggleTheme,\n} from '../DropdownMenu/DropdownMenu';\nimport NotificationCard, {\n type NotificationGroup,\n} from '../NotificationCard/NotificationCard';\nimport { PageContainer } from '../PageContainer/PageContainer';\nimport Text from '../Text/Text';\nimport { UserIcon } from '../UserIcon/UserIcon';\nimport { useMobile } from '../../hooks/useMobile';\nimport { syncDropdownState } from '../../utils/dropdown';\nimport {\n NotificationEntityType,\n NotificationEntityStatus,\n} from '../../types/notifications';\n\n/**\n * Subset of session info consumed by the application header.\n * Each property is optional so the consumer can pass whatever it has.\n */\nexport interface AppHeaderSessionInfo {\n userName?: string;\n email?: string;\n urlProfilePicture?: string;\n schoolName?: string;\n className?: string;\n schoolYearName?: string;\n}\n\n/**\n * Minimal user shape needed to fill the profile dropdown header.\n */\nexport interface AppHeaderUser {\n name?: string;\n email?: string;\n}\n\n/**\n * Tutorial action rendered as a pill button in the header (left of the\n * notifications bell). The consumer owns the click behavior (usually opening\n * the configured tutorial URL in a new tab).\n */\nexport interface AppHeaderTutorial {\n /** Show the tutorial button. */\n visible?: boolean;\n /** Button label. Defaults to \"Tutoriais\". */\n label?: string;\n /** Fired when the tutorial button is clicked. */\n onClick: () => void;\n}\n\n/**\n * Notifications data + callbacks the AppHeader forwards to NotificationCard.\n * Built by the consumer (usually via `createNotificationsHook(api)`).\n */\nexport interface AppHeaderNotifications {\n unreadCount: number;\n loading: boolean;\n error: string | null;\n groupedNotifications: NotificationGroup[];\n refreshNotifications: () => void;\n markAsRead: (id: string) => void;\n deleteNotification: (id: string) => void;\n fetchNotifications: () => void;\n fetchUnreadCount?: () => void;\n /**\n * Optional bulk action. When provided, the \"Marcar todas como lidas\" button\n * renders in the notification center; when omitted, it stays hidden, which is\n * the behaviour every consumer had before this prop existed.\n */\n markAllAsRead?: () => void;\n getActionLabel: (entityType?: NotificationEntityType) => string | undefined;\n}\n\nexport interface AppHeaderProps {\n /** Authenticated user (fallback when sessionInfo doesn't carry name/email). */\n user?: AppHeaderUser;\n /** Session metadata used to render profile name, email, photo and school info. */\n sessionInfo?: AppHeaderSessionInfo;\n /** Notifications wiring (state + callbacks). */\n notifications: AppHeaderNotifications;\n /** Tutorial pill button shown before the notifications bell. */\n tutorial?: AppHeaderTutorial;\n /** Show the calendar widget in the header. */\n showCalendar?: boolean;\n /** Content rendered inside the calendar (dropdown on tablet/desktop, modal on mobile). */\n calendarContent?: ReactNode;\n /**\n * Optional controlled open state for the calendar.\n * When provided, the consumer is the source of truth; useful for closing\n * the calendar programmatically (e.g. on route change).\n */\n calendarOpen?: boolean;\n /** Fired whenever the calendar open state changes. */\n onCalendarOpenChange?: (open: boolean) => void;\n /** Show school/class/year inside the profile dropdown. */\n showProfileInfo?: boolean;\n /** Optional fallback image for the notifications empty state. */\n emptyNotificationsImage?: string;\n /** Empty-state title for notifications dropdown. */\n emptyNotificationsTitle?: string;\n /** Empty-state description for notifications dropdown. */\n emptyNotificationsDescription?: string;\n /** Callback fired when the user activates logout. */\n onLogout: () => void;\n /** Callback fired when the user activates the \"My data\" menu item. */\n onNavigateToMyData: () => void;\n /** Callback fired when the user clicks on a notification with entity info. */\n onNavigateByNotification?: (\n entityType?: NotificationEntityType,\n entityId?: string,\n entityStatus?: NotificationEntityStatus | null,\n questionId?: string | null\n ) => void;\n /**\n * Tailwind class overriding the default `max-w-[1000px]` of the header\n * content (forwarded to the internal `PageContainer`'s `innerClassName`).\n * Pass e.g. `max-w-[1350px]` to align the header with a widened page\n * content. When omitted, the default `max-w-[1000px]` is kept, so other\n * consumers are unaffected.\n */\n contentMaxWidth?: string;\n}\n\nconst DEFAULT_EMPTY_TITLE = 'Nenhuma notificação no momento';\nconst DEFAULT_EMPTY_DESCRIPTION =\n 'Você está em dia com todas as novidades. Volte depois para conferir atualizações!';\n\n/**\n * Application header shared across the analytica frontends.\n *\n * Renders the institution logo, optional calendar dropdown (mobile/tablet),\n * notifications center and a profile menu. Width is constrained by\n * `<PageContainer>` so it always aligns with the rest of the page content.\n */\nexport const AppHeader = ({\n user,\n sessionInfo,\n notifications,\n tutorial,\n showCalendar = false,\n calendarContent,\n calendarOpen,\n onCalendarOpenChange,\n showProfileInfo = false,\n emptyNotificationsImage,\n emptyNotificationsTitle = DEFAULT_EMPTY_TITLE,\n emptyNotificationsDescription = DEFAULT_EMPTY_DESCRIPTION,\n onLogout,\n onNavigateToMyData,\n onNavigateByNotification,\n contentMaxWidth,\n}: AppHeaderProps) => {\n const { isMobile, isExtraSmallMobile } = useMobile();\n const [activeStates, setActiveStates] = useState<Record<string, boolean>>({});\n\n useEffect(() => {\n notifications.fetchUnreadCount?.();\n }, []);\n\n const toggleActive = (buttonId: string) => {\n setActiveStates((prev) => {\n if (prev[buttonId]) {\n return { ...prev, [buttonId]: false };\n }\n return {\n calendar: false,\n notifications: false,\n profile: false,\n [buttonId]: true,\n };\n });\n };\n\n // Stable callback so `DropdownMenu`'s `useEffect [open, onOpenChange]`\n // doesn't re-fire on every parent re-render, which would cascade into a\n // Maximum-update-depth loop (same root cause class as PR #435).\n const handleCalendarOpenChange = useCallback(\n (open: boolean) => {\n setActiveStates((prev) => {\n const current = prev.calendar ?? false;\n if (current === open) {\n return prev;\n }\n if (open) {\n return {\n calendar: true,\n notifications: false,\n profile: false,\n };\n }\n return { ...prev, calendar: false };\n });\n onCalendarOpenChange?.(open);\n },\n [onCalendarOpenChange]\n );\n\n useEffect(() => {\n const handleEscapeKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setActiveStates({});\n }\n };\n document.addEventListener('keydown', handleEscapeKey);\n return () => document.removeEventListener('keydown', handleEscapeKey);\n }, []);\n\n const handleMyDataClick = () => {\n setActiveStates({});\n onNavigateToMyData();\n };\n\n const displayName = sessionInfo?.userName ?? user?.name ?? 'Usuário';\n const displayEmail = sessionInfo?.email ?? user?.email ?? '';\n\n const pickResponsiveClass = (\n extraSmall: string,\n mobile: string,\n desktop: string\n ): string => {\n if (isExtraSmallMobile) return extraSmall;\n if (isMobile) return mobile;\n return desktop;\n };\n // On mobile the menu is anchored to the right of the trigger, so a min-width\n // alone lets it overflow the left edge of narrow viewports. Cap it to the\n // viewport minus a 16px gutter on each side.\n const profileDropdownWidth = isMobile\n ? 'w-[calc(100vw-2rem)] max-w-[320px]'\n : 'min-w-[320px]';\n const sectionGap = pickResponsiveClass('gap-1', 'gap-2', 'gap-3');\n const logoHeight = pickResponsiveClass('h-6', 'h-8', 'h-10');\n const tutorialPadding = pickResponsiveClass(\n 'px-3 py-1.5 text-xs',\n 'px-3.5 py-2 text-sm',\n 'px-4 py-2 text-sm'\n );\n\n return (\n <header\n data-component=\"AppHeader\"\n className=\"bg-primary-800 w-full h-[70px] flex justify-center items-center\"\n >\n <PageContainer\n className=\"pb-0 justify-center\"\n innerClassName={contentMaxWidth}\n >\n <div className=\"w-full flex flex-row justify-between items-center gap-3\">\n {/* `min-w-0 shrink` lets the logo compress instead of overflowing:\n an <img> resolves `min-width:auto` to its intrinsic width, which\n would otherwise block flex-shrink and push the actions off-screen\n on narrow viewports. `object-left` keeps it left-aligned as it\n scales down. The actions never shrink. */}\n <BrandingLogo\n variant=\"main\"\n alt=\"Logo\"\n className={`${logoHeight} object-contain object-left min-w-0 shrink`}\n />\n <section\n className={`flex flex-row items-center shrink-0 ${sectionGap}`}\n >\n {tutorial?.visible && (\n <button\n type=\"button\"\n data-testid=\"app-header-tutorial\"\n onClick={tutorial.onClick}\n /* `primary` (não `text`) é o foreground de `primary-800` em\n todos os temas — os dois formam um par contrastante mesmo\n onde o dark inverte o header (paraiba/analytica). Usar\n `text-*` aqui inverteria com o modo enquanto o fundo do\n header não inverte, apagando o botão no dark. */\n className={`rounded-full border border-primary text-primary font-medium whitespace-nowrap cursor-pointer transition-colors hover:bg-primary-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${tutorialPadding}`}\n >\n {tutorial.label ?? 'Tutoriais'}\n </button>\n )}\n\n {showCalendar && (\n <div className=\"lg:hidden\">\n <CalendarCard\n content={calendarContent}\n isOpen={calendarOpen ?? activeStates.calendar ?? false}\n onOpenChange={handleCalendarOpenChange}\n />\n </div>\n )}\n\n <NotificationCard\n mode=\"center\"\n isActive={activeStates.notifications}\n onToggleActive={() => toggleActive('notifications')}\n onOpenChange={(open: boolean) => {\n syncDropdownState(\n open,\n activeStates.notifications,\n setActiveStates,\n 'notifications'\n );\n }}\n unreadCount={notifications.unreadCount}\n groupedNotifications={notifications.groupedNotifications}\n loading={notifications.loading}\n error={notifications.error}\n onRetry={notifications.refreshNotifications}\n onMarkAsReadById={notifications.markAsRead}\n onMarkAllAsRead={notifications.markAllAsRead}\n onDeleteById={notifications.deleteNotification}\n onNavigateById={(\n entityType,\n entityId,\n entityStatus,\n questionId\n ) => {\n if (entityType && entityId) {\n // Fecha o painel antes de navegar. Sem isso, quando o destino\n // é a própria página em que o usuário já está (ex.: ele\n // termina a atividade, cai no resultado, abre o sino e clica\n // em \"Ver resultado\" da notificação dessa mesma atividade),\n // o navigate para a rota atual não muda nada na tela, o\n // painel segue aberto e ele clica de novo — rage click\n // FRONTEND-ALUNO-WEB-F3, 91 ocorrências / 36 usuários em seis\n // semanas. Fechar o painel é o feedback visível que faltava,\n // e vale para qualquer destino.\n //\n // É um setState em handler de clique, não em render/efeito:\n // não reabre o loop do PR #435. E o onOpenChange que o\n // DropdownMenu dispara ao fechar vira no-op no\n // syncDropdownState, porque isActive já estará false.\n setActiveStates((prev) => ({\n ...prev,\n notifications: false,\n }));\n onNavigateByNotification?.(\n entityType,\n entityId,\n entityStatus,\n questionId\n );\n }\n }}\n getActionLabel={notifications.getActionLabel}\n onFetchNotifications={notifications.fetchNotifications}\n emptyStateImage={emptyNotificationsImage}\n emptyStateTitle={emptyNotificationsTitle}\n emptyStateDescription={emptyNotificationsDescription}\n />\n\n <DropdownMenu\n onOpenChange={(open: boolean) => {\n syncDropdownState(\n open,\n activeStates.profile,\n setActiveStates,\n 'profile'\n );\n }}\n >\n <DropdownMenuTrigger\n className=\"text-primary cursor-pointer\"\n asChild\n >\n <IconButton\n active={activeStates.profile}\n // O IconButton só tem ícone: sem rótulo próprio ele cai no\n // padrão \"Botão de ação\", que não diz o que abre.\n aria-label=\"Perfil do usuário\"\n onClick={() => toggleActive('profile')}\n icon={\n <UserIcon\n size={24}\n className={activeStates.profile ? 'opacity-80' : ''}\n />\n }\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className={profileDropdownWidth}\n side=\"bottom\"\n variant=\"profile\"\n align=\"end\"\n >\n <ProfileMenuHeader\n className={isMobile ? 'min-w-0' : undefined}\n name={displayName}\n email={displayEmail}\n photoUrl={sessionInfo?.urlProfilePicture}\n />\n\n {showProfileInfo && (\n <ProfileMenuInfo\n schoolName={sessionInfo?.schoolName ?? ''}\n classYearName={sessionInfo?.className ?? ''}\n schoolYearName={sessionInfo?.schoolYearName ?? ''}\n />\n )}\n\n <ProfileMenuSection>\n <DropdownMenuItem\n variant=\"profile\"\n iconLeft={<UserPhosphorIcon />}\n iconRight={<CaretRightIcon />}\n onClick={handleMyDataClick}\n >\n <Text size=\"md\" color=\"text-text-700\">\n Meus dados\n </Text>\n </DropdownMenuItem>\n\n <ProfileToggleTheme />\n </ProfileMenuSection>\n\n <ProfileMenuFooter onClick={onLogout} />\n </DropdownMenuContent>\n </DropdownMenu>\n </section>\n </div>\n </PageContainer>\n </header>\n );\n};\n\nexport default AppHeader;\n"]}
1
+ {"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-GBIFSFWJ.js","../src/components/AppHeader/AppHeader.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-GBIFSFWJ.js","sourcesContent":[null,"import type { ReactNode } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\nimport { CaretRightIcon } from '@phosphor-icons/react/dist/csr/CaretRight';\nimport { UserIcon as UserPhosphorIcon } from '@phosphor-icons/react/dist/csr/User';\n\nimport { BrandingLogo } from '../BrandingLogo/BrandingLogo';\nimport CalendarCard from '../CalendarCard/CalendarCard';\nimport IconButton from '../IconButton/IconButton';\nimport DropdownMenu, {\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n ProfileMenuFooter,\n ProfileMenuHeader,\n ProfileMenuInfo,\n ProfileMenuSection,\n ProfileToggleTheme,\n} from '../DropdownMenu/DropdownMenu';\nimport NotificationCard, {\n type NotificationGroup,\n} from '../NotificationCard/NotificationCard';\nimport { PageContainer } from '../PageContainer/PageContainer';\nimport Text from '../Text/Text';\nimport { UserIcon } from '../UserIcon/UserIcon';\nimport { useMobile } from '../../hooks/useMobile';\nimport { syncDropdownState } from '../../utils/dropdown';\nimport {\n NotificationEntityType,\n NotificationEntityStatus,\n} from '../../types/notifications';\n\n/**\n * Subset of session info consumed by the application header.\n * Each property is optional so the consumer can pass whatever it has.\n */\nexport interface AppHeaderSessionInfo {\n userName?: string;\n email?: string;\n urlProfilePicture?: string;\n schoolName?: string;\n className?: string;\n schoolYearName?: string;\n}\n\n/**\n * Minimal user shape needed to fill the profile dropdown header.\n */\nexport interface AppHeaderUser {\n name?: string;\n email?: string;\n}\n\n/**\n * Tutorial action rendered as a pill button in the header (left of the\n * notifications bell). The consumer owns the click behavior (usually opening\n * the configured tutorial URL in a new tab).\n */\nexport interface AppHeaderTutorial {\n /** Show the tutorial button. */\n visible?: boolean;\n /** Button label. Defaults to \"Tutoriais\". */\n label?: string;\n /** Fired when the tutorial button is clicked. */\n onClick: () => void;\n}\n\n/**\n * Notifications data + callbacks the AppHeader forwards to NotificationCard.\n * Built by the consumer (usually via `createNotificationsHook(api)`).\n */\nexport interface AppHeaderNotifications {\n unreadCount: number;\n loading: boolean;\n error: string | null;\n groupedNotifications: NotificationGroup[];\n refreshNotifications: () => void;\n markAsRead: (id: string) => void;\n deleteNotification: (id: string) => void;\n fetchNotifications: () => void;\n fetchUnreadCount?: () => void;\n /**\n * Optional bulk action. When provided, the \"Marcar todas como lidas\" button\n * renders in the notification center; when omitted, it stays hidden, which is\n * the behaviour every consumer had before this prop existed.\n */\n markAllAsRead?: () => void;\n getActionLabel: (entityType?: NotificationEntityType) => string | undefined;\n}\n\nexport interface AppHeaderProps {\n /** Authenticated user (fallback when sessionInfo doesn't carry name/email). */\n user?: AppHeaderUser;\n /** Session metadata used to render profile name, email, photo and school info. */\n sessionInfo?: AppHeaderSessionInfo;\n /** Notifications wiring (state + callbacks). */\n notifications: AppHeaderNotifications;\n /** Tutorial pill button shown before the notifications bell. */\n tutorial?: AppHeaderTutorial;\n /** Show the calendar widget in the header. */\n showCalendar?: boolean;\n /** Content rendered inside the calendar (dropdown on tablet/desktop, modal on mobile). */\n calendarContent?: ReactNode;\n /**\n * Optional controlled open state for the calendar.\n * When provided, the consumer is the source of truth; useful for closing\n * the calendar programmatically (e.g. on route change).\n */\n calendarOpen?: boolean;\n /** Fired whenever the calendar open state changes. */\n onCalendarOpenChange?: (open: boolean) => void;\n /** Show school/class/year inside the profile dropdown. */\n showProfileInfo?: boolean;\n /** Optional fallback image for the notifications empty state. */\n emptyNotificationsImage?: string;\n /** Empty-state title for notifications dropdown. */\n emptyNotificationsTitle?: string;\n /** Empty-state description for notifications dropdown. */\n emptyNotificationsDescription?: string;\n /** Callback fired when the user activates logout. */\n onLogout: () => void;\n /** Callback fired when the user activates the \"My data\" menu item. */\n onNavigateToMyData: () => void;\n /** Callback fired when the user clicks on a notification with entity info. */\n onNavigateByNotification?: (\n entityType?: NotificationEntityType,\n entityId?: string,\n entityStatus?: NotificationEntityStatus | null,\n questionId?: string | null\n ) => void;\n /**\n * Tailwind class overriding the default `max-w-[1000px]` of the header\n * content (forwarded to the internal `PageContainer`'s `innerClassName`).\n * Pass e.g. `max-w-[1350px]` to align the header with a widened page\n * content. When omitted, the default `max-w-[1000px]` is kept, so other\n * consumers are unaffected.\n */\n contentMaxWidth?: string;\n}\n\nconst DEFAULT_EMPTY_TITLE = 'Nenhuma notificação no momento';\nconst DEFAULT_EMPTY_DESCRIPTION =\n 'Você está em dia com todas as novidades. Volte depois para conferir atualizações!';\n\n/**\n * Application header shared across the analytica frontends.\n *\n * Renders the institution logo, optional calendar dropdown (mobile/tablet),\n * notifications center and a profile menu. Width is constrained by\n * `<PageContainer>` so it always aligns with the rest of the page content.\n */\nexport const AppHeader = ({\n user,\n sessionInfo,\n notifications,\n tutorial,\n showCalendar = false,\n calendarContent,\n calendarOpen,\n onCalendarOpenChange,\n showProfileInfo = false,\n emptyNotificationsImage,\n emptyNotificationsTitle = DEFAULT_EMPTY_TITLE,\n emptyNotificationsDescription = DEFAULT_EMPTY_DESCRIPTION,\n onLogout,\n onNavigateToMyData,\n onNavigateByNotification,\n contentMaxWidth,\n}: AppHeaderProps) => {\n const { isMobile, isExtraSmallMobile } = useMobile();\n const [activeStates, setActiveStates] = useState<Record<string, boolean>>({});\n\n useEffect(() => {\n notifications.fetchUnreadCount?.();\n }, []);\n\n const toggleActive = (buttonId: string) => {\n setActiveStates((prev) => {\n if (prev[buttonId]) {\n return { ...prev, [buttonId]: false };\n }\n return {\n calendar: false,\n notifications: false,\n profile: false,\n [buttonId]: true,\n };\n });\n };\n\n // Stable callback so `DropdownMenu`'s `useEffect [open, onOpenChange]`\n // doesn't re-fire on every parent re-render, which would cascade into a\n // Maximum-update-depth loop (same root cause class as PR #435).\n const handleCalendarOpenChange = useCallback(\n (open: boolean) => {\n setActiveStates((prev) => {\n const current = prev.calendar ?? false;\n if (current === open) {\n return prev;\n }\n if (open) {\n return {\n calendar: true,\n notifications: false,\n profile: false,\n };\n }\n return { ...prev, calendar: false };\n });\n onCalendarOpenChange?.(open);\n },\n [onCalendarOpenChange]\n );\n\n useEffect(() => {\n const handleEscapeKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setActiveStates({});\n }\n };\n document.addEventListener('keydown', handleEscapeKey);\n return () => document.removeEventListener('keydown', handleEscapeKey);\n }, []);\n\n const handleMyDataClick = () => {\n setActiveStates({});\n onNavigateToMyData();\n };\n\n const displayName = sessionInfo?.userName ?? user?.name ?? 'Usuário';\n const displayEmail = sessionInfo?.email ?? user?.email ?? '';\n\n const pickResponsiveClass = (\n extraSmall: string,\n mobile: string,\n desktop: string\n ): string => {\n if (isExtraSmallMobile) return extraSmall;\n if (isMobile) return mobile;\n return desktop;\n };\n // On mobile the menu is anchored to the right of the trigger, so a min-width\n // alone lets it overflow the left edge of narrow viewports. Cap it to the\n // viewport minus a 16px gutter on each side.\n const profileDropdownWidth = isMobile\n ? 'w-[calc(100vw-2rem)] max-w-[320px]'\n : 'min-w-[320px]';\n const sectionGap = pickResponsiveClass('gap-1', 'gap-2', 'gap-3');\n const logoHeight = pickResponsiveClass('h-6', 'h-8', 'h-10');\n const tutorialPadding = pickResponsiveClass(\n 'px-3 py-1.5 text-xs',\n 'px-3.5 py-2 text-sm',\n 'px-4 py-2 text-sm'\n );\n\n return (\n <header\n data-component=\"AppHeader\"\n className=\"bg-primary-800 w-full h-[70px] flex justify-center items-center\"\n >\n <PageContainer\n className=\"pb-0 justify-center\"\n innerClassName={contentMaxWidth}\n >\n <div className=\"w-full flex flex-row justify-between items-center gap-3\">\n {/* `min-w-0 shrink` lets the logo compress instead of overflowing:\n an <img> resolves `min-width:auto` to its intrinsic width, which\n would otherwise block flex-shrink and push the actions off-screen\n on narrow viewports. `object-left` keeps it left-aligned as it\n scales down. The actions never shrink. */}\n <BrandingLogo\n variant=\"main\"\n alt=\"Logo\"\n className={`${logoHeight} object-contain object-left min-w-0 shrink`}\n />\n <section\n className={`flex flex-row items-center shrink-0 ${sectionGap}`}\n >\n {tutorial?.visible && (\n <button\n type=\"button\"\n data-testid=\"app-header-tutorial\"\n onClick={tutorial.onClick}\n /* `primary` (não `text`) é o foreground de `primary-800` em\n todos os temas — os dois formam um par contrastante mesmo\n onde o dark inverte o header (paraiba/analytica). Usar\n `text-*` aqui inverteria com o modo enquanto o fundo do\n header não inverte, apagando o botão no dark. */\n className={`rounded-full border border-primary text-primary font-medium whitespace-nowrap cursor-pointer transition-colors hover:bg-primary-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${tutorialPadding}`}\n >\n {tutorial.label ?? 'Tutoriais'}\n </button>\n )}\n\n {showCalendar && (\n <div className=\"lg:hidden\">\n <CalendarCard\n content={calendarContent}\n isOpen={calendarOpen ?? activeStates.calendar ?? false}\n onOpenChange={handleCalendarOpenChange}\n />\n </div>\n )}\n\n <NotificationCard\n mode=\"center\"\n isActive={activeStates.notifications}\n onToggleActive={() => toggleActive('notifications')}\n onOpenChange={(open: boolean) => {\n syncDropdownState(\n open,\n activeStates.notifications,\n setActiveStates,\n 'notifications'\n );\n }}\n unreadCount={notifications.unreadCount}\n groupedNotifications={notifications.groupedNotifications}\n loading={notifications.loading}\n error={notifications.error}\n onRetry={notifications.refreshNotifications}\n onMarkAsReadById={notifications.markAsRead}\n onMarkAllAsRead={notifications.markAllAsRead}\n onDeleteById={notifications.deleteNotification}\n onNavigateById={(\n entityType,\n entityId,\n entityStatus,\n questionId\n ) => {\n if (entityType && entityId) {\n // Fecha o painel antes de navegar. Sem isso, quando o destino\n // é a própria página em que o usuário já está (ex.: ele\n // termina a atividade, cai no resultado, abre o sino e clica\n // em \"Ver resultado\" da notificação dessa mesma atividade),\n // o navigate para a rota atual não muda nada na tela, o\n // painel segue aberto e ele clica de novo — rage click\n // FRONTEND-ALUNO-WEB-F3, 91 ocorrências / 36 usuários em seis\n // semanas. Fechar o painel é o feedback visível que faltava,\n // e vale para qualquer destino.\n //\n // É um setState em handler de clique, não em render/efeito:\n // não reabre o loop do PR #435. E o onOpenChange que o\n // DropdownMenu dispara ao fechar vira no-op no\n // syncDropdownState, porque isActive já estará false.\n setActiveStates((prev) => ({\n ...prev,\n notifications: false,\n }));\n onNavigateByNotification?.(\n entityType,\n entityId,\n entityStatus,\n questionId\n );\n }\n }}\n getActionLabel={notifications.getActionLabel}\n onFetchNotifications={notifications.fetchNotifications}\n emptyStateImage={emptyNotificationsImage}\n emptyStateTitle={emptyNotificationsTitle}\n emptyStateDescription={emptyNotificationsDescription}\n />\n\n <DropdownMenu\n onOpenChange={(open: boolean) => {\n syncDropdownState(\n open,\n activeStates.profile,\n setActiveStates,\n 'profile'\n );\n }}\n >\n <DropdownMenuTrigger\n className=\"text-primary cursor-pointer\"\n asChild\n >\n <IconButton\n active={activeStates.profile}\n // O IconButton só tem ícone: sem rótulo próprio ele cai no\n // padrão \"Botão de ação\", que não diz o que abre.\n aria-label=\"Perfil do usuário\"\n onClick={() => toggleActive('profile')}\n icon={\n <UserIcon\n size={24}\n className={activeStates.profile ? 'opacity-80' : ''}\n />\n }\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className={profileDropdownWidth}\n side=\"bottom\"\n variant=\"profile\"\n align=\"end\"\n >\n <ProfileMenuHeader\n className={isMobile ? 'min-w-0' : undefined}\n name={displayName}\n email={displayEmail}\n photoUrl={sessionInfo?.urlProfilePicture}\n />\n\n {showProfileInfo && (\n <ProfileMenuInfo\n schoolName={sessionInfo?.schoolName ?? ''}\n classYearName={sessionInfo?.className ?? ''}\n schoolYearName={sessionInfo?.schoolYearName ?? ''}\n />\n )}\n\n <ProfileMenuSection>\n <DropdownMenuItem\n variant=\"profile\"\n iconLeft={<UserPhosphorIcon />}\n iconRight={<CaretRightIcon />}\n onClick={handleMyDataClick}\n >\n <Text size=\"md\" color=\"text-text-700\">\n Meus dados\n </Text>\n </DropdownMenuItem>\n\n <ProfileToggleTheme />\n </ProfileMenuSection>\n\n <ProfileMenuFooter onClick={onLogout} />\n </DropdownMenuContent>\n </DropdownMenu>\n </section>\n </div>\n </PageContainer>\n </header>\n );\n};\n\nexport default AppHeader;\n"]}