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.
- package/dist/AccessReportModal/index.js +3 -3
- package/dist/AccessReportModal/index.mjs +2 -2
- package/dist/ActivitiesHistory/index.js +49 -49
- package/dist/ActivitiesHistory/index.mjs +48 -48
- package/dist/ActivityCardQuestionBanks/index.js +49 -49
- package/dist/ActivityCardQuestionBanks/index.mjs +48 -48
- package/dist/ActivityCardQuestionPreview/index.js +49 -49
- package/dist/ActivityCardQuestionPreview/index.mjs +48 -48
- package/dist/ActivityCreate/ActivityCreateContent/index.js +49 -49
- package/dist/ActivityCreate/ActivityCreateContent/index.mjs +48 -48
- package/dist/ActivityCreate/index.js +49 -49
- package/dist/ActivityCreate/index.mjs +48 -48
- package/dist/ActivityDetails/index.js +49 -49
- package/dist/ActivityDetails/index.mjs +48 -48
- package/dist/ActivityFilters/index.js +49 -49
- package/dist/ActivityFilters/index.mjs +48 -48
- package/dist/ActivityPageLayout/index.js +49 -49
- package/dist/ActivityPageLayout/index.mjs +48 -48
- package/dist/ActivityPreview/index.js +49 -49
- package/dist/ActivityPreview/index.mjs +48 -48
- package/dist/AlertManager/index.js +49 -49
- package/dist/AlertManager/index.mjs +48 -48
- package/dist/AlertManagerView/index.js +3 -3
- package/dist/AlertManagerView/index.mjs +2 -2
- package/dist/AnnouncementModal/index.js +3 -3
- package/dist/AnnouncementModal/index.mjs +2 -2
- package/dist/AnnouncementsGate/index.js +4 -4
- package/dist/AnnouncementsGate/index.mjs +3 -3
- package/dist/AnswerKeyModal/index.js +3 -3
- package/dist/AnswerKeyModal/index.mjs +2 -2
- package/dist/AppHeader/index.js +6 -6
- package/dist/AppHeader/index.mjs +5 -5
- package/dist/CalendarCard/index.js +4 -4
- package/dist/CalendarCard/index.mjs +3 -3
- package/dist/Chat/index.js +3 -3
- package/dist/Chat/index.mjs +2 -2
- package/dist/CheckBox/index.d.ts.map +1 -1
- package/dist/CheckBox/index.js +2 -2
- package/dist/CheckBox/index.mjs +1 -1
- package/dist/CheckBoxGroup/index.js +49 -49
- package/dist/CheckBoxGroup/index.mjs +48 -48
- package/dist/ComparatorChart/ComparatorView/index.js +3 -3
- package/dist/ComparatorChart/ComparatorView/index.mjs +2 -2
- package/dist/CorrectActivityModal/index.js +7 -7
- package/dist/CorrectActivityModal/index.mjs +6 -6
- package/dist/DownloadButton/index.js +4 -4
- package/dist/DownloadButton/index.mjs +3 -3
- package/dist/DownloadModal/index.js +3 -3
- package/dist/DownloadModal/index.mjs +2 -2
- package/dist/DropdownMenu/index.js +3 -3
- package/dist/DropdownMenu/index.mjs +2 -2
- package/dist/EnemClassroomStartModal/index.d.ts.map +1 -1
- package/dist/EnemClassroomStartModal/index.js +7 -7
- package/dist/EnemClassroomStartModal/index.mjs +6 -6
- package/dist/EnemMoment/index.js +57 -57
- package/dist/EnemMoment/index.mjs +51 -51
- package/dist/EnemMomentStudentModal/index.js +50 -50
- package/dist/EnemMomentStudentModal/index.mjs +48 -48
- package/dist/ExamDetailsLayout/ExamDetailsPage/index.js +49 -49
- package/dist/ExamDetailsLayout/ExamDetailsPage/index.mjs +48 -48
- package/dist/ExamPageLayout/index.js +49 -49
- package/dist/ExamPageLayout/index.mjs +48 -48
- package/dist/Forum/index.js +5 -5
- package/dist/Forum/index.mjs +4 -4
- package/dist/KnowledgePerformanceCard/index.js +51 -51
- package/dist/KnowledgePerformanceCard/index.mjs +50 -50
- package/dist/LessonCardPreview/index.js +49 -49
- package/dist/LessonCardPreview/index.mjs +48 -48
- package/dist/LessonMediaSections/index.js +49 -49
- package/dist/LessonMediaSections/index.mjs +48 -48
- package/dist/LessonsCatalog/index.js +49 -49
- package/dist/LessonsCatalog/index.mjs +48 -48
- package/dist/Modal/index.d.ts.map +1 -1
- package/dist/Modal/index.js +2 -2
- package/dist/Modal/index.mjs +1 -1
- package/dist/MultiCheckSelect/index.js +5 -5
- package/dist/MultiCheckSelect/index.mjs +4 -4
- package/dist/MultiSearchSelect/index.js +3 -3
- package/dist/MultiSearchSelect/index.mjs +2 -2
- package/dist/MultipleChoice/index.js +3 -3
- package/dist/MultipleChoice/index.mjs +2 -2
- package/dist/NotificationCard/index.js +4 -4
- package/dist/NotificationCard/index.mjs +3 -3
- package/dist/PerformanceReportModal/index.js +3 -3
- package/dist/PerformanceReportModal/index.mjs +2 -2
- package/dist/PrintableUsersTable/index.js +49 -49
- package/dist/PrintableUsersTable/index.mjs +48 -48
- package/dist/ProgressModal/index.js +3 -3
- package/dist/ProgressModal/index.mjs +2 -2
- package/dist/QuestionsPerformanceCard/index.js +50 -50
- package/dist/QuestionsPerformanceCard/index.mjs +49 -49
- package/dist/Quiz/index.js +6 -6
- package/dist/Quiz/index.mjs +5 -5
- package/dist/RecommendedLessonCreate/index.js +49 -49
- package/dist/RecommendedLessonCreate/index.mjs +48 -48
- package/dist/RecommendedLessonDetails/index.js +7 -7
- package/dist/RecommendedLessonDetails/index.mjs +6 -6
- package/dist/RecommendedLessonsHistory/index.js +49 -49
- package/dist/RecommendedLessonsHistory/index.mjs +48 -48
- package/dist/ReportDetailModal/index.js +4 -4
- package/dist/ReportDetailModal/index.mjs +3 -3
- package/dist/RichEditor/index.js +5 -5
- package/dist/RichEditor/index.mjs +4 -4
- package/dist/{RichEditorCore-6MTYSSKS.mjs → RichEditorCore-2S5YUAOI.mjs} +5 -5
- package/dist/{RichEditorCore-KDARBEK4.js → RichEditorCore-N7A2445B.js} +16 -16
- package/dist/{RichEditorCore-KDARBEK4.js.map → RichEditorCore-N7A2445B.js.map} +1 -1
- package/dist/Search/index.js +4 -4
- package/dist/Search/index.mjs +3 -3
- package/dist/SendActivityModal/SendActivityModal.js +49 -49
- package/dist/SendActivityModal/SendActivityModal.mjs +48 -48
- package/dist/SendActivityModal/index.js +49 -49
- package/dist/SendActivityModal/index.mjs +48 -48
- package/dist/SendLessonModal/index.js +49 -49
- package/dist/SendLessonModal/index.mjs +48 -48
- package/dist/SimulatedPerformance/SimulatedPerformanceView/index.js +49 -49
- package/dist/SimulatedPerformance/SimulatedPerformanceView/index.mjs +48 -48
- package/dist/SimulatedPerformance/useSimulatedPerformance/index.js +5 -5
- package/dist/SimulatedPerformance/useSimulatedPerformance/index.mjs +4 -4
- package/dist/SimulatedStudentSimulationsModal/index.js +6 -6
- package/dist/SimulatedStudentSimulationsModal/index.mjs +5 -5
- package/dist/SimulationsPage/index.js +49 -49
- package/dist/SimulationsPage/index.mjs +48 -48
- package/dist/StudentLessonProgressModal/index.js +3 -3
- package/dist/StudentLessonProgressModal/index.mjs +2 -2
- package/dist/StudentPerformanceDetailsModal/index.js +5 -5
- package/dist/StudentPerformanceDetailsModal/index.mjs +4 -4
- package/dist/Support/TicketModal/index.js +3 -3
- package/dist/Support/TicketModal/index.mjs +2 -2
- package/dist/Support/index.js +4 -4
- package/dist/Support/index.mjs +3 -3
- package/dist/SupportChatComposer/index.js +3 -3
- package/dist/SupportChatComposer/index.mjs +2 -2
- package/dist/SupportChatEvent/index.js +3 -3
- package/dist/SupportChatEvent/index.mjs +2 -2
- package/dist/SupportChatMessage/index.js +3 -3
- package/dist/SupportChatMessage/index.mjs +2 -2
- package/dist/SupportChatWidget/index.js +3 -3
- package/dist/SupportChatWidget/index.mjs +2 -2
- package/dist/SupportConcludeModal/index.js +4 -4
- package/dist/SupportConcludeModal/index.mjs +3 -3
- package/dist/SupportConversationHeader/index.js +4 -4
- package/dist/SupportConversationHeader/index.mjs +3 -3
- package/dist/SupportConversationMessages/index.js +5 -5
- package/dist/SupportConversationMessages/index.mjs +4 -4
- package/dist/SupportTicketConversation/index.js +12 -12
- package/dist/SupportTicketConversation/index.mjs +11 -11
- package/dist/TableProvider/index.js +49 -49
- package/dist/TableProvider/index.mjs +48 -48
- package/dist/UnifiedDraftModelPage/index.js +49 -49
- package/dist/UnifiedDraftModelPage/index.mjs +48 -48
- package/dist/UnifiedHistoryPage/index.js +49 -49
- package/dist/UnifiedHistoryPage/index.mjs +48 -48
- package/dist/VideoPlayer/index.js +5 -5
- package/dist/VideoPlayer/index.mjs +4 -4
- package/dist/Whiteboard/index.js +3 -3
- package/dist/Whiteboard/index.mjs +2 -2
- package/dist/{chunk-B6QOBHZM.mjs → chunk-24BEZK43.mjs} +2 -2
- package/dist/{chunk-CYSODZGX.js → chunk-27Y6V3GM.js} +169 -66
- package/dist/chunk-27Y6V3GM.js.map +1 -0
- package/dist/{chunk-OQTXTDSK.mjs → chunk-2OJ3QSLU.mjs} +3 -3
- package/dist/{chunk-VDUO65VK.mjs → chunk-3EGJJDIM.mjs} +2 -2
- package/dist/{chunk-VDUO65VK.mjs.map → chunk-3EGJJDIM.mjs.map} +1 -1
- package/dist/{chunk-4OUBPEVS.mjs → chunk-3HKLGNUE.mjs} +3 -3
- package/dist/{chunk-YA7XLH7D.js → chunk-3MFACEZ2.js} +3 -3
- package/dist/{chunk-YA7XLH7D.js.map → chunk-3MFACEZ2.js.map} +1 -1
- package/dist/{chunk-IHBWJM4C.mjs → chunk-3Q7RJKUP.mjs} +2 -2
- package/dist/{chunk-PY6WD6SB.mjs → chunk-3WRB4WCD.mjs} +4 -4
- package/dist/{chunk-4RHCBMMP.js → chunk-46VHAL4S.js} +3 -3
- package/dist/{chunk-4RHCBMMP.js.map → chunk-46VHAL4S.js.map} +1 -1
- package/dist/{chunk-POT3ALY3.js → chunk-5DINXU6W.js} +1 -1
- package/dist/{chunk-POT3ALY3.js.map → chunk-5DINXU6W.js.map} +1 -1
- package/dist/{chunk-L52NFNFK.mjs → chunk-5VC4BK65.mjs} +3 -3
- package/dist/{chunk-B67RLIUM.js → chunk-72D7G6YQ.js} +3 -3
- package/dist/{chunk-B67RLIUM.js.map → chunk-72D7G6YQ.js.map} +1 -1
- package/dist/{chunk-C65DG2RI.mjs → chunk-7FSBWUOM.mjs} +2 -2
- package/dist/{chunk-QWMFWYII.js → chunk-7IZNLARX.js} +3 -3
- package/dist/{chunk-QWMFWYII.js.map → chunk-7IZNLARX.js.map} +1 -1
- package/dist/{chunk-ZCBT2BUZ.js → chunk-7RFHXFFV.js} +13 -13
- package/dist/{chunk-ZCBT2BUZ.js.map → chunk-7RFHXFFV.js.map} +1 -1
- package/dist/{chunk-EMWX6IKP.js → chunk-7VJP5D26.js} +13 -13
- package/dist/{chunk-EMWX6IKP.js.map → chunk-7VJP5D26.js.map} +1 -1
- package/dist/{chunk-HCQJR5CE.mjs → chunk-7ZWEBNFB.mjs} +2 -2
- package/dist/{chunk-3RHNJUXU.mjs → chunk-ACSEJOW6.mjs} +2 -2
- package/dist/{chunk-WQZHUW7C.mjs → chunk-ANFHLSDB.mjs} +3 -3
- package/dist/{chunk-H6NQOLQY.mjs → chunk-ANFLWCVD.mjs} +2 -2
- package/dist/{chunk-BKBDQXZX.js → chunk-AOYPUZRO.js} +3 -3
- package/dist/{chunk-BKBDQXZX.js.map → chunk-AOYPUZRO.js.map} +1 -1
- package/dist/{chunk-5WS6IENQ.mjs → chunk-AU2HLQDJ.mjs} +2 -2
- package/dist/{chunk-P6FX3NT6.mjs → chunk-AZGDHAP5.mjs} +2 -2
- package/dist/{chunk-NCGO7FPB.js → chunk-AZKNYREH.js} +8 -8
- package/dist/{chunk-NCGO7FPB.js.map → chunk-AZKNYREH.js.map} +1 -1
- package/dist/{chunk-R6MTPYYW.js → chunk-AZTBNERQ.js} +3 -3
- package/dist/{chunk-R6MTPYYW.js.map → chunk-AZTBNERQ.js.map} +1 -1
- package/dist/{chunk-NPB2JTYC.mjs → chunk-BO3QVQ37.mjs} +4 -4
- package/dist/{chunk-2WI4Q2I2.mjs → chunk-BPMWRFSI.mjs} +4 -4
- package/dist/{chunk-TEW33GLR.mjs → chunk-BXN3VO6I.mjs} +2 -2
- package/dist/{chunk-7ZB3YHF2.mjs → chunk-C6LC5LD5.mjs} +1 -1
- package/dist/{chunk-7ZB3YHF2.mjs.map → chunk-C6LC5LD5.mjs.map} +1 -1
- package/dist/{chunk-5HONWYQA.js → chunk-C7ILTLT5.js} +3 -3
- package/dist/{chunk-5HONWYQA.js.map → chunk-C7ILTLT5.js.map} +1 -1
- package/dist/{chunk-OES54VU6.mjs → chunk-CFV2OZ3P.mjs} +116 -13
- package/dist/chunk-CFV2OZ3P.mjs.map +1 -0
- package/dist/{chunk-4OVIHZ3I.js → chunk-CGXWWPEA.js} +6 -6
- package/dist/{chunk-4OVIHZ3I.js.map → chunk-CGXWWPEA.js.map} +1 -1
- package/dist/{chunk-MNU45FM3.js → chunk-COT4KW3H.js} +2 -2
- package/dist/{chunk-MNU45FM3.js.map → chunk-COT4KW3H.js.map} +1 -1
- package/dist/{chunk-JDQUXG75.js → chunk-CVDNCU6L.js} +3 -3
- package/dist/{chunk-JDQUXG75.js.map → chunk-CVDNCU6L.js.map} +1 -1
- package/dist/{chunk-HBZHWSMZ.mjs → chunk-D46PJSQ7.mjs} +13 -13
- package/dist/{chunk-ARYIJ4RU.js → chunk-DDORKDQO.js} +3 -3
- package/dist/{chunk-ARYIJ4RU.js.map → chunk-DDORKDQO.js.map} +1 -1
- package/dist/{chunk-7YQTDJFA.js → chunk-DKXSR2V3.js} +3 -3
- package/dist/{chunk-7YQTDJFA.js.map → chunk-DKXSR2V3.js.map} +1 -1
- package/dist/{chunk-I6EAPPBL.mjs → chunk-DZMYIOKZ.mjs} +5 -5
- package/dist/{chunk-SKM7NFPY.js → chunk-EPXAFJVW.js} +6 -6
- package/dist/{chunk-SKM7NFPY.js.map → chunk-EPXAFJVW.js.map} +1 -1
- package/dist/{chunk-AYYMS23L.js → chunk-ESIQ2GB4.js} +7 -7
- package/dist/{chunk-AYYMS23L.js.map → chunk-ESIQ2GB4.js.map} +1 -1
- package/dist/{chunk-NU2WNYOD.js → chunk-EW7HGUFV.js} +87 -87
- package/dist/{chunk-NU2WNYOD.js.map → chunk-EW7HGUFV.js.map} +1 -1
- package/dist/{chunk-I4QGQMXI.mjs → chunk-EXYXZFNK.mjs} +2 -2
- package/dist/{chunk-RBJAO57A.js → chunk-FAAR4XC5.js} +3 -3
- package/dist/{chunk-RBJAO57A.js.map → chunk-FAAR4XC5.js.map} +1 -1
- package/dist/{chunk-N2VNE3ON.js → chunk-FDTDJDZI.js} +13 -13
- package/dist/{chunk-N2VNE3ON.js.map → chunk-FDTDJDZI.js.map} +1 -1
- package/dist/{chunk-SU5Q64TW.mjs → chunk-FVCTKS33.mjs} +6 -5
- package/dist/chunk-FVCTKS33.mjs.map +1 -0
- package/dist/{chunk-AVHZHWI3.js → chunk-GBIFSFWJ.js} +15 -15
- package/dist/{chunk-AVHZHWI3.js.map → chunk-GBIFSFWJ.js.map} +1 -1
- package/dist/{chunk-KSUPPAKH.js → chunk-GIQSHTB5.js} +9 -9
- package/dist/{chunk-KSUPPAKH.js.map → chunk-GIQSHTB5.js.map} +1 -1
- package/dist/{chunk-4QBKD4JN.js → chunk-GUUJYGXF.js} +3 -3
- package/dist/{chunk-4QBKD4JN.js.map → chunk-GUUJYGXF.js.map} +1 -1
- package/dist/{chunk-M4O46VDY.mjs → chunk-GX2PKLN2.mjs} +2 -2
- package/dist/{chunk-5BUTINIM.mjs → chunk-HLVLSWKD.mjs} +3 -3
- package/dist/{chunk-FU23WOTY.js → chunk-HSV5VZ4Z.js} +6 -6
- package/dist/{chunk-FU23WOTY.js.map → chunk-HSV5VZ4Z.js.map} +1 -1
- package/dist/{chunk-MMS2ELDK.mjs → chunk-IIQCS3A2.mjs} +2 -2
- package/dist/{chunk-NKWLCZUZ.mjs → chunk-JGGUMHM6.mjs} +2 -2
- package/dist/{chunk-HT2GREFH.js → chunk-JLD46DL7.js} +11 -11
- package/dist/{chunk-HT2GREFH.js.map → chunk-JLD46DL7.js.map} +1 -1
- package/dist/{chunk-NVL5TKWD.mjs → chunk-JYFLOQYT.mjs} +2 -2
- package/dist/{chunk-DWGDEUEW.mjs → chunk-KG563P7F.mjs} +5 -5
- package/dist/{chunk-TCIC5556.mjs → chunk-KH4TEDGD.mjs} +2 -2
- package/dist/{chunk-23PAYKWB.js → chunk-KM27ZDHZ.js} +2 -2
- package/dist/{chunk-23PAYKWB.js.map → chunk-KM27ZDHZ.js.map} +1 -1
- package/dist/{chunk-XZUMD3CB.mjs → chunk-LODDYDTP.mjs} +2 -2
- package/dist/{chunk-XZUMD3CB.mjs.map → chunk-LODDYDTP.mjs.map} +1 -1
- package/dist/{chunk-E6CGJBID.mjs → chunk-LUHKMY56.mjs} +2 -2
- package/dist/{chunk-TVLEUNKE.mjs → chunk-LZP5VZCO.mjs} +2 -2
- package/dist/{chunk-EHNEBXS7.mjs → chunk-M6DXZ2FM.mjs} +2 -2
- package/dist/{chunk-B4C5DWAP.mjs → chunk-MMMJDO75.mjs} +2 -2
- package/dist/{chunk-AFCWMJQO.js → chunk-MOUPNP53.js} +3 -3
- package/dist/{chunk-AFCWMJQO.js.map → chunk-MOUPNP53.js.map} +1 -1
- package/dist/{chunk-36KFIZ43.js → chunk-MYPUZ6EG.js} +3 -3
- package/dist/{chunk-36KFIZ43.js.map → chunk-MYPUZ6EG.js.map} +1 -1
- package/dist/{chunk-6JHIKIPA.js → chunk-NUGLTWEA.js} +23 -23
- package/dist/{chunk-6JHIKIPA.js.map → chunk-NUGLTWEA.js.map} +1 -1
- package/dist/{chunk-KWXOYHYK.mjs → chunk-P7MORXSE.mjs} +2 -2
- package/dist/{chunk-YG4IZ5Q3.mjs → chunk-Q2OSEROT.mjs} +2 -2
- package/dist/{chunk-L5SXG6T6.mjs → chunk-QQKOHKO2.mjs} +3 -3
- package/dist/{chunk-SADSJ2MV.js → chunk-QVGUYPXO.js} +3 -3
- package/dist/{chunk-SADSJ2MV.js.map → chunk-QVGUYPXO.js.map} +1 -1
- package/dist/{chunk-K45PTE7F.mjs → chunk-RBKQXT73.mjs} +4 -4
- package/dist/{chunk-JZFISWTP.js → chunk-RIN2IN7E.js} +2 -2
- package/dist/{chunk-JZFISWTP.js.map → chunk-RIN2IN7E.js.map} +1 -1
- package/dist/{chunk-BXLAOYAG.mjs → chunk-RIUVPTG7.mjs} +2 -2
- package/dist/{chunk-QVB54LBS.mjs → chunk-RNZGX6MX.mjs} +3 -3
- package/dist/{chunk-VSVLIRO2.js → chunk-RXEU77VN.js} +15 -15
- package/dist/{chunk-VSVLIRO2.js.map → chunk-RXEU77VN.js.map} +1 -1
- package/dist/{chunk-ZRIYCU2V.js → chunk-S2BZPPAI.js} +5 -5
- package/dist/{chunk-ZRIYCU2V.js.map → chunk-S2BZPPAI.js.map} +1 -1
- package/dist/{chunk-MES2BP4T.mjs → chunk-SGL5IUCV.mjs} +2 -2
- package/dist/{chunk-7LS5UQCQ.mjs → chunk-STKUPDHG.mjs} +2 -2
- package/dist/{chunk-PPYCCT2K.js → chunk-SWDVSCQJ.js} +9 -8
- package/dist/chunk-SWDVSCQJ.js.map +1 -0
- package/dist/{chunk-JCA76TCX.mjs → chunk-SZKLJOTN.mjs} +2 -2
- package/dist/{chunk-F5WR6XZZ.js → chunk-T73HPYF2.js} +3 -3
- package/dist/{chunk-F5WR6XZZ.js.map → chunk-T73HPYF2.js.map} +1 -1
- package/dist/{chunk-ZB6HDDE4.js → chunk-TQO37PVW.js} +14 -14
- package/dist/{chunk-ZB6HDDE4.js.map → chunk-TQO37PVW.js.map} +1 -1
- package/dist/{chunk-VKQ5AJDT.mjs → chunk-UENZQF2Y.mjs} +2 -2
- package/dist/{chunk-DCG7EUBC.js → chunk-UWLW5YVB.js} +6 -6
- package/dist/{chunk-DCG7EUBC.js.map → chunk-UWLW5YVB.js.map} +1 -1
- package/dist/{chunk-37AJ2GVO.mjs → chunk-UXJIZDXQ.mjs} +2 -2
- package/dist/{chunk-PLLPFCN3.js → chunk-UXMDPRAI.js} +14 -14
- package/dist/{chunk-PLLPFCN3.js.map → chunk-UXMDPRAI.js.map} +1 -1
- package/dist/{chunk-7BOTKRY6.mjs → chunk-V55DG5B4.mjs} +2 -2
- package/dist/{chunk-YRTIDZTN.js → chunk-VHEDMUAW.js} +4 -4
- package/dist/{chunk-YRTIDZTN.js.map → chunk-VHEDMUAW.js.map} +1 -1
- package/dist/{chunk-4RD55E4R.js → chunk-VWLWSO4J.js} +3 -3
- package/dist/{chunk-4RD55E4R.js.map → chunk-VWLWSO4J.js.map} +1 -1
- package/dist/{chunk-VJQIKFMG.mjs → chunk-W3CWEZDB.mjs} +3 -3
- package/dist/{chunk-JM6SLU7D.js → chunk-W7NNH4VY.js} +6 -6
- package/dist/{chunk-JM6SLU7D.js.map → chunk-W7NNH4VY.js.map} +1 -1
- package/dist/{chunk-VQ7MSYIH.js → chunk-WUN5NHZE.js} +4 -4
- package/dist/{chunk-VQ7MSYIH.js.map → chunk-WUN5NHZE.js.map} +1 -1
- package/dist/{chunk-AAU7ABJN.js → chunk-WWTRSQ3X.js} +3 -3
- package/dist/{chunk-AAU7ABJN.js.map → chunk-WWTRSQ3X.js.map} +1 -1
- package/dist/{chunk-BR6D2TGF.js → chunk-WZOA2PVJ.js} +3 -3
- package/dist/{chunk-BR6D2TGF.js.map → chunk-WZOA2PVJ.js.map} +1 -1
- package/dist/{chunk-TZKR5Z4J.mjs → chunk-XJF2F36N.mjs} +2 -2
- package/dist/{chunk-P6ACVNQK.mjs → chunk-YD2XBEKO.mjs} +2 -2
- package/dist/{chunk-LMXWIPGR.js → chunk-YWPLHFAK.js} +3 -3
- package/dist/{chunk-LMXWIPGR.js.map → chunk-YWPLHFAK.js.map} +1 -1
- package/dist/{chunk-DCEWWHV5.mjs → chunk-Z3HGYPH7.mjs} +2 -2
- package/dist/{chunk-Q3PKW6TH.js → chunk-ZCV3HWI2.js} +6 -6
- package/dist/{chunk-Q3PKW6TH.js.map → chunk-ZCV3HWI2.js.map} +1 -1
- package/dist/{chunk-OSA3YVDZ.mjs → chunk-ZF46DCAC.mjs} +2 -2
- package/dist/{chunk-5T6IDXSB.js → chunk-ZO2GA23I.js} +3 -3
- package/dist/{chunk-5T6IDXSB.js.map → chunk-ZO2GA23I.js.map} +1 -1
- package/dist/{chunk-ZN3763VZ.js → chunk-ZQLW4EJB.js} +9 -9
- package/dist/{chunk-ZN3763VZ.js.map → chunk-ZQLW4EJB.js.map} +1 -1
- package/dist/{chunk-CM5R4SPF.js → chunk-ZQQJTO6T.js} +3 -3
- package/dist/{chunk-CM5R4SPF.js.map → chunk-ZQQJTO6T.js.map} +1 -1
- package/dist/{chunk-SEL4QDCO.js → chunk-ZSXSAE3D.js} +3 -3
- package/dist/{chunk-SEL4QDCO.js.map → chunk-ZSXSAE3D.js.map} +1 -1
- package/dist/components/SupportChatWidget/guestSupportChatAdapter.d.ts +6 -1
- package/dist/components/SupportChatWidget/guestSupportChatAdapter.d.ts.map +1 -1
- package/dist/hooks/useAppContent/index.js +49 -49
- package/dist/hooks/useAppContent/index.mjs +48 -48
- package/dist/hooks/useSupportChat.d.ts +2 -0
- package/dist/hooks/useSupportChat.d.ts.map +1 -1
- package/dist/index.js +49 -49
- package/dist/index.mjs +48 -48
- package/dist/types/supportChat/index.d.ts +14 -0
- package/dist/types/supportChat/index.d.ts.map +1 -1
- package/dist/types/supportChat/index.js +2 -2
- package/dist/types/supportChat/index.mjs +1 -1
- package/dist/types/supportChat.d.ts +14 -0
- package/dist/types/supportChat.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-CYSODZGX.js.map +0 -1
- package/dist/chunk-OES54VU6.mjs.map +0 -1
- package/dist/chunk-PPYCCT2K.js.map +0 -1
- package/dist/chunk-SU5Q64TW.mjs.map +0 -1
- /package/dist/{RichEditorCore-6MTYSSKS.mjs.map → RichEditorCore-2S5YUAOI.mjs.map} +0 -0
- /package/dist/{chunk-B6QOBHZM.mjs.map → chunk-24BEZK43.mjs.map} +0 -0
- /package/dist/{chunk-OQTXTDSK.mjs.map → chunk-2OJ3QSLU.mjs.map} +0 -0
- /package/dist/{chunk-4OUBPEVS.mjs.map → chunk-3HKLGNUE.mjs.map} +0 -0
- /package/dist/{chunk-IHBWJM4C.mjs.map → chunk-3Q7RJKUP.mjs.map} +0 -0
- /package/dist/{chunk-PY6WD6SB.mjs.map → chunk-3WRB4WCD.mjs.map} +0 -0
- /package/dist/{chunk-L52NFNFK.mjs.map → chunk-5VC4BK65.mjs.map} +0 -0
- /package/dist/{chunk-C65DG2RI.mjs.map → chunk-7FSBWUOM.mjs.map} +0 -0
- /package/dist/{chunk-HCQJR5CE.mjs.map → chunk-7ZWEBNFB.mjs.map} +0 -0
- /package/dist/{chunk-3RHNJUXU.mjs.map → chunk-ACSEJOW6.mjs.map} +0 -0
- /package/dist/{chunk-WQZHUW7C.mjs.map → chunk-ANFHLSDB.mjs.map} +0 -0
- /package/dist/{chunk-H6NQOLQY.mjs.map → chunk-ANFLWCVD.mjs.map} +0 -0
- /package/dist/{chunk-5WS6IENQ.mjs.map → chunk-AU2HLQDJ.mjs.map} +0 -0
- /package/dist/{chunk-P6FX3NT6.mjs.map → chunk-AZGDHAP5.mjs.map} +0 -0
- /package/dist/{chunk-NPB2JTYC.mjs.map → chunk-BO3QVQ37.mjs.map} +0 -0
- /package/dist/{chunk-2WI4Q2I2.mjs.map → chunk-BPMWRFSI.mjs.map} +0 -0
- /package/dist/{chunk-TEW33GLR.mjs.map → chunk-BXN3VO6I.mjs.map} +0 -0
- /package/dist/{chunk-HBZHWSMZ.mjs.map → chunk-D46PJSQ7.mjs.map} +0 -0
- /package/dist/{chunk-I6EAPPBL.mjs.map → chunk-DZMYIOKZ.mjs.map} +0 -0
- /package/dist/{chunk-I4QGQMXI.mjs.map → chunk-EXYXZFNK.mjs.map} +0 -0
- /package/dist/{chunk-M4O46VDY.mjs.map → chunk-GX2PKLN2.mjs.map} +0 -0
- /package/dist/{chunk-5BUTINIM.mjs.map → chunk-HLVLSWKD.mjs.map} +0 -0
- /package/dist/{chunk-MMS2ELDK.mjs.map → chunk-IIQCS3A2.mjs.map} +0 -0
- /package/dist/{chunk-NKWLCZUZ.mjs.map → chunk-JGGUMHM6.mjs.map} +0 -0
- /package/dist/{chunk-NVL5TKWD.mjs.map → chunk-JYFLOQYT.mjs.map} +0 -0
- /package/dist/{chunk-DWGDEUEW.mjs.map → chunk-KG563P7F.mjs.map} +0 -0
- /package/dist/{chunk-TCIC5556.mjs.map → chunk-KH4TEDGD.mjs.map} +0 -0
- /package/dist/{chunk-E6CGJBID.mjs.map → chunk-LUHKMY56.mjs.map} +0 -0
- /package/dist/{chunk-TVLEUNKE.mjs.map → chunk-LZP5VZCO.mjs.map} +0 -0
- /package/dist/{chunk-EHNEBXS7.mjs.map → chunk-M6DXZ2FM.mjs.map} +0 -0
- /package/dist/{chunk-B4C5DWAP.mjs.map → chunk-MMMJDO75.mjs.map} +0 -0
- /package/dist/{chunk-KWXOYHYK.mjs.map → chunk-P7MORXSE.mjs.map} +0 -0
- /package/dist/{chunk-YG4IZ5Q3.mjs.map → chunk-Q2OSEROT.mjs.map} +0 -0
- /package/dist/{chunk-L5SXG6T6.mjs.map → chunk-QQKOHKO2.mjs.map} +0 -0
- /package/dist/{chunk-K45PTE7F.mjs.map → chunk-RBKQXT73.mjs.map} +0 -0
- /package/dist/{chunk-BXLAOYAG.mjs.map → chunk-RIUVPTG7.mjs.map} +0 -0
- /package/dist/{chunk-QVB54LBS.mjs.map → chunk-RNZGX6MX.mjs.map} +0 -0
- /package/dist/{chunk-MES2BP4T.mjs.map → chunk-SGL5IUCV.mjs.map} +0 -0
- /package/dist/{chunk-7LS5UQCQ.mjs.map → chunk-STKUPDHG.mjs.map} +0 -0
- /package/dist/{chunk-JCA76TCX.mjs.map → chunk-SZKLJOTN.mjs.map} +0 -0
- /package/dist/{chunk-VKQ5AJDT.mjs.map → chunk-UENZQF2Y.mjs.map} +0 -0
- /package/dist/{chunk-37AJ2GVO.mjs.map → chunk-UXJIZDXQ.mjs.map} +0 -0
- /package/dist/{chunk-7BOTKRY6.mjs.map → chunk-V55DG5B4.mjs.map} +0 -0
- /package/dist/{chunk-VJQIKFMG.mjs.map → chunk-W3CWEZDB.mjs.map} +0 -0
- /package/dist/{chunk-TZKR5Z4J.mjs.map → chunk-XJF2F36N.mjs.map} +0 -0
- /package/dist/{chunk-P6ACVNQK.mjs.map → chunk-YD2XBEKO.mjs.map} +0 -0
- /package/dist/{chunk-DCEWWHV5.mjs.map → chunk-Z3HGYPH7.mjs.map} +0 -0
- /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-DCG7EUBC.js","../src/components/Search/Search.tsx"],"names":["disabled","readOnly"],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-DCG7EUBC.js","sourcesContent":[null,"import { XIcon } from '@phosphor-icons/react/dist/csr/X';\nimport { MagnifyingGlassIcon } from '@phosphor-icons/react/dist/csr/MagnifyingGlass';\nimport {\n InputHTMLAttributes,\n forwardRef,\n useState,\n useId,\n useMemo,\n useEffect,\n useRef,\n ChangeEvent,\n MouseEvent,\n KeyboardEvent,\n} from 'react';\nimport DropdownMenu, {\n DropdownMenuContent,\n DropdownMenuItem,\n createDropdownStore,\n} from '../DropdownMenu/DropdownMenu';\nimport { cn } from '../../utils/utils';\n\n/**\n * Search component props interface\n */\ntype SearchProps = {\n /** List of options to show in dropdown */\n options: string[];\n /** Callback when an option is selected from dropdown */\n onSelect?: (value: string) => void;\n /** Callback when search input changes */\n onSearch?: (query: string) => void;\n /** Control dropdown visibility externally */\n showDropdown?: boolean;\n /** Callback when dropdown open state changes */\n onDropdownChange?: (open: boolean) => void;\n /** Maximum height of dropdown in pixels */\n dropdownMaxHeight?: number;\n /** Text to show when no results are found */\n noResultsText?: string;\n /** Debounce delay in ms for onSearch. Default 0 (no debounce). */\n debounceMs?: number;\n /**\n * Quantidade de resultados da busca **atual**. Quando informada, confirmar a\n * busca com Enter anuncia o total num `role=\"status\"` — sem isso o leitor de\n * tela não diz se achou algo.\n *\n * Precisa acompanhar o que está digitado. Todos os consumidores filtram a\n * cada tecla (e não só no Enter), então o valor já chega atualizado; um\n * consumidor que só filtrasse no submit anunciaria a contagem anterior.\n *\n * Omitir mantém o comportamento antigo: o componente só anuncia por conta\n * própria quando ele mesmo filtra, isto é, quando recebe `options`.\n */\n resultsCount?: number;\n /** Additional CSS classes to apply to the input */\n className?: string;\n /** Additional CSS classes to apply to the container */\n containerClassName?: string;\n /**\n * Entrega a decisão de largura para quem posiciona o campo: o container passa\n * a ser só `w-full`, sem o teto de 488px.\n *\n * Existe porque a largura padrão é fixa (`md:w-[488px]`) e largura fixa não se\n * sobrescreve de fora por CSS — um pai não tem como pedir \"ocupe a linha\n * inteira\". Quem usa: linhas de header que já controlam a própria largura por\n * breakpoint, como o `TableHeaderRow`.\n */\n fullWidth?: boolean;\n /** Callback when clear button is clicked */\n onClear?: () => void;\n} & Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'onSelect'>;\n\n/**\n * Search component for Analytica Ensino platforms\n *\n * A specialized search input component with dropdown suggestions.\n * Features filtering, keyboard navigation, and customizable options.\n *\n * @param options - Array of search options to display in dropdown\n * @param onSelect - Callback when an option is selected\n * @param onSearch - Callback when search query changes\n * @param placeholder - Placeholder text for the input\n * @param noResultsText - Text to show when no results are found\n * @param resultsCount - Total da busca atual; confirmar com Enter anuncia esse\n * total num `role=\"status\"` (\"3 resultados encontrados\")\n * @param dropdownMaxHeight - Maximum height of dropdown in pixels\n * @param className - Additional CSS classes for the input\n * @param containerClassName - Additional CSS classes for the container\n * @param fullWidth - Container só `w-full`, sem o teto de 488px; a largura passa\n * a ser responsabilidade de quem posiciona o campo\n * @param props - All other standard input HTML attributes\n * @returns A styled search input with dropdown functionality\n *\n * @example\n * ```tsx\n * // Basic search\n * <Search\n * options={['Filosofia', 'Física', 'Matemática']}\n * placeholder=\"Buscar matéria...\"\n * onSelect={(value) => console.log('Selected:', value)}\n * />\n *\n * // With custom filtering\n * <Search\n * options={materias}\n * onSearch={(query) => setFilteredMaterias(filterMaterias(query))}\n * noResultsText=\"Nenhum resultado encontrado\"\n * />\n * ```\n */\n\n/**\n * Filter options based on search query\n */\nconst filterOptions = (options: string[], query: string): string[] => {\n if (!query || query.length < 1) return [];\n\n return options.filter((option) =>\n option.toLowerCase().includes(query.toLowerCase())\n );\n};\n\n/**\n * Frase anunciada ao confirmar a busca. A cópia acompanha o resto da lib:\n * `NoSearchResult` e o `noResultsText` padrão daqui usam o mesmo\n * \"Nenhum resultado encontrado\".\n */\nexport const getResultsMessage = (count: number): string => {\n if (count === 0) return 'Nenhum resultado encontrado';\n if (count === 1) return '1 resultado encontrado';\n return `${count} resultados encontrados`;\n};\n\n/**\n * Updates input value and creates appropriate change event\n */\nconst updateInputValue = (\n value: string,\n ref:\n | { current: HTMLInputElement | null }\n | ((instance: HTMLInputElement | null) => void)\n | null,\n onChange?: (event: ChangeEvent<HTMLInputElement>) => void\n) => {\n if (!onChange) return;\n\n if (ref && 'current' in ref && ref.current) {\n ref.current.value = value;\n const event = new Event('input', { bubbles: true });\n Object.defineProperty(event, 'target', {\n writable: false,\n value: ref.current,\n });\n onChange(event as unknown as ChangeEvent<HTMLInputElement>);\n } else {\n // Fallback for cases where ref is not available\n const event = {\n target: { value },\n currentTarget: { value },\n } as ChangeEvent<HTMLInputElement>;\n onChange(event);\n }\n};\n\nconst Search = forwardRef<HTMLInputElement, SearchProps>(\n (\n {\n options = [],\n onSelect,\n onSearch,\n showDropdown: controlledShowDropdown,\n onDropdownChange,\n dropdownMaxHeight = 240,\n noResultsText = 'Nenhum resultado encontrado',\n className = '',\n containerClassName = '',\n fullWidth = false,\n disabled,\n readOnly,\n id,\n onClear,\n value,\n onChange,\n placeholder = 'Buscar...',\n onKeyDown: userOnKeyDown,\n debounceMs = 0,\n resultsCount,\n ...props\n },\n ref\n ) => {\n // Frase falada ao confirmar a busca.\n const [announcement, setAnnouncement] = useState('');\n const announceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Dropdown state and logic\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const [forceClose, setForceClose] = useState(false);\n const justSelectedRef = useRef(false);\n const dropdownStore = useRef(createDropdownStore()).current;\n const dropdownRef = useRef<HTMLDivElement>(null);\n const inputElRef = useRef<HTMLInputElement>(null);\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (debounceTimer.current) clearTimeout(debounceTimer.current);\n if (announceTimer.current) clearTimeout(announceTimer.current);\n };\n }, []);\n\n /**\n * Fala a frase na região live.\n *\n * Limpa e repõe o texto num tick separado, em vez de escrever direto. São\n * dois motivos, e os dois aparecem só num leitor de tela de verdade:\n *\n * - O VoiceOver engole a atualização quando ela acontece no mesmo tick do\n * Enter, com o foco dentro do input — a fala da tecla ganha e a região\n * nunca é anunciada.\n * - Região live só dispara quando o conteúdo MUDA. Sem o passo de limpeza,\n * confirmar duas vezes a mesma busca escreveria o mesmo texto e o leitor\n * ficaria mudo na segunda.\n */\n const announce = (message: string) => {\n if (announceTimer.current) clearTimeout(announceTimer.current);\n setAnnouncement('');\n announceTimer.current = setTimeout(() => {\n setAnnouncement(message);\n }, 150);\n };\n\n // Filter options based on input value\n const filteredOptions = useMemo(() => {\n if (!options.length) {\n return [];\n }\n const filtered = filterOptions(options, (value as string) || '');\n return filtered;\n }, [options, value]);\n\n // Control dropdown visibility\n const showDropdown =\n !forceClose &&\n (controlledShowDropdown ??\n (dropdownOpen && value && String(value).length > 0));\n\n /** Se o popup tem sugestões de verdade, ou só a mensagem de vazio. */\n const hasSuggestions = filteredOptions.length > 0;\n\n // Helper to keep all consumers in sync\n const setOpenAndNotify = (open: boolean) => {\n setDropdownOpen(open);\n dropdownStore.setState({ open });\n onDropdownChange?.(open);\n };\n\n // Handle dropdown visibility changes\n useEffect(() => {\n // Don't reopen dropdown if we just selected an option\n if (justSelectedRef.current) {\n justSelectedRef.current = false;\n return;\n }\n // Respect forceClose even if value is non-empty\n if (forceClose) {\n setOpenAndNotify(false);\n return;\n }\n\n const shouldShow = Boolean(value && String(value).length > 0);\n setOpenAndNotify(shouldShow);\n }, [value, forceClose, onDropdownChange, dropdownStore]);\n\n // Handle option selection\n const handleSelectOption = (option: string) => {\n justSelectedRef.current = true; // Prevent immediate dropdown reopen\n setForceClose(true); // Force dropdown to close immediately\n onSelect?.(option);\n setOpenAndNotify(false);\n\n // Update input value if onChange is provided\n updateInputValue(option, ref, onChange);\n };\n\n // Handle click outside dropdown\n useEffect(() => {\n const handleClickOutside = (event: globalThis.MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n setOpenAndNotify(false);\n }\n };\n\n if (showDropdown) {\n document.addEventListener('click', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('click', handleClickOutside);\n };\n }, [showDropdown, dropdownStore, onDropdownChange]);\n\n // Generate unique ID if not provided\n const generatedId = useId();\n const inputId = id ?? `search-${generatedId}`;\n const dropdownId = `${inputId}-dropdown`;\n\n // Handle clear button\n const handleClear = () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n debounceTimer.current = null;\n }\n if (onClear) {\n onClear();\n } else {\n updateInputValue('', ref, onChange);\n }\n // Limpar esconde o próprio botão (`showClearButton` passa a ser false) e\n // ele desmonta. No teclado isso largaria o foco no <body>; no mouse é\n // no-op, porque o `preventDefault` do mousedown já segurou o foco aqui.\n inputElRef.current?.focus();\n };\n\n // O mousedown existe só para o input não perder o foco no clique. A ação\n // fica no click — que é o que Enter e Espaço disparam num botão focado.\n // Prender a ação ao mousedown deixava os dois botões mortos no teclado.\n const preventFocusLoss = (e: MouseEvent) => {\n e.preventDefault();\n };\n\n // Handle clear button click - mantém foco no input\n const handleClearClick = (e: MouseEvent) => {\n e.stopPropagation(); // Para propagação do evento\n handleClear();\n };\n\n // Handle search icon click - focus on input\n const handleSearchIconClick = (e: MouseEvent) => {\n e.stopPropagation();\n inputElRef.current?.focus();\n };\n\n // Handle input change\n const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {\n setForceClose(false); // Allow dropdown to open when user types\n onChange?.(e);\n if (debounceMs > 0) {\n if (debounceTimer.current) clearTimeout(debounceTimer.current);\n const value = e.target.value;\n debounceTimer.current = setTimeout(() => {\n onSearch?.(value);\n }, debounceMs);\n } else {\n onSearch?.(e.target.value);\n }\n };\n\n // Handle keyboard events\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n // Let consumer run first; if they prevent default, skip our logic\n userOnKeyDown?.(e);\n if (e.defaultPrevented) return;\n\n if (e.key === 'Enter') {\n e.preventDefault();\n\n // If dropdown is open and there are filtered options, select the first one\n if (showDropdown && filteredOptions.length > 0) {\n handleSelectOption(filteredOptions[0]);\n } else if (value) {\n // If no dropdown or no options, execute search\n onSearch?.(String(value));\n setForceClose(true);\n setOpenAndNotify(false);\n\n // Sem `resultsCount` e sem `options`, o componente não sabe quantos\n // resultados existem — anunciar \"Nenhum resultado\" aí seria mentira.\n const count =\n resultsCount ??\n (options.length > 0 ? filteredOptions.length : undefined);\n if (count !== undefined) {\n announce(getResultsMessage(count));\n }\n }\n }\n };\n\n // Helper function for input state classes\n const getInputStateClasses = (disabled?: boolean, readOnly?: boolean) => {\n if (disabled) return 'cursor-not-allowed opacity-40';\n if (readOnly) return 'cursor-default focus:outline-none !text-text-900';\n return 'hover:border-border-400';\n };\n\n // Determine which icon to show\n const hasValue = String(value ?? '').length > 0;\n const showClearButton = hasValue && !disabled && !readOnly;\n const showSearchIcon = !hasValue && !disabled && !readOnly;\n\n // `cn` em vez de concatenação no container: é o que permite a\n // `containerClassName` vencer um conflito com a largura padrão — numa string\n // crua quem ganha é a ordem do CSS gerado, não a ordem escrita.\n return (\n <div\n ref={dropdownRef}\n className={cn(\n fullWidth ? 'w-full' : 'w-full max-w-lg md:w-[488px]',\n containerClassName\n )}\n >\n {/* `aria-atomic` faz o leitor reler a frase inteira, e não só o\n pedaço que mudou. */}\n <span\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"sr-only\"\n >\n {announcement}\n </span>\n\n {/* Search Input Container */}\n <div className=\"relative flex items-center\">\n {/* Search Input Field */}\n <input\n ref={(node) => {\n // Forward to parent\n if (ref) {\n if (typeof ref === 'function') ref(node);\n else\n (ref as { current: HTMLInputElement | null }).current = node;\n }\n // Keep our own handle\n inputElRef.current = node;\n }}\n id={inputId}\n type=\"text\"\n className={`w-full py-0 px-4 pr-10 font-normal text-text-900 focus:outline-primary-950 border rounded-full bg-background focus:bg-primary-50 border-border-300 focus:border-2 focus:border-primary-950 h-10 placeholder:text-text-600 ${getInputStateClasses(disabled, readOnly)} ${className}`}\n value={value}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n disabled={disabled}\n readOnly={readOnly}\n placeholder={placeholder}\n // Este campo é uma caixa de busca, e o leitor de tela precisa\n // anunciá-lo assim — é o que `searchbox` faz.\n //\n // Nenhum atributo de combobox entra aqui. Antes havia\n // `role=\"combobox\"` + `aria-haspopup=\"listbox\"`, que rendia\n // \"combinação, pop-up caixa de lista\" e ainda mentia duas vezes: o\n // popup é um `menu` (não um listbox), e o campo não tem navegação\n // por setas nem `aria-activedescendant` — sem isso não existe\n // combobox conforme, só a promessa dele.\n role=\"searchbox\"\n {...props}\n />\n\n {/* Right Icon - Clear Button */}\n {showClearButton && (\n <div className=\"absolute right-3 top-1/2 transform -translate-y-1/2\">\n <button\n type=\"button\"\n className=\"p-0 border-0 bg-transparent cursor-pointer\"\n onMouseDown={preventFocusLoss}\n onClick={handleClearClick}\n aria-label=\"Limpar busca\"\n >\n <span className=\"w-6 h-6 text-text-800 flex items-center justify-center hover:text-text-600 transition-colors\">\n <XIcon />\n </span>\n </button>\n </div>\n )}\n\n {/* Right Icon - Search Icon */}\n {showSearchIcon && (\n <div className=\"absolute right-3 top-1/2 transform -translate-y-1/2\">\n <button\n type=\"button\"\n className=\"p-0 border-0 bg-transparent cursor-pointer\"\n onMouseDown={preventFocusLoss}\n onClick={handleSearchIconClick}\n aria-label=\"Buscar\"\n >\n <span className=\"w-6 h-6 text-text-800 flex items-center justify-center hover:text-text-600 transition-colors\">\n <MagnifyingGlassIcon />\n </span>\n </button>\n </div>\n )}\n </div>\n\n {/* Search Dropdown */}\n {showDropdown && (\n <DropdownMenu open={showDropdown} onOpenChange={setDropdownOpen}>\n <DropdownMenuContent\n id={dropdownId}\n className=\"w-full mt-1\"\n style={{ maxHeight: dropdownMaxHeight }}\n align=\"start\"\n >\n {hasSuggestions ? (\n filteredOptions.map((option) => (\n <DropdownMenuItem\n key={option}\n onClick={() => handleSelectOption(option)}\n className=\"text-text-700 text-base leading-6 cursor-pointer\"\n >\n {option}\n </DropdownMenuItem>\n ))\n ) : (\n // O contêiner é um `role=\"menu\"`, e um menu sem nenhum\n // `menuitem` é anunciado como menu vazio — a frase dentro dele\n // se perde. Marcar o próprio texto como item desabilitado\n // deixa o menu bem-formado e a mensagem audível, sem precisar\n // trocar o papel do contêiner.\n <div\n role=\"menuitem\"\n aria-disabled=\"true\"\n className=\"px-3 py-3 text-text-700 text-base\"\n >\n {noResultsText}\n </div>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n );\n }\n);\n\nSearch.displayName = 'Search';\n\nexport default Search;\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-UWLW5YVB.js","../src/components/Search/Search.tsx"],"names":["disabled","readOnly"],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-UWLW5YVB.js","sourcesContent":[null,"import { XIcon } from '@phosphor-icons/react/dist/csr/X';\nimport { MagnifyingGlassIcon } from '@phosphor-icons/react/dist/csr/MagnifyingGlass';\nimport {\n InputHTMLAttributes,\n forwardRef,\n useState,\n useId,\n useMemo,\n useEffect,\n useRef,\n ChangeEvent,\n MouseEvent,\n KeyboardEvent,\n} from 'react';\nimport DropdownMenu, {\n DropdownMenuContent,\n DropdownMenuItem,\n createDropdownStore,\n} from '../DropdownMenu/DropdownMenu';\nimport { cn } from '../../utils/utils';\n\n/**\n * Search component props interface\n */\ntype SearchProps = {\n /** List of options to show in dropdown */\n options: string[];\n /** Callback when an option is selected from dropdown */\n onSelect?: (value: string) => void;\n /** Callback when search input changes */\n onSearch?: (query: string) => void;\n /** Control dropdown visibility externally */\n showDropdown?: boolean;\n /** Callback when dropdown open state changes */\n onDropdownChange?: (open: boolean) => void;\n /** Maximum height of dropdown in pixels */\n dropdownMaxHeight?: number;\n /** Text to show when no results are found */\n noResultsText?: string;\n /** Debounce delay in ms for onSearch. Default 0 (no debounce). */\n debounceMs?: number;\n /**\n * Quantidade de resultados da busca **atual**. Quando informada, confirmar a\n * busca com Enter anuncia o total num `role=\"status\"` — sem isso o leitor de\n * tela não diz se achou algo.\n *\n * Precisa acompanhar o que está digitado. Todos os consumidores filtram a\n * cada tecla (e não só no Enter), então o valor já chega atualizado; um\n * consumidor que só filtrasse no submit anunciaria a contagem anterior.\n *\n * Omitir mantém o comportamento antigo: o componente só anuncia por conta\n * própria quando ele mesmo filtra, isto é, quando recebe `options`.\n */\n resultsCount?: number;\n /** Additional CSS classes to apply to the input */\n className?: string;\n /** Additional CSS classes to apply to the container */\n containerClassName?: string;\n /**\n * Entrega a decisão de largura para quem posiciona o campo: o container passa\n * a ser só `w-full`, sem o teto de 488px.\n *\n * Existe porque a largura padrão é fixa (`md:w-[488px]`) e largura fixa não se\n * sobrescreve de fora por CSS — um pai não tem como pedir \"ocupe a linha\n * inteira\". Quem usa: linhas de header que já controlam a própria largura por\n * breakpoint, como o `TableHeaderRow`.\n */\n fullWidth?: boolean;\n /** Callback when clear button is clicked */\n onClear?: () => void;\n} & Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'onSelect'>;\n\n/**\n * Search component for Analytica Ensino platforms\n *\n * A specialized search input component with dropdown suggestions.\n * Features filtering, keyboard navigation, and customizable options.\n *\n * @param options - Array of search options to display in dropdown\n * @param onSelect - Callback when an option is selected\n * @param onSearch - Callback when search query changes\n * @param placeholder - Placeholder text for the input\n * @param noResultsText - Text to show when no results are found\n * @param resultsCount - Total da busca atual; confirmar com Enter anuncia esse\n * total num `role=\"status\"` (\"3 resultados encontrados\")\n * @param dropdownMaxHeight - Maximum height of dropdown in pixels\n * @param className - Additional CSS classes for the input\n * @param containerClassName - Additional CSS classes for the container\n * @param fullWidth - Container só `w-full`, sem o teto de 488px; a largura passa\n * a ser responsabilidade de quem posiciona o campo\n * @param props - All other standard input HTML attributes\n * @returns A styled search input with dropdown functionality\n *\n * @example\n * ```tsx\n * // Basic search\n * <Search\n * options={['Filosofia', 'Física', 'Matemática']}\n * placeholder=\"Buscar matéria...\"\n * onSelect={(value) => console.log('Selected:', value)}\n * />\n *\n * // With custom filtering\n * <Search\n * options={materias}\n * onSearch={(query) => setFilteredMaterias(filterMaterias(query))}\n * noResultsText=\"Nenhum resultado encontrado\"\n * />\n * ```\n */\n\n/**\n * Filter options based on search query\n */\nconst filterOptions = (options: string[], query: string): string[] => {\n if (!query || query.length < 1) return [];\n\n return options.filter((option) =>\n option.toLowerCase().includes(query.toLowerCase())\n );\n};\n\n/**\n * Frase anunciada ao confirmar a busca. A cópia acompanha o resto da lib:\n * `NoSearchResult` e o `noResultsText` padrão daqui usam o mesmo\n * \"Nenhum resultado encontrado\".\n */\nexport const getResultsMessage = (count: number): string => {\n if (count === 0) return 'Nenhum resultado encontrado';\n if (count === 1) return '1 resultado encontrado';\n return `${count} resultados encontrados`;\n};\n\n/**\n * Updates input value and creates appropriate change event\n */\nconst updateInputValue = (\n value: string,\n ref:\n | { current: HTMLInputElement | null }\n | ((instance: HTMLInputElement | null) => void)\n | null,\n onChange?: (event: ChangeEvent<HTMLInputElement>) => void\n) => {\n if (!onChange) return;\n\n if (ref && 'current' in ref && ref.current) {\n ref.current.value = value;\n const event = new Event('input', { bubbles: true });\n Object.defineProperty(event, 'target', {\n writable: false,\n value: ref.current,\n });\n onChange(event as unknown as ChangeEvent<HTMLInputElement>);\n } else {\n // Fallback for cases where ref is not available\n const event = {\n target: { value },\n currentTarget: { value },\n } as ChangeEvent<HTMLInputElement>;\n onChange(event);\n }\n};\n\nconst Search = forwardRef<HTMLInputElement, SearchProps>(\n (\n {\n options = [],\n onSelect,\n onSearch,\n showDropdown: controlledShowDropdown,\n onDropdownChange,\n dropdownMaxHeight = 240,\n noResultsText = 'Nenhum resultado encontrado',\n className = '',\n containerClassName = '',\n fullWidth = false,\n disabled,\n readOnly,\n id,\n onClear,\n value,\n onChange,\n placeholder = 'Buscar...',\n onKeyDown: userOnKeyDown,\n debounceMs = 0,\n resultsCount,\n ...props\n },\n ref\n ) => {\n // Frase falada ao confirmar a busca.\n const [announcement, setAnnouncement] = useState('');\n const announceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Dropdown state and logic\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const [forceClose, setForceClose] = useState(false);\n const justSelectedRef = useRef(false);\n const dropdownStore = useRef(createDropdownStore()).current;\n const dropdownRef = useRef<HTMLDivElement>(null);\n const inputElRef = useRef<HTMLInputElement>(null);\n const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (debounceTimer.current) clearTimeout(debounceTimer.current);\n if (announceTimer.current) clearTimeout(announceTimer.current);\n };\n }, []);\n\n /**\n * Fala a frase na região live.\n *\n * Limpa e repõe o texto num tick separado, em vez de escrever direto. São\n * dois motivos, e os dois aparecem só num leitor de tela de verdade:\n *\n * - O VoiceOver engole a atualização quando ela acontece no mesmo tick do\n * Enter, com o foco dentro do input — a fala da tecla ganha e a região\n * nunca é anunciada.\n * - Região live só dispara quando o conteúdo MUDA. Sem o passo de limpeza,\n * confirmar duas vezes a mesma busca escreveria o mesmo texto e o leitor\n * ficaria mudo na segunda.\n */\n const announce = (message: string) => {\n if (announceTimer.current) clearTimeout(announceTimer.current);\n setAnnouncement('');\n announceTimer.current = setTimeout(() => {\n setAnnouncement(message);\n }, 150);\n };\n\n // Filter options based on input value\n const filteredOptions = useMemo(() => {\n if (!options.length) {\n return [];\n }\n const filtered = filterOptions(options, (value as string) || '');\n return filtered;\n }, [options, value]);\n\n // Control dropdown visibility\n const showDropdown =\n !forceClose &&\n (controlledShowDropdown ??\n (dropdownOpen && value && String(value).length > 0));\n\n /** Se o popup tem sugestões de verdade, ou só a mensagem de vazio. */\n const hasSuggestions = filteredOptions.length > 0;\n\n // Helper to keep all consumers in sync\n const setOpenAndNotify = (open: boolean) => {\n setDropdownOpen(open);\n dropdownStore.setState({ open });\n onDropdownChange?.(open);\n };\n\n // Handle dropdown visibility changes\n useEffect(() => {\n // Don't reopen dropdown if we just selected an option\n if (justSelectedRef.current) {\n justSelectedRef.current = false;\n return;\n }\n // Respect forceClose even if value is non-empty\n if (forceClose) {\n setOpenAndNotify(false);\n return;\n }\n\n const shouldShow = Boolean(value && String(value).length > 0);\n setOpenAndNotify(shouldShow);\n }, [value, forceClose, onDropdownChange, dropdownStore]);\n\n // Handle option selection\n const handleSelectOption = (option: string) => {\n justSelectedRef.current = true; // Prevent immediate dropdown reopen\n setForceClose(true); // Force dropdown to close immediately\n onSelect?.(option);\n setOpenAndNotify(false);\n\n // Update input value if onChange is provided\n updateInputValue(option, ref, onChange);\n };\n\n // Handle click outside dropdown\n useEffect(() => {\n const handleClickOutside = (event: globalThis.MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node)\n ) {\n setOpenAndNotify(false);\n }\n };\n\n if (showDropdown) {\n document.addEventListener('click', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('click', handleClickOutside);\n };\n }, [showDropdown, dropdownStore, onDropdownChange]);\n\n // Generate unique ID if not provided\n const generatedId = useId();\n const inputId = id ?? `search-${generatedId}`;\n const dropdownId = `${inputId}-dropdown`;\n\n // Handle clear button\n const handleClear = () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n debounceTimer.current = null;\n }\n if (onClear) {\n onClear();\n } else {\n updateInputValue('', ref, onChange);\n }\n // Limpar esconde o próprio botão (`showClearButton` passa a ser false) e\n // ele desmonta. No teclado isso largaria o foco no <body>; no mouse é\n // no-op, porque o `preventDefault` do mousedown já segurou o foco aqui.\n inputElRef.current?.focus();\n };\n\n // O mousedown existe só para o input não perder o foco no clique. A ação\n // fica no click — que é o que Enter e Espaço disparam num botão focado.\n // Prender a ação ao mousedown deixava os dois botões mortos no teclado.\n const preventFocusLoss = (e: MouseEvent) => {\n e.preventDefault();\n };\n\n // Handle clear button click - mantém foco no input\n const handleClearClick = (e: MouseEvent) => {\n e.stopPropagation(); // Para propagação do evento\n handleClear();\n };\n\n // Handle search icon click - focus on input\n const handleSearchIconClick = (e: MouseEvent) => {\n e.stopPropagation();\n inputElRef.current?.focus();\n };\n\n // Handle input change\n const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {\n setForceClose(false); // Allow dropdown to open when user types\n onChange?.(e);\n if (debounceMs > 0) {\n if (debounceTimer.current) clearTimeout(debounceTimer.current);\n const value = e.target.value;\n debounceTimer.current = setTimeout(() => {\n onSearch?.(value);\n }, debounceMs);\n } else {\n onSearch?.(e.target.value);\n }\n };\n\n // Handle keyboard events\n const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => {\n // Let consumer run first; if they prevent default, skip our logic\n userOnKeyDown?.(e);\n if (e.defaultPrevented) return;\n\n if (e.key === 'Enter') {\n e.preventDefault();\n\n // If dropdown is open and there are filtered options, select the first one\n if (showDropdown && filteredOptions.length > 0) {\n handleSelectOption(filteredOptions[0]);\n } else if (value) {\n // If no dropdown or no options, execute search\n onSearch?.(String(value));\n setForceClose(true);\n setOpenAndNotify(false);\n\n // Sem `resultsCount` e sem `options`, o componente não sabe quantos\n // resultados existem — anunciar \"Nenhum resultado\" aí seria mentira.\n const count =\n resultsCount ??\n (options.length > 0 ? filteredOptions.length : undefined);\n if (count !== undefined) {\n announce(getResultsMessage(count));\n }\n }\n }\n };\n\n // Helper function for input state classes\n const getInputStateClasses = (disabled?: boolean, readOnly?: boolean) => {\n if (disabled) return 'cursor-not-allowed opacity-40';\n if (readOnly) return 'cursor-default focus:outline-none !text-text-900';\n return 'hover:border-border-400';\n };\n\n // Determine which icon to show\n const hasValue = String(value ?? '').length > 0;\n const showClearButton = hasValue && !disabled && !readOnly;\n const showSearchIcon = !hasValue && !disabled && !readOnly;\n\n // `cn` em vez de concatenação no container: é o que permite a\n // `containerClassName` vencer um conflito com a largura padrão — numa string\n // crua quem ganha é a ordem do CSS gerado, não a ordem escrita.\n return (\n <div\n ref={dropdownRef}\n className={cn(\n fullWidth ? 'w-full' : 'w-full max-w-lg md:w-[488px]',\n containerClassName\n )}\n >\n {/* `aria-atomic` faz o leitor reler a frase inteira, e não só o\n pedaço que mudou. */}\n <span\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className=\"sr-only\"\n >\n {announcement}\n </span>\n\n {/* Search Input Container */}\n <div className=\"relative flex items-center\">\n {/* Search Input Field */}\n <input\n ref={(node) => {\n // Forward to parent\n if (ref) {\n if (typeof ref === 'function') ref(node);\n else\n (ref as { current: HTMLInputElement | null }).current = node;\n }\n // Keep our own handle\n inputElRef.current = node;\n }}\n id={inputId}\n type=\"text\"\n className={`w-full py-0 px-4 pr-10 font-normal text-text-900 focus:outline-primary-950 border rounded-full bg-background focus:bg-primary-50 border-border-300 focus:border-2 focus:border-primary-950 h-10 placeholder:text-text-600 ${getInputStateClasses(disabled, readOnly)} ${className}`}\n value={value}\n onChange={handleInputChange}\n onKeyDown={handleKeyDown}\n disabled={disabled}\n readOnly={readOnly}\n placeholder={placeholder}\n // Este campo é uma caixa de busca, e o leitor de tela precisa\n // anunciá-lo assim — é o que `searchbox` faz.\n //\n // Nenhum atributo de combobox entra aqui. Antes havia\n // `role=\"combobox\"` + `aria-haspopup=\"listbox\"`, que rendia\n // \"combinação, pop-up caixa de lista\" e ainda mentia duas vezes: o\n // popup é um `menu` (não um listbox), e o campo não tem navegação\n // por setas nem `aria-activedescendant` — sem isso não existe\n // combobox conforme, só a promessa dele.\n role=\"searchbox\"\n {...props}\n />\n\n {/* Right Icon - Clear Button */}\n {showClearButton && (\n <div className=\"absolute right-3 top-1/2 transform -translate-y-1/2\">\n <button\n type=\"button\"\n className=\"p-0 border-0 bg-transparent cursor-pointer\"\n onMouseDown={preventFocusLoss}\n onClick={handleClearClick}\n aria-label=\"Limpar busca\"\n >\n <span className=\"w-6 h-6 text-text-800 flex items-center justify-center hover:text-text-600 transition-colors\">\n <XIcon />\n </span>\n </button>\n </div>\n )}\n\n {/* Right Icon - Search Icon */}\n {showSearchIcon && (\n <div className=\"absolute right-3 top-1/2 transform -translate-y-1/2\">\n <button\n type=\"button\"\n className=\"p-0 border-0 bg-transparent cursor-pointer\"\n onMouseDown={preventFocusLoss}\n onClick={handleSearchIconClick}\n aria-label=\"Buscar\"\n >\n <span className=\"w-6 h-6 text-text-800 flex items-center justify-center hover:text-text-600 transition-colors\">\n <MagnifyingGlassIcon />\n </span>\n </button>\n </div>\n )}\n </div>\n\n {/* Search Dropdown */}\n {showDropdown && (\n <DropdownMenu open={showDropdown} onOpenChange={setDropdownOpen}>\n <DropdownMenuContent\n id={dropdownId}\n className=\"w-full mt-1\"\n style={{ maxHeight: dropdownMaxHeight }}\n align=\"start\"\n >\n {hasSuggestions ? (\n filteredOptions.map((option) => (\n <DropdownMenuItem\n key={option}\n onClick={() => handleSelectOption(option)}\n className=\"text-text-700 text-base leading-6 cursor-pointer\"\n >\n {option}\n </DropdownMenuItem>\n ))\n ) : (\n // O contêiner é um `role=\"menu\"`, e um menu sem nenhum\n // `menuitem` é anunciado como menu vazio — a frase dentro dele\n // se perde. Marcar o próprio texto como item desabilitado\n // deixa o menu bem-formado e a mensagem audível, sem precisar\n // trocar o papel do contêiner.\n <div\n role=\"menuitem\"\n aria-disabled=\"true\"\n className=\"px-3 py-3 text-text-700 text-base\"\n >\n {noResultsText}\n </div>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n );\n }\n);\n\nSearch.displayName = 'Search';\n\nexport default Search;\n"]}
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from "./chunk-LWG7F5IU.mjs";
|
|
15
15
|
import {
|
|
16
16
|
Modal_default
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-LODDYDTP.mjs";
|
|
18
18
|
|
|
19
19
|
// src/components/AccessReportModal/AccessReportModal.tsx
|
|
20
20
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -265,4 +265,4 @@ export {
|
|
|
265
265
|
AccessReportModal,
|
|
266
266
|
AccessReportModal_default
|
|
267
267
|
};
|
|
268
|
-
//# sourceMappingURL=chunk-
|
|
268
|
+
//# sourceMappingURL=chunk-UXJIZDXQ.mjs.map
|
|
@@ -15,7 +15,7 @@ var _chunkYCOW5GXGjs = require('./chunk-YCOW5GXG.js');
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
var
|
|
18
|
+
var _chunk72D7G6YQjs = require('./chunk-72D7G6YQ.js');
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
var _chunkDOOH4LMYjs = require('./chunk-DOOH4LMY.js');
|
|
@@ -48,7 +48,7 @@ var _chunkAN62GXF5js = require('./chunk-AN62GXF5.js');
|
|
|
48
48
|
var _chunkCAQ2Q3ONjs = require('./chunk-CAQ2Q3ON.js');
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
var
|
|
51
|
+
var _chunkKM27ZDHZjs = require('./chunk-KM27ZDHZ.js');
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
var _chunkXN2HPVVHjs = require('./chunk-XN2HPVVH.js');
|
|
@@ -250,13 +250,13 @@ var QuizContent = ({ paddingBottom }) => {
|
|
|
250
250
|
const currentQuestion = getCurrentQuestion();
|
|
251
251
|
const contentPaddingBottom = _nullishCoalesce(paddingBottom, () => ( (isMobile ? "pb-32" : "pb-24")));
|
|
252
252
|
const questionComponents = {
|
|
253
|
-
["ALTERNATIVA" /* ALTERNATIVA */]:
|
|
254
|
-
["MULTIPLA_ESCOLHA" /* MULTIPLA_ESCOLHA */]:
|
|
255
|
-
["DISSERTATIVA" /* DISSERTATIVA */]:
|
|
256
|
-
["VERDADEIRO_FALSO" /* VERDADEIRO_FALSO */]:
|
|
257
|
-
["RELACIONAR" /* RELACIONAR */]:
|
|
258
|
-
["PREENCHER_LACUNAS" /* PREENCHER_LACUNAS */]:
|
|
259
|
-
["IMAGEM" /* IMAGEM */]:
|
|
253
|
+
["ALTERNATIVA" /* ALTERNATIVA */]: _chunk72D7G6YQjs.QuizAlternative,
|
|
254
|
+
["MULTIPLA_ESCOLHA" /* MULTIPLA_ESCOLHA */]: _chunk72D7G6YQjs.QuizMultipleChoice,
|
|
255
|
+
["DISSERTATIVA" /* DISSERTATIVA */]: _chunk72D7G6YQjs.QuizDissertative,
|
|
256
|
+
["VERDADEIRO_FALSO" /* VERDADEIRO_FALSO */]: _chunk72D7G6YQjs.QuizTrueOrFalse,
|
|
257
|
+
["RELACIONAR" /* RELACIONAR */]: _chunk72D7G6YQjs.QuizConnectDots,
|
|
258
|
+
["PREENCHER_LACUNAS" /* PREENCHER_LACUNAS */]: _chunk72D7G6YQjs.QuizFill,
|
|
259
|
+
["IMAGEM" /* IMAGEM */]: _chunk72D7G6YQjs.QuizImageQuestion
|
|
260
260
|
};
|
|
261
261
|
const QuestionComponent = currentQuestion ? questionComponents[currentQuestion.questionType] : null;
|
|
262
262
|
if (!QuestionComponent) {
|
|
@@ -360,7 +360,7 @@ var QuizResultModal = ({
|
|
|
360
360
|
const titleId = _react.useId.call(void 0, );
|
|
361
361
|
const descriptionId = _react.useId.call(void 0, );
|
|
362
362
|
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
363
|
-
|
|
363
|
+
_chunkKM27ZDHZjs.Modal_default,
|
|
364
364
|
{
|
|
365
365
|
isOpen,
|
|
366
366
|
onClose,
|
|
@@ -754,7 +754,7 @@ var QuizFooter = _react.forwardRef.call(void 0,
|
|
|
754
754
|
}
|
|
755
755
|
),
|
|
756
756
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
757
|
-
|
|
757
|
+
_chunkKM27ZDHZjs.Modal_default,
|
|
758
758
|
{
|
|
759
759
|
isOpen: isModalOpen("modalNavigate"),
|
|
760
760
|
onClose: closeModal,
|
|
@@ -791,7 +791,7 @@ var QuizFooter = _react.forwardRef.call(void 0,
|
|
|
791
791
|
}
|
|
792
792
|
),
|
|
793
793
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
794
|
-
|
|
794
|
+
_chunkKM27ZDHZjs.Modal_default,
|
|
795
795
|
{
|
|
796
796
|
isOpen: isModalOpen("modalResolution"),
|
|
797
797
|
onClose: closeModal,
|
|
@@ -807,7 +807,7 @@ var QuizFooter = _react.forwardRef.call(void 0,
|
|
|
807
807
|
}
|
|
808
808
|
),
|
|
809
809
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
810
|
-
|
|
810
|
+
_chunkKM27ZDHZjs.Modal_default,
|
|
811
811
|
{
|
|
812
812
|
isOpen: isModalOpen("modalTeacherComment"),
|
|
813
813
|
onClose: closeModal,
|
|
@@ -954,4 +954,4 @@ var QuizFooter = _react.forwardRef.call(void 0,
|
|
|
954
954
|
|
|
955
955
|
|
|
956
956
|
exports.getQuizTypeConfig = getQuizTypeConfig; exports.getTypeLabel = getTypeLabel; exports.getQuizArticle = getQuizArticle; exports.getQuizPreposition = getQuizPreposition; exports.getCompletionTitle = getCompletionTitle; exports.getGoBackButtonLabel = getGoBackButtonLabel; exports.getExitConfirmationText = getExitConfirmationText; exports.getFinishConfirmationText = getFinishConfirmationText; exports.Quiz = Quiz; exports.QuizTitle = QuizTitle; exports.QuizHeader = QuizHeader; exports.QuizContent = QuizContent; exports.QuizQuestionList = QuizQuestionList; exports.QuizFooter = QuizFooter;
|
|
957
|
-
//# sourceMappingURL=chunk-
|
|
957
|
+
//# sourceMappingURL=chunk-UXMDPRAI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-PLLPFCN3.js","../src/components/Quiz/Quiz.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-PLLPFCN3.js","sourcesContent":[null,"import { BookOpenIcon } from '@phosphor-icons/react/dist/csr/BookOpen';\nimport { CaretLeftIcon } from '@phosphor-icons/react/dist/csr/CaretLeft';\nimport { CaretRightIcon } from '@phosphor-icons/react/dist/csr/CaretRight';\nimport { SquaresFourIcon } from '@phosphor-icons/react/dist/csr/SquaresFour';\nimport { HeaderAlternative } from '../Alternative/Alternative';\nimport Button from '../Button/Button';\nimport IconButton from '../IconButton/IconButton';\nimport {\n forwardRef,\n ReactNode,\n useEffect,\n useId,\n useRef,\n useState,\n ComponentType,\n} from 'react';\nimport {\n useQuizStore,\n QUESTION_TYPE,\n QUIZ_TYPE,\n AI_CORRECTION_STATUS,\n CORRECTION_SOURCE,\n} from './useQuizStore';\nimport CorrectionSourceTag from './CorrectionSourceTag';\nimport { resolveCorrectionText } from './correction.utils';\nimport { QuizVariant } from './Quiz.types';\nimport { AlertDialog } from '../AlertDialog/AlertDialog';\nimport Modal from '../Modal/Modal';\n\nimport Select, {\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../Select/Select';\nimport { cn } from '../../utils/utils';\nimport {\n QuizAlternative,\n QuizConnectDots,\n QuizDissertative,\n QuizFill,\n QuizImageQuestion,\n QuizMultipleChoice,\n QuizTrueOrFalse,\n} from './QuizContent';\nimport { CardStatus } from '../Card/Card';\nimport Text from '../Text/Text';\nimport HtmlMathRenderer from '../HtmlMathRenderer/HtmlMathRenderer';\nimport {\n formatExamInfo,\n getQuestionA11yIds,\n shouldShowExamInfo,\n} from './Quiz.utils';\nimport QuizTimer from '../QuizTimer/QuizTimer';\nimport { useMobile } from '../../hooks/useMobile';\n\n// Função para obter configuração do tipo de quiz\nexport const getQuizTypeConfig = (type: QUIZ_TYPE) => {\n // Configuração centralizada para cada tipo de quiz\n const QUIZ_TYPE_CONFIG = {\n [QUIZ_TYPE.SIMULADO]: {\n label: 'Simulado',\n article: 'o',\n preposition: 'do',\n },\n [QUIZ_TYPE.QUESTIONARIO]: {\n label: 'Questionário',\n article: 'o',\n preposition: 'do',\n },\n [QUIZ_TYPE.ATIVIDADE]: {\n label: 'Atividade',\n article: 'a',\n preposition: 'da',\n },\n [QUIZ_TYPE.AULA_RECOMENDADA]: {\n label: 'Aula recomendada',\n article: 'a',\n preposition: 'da',\n },\n } as const;\n\n const config = QUIZ_TYPE_CONFIG[type];\n return config || QUIZ_TYPE_CONFIG[QUIZ_TYPE.SIMULADO]; // fallback para simulado\n};\n\n// Função para obter o label do tipo\nexport const getTypeLabel = (type: QUIZ_TYPE) => {\n return getQuizTypeConfig(type).label;\n};\n\n// Função para obter o artigo (o/a)\nexport const getQuizArticle = (type: QUIZ_TYPE) => {\n return getQuizTypeConfig(type).article;\n};\n\n// Função para obter a preposição (do/da)\nexport const getQuizPreposition = (type: QUIZ_TYPE) => {\n return getQuizTypeConfig(type).preposition;\n};\n\n// Função para gerar título de conclusão\nexport const getCompletionTitle = (type: QUIZ_TYPE) => {\n const config = getQuizTypeConfig(type);\n return `Você concluiu ${config.article} ${config.label.toLowerCase()}!`;\n};\n\n// Função para gerar o rótulo do botão de retorno no modal de conclusão\nexport const getGoBackButtonLabel = (type: QUIZ_TYPE): string => {\n if (type === QUIZ_TYPE.SIMULADO) return 'Ir para simulados';\n if (type === QUIZ_TYPE.QUESTIONARIO) return 'Ir para aulas';\n if (type === QUIZ_TYPE.ATIVIDADE) return 'Ir para atividades';\n if (type === QUIZ_TYPE.AULA_RECOMENDADA) return 'Ir para aulas recomendadas';\n return 'Ir para simulados';\n};\n\n// Função para gerar texto de confirmação de saída\nexport const getExitConfirmationText = (type: QUIZ_TYPE) => {\n const config = getQuizTypeConfig(type);\n // QUESTIONARIO não tem rascunho: ao sair, as respostas são perdidas.\n // Demais tipos (SIMULADO, ATIVIDADE, AULA_RECOMENDADA e fallback) salvam o\n // progresso, então o aluno pode continuar depois de onde parou.\n if (type === QUIZ_TYPE.QUESTIONARIO) {\n return `Se você sair ${config.preposition} ${config.label.toLowerCase()} agora, todas as respostas serão perdidas.`;\n }\n return `Se você sair ${config.preposition} ${config.label.toLowerCase()} agora, poderá continuar de onde parou depois.`;\n};\n\n// Função para gerar texto de confirmação de finalização\nexport const getFinishConfirmationText = (type: QUIZ_TYPE) => {\n const config = getQuizTypeConfig(type);\n return `Tem certeza que deseja finalizar ${config.article} ${config.label.toLowerCase()}?`;\n};\n\nconst Quiz = forwardRef<\n HTMLDivElement,\n { children: ReactNode; className?: string; variant?: 'result' | 'default' }\n>(({ children, className, variant = QuizVariant.DEFAULT, ...props }, ref) => {\n const { setVariant } = useQuizStore();\n\n useEffect(() => {\n setVariant(variant as QuizVariant);\n }, [variant, setVariant]);\n\n return (\n <div ref={ref} className={cn('flex flex-col', className)} {...props}>\n {children}\n </div>\n );\n});\n\nconst QuizTitle = forwardRef<\n HTMLDivElement,\n { className?: string; onBack?: () => void; showTimer?: boolean }\n>(({ className, onBack, showTimer = false, ...props }, ref) => {\n const {\n quiz,\n currentQuestionIndex,\n getTotalQuestions,\n getQuizTitle,\n isStarted,\n } = useQuizStore();\n\n const [showExitConfirmation, setShowExitConfirmation] = useState(false);\n\n const totalQuestions = getTotalQuestions();\n const quizTitle = getQuizTitle();\n\n const handleBackClick = () => {\n if (isStarted) {\n setShowExitConfirmation(true);\n } else {\n actionOnBack();\n }\n };\n\n const handleConfirmExit = () => {\n setShowExitConfirmation(false);\n actionOnBack();\n };\n\n const actionOnBack = () => {\n if (onBack) {\n onBack();\n } else {\n globalThis.history.back();\n }\n };\n\n const handleCancelExit = () => {\n setShowExitConfirmation(false);\n };\n\n return (\n <>\n <div\n ref={ref}\n /*\n * Três colunas em vez de `justify-between`: as laterais são `1fr`\n * iguais, então o título fica centralizado na tela mesmo com o voltar\n * e o cronômetro tendo larguras diferentes. Com flex ele era empurrado\n * para a direita junto do cronômetro.\n */\n className={cn(\n 'grid grid-cols-[1fr_auto_1fr] items-center gap-2 relative p-2',\n className\n )}\n {...props}\n >\n <IconButton\n icon={<CaretLeftIcon size={24} />}\n size=\"md\"\n aria-label=\"Voltar\"\n onClick={handleBackClick}\n className=\"justify-self-start\"\n />\n <span className=\"flex flex-col gap-2 text-center\">\n <Text size=\"md\" weight=\"bold\" color=\"text-text-950\">\n {quizTitle}\n </Text>\n <Text size=\"xs\" color=\"text-text-600\">\n {totalQuestions > 0\n ? `${currentQuestionIndex + 1} de ${totalQuestions}`\n : '0 de 0'}\n </Text>\n </span>\n <div className=\"justify-self-end\">{showTimer && <QuizTimer />}</div>\n </div>\n\n <AlertDialog\n isOpen={showExitConfirmation}\n onChangeOpen={setShowExitConfirmation}\n title=\"Deseja sair?\"\n description={getExitConfirmationText(quiz?.type || QUIZ_TYPE.SIMULADO)}\n cancelButtonLabel=\"Voltar e revisar\"\n submitButtonLabel=\"Sair Mesmo Assim\"\n onSubmit={handleConfirmExit}\n onCancel={handleCancelExit}\n />\n </>\n );\n});\n\nconst QuizHeader = () => {\n const { getCurrentQuestion, getQuestionIndex, quiz, currentQuestionIndex } =\n useQuizStore();\n const currentQuestion = getCurrentQuestion();\n const titleRef = useRef<HTMLHeadingElement>(null);\n const previousIndexRef = useRef(currentQuestionIndex);\n\n // After \"Próxima\"/\"Anterior\" focus would stay on the footer button and the\n // new question would go unannounced. Moving it to the heading makes the\n // screen reader read it, and the next Tab lands on the answer controls.\n // The first render is skipped so opening the quiz does not steal focus.\n useEffect(() => {\n if (previousIndexRef.current === currentQuestionIndex) return;\n previousIndexRef.current = currentQuestionIndex;\n titleRef.current?.focus();\n }, [currentQuestionIndex]);\n let currentId =\n currentQuestion && 'questionId' in currentQuestion\n ? (currentQuestion.questionId as string)\n : currentQuestion?.id;\n const questionIndex = getQuestionIndex(currentId!);\n\n const questionNumber = currentQuestion\n ? `Questão ${questionIndex.toString().padStart(2, '0')}`\n : 'Questão';\n\n const showExamInfo = shouldShowExamInfo(quiz);\n const examInfo = showExamInfo\n ? formatExamInfo(currentQuestion?.examBoard, currentQuestion?.examYear)\n : '';\n\n const title = examInfo ? `${questionNumber} ${examInfo}` : questionNumber;\n\n const { titleId, statementId } = getQuestionA11yIds(currentQuestion?.id);\n\n return (\n <HeaderAlternative\n titleId={titleId}\n contentId={statementId}\n titleRef={titleRef}\n title={title}\n subTitle={currentQuestion?.knowledgeMatrix?.[0]?.topic?.name ?? ''}\n content={currentQuestion?.statement ?? ''}\n />\n );\n};\n\nconst QuizContent = ({ paddingBottom }: { paddingBottom?: string }) => {\n const { getCurrentQuestion } = useQuizStore();\n const { isMobile } = useMobile();\n const currentQuestion = getCurrentQuestion();\n\n // `QuizFooter` is `position: fixed`, so it sits on top of the content instead\n // of taking space in the flow — without room reserved here, the last\n // alternative ends up underneath it and unreadable. The bar is taller on a\n // phone, where its controls stack into two rows.\n const contentPaddingBottom = paddingBottom ?? (isMobile ? 'pb-32' : 'pb-24');\n const questionComponents: Record<\n string,\n ComponentType<QuizVariantInterface>\n > = {\n [QUESTION_TYPE.ALTERNATIVA]: QuizAlternative,\n [QUESTION_TYPE.MULTIPLA_ESCOLHA]: QuizMultipleChoice,\n [QUESTION_TYPE.DISSERTATIVA]: QuizDissertative,\n [QUESTION_TYPE.VERDADEIRO_FALSO]: QuizTrueOrFalse,\n [QUESTION_TYPE.RELACIONAR]: QuizConnectDots,\n [QUESTION_TYPE.PREENCHER_LACUNAS]: QuizFill,\n [QUESTION_TYPE.IMAGEM]: QuizImageQuestion,\n };\n\n const QuestionComponent = currentQuestion\n ? questionComponents[currentQuestion.questionType]\n : null;\n\n if (!QuestionComponent) {\n return (\n <Text size=\"md\" weight=\"medium\" className=\"text-text-950 text-md\">\n Tipo de questão não suportado\n </Text>\n );\n }\n\n // The teacher's comment is no longer echoed here: in the result variant it\n // lives behind the \"Ver comentário\" button in the footer, so it is not shown\n // twice on the same screen.\n return <QuestionComponent paddingBottom={contentPaddingBottom} />;\n};\n\ninterface QuizVariantInterface {\n paddingBottom?: string;\n}\n\nconst QuizQuestionList = ({\n filterType = 'all',\n onQuestionClick,\n}: {\n filterType?: string;\n onQuestionClick?: () => void;\n} = {}) => {\n const {\n getQuestionsGroupedBySubject,\n goToQuestion,\n getQuestionStatusFromUserAnswers,\n getQuestionIndex,\n quiz,\n } = useQuizStore();\n\n const showExamInfo = shouldShowExamInfo(quiz);\n\n const groupedQuestions = getQuestionsGroupedBySubject();\n const getQuestionStatus = (questionId: string) => {\n return getQuestionStatusFromUserAnswers(questionId);\n };\n const filteredGroupedQuestions = Object.entries(groupedQuestions).reduce(\n (acc, [subjectId, questions]) => {\n const filteredQuestions = questions.filter((question) => {\n const status = getQuestionStatus(question.id);\n switch (filterType) {\n case 'answered':\n return status === 'answered';\n case 'unanswered':\n return status === 'unanswered' || status === 'skipped';\n default:\n return true;\n }\n });\n\n if (filteredQuestions.length > 0) {\n acc[subjectId] = filteredQuestions;\n }\n\n return acc;\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n {} as { [key: string]: any[] }\n );\n\n const getStatusLabel = (status: string) => {\n switch (status) {\n case 'answered':\n return 'Respondida';\n case 'skipped':\n return 'Em branco';\n default:\n return 'Em branco';\n }\n };\n return (\n <div className=\"space-y-6 px-4 h-full\">\n {Object.entries(filteredGroupedQuestions).length == 0 && (\n <div className=\"flex items-center justify-center text-gray-500 py-8 h-full\">\n <p className=\"text-lg\">Nenhum resultado</p>\n </div>\n )}\n {Object.entries(filteredGroupedQuestions).map(\n ([subjectId, questions]) => (\n <section key={subjectId} className=\"flex flex-col gap-2\">\n <span className=\"pt-6 pb-4 flex flex-row gap-2\">\n <div\n className=\"bg-primary-500 p-1 rounded-sm flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <BookOpenIcon size={17} className=\"text-white\" />\n </div>\n <h3 className=\"text-text-800 font-bold text-lg\">\n {questions?.[0]?.knowledgeMatrix?.[0]?.subject?.name ??\n 'Sem componente curricular'}\n </h3>\n </span>\n\n <ul className=\"flex flex-col gap-2\">\n {questions.map((question) => {\n const status = getQuestionStatus(question.id);\n const questionNumber = getQuestionIndex(question.id);\n const examInfo = showExamInfo\n ? formatExamInfo(question.examBoard, question.examYear)\n : '';\n const questionTitle = `Questão ${questionNumber.toString().padStart(2, '0')}`;\n const header = examInfo\n ? `${questionTitle} ${examInfo}`\n : questionTitle;\n return (\n <li key={question.id}>\n <CardStatus\n header={header}\n label={getStatusLabel(status)}\n onClick={() => {\n goToQuestion(questionNumber - 1);\n onQuestionClick?.();\n }}\n />\n </li>\n );\n })}\n </ul>\n </section>\n )\n )}\n </div>\n );\n};\n\n/**\n * Shared layout for the quiz result modals (generic result, all-correct and\n * all-incorrect questionnaire variants): a centered image, a title and a\n * footer with action buttons.\n */\nconst QuizResultModal = ({\n isOpen,\n onClose,\n image,\n showImagePlaceholder = true,\n title,\n description,\n footer,\n}: {\n isOpen: boolean;\n onClose: () => void;\n image?: ReactNode;\n showImagePlaceholder?: boolean;\n title: ReactNode;\n description: ReactNode;\n footer: ReactNode;\n}) => {\n const titleId = useId();\n const descriptionId = useId();\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title=\"\"\n labelledBy={titleId}\n describedBy={descriptionId}\n closeOnEscape={false}\n hideCloseButton\n size={'md'}\n >\n <div className=\"flex flex-col w-full h-full items-center justify-center gap-4\">\n {image ? (\n <div className=\"w-[282px] h-auto\">{image}</div>\n ) : (\n showImagePlaceholder && (\n // Placeholder puramente visual (sem imagem real): fora da leitura.\n <div\n className=\"w-[282px] h-[200px] bg-gray-100 rounded-md flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <Text as=\"span\" size=\"sm\" color=\"text-gray-500\">\n Imagem de resultado\n </Text>\n </div>\n )\n )}\n <div className=\"flex flex-col gap-2 text-center\">\n <Text as=\"h2\" id={titleId} size=\"lg\" weight=\"bold\">\n {title}\n </Text>\n <div id={descriptionId} className=\"flex flex-col gap-2\">\n {description}\n </div>\n </div>\n {footer}\n </div>\n </Modal>\n );\n};\n\n/**\n * Correction of the question currently on screen, resolved once.\n *\n * A dissertativa may have been graded by the AI. The teacher's text wins when it\n * exists, the AI's stands otherwise; the two are never merged — the backend\n * keeps them in separate columns precisely so a review does not destroy the\n * original verdict — and `correctionSource` says which one is on screen.\n *\n * It lives here, and not inline in `QuizFooter`, because both the footer (for\n * the modal body and title) and `QuizReviewActions` (for the buttons) need the\n * same four values, and deriving them twice would be two chances to disagree.\n *\n * @returns The effective comment plus the fields the tag and the title read\n */\nconst useCurrentCorrection = () => {\n const { getCurrentQuestion, getQuestionResultByQuestionId } = useQuizStore();\n\n const currentQuestion = getCurrentQuestion();\n const result = currentQuestion\n ? getQuestionResultByQuestionId(currentQuestion.id)\n : null;\n\n return {\n comment: resolveCorrectionText({ ...result }),\n correctionSource: result?.correctionSource,\n aiCorrectionStatus: result?.aiCorrectionStatus,\n };\n};\n\n/**\n * Title for the per-question feedback modal, phrased for whoever wrote it.\n *\n * Calling an AI correction \"Comentário do professor\" would be a lie the tag\n * inside the modal immediately contradicts, so both are derived from the same\n * `correctionSource`.\n *\n * @param correctionSource - Who produced the correction on display\n * @returns The modal title\n */\nconst getCorrectionModalTitle = (\n correctionSource?: CORRECTION_SOURCE | null\n): string => {\n if (correctionSource === CORRECTION_SOURCE.IA) {\n return 'Correção por IA';\n }\n\n if (correctionSource === CORRECTION_SOURCE.IA_PROFESSOR) {\n return 'Correção revisada pelo professor';\n }\n\n return 'Comentário do professor';\n};\n\n/**\n * The review bar's question-scoped actions: see the resolution, see the correction.\n *\n * Split out of `QuizFooter` because the two bars do different jobs — the\n * `default` one navigates between questions, this one reads a question already\n * graded — and because the four conditions the correction needs pushed the\n * footer past the cognitive-complexity limit while sitting in the middle of\n * unrelated navigation markup.\n *\n * @param props - Callbacks that open the footer's modals\n * @returns JSX element\n */\nconst QuizReviewActions = ({\n onOpenResolution,\n onOpenComment,\n className,\n}: {\n onOpenResolution: () => void;\n onOpenComment: () => void;\n readonly className?: string;\n}) => {\n const { getCurrentQuestion } = useQuizStore();\n const { comment, correctionSource, aiCorrectionStatus } =\n useCurrentCorrection();\n\n const currentQuestion = getCurrentQuestion();\n const hasResolution = Boolean(currentQuestion?.solutionExplanation);\n const isAiCorrecting = aiCorrectionStatus === AI_CORRECTION_STATUS.PENDING;\n const commentLabel =\n correctionSource === CORRECTION_SOURCE.IA\n ? 'Ver correção da IA'\n : 'Ver comentário';\n\n return (\n <div className={className}>\n {hasResolution && (\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"large\"\n onClick={onOpenResolution}\n >\n Ver resolução\n </Button>\n )}\n {comment && (\n <Button\n variant=\"outline\"\n action=\"primary\"\n size=\"large\"\n onClick={onOpenComment}\n >\n {commentLabel}\n </Button>\n )}\n {/* Sem comentário ainda, mas a IA está corrigindo: o aluno acaba de\n entregar e chegou aqui antes do feedback existir. Dizer que está a\n caminho é melhor do que não mostrar nada. */}\n {!comment && isAiCorrecting && (\n <CorrectionSourceTag\n aiCorrectionStatus={aiCorrectionStatus}\n className=\"self-center\"\n />\n )}\n </div>\n );\n};\n\n/**\n * What the completion modal shows instead of the score.\n *\n * Some exams are not corrected on the spot — the in-classroom ENEM simulation\n * is graded later — so telling the student how many they got right would be\n * wrong. With this set, finishing opens a modal with only this content and\n * one button.\n */\nexport interface QuizCompletionOverride {\n title: ReactNode;\n description: ReactNode;\n buttonLabel: string;\n onConfirm: () => void;\n}\n\nconst QuizFooter = forwardRef<\n HTMLDivElement,\n {\n className?: string;\n onGoToSimulated?: () => void;\n onDetailResult?: () => void;\n handleFinishSimulated?: () => void;\n onGoToNextModule?: () => void;\n onRepeat?: () => void;\n onTryLater?: () => void;\n resultImageComponent?: ReactNode;\n resultIncorrectImageComponent?: ReactNode;\n /** Replaces the score modal; see `QuizCompletionOverride`. */\n completionOverride?: QuizCompletionOverride;\n }\n>(\n (\n {\n className,\n onGoToSimulated,\n onDetailResult,\n handleFinishSimulated,\n onGoToNextModule,\n onRepeat,\n onTryLater,\n resultImageComponent,\n resultIncorrectImageComponent,\n completionOverride,\n ...props\n },\n ref\n ) => {\n const {\n quiz,\n currentQuestionIndex,\n getTotalQuestions,\n goToNextQuestion,\n goToPreviousQuestion,\n getUnansweredQuestionsFromUserAnswers,\n getCurrentAnswer,\n skipQuestion,\n skipCurrentQuestionIfUnanswered,\n getCurrentQuestion,\n getQuestionStatusFromUserAnswers,\n variant,\n getQuestionResultStatistics,\n } = useQuizStore();\n\n // The review bar carries four controls. Below ~500px they no longer fit on\n // one line, so the actions and the pagination stack into two centred rows.\n const { isMobile } = useMobile();\n\n const totalQuestions = getTotalQuestions();\n const isFirstQuestion = currentQuestionIndex === 0;\n const isLastQuestion = currentQuestionIndex === totalQuestions - 1;\n const currentAnswer = getCurrentAnswer();\n const currentQuestion = getCurrentQuestion();\n const {\n comment: teacherComment,\n correctionSource,\n aiCorrectionStatus,\n } = useCurrentCorrection();\n const isCurrentQuestionSkipped = currentQuestion\n ? getQuestionStatusFromUserAnswers(currentQuestion.id) === 'skipped'\n : false;\n // Sistema unificado de controle de modais\n const [activeModal, setActiveModal] = useState<string | null>(null);\n const [filterType, setFilterType] = useState<string>('all');\n const filterLabelId = useId();\n\n // Funções para controlar modais\n const openModal = (modalName: string) => setActiveModal(modalName);\n const closeModal = () => setActiveModal(null);\n const isModalOpen = (modalName: string) => activeModal === modalName;\n const unansweredQuestions = getUnansweredQuestionsFromUserAnswers();\n const allQuestions = getTotalQuestions();\n const stats = getQuestionResultStatistics();\n const correctAnswers = stats?.correctAnswers;\n const quizType = quiz?.type || QUIZ_TYPE.SIMULADO;\n const quizTypeLabel = getTypeLabel(quizType);\n // Real subtopic name, used to label the questionnaire completion modals.\n // The backend always populates the question knowledge matrix, so this is\n // available as soon as the quiz is loaded.\n const moduleName =\n quiz?.questions?.[0]?.knowledgeMatrix?.[0]?.subtopic?.name;\n\n // Submits the answers and opens the correct result modal. Statistics must\n // be read AFTER handleFinishSimulated, which is what populates\n // questionsResult in the store (the render-time values are still empty).\n const submitAndOpenResultModal = async () => {\n if (handleFinishSimulated) {\n await Promise.resolve(handleFinishSimulated());\n }\n\n if (completionOverride) {\n openModal('modalCompletionOverride');\n return;\n }\n\n const latestStats = getQuestionResultStatistics();\n const latestCorrect = latestStats?.correctAnswers;\n const latestTotal = latestStats?.totalAnswered;\n\n if (\n quizType === QUIZ_TYPE.QUESTIONARIO &&\n typeof latestCorrect === 'number' &&\n typeof latestTotal === 'number' &&\n latestCorrect === latestTotal\n ) {\n openModal('modalQuestionnaireAllCorrect');\n return;\n }\n\n if (\n quizType === QUIZ_TYPE.QUESTIONARIO &&\n typeof latestCorrect === 'number' &&\n latestCorrect === 0\n ) {\n openModal('modalQuestionnaireAllIncorrect');\n return;\n }\n\n openModal('modalResult');\n };\n\n const handleFinishQuiz = async () => {\n // Marca a questão atual como pulada se não foi respondida\n skipCurrentQuestionIfUnanswered();\n\n if (unansweredQuestions.length > 0) {\n openModal('alertDialog');\n return;\n }\n\n try {\n await submitAndOpenResultModal();\n } catch (err) {\n console.error('handleFinishSimulated failed:', err);\n }\n };\n\n const handleAlertSubmit = async () => {\n try {\n await submitAndOpenResultModal();\n } catch (err) {\n console.error('handleFinishSimulated failed:', err);\n closeModal();\n }\n };\n\n return (\n <>\n <footer\n ref={ref}\n className={cn(\n 'w-full px-2 bg-background lg:max-w-[1000px] not-lg:max-w-[calc(100vw-32px)] border-t border-border-50 fixed bottom-0 min-h-[80px] flex flex-row justify-between items-center',\n className\n )}\n // No modo resultado o rodapé é a navegação entre questões; o nome\n // distingue esta região das demais para quem navega por marcos.\n aria-label={\n variant === 'default' ? undefined : 'Navegação entre questões'\n }\n {...props}\n >\n {variant === 'default' ? (\n <>\n <div className=\"flex flex-row items-center gap-1\">\n <IconButton\n icon={<SquaresFourIcon size={24} className=\"text-text-950\" />}\n size=\"md\"\n aria-label=\"Lista de todas as questões\"\n aria-haspopup=\"dialog\"\n onClick={() => openModal('modalNavigate')}\n />\n\n {isFirstQuestion ? (\n <Button\n variant=\"outline\"\n size=\"small\"\n aria-label=\"Pular questão\"\n onClick={() => {\n skipQuestion();\n goToNextQuestion();\n }}\n >\n Pular\n </Button>\n ) : (\n <Button\n size=\"medium\"\n variant=\"link\"\n action=\"primary\"\n iconLeft={<CaretLeftIcon size={18} aria-hidden=\"true\" />}\n aria-label=\"Voltar à questão anterior\"\n onClick={() => {\n goToPreviousQuestion();\n }}\n >\n Voltar\n </Button>\n )}\n </div>\n\n {!isFirstQuestion && !isLastQuestion && (\n <Button\n size=\"small\"\n variant=\"outline\"\n action=\"primary\"\n aria-label=\"Pular questão\"\n onClick={() => {\n skipQuestion();\n goToNextQuestion();\n }}\n >\n Pular\n </Button>\n )}\n\n {isLastQuestion ? (\n <Button\n size=\"medium\"\n variant=\"solid\"\n action=\"primary\"\n aria-label={`Finalizar ${quizTypeLabel.toLowerCase()}`}\n onClick={handleFinishQuiz}\n >\n Finalizar\n </Button>\n ) : (\n <Button\n size=\"medium\"\n variant=\"link\"\n action=\"primary\"\n iconRight={<CaretRightIcon size={18} aria-hidden=\"true\" />}\n aria-label=\"Avançar para a próxima questão\"\n disabled={!currentAnswer && !isCurrentQuestionSkipped}\n onClick={() => {\n goToNextQuestion();\n }}\n >\n Avançar\n </Button>\n )}\n </>\n ) : (\n <div\n className={cn(\n 'flex w-full items-center gap-2',\n isMobile ? 'flex-col py-2' : 'flex-row'\n )}\n >\n <QuizReviewActions\n className={cn(\n 'flex flex-row items-center gap-2',\n isMobile && 'justify-center'\n )}\n onOpenResolution={() => openModal('modalResolution')}\n onOpenComment={() => openModal('modalTeacherComment')}\n />\n {/* On a wide bar the pagination sits at the far end, away from the\n actions that act on the question being read; stacked, it is\n centred under them. */}\n <div\n className={cn(\n 'flex flex-row items-center gap-2',\n isMobile ? 'justify-center' : 'flex-1 justify-end'\n )}\n >\n {/* Posição atual anunciada em texto: os botões só têm setas. */}\n <Text as=\"span\" className=\"sr-only\">\n {`Questão ${currentQuestionIndex + 1} de ${totalQuestions}`}\n </Text>\n <Button\n variant=\"outline\"\n action=\"primary\"\n size=\"medium\"\n aria-label=\"Questão anterior\"\n disabled={isFirstQuestion}\n onClick={goToPreviousQuestion}\n >\n <CaretLeftIcon size={18} aria-hidden=\"true\" />\n </Button>\n <Button\n variant=\"outline\"\n action=\"primary\"\n size=\"medium\"\n aria-label=\"Próxima questão\"\n disabled={isLastQuestion}\n onClick={goToNextQuestion}\n >\n <CaretRightIcon size={18} aria-hidden=\"true\" />\n </Button>\n </div>\n </div>\n )}\n </footer>\n\n <AlertDialog\n isOpen={isModalOpen('alertDialog')}\n onChangeOpen={(open) =>\n open ? openModal('alertDialog') : closeModal()\n }\n title={`Finalizar ${quizTypeLabel.toLowerCase()}?`}\n description={\n unansweredQuestions.length > 0\n ? `Você deixou as questões ${unansweredQuestions.join(', ')} sem resposta. Finalizar agora pode impactar seu desempenho.`\n : getFinishConfirmationText(quizType)\n }\n cancelButtonLabel=\"Voltar e revisar\"\n submitButtonLabel=\"Finalizar Mesmo Assim\"\n onSubmit={handleAlertSubmit}\n />\n\n <QuizResultModal\n isOpen={isModalOpen('modalResult')}\n onClose={closeModal}\n image={resultImageComponent}\n title={getCompletionTitle(quizType)}\n description={\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Você acertou {correctAnswers ?? '--'} de {allQuestions} questões.\n </Text>\n }\n footer={\n <div className=\"px-6 flex flex-row items-center gap-2 w-full\">\n <Button\n variant=\"outline\"\n className=\"w-full\"\n size=\"small\"\n onClick={onGoToSimulated}\n >\n {getGoBackButtonLabel(quizType)}\n </Button>\n\n <Button className=\"w-full\" onClick={onDetailResult}>\n Detalhar resultado\n </Button>\n </div>\n }\n />\n\n {completionOverride && (\n <QuizResultModal\n isOpen={isModalOpen('modalCompletionOverride')}\n onClose={closeModal}\n image={resultImageComponent}\n title={completionOverride.title}\n description={\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n {completionOverride.description}\n </Text>\n }\n footer={\n <div className=\"px-6 flex flex-row items-center w-full\">\n <Button\n className=\"w-full\"\n onClick={completionOverride.onConfirm}\n data-testid=\"quiz-completion-override-confirm\"\n >\n {completionOverride.buttonLabel}\n </Button>\n </div>\n }\n />\n )}\n\n <Modal\n isOpen={isModalOpen('modalNavigate')}\n onClose={closeModal}\n title=\"Questões\"\n size={'lg'}\n >\n <div className=\"flex flex-col w-full not-lg:h-[calc(100vh-200px)] lg:max-h-[687px] lg:h-[687px]\">\n <div className=\"flex flex-row justify-between items-center py-6 pt-6 pb-4 border-b border-border-200 flex-shrink-0\">\n <p id={filterLabelId} className=\"text-text-950 font-bold text-lg\">\n Filtrar por\n </p>\n <span className=\"max-w-[266px]\">\n <Select value={filterType} onValueChange={setFilterType}>\n <SelectTrigger\n aria-labelledby={filterLabelId}\n variant=\"rounded\"\n className=\"max-w-[266px] min-w-[160px]\"\n >\n <SelectValue placeholder=\"Selecione uma opção\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">Todas</SelectItem>\n <SelectItem value=\"unanswered\">Em branco</SelectItem>\n <SelectItem value=\"answered\">Respondidas</SelectItem>\n </SelectContent>\n </Select>\n </span>\n </div>\n\n <div className=\"flex flex-col gap-2 flex-1 min-h-0 overflow-y-auto\">\n <QuizQuestionList\n filterType={filterType}\n onQuestionClick={closeModal}\n />\n </div>\n </div>\n </Modal>\n\n <Modal\n isOpen={isModalOpen('modalResolution')}\n onClose={closeModal}\n title=\"Resolução\"\n size={'lg'}\n >\n <HtmlMathRenderer\n content={currentQuestion?.solutionExplanation || ''}\n className=\"text-text-950 text-base\"\n />\n </Modal>\n\n <Modal\n isOpen={isModalOpen('modalTeacherComment')}\n onClose={closeModal}\n title={getCorrectionModalTitle(correctionSource)}\n size={'lg'}\n >\n {/* A tag fica dentro do modal, junto do texto: é ela que diz se o que\n está sendo lido saiu da IA, do professor, ou da IA revisada por\n ele. Sem isso o título sozinho teria que carregar essa informação\n em toda variação. */}\n <CorrectionSourceTag\n correctionSource={correctionSource}\n aiCorrectionStatus={aiCorrectionStatus}\n className=\"mb-3\"\n />\n {/* Plain text on purpose: the teacher writes this in a bare textarea,\n so running it through the HTML/LaTeX renderer would change what\n they typed. `whitespace-pre-wrap` keeps their line breaks. The AI\n feedback is plain text for the same reason. */}\n <Text\n size=\"md\"\n className=\"text-text-950 whitespace-pre-wrap break-words\"\n >\n {teacherComment}\n </Text>\n </Modal>\n\n <QuizResultModal\n isOpen={isModalOpen('modalQuestionnaireAllCorrect')}\n onClose={closeModal}\n image={resultImageComponent}\n // Emoji decorativo: o leitor anunciaria o nome dele antes do título.\n title={\n <>\n <Text as=\"span\" size=\"lg\" weight=\"bold\" aria-hidden=\"true\">\n 🎉\n </Text>{' '}\n Parabéns!\n </>\n }\n description={\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n {moduleName\n ? `Você concluiu o módulo ${moduleName}.`\n : 'Você concluiu o questionário!'}\n </Text>\n }\n footer={\n <div className=\"px-6 flex flex-row items-center gap-2 w-full\">\n <Button className=\"w-full\" onClick={onGoToNextModule}>\n {getGoBackButtonLabel(quizType)}\n </Button>\n </div>\n }\n />\n\n <QuizResultModal\n isOpen={isModalOpen('modalQuestionnaireAllIncorrect')}\n onClose={closeModal}\n image={resultIncorrectImageComponent}\n showImagePlaceholder={false}\n title={\n <>\n <Text as=\"span\" size=\"lg\" weight=\"bold\" aria-hidden=\"true\">\n 😕\n </Text>{' '}\n Não foi dessa vez...\n </>\n }\n description={\n <>\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Você tirou 0 no questionário, mas não se preocupe! Isso é apenas\n uma oportunidade de aprendizado.\n </Text>\n\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Que tal tentar novamente para melhorar sua nota? Estamos aqui\n para te ajudar a entender o conteúdo e evoluir.\n </Text>\n\n {quiz?.canRetry && (\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Clique em Repetir Questionário e mostre do que você é capaz!{' '}\n <Text\n as=\"span\"\n size=\"sm\"\n color=\"text-text-500\"\n aria-hidden=\"true\"\n >\n 💪\n </Text>\n </Text>\n )}\n </>\n }\n footer={\n <div className=\"flex flex-row justify-center items-center gap-2 w-full\">\n {quiz?.canRetry && (\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"small\"\n className=\"w-auto\"\n onClick={() => {\n closeModal();\n openModal('alertDialogTryLater');\n }}\n >\n Tentar depois\n </Button>\n )}\n\n <Button\n variant=\"outline\"\n size=\"small\"\n className=\"w-auto\"\n onClick={onDetailResult}\n >\n Detalhar resultado\n </Button>\n\n {quiz?.canRetry ? (\n <Button className=\"w-auto\" size=\"small\" onClick={onRepeat}>\n Repetir questionário\n </Button>\n ) : (\n <Button\n className=\"w-auto\"\n size=\"small\"\n onClick={onGoToSimulated}\n >\n {getGoBackButtonLabel(quizType)}\n </Button>\n )}\n </div>\n }\n />\n\n <AlertDialog\n isOpen={isModalOpen('alertDialogTryLater')}\n onChangeOpen={(open) =>\n open ? openModal('alertDialogTryLater') : closeModal()\n }\n title=\"Tentar depois?\"\n description={\n 'Você optou por refazer o questionário mais tarde.\\n\\nLembre-se: enquanto não refazer o questionário, sua nota permanecerá 0 no sistema.'\n }\n cancelButtonLabel=\"Repetir questionário\"\n submitButtonLabel=\"Tentar depois\"\n onSubmit={() => {\n onTryLater?.();\n closeModal();\n }}\n onCancel={() => {\n onRepeat?.();\n closeModal();\n }}\n />\n </>\n );\n }\n);\n\nexport {\n QuizTitle,\n Quiz,\n QuizHeader,\n QuizContent,\n QuizFooter,\n QuizQuestionList,\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-UXMDPRAI.js","../src/components/Quiz/Quiz.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-UXMDPRAI.js","sourcesContent":[null,"import { BookOpenIcon } from '@phosphor-icons/react/dist/csr/BookOpen';\nimport { CaretLeftIcon } from '@phosphor-icons/react/dist/csr/CaretLeft';\nimport { CaretRightIcon } from '@phosphor-icons/react/dist/csr/CaretRight';\nimport { SquaresFourIcon } from '@phosphor-icons/react/dist/csr/SquaresFour';\nimport { HeaderAlternative } from '../Alternative/Alternative';\nimport Button from '../Button/Button';\nimport IconButton from '../IconButton/IconButton';\nimport {\n forwardRef,\n ReactNode,\n useEffect,\n useId,\n useRef,\n useState,\n ComponentType,\n} from 'react';\nimport {\n useQuizStore,\n QUESTION_TYPE,\n QUIZ_TYPE,\n AI_CORRECTION_STATUS,\n CORRECTION_SOURCE,\n} from './useQuizStore';\nimport CorrectionSourceTag from './CorrectionSourceTag';\nimport { resolveCorrectionText } from './correction.utils';\nimport { QuizVariant } from './Quiz.types';\nimport { AlertDialog } from '../AlertDialog/AlertDialog';\nimport Modal from '../Modal/Modal';\n\nimport Select, {\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../Select/Select';\nimport { cn } from '../../utils/utils';\nimport {\n QuizAlternative,\n QuizConnectDots,\n QuizDissertative,\n QuizFill,\n QuizImageQuestion,\n QuizMultipleChoice,\n QuizTrueOrFalse,\n} from './QuizContent';\nimport { CardStatus } from '../Card/Card';\nimport Text from '../Text/Text';\nimport HtmlMathRenderer from '../HtmlMathRenderer/HtmlMathRenderer';\nimport {\n formatExamInfo,\n getQuestionA11yIds,\n shouldShowExamInfo,\n} from './Quiz.utils';\nimport QuizTimer from '../QuizTimer/QuizTimer';\nimport { useMobile } from '../../hooks/useMobile';\n\n// Função para obter configuração do tipo de quiz\nexport const getQuizTypeConfig = (type: QUIZ_TYPE) => {\n // Configuração centralizada para cada tipo de quiz\n const QUIZ_TYPE_CONFIG = {\n [QUIZ_TYPE.SIMULADO]: {\n label: 'Simulado',\n article: 'o',\n preposition: 'do',\n },\n [QUIZ_TYPE.QUESTIONARIO]: {\n label: 'Questionário',\n article: 'o',\n preposition: 'do',\n },\n [QUIZ_TYPE.ATIVIDADE]: {\n label: 'Atividade',\n article: 'a',\n preposition: 'da',\n },\n [QUIZ_TYPE.AULA_RECOMENDADA]: {\n label: 'Aula recomendada',\n article: 'a',\n preposition: 'da',\n },\n } as const;\n\n const config = QUIZ_TYPE_CONFIG[type];\n return config || QUIZ_TYPE_CONFIG[QUIZ_TYPE.SIMULADO]; // fallback para simulado\n};\n\n// Função para obter o label do tipo\nexport const getTypeLabel = (type: QUIZ_TYPE) => {\n return getQuizTypeConfig(type).label;\n};\n\n// Função para obter o artigo (o/a)\nexport const getQuizArticle = (type: QUIZ_TYPE) => {\n return getQuizTypeConfig(type).article;\n};\n\n// Função para obter a preposição (do/da)\nexport const getQuizPreposition = (type: QUIZ_TYPE) => {\n return getQuizTypeConfig(type).preposition;\n};\n\n// Função para gerar título de conclusão\nexport const getCompletionTitle = (type: QUIZ_TYPE) => {\n const config = getQuizTypeConfig(type);\n return `Você concluiu ${config.article} ${config.label.toLowerCase()}!`;\n};\n\n// Função para gerar o rótulo do botão de retorno no modal de conclusão\nexport const getGoBackButtonLabel = (type: QUIZ_TYPE): string => {\n if (type === QUIZ_TYPE.SIMULADO) return 'Ir para simulados';\n if (type === QUIZ_TYPE.QUESTIONARIO) return 'Ir para aulas';\n if (type === QUIZ_TYPE.ATIVIDADE) return 'Ir para atividades';\n if (type === QUIZ_TYPE.AULA_RECOMENDADA) return 'Ir para aulas recomendadas';\n return 'Ir para simulados';\n};\n\n// Função para gerar texto de confirmação de saída\nexport const getExitConfirmationText = (type: QUIZ_TYPE) => {\n const config = getQuizTypeConfig(type);\n // QUESTIONARIO não tem rascunho: ao sair, as respostas são perdidas.\n // Demais tipos (SIMULADO, ATIVIDADE, AULA_RECOMENDADA e fallback) salvam o\n // progresso, então o aluno pode continuar depois de onde parou.\n if (type === QUIZ_TYPE.QUESTIONARIO) {\n return `Se você sair ${config.preposition} ${config.label.toLowerCase()} agora, todas as respostas serão perdidas.`;\n }\n return `Se você sair ${config.preposition} ${config.label.toLowerCase()} agora, poderá continuar de onde parou depois.`;\n};\n\n// Função para gerar texto de confirmação de finalização\nexport const getFinishConfirmationText = (type: QUIZ_TYPE) => {\n const config = getQuizTypeConfig(type);\n return `Tem certeza que deseja finalizar ${config.article} ${config.label.toLowerCase()}?`;\n};\n\nconst Quiz = forwardRef<\n HTMLDivElement,\n { children: ReactNode; className?: string; variant?: 'result' | 'default' }\n>(({ children, className, variant = QuizVariant.DEFAULT, ...props }, ref) => {\n const { setVariant } = useQuizStore();\n\n useEffect(() => {\n setVariant(variant as QuizVariant);\n }, [variant, setVariant]);\n\n return (\n <div ref={ref} className={cn('flex flex-col', className)} {...props}>\n {children}\n </div>\n );\n});\n\nconst QuizTitle = forwardRef<\n HTMLDivElement,\n { className?: string; onBack?: () => void; showTimer?: boolean }\n>(({ className, onBack, showTimer = false, ...props }, ref) => {\n const {\n quiz,\n currentQuestionIndex,\n getTotalQuestions,\n getQuizTitle,\n isStarted,\n } = useQuizStore();\n\n const [showExitConfirmation, setShowExitConfirmation] = useState(false);\n\n const totalQuestions = getTotalQuestions();\n const quizTitle = getQuizTitle();\n\n const handleBackClick = () => {\n if (isStarted) {\n setShowExitConfirmation(true);\n } else {\n actionOnBack();\n }\n };\n\n const handleConfirmExit = () => {\n setShowExitConfirmation(false);\n actionOnBack();\n };\n\n const actionOnBack = () => {\n if (onBack) {\n onBack();\n } else {\n globalThis.history.back();\n }\n };\n\n const handleCancelExit = () => {\n setShowExitConfirmation(false);\n };\n\n return (\n <>\n <div\n ref={ref}\n /*\n * Três colunas em vez de `justify-between`: as laterais são `1fr`\n * iguais, então o título fica centralizado na tela mesmo com o voltar\n * e o cronômetro tendo larguras diferentes. Com flex ele era empurrado\n * para a direita junto do cronômetro.\n */\n className={cn(\n 'grid grid-cols-[1fr_auto_1fr] items-center gap-2 relative p-2',\n className\n )}\n {...props}\n >\n <IconButton\n icon={<CaretLeftIcon size={24} />}\n size=\"md\"\n aria-label=\"Voltar\"\n onClick={handleBackClick}\n className=\"justify-self-start\"\n />\n <span className=\"flex flex-col gap-2 text-center\">\n <Text size=\"md\" weight=\"bold\" color=\"text-text-950\">\n {quizTitle}\n </Text>\n <Text size=\"xs\" color=\"text-text-600\">\n {totalQuestions > 0\n ? `${currentQuestionIndex + 1} de ${totalQuestions}`\n : '0 de 0'}\n </Text>\n </span>\n <div className=\"justify-self-end\">{showTimer && <QuizTimer />}</div>\n </div>\n\n <AlertDialog\n isOpen={showExitConfirmation}\n onChangeOpen={setShowExitConfirmation}\n title=\"Deseja sair?\"\n description={getExitConfirmationText(quiz?.type || QUIZ_TYPE.SIMULADO)}\n cancelButtonLabel=\"Voltar e revisar\"\n submitButtonLabel=\"Sair Mesmo Assim\"\n onSubmit={handleConfirmExit}\n onCancel={handleCancelExit}\n />\n </>\n );\n});\n\nconst QuizHeader = () => {\n const { getCurrentQuestion, getQuestionIndex, quiz, currentQuestionIndex } =\n useQuizStore();\n const currentQuestion = getCurrentQuestion();\n const titleRef = useRef<HTMLHeadingElement>(null);\n const previousIndexRef = useRef(currentQuestionIndex);\n\n // After \"Próxima\"/\"Anterior\" focus would stay on the footer button and the\n // new question would go unannounced. Moving it to the heading makes the\n // screen reader read it, and the next Tab lands on the answer controls.\n // The first render is skipped so opening the quiz does not steal focus.\n useEffect(() => {\n if (previousIndexRef.current === currentQuestionIndex) return;\n previousIndexRef.current = currentQuestionIndex;\n titleRef.current?.focus();\n }, [currentQuestionIndex]);\n let currentId =\n currentQuestion && 'questionId' in currentQuestion\n ? (currentQuestion.questionId as string)\n : currentQuestion?.id;\n const questionIndex = getQuestionIndex(currentId!);\n\n const questionNumber = currentQuestion\n ? `Questão ${questionIndex.toString().padStart(2, '0')}`\n : 'Questão';\n\n const showExamInfo = shouldShowExamInfo(quiz);\n const examInfo = showExamInfo\n ? formatExamInfo(currentQuestion?.examBoard, currentQuestion?.examYear)\n : '';\n\n const title = examInfo ? `${questionNumber} ${examInfo}` : questionNumber;\n\n const { titleId, statementId } = getQuestionA11yIds(currentQuestion?.id);\n\n return (\n <HeaderAlternative\n titleId={titleId}\n contentId={statementId}\n titleRef={titleRef}\n title={title}\n subTitle={currentQuestion?.knowledgeMatrix?.[0]?.topic?.name ?? ''}\n content={currentQuestion?.statement ?? ''}\n />\n );\n};\n\nconst QuizContent = ({ paddingBottom }: { paddingBottom?: string }) => {\n const { getCurrentQuestion } = useQuizStore();\n const { isMobile } = useMobile();\n const currentQuestion = getCurrentQuestion();\n\n // `QuizFooter` is `position: fixed`, so it sits on top of the content instead\n // of taking space in the flow — without room reserved here, the last\n // alternative ends up underneath it and unreadable. The bar is taller on a\n // phone, where its controls stack into two rows.\n const contentPaddingBottom = paddingBottom ?? (isMobile ? 'pb-32' : 'pb-24');\n const questionComponents: Record<\n string,\n ComponentType<QuizVariantInterface>\n > = {\n [QUESTION_TYPE.ALTERNATIVA]: QuizAlternative,\n [QUESTION_TYPE.MULTIPLA_ESCOLHA]: QuizMultipleChoice,\n [QUESTION_TYPE.DISSERTATIVA]: QuizDissertative,\n [QUESTION_TYPE.VERDADEIRO_FALSO]: QuizTrueOrFalse,\n [QUESTION_TYPE.RELACIONAR]: QuizConnectDots,\n [QUESTION_TYPE.PREENCHER_LACUNAS]: QuizFill,\n [QUESTION_TYPE.IMAGEM]: QuizImageQuestion,\n };\n\n const QuestionComponent = currentQuestion\n ? questionComponents[currentQuestion.questionType]\n : null;\n\n if (!QuestionComponent) {\n return (\n <Text size=\"md\" weight=\"medium\" className=\"text-text-950 text-md\">\n Tipo de questão não suportado\n </Text>\n );\n }\n\n // The teacher's comment is no longer echoed here: in the result variant it\n // lives behind the \"Ver comentário\" button in the footer, so it is not shown\n // twice on the same screen.\n return <QuestionComponent paddingBottom={contentPaddingBottom} />;\n};\n\ninterface QuizVariantInterface {\n paddingBottom?: string;\n}\n\nconst QuizQuestionList = ({\n filterType = 'all',\n onQuestionClick,\n}: {\n filterType?: string;\n onQuestionClick?: () => void;\n} = {}) => {\n const {\n getQuestionsGroupedBySubject,\n goToQuestion,\n getQuestionStatusFromUserAnswers,\n getQuestionIndex,\n quiz,\n } = useQuizStore();\n\n const showExamInfo = shouldShowExamInfo(quiz);\n\n const groupedQuestions = getQuestionsGroupedBySubject();\n const getQuestionStatus = (questionId: string) => {\n return getQuestionStatusFromUserAnswers(questionId);\n };\n const filteredGroupedQuestions = Object.entries(groupedQuestions).reduce(\n (acc, [subjectId, questions]) => {\n const filteredQuestions = questions.filter((question) => {\n const status = getQuestionStatus(question.id);\n switch (filterType) {\n case 'answered':\n return status === 'answered';\n case 'unanswered':\n return status === 'unanswered' || status === 'skipped';\n default:\n return true;\n }\n });\n\n if (filteredQuestions.length > 0) {\n acc[subjectId] = filteredQuestions;\n }\n\n return acc;\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n {} as { [key: string]: any[] }\n );\n\n const getStatusLabel = (status: string) => {\n switch (status) {\n case 'answered':\n return 'Respondida';\n case 'skipped':\n return 'Em branco';\n default:\n return 'Em branco';\n }\n };\n return (\n <div className=\"space-y-6 px-4 h-full\">\n {Object.entries(filteredGroupedQuestions).length == 0 && (\n <div className=\"flex items-center justify-center text-gray-500 py-8 h-full\">\n <p className=\"text-lg\">Nenhum resultado</p>\n </div>\n )}\n {Object.entries(filteredGroupedQuestions).map(\n ([subjectId, questions]) => (\n <section key={subjectId} className=\"flex flex-col gap-2\">\n <span className=\"pt-6 pb-4 flex flex-row gap-2\">\n <div\n className=\"bg-primary-500 p-1 rounded-sm flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <BookOpenIcon size={17} className=\"text-white\" />\n </div>\n <h3 className=\"text-text-800 font-bold text-lg\">\n {questions?.[0]?.knowledgeMatrix?.[0]?.subject?.name ??\n 'Sem componente curricular'}\n </h3>\n </span>\n\n <ul className=\"flex flex-col gap-2\">\n {questions.map((question) => {\n const status = getQuestionStatus(question.id);\n const questionNumber = getQuestionIndex(question.id);\n const examInfo = showExamInfo\n ? formatExamInfo(question.examBoard, question.examYear)\n : '';\n const questionTitle = `Questão ${questionNumber.toString().padStart(2, '0')}`;\n const header = examInfo\n ? `${questionTitle} ${examInfo}`\n : questionTitle;\n return (\n <li key={question.id}>\n <CardStatus\n header={header}\n label={getStatusLabel(status)}\n onClick={() => {\n goToQuestion(questionNumber - 1);\n onQuestionClick?.();\n }}\n />\n </li>\n );\n })}\n </ul>\n </section>\n )\n )}\n </div>\n );\n};\n\n/**\n * Shared layout for the quiz result modals (generic result, all-correct and\n * all-incorrect questionnaire variants): a centered image, a title and a\n * footer with action buttons.\n */\nconst QuizResultModal = ({\n isOpen,\n onClose,\n image,\n showImagePlaceholder = true,\n title,\n description,\n footer,\n}: {\n isOpen: boolean;\n onClose: () => void;\n image?: ReactNode;\n showImagePlaceholder?: boolean;\n title: ReactNode;\n description: ReactNode;\n footer: ReactNode;\n}) => {\n const titleId = useId();\n const descriptionId = useId();\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title=\"\"\n labelledBy={titleId}\n describedBy={descriptionId}\n closeOnEscape={false}\n hideCloseButton\n size={'md'}\n >\n <div className=\"flex flex-col w-full h-full items-center justify-center gap-4\">\n {image ? (\n <div className=\"w-[282px] h-auto\">{image}</div>\n ) : (\n showImagePlaceholder && (\n // Placeholder puramente visual (sem imagem real): fora da leitura.\n <div\n className=\"w-[282px] h-[200px] bg-gray-100 rounded-md flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <Text as=\"span\" size=\"sm\" color=\"text-gray-500\">\n Imagem de resultado\n </Text>\n </div>\n )\n )}\n <div className=\"flex flex-col gap-2 text-center\">\n <Text as=\"h2\" id={titleId} size=\"lg\" weight=\"bold\">\n {title}\n </Text>\n <div id={descriptionId} className=\"flex flex-col gap-2\">\n {description}\n </div>\n </div>\n {footer}\n </div>\n </Modal>\n );\n};\n\n/**\n * Correction of the question currently on screen, resolved once.\n *\n * A dissertativa may have been graded by the AI. The teacher's text wins when it\n * exists, the AI's stands otherwise; the two are never merged — the backend\n * keeps them in separate columns precisely so a review does not destroy the\n * original verdict — and `correctionSource` says which one is on screen.\n *\n * It lives here, and not inline in `QuizFooter`, because both the footer (for\n * the modal body and title) and `QuizReviewActions` (for the buttons) need the\n * same four values, and deriving them twice would be two chances to disagree.\n *\n * @returns The effective comment plus the fields the tag and the title read\n */\nconst useCurrentCorrection = () => {\n const { getCurrentQuestion, getQuestionResultByQuestionId } = useQuizStore();\n\n const currentQuestion = getCurrentQuestion();\n const result = currentQuestion\n ? getQuestionResultByQuestionId(currentQuestion.id)\n : null;\n\n return {\n comment: resolveCorrectionText({ ...result }),\n correctionSource: result?.correctionSource,\n aiCorrectionStatus: result?.aiCorrectionStatus,\n };\n};\n\n/**\n * Title for the per-question feedback modal, phrased for whoever wrote it.\n *\n * Calling an AI correction \"Comentário do professor\" would be a lie the tag\n * inside the modal immediately contradicts, so both are derived from the same\n * `correctionSource`.\n *\n * @param correctionSource - Who produced the correction on display\n * @returns The modal title\n */\nconst getCorrectionModalTitle = (\n correctionSource?: CORRECTION_SOURCE | null\n): string => {\n if (correctionSource === CORRECTION_SOURCE.IA) {\n return 'Correção por IA';\n }\n\n if (correctionSource === CORRECTION_SOURCE.IA_PROFESSOR) {\n return 'Correção revisada pelo professor';\n }\n\n return 'Comentário do professor';\n};\n\n/**\n * The review bar's question-scoped actions: see the resolution, see the correction.\n *\n * Split out of `QuizFooter` because the two bars do different jobs — the\n * `default` one navigates between questions, this one reads a question already\n * graded — and because the four conditions the correction needs pushed the\n * footer past the cognitive-complexity limit while sitting in the middle of\n * unrelated navigation markup.\n *\n * @param props - Callbacks that open the footer's modals\n * @returns JSX element\n */\nconst QuizReviewActions = ({\n onOpenResolution,\n onOpenComment,\n className,\n}: {\n onOpenResolution: () => void;\n onOpenComment: () => void;\n readonly className?: string;\n}) => {\n const { getCurrentQuestion } = useQuizStore();\n const { comment, correctionSource, aiCorrectionStatus } =\n useCurrentCorrection();\n\n const currentQuestion = getCurrentQuestion();\n const hasResolution = Boolean(currentQuestion?.solutionExplanation);\n const isAiCorrecting = aiCorrectionStatus === AI_CORRECTION_STATUS.PENDING;\n const commentLabel =\n correctionSource === CORRECTION_SOURCE.IA\n ? 'Ver correção da IA'\n : 'Ver comentário';\n\n return (\n <div className={className}>\n {hasResolution && (\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"large\"\n onClick={onOpenResolution}\n >\n Ver resolução\n </Button>\n )}\n {comment && (\n <Button\n variant=\"outline\"\n action=\"primary\"\n size=\"large\"\n onClick={onOpenComment}\n >\n {commentLabel}\n </Button>\n )}\n {/* Sem comentário ainda, mas a IA está corrigindo: o aluno acaba de\n entregar e chegou aqui antes do feedback existir. Dizer que está a\n caminho é melhor do que não mostrar nada. */}\n {!comment && isAiCorrecting && (\n <CorrectionSourceTag\n aiCorrectionStatus={aiCorrectionStatus}\n className=\"self-center\"\n />\n )}\n </div>\n );\n};\n\n/**\n * What the completion modal shows instead of the score.\n *\n * Some exams are not corrected on the spot — the in-classroom ENEM simulation\n * is graded later — so telling the student how many they got right would be\n * wrong. With this set, finishing opens a modal with only this content and\n * one button.\n */\nexport interface QuizCompletionOverride {\n title: ReactNode;\n description: ReactNode;\n buttonLabel: string;\n onConfirm: () => void;\n}\n\nconst QuizFooter = forwardRef<\n HTMLDivElement,\n {\n className?: string;\n onGoToSimulated?: () => void;\n onDetailResult?: () => void;\n handleFinishSimulated?: () => void;\n onGoToNextModule?: () => void;\n onRepeat?: () => void;\n onTryLater?: () => void;\n resultImageComponent?: ReactNode;\n resultIncorrectImageComponent?: ReactNode;\n /** Replaces the score modal; see `QuizCompletionOverride`. */\n completionOverride?: QuizCompletionOverride;\n }\n>(\n (\n {\n className,\n onGoToSimulated,\n onDetailResult,\n handleFinishSimulated,\n onGoToNextModule,\n onRepeat,\n onTryLater,\n resultImageComponent,\n resultIncorrectImageComponent,\n completionOverride,\n ...props\n },\n ref\n ) => {\n const {\n quiz,\n currentQuestionIndex,\n getTotalQuestions,\n goToNextQuestion,\n goToPreviousQuestion,\n getUnansweredQuestionsFromUserAnswers,\n getCurrentAnswer,\n skipQuestion,\n skipCurrentQuestionIfUnanswered,\n getCurrentQuestion,\n getQuestionStatusFromUserAnswers,\n variant,\n getQuestionResultStatistics,\n } = useQuizStore();\n\n // The review bar carries four controls. Below ~500px they no longer fit on\n // one line, so the actions and the pagination stack into two centred rows.\n const { isMobile } = useMobile();\n\n const totalQuestions = getTotalQuestions();\n const isFirstQuestion = currentQuestionIndex === 0;\n const isLastQuestion = currentQuestionIndex === totalQuestions - 1;\n const currentAnswer = getCurrentAnswer();\n const currentQuestion = getCurrentQuestion();\n const {\n comment: teacherComment,\n correctionSource,\n aiCorrectionStatus,\n } = useCurrentCorrection();\n const isCurrentQuestionSkipped = currentQuestion\n ? getQuestionStatusFromUserAnswers(currentQuestion.id) === 'skipped'\n : false;\n // Sistema unificado de controle de modais\n const [activeModal, setActiveModal] = useState<string | null>(null);\n const [filterType, setFilterType] = useState<string>('all');\n const filterLabelId = useId();\n\n // Funções para controlar modais\n const openModal = (modalName: string) => setActiveModal(modalName);\n const closeModal = () => setActiveModal(null);\n const isModalOpen = (modalName: string) => activeModal === modalName;\n const unansweredQuestions = getUnansweredQuestionsFromUserAnswers();\n const allQuestions = getTotalQuestions();\n const stats = getQuestionResultStatistics();\n const correctAnswers = stats?.correctAnswers;\n const quizType = quiz?.type || QUIZ_TYPE.SIMULADO;\n const quizTypeLabel = getTypeLabel(quizType);\n // Real subtopic name, used to label the questionnaire completion modals.\n // The backend always populates the question knowledge matrix, so this is\n // available as soon as the quiz is loaded.\n const moduleName =\n quiz?.questions?.[0]?.knowledgeMatrix?.[0]?.subtopic?.name;\n\n // Submits the answers and opens the correct result modal. Statistics must\n // be read AFTER handleFinishSimulated, which is what populates\n // questionsResult in the store (the render-time values are still empty).\n const submitAndOpenResultModal = async () => {\n if (handleFinishSimulated) {\n await Promise.resolve(handleFinishSimulated());\n }\n\n if (completionOverride) {\n openModal('modalCompletionOverride');\n return;\n }\n\n const latestStats = getQuestionResultStatistics();\n const latestCorrect = latestStats?.correctAnswers;\n const latestTotal = latestStats?.totalAnswered;\n\n if (\n quizType === QUIZ_TYPE.QUESTIONARIO &&\n typeof latestCorrect === 'number' &&\n typeof latestTotal === 'number' &&\n latestCorrect === latestTotal\n ) {\n openModal('modalQuestionnaireAllCorrect');\n return;\n }\n\n if (\n quizType === QUIZ_TYPE.QUESTIONARIO &&\n typeof latestCorrect === 'number' &&\n latestCorrect === 0\n ) {\n openModal('modalQuestionnaireAllIncorrect');\n return;\n }\n\n openModal('modalResult');\n };\n\n const handleFinishQuiz = async () => {\n // Marca a questão atual como pulada se não foi respondida\n skipCurrentQuestionIfUnanswered();\n\n if (unansweredQuestions.length > 0) {\n openModal('alertDialog');\n return;\n }\n\n try {\n await submitAndOpenResultModal();\n } catch (err) {\n console.error('handleFinishSimulated failed:', err);\n }\n };\n\n const handleAlertSubmit = async () => {\n try {\n await submitAndOpenResultModal();\n } catch (err) {\n console.error('handleFinishSimulated failed:', err);\n closeModal();\n }\n };\n\n return (\n <>\n <footer\n ref={ref}\n className={cn(\n 'w-full px-2 bg-background lg:max-w-[1000px] not-lg:max-w-[calc(100vw-32px)] border-t border-border-50 fixed bottom-0 min-h-[80px] flex flex-row justify-between items-center',\n className\n )}\n // No modo resultado o rodapé é a navegação entre questões; o nome\n // distingue esta região das demais para quem navega por marcos.\n aria-label={\n variant === 'default' ? undefined : 'Navegação entre questões'\n }\n {...props}\n >\n {variant === 'default' ? (\n <>\n <div className=\"flex flex-row items-center gap-1\">\n <IconButton\n icon={<SquaresFourIcon size={24} className=\"text-text-950\" />}\n size=\"md\"\n aria-label=\"Lista de todas as questões\"\n aria-haspopup=\"dialog\"\n onClick={() => openModal('modalNavigate')}\n />\n\n {isFirstQuestion ? (\n <Button\n variant=\"outline\"\n size=\"small\"\n aria-label=\"Pular questão\"\n onClick={() => {\n skipQuestion();\n goToNextQuestion();\n }}\n >\n Pular\n </Button>\n ) : (\n <Button\n size=\"medium\"\n variant=\"link\"\n action=\"primary\"\n iconLeft={<CaretLeftIcon size={18} aria-hidden=\"true\" />}\n aria-label=\"Voltar à questão anterior\"\n onClick={() => {\n goToPreviousQuestion();\n }}\n >\n Voltar\n </Button>\n )}\n </div>\n\n {!isFirstQuestion && !isLastQuestion && (\n <Button\n size=\"small\"\n variant=\"outline\"\n action=\"primary\"\n aria-label=\"Pular questão\"\n onClick={() => {\n skipQuestion();\n goToNextQuestion();\n }}\n >\n Pular\n </Button>\n )}\n\n {isLastQuestion ? (\n <Button\n size=\"medium\"\n variant=\"solid\"\n action=\"primary\"\n aria-label={`Finalizar ${quizTypeLabel.toLowerCase()}`}\n onClick={handleFinishQuiz}\n >\n Finalizar\n </Button>\n ) : (\n <Button\n size=\"medium\"\n variant=\"link\"\n action=\"primary\"\n iconRight={<CaretRightIcon size={18} aria-hidden=\"true\" />}\n aria-label=\"Avançar para a próxima questão\"\n disabled={!currentAnswer && !isCurrentQuestionSkipped}\n onClick={() => {\n goToNextQuestion();\n }}\n >\n Avançar\n </Button>\n )}\n </>\n ) : (\n <div\n className={cn(\n 'flex w-full items-center gap-2',\n isMobile ? 'flex-col py-2' : 'flex-row'\n )}\n >\n <QuizReviewActions\n className={cn(\n 'flex flex-row items-center gap-2',\n isMobile && 'justify-center'\n )}\n onOpenResolution={() => openModal('modalResolution')}\n onOpenComment={() => openModal('modalTeacherComment')}\n />\n {/* On a wide bar the pagination sits at the far end, away from the\n actions that act on the question being read; stacked, it is\n centred under them. */}\n <div\n className={cn(\n 'flex flex-row items-center gap-2',\n isMobile ? 'justify-center' : 'flex-1 justify-end'\n )}\n >\n {/* Posição atual anunciada em texto: os botões só têm setas. */}\n <Text as=\"span\" className=\"sr-only\">\n {`Questão ${currentQuestionIndex + 1} de ${totalQuestions}`}\n </Text>\n <Button\n variant=\"outline\"\n action=\"primary\"\n size=\"medium\"\n aria-label=\"Questão anterior\"\n disabled={isFirstQuestion}\n onClick={goToPreviousQuestion}\n >\n <CaretLeftIcon size={18} aria-hidden=\"true\" />\n </Button>\n <Button\n variant=\"outline\"\n action=\"primary\"\n size=\"medium\"\n aria-label=\"Próxima questão\"\n disabled={isLastQuestion}\n onClick={goToNextQuestion}\n >\n <CaretRightIcon size={18} aria-hidden=\"true\" />\n </Button>\n </div>\n </div>\n )}\n </footer>\n\n <AlertDialog\n isOpen={isModalOpen('alertDialog')}\n onChangeOpen={(open) =>\n open ? openModal('alertDialog') : closeModal()\n }\n title={`Finalizar ${quizTypeLabel.toLowerCase()}?`}\n description={\n unansweredQuestions.length > 0\n ? `Você deixou as questões ${unansweredQuestions.join(', ')} sem resposta. Finalizar agora pode impactar seu desempenho.`\n : getFinishConfirmationText(quizType)\n }\n cancelButtonLabel=\"Voltar e revisar\"\n submitButtonLabel=\"Finalizar Mesmo Assim\"\n onSubmit={handleAlertSubmit}\n />\n\n <QuizResultModal\n isOpen={isModalOpen('modalResult')}\n onClose={closeModal}\n image={resultImageComponent}\n title={getCompletionTitle(quizType)}\n description={\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Você acertou {correctAnswers ?? '--'} de {allQuestions} questões.\n </Text>\n }\n footer={\n <div className=\"px-6 flex flex-row items-center gap-2 w-full\">\n <Button\n variant=\"outline\"\n className=\"w-full\"\n size=\"small\"\n onClick={onGoToSimulated}\n >\n {getGoBackButtonLabel(quizType)}\n </Button>\n\n <Button className=\"w-full\" onClick={onDetailResult}>\n Detalhar resultado\n </Button>\n </div>\n }\n />\n\n {completionOverride && (\n <QuizResultModal\n isOpen={isModalOpen('modalCompletionOverride')}\n onClose={closeModal}\n image={resultImageComponent}\n title={completionOverride.title}\n description={\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n {completionOverride.description}\n </Text>\n }\n footer={\n <div className=\"px-6 flex flex-row items-center w-full\">\n <Button\n className=\"w-full\"\n onClick={completionOverride.onConfirm}\n data-testid=\"quiz-completion-override-confirm\"\n >\n {completionOverride.buttonLabel}\n </Button>\n </div>\n }\n />\n )}\n\n <Modal\n isOpen={isModalOpen('modalNavigate')}\n onClose={closeModal}\n title=\"Questões\"\n size={'lg'}\n >\n <div className=\"flex flex-col w-full not-lg:h-[calc(100vh-200px)] lg:max-h-[687px] lg:h-[687px]\">\n <div className=\"flex flex-row justify-between items-center py-6 pt-6 pb-4 border-b border-border-200 flex-shrink-0\">\n <p id={filterLabelId} className=\"text-text-950 font-bold text-lg\">\n Filtrar por\n </p>\n <span className=\"max-w-[266px]\">\n <Select value={filterType} onValueChange={setFilterType}>\n <SelectTrigger\n aria-labelledby={filterLabelId}\n variant=\"rounded\"\n className=\"max-w-[266px] min-w-[160px]\"\n >\n <SelectValue placeholder=\"Selecione uma opção\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">Todas</SelectItem>\n <SelectItem value=\"unanswered\">Em branco</SelectItem>\n <SelectItem value=\"answered\">Respondidas</SelectItem>\n </SelectContent>\n </Select>\n </span>\n </div>\n\n <div className=\"flex flex-col gap-2 flex-1 min-h-0 overflow-y-auto\">\n <QuizQuestionList\n filterType={filterType}\n onQuestionClick={closeModal}\n />\n </div>\n </div>\n </Modal>\n\n <Modal\n isOpen={isModalOpen('modalResolution')}\n onClose={closeModal}\n title=\"Resolução\"\n size={'lg'}\n >\n <HtmlMathRenderer\n content={currentQuestion?.solutionExplanation || ''}\n className=\"text-text-950 text-base\"\n />\n </Modal>\n\n <Modal\n isOpen={isModalOpen('modalTeacherComment')}\n onClose={closeModal}\n title={getCorrectionModalTitle(correctionSource)}\n size={'lg'}\n >\n {/* A tag fica dentro do modal, junto do texto: é ela que diz se o que\n está sendo lido saiu da IA, do professor, ou da IA revisada por\n ele. Sem isso o título sozinho teria que carregar essa informação\n em toda variação. */}\n <CorrectionSourceTag\n correctionSource={correctionSource}\n aiCorrectionStatus={aiCorrectionStatus}\n className=\"mb-3\"\n />\n {/* Plain text on purpose: the teacher writes this in a bare textarea,\n so running it through the HTML/LaTeX renderer would change what\n they typed. `whitespace-pre-wrap` keeps their line breaks. The AI\n feedback is plain text for the same reason. */}\n <Text\n size=\"md\"\n className=\"text-text-950 whitespace-pre-wrap break-words\"\n >\n {teacherComment}\n </Text>\n </Modal>\n\n <QuizResultModal\n isOpen={isModalOpen('modalQuestionnaireAllCorrect')}\n onClose={closeModal}\n image={resultImageComponent}\n // Emoji decorativo: o leitor anunciaria o nome dele antes do título.\n title={\n <>\n <Text as=\"span\" size=\"lg\" weight=\"bold\" aria-hidden=\"true\">\n 🎉\n </Text>{' '}\n Parabéns!\n </>\n }\n description={\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n {moduleName\n ? `Você concluiu o módulo ${moduleName}.`\n : 'Você concluiu o questionário!'}\n </Text>\n }\n footer={\n <div className=\"px-6 flex flex-row items-center gap-2 w-full\">\n <Button className=\"w-full\" onClick={onGoToNextModule}>\n {getGoBackButtonLabel(quizType)}\n </Button>\n </div>\n }\n />\n\n <QuizResultModal\n isOpen={isModalOpen('modalQuestionnaireAllIncorrect')}\n onClose={closeModal}\n image={resultIncorrectImageComponent}\n showImagePlaceholder={false}\n title={\n <>\n <Text as=\"span\" size=\"lg\" weight=\"bold\" aria-hidden=\"true\">\n 😕\n </Text>{' '}\n Não foi dessa vez...\n </>\n }\n description={\n <>\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Você tirou 0 no questionário, mas não se preocupe! Isso é apenas\n uma oportunidade de aprendizado.\n </Text>\n\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Que tal tentar novamente para melhorar sua nota? Estamos aqui\n para te ajudar a entender o conteúdo e evoluir.\n </Text>\n\n {quiz?.canRetry && (\n <Text as=\"p\" size=\"sm\" color=\"text-text-500\">\n Clique em Repetir Questionário e mostre do que você é capaz!{' '}\n <Text\n as=\"span\"\n size=\"sm\"\n color=\"text-text-500\"\n aria-hidden=\"true\"\n >\n 💪\n </Text>\n </Text>\n )}\n </>\n }\n footer={\n <div className=\"flex flex-row justify-center items-center gap-2 w-full\">\n {quiz?.canRetry && (\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"small\"\n className=\"w-auto\"\n onClick={() => {\n closeModal();\n openModal('alertDialogTryLater');\n }}\n >\n Tentar depois\n </Button>\n )}\n\n <Button\n variant=\"outline\"\n size=\"small\"\n className=\"w-auto\"\n onClick={onDetailResult}\n >\n Detalhar resultado\n </Button>\n\n {quiz?.canRetry ? (\n <Button className=\"w-auto\" size=\"small\" onClick={onRepeat}>\n Repetir questionário\n </Button>\n ) : (\n <Button\n className=\"w-auto\"\n size=\"small\"\n onClick={onGoToSimulated}\n >\n {getGoBackButtonLabel(quizType)}\n </Button>\n )}\n </div>\n }\n />\n\n <AlertDialog\n isOpen={isModalOpen('alertDialogTryLater')}\n onChangeOpen={(open) =>\n open ? openModal('alertDialogTryLater') : closeModal()\n }\n title=\"Tentar depois?\"\n description={\n 'Você optou por refazer o questionário mais tarde.\\n\\nLembre-se: enquanto não refazer o questionário, sua nota permanecerá 0 no sistema.'\n }\n cancelButtonLabel=\"Repetir questionário\"\n submitButtonLabel=\"Tentar depois\"\n onSubmit={() => {\n onTryLater?.();\n closeModal();\n }}\n onCancel={() => {\n onRepeat?.();\n closeModal();\n }}\n />\n </>\n );\n }\n);\n\nexport {\n QuizTitle,\n Quiz,\n QuizHeader,\n QuizContent,\n QuizFooter,\n QuizQuestionList,\n};\n"]}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "./chunk-N26PFH64.mjs";
|
|
14
14
|
import {
|
|
15
15
|
Modal_default
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-LODDYDTP.mjs";
|
|
17
17
|
import {
|
|
18
18
|
Button_default
|
|
19
19
|
} from "./chunk-ZQZBOTZJ.mjs";
|
|
@@ -850,4 +850,4 @@ export {
|
|
|
850
850
|
ComparatorTabContent,
|
|
851
851
|
ComparatorView
|
|
852
852
|
};
|
|
853
|
-
//# sourceMappingURL=chunk-
|
|
853
|
+
//# sourceMappingURL=chunk-V55DG5B4.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var _chunkWUN5NHZEjs = require('./chunk-WUN5NHZE.js');
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
@@ -110,7 +110,7 @@ var TicketCard = ({
|
|
|
110
110
|
}
|
|
111
111
|
),
|
|
112
112
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJVDEOFXDjs.Badge_default, { variant: "solid", className: "flex items-center gap-1", action: "muted", children: [
|
|
113
|
-
|
|
113
|
+
_chunkWUN5NHZEjs.getCategoryIcon.call(void 0, ticket.category, 18),
|
|
114
114
|
_chunk64WFAQC6js.getCategoryText.call(void 0, ticket.category)
|
|
115
115
|
] }),
|
|
116
116
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _react3.CaretRightIcon, { size: 24, className: "text-text-800" })
|
|
@@ -519,7 +519,7 @@ var Support = ({
|
|
|
519
519
|
] })
|
|
520
520
|
] }) }),
|
|
521
521
|
selectedTicket && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
522
|
-
|
|
522
|
+
_chunkWUN5NHZEjs.TicketModal,
|
|
523
523
|
{
|
|
524
524
|
ticket: selectedTicket,
|
|
525
525
|
isOpen: isModalOpen,
|
|
@@ -1100,4 +1100,4 @@ var TicketList = ({
|
|
|
1100
1100
|
|
|
1101
1101
|
|
|
1102
1102
|
exports.supportSchema = supportSchema; exports.Support_default = Support_default; exports.SidebarMenuItem = SidebarMenuItem; exports.formatTicketTime = formatTicketTime; exports.TicketListItem = TicketListItem; exports.useInfiniteScrollSentinel = useInfiniteScrollSentinel; exports.TicketList = TicketList;
|
|
1103
|
-
//# sourceMappingURL=chunk-
|
|
1103
|
+
//# sourceMappingURL=chunk-VHEDMUAW.js.map
|