@hed-hog/lms 0.0.349 → 0.0.350
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/achievement/achievement.controller.d.ts +62 -0
- package/dist/achievement/achievement.controller.d.ts.map +1 -0
- package/dist/achievement/achievement.controller.js +90 -0
- package/dist/achievement/achievement.controller.js.map +1 -0
- package/dist/achievement/achievement.mcp-tools.d.ts +19 -0
- package/dist/achievement/achievement.mcp-tools.d.ts.map +1 -0
- package/dist/achievement/achievement.mcp-tools.js +157 -0
- package/dist/achievement/achievement.mcp-tools.js.map +1 -0
- package/dist/achievement/achievement.module.d.ts +3 -0
- package/dist/achievement/achievement.module.d.ts.map +1 -0
- package/dist/achievement/achievement.module.js +26 -0
- package/dist/achievement/achievement.module.js.map +1 -0
- package/dist/achievement/achievement.service.d.ts +72 -0
- package/dist/achievement/achievement.service.d.ts.map +1 -0
- package/dist/achievement/achievement.service.js +200 -0
- package/dist/achievement/achievement.service.js.map +1 -0
- package/dist/achievement/dto/create-achievement.dto.d.ts +12 -0
- package/dist/achievement/dto/create-achievement.dto.d.ts.map +1 -0
- package/dist/achievement/dto/create-achievement.dto.js +60 -0
- package/dist/achievement/dto/create-achievement.dto.js.map +1 -0
- package/dist/achievement/dto/update-achievement.dto.d.ts +11 -0
- package/dist/achievement/dto/update-achievement.dto.d.ts.map +1 -0
- package/dist/achievement/dto/update-achievement.dto.js +57 -0
- package/dist/achievement/dto/update-achievement.dto.js.map +1 -0
- package/dist/bitcode-wallet/bitcode-wallet.controller.d.ts +114 -0
- package/dist/bitcode-wallet/bitcode-wallet.controller.d.ts.map +1 -0
- package/dist/bitcode-wallet/bitcode-wallet.controller.js +102 -0
- package/dist/bitcode-wallet/bitcode-wallet.controller.js.map +1 -0
- package/dist/bitcode-wallet/bitcode-wallet.mcp-tools.d.ts +25 -0
- package/dist/bitcode-wallet/bitcode-wallet.mcp-tools.d.ts.map +1 -0
- package/dist/bitcode-wallet/bitcode-wallet.mcp-tools.js +160 -0
- package/dist/bitcode-wallet/bitcode-wallet.mcp-tools.js.map +1 -0
- package/dist/bitcode-wallet/bitcode-wallet.module.d.ts +3 -0
- package/dist/bitcode-wallet/bitcode-wallet.module.d.ts.map +1 -0
- package/dist/bitcode-wallet/bitcode-wallet.module.js +26 -0
- package/dist/bitcode-wallet/bitcode-wallet.module.js.map +1 -0
- package/dist/bitcode-wallet/bitcode-wallet.service.d.ts +127 -0
- package/dist/bitcode-wallet/bitcode-wallet.service.d.ts.map +1 -0
- package/dist/bitcode-wallet/bitcode-wallet.service.js +264 -0
- package/dist/bitcode-wallet/bitcode-wallet.service.js.map +1 -0
- package/dist/bitcode-wallet/dto/create-bitcode-wallet-transaction.dto.d.ts +8 -0
- package/dist/bitcode-wallet/dto/create-bitcode-wallet-transaction.dto.d.ts.map +1 -0
- package/dist/bitcode-wallet/dto/create-bitcode-wallet-transaction.dto.js +33 -0
- package/dist/bitcode-wallet/dto/create-bitcode-wallet-transaction.dto.js.map +1 -0
- package/dist/bitcode-wallet/dto/create-bitcode-wallet.dto.d.ts +4 -0
- package/dist/bitcode-wallet/dto/create-bitcode-wallet.dto.d.ts.map +1 -0
- package/dist/bitcode-wallet/dto/create-bitcode-wallet.dto.js +22 -0
- package/dist/bitcode-wallet/dto/create-bitcode-wallet.dto.js.map +1 -0
- package/dist/bitcode-wallet/dto/update-bitcode-wallet-transaction.dto.d.ts +7 -0
- package/dist/bitcode-wallet/dto/update-bitcode-wallet-transaction.dto.d.ts.map +1 -0
- package/dist/bitcode-wallet/dto/update-bitcode-wallet-transaction.dto.js +35 -0
- package/dist/bitcode-wallet/dto/update-bitcode-wallet-transaction.dto.js.map +1 -0
- package/dist/bitcode-wallet/dto/update-bitcode-wallet.dto.d.ts +4 -0
- package/dist/bitcode-wallet/dto/update-bitcode-wallet.dto.d.ts.map +1 -0
- package/dist/bitcode-wallet/dto/update-bitcode-wallet.dto.js +23 -0
- package/dist/bitcode-wallet/dto/update-bitcode-wallet.dto.js.map +1 -0
- package/dist/certificate/certificate.controller.d.ts +22 -0
- package/dist/certificate/certificate.controller.d.ts.map +1 -1
- package/dist/certificate/certificate.controller.js +12 -0
- package/dist/certificate/certificate.controller.js.map +1 -1
- package/dist/certificate/certificate.mcp-tools.d.ts +24 -0
- package/dist/certificate/certificate.mcp-tools.d.ts.map +1 -0
- package/dist/certificate/certificate.mcp-tools.js +188 -0
- package/dist/certificate/certificate.mcp-tools.js.map +1 -0
- package/dist/certificate/certificate.module.d.ts.map +1 -1
- package/dist/certificate/certificate.module.js +2 -1
- package/dist/certificate/certificate.module.js.map +1 -1
- package/dist/certificate/certificate.service.d.ts +25 -2
- package/dist/certificate/certificate.service.d.ts.map +1 -1
- package/dist/certificate/certificate.service.js +87 -2
- package/dist/certificate/certificate.service.js.map +1 -1
- package/dist/certificate/dto/update-certificate-public-access.dto.d.ts +4 -0
- package/dist/certificate/dto/update-certificate-public-access.dto.d.ts.map +1 -0
- package/dist/certificate/dto/update-certificate-public-access.dto.js +21 -0
- package/dist/certificate/dto/update-certificate-public-access.dto.js.map +1 -0
- package/dist/class-group/class-group.mcp-tools.d.ts +87 -0
- package/dist/class-group/class-group.mcp-tools.d.ts.map +1 -0
- package/dist/class-group/class-group.mcp-tools.js +553 -0
- package/dist/class-group/class-group.mcp-tools.js.map +1 -0
- package/dist/class-group/class-group.module.d.ts.map +1 -1
- package/dist/class-group/class-group.module.js +2 -1
- package/dist/class-group/class-group.module.js.map +1 -1
- package/dist/class-group/class-group.service.d.ts +3 -1
- package/dist/class-group/class-group.service.d.ts.map +1 -1
- package/dist/class-group/class-group.service.js +45 -2
- package/dist/class-group/class-group.service.js.map +1 -1
- package/dist/course/course-operations-integration.service.d.ts +40 -0
- package/dist/course/course-operations-integration.service.d.ts.map +1 -0
- package/dist/course/course-operations-integration.service.js +372 -0
- package/dist/course/course-operations-integration.service.js.map +1 -0
- package/dist/course/course-structure.controller.d.ts +43 -4
- package/dist/course/course-structure.controller.d.ts.map +1 -1
- package/dist/course/course-structure.controller.js +22 -0
- package/dist/course/course-structure.controller.js.map +1 -1
- package/dist/course/course-structure.service.d.ts +42 -1
- package/dist/course/course-structure.service.d.ts.map +1 -1
- package/dist/course/course-structure.service.js +199 -32
- package/dist/course/course-structure.service.js.map +1 -1
- package/dist/course/course.controller.d.ts +12 -0
- package/dist/course/course.controller.d.ts.map +1 -1
- package/dist/course/course.mcp-tools.d.ts +90 -0
- package/dist/course/course.mcp-tools.d.ts.map +1 -0
- package/dist/course/course.mcp-tools.js +520 -0
- package/dist/course/course.mcp-tools.js.map +1 -0
- package/dist/course/course.module.d.ts.map +1 -1
- package/dist/course/course.module.js +8 -1
- package/dist/course/course.module.js.map +1 -1
- package/dist/course/course.service.d.ts +15 -1
- package/dist/course/course.service.d.ts.map +1 -1
- package/dist/course/course.service.js +70 -35
- package/dist/course/course.service.js.map +1 -1
- package/dist/course/dto/create-course.dto.d.ts +1 -0
- package/dist/course/dto/create-course.dto.d.ts.map +1 -1
- package/dist/course/dto/create-course.dto.js +7 -0
- package/dist/course/dto/create-course.dto.js.map +1 -1
- package/dist/course/dto/update-course-resources.dto.d.ts +11 -0
- package/dist/course/dto/update-course-resources.dto.d.ts.map +1 -0
- package/dist/course/dto/update-course-resources.dto.js +51 -0
- package/dist/course/dto/update-course-resources.dto.js.map +1 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.controller.d.ts +23 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.controller.d.ts.map +1 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.controller.js +78 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.controller.js.map +1 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.mcp-tools.d.ts +22 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.mcp-tools.d.ts.map +1 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.mcp-tools.js +120 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.mcp-tools.js.map +1 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.module.d.ts +3 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.module.d.ts.map +1 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.module.js +26 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.module.js.map +1 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.service.d.ts +49 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.service.d.ts.map +1 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.service.js +272 -0
- package/dist/course-lesson-discussion/course-lesson-discussion.service.js.map +1 -0
- package/dist/course-lesson-discussion/dto/create-course-lesson-discussion-topic.dto.d.ts +6 -0
- package/dist/course-lesson-discussion/dto/create-course-lesson-discussion-topic.dto.d.ts.map +1 -0
- package/dist/course-lesson-discussion/dto/create-course-lesson-discussion-topic.dto.js +33 -0
- package/dist/course-lesson-discussion/dto/create-course-lesson-discussion-topic.dto.js.map +1 -0
- package/dist/course-lesson-note/course-lesson-note.controller.d.ts +53 -0
- package/dist/course-lesson-note/course-lesson-note.controller.d.ts.map +1 -0
- package/dist/course-lesson-note/course-lesson-note.controller.js +93 -0
- package/dist/course-lesson-note/course-lesson-note.controller.js.map +1 -0
- package/dist/course-lesson-note/course-lesson-note.mcp-tools.d.ts +27 -0
- package/dist/course-lesson-note/course-lesson-note.mcp-tools.d.ts.map +1 -0
- package/dist/course-lesson-note/course-lesson-note.mcp-tools.js +145 -0
- package/dist/course-lesson-note/course-lesson-note.mcp-tools.js.map +1 -0
- package/dist/course-lesson-note/course-lesson-note.module.d.ts +3 -0
- package/dist/course-lesson-note/course-lesson-note.module.d.ts.map +1 -0
- package/dist/course-lesson-note/course-lesson-note.module.js +26 -0
- package/dist/course-lesson-note/course-lesson-note.module.js.map +1 -0
- package/dist/course-lesson-note/course-lesson-note.service.d.ts +59 -0
- package/dist/course-lesson-note/course-lesson-note.service.d.ts.map +1 -0
- package/dist/course-lesson-note/course-lesson-note.service.js +195 -0
- package/dist/course-lesson-note/course-lesson-note.service.js.map +1 -0
- package/dist/course-lesson-note/dto/create-course-lesson-note.dto.d.ts +6 -0
- package/dist/course-lesson-note/dto/create-course-lesson-note.dto.d.ts.map +1 -0
- package/dist/course-lesson-note/dto/create-course-lesson-note.dto.js +33 -0
- package/dist/course-lesson-note/dto/create-course-lesson-note.dto.js.map +1 -0
- package/dist/course-lesson-note/dto/update-course-lesson-note.dto.d.ts +6 -0
- package/dist/course-lesson-note/dto/update-course-lesson-note.dto.d.ts.map +1 -0
- package/dist/course-lesson-note/dto/update-course-lesson-note.dto.js +35 -0
- package/dist/course-lesson-note/dto/update-course-lesson-note.dto.js.map +1 -0
- package/dist/dashboard/dashboard.mcp-tools.d.ts +10 -0
- package/dist/dashboard/dashboard.mcp-tools.d.ts.map +1 -0
- package/dist/dashboard/dashboard.mcp-tools.js +46 -0
- package/dist/dashboard/dashboard.mcp-tools.js.map +1 -0
- package/dist/dashboard/dashboard.module.d.ts.map +1 -1
- package/dist/dashboard/dashboard.module.js +2 -1
- package/dist/dashboard/dashboard.module.js.map +1 -1
- package/dist/enterprise/enterprise.mcp-tools.d.ts +82 -0
- package/dist/enterprise/enterprise.mcp-tools.d.ts.map +1 -0
- package/dist/enterprise/enterprise.mcp-tools.js +516 -0
- package/dist/enterprise/enterprise.mcp-tools.js.map +1 -0
- package/dist/enterprise/enterprise.module.d.ts.map +1 -1
- package/dist/enterprise/enterprise.module.js +2 -1
- package/dist/enterprise/enterprise.module.js.map +1 -1
- package/dist/enterprise/training/enterprise-training.module.d.ts.map +1 -1
- package/dist/enterprise/training/enterprise-training.module.js +11 -1
- package/dist/enterprise/training/enterprise-training.module.js.map +1 -1
- package/dist/enterprise/training/training-admin.mcp-tools.d.ts +79 -0
- package/dist/enterprise/training/training-admin.mcp-tools.d.ts.map +1 -0
- package/dist/enterprise/training/training-admin.mcp-tools.js +620 -0
- package/dist/enterprise/training/training-admin.mcp-tools.js.map +1 -0
- package/dist/enterprise/training/training-instructor.mcp-tools.d.ts +47 -0
- package/dist/enterprise/training/training-instructor.mcp-tools.d.ts.map +1 -0
- package/dist/enterprise/training/training-instructor.mcp-tools.js +275 -0
- package/dist/enterprise/training/training-instructor.mcp-tools.js.map +1 -0
- package/dist/enterprise/training/training-student.controller.d.ts +24 -0
- package/dist/enterprise/training/training-student.controller.d.ts.map +1 -1
- package/dist/enterprise/training/training-student.controller.js +22 -0
- package/dist/enterprise/training/training-student.controller.js.map +1 -1
- package/dist/enterprise/training/training-student.mcp-tools.d.ts +27 -0
- package/dist/enterprise/training/training-student.mcp-tools.d.ts.map +1 -0
- package/dist/enterprise/training/training-student.mcp-tools.js +186 -0
- package/dist/enterprise/training/training-student.mcp-tools.js.map +1 -0
- package/dist/enterprise/training/training-student.service.d.ts +32 -0
- package/dist/enterprise/training/training-student.service.d.ts.map +1 -1
- package/dist/enterprise/training/training-student.service.js +138 -0
- package/dist/enterprise/training/training-student.service.js.map +1 -1
- package/dist/evaluation/evaluation.mcp-tools.d.ts +25 -0
- package/dist/evaluation/evaluation.mcp-tools.d.ts.map +1 -0
- package/dist/evaluation/evaluation.mcp-tools.js +220 -0
- package/dist/evaluation/evaluation.mcp-tools.js.map +1 -0
- package/dist/evaluation/evaluation.module.d.ts.map +1 -1
- package/dist/evaluation/evaluation.module.js +2 -1
- package/dist/evaluation/evaluation.module.js.map +1 -1
- package/dist/exam/dto/create-exam-question.dto.d.ts +2 -0
- package/dist/exam/dto/create-exam-question.dto.d.ts.map +1 -1
- package/dist/exam/dto/create-exam-question.dto.js +10 -0
- package/dist/exam/dto/create-exam-question.dto.js.map +1 -1
- package/dist/exam/dto/create-exam.dto.d.ts +2 -0
- package/dist/exam/dto/create-exam.dto.d.ts.map +1 -1
- package/dist/exam/dto/create-exam.dto.js +10 -0
- package/dist/exam/dto/create-exam.dto.js.map +1 -1
- package/dist/exam/dto/create-question-subject.dto.d.ts +5 -0
- package/dist/exam/dto/create-question-subject.dto.d.ts.map +1 -0
- package/dist/exam/dto/create-question-subject.dto.js +28 -0
- package/dist/exam/dto/create-question-subject.dto.js.map +1 -0
- package/dist/exam/exam-attempt.controller.d.ts +4 -0
- package/dist/exam/exam-attempt.controller.d.ts.map +1 -1
- package/dist/exam/exam-attempt.service.d.ts +7 -1
- package/dist/exam/exam-attempt.service.d.ts.map +1 -1
- package/dist/exam/exam-attempt.service.js +47 -17
- package/dist/exam/exam-attempt.service.js.map +1 -1
- package/dist/exam/exam.controller.d.ts +34 -0
- package/dist/exam/exam.controller.d.ts.map +1 -1
- package/dist/exam/exam.controller.js +27 -0
- package/dist/exam/exam.controller.js.map +1 -1
- package/dist/exam/exam.mcp-tools.d.ts +62 -0
- package/dist/exam/exam.mcp-tools.d.ts.map +1 -0
- package/dist/exam/exam.mcp-tools.js +430 -0
- package/dist/exam/exam.mcp-tools.js.map +1 -0
- package/dist/exam/exam.module.d.ts.map +1 -1
- package/dist/exam/exam.module.js +2 -1
- package/dist/exam/exam.module.js.map +1 -1
- package/dist/exam/exam.service.d.ts +38 -0
- package/dist/exam/exam.service.d.ts.map +1 -1
- package/dist/exam/exam.service.js +114 -17
- package/dist/exam/exam.service.js.map +1 -1
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/instructor/instructor.mcp-tools.d.ts +41 -0
- package/dist/instructor/instructor.mcp-tools.d.ts.map +1 -0
- package/dist/instructor/instructor.mcp-tools.js +326 -0
- package/dist/instructor/instructor.mcp-tools.js.map +1 -0
- package/dist/instructor/instructor.module.d.ts.map +1 -1
- package/dist/instructor/instructor.module.js +2 -1
- package/dist/instructor/instructor.module.js.map +1 -1
- package/dist/lms.module.d.ts.map +1 -1
- package/dist/lms.module.js +15 -0
- package/dist/lms.module.js.map +1 -1
- package/dist/realtime/lms-realtime.controller.d.ts +7 -0
- package/dist/realtime/lms-realtime.controller.d.ts.map +1 -0
- package/dist/realtime/lms-realtime.controller.js +34 -0
- package/dist/realtime/lms-realtime.controller.js.map +1 -0
- package/dist/realtime/lms-realtime.module.d.ts +3 -0
- package/dist/realtime/lms-realtime.module.d.ts.map +1 -0
- package/dist/realtime/lms-realtime.module.js +25 -0
- package/dist/realtime/lms-realtime.module.js.map +1 -0
- package/dist/realtime/lms-realtime.service.d.ts +36 -0
- package/dist/realtime/lms-realtime.service.d.ts.map +1 -0
- package/dist/realtime/lms-realtime.service.js +59 -0
- package/dist/realtime/lms-realtime.service.js.map +1 -0
- package/dist/realtime/lms-realtime.subscriber.d.ts +10 -0
- package/dist/realtime/lms-realtime.subscriber.d.ts.map +1 -0
- package/dist/realtime/lms-realtime.subscriber.js +70 -0
- package/dist/realtime/lms-realtime.subscriber.js.map +1 -0
- package/dist/reports/reports.mcp-tools.d.ts +10 -0
- package/dist/reports/reports.mcp-tools.d.ts.map +1 -0
- package/dist/reports/reports.mcp-tools.js +50 -0
- package/dist/reports/reports.mcp-tools.js.map +1 -0
- package/dist/reports/reports.module.d.ts.map +1 -1
- package/dist/reports/reports.module.js +2 -1
- package/dist/reports/reports.module.js.map +1 -1
- package/dist/training/training.mcp-tools.d.ts +20 -0
- package/dist/training/training.mcp-tools.d.ts.map +1 -0
- package/dist/training/training.mcp-tools.js +181 -0
- package/dist/training/training.mcp-tools.js.map +1 -0
- package/dist/training/training.module.d.ts.map +1 -1
- package/dist/training/training.module.js +2 -1
- package/dist/training/training.module.js.map +1 -1
- package/hedhog/data/integration_event_catalog.yaml +69 -0
- package/hedhog/data/menu.yaml +34 -0
- package/hedhog/data/route.yaml +2351 -0
- package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +168 -103
- package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +80 -1
- package/hedhog/frontend/app/_components/course-picker.tsx.ejs +228 -0
- package/hedhog/frontend/app/_lib/hooks/use-lms-realtime-refresh.ts.ejs +58 -0
- package/hedhog/frontend/app/achievements/page.tsx.ejs +844 -0
- package/hedhog/frontend/app/bitcodes/page.tsx.ejs +1010 -0
- package/hedhog/frontend/app/certificates/issued/page.tsx.ejs +61 -2
- package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +7 -0
- package/hedhog/frontend/app/classes/page.tsx.ejs +55 -2060
- package/hedhog/frontend/app/courses/[id]/_components/CourseRelationsCard.tsx.ejs +28 -0
- package/hedhog/frontend/app/courses/[id]/_components/course-edit-types.ts.ejs +1 -0
- package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +0 -9
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +80 -66
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +583 -8
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +527 -57
- package/hedhog/frontend/app/courses/[id]/structure/_components/mock-data.ts.ejs +1 -1
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-context-menu.tsx.ejs +106 -4
- package/hedhog/frontend/app/courses/[id]/structure/_components/types.ts.ejs +2 -1
- package/hedhog/frontend/app/courses/[id]/structure/_data/adapters/course-structure.adapter.ts.ejs +11 -1
- package/hedhog/frontend/app/courses/[id]/structure/_data/services/course-structure.service.ts.ejs +53 -6
- package/hedhog/frontend/app/courses/[id]/structure/_data/types/api-course.types.ts.ejs +13 -2
- package/hedhog/frontend/app/courses/page.tsx.ejs +175 -29
- package/hedhog/frontend/app/enterprise/_components/enterprise-course-create-sheet.tsx.ejs +3 -0
- package/hedhog/frontend/app/enterprise/_components/enterprise-course-edit-sheet.tsx.ejs +7 -0
- package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +169 -2
- package/hedhog/frontend/app/exams/page.tsx.ejs +77 -22
- package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +1 -0
- package/hedhog/frontend/app/instructors/page.tsx.ejs +1 -0
- package/hedhog/frontend/app/paths/page.tsx.ejs +6 -24
- package/hedhog/frontend/app/training/page.tsx.ejs +6 -24
- package/hedhog/frontend/messages/en.json +314 -12
- package/hedhog/frontend/messages/pt.json +314 -12
- package/hedhog/query/triggers.sql +53 -0
- package/hedhog/table/achievement.yaml +46 -0
- package/hedhog/table/bitcode_wallet.yaml +18 -0
- package/hedhog/table/bitcode_wallet_transaction.yaml +22 -0
- package/hedhog/table/certificate.yaml +3 -0
- package/hedhog/table/course.yaml +4 -0
- package/hedhog/table/course_file.yaml +23 -0
- package/hedhog/table/course_lesson.yaml +5 -0
- package/hedhog/table/course_lesson_discussion_like.yaml +21 -0
- package/hedhog/table/course_lesson_discussion_topic.yaml +35 -0
- package/hedhog/table/course_lesson_note.yaml +34 -0
- package/hedhog/table/exam.yaml +5 -0
- package/hedhog/table/learning_path_enrollment.yaml +6 -0
- package/hedhog/table/question.yaml +10 -0
- package/hedhog/table/question_subject.yaml +17 -0
- package/hedhog/table/student_activity_streak.yaml +25 -0
- package/package.json +6 -6
- package/src/achievement/achievement.controller.ts +60 -0
- package/src/achievement/achievement.mcp-tools.ts +108 -0
- package/src/achievement/achievement.module.ts +13 -0
- package/src/achievement/achievement.service.ts +252 -0
- package/src/achievement/dto/create-achievement.dto.ts +50 -0
- package/src/achievement/dto/update-achievement.dto.ts +47 -0
- package/src/bitcode-wallet/bitcode-wallet.controller.ts +69 -0
- package/src/bitcode-wallet/bitcode-wallet.mcp-tools.ts +107 -0
- package/src/bitcode-wallet/bitcode-wallet.module.ts +13 -0
- package/src/bitcode-wallet/bitcode-wallet.service.ts +361 -0
- package/src/bitcode-wallet/dto/create-bitcode-wallet-transaction.dto.ts +27 -0
- package/src/bitcode-wallet/dto/create-bitcode-wallet.dto.ts +7 -0
- package/src/bitcode-wallet/dto/update-bitcode-wallet-transaction.dto.ts +28 -0
- package/src/bitcode-wallet/dto/update-bitcode-wallet.dto.ts +8 -0
- package/src/certificate/certificate.controller.ts +20 -11
- package/src/certificate/certificate.mcp-tools.ts +131 -0
- package/src/certificate/certificate.module.ts +2 -1
- package/src/certificate/certificate.service.ts +95 -4
- package/src/certificate/dto/update-certificate-public-access.dto.ts +6 -0
- package/src/class-group/class-group.mcp-tools.ts +435 -0
- package/src/class-group/class-group.module.ts +2 -1
- package/src/class-group/class-group.service.ts +51 -1
- package/src/course/course-operations-integration.service.ts +520 -0
- package/src/course/course-structure.controller.ts +22 -8
- package/src/course/course-structure.service.ts +215 -23
- package/src/course/course.mcp-tools.ts +409 -0
- package/src/course/course.module.ts +8 -1
- package/src/course/course.service.ts +106 -27
- package/src/course/dto/create-course.dto.ts +8 -0
- package/src/course/dto/update-course-resources.dto.ts +39 -0
- package/src/course-lesson-discussion/course-lesson-discussion.controller.ts +55 -0
- package/src/course-lesson-discussion/course-lesson-discussion.mcp-tools.ts +75 -0
- package/src/course-lesson-discussion/course-lesson-discussion.module.ts +13 -0
- package/src/course-lesson-discussion/course-lesson-discussion.service.ts +354 -0
- package/src/course-lesson-discussion/dto/create-course-lesson-discussion-topic.dto.ts +16 -0
- package/src/course-lesson-note/course-lesson-note.controller.ts +68 -0
- package/src/course-lesson-note/course-lesson-note.mcp-tools.ts +96 -0
- package/src/course-lesson-note/course-lesson-note.module.ts +13 -0
- package/src/course-lesson-note/course-lesson-note.service.ts +248 -0
- package/src/course-lesson-note/dto/create-course-lesson-note.dto.ts +16 -0
- package/src/course-lesson-note/dto/update-course-lesson-note.dto.ts +18 -0
- package/src/dashboard/dashboard.mcp-tools.ts +23 -0
- package/src/dashboard/dashboard.module.ts +2 -1
- package/src/enterprise/enterprise.mcp-tools.ts +403 -0
- package/src/enterprise/enterprise.module.ts +2 -1
- package/src/enterprise/training/enterprise-training.module.ts +11 -1
- package/src/enterprise/training/training-admin.mcp-tools.ts +479 -0
- package/src/enterprise/training/training-instructor.mcp-tools.ts +210 -0
- package/src/enterprise/training/training-student.controller.ts +17 -1
- package/src/enterprise/training/training-student.mcp-tools.ts +136 -0
- package/src/enterprise/training/training-student.service.ts +167 -1
- package/src/evaluation/evaluation.mcp-tools.ts +155 -0
- package/src/evaluation/evaluation.module.ts +2 -1
- package/src/exam/dto/create-exam-question.dto.ts +8 -0
- package/src/exam/dto/create-exam.dto.ts +8 -0
- package/src/exam/dto/create-question-subject.dto.ts +12 -0
- package/src/exam/exam-attempt.service.ts +46 -14
- package/src/exam/exam.controller.ts +19 -0
- package/src/exam/exam.mcp-tools.ts +337 -0
- package/src/exam/exam.module.ts +2 -1
- package/src/exam/exam.service.ts +121 -0
- package/src/index.ts +9 -0
- package/src/instructor/instructor.mcp-tools.ts +243 -0
- package/src/instructor/instructor.module.ts +2 -1
- package/src/lms.module.ts +15 -1
- package/src/realtime/lms-realtime.controller.ts +12 -0
- package/src/realtime/lms-realtime.module.ts +12 -0
- package/src/realtime/lms-realtime.service.ts +98 -0
- package/src/realtime/lms-realtime.subscriber.ts +61 -0
- package/src/reports/reports.mcp-tools.ts +27 -0
- package/src/reports/reports.module.ts +2 -1
- package/src/training/training.mcp-tools.ts +128 -0
- package/src/training/training.module.ts +2 -1
|
@@ -36,6 +36,7 @@ type ApiCourse = {
|
|
|
36
36
|
primaryColor?: string | null;
|
|
37
37
|
secondaryColor?: string | null;
|
|
38
38
|
logoFileId?: number | null;
|
|
39
|
+
operationsProjectId?: number | null;
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
export interface EnterpriseCourseEditSheetProps {
|
|
@@ -128,6 +129,9 @@ export function EnterpriseCourseEditSheet({
|
|
|
128
129
|
nivel: toPtLevel(course.level),
|
|
129
130
|
status: toPtStatus(course.status),
|
|
130
131
|
categorias: course.categories ?? [],
|
|
132
|
+
operationsProjectId: course.operationsProjectId
|
|
133
|
+
? String(course.operationsProjectId)
|
|
134
|
+
: '',
|
|
131
135
|
primaryColor: course.primaryColor ?? '#1D4ED8',
|
|
132
136
|
secondaryColor: course.secondaryColor ?? '#111827',
|
|
133
137
|
logoFileId: course.logoFileId ?? null,
|
|
@@ -171,6 +175,9 @@ export function EnterpriseCourseEditSheet({
|
|
|
171
175
|
primaryContrastColor: getContrastColor(values.primaryColor),
|
|
172
176
|
secondaryColor: values.secondaryColor,
|
|
173
177
|
secondaryContrastColor: getContrastColor(values.secondaryColor),
|
|
178
|
+
operationsProjectId: values.operationsProjectId
|
|
179
|
+
? Number(values.operationsProjectId)
|
|
180
|
+
: null,
|
|
174
181
|
logoFileId: values.logoFileId ?? null,
|
|
175
182
|
},
|
|
176
183
|
});
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
SearchBar,
|
|
9
9
|
ViewModeToggle,
|
|
10
10
|
} from '@/components/entity-list';
|
|
11
|
+
import { EntityPicker } from '@/components/ui/entity-picker';
|
|
11
12
|
import { RichTextEditor } from '@/components/rich-text-editor';
|
|
12
13
|
import { Badge } from '@/components/ui/badge';
|
|
13
14
|
import { Button } from '@/components/ui/button';
|
|
@@ -132,13 +133,22 @@ interface Questao {
|
|
|
132
133
|
examQuestionId: number;
|
|
133
134
|
order: number;
|
|
134
135
|
tipo: ExamQuestionType;
|
|
136
|
+
assuntoId: number | null;
|
|
137
|
+
assunto: string | null;
|
|
135
138
|
enunciado: string;
|
|
139
|
+
explicacao: string;
|
|
136
140
|
pontuacao: number;
|
|
137
141
|
alternativas: Alternativa[];
|
|
138
142
|
fillBlankAnswers: FillBlankAnswer[];
|
|
139
143
|
matchingPairs: MatchingPair[];
|
|
140
144
|
}
|
|
141
145
|
|
|
146
|
+
type AssuntoQuestaoOption = {
|
|
147
|
+
id: number;
|
|
148
|
+
name: string;
|
|
149
|
+
description?: string | null;
|
|
150
|
+
};
|
|
151
|
+
|
|
142
152
|
type ExamQuestionType =
|
|
143
153
|
| 'multiple_choice'
|
|
144
154
|
| 'true_false'
|
|
@@ -164,7 +174,10 @@ type ApiExamQuestion = {
|
|
|
164
174
|
examQuestionId: number;
|
|
165
175
|
order: number;
|
|
166
176
|
questionType: ExamQuestionType;
|
|
177
|
+
subjectId: number | null;
|
|
178
|
+
subjectName: string | null;
|
|
167
179
|
statement: string;
|
|
180
|
+
explanation?: string | null;
|
|
168
181
|
points: number;
|
|
169
182
|
alternatives: ApiExamQuestionAlternative[];
|
|
170
183
|
fillBlankAnswers?: Array<{
|
|
@@ -188,8 +201,18 @@ type ApiExamQuestionsResponse = {
|
|
|
188
201
|
data: ApiExamQuestion[];
|
|
189
202
|
};
|
|
190
203
|
|
|
204
|
+
type ApiQuestionSubjectListResponse = {
|
|
205
|
+
data: AssuntoQuestaoOption[];
|
|
206
|
+
total: number;
|
|
207
|
+
page: number;
|
|
208
|
+
pageSize: number;
|
|
209
|
+
lastPage: number;
|
|
210
|
+
};
|
|
211
|
+
|
|
191
212
|
type QuestaoForm = {
|
|
213
|
+
subjectId: number;
|
|
192
214
|
enunciado: string;
|
|
215
|
+
explicacao?: string;
|
|
193
216
|
questionType: ExamQuestionType;
|
|
194
217
|
pontuacao: number;
|
|
195
218
|
};
|
|
@@ -204,7 +227,10 @@ function mapApiQuestion(question: ApiExamQuestion): Questao {
|
|
|
204
227
|
examQuestionId: question.examQuestionId,
|
|
205
228
|
order: question.order,
|
|
206
229
|
tipo: question.questionType,
|
|
230
|
+
assuntoId: question.subjectId,
|
|
231
|
+
assunto: question.subjectName,
|
|
207
232
|
enunciado: question.statement,
|
|
233
|
+
explicacao: question.explanation ?? '',
|
|
208
234
|
pontuacao: question.points,
|
|
209
235
|
alternativas: question.alternatives.map((alternative) => ({
|
|
210
236
|
id: alternative.id,
|
|
@@ -440,6 +466,11 @@ function SortableQuestao({
|
|
|
440
466
|
|
|
441
467
|
<div className="flex items-start justify-between gap-3">
|
|
442
468
|
<div className="mt-2 flex flex-wrap items-center gap-2">
|
|
469
|
+
{questao.assunto && (
|
|
470
|
+
<Badge variant="secondary" className="text-xs">
|
|
471
|
+
{questao.assunto}
|
|
472
|
+
</Badge>
|
|
473
|
+
)}
|
|
443
474
|
<Badge variant="outline" className="text-xs">
|
|
444
475
|
{t(`question.types.${questao.tipo}`)}
|
|
445
476
|
</Badge>
|
|
@@ -588,6 +619,9 @@ export default function QuestoesPage() {
|
|
|
588
619
|
);
|
|
589
620
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
590
621
|
const [questaoToDelete, setQuestaoToDelete] = useState<Questao | null>(null);
|
|
622
|
+
const [assuntosLocais, setAssuntosLocais] = useState<AssuntoQuestaoOption[]>(
|
|
623
|
+
[]
|
|
624
|
+
);
|
|
591
625
|
const [hasChanges, setHasChanges] = useState(false);
|
|
592
626
|
const [saving, setSaving] = useState(false);
|
|
593
627
|
const [buscaInput, setBuscaInput] = useState('');
|
|
@@ -608,7 +642,9 @@ export default function QuestoesPage() {
|
|
|
608
642
|
});
|
|
609
643
|
|
|
610
644
|
const questaoSchema = z.object({
|
|
645
|
+
subjectId: z.coerce.number().int().min(1, t('sheet.validation.subjectRequired')),
|
|
611
646
|
enunciado: z.string().min(5, t('sheet.validation.statementMin')),
|
|
647
|
+
explicacao: z.string().optional(),
|
|
612
648
|
questionType: z.enum([
|
|
613
649
|
'multiple_choice',
|
|
614
650
|
'true_false',
|
|
@@ -622,7 +658,9 @@ export default function QuestoesPage() {
|
|
|
622
658
|
const form = useForm<QuestaoForm>({
|
|
623
659
|
resolver: zodResolver(questaoSchema),
|
|
624
660
|
defaultValues: {
|
|
661
|
+
subjectId: 0,
|
|
625
662
|
enunciado: '',
|
|
663
|
+
explicacao: '',
|
|
626
664
|
questionType: 'multiple_choice',
|
|
627
665
|
pontuacao: 1,
|
|
628
666
|
},
|
|
@@ -701,6 +739,65 @@ export default function QuestoesPage() {
|
|
|
701
739
|
setCurrentPage(1);
|
|
702
740
|
}
|
|
703
741
|
|
|
742
|
+
|
|
743
|
+
async function loadQuestionSubjectOptions(args: {
|
|
744
|
+
page: number;
|
|
745
|
+
pageSize: number;
|
|
746
|
+
search: string;
|
|
747
|
+
}) {
|
|
748
|
+
const response = await request<ApiQuestionSubjectListResponse>({
|
|
749
|
+
url: '/lms/exams/question-subjects',
|
|
750
|
+
method: 'GET',
|
|
751
|
+
params: {
|
|
752
|
+
page: args.page,
|
|
753
|
+
pageSize: args.pageSize,
|
|
754
|
+
...(args.search ? { search: args.search } : {}),
|
|
755
|
+
},
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
const items = response.data?.data ?? [];
|
|
759
|
+
|
|
760
|
+
setAssuntosLocais((prev) => {
|
|
761
|
+
const merged = [...prev, ...items];
|
|
762
|
+
return merged.filter(
|
|
763
|
+
(item, index, arr) =>
|
|
764
|
+
arr.findIndex((candidate) => candidate.id === item.id) === index
|
|
765
|
+
);
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
return {
|
|
769
|
+
items,
|
|
770
|
+
hasMore: (response.data?.page ?? 1) < (response.data?.lastPage ?? 1),
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
async function createQuestionSubject(values: Record<string, string>) {
|
|
775
|
+
const name = values.name?.trim() ?? '';
|
|
776
|
+
|
|
777
|
+
if (!name) {
|
|
778
|
+
toast.error(t('toasts.subjectNameRequired'));
|
|
779
|
+
return null;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
const response = await request<AssuntoQuestaoOption>({
|
|
783
|
+
url: '/lms/exams/question-subjects',
|
|
784
|
+
method: 'POST',
|
|
785
|
+
data: { name },
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
const created = response.data;
|
|
789
|
+
|
|
790
|
+
if (created?.id) {
|
|
791
|
+
setAssuntosLocais((prev) =>
|
|
792
|
+
prev.some((item) => item.id === created.id) ? prev : [...prev, created]
|
|
793
|
+
);
|
|
794
|
+
toast.success(t('toasts.subjectCreated'));
|
|
795
|
+
return created;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
return null;
|
|
799
|
+
}
|
|
800
|
+
|
|
704
801
|
useEffect(() => {
|
|
705
802
|
if (currentPage > totalPages) {
|
|
706
803
|
setCurrentPage(totalPages);
|
|
@@ -786,7 +883,9 @@ export default function QuestoesPage() {
|
|
|
786
883
|
function openCreateSheet() {
|
|
787
884
|
setEditingQuestao(null);
|
|
788
885
|
form.reset({
|
|
886
|
+
subjectId: 0,
|
|
789
887
|
enunciado: '',
|
|
888
|
+
explicacao: '',
|
|
790
889
|
questionType: 'multiple_choice',
|
|
791
890
|
pontuacao: 1,
|
|
792
891
|
});
|
|
@@ -802,7 +901,9 @@ export default function QuestoesPage() {
|
|
|
802
901
|
function openEditSheet(questao: Questao) {
|
|
803
902
|
setEditingQuestao(questao);
|
|
804
903
|
form.reset({
|
|
904
|
+
subjectId: questao.assuntoId ?? 0,
|
|
805
905
|
enunciado: questao.enunciado,
|
|
906
|
+
explicacao: questao.explicacao,
|
|
806
907
|
questionType: questao.tipo,
|
|
807
908
|
pontuacao: questao.pontuacao,
|
|
808
909
|
});
|
|
@@ -967,7 +1068,9 @@ export default function QuestoesPage() {
|
|
|
967
1068
|
}
|
|
968
1069
|
|
|
969
1070
|
const payload = {
|
|
1071
|
+
subjectId: data.subjectId,
|
|
970
1072
|
statement: data.enunciado,
|
|
1073
|
+
explanation: data.explicacao?.trim() || null,
|
|
971
1074
|
questionType: data.questionType,
|
|
972
1075
|
points: Math.max(1, Math.round(data.pontuacao)),
|
|
973
1076
|
...(requiresAlternatives && {
|
|
@@ -1033,11 +1136,18 @@ export default function QuestoesPage() {
|
|
|
1033
1136
|
}
|
|
1034
1137
|
|
|
1035
1138
|
async function duplicateQuestao(questao: Questao) {
|
|
1139
|
+
if (!questao.assuntoId) {
|
|
1140
|
+
toast.error(t('toasts.subjectRequiredToDuplicate'));
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1036
1144
|
await request({
|
|
1037
|
-
url:
|
|
1145
|
+
url: '/lms/exams/' + examId + '/questions',
|
|
1038
1146
|
method: 'POST',
|
|
1039
1147
|
data: {
|
|
1040
|
-
|
|
1148
|
+
subjectId: questao.assuntoId,
|
|
1149
|
+
statement: questao.enunciado + t('copySuffix'),
|
|
1150
|
+
explanation: questao.explicacao?.trim() || null,
|
|
1041
1151
|
questionType: questao.tipo,
|
|
1042
1152
|
points: Math.max(1, Math.round(questao.pontuacao)),
|
|
1043
1153
|
...(OBJECTIVE_QUESTION_TYPES.includes(questao.tipo) && {
|
|
@@ -1346,6 +1456,7 @@ export default function QuestoesPage() {
|
|
|
1346
1456
|
<TableHeader>
|
|
1347
1457
|
<TableRow>
|
|
1348
1458
|
<TableHead>{t('table.headers.question')}</TableHead>
|
|
1459
|
+
<TableHead>{t('table.headers.subject')}</TableHead>
|
|
1349
1460
|
<TableHead>{t('table.headers.type')}</TableHead>
|
|
1350
1461
|
<TableHead className="text-right">
|
|
1351
1462
|
{t('table.headers.points')}
|
|
@@ -1366,6 +1477,7 @@ export default function QuestoesPage() {
|
|
|
1366
1477
|
</p>
|
|
1367
1478
|
</div>
|
|
1368
1479
|
</TableCell>
|
|
1480
|
+
<TableCell>{questao.assunto ?? '-'}</TableCell>
|
|
1369
1481
|
<TableCell>
|
|
1370
1482
|
<Badge variant="outline" className="text-xs">
|
|
1371
1483
|
{t(`question.types.${questao.tipo}`)}
|
|
@@ -1493,6 +1605,43 @@ export default function QuestoesPage() {
|
|
|
1493
1605
|
onSubmit={form.handleSubmit(onSubmit)}
|
|
1494
1606
|
className="flex flex-1 flex-col gap-5 px-4 pb-4"
|
|
1495
1607
|
>
|
|
1608
|
+
<FormField
|
|
1609
|
+
control={form.control}
|
|
1610
|
+
name="subjectId"
|
|
1611
|
+
render={({ field }) => (
|
|
1612
|
+
<FormItem>
|
|
1613
|
+
<FormLabel>{t('sheet.fields.subject')}</FormLabel>
|
|
1614
|
+
<FormControl>
|
|
1615
|
+
<EntityPicker<AssuntoQuestaoOption>
|
|
1616
|
+
value={field.value || null}
|
|
1617
|
+
valueType="number"
|
|
1618
|
+
placeholder={t('sheet.fields.subjectPlaceholder')}
|
|
1619
|
+
searchPlaceholder={t('sheet.fields.subjectSearchPlaceholder')}
|
|
1620
|
+
entityLabel={t('sheet.fields.subjectEntityLabel')}
|
|
1621
|
+
noResultsLabel={t('sheet.fields.subjectNoResults')}
|
|
1622
|
+
options={assuntosLocais}
|
|
1623
|
+
loadOptions={loadQuestionSubjectOptions}
|
|
1624
|
+
getOptionLabel={(option) => option.name}
|
|
1625
|
+
getOptionDescription={(option) => option.description ?? undefined}
|
|
1626
|
+
createTitle={t('sheet.fields.subjectCreateTitle')}
|
|
1627
|
+
createDescription={t('sheet.fields.subjectCreateDescription')}
|
|
1628
|
+
createFields={[
|
|
1629
|
+
{
|
|
1630
|
+
name: 'name',
|
|
1631
|
+
label: t('sheet.fields.subjectCreateNameLabel'),
|
|
1632
|
+
placeholder: t('sheet.fields.subjectCreateNamePlaceholder'),
|
|
1633
|
+
required: true,
|
|
1634
|
+
},
|
|
1635
|
+
]}
|
|
1636
|
+
onCreate={createQuestionSubject}
|
|
1637
|
+
onChange={(value) => field.onChange(Number(value ?? 0))}
|
|
1638
|
+
/>
|
|
1639
|
+
</FormControl>
|
|
1640
|
+
<FormMessage />
|
|
1641
|
+
</FormItem>
|
|
1642
|
+
)}
|
|
1643
|
+
/>
|
|
1644
|
+
|
|
1496
1645
|
<FormField
|
|
1497
1646
|
control={form.control}
|
|
1498
1647
|
name="enunciado"
|
|
@@ -1554,6 +1703,24 @@ export default function QuestoesPage() {
|
|
|
1554
1703
|
)}
|
|
1555
1704
|
/>
|
|
1556
1705
|
|
|
1706
|
+
<FormField
|
|
1707
|
+
control={form.control}
|
|
1708
|
+
name="explicacao"
|
|
1709
|
+
render={({ field }) => (
|
|
1710
|
+
<FormItem>
|
|
1711
|
+
<FormLabel>{t('sheet.fields.explanation')}</FormLabel>
|
|
1712
|
+
<FormControl>
|
|
1713
|
+
<RichTextEditor
|
|
1714
|
+
className="w-full max-w-full h-40"
|
|
1715
|
+
value={field.value ?? ''}
|
|
1716
|
+
onChange={field.onChange}
|
|
1717
|
+
/>
|
|
1718
|
+
</FormControl>
|
|
1719
|
+
<FormMessage />
|
|
1720
|
+
</FormItem>
|
|
1721
|
+
)}
|
|
1722
|
+
/>
|
|
1723
|
+
|
|
1557
1724
|
<FormField
|
|
1558
1725
|
control={form.control}
|
|
1559
1726
|
name="pontuacao"
|
|
@@ -82,7 +82,7 @@ import {
|
|
|
82
82
|
} from 'lucide-react';
|
|
83
83
|
import { useTranslations } from 'next-intl';
|
|
84
84
|
import { useRouter } from 'next/navigation';
|
|
85
|
-
import { useEffect, useMemo,
|
|
85
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
86
86
|
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
87
87
|
import { Controller, useForm, useWatch } from 'react-hook-form';
|
|
88
88
|
import { toast } from 'sonner';
|
|
@@ -94,9 +94,11 @@ interface Exame {
|
|
|
94
94
|
id: number;
|
|
95
95
|
codigo: string;
|
|
96
96
|
titulo: string;
|
|
97
|
+
nivel: 'beginner' | 'intermediate' | 'advanced';
|
|
97
98
|
notaMinima: number;
|
|
98
99
|
limiteTempo: number;
|
|
99
100
|
shuffle: boolean;
|
|
101
|
+
mostrarGabaritoAposConclusao: boolean;
|
|
100
102
|
status: 'publicado' | 'rascunho' | 'encerrado';
|
|
101
103
|
questoes: number;
|
|
102
104
|
realizacoes: number;
|
|
@@ -110,9 +112,11 @@ type ApiExame = {
|
|
|
110
112
|
id: number;
|
|
111
113
|
code: string;
|
|
112
114
|
title: string;
|
|
115
|
+
level: 'beginner' | 'intermediate' | 'advanced';
|
|
113
116
|
minScore: number;
|
|
114
117
|
timeLimit: number;
|
|
115
118
|
shuffle: boolean;
|
|
119
|
+
showAnswerKeyAfterFinish: boolean;
|
|
116
120
|
status: 'published' | 'draft' | 'closed' | 'archived';
|
|
117
121
|
questions: number;
|
|
118
122
|
attempts: number;
|
|
@@ -153,12 +157,14 @@ const API_EXAMS_CACHE_KEY = 'lms:exams:api-cache';
|
|
|
153
157
|
const createExameSchema = (t: (key: string) => string) =>
|
|
154
158
|
z.object({
|
|
155
159
|
titulo: z.string().min(3, t('form.validation.titleMinLength')),
|
|
160
|
+
nivel: z.enum(['beginner', 'intermediate', 'advanced']),
|
|
156
161
|
notaMinima: z.coerce
|
|
157
162
|
.number()
|
|
158
163
|
.min(0, t('form.validation.minScoreMin'))
|
|
159
164
|
.max(10, t('form.validation.minScoreMax')),
|
|
160
165
|
limiteTempo: z.coerce.number().min(1, t('form.validation.timeLimitMin')),
|
|
161
166
|
shuffle: z.boolean().default(false),
|
|
167
|
+
mostrarGabaritoAposConclusao: z.boolean().default(false),
|
|
162
168
|
status: z.string().min(1, t('form.validation.statusRequired')),
|
|
163
169
|
primaryColor: z
|
|
164
170
|
.string()
|
|
@@ -190,9 +196,11 @@ function mapApiExame(exame: ApiExame): Exame {
|
|
|
190
196
|
id: exame.id,
|
|
191
197
|
codigo: exame.code,
|
|
192
198
|
titulo: exame.title,
|
|
199
|
+
nivel: exame.level,
|
|
193
200
|
notaMinima: exame.minScore,
|
|
194
201
|
limiteTempo: exame.timeLimit,
|
|
195
202
|
shuffle: exame.shuffle,
|
|
203
|
+
mostrarGabaritoAposConclusao: Boolean(exame.showAnswerKeyAfterFinish),
|
|
196
204
|
status: toPtStatus(exame.status),
|
|
197
205
|
questoes: exame.questions,
|
|
198
206
|
realizacoes: exame.attempts,
|
|
@@ -268,18 +276,15 @@ export default function ExamesPage() {
|
|
|
268
276
|
allowedValues: PAGE_SIZES,
|
|
269
277
|
});
|
|
270
278
|
|
|
271
|
-
// Double-click tracking
|
|
272
|
-
const clickTimers = useRef<Map<number, ReturnType<typeof setTimeout>>>(
|
|
273
|
-
new Map()
|
|
274
|
-
);
|
|
275
|
-
|
|
276
279
|
const form = useForm<ExameForm>({
|
|
277
280
|
resolver: zodResolver(exameSchema),
|
|
278
281
|
defaultValues: {
|
|
279
282
|
titulo: '',
|
|
283
|
+
nivel: 'beginner',
|
|
280
284
|
notaMinima: 7,
|
|
281
285
|
limiteTempo: 60,
|
|
282
286
|
shuffle: true,
|
|
287
|
+
mostrarGabaritoAposConclusao: false,
|
|
283
288
|
status: 'rascunho',
|
|
284
289
|
primaryColor: '#1D4ED8',
|
|
285
290
|
secondaryColor: '#111827',
|
|
@@ -365,11 +370,18 @@ export default function ExamesPage() {
|
|
|
365
370
|
watchedFormValues.notaMinima,
|
|
366
371
|
editingExame.notaMinima
|
|
367
372
|
),
|
|
373
|
+
nivel:
|
|
374
|
+
watchedFormValues.nivel === undefined
|
|
375
|
+
? editingExame.nivel
|
|
376
|
+
: watchedFormValues.nivel,
|
|
368
377
|
limiteTempo: toNumberOrFallback(
|
|
369
378
|
watchedFormValues.limiteTempo,
|
|
370
379
|
editingExame.limiteTempo
|
|
371
380
|
),
|
|
372
381
|
shuffle: watchedFormValues.shuffle ?? editingExame.shuffle,
|
|
382
|
+
mostrarGabaritoAposConclusao:
|
|
383
|
+
watchedFormValues.mostrarGabaritoAposConclusao ??
|
|
384
|
+
editingExame.mostrarGabaritoAposConclusao,
|
|
373
385
|
status:
|
|
374
386
|
(watchedFormValues.status as Exame['status'] | undefined) ??
|
|
375
387
|
editingExame.status,
|
|
@@ -421,29 +433,17 @@ export default function ExamesPage() {
|
|
|
421
433
|
setDeleteDialogOpen(true);
|
|
422
434
|
}
|
|
423
435
|
|
|
424
|
-
// ── Double-click ──────────────────────────────────────────────────────────
|
|
425
|
-
|
|
426
|
-
function handleCardClick(exame: Exame) {
|
|
427
|
-
const existing = clickTimers.current.get(exame.id);
|
|
428
|
-
if (existing) {
|
|
429
|
-
clearTimeout(existing);
|
|
430
|
-
clickTimers.current.delete(exame.id);
|
|
431
|
-
router.push(`/lms/exams/${exame.id}/questions`);
|
|
432
|
-
} else {
|
|
433
|
-
const t = setTimeout(() => clickTimers.current.delete(exame.id), 300);
|
|
434
|
-
clickTimers.current.set(exame.id, t);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
436
|
// ── CRUD ──────────────────────────────────────────────────────────────────
|
|
439
437
|
|
|
440
438
|
function openCreateSheet() {
|
|
441
439
|
setEditingExame(null);
|
|
442
440
|
form.reset({
|
|
443
441
|
titulo: '',
|
|
442
|
+
nivel: 'beginner',
|
|
444
443
|
notaMinima: 7,
|
|
445
444
|
limiteTempo: 60,
|
|
446
445
|
shuffle: true,
|
|
446
|
+
mostrarGabaritoAposConclusao: false,
|
|
447
447
|
status: 'rascunho',
|
|
448
448
|
primaryColor: '#1D4ED8',
|
|
449
449
|
secondaryColor: '#111827',
|
|
@@ -456,9 +456,11 @@ export default function ExamesPage() {
|
|
|
456
456
|
setEditingExame(exame);
|
|
457
457
|
form.reset({
|
|
458
458
|
titulo: exame.titulo,
|
|
459
|
+
nivel: exame.nivel,
|
|
459
460
|
notaMinima: exame.notaMinima,
|
|
460
461
|
limiteTempo: exame.limiteTempo,
|
|
461
462
|
shuffle: exame.shuffle,
|
|
463
|
+
mostrarGabaritoAposConclusao: exame.mostrarGabaritoAposConclusao,
|
|
462
464
|
status: exame.status,
|
|
463
465
|
primaryColor: exame.primaryColor ?? '#1D4ED8',
|
|
464
466
|
secondaryColor: exame.secondaryColor ?? '#111827',
|
|
@@ -471,9 +473,11 @@ export default function ExamesPage() {
|
|
|
471
473
|
try {
|
|
472
474
|
const payload = {
|
|
473
475
|
title: data.titulo,
|
|
476
|
+
level: data.nivel,
|
|
474
477
|
minScore: data.notaMinima,
|
|
475
478
|
timeLimit: data.limiteTempo,
|
|
476
479
|
shuffle: data.shuffle,
|
|
480
|
+
showAnswerKeyAfterFinish: data.mostrarGabaritoAposConclusao,
|
|
477
481
|
status: toApiStatus(data.status),
|
|
478
482
|
primaryColor: data.primaryColor,
|
|
479
483
|
secondaryColor: data.secondaryColor,
|
|
@@ -783,7 +787,7 @@ export default function ExamesPage() {
|
|
|
783
787
|
<motion.div key={exame.id} variants={fadeUp}>
|
|
784
788
|
<Card
|
|
785
789
|
className="group relative h-95 cursor-pointer overflow-hidden border-border/70 shadow-sm transition-all duration-200 hover:border-border hover:shadow-md"
|
|
786
|
-
|
|
790
|
+
onDoubleClick={() => openEditSheet(exame)}
|
|
787
791
|
title={t('cards.tooltip')}
|
|
788
792
|
>
|
|
789
793
|
<div
|
|
@@ -962,7 +966,7 @@ export default function ExamesPage() {
|
|
|
962
966
|
<TableRow
|
|
963
967
|
key={exame.id}
|
|
964
968
|
className="cursor-pointer"
|
|
965
|
-
|
|
969
|
+
onDoubleClick={() => openEditSheet(exame)}
|
|
966
970
|
title={t('cards.tooltip')}
|
|
967
971
|
>
|
|
968
972
|
<TableCell>
|
|
@@ -1114,6 +1118,37 @@ export default function ExamesPage() {
|
|
|
1114
1118
|
<FieldError>{form.formState.errors.titulo?.message}</FieldError>
|
|
1115
1119
|
</Field>
|
|
1116
1120
|
<div className="grid grid-cols-2 gap-4">
|
|
1121
|
+
<Field>
|
|
1122
|
+
<FieldLabel>
|
|
1123
|
+
{t('form.fields.level.label')}{' '}
|
|
1124
|
+
<span className="text-destructive">*</span>
|
|
1125
|
+
</FieldLabel>
|
|
1126
|
+
<Controller
|
|
1127
|
+
name="nivel"
|
|
1128
|
+
control={form.control}
|
|
1129
|
+
render={({ field }) => (
|
|
1130
|
+
<Select onValueChange={field.onChange} value={field.value}>
|
|
1131
|
+
<SelectTrigger>
|
|
1132
|
+
<SelectValue
|
|
1133
|
+
placeholder={t('form.fields.level.placeholder')}
|
|
1134
|
+
/>
|
|
1135
|
+
</SelectTrigger>
|
|
1136
|
+
<SelectContent>
|
|
1137
|
+
<SelectItem value="beginner">
|
|
1138
|
+
{t('form.fields.level.options.beginner')}
|
|
1139
|
+
</SelectItem>
|
|
1140
|
+
<SelectItem value="intermediate">
|
|
1141
|
+
{t('form.fields.level.options.intermediate')}
|
|
1142
|
+
</SelectItem>
|
|
1143
|
+
<SelectItem value="advanced">
|
|
1144
|
+
{t('form.fields.level.options.advanced')}
|
|
1145
|
+
</SelectItem>
|
|
1146
|
+
</SelectContent>
|
|
1147
|
+
</Select>
|
|
1148
|
+
)}
|
|
1149
|
+
/>
|
|
1150
|
+
<FieldError>{form.formState.errors.nivel?.message}</FieldError>
|
|
1151
|
+
</Field>
|
|
1117
1152
|
<Field>
|
|
1118
1153
|
<FieldLabel htmlFor="notaMinima">
|
|
1119
1154
|
{t('form.fields.minScore.label')}{' '}
|
|
@@ -1261,6 +1296,26 @@ export default function ExamesPage() {
|
|
|
1261
1296
|
)}
|
|
1262
1297
|
/>
|
|
1263
1298
|
</label>
|
|
1299
|
+
<label className="flex cursor-pointer items-center justify-between rounded-lg border p-3 hover:bg-muted">
|
|
1300
|
+
<div>
|
|
1301
|
+
<p className="text-sm font-medium">
|
|
1302
|
+
{t('form.fields.showAnswerKeyAfterFinish.label')}
|
|
1303
|
+
</p>
|
|
1304
|
+
<p className="text-xs text-muted-foreground">
|
|
1305
|
+
{t('form.fields.showAnswerKeyAfterFinish.description')}
|
|
1306
|
+
</p>
|
|
1307
|
+
</div>
|
|
1308
|
+
<Controller
|
|
1309
|
+
name="mostrarGabaritoAposConclusao"
|
|
1310
|
+
control={form.control}
|
|
1311
|
+
render={({ field }) => (
|
|
1312
|
+
<Switch
|
|
1313
|
+
checked={field.value}
|
|
1314
|
+
onCheckedChange={field.onChange}
|
|
1315
|
+
/>
|
|
1316
|
+
)}
|
|
1317
|
+
/>
|
|
1318
|
+
</label>
|
|
1264
1319
|
<SheetFooter className="mt-auto shrink-0 gap-2 pt-4 px-0">
|
|
1265
1320
|
<Button type="submit" disabled={saving} className="gap-2">
|
|
1266
1321
|
{saving && <Loader2 className="size-4 animate-spin" />}
|
|
@@ -591,11 +591,6 @@ export default function TrainingPage() {
|
|
|
591
591
|
allowedValues: PAGE_SIZES,
|
|
592
592
|
});
|
|
593
593
|
|
|
594
|
-
// Double-click tracking
|
|
595
|
-
const clickTimers = useRef<Map<number, ReturnType<typeof setTimeout>>>(
|
|
596
|
-
new Map()
|
|
597
|
-
);
|
|
598
|
-
|
|
599
594
|
const sensors = useSensors(
|
|
600
595
|
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
|
|
601
596
|
useSensor(KeyboardSensor, {
|
|
@@ -961,23 +956,6 @@ export default function TrainingPage() {
|
|
|
961
956
|
setDeleteDialogOpen(true);
|
|
962
957
|
}
|
|
963
958
|
|
|
964
|
-
// ── Double-click ──────────────────────────────────────────────────────────
|
|
965
|
-
|
|
966
|
-
function handleCardClick(formacao: Formacao) {
|
|
967
|
-
const existing = clickTimers.current.get(formacao.id);
|
|
968
|
-
if (existing) {
|
|
969
|
-
clearTimeout(existing);
|
|
970
|
-
clickTimers.current.delete(formacao.id);
|
|
971
|
-
// Toast message for opening would go here if integrated
|
|
972
|
-
} else {
|
|
973
|
-
const timer = setTimeout(
|
|
974
|
-
() => clickTimers.current.delete(formacao.id),
|
|
975
|
-
300
|
|
976
|
-
);
|
|
977
|
-
clickTimers.current.set(formacao.id, timer);
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
|
|
981
959
|
// ── CRUD ──────────────────────────────────────────────────────────────────
|
|
982
960
|
|
|
983
961
|
function openCreateSheet() {
|
|
@@ -1318,11 +1296,15 @@ export default function TrainingPage() {
|
|
|
1318
1296
|
data.tituloComercial || data.nomeInterno
|
|
1319
1297
|
),
|
|
1320
1298
|
slug,
|
|
1299
|
+
name: data.nomeInterno.trim() || undefined,
|
|
1321
1300
|
title: data.tituloComercial,
|
|
1322
1301
|
description: data.descricao,
|
|
1323
1302
|
level: ptLevelToApi(data.nivel),
|
|
1324
1303
|
status: courseStatusToApi(data.status),
|
|
1325
1304
|
categorySlugs,
|
|
1305
|
+
operationsProjectId: data.operationsProjectId
|
|
1306
|
+
? Number(data.operationsProjectId)
|
|
1307
|
+
: null,
|
|
1326
1308
|
},
|
|
1327
1309
|
});
|
|
1328
1310
|
|
|
@@ -1664,7 +1646,7 @@ export default function TrainingPage() {
|
|
|
1664
1646
|
<motion.div key={formacao.id} variants={fadeUp}>
|
|
1665
1647
|
<Card
|
|
1666
1648
|
className="group relative flex min-h-60 max-h-67.5 cursor-pointer flex-col overflow-hidden border-border/70 py-0 shadow-sm transition-all duration-200 hover:border-border hover:shadow-md"
|
|
1667
|
-
|
|
1649
|
+
onDoubleClick={() => openEditSheet(formacao)}
|
|
1668
1650
|
title={t('cards.tooltip')}
|
|
1669
1651
|
>
|
|
1670
1652
|
<div
|
|
@@ -1806,7 +1788,7 @@ export default function TrainingPage() {
|
|
|
1806
1788
|
<TableRow
|
|
1807
1789
|
key={formacao.id}
|
|
1808
1790
|
className="cursor-pointer"
|
|
1809
|
-
|
|
1791
|
+
onDoubleClick={() => openEditSheet(formacao)}
|
|
1810
1792
|
title={t('cards.tooltip')}
|
|
1811
1793
|
>
|
|
1812
1794
|
<TableCell>
|