analytica-frontend-lib 1.6.21 → 1.6.22
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 +1 -1
- package/dist/AccessReportModal/index.mjs +1 -1
- package/dist/AccessibilityWidget/index.js +1 -1
- package/dist/AccessibilityWidget/index.mjs +1 -1
- package/dist/Accordation/index.js +1 -1
- package/dist/Accordation/index.mjs +1 -1
- package/dist/ActivitiesHistory/index.js +19 -19
- package/dist/ActivitiesHistory/index.mjs +18 -18
- package/dist/ActivityCardQuestionBanks/index.js +19 -19
- package/dist/ActivityCardQuestionBanks/index.mjs +18 -18
- package/dist/ActivityCardQuestionPreview/index.js +19 -19
- package/dist/ActivityCardQuestionPreview/index.mjs +18 -18
- package/dist/ActivityCreate/ActivityCreate.utils/index.js +3 -3
- package/dist/ActivityCreate/ActivityCreate.utils/index.mjs +2 -2
- package/dist/ActivityCreate/ActivityCreateContent/index.js +19 -19
- package/dist/ActivityCreate/ActivityCreateContent/index.mjs +18 -18
- package/dist/ActivityCreate/index.js +19 -19
- package/dist/ActivityCreate/index.mjs +18 -18
- package/dist/ActivityDetails/index.js +19 -19
- package/dist/ActivityDetails/index.mjs +18 -18
- package/dist/ActivityFilters/index.js +19 -19
- package/dist/ActivityFilters/index.mjs +18 -18
- package/dist/ActivityPageLayout/index.js +19 -19
- package/dist/ActivityPageLayout/index.mjs +18 -18
- package/dist/ActivityPreview/index.js +19 -19
- package/dist/ActivityPreview/index.mjs +18 -18
- package/dist/Alert/index.js +1 -1
- package/dist/Alert/index.mjs +1 -1
- package/dist/AlertDialog/index.js +1 -1
- package/dist/AlertDialog/index.mjs +1 -1
- package/dist/AlertManager/index.js +19 -19
- package/dist/AlertManager/index.mjs +18 -18
- package/dist/AlertManagerView/index.js +1 -1
- package/dist/AlertManagerView/index.mjs +1 -1
- package/dist/Alternative/index.js +1 -1
- package/dist/Alternative/index.mjs +1 -1
- package/dist/AnnouncementModal/index.js +1 -1
- package/dist/AnnouncementModal/index.mjs +1 -1
- package/dist/AnnouncementsGate/index.js +1 -1
- package/dist/AnnouncementsGate/index.mjs +1 -1
- package/dist/AnswerKeyModal/index.js +1 -1
- package/dist/AnswerKeyModal/index.mjs +1 -1
- package/dist/AppHeader/index.js +1 -1
- package/dist/AppHeader/index.mjs +1 -1
- package/dist/AppLayout/index.js +1 -1
- package/dist/AppLayout/index.mjs +1 -1
- package/dist/Avatar/index.js +1 -1
- package/dist/Avatar/index.mjs +1 -1
- package/dist/Badge/index.js +1 -1
- package/dist/Badge/index.mjs +1 -1
- package/dist/BreadcrumbMenu/index.js +1 -1
- package/dist/BreadcrumbMenu/index.mjs +1 -1
- package/dist/Button/index.js +1 -1
- package/dist/Button/index.mjs +1 -1
- package/dist/Calendar/index.js +1 -1
- package/dist/Calendar/index.mjs +1 -1
- package/dist/CalendarCard/index.js +1 -1
- package/dist/CalendarCard/index.mjs +1 -1
- package/dist/Card/index.js +1 -1
- package/dist/Card/index.mjs +1 -1
- package/dist/ChartComponents/index.js +1 -1
- package/dist/ChartComponents/index.mjs +1 -1
- package/dist/Chat/index.js +1 -1
- package/dist/Chat/index.mjs +1 -1
- package/dist/Chatbot/index.js +1 -1
- package/dist/Chatbot/index.mjs +1 -1
- package/dist/CheckBox/index.js +1 -1
- package/dist/CheckBox/index.mjs +1 -1
- package/dist/CheckBoxGroup/index.js +19 -19
- package/dist/CheckBoxGroup/index.mjs +18 -18
- package/dist/Chips/index.js +1 -1
- package/dist/Chips/index.mjs +1 -1
- package/dist/ChoroplethMap/index.js +1 -1
- package/dist/ChoroplethMap/index.mjs +1 -1
- package/dist/ColorPicker/index.js +1 -1
- package/dist/ColorPicker/index.mjs +1 -1
- package/dist/ComparatorChart/ComparatorView/index.js +1 -1
- package/dist/ComparatorChart/ComparatorView/index.mjs +1 -1
- package/dist/CorrectActivityModal/index.js +6 -6
- package/dist/CorrectActivityModal/index.mjs +5 -5
- package/dist/Divider/index.js +1 -1
- package/dist/Divider/index.mjs +1 -1
- package/dist/DownloadButton/index.js +1 -1
- package/dist/DownloadButton/index.mjs +1 -1
- package/dist/DownloadModal/index.js +1 -1
- package/dist/DownloadModal/index.mjs +1 -1
- package/dist/DragHandleButton/index.js +1 -1
- package/dist/DragHandleButton/index.mjs +1 -1
- package/dist/DropdownMenu/index.js +1 -1
- package/dist/DropdownMenu/index.mjs +1 -1
- package/dist/EmptyState/index.js +1 -1
- package/dist/EmptyState/index.mjs +1 -1
- package/dist/EnemClassroomStartModal/index.d.ts +0 -2
- package/dist/EnemClassroomStartModal/index.d.ts.map +1 -1
- package/dist/EnemClassroomStartModal/index.js +4 -6
- package/dist/EnemClassroomStartModal/index.js.map +1 -1
- package/dist/EnemClassroomStartModal/index.mjs +3 -5
- package/dist/EssayThemePicker/index.js +1 -1
- package/dist/EssayThemePicker/index.mjs +1 -1
- package/dist/ExamDetailsLayout/ExamDetailsPage/index.js +19 -19
- package/dist/ExamDetailsLayout/ExamDetailsPage/index.mjs +18 -18
- package/dist/ExamPageLayout/examsTableConfig/index.js +1 -1
- package/dist/ExamPageLayout/examsTableConfig/index.mjs +1 -1
- package/dist/ExamPageLayout/index.js +19 -19
- package/dist/ExamPageLayout/index.mjs +18 -18
- package/dist/FileAttachment/index.js +1 -1
- package/dist/FileAttachment/index.mjs +1 -1
- package/dist/FileDropzone/index.js +1 -1
- package/dist/FileDropzone/index.mjs +1 -1
- package/dist/Forum/index.js +4 -4
- package/dist/Forum/index.mjs +3 -3
- package/dist/HtmlMathRenderer/index.js +1 -1
- package/dist/HtmlMathRenderer/index.mjs +1 -1
- package/dist/IconButton/index.js +1 -1
- package/dist/IconButton/index.mjs +1 -1
- package/dist/IconRoundedButton/index.js +1 -1
- package/dist/IconRoundedButton/index.mjs +1 -1
- package/dist/ImagePreviewCard/index.js +1 -1
- package/dist/ImagePreviewCard/index.mjs +1 -1
- package/dist/ImageUpload/index.js +1 -1
- package/dist/ImageUpload/index.mjs +1 -1
- package/dist/LatexRenderer/index.js +1 -1
- package/dist/LatexRenderer/index.mjs +1 -1
- package/dist/LevelBar/index.js +1 -1
- package/dist/LevelBar/index.mjs +1 -1
- package/dist/Menu/index.js +1 -1
- package/dist/Menu/index.mjs +1 -1
- package/dist/MetricBox/index.js +1 -1
- package/dist/MetricBox/index.mjs +1 -1
- package/dist/Modal/index.js +1 -1
- package/dist/Modal/index.mjs +1 -1
- package/dist/ModalComponents/index.js +1 -1
- package/dist/ModalComponents/index.mjs +1 -1
- package/dist/MultiSearchSelect/index.js +1 -1
- package/dist/MultiSearchSelect/index.mjs +1 -1
- package/dist/MultipleChoice/index.js +1 -1
- package/dist/MultipleChoice/index.mjs +1 -1
- package/dist/NavButton/index.js +1 -1
- package/dist/NavButton/index.mjs +1 -1
- package/dist/NoSearchResult/index.js +1 -1
- package/dist/NoSearchResult/index.mjs +1 -1
- package/dist/NotFound/index.js +1 -1
- package/dist/NotFound/index.mjs +1 -1
- package/dist/NotificationCard/index.js +1 -1
- package/dist/NotificationCard/index.mjs +1 -1
- package/dist/PerformanceDistributionChart/index.js +1 -1
- package/dist/PerformanceDistributionChart/index.mjs +1 -1
- package/dist/PerformanceQuestionsData/index.js +1 -1
- package/dist/PerformanceQuestionsData/index.mjs +1 -1
- package/dist/PerformanceRanking/index.js +1 -1
- package/dist/PerformanceRanking/index.mjs +1 -1
- package/dist/PerformanceReport/index.js +1 -1
- package/dist/PerformanceReport/index.mjs +1 -1
- package/dist/PerformanceReportModal/index.js +1 -1
- package/dist/PerformanceReportModal/index.mjs +1 -1
- package/dist/PeriodSelector/index.js +1 -1
- package/dist/PeriodSelector/index.mjs +1 -1
- package/dist/PrintableUsersTable/index.js +19 -19
- package/dist/PrintableUsersTable/index.mjs +18 -18
- package/dist/ProficiencyChart/index.js +1 -1
- package/dist/ProficiencyChart/index.mjs +1 -1
- package/dist/ProgressBar/index.js +1 -1
- package/dist/ProgressBar/index.mjs +1 -1
- package/dist/ProgressCircle/index.js +1 -1
- package/dist/ProgressCircle/index.mjs +1 -1
- package/dist/ProgressModal/index.js +1 -1
- package/dist/ProgressModal/index.mjs +1 -1
- package/dist/QuestionsData/index.js +1 -1
- package/dist/QuestionsData/index.mjs +1 -1
- package/dist/QuestionsPerformanceCard/index.js +19 -19
- package/dist/QuestionsPerformanceCard/index.mjs +18 -18
- package/dist/Quiz/QuizResult/index.d.ts.map +1 -1
- package/dist/Quiz/QuizResult/index.js +4 -4
- package/dist/Quiz/QuizResult/index.mjs +3 -3
- package/dist/Quiz/TeacherFeedbackSection/index.js +3 -3
- package/dist/Quiz/TeacherFeedbackSection/index.mjs +2 -2
- package/dist/Quiz/TeacherQuestionComment/index.js +3 -3
- package/dist/Quiz/TeacherQuestionComment/index.mjs +2 -2
- package/dist/Quiz/index.d.ts.map +1 -1
- package/dist/Quiz/index.js +6 -6
- package/dist/Quiz/index.mjs +5 -5
- package/dist/Quiz/useQuizStore/index.d.ts +6 -0
- package/dist/Quiz/useQuizStore/index.d.ts.map +1 -1
- package/dist/Quiz/useQuizStore/index.js +2 -2
- package/dist/Quiz/useQuizStore/index.mjs +1 -1
- package/dist/QuizTimer/index.js +3 -3
- package/dist/QuizTimer/index.mjs +2 -2
- package/dist/Radio/index.js +1 -1
- package/dist/Radio/index.mjs +1 -1
- package/dist/RangeGauge/index.js +1 -1
- package/dist/RangeGauge/index.mjs +1 -1
- package/dist/RecommendedLessonCreate/index.js +19 -19
- package/dist/RecommendedLessonCreate/index.mjs +18 -18
- package/dist/RecommendedLessonDetails/index.js +1 -1
- package/dist/RecommendedLessonDetails/index.mjs +1 -1
- package/dist/RecommendedLessonsHistory/index.js +19 -19
- package/dist/RecommendedLessonsHistory/index.mjs +18 -18
- package/dist/ReportDetailModal/index.js +1 -1
- package/dist/ReportDetailModal/index.mjs +1 -1
- package/dist/RestrictedAccess/index.js +1 -1
- package/dist/RestrictedAccess/index.mjs +1 -1
- package/dist/RichEditor/index.js +3 -3
- package/dist/RichEditor/index.mjs +2 -2
- package/dist/{RichEditorCore-F5QPQLEK.js → RichEditorCore-NEIZKFKE.js} +2 -2
- package/dist/{RichEditorCore-F5QPQLEK.js.map → RichEditorCore-NEIZKFKE.js.map} +1 -1
- package/dist/{RichEditorCore-QZYPHNRY.mjs → RichEditorCore-TLAFZ5XG.mjs} +2 -2
- package/dist/ScoreCircle/index.js +1 -1
- package/dist/ScoreCircle/index.mjs +1 -1
- package/dist/Search/index.js +1 -1
- package/dist/Search/index.mjs +1 -1
- package/dist/SearchSelect/index.js +1 -1
- package/dist/SearchSelect/index.mjs +1 -1
- package/dist/Select/index.js +1 -1
- package/dist/Select/index.mjs +1 -1
- package/dist/SelectionButton/index.js +1 -1
- package/dist/SelectionButton/index.mjs +1 -1
- package/dist/SendActivityModal/SendActivityModal.js +19 -19
- package/dist/SendActivityModal/SendActivityModal.mjs +18 -18
- package/dist/SendActivityModal/index.js +19 -19
- package/dist/SendActivityModal/index.mjs +18 -18
- package/dist/SendLessonModal/index.js +19 -19
- package/dist/SendLessonModal/index.mjs +18 -18
- package/dist/SimpleBarChart/index.js +1 -1
- package/dist/SimpleBarChart/index.mjs +1 -1
- package/dist/SimulatedPerformance/SimulatedPerformanceView/index.js +19 -19
- package/dist/SimulatedPerformance/SimulatedPerformanceView/index.mjs +18 -18
- package/dist/SimulatedPerformance/useSimulatedPerformance/index.js +1 -1
- package/dist/SimulatedPerformance/useSimulatedPerformance/index.mjs +1 -1
- package/dist/SimulatedStudentSimulationsModal/index.js +19 -19
- package/dist/SimulatedStudentSimulationsModal/index.mjs +5 -5
- package/dist/SimulationsPage/index.js +19 -19
- package/dist/SimulationsPage/index.mjs +18 -18
- package/dist/Skeleton/index.js +1 -1
- package/dist/Skeleton/index.mjs +1 -1
- package/dist/StatisticsCard/index.js +1 -1
- package/dist/StatisticsCard/index.mjs +1 -1
- package/dist/Stepper/index.js +1 -1
- package/dist/Stepper/index.mjs +1 -1
- package/dist/StudentLessonProgressModal/index.js +1 -1
- package/dist/StudentLessonProgressModal/index.mjs +1 -1
- package/dist/StudentPerformanceDetailsModal/index.js +1 -1
- package/dist/StudentPerformanceDetailsModal/index.mjs +1 -1
- package/dist/StudentRanking/index.js +1 -1
- package/dist/StudentRanking/index.mjs +1 -1
- package/dist/SubjectIcons/index.js +1 -1
- package/dist/SubjectIcons/index.mjs +1 -1
- package/dist/SubjectMenuOverflow/index.js +1 -1
- package/dist/SubjectMenuOverflow/index.mjs +1 -1
- package/dist/Support/TicketModal/index.js +1 -1
- package/dist/Support/TicketModal/index.mjs +1 -1
- package/dist/Support/index.js +1 -1
- package/dist/Support/index.mjs +1 -1
- package/dist/Table/TablePagination/index.js +1 -1
- package/dist/Table/TablePagination/index.mjs +1 -1
- package/dist/Table/index.js +1 -1
- package/dist/Table/index.mjs +1 -1
- package/dist/TableProvider/index.js +19 -19
- package/dist/TableProvider/index.mjs +18 -18
- package/dist/Text/index.js +1 -1
- package/dist/Text/index.mjs +1 -1
- package/dist/TextArea/index.js +1 -1
- package/dist/TextArea/index.mjs +1 -1
- package/dist/ThemeToggle/index.js +1 -1
- package/dist/ThemeToggle/index.mjs +1 -1
- package/dist/TimeChart/index.js +1 -1
- package/dist/TimeChart/index.mjs +1 -1
- package/dist/TimeReport/index.js +1 -1
- package/dist/TimeReport/index.mjs +1 -1
- package/dist/Toast/Toaster/index.js +1 -1
- package/dist/Toast/Toaster/index.mjs +1 -1
- package/dist/Toast/index.js +1 -1
- package/dist/Toast/index.mjs +1 -1
- package/dist/ToggleSwitch/index.js +1 -1
- package/dist/ToggleSwitch/index.mjs +1 -1
- package/dist/TokenValidation/index.js +1 -1
- package/dist/TokenValidation/index.mjs +1 -1
- package/dist/Tooltip/index.js +1 -1
- package/dist/Tooltip/index.mjs +1 -1
- package/dist/TruncatedText/index.js +1 -1
- package/dist/TruncatedText/index.mjs +1 -1
- package/dist/TypeSelector/index.js +1 -1
- package/dist/TypeSelector/index.mjs +1 -1
- package/dist/UnifiedDraftModelPage/index.js +19 -19
- package/dist/UnifiedDraftModelPage/index.mjs +18 -18
- package/dist/UnifiedHistoryPage/index.js +19 -19
- package/dist/UnifiedHistoryPage/index.mjs +18 -18
- package/dist/VerticalBarChart/index.js +1 -1
- package/dist/VerticalBarChart/index.mjs +1 -1
- package/dist/VideoPlayer/index.js +1 -1
- package/dist/VideoPlayer/index.mjs +1 -1
- package/dist/Whiteboard/index.js +1 -1
- package/dist/Whiteboard/index.mjs +1 -1
- package/dist/{chunk-JBAGQ7L5.js → chunk-3VG5MEMY.js} +14 -13
- package/dist/chunk-3VG5MEMY.js.map +1 -0
- package/dist/{chunk-ED23HOE6.mjs → chunk-5NIU4XJY.mjs} +7 -6
- package/dist/chunk-5NIU4XJY.mjs.map +1 -0
- package/dist/{chunk-DDZDNGBU.mjs → chunk-64WGFT5E.mjs} +3 -1
- package/dist/chunk-64WGFT5E.mjs.map +1 -0
- package/dist/{chunk-QN32O3J3.js → chunk-6MK23BTK.js} +62 -62
- package/dist/{chunk-QN32O3J3.js.map → chunk-6MK23BTK.js.map} +1 -1
- package/dist/{chunk-XX4WE4TL.js → chunk-726PIA5M.js} +1 -1
- package/dist/chunk-726PIA5M.js.map +1 -0
- package/dist/{chunk-VZJKHIHN.mjs → chunk-7KALNPIG.mjs} +4 -4
- package/dist/{chunk-NQNEG4KR.mjs → chunk-7VKFZHWP.mjs} +11 -10
- package/dist/chunk-7VKFZHWP.mjs.map +1 -0
- package/dist/{chunk-GYQUB3VW.js → chunk-BBFV3NDF.js} +8 -6
- package/dist/chunk-BBFV3NDF.js.map +1 -0
- package/dist/{chunk-I3Z2BHGN.js → chunk-BJHYT75K.js} +3 -3
- package/dist/{chunk-I3Z2BHGN.js.map → chunk-BJHYT75K.js.map} +1 -1
- package/dist/{chunk-CFTQ24UT.mjs → chunk-CMYBNZ74.mjs} +2 -2
- package/dist/{chunk-R7NS5KFE.mjs → chunk-CWUNF7U6.mjs} +3 -3
- package/dist/{chunk-NAOHJW6H.mjs → chunk-DLHV7CZN.mjs} +6 -6
- package/dist/{chunk-7EXSCXPK.mjs → chunk-DMYETMZG.mjs} +2 -2
- package/dist/{chunk-RQPSA4QV.js → chunk-GQUTHDV2.js} +3 -3
- package/dist/{chunk-RQPSA4QV.js.map → chunk-GQUTHDV2.js.map} +1 -1
- package/dist/{chunk-OZWPOXVU.mjs → chunk-GVGDUCVF.mjs} +2 -2
- package/dist/{chunk-QFWY46XU.js → chunk-IMDS5NQL.js} +16 -16
- package/dist/{chunk-QFWY46XU.js.map → chunk-IMDS5NQL.js.map} +1 -1
- package/dist/{chunk-KYGFYAU7.js → chunk-JHN35HPH.js} +3 -3
- package/dist/{chunk-KYGFYAU7.js.map → chunk-JHN35HPH.js.map} +1 -1
- package/dist/{chunk-DMZTDCUF.js → chunk-JPQI2RIV.js} +3 -3
- package/dist/{chunk-DMZTDCUF.js.map → chunk-JPQI2RIV.js.map} +1 -1
- package/dist/{chunk-LXX5KU3O.mjs → chunk-LMDAF6LA.mjs} +2 -2
- package/dist/{chunk-FL4W4S6J.mjs → chunk-MOSP7FR5.mjs} +1 -1
- package/dist/chunk-MOSP7FR5.mjs.map +1 -0
- package/dist/{chunk-HZXXADG4.js → chunk-NLPBW3SW.js} +44 -43
- package/dist/chunk-NLPBW3SW.js.map +1 -0
- package/dist/{chunk-TAABXGZL.mjs → chunk-O3JP6ZMQ.mjs} +2 -2
- package/dist/{chunk-MFO4S7T5.js → chunk-PJOBOBNJ.js} +3 -3
- package/dist/{chunk-MFO4S7T5.js.map → chunk-PJOBOBNJ.js.map} +1 -1
- package/dist/{chunk-CWGYVJTQ.mjs → chunk-PORNR2NU.mjs} +3 -3
- package/dist/chunk-QF3UKRIJ.js +33 -0
- package/dist/chunk-QF3UKRIJ.js.map +1 -0
- package/dist/chunk-RAHXO5YU.mjs +33 -0
- package/dist/chunk-RAHXO5YU.mjs.map +1 -0
- package/dist/{chunk-BTZANNVO.js → chunk-RQ65U5G2.js} +3 -3
- package/dist/{chunk-BTZANNVO.js.map → chunk-RQ65U5G2.js.map} +1 -1
- package/dist/{chunk-Q56I63FO.mjs → chunk-RVGLLMWG.mjs} +2 -2
- package/dist/{chunk-VVRRAF6H.js → chunk-S2S7TK3L.js} +49 -36
- package/dist/chunk-S2S7TK3L.js.map +1 -0
- package/dist/{chunk-INIH23HU.js → chunk-VF6QXUX3.js} +2 -2
- package/dist/{chunk-INIH23HU.js.map → chunk-VF6QXUX3.js.map} +1 -1
- package/dist/{chunk-QWC5GC2Q.mjs → chunk-WY7V5UJN.mjs} +2 -2
- package/dist/{chunk-OCKO7T7L.js → chunk-XQAYZBLL.js} +3 -3
- package/dist/{chunk-OCKO7T7L.js.map → chunk-XQAYZBLL.js.map} +1 -1
- package/dist/{chunk-ATGLKKXI.js → chunk-Y7ZBWTD7.js} +17 -17
- package/dist/{chunk-ATGLKKXI.js.map → chunk-Y7ZBWTD7.js.map} +1 -1
- package/dist/{chunk-7XWWI5EY.js → chunk-YFIB3YNQ.js} +11 -11
- package/dist/{chunk-7XWWI5EY.js.map → chunk-YFIB3YNQ.js.map} +1 -1
- package/dist/{chunk-UCWTF336.mjs → chunk-YWGJAB63.mjs} +2 -2
- package/dist/{chunk-4MPXVPBQ.mjs → chunk-YYHS2TM6.mjs} +43 -30
- package/dist/chunk-YYHS2TM6.mjs.map +1 -0
- package/dist/components/Quiz/Quiz.utils.d.ts +8 -0
- package/dist/components/Quiz/Quiz.utils.d.ts.map +1 -1
- package/dist/hooks/useAppContent/index.js +19 -19
- package/dist/hooks/useAppContent/index.mjs +18 -18
- package/dist/hooks/useComparator/index.js +1 -1
- package/dist/hooks/useComparator/index.mjs +1 -1
- package/dist/hooks/useDraftAutoSave/index.js +3 -3
- package/dist/hooks/useDraftAutoSave/index.mjs +2 -2
- package/dist/index.js +19 -19
- package/dist/index.mjs +18 -18
- package/dist/types/enemClassroom/index.d.ts +29 -2
- package/dist/types/enemClassroom/index.d.ts.map +1 -1
- package/dist/types/enemClassroom/index.js +4 -2
- package/dist/types/enemClassroom/index.js.map +1 -1
- package/dist/types/enemClassroom/index.mjs +3 -1
- package/dist/types/enemClassroom.d.ts +29 -2
- package/dist/types/enemClassroom.d.ts.map +1 -1
- package/dist/types/questionTypes/index.js +1 -1
- package/dist/types/questionTypes/index.mjs +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/renderSubjectCell/index.js +1 -1
- package/dist/utils/renderSubjectCell/index.mjs +1 -1
- package/dist/utils/renderTextCell/index.js +1 -1
- package/dist/utils/renderTextCell/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-4MPXVPBQ.mjs.map +0 -1
- package/dist/chunk-DDZDNGBU.mjs.map +0 -1
- package/dist/chunk-ED23HOE6.mjs.map +0 -1
- package/dist/chunk-FL4W4S6J.mjs.map +0 -1
- package/dist/chunk-GYQUB3VW.js.map +0 -1
- package/dist/chunk-HZXXADG4.js.map +0 -1
- package/dist/chunk-JBAGQ7L5.js.map +0 -1
- package/dist/chunk-ND5M3DZA.mjs +0 -21
- package/dist/chunk-ND5M3DZA.mjs.map +0 -1
- package/dist/chunk-NQNEG4KR.mjs.map +0 -1
- package/dist/chunk-NYKBCQUO.js +0 -21
- package/dist/chunk-NYKBCQUO.js.map +0 -1
- package/dist/chunk-VVRRAF6H.js.map +0 -1
- package/dist/chunk-XX4WE4TL.js.map +0 -1
- /package/dist/{RichEditorCore-QZYPHNRY.mjs.map → RichEditorCore-TLAFZ5XG.mjs.map} +0 -0
- /package/dist/{chunk-VZJKHIHN.mjs.map → chunk-7KALNPIG.mjs.map} +0 -0
- /package/dist/{chunk-CFTQ24UT.mjs.map → chunk-CMYBNZ74.mjs.map} +0 -0
- /package/dist/{chunk-R7NS5KFE.mjs.map → chunk-CWUNF7U6.mjs.map} +0 -0
- /package/dist/{chunk-NAOHJW6H.mjs.map → chunk-DLHV7CZN.mjs.map} +0 -0
- /package/dist/{chunk-7EXSCXPK.mjs.map → chunk-DMYETMZG.mjs.map} +0 -0
- /package/dist/{chunk-OZWPOXVU.mjs.map → chunk-GVGDUCVF.mjs.map} +0 -0
- /package/dist/{chunk-LXX5KU3O.mjs.map → chunk-LMDAF6LA.mjs.map} +0 -0
- /package/dist/{chunk-TAABXGZL.mjs.map → chunk-O3JP6ZMQ.mjs.map} +0 -0
- /package/dist/{chunk-CWGYVJTQ.mjs.map → chunk-PORNR2NU.mjs.map} +0 -0
- /package/dist/{chunk-Q56I63FO.mjs.map → chunk-RVGLLMWG.mjs.map} +0 -0
- /package/dist/{chunk-QWC5GC2Q.mjs.map → chunk-WY7V5UJN.mjs.map} +0 -0
- /package/dist/{chunk-UCWTF336.mjs.map → chunk-YWGJAB63.mjs.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-KYGFYAU7.js","../src/components/Forum/Forum.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-KYGFYAU7.js","sourcesContent":[null,"import { useState, useEffect, useCallback } from 'react';\nimport {\n CaretLeftIcon,\n ChatCircleTextIcon,\n CheckIcon,\n DotsThreeVerticalIcon,\n ImageIcon,\n PencilSimpleIcon,\n TrashIcon,\n} from '@phosphor-icons/react';\nimport Text from '../Text/Text';\nimport Button from '../Button/Button';\nimport Input from '../Input/Input';\nimport TextArea from '../TextArea/TextArea';\nimport Modal from '../Modal/Modal';\nimport Radio from '../Radio/Radio';\nimport DropdownMenu, {\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n} from '../DropdownMenu/DropdownMenu';\nimport { RichEditor } from '../RichEditor/RichEditor';\nimport ImageUpload from '../ImageUpload/ImageUpload';\nimport { SkeletonList, SkeletonCard } from '../Skeleton/Skeleton';\nimport { stripHtml, sanitizeHtmlForDisplay } from '../HtmlMathRenderer';\nimport { cn } from '../../utils/utils';\nimport type { ForumApiClient, ForumTopic, ForumReply } from '../../types/forum';\nimport { PROFILE_ROLES } from '../../types/chat';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst MONTHS_PT = [\n 'Janeiro',\n 'Fevereiro',\n 'Março',\n 'Abril',\n 'Maio',\n 'Junho',\n 'Julho',\n 'Agosto',\n 'Setembro',\n 'Outubro',\n 'Novembro',\n 'Dezembro',\n];\n\nfunction formatForumDate(isoDate: string): string {\n const d = new Date(isoDate);\n const day = d.getDate();\n const month = MONTHS_PT[d.getMonth()];\n const year = d.getFullYear();\n const hours = d.getHours();\n const minutes = d.getMinutes().toString().padStart(2, '0');\n return `${day} ${month} ${year} • ${hours}:${minutes}`;\n}\n\nfunction getInitials(name: string): string {\n return name\n .split(' ')\n .slice(0, 2)\n .map((word) => word[0] ?? '')\n .join('')\n .toUpperCase();\n}\n\nfunction formatReplyCount(count: number): string {\n if (count === 1) return '1 resposta';\n return `${count} respostas`;\n}\n\n// ---------------------------------------------------------------------------\n// Sub-components\n// ---------------------------------------------------------------------------\n\ninterface AuthorAvatarProps {\n readonly name: string;\n readonly photoUrl: string | null;\n}\n\nfunction AuthorAvatar({ name, photoUrl }: AuthorAvatarProps) {\n if (photoUrl) {\n return (\n <img\n src={photoUrl}\n alt={name}\n className=\"w-8 h-8 rounded-full object-cover shrink-0\"\n />\n );\n }\n return (\n <div className=\"w-8 h-8 rounded-full bg-primary-600 flex items-center justify-center shrink-0\">\n <Text size=\"xs\" weight=\"semibold\" color=\"text-white\">\n {getInitials(name)}\n </Text>\n </div>\n );\n}\n\ninterface AuthorMetaProps {\n readonly authorName: string;\n readonly authorPhoto: string | null;\n readonly createdAt: string;\n}\n\nfunction AuthorMeta({ authorName, authorPhoto, createdAt }: AuthorMetaProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <AuthorAvatar name={authorName} photoUrl={authorPhoto} />\n <div className=\"flex items-center gap-1\">\n <Text size=\"xs\" weight=\"semibold\" color=\"text-primary-700\">\n Postado por {authorName}\n </Text>\n <Text size=\"xs\" color=\"text-text-600\">\n • {formatForumDate(createdAt)}\n </Text>\n </div>\n </div>\n );\n}\n\ninterface PostActionsMenuProps {\n readonly onEdit: () => void;\n readonly onDelete: () => void;\n}\n\nfunction PostActionsMenu({ onEdit, onDelete }: PostActionsMenuProps) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-label=\"Abrir ações do post\"\n className=\"p-1 rounded hover:bg-background-100 transition-colors shrink-0\"\n >\n <DotsThreeVerticalIcon size={20} className=\"text-text-600\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n iconLeft={<PencilSimpleIcon size={16} />}\n onClick={onEdit}\n >\n Editar\n </DropdownMenuItem>\n <DropdownMenuItem iconLeft={<TrashIcon size={16} />} onClick={onDelete}>\n Deletar\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\ninterface PostContentModalProps {\n readonly isOpen: boolean;\n readonly title: string;\n readonly submitLabel: string;\n readonly content: string;\n readonly imageUrl: string | undefined;\n readonly isSubmitting: boolean;\n readonly onContentChange: (value: string) => void;\n readonly onClose: () => void;\n readonly onSubmit: () => void;\n readonly onUploadImage?: (file: File) => Promise<string>;\n readonly onImageUploaded: (url: string) => void;\n readonly maxLength: number;\n /** Use RichEditor with toolbar instead of plain TextArea */\n readonly richText?: boolean;\n /** Show \"Este fórum vale nota no boletim?\" question (professor only) */\n readonly showGradeQuestion?: boolean;\n readonly countsForGrade?: boolean;\n readonly onCountsForGradeChange?: (value: boolean) => void;\n}\n\nfunction PostContentModal({\n isOpen,\n title,\n submitLabel,\n content,\n imageUrl,\n isSubmitting,\n onContentChange,\n onClose,\n onSubmit,\n onUploadImage,\n onImageUploaded,\n maxLength,\n richText = false,\n showGradeQuestion = false,\n countsForGrade,\n onCountsForGradeChange,\n}: PostContentModalProps) {\n const handleImageSelect = useCallback(\n async (file: File) => {\n if (!onUploadImage) return;\n try {\n const url = await onUploadImage(file);\n onImageUploaded(url);\n } catch {\n // silently fail — consuming app should handle upload errors\n }\n },\n [onUploadImage, onImageUploaded]\n );\n\n // Determine if content is effectively empty or exceeds the limit\n const plainTextContent = richText ? stripHtml(content) : content;\n const isContentEmpty = !plainTextContent.trim();\n const exceedsMaxLength = plainTextContent.trim().length > maxLength;\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={title}\n size=\"md\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={onClose}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n disabled={isContentEmpty || exceedsMaxLength || isSubmitting}\n onClick={onSubmit}\n >\n {submitLabel}\n </Button>\n </div>\n }\n >\n <div className=\"flex flex-col gap-3\">\n {richText ? (\n // key forces remount (and thus reset) whenever the modal opens/closes\n <RichEditor\n key={String(isOpen)}\n content={content}\n onChange={(data) => onContentChange(data.html)}\n placeholder=\"Escreva o conteúdo do seu post aqui.\"\n />\n ) : (\n <TextArea\n placeholder=\"Escreva o conteúdo do seu post aqui.\"\n value={content}\n onChange={(e) => onContentChange(e.target.value)}\n autoResize\n minHeight={120}\n maxLength={maxLength}\n />\n )}\n\n <ImageUpload\n variant=\"compact\"\n onFileSelect={handleImageSelect}\n onRemoveFile={() => onImageUploaded('')}\n buttonIcon={<ImageIcon size={16} />}\n />\n {imageUrl && (\n <img\n src={imageUrl}\n alt=\"Preview da imagem\"\n className=\"max-h-40 rounded-lg object-contain\"\n />\n )}\n\n {showGradeQuestion && (\n <div className=\"flex flex-col gap-2\">\n <Text size=\"sm\" weight=\"medium\">\n Este fórum vale nota no boletim?\n </Text>\n <div className=\"flex items-center gap-4\">\n <Radio\n name=\"countsForGrade\"\n value=\"yes\"\n label=\"Sim\"\n size=\"small\"\n checked={countsForGrade === true}\n onChange={() => onCountsForGradeChange?.(true)}\n />\n <Radio\n name=\"countsForGrade\"\n value=\"no\"\n label=\"Não\"\n size=\"small\"\n checked={countsForGrade === false}\n onChange={() => onCountsForGradeChange?.(false)}\n />\n </div>\n </div>\n )}\n </div>\n </Modal>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Skeleton\n// ---------------------------------------------------------------------------\n\nfunction TopicListSkeleton() {\n return (\n <SkeletonList items={3} showAvatar showTitle showDescription lines={2} />\n );\n}\n\nfunction TopicDetailSkeleton() {\n return (\n <SkeletonCard\n showAvatar\n showTitle\n showDescription\n showActions={false}\n lines={2}\n />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component\n// ---------------------------------------------------------------------------\n\nexport type ForumProps = {\n /** API client with forum CRUD methods */\n readonly apiClient: ForumApiClient;\n /** Current user's userInstitutionId — used to identify own posts */\n readonly currentUserId: string;\n /** User role — enables professor-specific features (e.g. grade question on create) */\n readonly userRole?: PROFILE_ROLES.STUDENT | PROFILE_ROLES.TEACHER;\n /** Forum page title */\n readonly title?: string;\n /** Forum page subtitle */\n readonly subtitle?: string;\n /** Callback to upload an image file and return its hosted URL */\n readonly onUploadImage?: (file: File) => Promise<string>;\n /**\n * Callback to evaluate a reply (teacher only).\n * If provided, an \"Avaliar\" button appears on each reply when the topic counts for grade.\n */\n readonly onEvaluateReply?: (replyId: string, grade: number) => Promise<void>;\n /** Additional CSS classes */\n readonly className?: string;\n};\n\nexport function Forum({\n apiClient,\n currentUserId,\n userRole = PROFILE_ROLES.STUDENT,\n title = 'Fórum',\n subtitle = 'Espaço para troca de conhecimento',\n onUploadImage,\n onEvaluateReply,\n className,\n}: ForumProps) {\n const isTeacher = userRole === PROFILE_ROLES.TEACHER;\n const [view, setView] = useState<'list' | 'detail'>('list');\n const [topics, setTopics] = useState<ForumTopic[]>([]);\n const [isLoadingTopics, setIsLoadingTopics] = useState(false);\n const [selectedTopic, setSelectedTopic] = useState<ForumTopic | null>(null);\n const [replies, setReplies] = useState<ForumReply[]>([]);\n const [isLoadingTopic, setIsLoadingTopic] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n // Create post modal state\n const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);\n const [createContent, setCreateContent] = useState('');\n const [createImageUrl, setCreateImageUrl] = useState<string | undefined>();\n const [createCountsForGrade, setCreateCountsForGrade] = useState<\n boolean | undefined\n >();\n\n // Reply modal state\n const [isReplyModalOpen, setIsReplyModalOpen] = useState(false);\n const [replyContent, setReplyContent] = useState('');\n const [replyImageUrl, setReplyImageUrl] = useState<string | undefined>();\n\n // Edit topic modal state\n const [editingTopic, setEditingTopic] = useState<ForumTopic | null>(null);\n const [editTopicContent, setEditTopicContent] = useState('');\n const [editTopicImageUrl, setEditTopicImageUrl] = useState<\n string | undefined\n >();\n\n // Edit reply modal state\n const [editingReply, setEditingReply] = useState<ForumReply | null>(null);\n const [editReplyContent, setEditReplyContent] = useState('');\n const [editReplyImageUrl, setEditReplyImageUrl] = useState<\n string | undefined\n >();\n\n // Evaluate reply modal state (teacher only)\n const [evaluatingReplyId, setEvaluatingReplyId] = useState<string | null>(\n null\n );\n const [gradeValue, setGradeValue] = useState<number | null>(null);\n const [isEditingGrade, setIsEditingGrade] = useState(false);\n\n // Delete confirmation state\n const [pendingDelete, setPendingDelete] = useState<\n { type: 'topic'; id: string } | { type: 'reply'; id: string } | null\n >(null);\n\n const fetchTopics = useCallback(async () => {\n setIsLoadingTopics(true);\n try {\n const response = await apiClient.getTopics({ limit: 50 });\n setTopics(response.topics);\n } finally {\n setIsLoadingTopics(false);\n }\n }, [apiClient]);\n\n const fetchTopic = useCallback(\n async (topicId: string) => {\n setIsLoadingTopic(true);\n try {\n const response = await apiClient.getTopic(topicId);\n setSelectedTopic(response.topic);\n setReplies(response.replies);\n } finally {\n setIsLoadingTopic(false);\n }\n },\n [apiClient]\n );\n\n useEffect(() => {\n fetchTopics();\n }, [fetchTopics]);\n\n const handleTopicClick = useCallback(\n (topic: ForumTopic) => {\n setSelectedTopic(topic);\n setView('detail');\n fetchTopic(topic.id);\n },\n [fetchTopic]\n );\n\n const handleBack = useCallback(() => {\n setView('list');\n setSelectedTopic(null);\n setReplies([]);\n fetchTopics();\n }, [fetchTopics]);\n\n // Create topic\n const handleCloseCreateModal = useCallback(() => {\n setIsCreateModalOpen(false);\n setCreateContent('');\n setCreateImageUrl(undefined);\n setCreateCountsForGrade(undefined);\n }, []);\n\n const handleCreateTopic = useCallback(async () => {\n if (!createContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.createTopic({\n content: createContent.trim(),\n ...(createImageUrl && { imageUrl: createImageUrl }),\n ...(isTeacher &&\n createCountsForGrade !== undefined && {\n countsForGrade: createCountsForGrade,\n }),\n });\n handleCloseCreateModal();\n await fetchTopics();\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n createContent,\n createImageUrl,\n createCountsForGrade,\n isTeacher,\n handleCloseCreateModal,\n fetchTopics,\n ]);\n\n // Edit topic\n const handleOpenEditTopic = useCallback((topic: ForumTopic) => {\n setEditingTopic(topic);\n setEditTopicContent(topic.content);\n setEditTopicImageUrl(topic.imageUrl ?? undefined);\n }, []);\n\n const handleCloseEditTopic = useCallback(() => {\n setEditingTopic(null);\n setEditTopicContent('');\n setEditTopicImageUrl(undefined);\n }, []);\n\n const handleEditTopic = useCallback(async () => {\n if (!editingTopic || !editTopicContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.updateTopic(editingTopic.id, {\n content: editTopicContent.trim(),\n imageUrl: editTopicImageUrl ?? null,\n });\n handleCloseEditTopic();\n if (view === 'list') {\n await fetchTopics();\n } else {\n await fetchTopic(editingTopic.id);\n }\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n editingTopic,\n editTopicContent,\n editTopicImageUrl,\n handleCloseEditTopic,\n view,\n fetchTopics,\n fetchTopic,\n ]);\n\n const handleDeleteTopic = useCallback(\n async (topicId: string) => {\n setIsSubmitting(true);\n try {\n await apiClient.deleteTopic(topicId);\n if (view === 'detail') {\n handleBack();\n } else {\n await fetchTopics();\n }\n } finally {\n setIsSubmitting(false);\n setPendingDelete(null);\n }\n },\n [apiClient, view, handleBack, fetchTopics]\n );\n\n // Reply\n const handleCloseReplyModal = useCallback(() => {\n setIsReplyModalOpen(false);\n setReplyContent('');\n setReplyImageUrl(undefined);\n }, []);\n\n const handleCreateReply = useCallback(async () => {\n if (!selectedTopic || !replyContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.createReply(selectedTopic.id, {\n content: replyContent.trim(),\n ...(replyImageUrl && { imageUrl: replyImageUrl }),\n });\n handleCloseReplyModal();\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n selectedTopic,\n replyContent,\n replyImageUrl,\n handleCloseReplyModal,\n fetchTopic,\n ]);\n\n // Edit reply\n const handleOpenEditReply = useCallback((reply: ForumReply) => {\n setEditingReply(reply);\n setEditReplyContent(reply.content);\n setEditReplyImageUrl(reply.imageUrl ?? undefined);\n }, []);\n\n const handleCloseEditReply = useCallback(() => {\n setEditingReply(null);\n setEditReplyContent('');\n setEditReplyImageUrl(undefined);\n }, []);\n\n const handleEditReply = useCallback(async () => {\n if (!editingReply || !editReplyContent.trim() || !selectedTopic) return;\n setIsSubmitting(true);\n try {\n await apiClient.updateReply(editingReply.id, {\n content: editReplyContent.trim(),\n imageUrl: editReplyImageUrl ?? null,\n });\n handleCloseEditReply();\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n editingReply,\n editReplyContent,\n editReplyImageUrl,\n handleCloseEditReply,\n selectedTopic,\n fetchTopic,\n ]);\n\n const handleDeleteReply = useCallback(\n async (replyId: string) => {\n if (!selectedTopic) return;\n setIsSubmitting(true);\n try {\n await apiClient.deleteReply(replyId);\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n setPendingDelete(null);\n }\n },\n [apiClient, selectedTopic, fetchTopic]\n );\n\n const handleCloseEvaluateModal = useCallback(() => {\n setEvaluatingReplyId(null);\n setGradeValue(null);\n setIsEditingGrade(false);\n }, []);\n\n const handleOpenEvaluate = useCallback((reply: ForumReply) => {\n setEvaluatingReplyId(reply.id);\n setGradeValue(null);\n setIsEditingGrade(false);\n }, []);\n\n const handleOpenEditGrade = useCallback((reply: ForumReply) => {\n setEvaluatingReplyId(reply.id);\n setGradeValue(reply.grade ?? null);\n setIsEditingGrade(true);\n }, []);\n\n const isValidGrade =\n gradeValue !== null &&\n Number.isInteger(gradeValue) &&\n gradeValue >= 0 &&\n gradeValue <= 10;\n\n const handleSubmitEvaluation = useCallback(async () => {\n if (!evaluatingReplyId || !isValidGrade || !onEvaluateReply) return;\n setIsSubmitting(true);\n try {\n await onEvaluateReply(evaluatingReplyId, gradeValue);\n // Optimistically update grade in local state\n setReplies((prev) =>\n prev.map((r) =>\n r.id === evaluatingReplyId ? { ...r, grade: gradeValue } : r\n )\n );\n handleCloseEvaluateModal();\n } finally {\n setIsSubmitting(false);\n }\n }, [\n evaluatingReplyId,\n gradeValue,\n isValidGrade,\n onEvaluateReply,\n handleCloseEvaluateModal,\n ]);\n\n const handleConfirmDelete = useCallback(async () => {\n if (!pendingDelete) return;\n if (pendingDelete.type === 'topic') {\n await handleDeleteTopic(pendingDelete.id);\n } else {\n await handleDeleteReply(pendingDelete.id);\n }\n }, [pendingDelete, handleDeleteTopic, handleDeleteReply]);\n\n /* ---- Extracted render blocks (avoids nested ternaries — SonarQube) ---- */\n\n const topicListContent = (() => {\n if (isLoadingTopics) return <TopicListSkeleton />;\n\n if (topics.length === 0) {\n return (\n <div className=\"flex items-center justify-center py-16 border border-border-200 rounded-lg\">\n <Text size=\"md\" color=\"text-text-500\">\n Nenhum tópico ainda. Seja o primeiro a criar um post!\n </Text>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col gap-4\">\n {topics.map((topic) => (\n <div\n key={topic.id}\n className=\"flex items-start bg-white border border-border-100 rounded-lg pt-4 pr-2 pb-4 pl-2 shadow-sm\"\n >\n {/* Clickable content area */}\n <button\n type=\"button\"\n className=\"flex flex-col gap-3 flex-1 min-w-0 text-left hover:opacity-90 transition-opacity\"\n onClick={() => handleTopicClick(topic)}\n >\n <AuthorMeta\n authorName={topic.authorName}\n authorPhoto={topic.authorPhoto}\n createdAt={topic.createdAt}\n />\n <Text size=\"sm\" className=\"leading-normal line-clamp-3 ml-10\">\n {stripHtml(topic.content)}\n </Text>\n <div className=\"flex items-center gap-1 text-text-600 ml-10\">\n <ChatCircleTextIcon size={16} />\n <Text size=\"xs\">{formatReplyCount(topic.replyCount)}</Text>\n </div>\n </button>\n\n {/* Actions menu — only for own posts */}\n {topic.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditTopic(topic)}\n onDelete={() =>\n setPendingDelete({ type: 'topic', id: topic.id })\n }\n />\n )}\n </div>\n ))}\n </div>\n );\n })();\n\n const topicDetailContent = (() => {\n if (isLoadingTopic) return <TopicDetailSkeleton />;\n\n if (!selectedTopic) return null;\n\n return (\n <>\n {/* Original post */}\n <div className=\"flex items-start gap-2\">\n <div className=\"flex flex-col gap-3 flex-1 min-w-0\">\n <AuthorMeta\n authorName={selectedTopic.authorName}\n authorPhoto={selectedTopic.authorPhoto}\n createdAt={selectedTopic.createdAt}\n />\n <div\n className=\"text-sm text-text-950 leading-normal ml-10 prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtmlForDisplay(selectedTopic.content),\n }}\n />\n {selectedTopic.imageUrl && (\n <img\n src={selectedTopic.imageUrl}\n alt=\"Imagem do post\"\n className=\"ml-10 max-w-lg rounded-lg\"\n />\n )}\n </div>\n {selectedTopic.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditTopic(selectedTopic)}\n onDelete={() =>\n setPendingDelete({ type: 'topic', id: selectedTopic.id })\n }\n />\n )}\n </div>\n\n {/* Replies header */}\n <div className=\"flex items-center justify-between\">\n <Text size=\"sm\" color=\"text-text-600\">\n {formatReplyCount(selectedTopic.replyCount)}\n </Text>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n onClick={() => setIsReplyModalOpen(true)}\n >\n Responder\n </Button>\n </div>\n\n {/* Replies list */}\n {replies.length > 0 && (\n <div className=\"flex flex-col divide-y divide-border-200\">\n {replies.map((reply) => (\n <div key={reply.id} className=\"flex items-start gap-2 py-4\">\n <div className=\"flex flex-col gap-3 flex-1 min-w-0\">\n <AuthorMeta\n authorName={reply.authorName}\n authorPhoto={reply.authorPhoto}\n createdAt={reply.createdAt}\n />\n <div\n className=\"text-sm text-text-950 leading-normal ml-10 prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtmlForDisplay(reply.content),\n }}\n />\n {reply.imageUrl && (\n <img\n src={reply.imageUrl}\n alt=\"Imagem da resposta\"\n className=\"ml-10 max-w-lg rounded-lg\"\n />\n )}\n {isTeacher &&\n selectedTopic?.countsForGrade &&\n onEvaluateReply &&\n (reply.grade == null ? (\n /* Not yet graded — show Avaliar button */\n <button\n type=\"button\"\n className=\"flex items-center gap-1.5 text-text-600 text-sm hover:text-text-950 transition-colors w-fit ml-10\"\n onClick={() => handleOpenEvaluate(reply)}\n >\n <CheckIcon size={16} />\n Avaliar\n </button>\n ) : (\n /* Grade already set — teacher sees it with edit pencil */\n <div className=\"flex items-center gap-1.5 ml-10\">\n <Text size=\"sm\" color=\"text-text-600\">\n Nota {reply.grade}\n </Text>\n <button\n type=\"button\"\n className=\"text-text-600 hover:text-text-950 transition-colors\"\n onClick={() => handleOpenEditGrade(reply)}\n >\n <PencilSimpleIcon size={14} />\n </button>\n </div>\n ))}\n {!isTeacher &&\n reply.grade != null &&\n reply.userInstitutionId === currentUserId &&\n selectedTopic?.countsForGrade && (\n <Text size=\"sm\" color=\"text-text-600\" className=\"ml-10\">\n Nota {reply.grade}\n </Text>\n )}\n </div>\n {reply.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditReply(reply)}\n onDelete={() =>\n setPendingDelete({ type: 'reply', id: reply.id })\n }\n />\n )}\n </div>\n ))}\n </div>\n )}\n </>\n );\n })();\n\n return (\n <div className={cn('flex flex-col gap-4', className)}>\n {view === 'list' ? (\n <>\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <Text as=\"h1\" size=\"2xl\" weight=\"bold\" color=\"text-text-950\">\n {title}\n </Text>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n onClick={() => setIsCreateModalOpen(true)}\n >\n Criar post\n </Button>\n </div>\n\n {/* Subtitle + topic list */}\n <div className=\"flex flex-col gap-3\">\n <Text as=\"h2\" size=\"lg\" weight=\"semibold\" color=\"text-text-950\">\n {subtitle}\n </Text>\n\n {topicListContent}\n </div>\n </>\n ) : (\n /* Detail view */\n <>\n <button\n type=\"button\"\n className=\"flex items-center gap-2 hover:opacity-80 transition-opacity w-fit\"\n onClick={handleBack}\n >\n <CaretLeftIcon size={24} className=\"text-text-950\" />\n <Text size=\"2xl\" weight=\"bold\">\n Voltar\n </Text>\n </button>\n\n {topicDetailContent}\n </>\n )}\n\n {/* Create post modal */}\n <PostContentModal\n isOpen={isCreateModalOpen}\n title=\"Criar post\"\n submitLabel=\"Criar post\"\n content={createContent}\n imageUrl={createImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setCreateContent}\n onClose={handleCloseCreateModal}\n onSubmit={handleCreateTopic}\n onUploadImage={onUploadImage}\n onImageUploaded={setCreateImageUrl}\n maxLength={10000}\n richText\n showGradeQuestion={isTeacher}\n countsForGrade={createCountsForGrade}\n onCountsForGradeChange={setCreateCountsForGrade}\n />\n\n {/* Reply modal */}\n <PostContentModal\n isOpen={isReplyModalOpen}\n title=\"Responder\"\n submitLabel=\"Responder\"\n content={replyContent}\n imageUrl={replyImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setReplyContent}\n onClose={handleCloseReplyModal}\n onSubmit={handleCreateReply}\n onUploadImage={onUploadImage}\n onImageUploaded={setReplyImageUrl}\n maxLength={5000}\n richText\n />\n\n {/* Edit topic modal */}\n <PostContentModal\n isOpen={!!editingTopic}\n title=\"Editar\"\n submitLabel=\"Salvar\"\n content={editTopicContent}\n imageUrl={editTopicImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setEditTopicContent}\n onClose={handleCloseEditTopic}\n onSubmit={handleEditTopic}\n onUploadImage={onUploadImage}\n onImageUploaded={setEditTopicImageUrl}\n maxLength={10000}\n richText\n />\n\n {/* Edit reply modal */}\n <PostContentModal\n isOpen={!!editingReply}\n title=\"Editar\"\n submitLabel=\"Salvar\"\n content={editReplyContent}\n imageUrl={editReplyImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setEditReplyContent}\n onClose={handleCloseEditReply}\n onSubmit={handleEditReply}\n onUploadImage={onUploadImage}\n onImageUploaded={setEditReplyImageUrl}\n maxLength={5000}\n richText\n />\n\n {/* Evaluate / edit grade modal (teacher only) */}\n <Modal\n isOpen={!!evaluatingReplyId}\n onClose={handleCloseEvaluateModal}\n title={\n isEditingGrade\n ? 'Edite a nota da atividade'\n : 'Defina a nota da atividade'\n }\n size=\"md\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={handleCloseEvaluateModal}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n disabled={!isValidGrade || isSubmitting}\n onClick={handleSubmitEvaluation}\n >\n {isEditingGrade ? 'Salvar' : 'Avaliar'}\n </Button>\n </div>\n }\n >\n <Input\n type=\"number\"\n min={0}\n max={10}\n step={1}\n placeholder=\"Nota (0-10)\"\n value={gradeValue ?? ''}\n onChange={(e) => {\n const val = e.target.value;\n const parsed = Number(val);\n setGradeValue(val === '' || Number.isNaN(parsed) ? null : parsed);\n }}\n />\n </Modal>\n\n {/* Delete confirmation modal */}\n <Modal\n isOpen={!!pendingDelete}\n onClose={() => setPendingDelete(null)}\n title=\"Deseja deletar post?\"\n size=\"sm\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={() => setPendingDelete(null)}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"negative\"\n size=\"medium\"\n disabled={isSubmitting}\n onClick={handleConfirmDelete}\n >\n Deletar\n </Button>\n </div>\n }\n >\n <Text size=\"md\" color=\"text-text-600\">\n Essa ação é permanente e não poderá ser desfeita.\n </Text>\n </Modal>\n </div>\n );\n}\n\nexport default Forum;\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-JHN35HPH.js","../src/components/Forum/Forum.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-JHN35HPH.js","sourcesContent":[null,"import { useState, useEffect, useCallback } from 'react';\nimport {\n CaretLeftIcon,\n ChatCircleTextIcon,\n CheckIcon,\n DotsThreeVerticalIcon,\n ImageIcon,\n PencilSimpleIcon,\n TrashIcon,\n} from '@phosphor-icons/react';\nimport Text from '../Text/Text';\nimport Button from '../Button/Button';\nimport Input from '../Input/Input';\nimport TextArea from '../TextArea/TextArea';\nimport Modal from '../Modal/Modal';\nimport Radio from '../Radio/Radio';\nimport DropdownMenu, {\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n} from '../DropdownMenu/DropdownMenu';\nimport { RichEditor } from '../RichEditor/RichEditor';\nimport ImageUpload from '../ImageUpload/ImageUpload';\nimport { SkeletonList, SkeletonCard } from '../Skeleton/Skeleton';\nimport { stripHtml, sanitizeHtmlForDisplay } from '../HtmlMathRenderer';\nimport { cn } from '../../utils/utils';\nimport type { ForumApiClient, ForumTopic, ForumReply } from '../../types/forum';\nimport { PROFILE_ROLES } from '../../types/chat';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst MONTHS_PT = [\n 'Janeiro',\n 'Fevereiro',\n 'Março',\n 'Abril',\n 'Maio',\n 'Junho',\n 'Julho',\n 'Agosto',\n 'Setembro',\n 'Outubro',\n 'Novembro',\n 'Dezembro',\n];\n\nfunction formatForumDate(isoDate: string): string {\n const d = new Date(isoDate);\n const day = d.getDate();\n const month = MONTHS_PT[d.getMonth()];\n const year = d.getFullYear();\n const hours = d.getHours();\n const minutes = d.getMinutes().toString().padStart(2, '0');\n return `${day} ${month} ${year} • ${hours}:${minutes}`;\n}\n\nfunction getInitials(name: string): string {\n return name\n .split(' ')\n .slice(0, 2)\n .map((word) => word[0] ?? '')\n .join('')\n .toUpperCase();\n}\n\nfunction formatReplyCount(count: number): string {\n if (count === 1) return '1 resposta';\n return `${count} respostas`;\n}\n\n// ---------------------------------------------------------------------------\n// Sub-components\n// ---------------------------------------------------------------------------\n\ninterface AuthorAvatarProps {\n readonly name: string;\n readonly photoUrl: string | null;\n}\n\nfunction AuthorAvatar({ name, photoUrl }: AuthorAvatarProps) {\n if (photoUrl) {\n return (\n <img\n src={photoUrl}\n alt={name}\n className=\"w-8 h-8 rounded-full object-cover shrink-0\"\n />\n );\n }\n return (\n <div className=\"w-8 h-8 rounded-full bg-primary-600 flex items-center justify-center shrink-0\">\n <Text size=\"xs\" weight=\"semibold\" color=\"text-white\">\n {getInitials(name)}\n </Text>\n </div>\n );\n}\n\ninterface AuthorMetaProps {\n readonly authorName: string;\n readonly authorPhoto: string | null;\n readonly createdAt: string;\n}\n\nfunction AuthorMeta({ authorName, authorPhoto, createdAt }: AuthorMetaProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <AuthorAvatar name={authorName} photoUrl={authorPhoto} />\n <div className=\"flex items-center gap-1\">\n <Text size=\"xs\" weight=\"semibold\" color=\"text-primary-700\">\n Postado por {authorName}\n </Text>\n <Text size=\"xs\" color=\"text-text-600\">\n • {formatForumDate(createdAt)}\n </Text>\n </div>\n </div>\n );\n}\n\ninterface PostActionsMenuProps {\n readonly onEdit: () => void;\n readonly onDelete: () => void;\n}\n\nfunction PostActionsMenu({ onEdit, onDelete }: PostActionsMenuProps) {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-label=\"Abrir ações do post\"\n className=\"p-1 rounded hover:bg-background-100 transition-colors shrink-0\"\n >\n <DotsThreeVerticalIcon size={20} className=\"text-text-600\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n iconLeft={<PencilSimpleIcon size={16} />}\n onClick={onEdit}\n >\n Editar\n </DropdownMenuItem>\n <DropdownMenuItem iconLeft={<TrashIcon size={16} />} onClick={onDelete}>\n Deletar\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\ninterface PostContentModalProps {\n readonly isOpen: boolean;\n readonly title: string;\n readonly submitLabel: string;\n readonly content: string;\n readonly imageUrl: string | undefined;\n readonly isSubmitting: boolean;\n readonly onContentChange: (value: string) => void;\n readonly onClose: () => void;\n readonly onSubmit: () => void;\n readonly onUploadImage?: (file: File) => Promise<string>;\n readonly onImageUploaded: (url: string) => void;\n readonly maxLength: number;\n /** Use RichEditor with toolbar instead of plain TextArea */\n readonly richText?: boolean;\n /** Show \"Este fórum vale nota no boletim?\" question (professor only) */\n readonly showGradeQuestion?: boolean;\n readonly countsForGrade?: boolean;\n readonly onCountsForGradeChange?: (value: boolean) => void;\n}\n\nfunction PostContentModal({\n isOpen,\n title,\n submitLabel,\n content,\n imageUrl,\n isSubmitting,\n onContentChange,\n onClose,\n onSubmit,\n onUploadImage,\n onImageUploaded,\n maxLength,\n richText = false,\n showGradeQuestion = false,\n countsForGrade,\n onCountsForGradeChange,\n}: PostContentModalProps) {\n const handleImageSelect = useCallback(\n async (file: File) => {\n if (!onUploadImage) return;\n try {\n const url = await onUploadImage(file);\n onImageUploaded(url);\n } catch {\n // silently fail — consuming app should handle upload errors\n }\n },\n [onUploadImage, onImageUploaded]\n );\n\n // Determine if content is effectively empty or exceeds the limit\n const plainTextContent = richText ? stripHtml(content) : content;\n const isContentEmpty = !plainTextContent.trim();\n const exceedsMaxLength = plainTextContent.trim().length > maxLength;\n\n return (\n <Modal\n isOpen={isOpen}\n onClose={onClose}\n title={title}\n size=\"md\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={onClose}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n disabled={isContentEmpty || exceedsMaxLength || isSubmitting}\n onClick={onSubmit}\n >\n {submitLabel}\n </Button>\n </div>\n }\n >\n <div className=\"flex flex-col gap-3\">\n {richText ? (\n // key forces remount (and thus reset) whenever the modal opens/closes\n <RichEditor\n key={String(isOpen)}\n content={content}\n onChange={(data) => onContentChange(data.html)}\n placeholder=\"Escreva o conteúdo do seu post aqui.\"\n />\n ) : (\n <TextArea\n placeholder=\"Escreva o conteúdo do seu post aqui.\"\n value={content}\n onChange={(e) => onContentChange(e.target.value)}\n autoResize\n minHeight={120}\n maxLength={maxLength}\n />\n )}\n\n <ImageUpload\n variant=\"compact\"\n onFileSelect={handleImageSelect}\n onRemoveFile={() => onImageUploaded('')}\n buttonIcon={<ImageIcon size={16} />}\n />\n {imageUrl && (\n <img\n src={imageUrl}\n alt=\"Preview da imagem\"\n className=\"max-h-40 rounded-lg object-contain\"\n />\n )}\n\n {showGradeQuestion && (\n <div className=\"flex flex-col gap-2\">\n <Text size=\"sm\" weight=\"medium\">\n Este fórum vale nota no boletim?\n </Text>\n <div className=\"flex items-center gap-4\">\n <Radio\n name=\"countsForGrade\"\n value=\"yes\"\n label=\"Sim\"\n size=\"small\"\n checked={countsForGrade === true}\n onChange={() => onCountsForGradeChange?.(true)}\n />\n <Radio\n name=\"countsForGrade\"\n value=\"no\"\n label=\"Não\"\n size=\"small\"\n checked={countsForGrade === false}\n onChange={() => onCountsForGradeChange?.(false)}\n />\n </div>\n </div>\n )}\n </div>\n </Modal>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Skeleton\n// ---------------------------------------------------------------------------\n\nfunction TopicListSkeleton() {\n return (\n <SkeletonList items={3} showAvatar showTitle showDescription lines={2} />\n );\n}\n\nfunction TopicDetailSkeleton() {\n return (\n <SkeletonCard\n showAvatar\n showTitle\n showDescription\n showActions={false}\n lines={2}\n />\n );\n}\n\n// ---------------------------------------------------------------------------\n// Main component\n// ---------------------------------------------------------------------------\n\nexport type ForumProps = {\n /** API client with forum CRUD methods */\n readonly apiClient: ForumApiClient;\n /** Current user's userInstitutionId — used to identify own posts */\n readonly currentUserId: string;\n /** User role — enables professor-specific features (e.g. grade question on create) */\n readonly userRole?: PROFILE_ROLES.STUDENT | PROFILE_ROLES.TEACHER;\n /** Forum page title */\n readonly title?: string;\n /** Forum page subtitle */\n readonly subtitle?: string;\n /** Callback to upload an image file and return its hosted URL */\n readonly onUploadImage?: (file: File) => Promise<string>;\n /**\n * Callback to evaluate a reply (teacher only).\n * If provided, an \"Avaliar\" button appears on each reply when the topic counts for grade.\n */\n readonly onEvaluateReply?: (replyId: string, grade: number) => Promise<void>;\n /** Additional CSS classes */\n readonly className?: string;\n};\n\nexport function Forum({\n apiClient,\n currentUserId,\n userRole = PROFILE_ROLES.STUDENT,\n title = 'Fórum',\n subtitle = 'Espaço para troca de conhecimento',\n onUploadImage,\n onEvaluateReply,\n className,\n}: ForumProps) {\n const isTeacher = userRole === PROFILE_ROLES.TEACHER;\n const [view, setView] = useState<'list' | 'detail'>('list');\n const [topics, setTopics] = useState<ForumTopic[]>([]);\n const [isLoadingTopics, setIsLoadingTopics] = useState(false);\n const [selectedTopic, setSelectedTopic] = useState<ForumTopic | null>(null);\n const [replies, setReplies] = useState<ForumReply[]>([]);\n const [isLoadingTopic, setIsLoadingTopic] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n // Create post modal state\n const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);\n const [createContent, setCreateContent] = useState('');\n const [createImageUrl, setCreateImageUrl] = useState<string | undefined>();\n const [createCountsForGrade, setCreateCountsForGrade] = useState<\n boolean | undefined\n >();\n\n // Reply modal state\n const [isReplyModalOpen, setIsReplyModalOpen] = useState(false);\n const [replyContent, setReplyContent] = useState('');\n const [replyImageUrl, setReplyImageUrl] = useState<string | undefined>();\n\n // Edit topic modal state\n const [editingTopic, setEditingTopic] = useState<ForumTopic | null>(null);\n const [editTopicContent, setEditTopicContent] = useState('');\n const [editTopicImageUrl, setEditTopicImageUrl] = useState<\n string | undefined\n >();\n\n // Edit reply modal state\n const [editingReply, setEditingReply] = useState<ForumReply | null>(null);\n const [editReplyContent, setEditReplyContent] = useState('');\n const [editReplyImageUrl, setEditReplyImageUrl] = useState<\n string | undefined\n >();\n\n // Evaluate reply modal state (teacher only)\n const [evaluatingReplyId, setEvaluatingReplyId] = useState<string | null>(\n null\n );\n const [gradeValue, setGradeValue] = useState<number | null>(null);\n const [isEditingGrade, setIsEditingGrade] = useState(false);\n\n // Delete confirmation state\n const [pendingDelete, setPendingDelete] = useState<\n { type: 'topic'; id: string } | { type: 'reply'; id: string } | null\n >(null);\n\n const fetchTopics = useCallback(async () => {\n setIsLoadingTopics(true);\n try {\n const response = await apiClient.getTopics({ limit: 50 });\n setTopics(response.topics);\n } finally {\n setIsLoadingTopics(false);\n }\n }, [apiClient]);\n\n const fetchTopic = useCallback(\n async (topicId: string) => {\n setIsLoadingTopic(true);\n try {\n const response = await apiClient.getTopic(topicId);\n setSelectedTopic(response.topic);\n setReplies(response.replies);\n } finally {\n setIsLoadingTopic(false);\n }\n },\n [apiClient]\n );\n\n useEffect(() => {\n fetchTopics();\n }, [fetchTopics]);\n\n const handleTopicClick = useCallback(\n (topic: ForumTopic) => {\n setSelectedTopic(topic);\n setView('detail');\n fetchTopic(topic.id);\n },\n [fetchTopic]\n );\n\n const handleBack = useCallback(() => {\n setView('list');\n setSelectedTopic(null);\n setReplies([]);\n fetchTopics();\n }, [fetchTopics]);\n\n // Create topic\n const handleCloseCreateModal = useCallback(() => {\n setIsCreateModalOpen(false);\n setCreateContent('');\n setCreateImageUrl(undefined);\n setCreateCountsForGrade(undefined);\n }, []);\n\n const handleCreateTopic = useCallback(async () => {\n if (!createContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.createTopic({\n content: createContent.trim(),\n ...(createImageUrl && { imageUrl: createImageUrl }),\n ...(isTeacher &&\n createCountsForGrade !== undefined && {\n countsForGrade: createCountsForGrade,\n }),\n });\n handleCloseCreateModal();\n await fetchTopics();\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n createContent,\n createImageUrl,\n createCountsForGrade,\n isTeacher,\n handleCloseCreateModal,\n fetchTopics,\n ]);\n\n // Edit topic\n const handleOpenEditTopic = useCallback((topic: ForumTopic) => {\n setEditingTopic(topic);\n setEditTopicContent(topic.content);\n setEditTopicImageUrl(topic.imageUrl ?? undefined);\n }, []);\n\n const handleCloseEditTopic = useCallback(() => {\n setEditingTopic(null);\n setEditTopicContent('');\n setEditTopicImageUrl(undefined);\n }, []);\n\n const handleEditTopic = useCallback(async () => {\n if (!editingTopic || !editTopicContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.updateTopic(editingTopic.id, {\n content: editTopicContent.trim(),\n imageUrl: editTopicImageUrl ?? null,\n });\n handleCloseEditTopic();\n if (view === 'list') {\n await fetchTopics();\n } else {\n await fetchTopic(editingTopic.id);\n }\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n editingTopic,\n editTopicContent,\n editTopicImageUrl,\n handleCloseEditTopic,\n view,\n fetchTopics,\n fetchTopic,\n ]);\n\n const handleDeleteTopic = useCallback(\n async (topicId: string) => {\n setIsSubmitting(true);\n try {\n await apiClient.deleteTopic(topicId);\n if (view === 'detail') {\n handleBack();\n } else {\n await fetchTopics();\n }\n } finally {\n setIsSubmitting(false);\n setPendingDelete(null);\n }\n },\n [apiClient, view, handleBack, fetchTopics]\n );\n\n // Reply\n const handleCloseReplyModal = useCallback(() => {\n setIsReplyModalOpen(false);\n setReplyContent('');\n setReplyImageUrl(undefined);\n }, []);\n\n const handleCreateReply = useCallback(async () => {\n if (!selectedTopic || !replyContent.trim()) return;\n setIsSubmitting(true);\n try {\n await apiClient.createReply(selectedTopic.id, {\n content: replyContent.trim(),\n ...(replyImageUrl && { imageUrl: replyImageUrl }),\n });\n handleCloseReplyModal();\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n selectedTopic,\n replyContent,\n replyImageUrl,\n handleCloseReplyModal,\n fetchTopic,\n ]);\n\n // Edit reply\n const handleOpenEditReply = useCallback((reply: ForumReply) => {\n setEditingReply(reply);\n setEditReplyContent(reply.content);\n setEditReplyImageUrl(reply.imageUrl ?? undefined);\n }, []);\n\n const handleCloseEditReply = useCallback(() => {\n setEditingReply(null);\n setEditReplyContent('');\n setEditReplyImageUrl(undefined);\n }, []);\n\n const handleEditReply = useCallback(async () => {\n if (!editingReply || !editReplyContent.trim() || !selectedTopic) return;\n setIsSubmitting(true);\n try {\n await apiClient.updateReply(editingReply.id, {\n content: editReplyContent.trim(),\n imageUrl: editReplyImageUrl ?? null,\n });\n handleCloseEditReply();\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n }\n }, [\n apiClient,\n editingReply,\n editReplyContent,\n editReplyImageUrl,\n handleCloseEditReply,\n selectedTopic,\n fetchTopic,\n ]);\n\n const handleDeleteReply = useCallback(\n async (replyId: string) => {\n if (!selectedTopic) return;\n setIsSubmitting(true);\n try {\n await apiClient.deleteReply(replyId);\n await fetchTopic(selectedTopic.id);\n } finally {\n setIsSubmitting(false);\n setPendingDelete(null);\n }\n },\n [apiClient, selectedTopic, fetchTopic]\n );\n\n const handleCloseEvaluateModal = useCallback(() => {\n setEvaluatingReplyId(null);\n setGradeValue(null);\n setIsEditingGrade(false);\n }, []);\n\n const handleOpenEvaluate = useCallback((reply: ForumReply) => {\n setEvaluatingReplyId(reply.id);\n setGradeValue(null);\n setIsEditingGrade(false);\n }, []);\n\n const handleOpenEditGrade = useCallback((reply: ForumReply) => {\n setEvaluatingReplyId(reply.id);\n setGradeValue(reply.grade ?? null);\n setIsEditingGrade(true);\n }, []);\n\n const isValidGrade =\n gradeValue !== null &&\n Number.isInteger(gradeValue) &&\n gradeValue >= 0 &&\n gradeValue <= 10;\n\n const handleSubmitEvaluation = useCallback(async () => {\n if (!evaluatingReplyId || !isValidGrade || !onEvaluateReply) return;\n setIsSubmitting(true);\n try {\n await onEvaluateReply(evaluatingReplyId, gradeValue);\n // Optimistically update grade in local state\n setReplies((prev) =>\n prev.map((r) =>\n r.id === evaluatingReplyId ? { ...r, grade: gradeValue } : r\n )\n );\n handleCloseEvaluateModal();\n } finally {\n setIsSubmitting(false);\n }\n }, [\n evaluatingReplyId,\n gradeValue,\n isValidGrade,\n onEvaluateReply,\n handleCloseEvaluateModal,\n ]);\n\n const handleConfirmDelete = useCallback(async () => {\n if (!pendingDelete) return;\n if (pendingDelete.type === 'topic') {\n await handleDeleteTopic(pendingDelete.id);\n } else {\n await handleDeleteReply(pendingDelete.id);\n }\n }, [pendingDelete, handleDeleteTopic, handleDeleteReply]);\n\n /* ---- Extracted render blocks (avoids nested ternaries — SonarQube) ---- */\n\n const topicListContent = (() => {\n if (isLoadingTopics) return <TopicListSkeleton />;\n\n if (topics.length === 0) {\n return (\n <div className=\"flex items-center justify-center py-16 border border-border-200 rounded-lg\">\n <Text size=\"md\" color=\"text-text-500\">\n Nenhum tópico ainda. Seja o primeiro a criar um post!\n </Text>\n </div>\n );\n }\n\n return (\n <div className=\"flex flex-col gap-4\">\n {topics.map((topic) => (\n <div\n key={topic.id}\n className=\"flex items-start bg-white border border-border-100 rounded-lg pt-4 pr-2 pb-4 pl-2 shadow-sm\"\n >\n {/* Clickable content area */}\n <button\n type=\"button\"\n className=\"flex flex-col gap-3 flex-1 min-w-0 text-left hover:opacity-90 transition-opacity\"\n onClick={() => handleTopicClick(topic)}\n >\n <AuthorMeta\n authorName={topic.authorName}\n authorPhoto={topic.authorPhoto}\n createdAt={topic.createdAt}\n />\n <Text size=\"sm\" className=\"leading-normal line-clamp-3 ml-10\">\n {stripHtml(topic.content)}\n </Text>\n <div className=\"flex items-center gap-1 text-text-600 ml-10\">\n <ChatCircleTextIcon size={16} />\n <Text size=\"xs\">{formatReplyCount(topic.replyCount)}</Text>\n </div>\n </button>\n\n {/* Actions menu — only for own posts */}\n {topic.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditTopic(topic)}\n onDelete={() =>\n setPendingDelete({ type: 'topic', id: topic.id })\n }\n />\n )}\n </div>\n ))}\n </div>\n );\n })();\n\n const topicDetailContent = (() => {\n if (isLoadingTopic) return <TopicDetailSkeleton />;\n\n if (!selectedTopic) return null;\n\n return (\n <>\n {/* Original post */}\n <div className=\"flex items-start gap-2\">\n <div className=\"flex flex-col gap-3 flex-1 min-w-0\">\n <AuthorMeta\n authorName={selectedTopic.authorName}\n authorPhoto={selectedTopic.authorPhoto}\n createdAt={selectedTopic.createdAt}\n />\n <div\n className=\"text-sm text-text-950 leading-normal ml-10 prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtmlForDisplay(selectedTopic.content),\n }}\n />\n {selectedTopic.imageUrl && (\n <img\n src={selectedTopic.imageUrl}\n alt=\"Imagem do post\"\n className=\"ml-10 max-w-lg rounded-lg\"\n />\n )}\n </div>\n {selectedTopic.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditTopic(selectedTopic)}\n onDelete={() =>\n setPendingDelete({ type: 'topic', id: selectedTopic.id })\n }\n />\n )}\n </div>\n\n {/* Replies header */}\n <div className=\"flex items-center justify-between\">\n <Text size=\"sm\" color=\"text-text-600\">\n {formatReplyCount(selectedTopic.replyCount)}\n </Text>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n onClick={() => setIsReplyModalOpen(true)}\n >\n Responder\n </Button>\n </div>\n\n {/* Replies list */}\n {replies.length > 0 && (\n <div className=\"flex flex-col divide-y divide-border-200\">\n {replies.map((reply) => (\n <div key={reply.id} className=\"flex items-start gap-2 py-4\">\n <div className=\"flex flex-col gap-3 flex-1 min-w-0\">\n <AuthorMeta\n authorName={reply.authorName}\n authorPhoto={reply.authorPhoto}\n createdAt={reply.createdAt}\n />\n <div\n className=\"text-sm text-text-950 leading-normal ml-10 prose prose-sm max-w-none\"\n dangerouslySetInnerHTML={{\n __html: sanitizeHtmlForDisplay(reply.content),\n }}\n />\n {reply.imageUrl && (\n <img\n src={reply.imageUrl}\n alt=\"Imagem da resposta\"\n className=\"ml-10 max-w-lg rounded-lg\"\n />\n )}\n {isTeacher &&\n selectedTopic?.countsForGrade &&\n onEvaluateReply &&\n (reply.grade == null ? (\n /* Not yet graded — show Avaliar button */\n <button\n type=\"button\"\n className=\"flex items-center gap-1.5 text-text-600 text-sm hover:text-text-950 transition-colors w-fit ml-10\"\n onClick={() => handleOpenEvaluate(reply)}\n >\n <CheckIcon size={16} />\n Avaliar\n </button>\n ) : (\n /* Grade already set — teacher sees it with edit pencil */\n <div className=\"flex items-center gap-1.5 ml-10\">\n <Text size=\"sm\" color=\"text-text-600\">\n Nota {reply.grade}\n </Text>\n <button\n type=\"button\"\n className=\"text-text-600 hover:text-text-950 transition-colors\"\n onClick={() => handleOpenEditGrade(reply)}\n >\n <PencilSimpleIcon size={14} />\n </button>\n </div>\n ))}\n {!isTeacher &&\n reply.grade != null &&\n reply.userInstitutionId === currentUserId &&\n selectedTopic?.countsForGrade && (\n <Text size=\"sm\" color=\"text-text-600\" className=\"ml-10\">\n Nota {reply.grade}\n </Text>\n )}\n </div>\n {reply.userInstitutionId === currentUserId && (\n <PostActionsMenu\n onEdit={() => handleOpenEditReply(reply)}\n onDelete={() =>\n setPendingDelete({ type: 'reply', id: reply.id })\n }\n />\n )}\n </div>\n ))}\n </div>\n )}\n </>\n );\n })();\n\n return (\n <div className={cn('flex flex-col gap-4', className)}>\n {view === 'list' ? (\n <>\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <Text as=\"h1\" size=\"2xl\" weight=\"bold\" color=\"text-text-950\">\n {title}\n </Text>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n onClick={() => setIsCreateModalOpen(true)}\n >\n Criar post\n </Button>\n </div>\n\n {/* Subtitle + topic list */}\n <div className=\"flex flex-col gap-3\">\n <Text as=\"h2\" size=\"lg\" weight=\"semibold\" color=\"text-text-950\">\n {subtitle}\n </Text>\n\n {topicListContent}\n </div>\n </>\n ) : (\n /* Detail view */\n <>\n <button\n type=\"button\"\n className=\"flex items-center gap-2 hover:opacity-80 transition-opacity w-fit\"\n onClick={handleBack}\n >\n <CaretLeftIcon size={24} className=\"text-text-950\" />\n <Text size=\"2xl\" weight=\"bold\">\n Voltar\n </Text>\n </button>\n\n {topicDetailContent}\n </>\n )}\n\n {/* Create post modal */}\n <PostContentModal\n isOpen={isCreateModalOpen}\n title=\"Criar post\"\n submitLabel=\"Criar post\"\n content={createContent}\n imageUrl={createImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setCreateContent}\n onClose={handleCloseCreateModal}\n onSubmit={handleCreateTopic}\n onUploadImage={onUploadImage}\n onImageUploaded={setCreateImageUrl}\n maxLength={10000}\n richText\n showGradeQuestion={isTeacher}\n countsForGrade={createCountsForGrade}\n onCountsForGradeChange={setCreateCountsForGrade}\n />\n\n {/* Reply modal */}\n <PostContentModal\n isOpen={isReplyModalOpen}\n title=\"Responder\"\n submitLabel=\"Responder\"\n content={replyContent}\n imageUrl={replyImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setReplyContent}\n onClose={handleCloseReplyModal}\n onSubmit={handleCreateReply}\n onUploadImage={onUploadImage}\n onImageUploaded={setReplyImageUrl}\n maxLength={5000}\n richText\n />\n\n {/* Edit topic modal */}\n <PostContentModal\n isOpen={!!editingTopic}\n title=\"Editar\"\n submitLabel=\"Salvar\"\n content={editTopicContent}\n imageUrl={editTopicImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setEditTopicContent}\n onClose={handleCloseEditTopic}\n onSubmit={handleEditTopic}\n onUploadImage={onUploadImage}\n onImageUploaded={setEditTopicImageUrl}\n maxLength={10000}\n richText\n />\n\n {/* Edit reply modal */}\n <PostContentModal\n isOpen={!!editingReply}\n title=\"Editar\"\n submitLabel=\"Salvar\"\n content={editReplyContent}\n imageUrl={editReplyImageUrl}\n isSubmitting={isSubmitting}\n onContentChange={setEditReplyContent}\n onClose={handleCloseEditReply}\n onSubmit={handleEditReply}\n onUploadImage={onUploadImage}\n onImageUploaded={setEditReplyImageUrl}\n maxLength={5000}\n richText\n />\n\n {/* Evaluate / edit grade modal (teacher only) */}\n <Modal\n isOpen={!!evaluatingReplyId}\n onClose={handleCloseEvaluateModal}\n title={\n isEditingGrade\n ? 'Edite a nota da atividade'\n : 'Defina a nota da atividade'\n }\n size=\"md\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={handleCloseEvaluateModal}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"primary\"\n size=\"medium\"\n disabled={!isValidGrade || isSubmitting}\n onClick={handleSubmitEvaluation}\n >\n {isEditingGrade ? 'Salvar' : 'Avaliar'}\n </Button>\n </div>\n }\n >\n <Input\n type=\"number\"\n min={0}\n max={10}\n step={1}\n placeholder=\"Nota (0-10)\"\n value={gradeValue ?? ''}\n onChange={(e) => {\n const val = e.target.value;\n const parsed = Number(val);\n setGradeValue(val === '' || Number.isNaN(parsed) ? null : parsed);\n }}\n />\n </Modal>\n\n {/* Delete confirmation modal */}\n <Modal\n isOpen={!!pendingDelete}\n onClose={() => setPendingDelete(null)}\n title=\"Deseja deletar post?\"\n size=\"sm\"\n footer={\n <div className=\"flex justify-end gap-2\">\n <Button\n variant=\"outline\"\n action=\"secondary\"\n size=\"medium\"\n onClick={() => setPendingDelete(null)}\n >\n Cancelar\n </Button>\n <Button\n variant=\"solid\"\n action=\"negative\"\n size=\"medium\"\n disabled={isSubmitting}\n onClick={handleConfirmDelete}\n >\n Deletar\n </Button>\n </div>\n }\n >\n <Text size=\"md\" color=\"text-text-600\">\n Essa ação é permanente e não poderá ser desfeita.\n </Text>\n </Modal>\n </div>\n );\n}\n\nexport default Forum;\n"]}
|
|
@@ -12,7 +12,7 @@ var _chunkANT66KVKjs = require('./chunk-ANT66KVK.js');
|
|
|
12
12
|
var _chunkTN3AYOMVjs = require('./chunk-TN3AYOMV.js');
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
var
|
|
15
|
+
var _chunk726PIA5Mjs = require('./chunk-726PIA5M.js');
|
|
16
16
|
|
|
17
17
|
// src/components/Quiz/TeacherQuestionComment.tsx
|
|
18
18
|
var _jsxruntime = require('react/jsx-runtime');
|
|
@@ -28,7 +28,7 @@ function getFeedbackTitle(correctionSource) {
|
|
|
28
28
|
var TeacherQuestionComment = ({
|
|
29
29
|
className
|
|
30
30
|
}) => {
|
|
31
|
-
const { variant, getCurrentQuestion, getQuestionResultByQuestionId } =
|
|
31
|
+
const { variant, getCurrentQuestion, getQuestionResultByQuestionId } = _chunk726PIA5Mjs.useQuizStore.call(void 0, );
|
|
32
32
|
if (variant !== "result" /* RESULT */) {
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
@@ -79,4 +79,4 @@ var TeacherQuestionComment_default = TeacherQuestionComment;
|
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
exports.TeacherQuestionComment = TeacherQuestionComment; exports.TeacherQuestionComment_default = TeacherQuestionComment_default;
|
|
82
|
-
//# sourceMappingURL=chunk-
|
|
82
|
+
//# sourceMappingURL=chunk-JPQI2RIV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-JPQI2RIV.js","../src/components/Quiz/TeacherQuestionComment.tsx"],"names":[],"mappings":"AAAA;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACE;AACF,sDAA4B;AAC5B;AACA;AC8FM,+CAAA;AArFN,SAAS,gBAAA,CAAiB,gBAAA,EAAqD;AAC7E,EAAA,GAAA,CAAI,iBAAA,IAAA,aAAA,EAA2C;AAC7C,IAAA,OAAO,uBAAA;AAAA,EACT;AAEA,EAAA,GAAA,CAAI,iBAAA,IAAA,iCAAA,EAAqD;AACvD,IAAA,OAAO,wCAAA;AAAA,EACT;AAEA,EAAA,OAAO,4BAAA;AACT;AAkCO,IAAM,uBAAA,EAAyB,CAAC;AAAA,EACrC;AACF,CAAA,EAAA,GAAmC;AACjC,EAAA,MAAM,EAAE,OAAA,EAAS,kBAAA,EAAoB,8BAA8B,EAAA,EACjE,2CAAA,CAAa;AAEf,EAAA,GAAA,CAAI,QAAA,IAAA,qBAAA,EAAgC;AAClC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,gBAAA,EAAkB,kBAAA,CAAmB,CAAA;AAC3C,EAAA,GAAA,CAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAA,EAAS,6BAAA,CAA8B,eAAA,CAAgB,EAAE,CAAA;AAC/D,EAAA,GAAA,CAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,EAAE,eAAA,EAAiB,UAAA,EAAY,kBAAA,EAAoB,iBAAiB,EAAA,EACxE,MAAA;AAEF,EAAA,MAAM,QAAA,EAAU,oDAAA;AAAsB,IACpC,eAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,EACF,CAAC,CAAA;AACD,EAAA,MAAM,aAAA,EAAe,mBAAA,IAAA,uBAAA;AAErB,EAAA,GAAA,CAAI,CAAC,QAAA,GAAW,CAAC,YAAA,EAAc;AAC7B,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,uBACE,8BAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,iCAAA;AAAA,QACT,4DAAA;AAAA,QACA;AAAA,MACF,CAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,8BAAA,KAAC,EAAA,EAAI,SAAA,EAAU,wCAAA,EACZ,QAAA,EAAA;AAAA,UAAA,QAAA,mBACC,6BAAA,6BAAC,EAAA,EAAK,SAAA,EAAU,iCAAA,EACb,QAAA,EAAA,gBAAA,CAAiB,gBAAgB,EAAA,CACpC,CAAA;AAAA,0BAEF,6BAAA;AAAA,YAAC,4CAAA;AAAA,YAAA;AAAA,cACC,gBAAA;AAAA,cACA;AAAA,YAAA;AAAA,UACF;AAAA,QAAA,EAAA,CACF,CAAA;AAAA,QAEC,QAAA,kBACC,6BAAA,6BAAC,EAAA,EAAK,IAAA,EAAK,IAAA,EAAK,SAAA,EAAU,mCAAA,EACvB,QAAA,EAAA,QAAA,CACH,EAAA,kBAEA,6BAAA,6BAAC,EAAA,EAAK,IAAA,EAAK,IAAA,EAAK,SAAA,EAAU,eAAA,EAAgB,QAAA,EAAA,8EAAA,CAG1C;AAAA,MAAA;AAAA,IAAA;AAAA,EAEJ,CAAA;AAEJ,CAAA;AAEA,IAAO,+BAAA,EAAQ,sBAAA;AD5Df;AACA;AACE;AACA;AACF,iIAAC","file":"/home/runner/work/analytica-frontend-lib/analytica-frontend-lib/dist/chunk-JPQI2RIV.js","sourcesContent":[null,"import { cn } from '../../utils/utils';\nimport Text from '../Text/Text';\nimport {\n AI_CORRECTION_STATUS,\n CORRECTION_SOURCE,\n useQuizStore,\n} from './useQuizStore';\nimport { QuizVariant } from './Quiz.types';\nimport CorrectionSourceTag from './CorrectionSourceTag';\nimport { resolveCorrectionText } from './correction.utils';\n\nexport interface TeacherQuestionCommentProps {\n readonly className?: string;\n}\n\n/**\n * Heading above the feedback, phrased for whoever actually wrote it.\n *\n * Attributing an AI correction to \"o professor\" would be a lie the tag right\n * next to it immediately contradicts, so the two are derived from the same\n * `correctionSource`.\n *\n * @param correctionSource - Who produced the correction\n * @returns The heading to display\n */\nfunction getFeedbackTitle(correctionSource?: CORRECTION_SOURCE | null): 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 * Feedback on the question currently under review.\n *\n * Distinct from `TeacherFeedbackSection`, which shows the single observation the\n * teacher wrote for the activity as a whole: this one is per question and sits\n * right below its alternatives, which is where the explanation of a specific\n * mistake belongs.\n *\n * For a dissertative answer the text can come from either of two places. The\n * teacher's own words win when they exist; otherwise the AI's stand. They are\n * never merged — the backend keeps them in separate columns precisely so a\n * review does not destroy the original verdict — and the tag says which one is\n * on screen.\n *\n * It also renders while there is nothing to show yet: an answer whose AI\n * correction is still running gets the \"Corrigindo com IA\" tag on its own, so\n * the student who lands here right after submitting sees that feedback is\n * coming rather than an empty space.\n *\n * Renders nothing outside the result variant, or when the question has neither\n * feedback nor a correction under way.\n *\n * @param props - Component props\n * @returns JSX element or null\n *\n * @example\n * ```tsx\n * <Quiz variant=\"result\">\n * <QuizContent />\n * </Quiz>\n * ```\n */\nexport const TeacherQuestionComment = ({\n className,\n}: TeacherQuestionCommentProps) => {\n const { variant, getCurrentQuestion, getQuestionResultByQuestionId } =\n useQuizStore();\n\n if (variant !== QuizVariant.RESULT) {\n return null;\n }\n\n const currentQuestion = getCurrentQuestion();\n if (!currentQuestion) {\n return null;\n }\n\n const result = getQuestionResultByQuestionId(currentQuestion.id);\n if (!result) {\n return null;\n }\n\n const { teacherFeedback, aiFeedback, aiCorrectionStatus, correctionSource } =\n result;\n\n const comment = resolveCorrectionText({\n teacherFeedback,\n aiFeedback,\n correctionSource,\n });\n const isCorrecting = aiCorrectionStatus === AI_CORRECTION_STATUS.PENDING;\n\n if (!comment && !isCorrecting) {\n return null;\n }\n\n return (\n <div\n className={cn(\n 'bg-background border border-border-100 rounded-lg p-4 mt-4',\n className\n )}\n >\n <div className=\"flex flex-wrap items-center gap-2 mb-2\">\n {comment && (\n <Text className=\"text-sm font-bold text-text-950\">\n {getFeedbackTitle(correctionSource)}\n </Text>\n )}\n <CorrectionSourceTag\n correctionSource={correctionSource}\n aiCorrectionStatus={aiCorrectionStatus}\n />\n </div>\n\n {comment ? (\n <Text size=\"sm\" className=\"text-text-700 whitespace-pre-wrap\">\n {comment}\n </Text>\n ) : (\n <Text size=\"sm\" className=\"text-text-600\">\n Sua resposta está sendo corrigida. O feedback aparece aqui em\n instantes.\n </Text>\n )}\n </div>\n );\n};\n\nexport default TeacherQuestionComment;\n"]}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-WKILJIST.mjs";
|
|
10
10
|
import {
|
|
11
11
|
useQuizStore
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-MOSP7FR5.mjs";
|
|
13
13
|
|
|
14
14
|
// src/components/QuizTimer/QuizTimer.tsx
|
|
15
15
|
import { ClockIcon } from "@phosphor-icons/react/dist/csr/Clock";
|
|
@@ -48,4 +48,4 @@ var QuizTimer_default = QuizTimer;
|
|
|
48
48
|
export {
|
|
49
49
|
QuizTimer_default
|
|
50
50
|
};
|
|
51
|
-
//# sourceMappingURL=chunk-
|
|
51
|
+
//# sourceMappingURL=chunk-LMDAF6LA.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Quiz/useQuizStore.ts"],"sourcesContent":["import { create } from 'zustand';\nimport { devtools } from 'zustand/middleware';\nimport { QuizVariant } from './Quiz.types';\n\nexport enum QUESTION_DIFFICULTY {\n FACIL = 'FACIL',\n MEDIO = 'MEDIO',\n DIFICIL = 'DIFICIL',\n}\n\n// Enum para tipos de quiz\nexport enum QUIZ_TYPE {\n SIMULADO = 'SIMULADO',\n QUESTIONARIO = 'QUESTIONARIO',\n ATIVIDADE = 'ATIVIDADE',\n AULA_RECOMENDADA = 'AULA_RECOMENDADA',\n}\n\nexport enum QUESTION_TYPE {\n ALTERNATIVA = 'ALTERNATIVA',\n DISSERTATIVA = 'DISSERTATIVA',\n MULTIPLA_ESCOLHA = 'MULTIPLA_ESCOLHA',\n VERDADEIRO_FALSO = 'VERDADEIRO_FALSO',\n RELACIONAR = 'RELACIONAR',\n PREENCHER_LACUNAS = 'PREENCHER_LACUNAS',\n IMAGEM = 'IMAGEM',\n}\n\n/**\n * Determines if a user answer has meaningful content.\n * For option-based questions: checks if optionId is not null\n * For multiple choice questions: checks if selectedOptionIds has items\n * For free-text questions (DISSERTATIVA): checks if answer is non-empty string\n * For structured questions (RELACIONAR, PREENCHER_LACUNAS): checks if answer is valid JSON with values\n *\n * @param answer - The user answer item to check (can be null/undefined)\n * @returns true if the answer has meaningful content, false otherwise\n */\nexport const hasMeaningfulAnswer = (\n answer:\n | {\n optionId: string | null;\n answer: string | null;\n questionType: QUESTION_TYPE;\n selectedOptionIds?: string[] | null;\n }\n | null\n | undefined\n): boolean => {\n if (!answer) return false;\n\n // For MULTIPLA_ESCOLHA, check selectedOptionIds array or legacy optionId\n if (answer.questionType === QUESTION_TYPE.MULTIPLA_ESCOLHA) {\n return (\n (Array.isArray(answer.selectedOptionIds) &&\n answer.selectedOptionIds.length > 0) ||\n Boolean(answer.optionId)\n );\n }\n\n // For free-text question types, check the answer field\n const freeTextTypes = [\n QUESTION_TYPE.DISSERTATIVA,\n QUESTION_TYPE.RELACIONAR,\n QUESTION_TYPE.PREENCHER_LACUNAS,\n QUESTION_TYPE.IMAGEM,\n QUESTION_TYPE.VERDADEIRO_FALSO,\n ];\n\n if (freeTextTypes.includes(answer.questionType)) {\n // Check if answer has content (non-empty string)\n if (!answer.answer || answer.answer.trim() === '') return false;\n\n // For RELACIONAR/PREENCHER_LACUNAS/VERDADEIRO_FALSO, also check if JSON has actual values\n if (\n answer.questionType === QUESTION_TYPE.RELACIONAR ||\n answer.questionType === QUESTION_TYPE.PREENCHER_LACUNAS ||\n answer.questionType === QUESTION_TYPE.VERDADEIRO_FALSO\n ) {\n try {\n const parsed = JSON.parse(answer.answer);\n return typeof parsed === 'object' && Object.keys(parsed).length > 0;\n } catch {\n return false;\n }\n }\n\n // For DISSERTATIVA, non-empty string is meaningful\n return true;\n }\n\n // For option-based question types, check optionId (not null and not empty string)\n return answer.optionId !== null && answer.optionId !== '';\n};\n\nexport enum QUESTION_STATUS {\n PENDENTE_AVALIACAO = 'PENDENTE_AVALIACAO',\n RESPOSTA_CORRETA = 'RESPOSTA_CORRETA',\n RESPOSTA_INCORRETA = 'RESPOSTA_INCORRETA',\n NAO_RESPONDIDO = 'NAO_RESPONDIDO',\n}\n\nexport enum ANSWER_STATUS {\n RESPOSTA_CORRETA = 'RESPOSTA_CORRETA',\n RESPOSTA_INCORRETA = 'RESPOSTA_INCORRETA',\n PENDENTE_AVALIACAO = 'PENDENTE_AVALIACAO',\n NAO_RESPONDIDO = 'NAO_RESPONDIDO',\n}\n\n/**\n * Who produced the correction stored on a dissertative answer.\n *\n * Drives the tag shown next to the feedback. `IA_PROFESSOR` is not a third kind\n * of correction — it is an AI correction a teacher has since reviewed.\n */\nexport enum CORRECTION_SOURCE {\n /** Corrected by the AI, not yet reviewed by a teacher. */\n IA = 'IA',\n /** Corrected by the AI and afterwards reviewed by a teacher. */\n IA_PROFESSOR = 'IA_PROFESSOR',\n /** Corrected by a teacher, with no AI involvement. */\n PROFESSOR = 'PROFESSOR',\n}\n\n/**\n * Lifecycle of the asynchronous AI correction of a dissertative answer.\n *\n * `null` on an answer means the AI was never in play for it — the institution\n * has the feature off — which reads differently from `FAILED`: the first waits\n * on a teacher, the second fell back to waiting on one.\n */\nexport enum AI_CORRECTION_STATUS {\n /** Submitted; the AI correction is still running. */\n PENDING = 'PENDING',\n /** The AI returned a verdict. */\n DONE = 'DONE',\n /** The AI call failed; the answer awaits manual correction. */\n FAILED = 'FAILED',\n}\n\nexport enum SUBTYPE_ENUM {\n PROVA = 'PROVA',\n ENEM_PROVA_1 = 'ENEM_PROVA_1',\n ENEM_PROVA_2 = 'ENEM_PROVA_2',\n VESTIBULAR = 'VESTIBULAR',\n SIMULADO = 'SIMULADO',\n SIMULADAO = 'SIMULADAO',\n}\n\nexport interface QuestionResult {\n answers: {\n id: string;\n questionId: string;\n answer: string | null;\n selectedOptions: {\n optionId: string;\n option?: string;\n isCorrect?: boolean;\n correctValue?: string | null;\n }[];\n answerStatus: ANSWER_STATUS;\n statement: string;\n additionalContent: string | null;\n questionType: QUESTION_TYPE;\n difficultyLevel: QUESTION_DIFFICULTY;\n solutionExplanation: string | null;\n correctOption: string;\n createdAt: string;\n updatedAt: string;\n options?: {\n id: string;\n option: string;\n isCorrect: boolean;\n correctValue?: string | null;\n }[];\n matchingAnswers?: {\n optionId: string;\n selectedValue: string;\n }[];\n fillAnswers?: Record<string, string>;\n knowledgeMatrix: {\n areaKnowledge: {\n id: string;\n name: string;\n } | null;\n subject: {\n id: string;\n name: string;\n color: string;\n icon: string;\n } | null;\n topic: {\n id: string;\n name: string;\n } | null;\n subtopic: {\n id: string;\n name: string;\n } | null;\n content: {\n id: string;\n name: string;\n } | null;\n }[];\n teacherFeedback: string | null;\n /**\n * DISSERTATIVA only: what the AI wrote, kept apart from `teacherFeedback`\n * so a teacher's review never destroys the original verdict. The feedback\n * to render is `teacherFeedback ?? aiFeedback`; `correctionSource` says\n * which of the two produced it.\n */\n aiFeedback?: string | null;\n /** DISSERTATIVA only: the AI's original verdict, before any teacher review. */\n aiIsCorrect?: boolean | null;\n /** DISSERTATIVA only: whether the AI correction is running, done or failed. */\n aiCorrectionStatus?: AI_CORRECTION_STATUS | null;\n /** DISSERTATIVA only: drives the correction tag. */\n correctionSource?: CORRECTION_SOURCE | null;\n /** IMAGEM only: where the student clicked, in image percentage points. */\n imageAnswer?: { coordinateX: number; coordinateY: number } | null;\n /**\n * IMAGEM only: radius within which a click counts as correct, in the same\n * percentage space. Sent by the backend so the drawn target circle matches\n * the grade instead of each client inventing its own.\n */\n imageTolerance?: number | null;\n attachment: string | null;\n score: number | null;\n gradedAt: string | null;\n gradedBy: string | null;\n }[];\n statistics: {\n totalAnswered: number;\n correctAnswers: number;\n incorrectAnswers: number;\n pendingAnswers: number;\n score: number;\n timeSpent: number;\n };\n}\n\nexport interface Question {\n id: string;\n statement: string;\n questionType: QUESTION_TYPE;\n difficultyLevel: QUESTION_DIFFICULTY;\n description: string;\n examBoard: string | null;\n examYear: string | null;\n solutionExplanation: string | null;\n additionalContent: string | null;\n answer: null;\n answerStatus: ANSWER_STATUS;\n options: {\n id: string;\n option: string;\n correctValue?: string | null;\n }[];\n knowledgeMatrix: {\n areaKnowledge: {\n id: string;\n name: string;\n };\n subject: {\n id: string;\n name: string;\n color: string;\n icon: string;\n };\n topic: {\n id: string;\n name: string;\n };\n subtopic: {\n id: string;\n name: string;\n };\n content: {\n id: string;\n name: string;\n };\n }[];\n correctOptionIds?: string[];\n}\n\nexport interface QuizInterface {\n id: string;\n title: string;\n type: QUIZ_TYPE;\n subtype: SUBTYPE_ENUM | string;\n difficulty: string | null;\n notification: string | null;\n status: string;\n startDate: string | null;\n finalDate: string | null;\n canRetry: boolean;\n createdAt: string | null;\n updatedAt: string | null;\n questions: Question[];\n /**\n * Shows the exam board and year on every question, as a SIMULADO does.\n * For a quiz of another type that is made of exam questions — the ENEM\n * in the classroom runs as an ATIVIDADE for its endpoints' sake.\n */\n showExamInfo?: boolean;\n}\n\nexport interface UserAnswerItem {\n questionId: string;\n activityId: string;\n userId: string;\n answer: string | null;\n optionId: string | null;\n selectedOptionIds?: string[] | null;\n questionType: QUESTION_TYPE;\n answerStatus: ANSWER_STATUS;\n}\n\n/**\n * Draft answer item from the backend API\n * Used when loading saved drafts\n */\nexport interface DraftAnswerItem {\n questionId: string;\n answer: string | null;\n optionId: string | null;\n selectedOptionIds?: string[] | null;\n fillAnswers?: Record<string, string> | null;\n matchingAnswers?: Array<{ optionId: string; selectedValue: string }> | null;\n imageAnswer?: { coordinateX: number; coordinateY: number } | null;\n sequence?: number;\n timeSpent?: number;\n}\n\n/**\n * Payload for saving drafts to the backend\n */\nexport interface SaveDraftPayload {\n answers: Array<{\n questionId: string;\n answer?: string | null;\n optionId?: string | null;\n selectedOptionIds?: string[] | null;\n fillAnswers?: Record<string, string> | null;\n matchingAnswers?: Array<{ optionId: string; selectedValue: string }> | null;\n imageAnswer?: { coordinateX: number; coordinateY: number } | null;\n }>;\n}\n\n/**\n * API client interface for draft operations\n * Pass this to the store to enable auto-save functionality\n */\nexport interface DraftApiClient {\n /**\n * Persists the draft.\n *\n * `activityGone` reports that the activity no longer exists — the backend\n * answers 404 for it. The store uses that to stop autosaving instead of\n * retrying a request that can never succeed.\n */\n saveDraft: (\n activityId: string,\n payload: SaveDraftPayload\n ) => Promise<{ success: boolean; activityGone?: boolean }>;\n loadDraft: (activityId: string) => Promise<{\n hasDraft: boolean;\n answers: DraftAnswerItem[];\n } | null>;\n}\n\nexport interface QuizState {\n // Data\n quiz: QuizInterface | null;\n\n // UI State\n currentQuestionIndex: number;\n selectedAnswers: Record<string, string>;\n userAnswers: UserAnswerItem[];\n timeElapsed: number;\n isStarted: boolean;\n isFinished: boolean;\n userId: string;\n variant: QuizVariant;\n minuteCallback: (() => void) | null;\n dissertativeCharLimit?: number;\n timeLimit: number | null;\n onTimeUp: (() => void) | null;\n timeWarningThreshold: number | null;\n onTimeWarning: (() => void) | null;\n hasTimeWarningFired: boolean;\n // Actions\n setQuiz: (quiz: QuizInterface) => void;\n setQuestionResult: (questionResult: QuestionResult) => void;\n setUserId: (userId: string) => void;\n setUserAnswers: (userAnswers: UserAnswerItem[]) => void;\n setVariant: (variant: QuizVariant) => void;\n setDissertativeCharLimit: (limit?: number) => void;\n getDissertativeCharLimit: () => number | undefined;\n // Quiz Navigation\n goToNextQuestion: () => void;\n goToPreviousQuestion: () => void;\n goToQuestion: (index: number) => void;\n\n // Quiz Actions\n selectAnswer: (questionId: string, answerId: string) => void;\n selectMultipleAnswer: (questionId: string, answerIds: string[]) => void;\n selectDissertativeAnswer: (questionId: string, answer: string) => void;\n skipQuestion: () => void;\n skipCurrentQuestionIfUnanswered: () => void;\n addUserAnswer: (questionId: string, answerId?: string) => void;\n startQuiz: (options?: { initialElapsedSeconds?: number }) => void;\n finishQuiz: () => void;\n resetQuiz: () => void;\n\n // Timer\n updateTime: (time: number) => void;\n startTimer: () => void;\n stopTimer: () => void;\n setTimeLimit: (seconds: number | null) => void;\n setOnTimeUp: (callback: (() => void) | null) => void;\n getRemainingTime: () => number | null;\n setTimeWarning: (\n seconds: number | null,\n callback?: (() => void) | null\n ) => void;\n isTimeExceeded: () => boolean;\n\n // Minute Callback\n setMinuteCallback: (callback: (() => void) | null) => void;\n startMinuteCallback: () => void;\n stopMinuteCallback: () => void;\n\n // Getters\n getCurrentQuestion: () => Question | null;\n getTotalQuestions: () => number;\n getAnsweredQuestions: () => number;\n getUnansweredQuestions: () => number[];\n getSkippedQuestions: () => number;\n getProgress: () => number;\n isQuestionAnswered: (questionId: string) => boolean;\n isQuestionSkipped: (questionId: string) => boolean;\n getCurrentAnswer: () => UserAnswerItem | undefined;\n getAllCurrentAnswer: () => UserAnswerItem[] | undefined;\n getQuizTitle: () => string;\n formatTime: (seconds: number) => string;\n getUserAnswers: () => UserAnswerItem[];\n getUnansweredQuestionsFromUserAnswers: () => number[];\n getQuestionsGroupedBySubject: () => {\n [key: string]: (Question | QuestionResult['answers'][number])[];\n };\n getUserId: () => string;\n setCurrentQuestion: (question: Question) => void;\n\n // New methods for userAnswers\n getQuestionIndex: (questionId: string) => number;\n getUserAnswerByQuestionId: (questionId: string) => UserAnswerItem | null;\n isQuestionAnsweredByUserAnswers: (questionId: string) => boolean;\n getQuestionStatusFromUserAnswers: (\n questionId: string\n ) => 'answered' | 'unanswered' | 'skipped';\n getUserAnswersForActivity: () => UserAnswerItem[];\n // Answer status management\n setAnswerStatus: (questionId: string, status: ANSWER_STATUS) => void;\n getAnswerStatus: (questionId: string) => ANSWER_STATUS | null;\n\n // Question Result\n questionsResult: QuestionResult | null;\n currentQuestionResult: QuestionResult['answers'] | null;\n setQuestionsResult: (questionsResult: QuestionResult) => void;\n setCurrentQuestionResult: (\n currentQuestionResult: QuestionResult['answers']\n ) => void;\n getQuestionResultByQuestionId: (\n questionId: string\n ) => QuestionResult['answers'][number] | null;\n getQuestionResultStatistics: () => QuestionResult['statistics'] | null;\n getQuestionResult: () => QuestionResult | null;\n getCurrentQuestionResult: () => QuestionResult['answers'] | null;\n\n // Draft management\n applyDraftAnswers: (draftAnswers: DraftAnswerItem[]) => void;\n prepareDraftPayload: () => SaveDraftPayload;\n hasDraftChanges: () => boolean;\n\n // Draft API client (for auto-save functionality)\n draftApiClient: DraftApiClient | null;\n setDraftApiClient: (client: DraftApiClient | null) => void;\n saveDraft: () => Promise<void>;\n loadAndApplyDraft: () => Promise<void>;\n\n // Internal refs for draft management (not exposed, but tracked in state for reactivity)\n lastSavedDraftPayload: string;\n isSavingDraft: boolean;\n /**\n * Set once the backend reports the activity no longer exists. Autosave stops\n * for the rest of the session: `lastSavedDraftPayload` only advances on\n * success, so without this every question navigation and every\n * `visibilitychange` resends the same doomed payload — one student produced\n * 160 such requests in a day.\n */\n isDraftUnavailable: boolean;\n\n // Activity-level teacher feedback (general observation)\n activityFeedback: {\n teacherFeedback: string | null;\n attachment: string | null;\n } | null;\n setActivityFeedback: (\n feedback: {\n teacherFeedback: string | null;\n attachment: string | null;\n } | null\n ) => void;\n getActivityFeedback: () => {\n teacherFeedback: string | null;\n attachment: string | null;\n } | null;\n}\n\n// Constants\nexport const MINUTE_INTERVAL_MS = 60000; // 60 seconds = 1 minute\n\nexport const useQuizStore = create<QuizState>()(\n devtools(\n (set, get) => {\n let timerInterval: ReturnType<typeof setInterval> | null = null;\n let minuteCallbackInterval: ReturnType<typeof setInterval> | null = null;\n let timerStartedAt: number | null = null;\n let timerBaseElapsed = 0;\n\n const clampElapsed = (elapsed: number) => {\n const { timeLimit } = get();\n return timeLimit === null ? elapsed : Math.min(elapsed, timeLimit);\n };\n\n const handleVisibilityChange = () => {\n if (document.visibilityState === 'visible' && timerStartedAt !== null) {\n const now = Date.now();\n const elapsed = clampElapsed(\n timerBaseElapsed + Math.floor((now - timerStartedAt) / 1000)\n );\n set({ timeElapsed: elapsed });\n checkTimeThresholds(elapsed);\n }\n };\n\n /**\n * Soft threshold: notifies once and lets the clock keep running.\n *\n * Deliberately separate from `timeLimit` below, which is a hard stop that\n * submits the quiz. A progressive exam timer needs the opposite — the\n * student is told they went over the expected duration and carries on.\n */\n const checkTimeWarning = (elapsed: number) => {\n const { timeWarningThreshold, hasTimeWarningFired, onTimeWarning } =\n get();\n\n if (\n timeWarningThreshold !== null &&\n elapsed >= timeWarningThreshold &&\n !hasTimeWarningFired\n ) {\n set({ hasTimeWarningFired: true });\n onTimeWarning?.();\n }\n };\n\n const checkTimeThresholds = (elapsed: number) => {\n checkTimeWarning(elapsed);\n\n const { timeLimit, isFinished, onTimeUp } = get();\n if (timeLimit !== null && elapsed >= timeLimit && !isFinished) {\n get().finishQuiz();\n onTimeUp?.();\n }\n };\n\n const startTimer = () => {\n if (get().isFinished) {\n return;\n }\n\n if (timerInterval) {\n clearInterval(timerInterval);\n }\n\n timerStartedAt = Date.now();\n timerBaseElapsed = get().timeElapsed;\n\n document.addEventListener('visibilitychange', handleVisibilityChange);\n\n timerInterval = setInterval(() => {\n if (timerStartedAt === null) return;\n const now = Date.now();\n const elapsed = clampElapsed(\n timerBaseElapsed + Math.floor((now - timerStartedAt) / 1000)\n );\n set({ timeElapsed: elapsed });\n checkTimeThresholds(elapsed);\n }, 1000);\n };\n\n const stopTimer = () => {\n if (timerInterval) {\n clearInterval(timerInterval);\n timerInterval = null;\n }\n timerStartedAt = null;\n timerBaseElapsed = 0;\n document.removeEventListener(\n 'visibilitychange',\n handleVisibilityChange\n );\n };\n\n const setMinuteCallback = (callback: (() => void) | null) => {\n set({ minuteCallback: callback });\n };\n\n const startMinuteCallback = () => {\n const { minuteCallback, isFinished } = get();\n\n if (isFinished || !minuteCallback) {\n return;\n }\n\n if (minuteCallbackInterval) {\n clearInterval(minuteCallbackInterval);\n }\n\n minuteCallbackInterval = setInterval(() => {\n const {\n minuteCallback: currentCallback,\n isFinished: currentIsFinished,\n } = get();\n\n if (currentIsFinished || !currentCallback) {\n stopMinuteCallback();\n return;\n }\n\n currentCallback();\n }, MINUTE_INTERVAL_MS);\n };\n\n const stopMinuteCallback = () => {\n if (minuteCallbackInterval) {\n clearInterval(minuteCallbackInterval);\n minuteCallbackInterval = null;\n }\n };\n\n return {\n // Initial State\n quiz: null,\n currentQuestionIndex: 0,\n selectedAnswers: {},\n userAnswers: [],\n timeElapsed: 0,\n isStarted: false,\n isFinished: false,\n userId: '',\n variant: QuizVariant.DEFAULT,\n minuteCallback: null,\n dissertativeCharLimit: undefined,\n timeLimit: null,\n onTimeUp: null,\n timeWarningThreshold: null,\n onTimeWarning: null,\n hasTimeWarningFired: false,\n questionsResult: null,\n currentQuestionResult: null,\n draftApiClient: null,\n lastSavedDraftPayload: '',\n isSavingDraft: false,\n isDraftUnavailable: false,\n activityFeedback: null,\n // Setters\n setQuiz: (quiz) => set({ quiz }),\n setUserId: (userId) => set({ userId }),\n setUserAnswers: (userAnswers) => set({ userAnswers }),\n getUserId: () => get().userId,\n setVariant: (variant) => set({ variant }),\n setQuestionResult: (questionsResult) => set({ questionsResult }),\n setDissertativeCharLimit: (limit?: number) =>\n set({ dissertativeCharLimit: limit }),\n getDissertativeCharLimit: () => get().dissertativeCharLimit,\n setDraftApiClient: (client) => set({ draftApiClient: client }),\n\n // Draft save - called automatically on navigation\n saveDraft: async () => {\n const {\n draftApiClient,\n quiz,\n hasDraftChanges,\n prepareDraftPayload,\n lastSavedDraftPayload,\n isSavingDraft,\n isDraftUnavailable,\n } = get();\n\n // Skip if no API client configured or no quiz\n if (!draftApiClient || !quiz) return;\n\n // The activity is gone; there is nothing to save into.\n if (isDraftUnavailable) return;\n\n // Skip if already saving\n if (isSavingDraft) return;\n\n // Skip if no changes\n if (!hasDraftChanges()) return;\n\n const payload = prepareDraftPayload();\n const payloadString = JSON.stringify(payload);\n\n // Skip if payload hasn't changed\n if (payloadString === lastSavedDraftPayload) return;\n\n try {\n set({ isSavingDraft: true });\n const result = await draftApiClient.saveDraft(quiz.id, payload);\n\n if (result?.activityGone) {\n set({ isDraftUnavailable: true });\n return;\n }\n\n set({ lastSavedDraftPayload: payloadString });\n } catch (error) {\n // Silent fail - don't interrupt user experience\n console.warn('Erro ao salvar rascunho:', error);\n } finally {\n set({ isSavingDraft: false });\n }\n },\n\n // Load draft and apply to quiz, navigate to first unanswered question\n loadAndApplyDraft: async () => {\n const {\n draftApiClient,\n quiz,\n applyDraftAnswers,\n prepareDraftPayload,\n } = get();\n\n // Skip if no API client configured or no quiz\n if (!draftApiClient || !quiz) return;\n\n try {\n const draftData = await draftApiClient.loadDraft(quiz.id);\n\n if (draftData?.hasDraft && draftData.answers?.length > 0) {\n applyDraftAnswers(draftData.answers);\n\n // Update last saved payload to prevent immediate re-save\n const payload = prepareDraftPayload();\n set({ lastSavedDraftPayload: JSON.stringify(payload) });\n\n // Navigate to first unanswered question\n const questions = get().quiz?.questions || [];\n const updatedAnswers = get().userAnswers;\n\n const firstUnansweredIndex = questions.findIndex((question) => {\n const answer = updatedAnswers.find(\n (a) => a.questionId === question.id\n );\n if (!answer) return true;\n if (answer.optionId) return false;\n if (\n answer.selectedOptionIds &&\n answer.selectedOptionIds.length > 0\n )\n return false;\n if (answer.answer && answer.answer.trim() !== '') return false;\n return true;\n });\n\n if (firstUnansweredIndex > 0) {\n // Navigate without triggering save (internal navigation)\n set({ currentQuestionIndex: firstUnansweredIndex });\n }\n }\n } catch (error) {\n // Silent fail - user can continue fresh\n console.warn('Erro ao carregar rascunho:', error);\n }\n },\n\n // Navigation\n goToNextQuestion: () => {\n const { currentQuestionIndex, getTotalQuestions, saveDraft } = get();\n const totalQuestions = getTotalQuestions();\n\n if (currentQuestionIndex < totalQuestions - 1) {\n // Save draft before navigating\n saveDraft();\n set({ currentQuestionIndex: currentQuestionIndex + 1 });\n }\n },\n\n goToPreviousQuestion: () => {\n const { currentQuestionIndex, saveDraft } = get();\n\n if (currentQuestionIndex > 0) {\n // Save draft before navigating\n saveDraft();\n set({ currentQuestionIndex: currentQuestionIndex - 1 });\n }\n },\n\n goToQuestion: (index) => {\n const { getTotalQuestions, currentQuestionIndex, saveDraft } = get();\n const totalQuestions = getTotalQuestions();\n\n if (\n index >= 0 &&\n index < totalQuestions &&\n index !== currentQuestionIndex\n ) {\n // Save draft before navigating\n saveDraft();\n set({ currentQuestionIndex: index });\n }\n },\n\n selectAnswer: (questionId, answerId) => {\n const { quiz, userAnswers } = get();\n\n if (!quiz) return;\n\n const activityId = quiz.id;\n const userId = get().getUserId();\n\n if (!userId || userId === '') {\n // Silent validation - userId not set\n return;\n }\n\n const question = quiz.questions.find((q) => q.id === questionId);\n if (!question) return;\n\n const existingAnswerIndex = userAnswers.findIndex(\n (answer) => answer.questionId === questionId\n );\n\n const newUserAnswer: UserAnswerItem = {\n questionId,\n activityId,\n userId,\n answer:\n question.questionType === QUESTION_TYPE.DISSERTATIVA\n ? answerId\n : null,\n optionId:\n question.questionType === QUESTION_TYPE.DISSERTATIVA\n ? null\n : answerId,\n questionType: question.questionType,\n answerStatus: ANSWER_STATUS.PENDENTE_AVALIACAO,\n };\n\n let updatedUserAnswers;\n if (existingAnswerIndex !== -1) {\n updatedUserAnswers = [...userAnswers];\n updatedUserAnswers[existingAnswerIndex] = newUserAnswer;\n } else {\n updatedUserAnswers = [...userAnswers, newUserAnswer];\n }\n\n set({\n userAnswers: updatedUserAnswers,\n });\n },\n\n selectMultipleAnswer: (questionId, answerIds) => {\n const { quiz, userAnswers } = get();\n\n if (!quiz) return;\n\n const activityId = quiz.id;\n const userId = get().getUserId();\n\n if (!userId || userId === '') {\n // Silent validation - userId not set\n return;\n }\n\n const question = quiz.questions.find((q) => q.id === questionId);\n if (!question) return;\n\n // Remove all existing answers for this questionId\n const filteredUserAnswers = userAnswers.filter(\n (answer) => answer.questionId !== questionId\n );\n\n // Don't persist empty MULTIPLA_ESCOLHA answers\n if (answerIds.length === 0) {\n set({\n userAnswers: filteredUserAnswers,\n });\n return;\n }\n\n // Create a single UserAnswerItem with selectedOptionIds array\n // This matches the backend API expected format for MULTIPLA_ESCOLHA\n // Also set optionId to first selection for backward compatibility\n const newUserAnswer: UserAnswerItem = {\n questionId,\n activityId,\n userId,\n answer: null,\n optionId: answerIds.length > 0 ? answerIds[0] : null,\n selectedOptionIds: answerIds,\n questionType: question.questionType,\n answerStatus: ANSWER_STATUS.PENDENTE_AVALIACAO,\n };\n\n const updatedUserAnswers = [...filteredUserAnswers, newUserAnswer];\n\n set({\n userAnswers: updatedUserAnswers,\n });\n },\n\n selectDissertativeAnswer: (questionId, answer) => {\n const { quiz, userAnswers, dissertativeCharLimit } = get();\n\n if (!quiz) return;\n\n const activityId = quiz.id;\n const userId = get().getUserId();\n\n if (!userId || userId === '') {\n // Silent validation - userId not set\n return;\n }\n\n const question = quiz.questions.find((q) => q.id === questionId);\n // Allow free-text question types: DISSERTATIVA, RELACIONAR, PREENCHER_LACUNAS, IMAGEM, VERDADEIRO_FALSO\n const allowedTypes = [\n QUESTION_TYPE.DISSERTATIVA,\n QUESTION_TYPE.RELACIONAR,\n QUESTION_TYPE.PREENCHER_LACUNAS,\n QUESTION_TYPE.IMAGEM,\n QUESTION_TYPE.VERDADEIRO_FALSO,\n ];\n if (!question || !allowedTypes.includes(question.questionType)) {\n // Silent validation - wrong question type\n return;\n }\n\n // Validate character limit if set (only for DISSERTATIVA)\n let validatedAnswer = answer;\n if (\n question.questionType === QUESTION_TYPE.DISSERTATIVA &&\n dissertativeCharLimit !== undefined &&\n answer.length > dissertativeCharLimit\n ) {\n validatedAnswer = answer.substring(0, dissertativeCharLimit);\n }\n\n const existingAnswerIndex = userAnswers.findIndex(\n (answerItem) => answerItem.questionId === questionId\n );\n\n const newUserAnswer: UserAnswerItem = {\n questionId,\n activityId,\n userId,\n answer: validatedAnswer,\n optionId: null,\n questionType: question.questionType,\n answerStatus: ANSWER_STATUS.PENDENTE_AVALIACAO,\n };\n\n let updatedUserAnswers;\n if (existingAnswerIndex !== -1) {\n updatedUserAnswers = [...userAnswers];\n updatedUserAnswers[existingAnswerIndex] = newUserAnswer;\n } else {\n updatedUserAnswers = [...userAnswers, newUserAnswer];\n }\n\n set({\n userAnswers: updatedUserAnswers,\n });\n },\n\n skipQuestion: () => {\n const { getCurrentQuestion, userAnswers, quiz } = get();\n const currentQuestion = getCurrentQuestion();\n\n if (!quiz) return;\n\n if (currentQuestion) {\n const activityId = quiz.id;\n const userId = get().getUserId();\n\n if (!userId || userId === '') {\n // Silent validation - userId not set\n return;\n }\n\n const existingAnswerIndex = userAnswers.findIndex(\n (answer) => answer.questionId === currentQuestion.id\n );\n const existingAnswer =\n existingAnswerIndex === -1\n ? null\n : userAnswers[existingAnswerIndex];\n\n // If the user already has an answer with meaningful content, preserve it\n if (hasMeaningfulAnswer(existingAnswer)) {\n // Keep existing answers - don't overwrite with empty skip\n return;\n }\n\n // Create empty \"skipped\" entry\n const newUserAnswer: UserAnswerItem = {\n questionId: currentQuestion.id,\n activityId,\n userId,\n answer: null,\n optionId: null,\n questionType: currentQuestion.questionType,\n answerStatus: ANSWER_STATUS.PENDENTE_AVALIACAO,\n };\n\n let updatedUserAnswers;\n if (existingAnswerIndex !== -1) {\n // Update existing empty entry to proper \"skipped\" format\n updatedUserAnswers = [...userAnswers];\n updatedUserAnswers[existingAnswerIndex] = newUserAnswer;\n } else {\n // Add new skipped entry\n updatedUserAnswers = [...userAnswers, newUserAnswer];\n }\n\n set({\n userAnswers: updatedUserAnswers,\n });\n }\n },\n\n skipCurrentQuestionIfUnanswered: () => {\n const { getCurrentQuestion, getCurrentAnswer, skipQuestion } = get();\n const currentQuestion = getCurrentQuestion();\n const currentAnswer = getCurrentAnswer();\n\n // Se não há questão atual, não faz nada\n if (!currentQuestion) return;\n\n // Se não há resposta ou a resposta está vazia (null), marca como pulada\n // Considera selectedOptionIds para MULTIPLA_ESCOLHA\n if (\n !currentAnswer ||\n (currentAnswer.optionId === null &&\n currentAnswer.answer === null &&\n (!currentAnswer.selectedOptionIds ||\n currentAnswer.selectedOptionIds.length === 0))\n ) {\n skipQuestion();\n }\n },\n\n addUserAnswer: (questionId, answerId) => {\n const { quiz, userAnswers } = get();\n\n if (!quiz) return;\n\n // Add to userAnswers array with new structure\n const activityId = quiz.id;\n const userId = get().getUserId();\n\n if (!userId || userId === '') {\n // Silent validation - userId not set\n return;\n }\n\n const question = quiz.questions.find((q) => q.id === questionId);\n if (!question) return;\n\n const existingAnswerIndex = userAnswers.findIndex(\n (answer) => answer.questionId === questionId\n );\n\n const newUserAnswer: UserAnswerItem = {\n questionId,\n activityId,\n userId,\n answer:\n question.questionType === QUESTION_TYPE.DISSERTATIVA\n ? answerId || null\n : null,\n optionId:\n question.questionType !== QUESTION_TYPE.DISSERTATIVA\n ? answerId || null\n : null,\n questionType: question.questionType,\n answerStatus: ANSWER_STATUS.PENDENTE_AVALIACAO,\n };\n\n if (existingAnswerIndex !== -1) {\n // Update existing answer\n const updatedUserAnswers = [...userAnswers];\n updatedUserAnswers[existingAnswerIndex] = newUserAnswer;\n set({ userAnswers: updatedUserAnswers });\n } else {\n // Add new answer\n set({ userAnswers: [...userAnswers, newUserAnswer] });\n }\n },\n\n startQuiz: (options) => {\n // `initialElapsedSeconds` seeds the stopwatch when resuming an exam\n // the student had already started, so the count picks up from the\n // second it stopped at instead of restarting. startTimer() reads\n // timeElapsed as its base, so setting it here is enough.\n const initialElapsedSeconds = options?.initialElapsedSeconds ?? 0;\n set({ isStarted: true, timeElapsed: initialElapsedSeconds });\n startTimer();\n startMinuteCallback();\n checkTimeWarning(initialElapsedSeconds);\n },\n\n finishQuiz: () => {\n set({ isFinished: true });\n stopTimer();\n stopMinuteCallback();\n },\n\n resetQuiz: () => {\n stopTimer();\n stopMinuteCallback();\n set({\n quiz: null,\n currentQuestionIndex: 0,\n selectedAnswers: {},\n userAnswers: [],\n timeElapsed: 0,\n isStarted: false,\n isFinished: false,\n userId: '',\n variant: QuizVariant.DEFAULT,\n minuteCallback: null,\n dissertativeCharLimit: undefined,\n timeLimit: null,\n onTimeUp: null,\n timeWarningThreshold: null,\n onTimeWarning: null,\n hasTimeWarningFired: false,\n questionsResult: null,\n currentQuestionResult: null,\n // Note: draftApiClient is NOT reset here - it's managed by useDraftAutoSave hook\n lastSavedDraftPayload: '',\n isSavingDraft: false,\n // Scoped to the activity that was open: the next quiz has its own\n // existence, so leaving this set would silently disable autosave\n // for it too.\n isDraftUnavailable: false,\n activityFeedback: null,\n });\n },\n\n // Timer\n updateTime: (time) => {\n timerBaseElapsed = time;\n if (timerStartedAt !== null) {\n timerStartedAt = Date.now();\n }\n set({ timeElapsed: time });\n checkTimeThresholds(time);\n },\n startTimer,\n stopTimer,\n setTimeLimit: (seconds) => set({ timeLimit: seconds }),\n setOnTimeUp: (callback) => set({ onTimeUp: callback }),\n getRemainingTime: () => {\n const { timeLimit, timeElapsed } = get();\n if (timeLimit === null) return null;\n return Math.max(0, timeLimit - timeElapsed);\n },\n setTimeWarning: (seconds, callback) =>\n set({\n timeWarningThreshold: seconds,\n onTimeWarning: callback ?? null,\n // A new threshold is a new warning: rearm it, otherwise raising the\n // limit mid-exam would leave the student without the notice.\n hasTimeWarningFired: false,\n }),\n isTimeExceeded: () => {\n const { timeWarningThreshold, timeElapsed } = get();\n if (timeWarningThreshold === null) return false;\n return timeElapsed >= timeWarningThreshold;\n },\n\n // Minute Callback\n setMinuteCallback,\n startMinuteCallback,\n stopMinuteCallback,\n\n // Getters\n getCurrentQuestion: () => {\n const { currentQuestionIndex, quiz } = get();\n\n if (!quiz) {\n return null;\n }\n\n return quiz.questions[currentQuestionIndex];\n },\n\n getTotalQuestions: () => {\n const { quiz } = get();\n\n return quiz?.questions?.length || 0;\n },\n\n getAnsweredQuestions: () => {\n const { userAnswers } = get();\n const answeredQuestionIds = new Set(\n userAnswers\n .filter((answer) => hasMeaningfulAnswer(answer))\n .map((answer) => answer.questionId)\n );\n return answeredQuestionIds.size;\n },\n\n getUnansweredQuestions: () => {\n const { quiz, userAnswers } = get();\n if (!quiz) return [];\n\n const unansweredQuestions: number[] = [];\n\n quiz.questions.forEach((question, index) => {\n const userAnswer = userAnswers.find(\n (answer) => answer.questionId === question.id\n );\n const isAnswered = hasMeaningfulAnswer(userAnswer);\n // Question is skipped if it has a userAnswer entry but no meaningful content\n const isSkipped = userAnswer && !hasMeaningfulAnswer(userAnswer);\n\n if (!isAnswered && !isSkipped) {\n unansweredQuestions.push(index + 1); // index + 1 para mostrar número da questão\n }\n });\n return unansweredQuestions;\n },\n\n getSkippedQuestions: () => {\n const { userAnswers } = get();\n const skippedQuestionIds = new Set(\n userAnswers\n .filter((answer) => !hasMeaningfulAnswer(answer))\n .map((answer) => answer.questionId)\n );\n return skippedQuestionIds.size;\n },\n\n getProgress: () => {\n const { getTotalQuestions, getAnsweredQuestions } = get();\n const total = getTotalQuestions();\n const answered = getAnsweredQuestions();\n\n return total > 0 ? (answered / total) * 100 : 0;\n },\n\n isQuestionAnswered: (questionId) => {\n const { userAnswers } = get();\n const userAnswer = userAnswers.find(\n (answer) => answer.questionId === questionId\n );\n return hasMeaningfulAnswer(userAnswer);\n },\n\n isQuestionSkipped: (questionId) => {\n const { userAnswers } = get();\n const userAnswer = userAnswers.find(\n (answer) => answer.questionId === questionId\n );\n // Question is skipped if it has a userAnswer entry but no meaningful content\n return userAnswer ? !hasMeaningfulAnswer(userAnswer) : false;\n },\n\n getCurrentAnswer: () => {\n const { getCurrentQuestion, userAnswers } = get();\n const currentQuestion = getCurrentQuestion();\n\n if (!currentQuestion) return undefined;\n\n const userAnswer = userAnswers.find(\n (answer) => answer.questionId === currentQuestion.id\n );\n\n // Retorna undefined se a resposta está vazia (não respondida)\n if (!hasMeaningfulAnswer(userAnswer)) {\n return undefined;\n }\n\n return userAnswer;\n },\n\n getAllCurrentAnswer: () => {\n const { getCurrentQuestion, userAnswers } = get();\n const currentQuestion = getCurrentQuestion();\n\n if (!currentQuestion) return undefined;\n\n const userAnswer = userAnswers.filter(\n (answer) => answer.questionId === currentQuestion.id\n );\n\n return userAnswer;\n },\n\n getQuizTitle: () => {\n const { quiz } = get();\n\n return quiz?.title || 'Quiz';\n },\n\n formatTime: (seconds: number) => {\n const minutes = Math.floor(seconds / 60);\n const remainingSeconds = seconds % 60;\n return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;\n },\n\n getUserAnswers: () => {\n const { userAnswers } = get();\n return userAnswers;\n },\n\n getUnansweredQuestionsFromUserAnswers: () => {\n const { quiz, userAnswers } = get();\n if (!quiz) return [];\n\n const unansweredQuestions: number[] = [];\n\n quiz.questions.forEach((question, index) => {\n const userAnswer = userAnswers.find(\n (answer) => answer.questionId === question.id\n );\n const hasAnswer = hasMeaningfulAnswer(userAnswer);\n // Question is skipped if it has a userAnswer entry but no meaningful content\n const isSkipped = userAnswer && !hasMeaningfulAnswer(userAnswer);\n\n // Se não há resposta do usuário OU se a questão foi pulada\n if (!hasAnswer || isSkipped) {\n unansweredQuestions.push(index + 1); // index + 1 para mostrar número da questão\n }\n });\n\n return unansweredQuestions;\n },\n\n getQuestionsGroupedBySubject: () => {\n const { getQuestionResult, quiz, variant } = get();\n const questions =\n variant == 'result'\n ? getQuestionResult()?.answers\n : quiz?.questions;\n if (!questions) return {};\n const groupedQuestions: {\n [key: string]: (Question | QuestionResult['answers'][number])[];\n } = {};\n questions.forEach((question) => {\n const subjectId =\n question.knowledgeMatrix?.[0]?.subject?.id || 'Sem matéria';\n\n if (!groupedQuestions[subjectId]) {\n groupedQuestions[subjectId] = [];\n }\n\n groupedQuestions[subjectId].push(question);\n });\n\n return groupedQuestions;\n },\n\n // New methods for userAnswers\n getUserAnswerByQuestionId: (questionId) => {\n const { userAnswers } = get();\n return (\n userAnswers.find((answer) => answer.questionId === questionId) ||\n null\n );\n },\n isQuestionAnsweredByUserAnswers: (questionId) => {\n const { userAnswers } = get();\n const answer = userAnswers.find(\n (answer) => answer.questionId === questionId\n );\n return hasMeaningfulAnswer(answer);\n },\n getQuestionStatusFromUserAnswers: (questionId) => {\n const { userAnswers } = get();\n const answer = userAnswers.find(\n (answer) => answer.questionId === questionId\n );\n if (!answer) return 'unanswered';\n if (hasMeaningfulAnswer(answer)) return 'answered';\n return 'skipped';\n },\n getUserAnswersForActivity: () => {\n const { userAnswers } = get();\n return userAnswers;\n },\n setCurrentQuestion: (question) => {\n const { quiz, variant, questionsResult } = get();\n if (!quiz) return;\n let questionIndex: number;\n if (variant == 'result') {\n if (!questionsResult) return;\n const questionResult =\n questionsResult.answers.find((q) => q.id === question.id) ??\n questionsResult.answers.find((q) => q.questionId === question.id);\n if (!questionResult) return;\n questionIndex = quiz.questions.findIndex(\n (q) => q.id === questionResult.questionId\n );\n } else {\n questionIndex = quiz.questions.findIndex(\n (q) => q.id === question.id\n );\n }\n\n // Validate that the question was found before updating currentQuestionIndex\n if (questionIndex === -1) {\n // Silent validation - question not found\n return;\n }\n\n set({ currentQuestionIndex: questionIndex });\n },\n\n setAnswerStatus: (questionId, status) => {\n const { userAnswers } = get();\n const existingAnswerIndex = userAnswers.findIndex(\n (answer) => answer.questionId === questionId\n );\n\n if (existingAnswerIndex !== -1) {\n const updatedUserAnswers = [...userAnswers];\n updatedUserAnswers[existingAnswerIndex] = {\n ...updatedUserAnswers[existingAnswerIndex],\n answerStatus: status,\n };\n set({ userAnswers: updatedUserAnswers });\n }\n },\n\n getAnswerStatus: (questionId) => {\n const { userAnswers } = get();\n const userAnswer = userAnswers.find(\n (answer) => answer.questionId === questionId\n );\n return userAnswer ? userAnswer.answerStatus : null;\n },\n getQuestionIndex: (questionId) => {\n const { questionsResult, variant, quiz } = get();\n if (variant == 'result') {\n if (!questionsResult) return 0;\n\n let idx = questionsResult.answers.findIndex(\n (q) => q.questionId === questionId\n );\n if (idx === -1) {\n idx = questionsResult.answers.findIndex(\n (q) => q.id === questionId\n );\n }\n return idx !== -1 ? idx + 1 : 0;\n } else {\n if (!quiz) return 0;\n const idx = quiz.questions.findIndex((q) => q.id === questionId);\n return idx !== -1 ? idx + 1 : 0;\n }\n },\n\n // Question Result\n getQuestionResultByQuestionId: (questionId) => {\n const { questionsResult } = get();\n const question = questionsResult?.answers.find(\n (answer) => answer.questionId === questionId\n );\n\n return question || null;\n },\n getQuestionResultStatistics: () => {\n const { questionsResult } = get();\n return questionsResult?.statistics || null;\n },\n getQuestionResult: () => {\n const { questionsResult } = get();\n return questionsResult;\n },\n setQuestionsResult: (questionsResult) => {\n set({ questionsResult });\n },\n setCurrentQuestionResult: (currentQuestionResult) => {\n set({ currentQuestionResult });\n },\n getCurrentQuestionResult: () => {\n const { currentQuestionResult } = get();\n return currentQuestionResult;\n },\n\n // Draft management\n applyDraftAnswers: (draftAnswers) => {\n const { quiz, userId } = get();\n if (!quiz || !draftAnswers || draftAnswers.length === 0) return;\n\n const activityId = quiz.id;\n const newUserAnswers: UserAnswerItem[] = [];\n\n for (const draft of draftAnswers) {\n const question = quiz.questions.find(\n (q) => q.id === draft.questionId\n );\n if (!question) continue;\n\n // Parse answer if it's a JSON string (for complex answer types)\n let parsedAnswer = draft.answer;\n let selectedOptionIds = draft.selectedOptionIds;\n\n // Try to parse JSON answer for complex types\n if (draft.answer && !draft.optionId) {\n try {\n const parsed = JSON.parse(draft.answer);\n if (parsed.selectedOptionIds) {\n selectedOptionIds = parsed.selectedOptionIds;\n parsedAnswer = null;\n }\n } catch {\n // Not JSON, keep as plain text\n }\n }\n\n const userAnswer: UserAnswerItem = {\n questionId: draft.questionId,\n activityId,\n userId,\n answer: parsedAnswer,\n optionId: draft.optionId || null,\n selectedOptionIds: selectedOptionIds || null,\n questionType: question.questionType,\n answerStatus: ANSWER_STATUS.PENDENTE_AVALIACAO,\n };\n\n newUserAnswers.push(userAnswer);\n }\n\n set({ userAnswers: newUserAnswers });\n },\n\n prepareDraftPayload: () => {\n const { userAnswers } = get();\n\n const answers = userAnswers\n .filter((answer) => hasMeaningfulAnswer(answer))\n .map((answer) => {\n const draftAnswer: SaveDraftPayload['answers'][number] = {\n questionId: answer.questionId,\n };\n\n if (answer.optionId) {\n draftAnswer.optionId = answer.optionId;\n }\n\n if (answer.answer) {\n draftAnswer.answer = answer.answer;\n }\n\n if (\n answer.selectedOptionIds &&\n answer.selectedOptionIds.length > 0\n ) {\n draftAnswer.selectedOptionIds = answer.selectedOptionIds;\n }\n\n return draftAnswer;\n });\n\n return { answers };\n },\n\n hasDraftChanges: () => {\n const { userAnswers } = get();\n return userAnswers.some((answer) => hasMeaningfulAnswer(answer));\n },\n\n // Activity Feedback\n setActivityFeedback: (feedback) => set({ activityFeedback: feedback }),\n getActivityFeedback: () => get().activityFeedback,\n };\n },\n {\n name: 'quiz-store',\n }\n )\n);\n"],"mappings":"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","names":["QUESTION_DIFFICULTY","QUIZ_TYPE","QUESTION_TYPE","QUESTION_STATUS","ANSWER_STATUS","CORRECTION_SOURCE","AI_CORRECTION_STATUS","SUBTYPE_ENUM","answer"]}
|