@hed-hog/lms 0.0.347 → 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.controller.d.ts +3 -3
- 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 +6 -4
- 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.controller.d.ts +2 -2
- 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-admin.service.d.ts +2 -2
- 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.controller.d.ts +4 -4
- 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/evaluation/evaluation.service.d.ts +4 -4
- 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 +7 -7
- 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
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
Plus,
|
|
22
22
|
Trash2,
|
|
23
23
|
} from 'lucide-react';
|
|
24
|
+
import { useTranslations } from 'next-intl';
|
|
24
25
|
import { toast } from 'sonner';
|
|
25
26
|
|
|
26
27
|
import {
|
|
@@ -53,6 +54,7 @@ interface TreeContextMenuProps {
|
|
|
53
54
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
54
55
|
|
|
55
56
|
function CourseMenu({ data }: { data: Course }) {
|
|
57
|
+
const t = useTranslations('lms.CoursesPage.StructurePage');
|
|
56
58
|
const expandAll = useStructureStore((s) => s.expandAll);
|
|
57
59
|
const collapseAll = useStructureStore((s) => s.collapseAll);
|
|
58
60
|
const copiedType = useStructureStore((s) => s.copiedType);
|
|
@@ -80,7 +82,7 @@ function CourseMenu({ data }: { data: Course }) {
|
|
|
80
82
|
) : (
|
|
81
83
|
<Plus className="size-3.5 mr-2 text-muted-foreground" />
|
|
82
84
|
)}
|
|
83
|
-
|
|
85
|
+
{t('contextMenu.addSession')}
|
|
84
86
|
</ContextMenuItem>
|
|
85
87
|
|
|
86
88
|
<ContextMenuSeparator />
|
|
@@ -92,7 +94,7 @@ function CourseMenu({ data }: { data: Course }) {
|
|
|
92
94
|
}}
|
|
93
95
|
>
|
|
94
96
|
<BookOpen className="size-3.5 mr-2 text-muted-foreground" />
|
|
95
|
-
|
|
97
|
+
{t('tree.expandAll')}
|
|
96
98
|
</ContextMenuItem>
|
|
97
99
|
|
|
98
100
|
<ContextMenuItem
|
|
@@ -102,7 +104,7 @@ function CourseMenu({ data }: { data: Course }) {
|
|
|
102
104
|
}}
|
|
103
105
|
>
|
|
104
106
|
<Layers className="size-3.5 mr-2 text-muted-foreground" />
|
|
105
|
-
|
|
107
|
+
{t('tree.collapseAll')}
|
|
106
108
|
</ContextMenuItem>
|
|
107
109
|
|
|
108
110
|
{hasSessionClipboard && (
|
|
@@ -119,7 +121,8 @@ function CourseMenu({ data }: { data: Course }) {
|
|
|
119
121
|
) : (
|
|
120
122
|
<Clipboard className="size-3.5 mr-2 text-muted-foreground" />
|
|
121
123
|
)}
|
|
122
|
-
|
|
124
|
+
{t('contextMenu.pasteSession')}
|
|
125
|
+
{copiedIds.length > 1 ? ` (${copiedIds.length})` : ''}
|
|
123
126
|
</ContextMenuItem>
|
|
124
127
|
</>
|
|
125
128
|
)}
|
|
@@ -523,3 +526,102 @@ export function TreeContextMenu({ item, children }: TreeContextMenuProps) {
|
|
|
523
526
|
</ContextMenu>
|
|
524
527
|
);
|
|
525
528
|
}
|
|
529
|
+
|
|
530
|
+
export function TreeRootContextMenu({
|
|
531
|
+
children,
|
|
532
|
+
}: {
|
|
533
|
+
children: React.ReactNode;
|
|
534
|
+
}) {
|
|
535
|
+
const t = useTranslations('lms.CoursesPage.StructurePage');
|
|
536
|
+
const course = useStructureStore((s) => s.course);
|
|
537
|
+
const activeItemId = useStructureStore((s) => s.activeItemId);
|
|
538
|
+
const activeItemType = useStructureStore((s) => s.activeItemType);
|
|
539
|
+
const lessons = useStructureStore((s) => s.lessons);
|
|
540
|
+
const copiedType = useStructureStore((s) => s.copiedType);
|
|
541
|
+
const copiedIds = useStructureStore((s) => s.copiedIds);
|
|
542
|
+
|
|
543
|
+
const createSessionMutation = useCreateSessionMutation();
|
|
544
|
+
const pasteSessionsMutation = usePasteSessionsMutation();
|
|
545
|
+
const pasteLessonsMutation = usePasteLessonsMutation();
|
|
546
|
+
|
|
547
|
+
const hasSessionClipboard = copiedType === 'session' && copiedIds.length > 0;
|
|
548
|
+
const hasLessonClipboard = copiedType === 'lesson' && copiedIds.length > 0;
|
|
549
|
+
|
|
550
|
+
function getActiveSessionId(): string | null {
|
|
551
|
+
if (activeItemType === 'session' && activeItemId) return activeItemId;
|
|
552
|
+
if (activeItemType === 'lesson' && activeItemId) {
|
|
553
|
+
const lesson = lessons.find((item) => item.id === activeItemId);
|
|
554
|
+
return lesson?.sessionId ?? null;
|
|
555
|
+
}
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return (
|
|
560
|
+
<ContextMenu>
|
|
561
|
+
<ContextMenuTrigger className="block h-full w-full">
|
|
562
|
+
{children}
|
|
563
|
+
</ContextMenuTrigger>
|
|
564
|
+
<ContextMenuContent className="w-56">
|
|
565
|
+
<ContextMenuLabel className="text-[0.65rem] text-muted-foreground px-2 py-1">
|
|
566
|
+
{course.title || course.name || t('contextMenu.courseFallback')}
|
|
567
|
+
</ContextMenuLabel>
|
|
568
|
+
<ContextMenuSeparator />
|
|
569
|
+
|
|
570
|
+
<ContextMenuItem
|
|
571
|
+
disabled={createSessionMutation.isPending}
|
|
572
|
+
onSelect={() => createSessionMutation.mutate()}
|
|
573
|
+
>
|
|
574
|
+
{createSessionMutation.isPending ? (
|
|
575
|
+
<Loader2 className="size-3.5 mr-2 animate-spin" />
|
|
576
|
+
) : (
|
|
577
|
+
<Plus className="size-3.5 mr-2 text-muted-foreground" />
|
|
578
|
+
)}
|
|
579
|
+
{t('contextMenu.addSession')}
|
|
580
|
+
</ContextMenuItem>
|
|
581
|
+
|
|
582
|
+
{hasSessionClipboard && (
|
|
583
|
+
<ContextMenuItem
|
|
584
|
+
disabled={pasteSessionsMutation.isPending}
|
|
585
|
+
onSelect={() => {
|
|
586
|
+
pasteSessionsMutation.mutate({ sessionIds: copiedIds });
|
|
587
|
+
}}
|
|
588
|
+
>
|
|
589
|
+
{pasteSessionsMutation.isPending ? (
|
|
590
|
+
<Loader2 className="size-3.5 mr-2 animate-spin" />
|
|
591
|
+
) : (
|
|
592
|
+
<Clipboard className="size-3.5 mr-2 text-muted-foreground" />
|
|
593
|
+
)}
|
|
594
|
+
{t('contextMenu.pasteSession')}
|
|
595
|
+
{copiedIds.length > 1 ? ` (${copiedIds.length})` : ''}
|
|
596
|
+
</ContextMenuItem>
|
|
597
|
+
)}
|
|
598
|
+
|
|
599
|
+
{hasLessonClipboard && (
|
|
600
|
+
<ContextMenuItem
|
|
601
|
+
disabled={pasteLessonsMutation.isPending}
|
|
602
|
+
onSelect={() => {
|
|
603
|
+
const targetSessionId = getActiveSessionId();
|
|
604
|
+
if (!targetSessionId) {
|
|
605
|
+
toast.error(t('contextMenu.selectSessionToPasteLessons'));
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
pasteLessonsMutation.mutate({
|
|
609
|
+
targetSessionId,
|
|
610
|
+
lessonIds: copiedIds,
|
|
611
|
+
});
|
|
612
|
+
}}
|
|
613
|
+
>
|
|
614
|
+
{pasteLessonsMutation.isPending ? (
|
|
615
|
+
<Loader2 className="size-3.5 mr-2 animate-spin" />
|
|
616
|
+
) : (
|
|
617
|
+
<Clipboard className="size-3.5 mr-2 text-muted-foreground" />
|
|
618
|
+
)}
|
|
619
|
+
{copiedIds.length > 1
|
|
620
|
+
? t('contextMenu.pasteLessons', { count: copiedIds.length })
|
|
621
|
+
: t('contextMenu.pasteLesson')}
|
|
622
|
+
</ContextMenuItem>
|
|
623
|
+
)}
|
|
624
|
+
</ContextMenuContent>
|
|
625
|
+
</ContextMenu>
|
|
626
|
+
);
|
|
627
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
4
4
|
|
|
5
5
|
export type LessonType = 'video' | 'questao' | 'post' | 'exercicio';
|
|
6
|
-
export type VideoProvider = 'youtube' | 'vimeo' | '
|
|
6
|
+
export type VideoProvider = 'youtube' | 'vimeo' | 'file_storage';
|
|
7
7
|
export type ItemType = 'course' | 'session' | 'lesson';
|
|
8
8
|
|
|
9
9
|
export type LessonStatus =
|
|
@@ -24,6 +24,7 @@ export interface Course {
|
|
|
24
24
|
title: string;
|
|
25
25
|
description: string;
|
|
26
26
|
slug: string;
|
|
27
|
+
offeringType?: 'scheduled' | 'on_demand' | 'blended';
|
|
27
28
|
published: boolean;
|
|
28
29
|
}
|
|
29
30
|
|
package/hedhog/frontend/app/courses/[id]/structure/_data/adapters/course-structure.adapter.ts.ejs
CHANGED
|
@@ -61,6 +61,15 @@ function normalizeLessonType(tipo: ApiLesson['tipo']): LessonType {
|
|
|
61
61
|
return tipo as LessonType;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
function normalizeVideoProvider(
|
|
65
|
+
provider?: ApiLesson['videoProvedor']
|
|
66
|
+
): Lesson['videoProvider'] {
|
|
67
|
+
if (provider === 'youtube' || provider === 'vimeo') return provider;
|
|
68
|
+
if (provider === 'file_storage') return 'file_storage';
|
|
69
|
+
if (provider === 'bunny' || provider === 'custom') return 'file_storage';
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
|
|
64
73
|
/** Normalize a raw API resource to the frontend Resource shape. */
|
|
65
74
|
function normalizeResource(raw: ApiLessonResource): Resource {
|
|
66
75
|
return {
|
|
@@ -96,6 +105,7 @@ export function normalizeCourse(raw: ApiCourse): Course {
|
|
|
96
105
|
title: raw.titulo,
|
|
97
106
|
description: raw.descricao,
|
|
98
107
|
slug: raw.slug,
|
|
108
|
+
offeringType: raw.offeringType,
|
|
99
109
|
published: false,
|
|
100
110
|
};
|
|
101
111
|
}
|
|
@@ -149,7 +159,7 @@ export function normalizeLesson(raw: ApiLesson, order = 0): Lesson {
|
|
|
149
159
|
duration: raw.duracao,
|
|
150
160
|
sessionId: raw.sessaoId,
|
|
151
161
|
order,
|
|
152
|
-
videoProvider: raw.videoProvedor,
|
|
162
|
+
videoProvider: normalizeVideoProvider(raw.videoProvedor),
|
|
153
163
|
videoUrl: raw.videoUrl,
|
|
154
164
|
autoDuration: raw.duracaoAutomatica,
|
|
155
165
|
transcription: raw.transcricao,
|
package/hedhog/frontend/app/courses/[id]/structure/_data/services/course-structure.service.ts.ejs
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import type {
|
|
24
|
+
ApiCourseResource,
|
|
24
25
|
ApiCreateLessonPayload,
|
|
25
26
|
ApiCreateSessionPayload,
|
|
26
27
|
ApiDuplicateSessionResponse,
|
|
@@ -107,6 +108,47 @@ export async function getCourseStructure(
|
|
|
107
108
|
return extractData<ApiGetStructureResponse>(response);
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
/**
|
|
112
|
+
* GET /lms/courses/:courseId/structure/resources
|
|
113
|
+
*
|
|
114
|
+
* Lists resources attached directly to the course (not tied to lessons).
|
|
115
|
+
*/
|
|
116
|
+
export async function getCourseResources(
|
|
117
|
+
request: RequestFn,
|
|
118
|
+
courseId: string | number
|
|
119
|
+
): Promise<ApiCourseResource[]> {
|
|
120
|
+
const response = await request({
|
|
121
|
+
url: `${STRUCTURE_BASE(courseId)}/resources`,
|
|
122
|
+
method: 'GET',
|
|
123
|
+
});
|
|
124
|
+
return extractData<ApiCourseResource[]>(response);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* PATCH /lms/courses/:courseId/structure/resources
|
|
129
|
+
*
|
|
130
|
+
* Replaces the full set of course-level resources.
|
|
131
|
+
*/
|
|
132
|
+
export async function updateCourseResources(
|
|
133
|
+
request: RequestFn,
|
|
134
|
+
courseId: string | number,
|
|
135
|
+
payload: {
|
|
136
|
+
recursos: Array<{
|
|
137
|
+
nome: string;
|
|
138
|
+
fileId?: number;
|
|
139
|
+
tipo?: string;
|
|
140
|
+
publico?: boolean;
|
|
141
|
+
}>;
|
|
142
|
+
}
|
|
143
|
+
): Promise<ApiCourseResource[]> {
|
|
144
|
+
const response = await request({
|
|
145
|
+
url: `${STRUCTURE_BASE(courseId)}/resources`,
|
|
146
|
+
method: 'PATCH',
|
|
147
|
+
data: payload,
|
|
148
|
+
});
|
|
149
|
+
return extractData<ApiCourseResource[]>(response);
|
|
150
|
+
}
|
|
151
|
+
|
|
110
152
|
/**
|
|
111
153
|
* PATCH /lms/courses/:courseId
|
|
112
154
|
*
|
|
@@ -391,11 +433,12 @@ export async function pasteLessons(
|
|
|
391
433
|
*/
|
|
392
434
|
export async function uploadFile(
|
|
393
435
|
request: RequestFn,
|
|
394
|
-
file: File
|
|
436
|
+
file: File,
|
|
437
|
+
destination = 'lms/lessons'
|
|
395
438
|
): Promise<{ id: number; filename: string }> {
|
|
396
439
|
const formData = new FormData();
|
|
397
440
|
formData.append('file', file);
|
|
398
|
-
formData.append('destination',
|
|
441
|
+
formData.append('destination', destination);
|
|
399
442
|
|
|
400
443
|
const response = await request({
|
|
401
444
|
url: '/file',
|
|
@@ -407,14 +450,18 @@ export async function uploadFile(
|
|
|
407
450
|
}
|
|
408
451
|
|
|
409
452
|
/**
|
|
410
|
-
* DELETE /file
|
|
453
|
+
* DELETE /file
|
|
411
454
|
*
|
|
412
|
-
* Permanently deletes
|
|
413
|
-
* Called when the user removes a resource from
|
|
455
|
+
* Permanently deletes stored files by ID list.
|
|
456
|
+
* Called when the user removes a resource from lesson/course.
|
|
414
457
|
*/
|
|
415
458
|
export async function deleteFile(
|
|
416
459
|
request: RequestFn,
|
|
417
460
|
fileId: number
|
|
418
461
|
): Promise<void> {
|
|
419
|
-
await request({
|
|
462
|
+
await request({
|
|
463
|
+
url: '/file',
|
|
464
|
+
method: 'DELETE',
|
|
465
|
+
data: { ids: [fileId] },
|
|
466
|
+
});
|
|
420
467
|
}
|
|
@@ -31,6 +31,15 @@ export interface ApiLessonResource {
|
|
|
31
31
|
url?: string;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/** Resource (arquivo de suporte) attached directly to a course. */
|
|
35
|
+
export interface ApiCourseResource {
|
|
36
|
+
id: number;
|
|
37
|
+
nome: string;
|
|
38
|
+
fileId?: number | null;
|
|
39
|
+
tipo?: string | null;
|
|
40
|
+
publico?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
34
43
|
/** Instructor linked to a lesson or available in the course pool. */
|
|
35
44
|
export interface ApiLessonInstructor {
|
|
36
45
|
id: number;
|
|
@@ -63,7 +72,7 @@ export interface ApiLesson {
|
|
|
63
72
|
duracao: number;
|
|
64
73
|
/** ID of the parent session (course_module). */
|
|
65
74
|
sessaoId: string;
|
|
66
|
-
videoProvedor?: 'youtube' | 'vimeo' | 'bunny' | 'custom';
|
|
75
|
+
videoProvedor?: 'youtube' | 'vimeo' | 'file_storage' | 'bunny' | 'custom';
|
|
67
76
|
videoUrl?: string;
|
|
68
77
|
duracaoAutomatica?: boolean;
|
|
69
78
|
transcricao?: string;
|
|
@@ -105,6 +114,8 @@ export interface ApiCourse {
|
|
|
105
114
|
slug: string;
|
|
106
115
|
titulo: string;
|
|
107
116
|
descricao: string;
|
|
117
|
+
offeringType?: 'scheduled' | 'on_demand' | 'blended';
|
|
118
|
+
recursos?: ApiCourseResource[];
|
|
108
119
|
}
|
|
109
120
|
|
|
110
121
|
/**
|
|
@@ -173,7 +184,7 @@ export interface ApiCreateLessonPayload {
|
|
|
173
184
|
duracao: number;
|
|
174
185
|
descricaoPublica?: string;
|
|
175
186
|
descricaoPrivada?: string;
|
|
176
|
-
videoProvedor?: 'youtube' | 'vimeo' | 'bunny' | 'custom';
|
|
187
|
+
videoProvedor?: 'youtube' | 'vimeo' | 'file_storage' | 'bunny' | 'custom';
|
|
177
188
|
videoUrl?: string;
|
|
178
189
|
duracaoAutomatica?: boolean;
|
|
179
190
|
transcricao?: string;
|
|
@@ -27,8 +27,18 @@ import {
|
|
|
27
27
|
DropdownMenuSeparator,
|
|
28
28
|
DropdownMenuTrigger,
|
|
29
29
|
} from '@/components/ui/dropdown-menu';
|
|
30
|
+
import { Input } from '@/components/ui/input';
|
|
30
31
|
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
32
|
+
import { Label } from '@/components/ui/label';
|
|
31
33
|
import { Separator } from '@/components/ui/separator';
|
|
34
|
+
import {
|
|
35
|
+
Sheet,
|
|
36
|
+
SheetContent,
|
|
37
|
+
SheetDescription,
|
|
38
|
+
SheetFooter,
|
|
39
|
+
SheetHeader,
|
|
40
|
+
SheetTitle,
|
|
41
|
+
} from '@/components/ui/sheet';
|
|
32
42
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
33
43
|
import {
|
|
34
44
|
Table,
|
|
@@ -38,6 +48,7 @@ import {
|
|
|
38
48
|
TableHeader,
|
|
39
49
|
TableRow,
|
|
40
50
|
} from '@/components/ui/table';
|
|
51
|
+
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
41
52
|
import { usePersistedViewMode } from '@/hooks/use-persisted-view-mode';
|
|
42
53
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
43
54
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
@@ -59,8 +70,7 @@ import {
|
|
|
59
70
|
} from 'lucide-react';
|
|
60
71
|
import { useTranslations } from 'next-intl';
|
|
61
72
|
import { useRouter } from 'next/navigation';
|
|
62
|
-
import { useEffect, useMemo,
|
|
63
|
-
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
73
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
64
74
|
import { useForm, useWatch } from 'react-hook-form';
|
|
65
75
|
import { toast } from 'sonner';
|
|
66
76
|
import { CourseAvatar } from '../_components/course-avatar';
|
|
@@ -93,6 +103,7 @@ interface Curso {
|
|
|
93
103
|
alunosInscritos: number;
|
|
94
104
|
criadoEm: string;
|
|
95
105
|
logoFileId?: number | null;
|
|
106
|
+
operationsProjectId?: number | null;
|
|
96
107
|
}
|
|
97
108
|
|
|
98
109
|
type ApiCourse = {
|
|
@@ -114,6 +125,7 @@ type ApiCourse = {
|
|
|
114
125
|
enrollmentCount: number;
|
|
115
126
|
createdAt: string;
|
|
116
127
|
logoFileId?: number | null;
|
|
128
|
+
operationsProjectId?: number | null;
|
|
117
129
|
};
|
|
118
130
|
|
|
119
131
|
type ApiCourseList = {
|
|
@@ -218,6 +230,7 @@ function mapApiCourse(course: ApiCourse): Curso {
|
|
|
218
230
|
alunosInscritos: course.enrollmentCount ?? 0,
|
|
219
231
|
criadoEm: course.createdAt ?? '',
|
|
220
232
|
logoFileId: course.logoFileId ?? null,
|
|
233
|
+
operationsProjectId: course.operationsProjectId ?? null,
|
|
221
234
|
};
|
|
222
235
|
}
|
|
223
236
|
|
|
@@ -259,6 +272,8 @@ const STATUS_VARIANT: Record<string, 'default' | 'secondary' | 'outline'> = {
|
|
|
259
272
|
arquivado: 'outline',
|
|
260
273
|
};
|
|
261
274
|
|
|
275
|
+
const PAGE_SIZES = [6, 12, 24] as const;
|
|
276
|
+
|
|
262
277
|
// ── Seed Data ─────────────────────────────────────────────────────────────────
|
|
263
278
|
|
|
264
279
|
// ── Animations ────────────────────────────────────────────────────────────────
|
|
@@ -283,7 +298,12 @@ export default function CursosPage() {
|
|
|
283
298
|
// UI
|
|
284
299
|
const [sheetOpen, setSheetOpen] = useState(false);
|
|
285
300
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
301
|
+
const [createCategorySheetOpen, setCreateCategorySheetOpen] = useState(false);
|
|
286
302
|
const [saving, setSaving] = useState(false);
|
|
303
|
+
const [creatingCategory, setCreatingCategory] = useState(false);
|
|
304
|
+
const [newCategoryName, setNewCategoryName] = useState('');
|
|
305
|
+
const [newCategorySlug, setNewCategorySlug] = useState('');
|
|
306
|
+
const [newCategorySlugTouched, setNewCategorySlugTouched] = useState(false);
|
|
287
307
|
|
|
288
308
|
// Data
|
|
289
309
|
const [editingCurso, setEditingCurso] = useState<Curso | null>(null);
|
|
@@ -311,14 +331,9 @@ export default function CursosPage() {
|
|
|
311
331
|
const [pageSize, setPageSize] = usePersistedPageSize({
|
|
312
332
|
storageKey: 'pagination:global:pageSize',
|
|
313
333
|
defaultValue: 12,
|
|
314
|
-
allowedValues:
|
|
334
|
+
allowedValues: PAGE_SIZES,
|
|
315
335
|
});
|
|
316
336
|
|
|
317
|
-
// Double-click tracking
|
|
318
|
-
const clickTimers = useRef<Map<number, ReturnType<typeof setTimeout>>>(
|
|
319
|
-
new Map()
|
|
320
|
-
);
|
|
321
|
-
|
|
322
337
|
const form = useForm<CourseSheetFormValues>({
|
|
323
338
|
resolver: zodResolver(getCourseSheetSchema(t)),
|
|
324
339
|
defaultValues: DEFAULT_COURSE_FORM_VALUES,
|
|
@@ -557,22 +572,6 @@ export default function CursosPage() {
|
|
|
557
572
|
setDeleteDialogOpen(true);
|
|
558
573
|
}
|
|
559
574
|
|
|
560
|
-
// ── Double-click to navigate ──────────────────────────────────────────────
|
|
561
|
-
|
|
562
|
-
function handleCardClick(curso: Curso) {
|
|
563
|
-
const existing = clickTimers.current.get(curso.id);
|
|
564
|
-
if (existing) {
|
|
565
|
-
clearTimeout(existing);
|
|
566
|
-
clickTimers.current.delete(curso.id);
|
|
567
|
-
router.push(`/lms/courses/${curso.id}`);
|
|
568
|
-
} else {
|
|
569
|
-
const t = setTimeout(() => {
|
|
570
|
-
clickTimers.current.delete(curso.id);
|
|
571
|
-
}, 300);
|
|
572
|
-
clickTimers.current.set(curso.id, t);
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
575
|
// ── Selection ─────────────────────────────────────────────────────────────
|
|
577
576
|
|
|
578
577
|
function toggleSelect(id: number, e: React.MouseEvent) {
|
|
@@ -609,6 +608,9 @@ export default function CursosPage() {
|
|
|
609
608
|
nivel: curso.nivel,
|
|
610
609
|
status: curso.status,
|
|
611
610
|
categorias: curso.categorias,
|
|
611
|
+
operationsProjectId: curso.operationsProjectId
|
|
612
|
+
? String(curso.operationsProjectId)
|
|
613
|
+
: '',
|
|
612
614
|
logoFileId: curso.logoFileId ?? null,
|
|
613
615
|
});
|
|
614
616
|
setSheetOpen(true);
|
|
@@ -629,6 +631,9 @@ export default function CursosPage() {
|
|
|
629
631
|
primaryContrastColor: getContrastColor(data.primaryColor),
|
|
630
632
|
secondaryColor: data.secondaryColor,
|
|
631
633
|
secondaryContrastColor: getContrastColor(data.secondaryColor),
|
|
634
|
+
operationsProjectId: data.operationsProjectId
|
|
635
|
+
? Number(data.operationsProjectId)
|
|
636
|
+
: null,
|
|
632
637
|
logoFileId: data.logoFileId ?? null,
|
|
633
638
|
};
|
|
634
639
|
|
|
@@ -729,7 +734,7 @@ export default function CursosPage() {
|
|
|
729
734
|
},
|
|
730
735
|
];
|
|
731
736
|
|
|
732
|
-
const { locales } = useApp();
|
|
737
|
+
const { locales, currentLocaleCode } = useApp();
|
|
733
738
|
|
|
734
739
|
const handleNewCourse = (): void => {
|
|
735
740
|
const nextLocaleData: Record<string, { name: string }> = {};
|
|
@@ -742,6 +747,76 @@ export default function CursosPage() {
|
|
|
742
747
|
openCreateSheet();
|
|
743
748
|
};
|
|
744
749
|
|
|
750
|
+
useEffect(() => {
|
|
751
|
+
if (newCategorySlugTouched) return;
|
|
752
|
+
|
|
753
|
+
const generatedSlug = newCategoryName
|
|
754
|
+
.trim()
|
|
755
|
+
.toLowerCase()
|
|
756
|
+
.normalize('NFD')
|
|
757
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
758
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
759
|
+
.replace(/^-+|-+$/g, '');
|
|
760
|
+
|
|
761
|
+
setNewCategorySlug(generatedSlug);
|
|
762
|
+
}, [newCategoryName, newCategorySlugTouched]);
|
|
763
|
+
|
|
764
|
+
function openCreateCategorySheet() {
|
|
765
|
+
setNewCategoryName('');
|
|
766
|
+
setNewCategorySlug('');
|
|
767
|
+
setNewCategorySlugTouched(false);
|
|
768
|
+
setCreateCategorySheetOpen(true);
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
async function handleCreateCategory() {
|
|
772
|
+
const trimmedName = newCategoryName.trim();
|
|
773
|
+
const trimmedSlug = newCategorySlug.trim().toLowerCase();
|
|
774
|
+
|
|
775
|
+
if (!trimmedName || !trimmedSlug) {
|
|
776
|
+
toast.error('Informe nome e slug da categoria.');
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
const localeCode = currentLocaleCode || locales[0]?.code || 'pt-BR';
|
|
781
|
+
|
|
782
|
+
setCreatingCategory(true);
|
|
783
|
+
try {
|
|
784
|
+
const response = await request<{ slug?: string }>({
|
|
785
|
+
url: '/category',
|
|
786
|
+
method: 'POST',
|
|
787
|
+
data: {
|
|
788
|
+
locale: {
|
|
789
|
+
[localeCode]: {
|
|
790
|
+
name: trimmedName,
|
|
791
|
+
},
|
|
792
|
+
},
|
|
793
|
+
slug: trimmedSlug,
|
|
794
|
+
category_id: null,
|
|
795
|
+
color: '#000000',
|
|
796
|
+
icon: '',
|
|
797
|
+
status: 'active',
|
|
798
|
+
},
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
const createdSlug = response.data?.slug || trimmedSlug;
|
|
802
|
+
const existingCategories = form.getValues('categorias') ?? [];
|
|
803
|
+
if (!existingCategories.includes(createdSlug)) {
|
|
804
|
+
form.setValue('categorias', [...existingCategories, createdSlug], {
|
|
805
|
+
shouldDirty: true,
|
|
806
|
+
shouldTouch: true,
|
|
807
|
+
});
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
await refetchCategoryOptions();
|
|
811
|
+
setCreateCategorySheetOpen(false);
|
|
812
|
+
toast.success('Categoria criada com sucesso.');
|
|
813
|
+
} catch {
|
|
814
|
+
toast.error('Nao foi possivel criar a categoria.');
|
|
815
|
+
} finally {
|
|
816
|
+
setCreatingCategory(false);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
745
820
|
// ── Render ────────────────────────────────────────────────────────────────
|
|
746
821
|
|
|
747
822
|
return (
|
|
@@ -1057,7 +1132,7 @@ export default function CursosPage() {
|
|
|
1057
1132
|
>
|
|
1058
1133
|
<Card
|
|
1059
1134
|
className={`group relative flex h-full cursor-pointer flex-col overflow-hidden border-border/70 shadow-sm transition-all duration-200 hover:border-border hover:shadow-md ${isSelected ? 'ring-2 ring-primary ring-offset-2' : ''}`}
|
|
1060
|
-
|
|
1135
|
+
onDoubleClick={() => openEditSheet(curso)}
|
|
1061
1136
|
title={t('cards.tooltip')}
|
|
1062
1137
|
>
|
|
1063
1138
|
<div
|
|
@@ -1243,7 +1318,7 @@ export default function CursosPage() {
|
|
|
1243
1318
|
key={curso.id}
|
|
1244
1319
|
className="cursor-pointer"
|
|
1245
1320
|
data-state={isSelected ? 'selected' : undefined}
|
|
1246
|
-
|
|
1321
|
+
onDoubleClick={() => openEditSheet(curso)}
|
|
1247
1322
|
title={t('cards.tooltip')}
|
|
1248
1323
|
>
|
|
1249
1324
|
<TableCell onClick={(e) => e.stopPropagation()}>
|
|
@@ -1388,7 +1463,7 @@ export default function CursosPage() {
|
|
|
1388
1463
|
setPageSize(nextPageSize);
|
|
1389
1464
|
setCurrentPage(1);
|
|
1390
1465
|
}}
|
|
1391
|
-
pageSizeOptions={
|
|
1466
|
+
pageSizeOptions={PAGE_SIZES}
|
|
1392
1467
|
selectedCount={selectedIds.size}
|
|
1393
1468
|
/>
|
|
1394
1469
|
</div>
|
|
@@ -1407,11 +1482,82 @@ export default function CursosPage() {
|
|
|
1407
1482
|
form={form}
|
|
1408
1483
|
onSubmit={onSubmit}
|
|
1409
1484
|
categories={categoryOptions}
|
|
1410
|
-
onCreateCategory={
|
|
1485
|
+
onCreateCategory={openCreateCategorySheet}
|
|
1411
1486
|
initialLogoFileId={editingCurso?.logoFileId ?? null}
|
|
1412
1487
|
t={t}
|
|
1413
1488
|
/>
|
|
1414
1489
|
|
|
1490
|
+
<Sheet
|
|
1491
|
+
open={createCategorySheetOpen}
|
|
1492
|
+
onOpenChange={(open) => {
|
|
1493
|
+
setCreateCategorySheetOpen(open);
|
|
1494
|
+
if (!open) {
|
|
1495
|
+
setNewCategoryName('');
|
|
1496
|
+
setNewCategorySlug('');
|
|
1497
|
+
setNewCategorySlugTouched(false);
|
|
1498
|
+
}
|
|
1499
|
+
}}
|
|
1500
|
+
>
|
|
1501
|
+
<SheetContent side="right" className="w-full sm:max-w-md">
|
|
1502
|
+
<SheetHeader>
|
|
1503
|
+
<SheetTitle>{t('form.fields.categories.createAction')}</SheetTitle>
|
|
1504
|
+
<SheetDescription>
|
|
1505
|
+
Crie uma categoria sem sair do cadastro de curso.
|
|
1506
|
+
</SheetDescription>
|
|
1507
|
+
</SheetHeader>
|
|
1508
|
+
|
|
1509
|
+
<div className="space-y-4 px-4">
|
|
1510
|
+
<div className="space-y-2">
|
|
1511
|
+
<Label htmlFor="new-category-name">Nome</Label>
|
|
1512
|
+
<Input
|
|
1513
|
+
id="new-category-name"
|
|
1514
|
+
value={newCategoryName}
|
|
1515
|
+
onChange={(event) => setNewCategoryName(event.target.value)}
|
|
1516
|
+
placeholder="Ex.: Desenvolvimento Web"
|
|
1517
|
+
/>
|
|
1518
|
+
</div>
|
|
1519
|
+
|
|
1520
|
+
<div className="space-y-2">
|
|
1521
|
+
<Label htmlFor="new-category-slug">Slug</Label>
|
|
1522
|
+
<Input
|
|
1523
|
+
id="new-category-slug"
|
|
1524
|
+
value={newCategorySlug}
|
|
1525
|
+
onChange={(event) => {
|
|
1526
|
+
setNewCategorySlugTouched(true);
|
|
1527
|
+
setNewCategorySlug(event.target.value);
|
|
1528
|
+
}}
|
|
1529
|
+
placeholder="desenvolvimento-web"
|
|
1530
|
+
/>
|
|
1531
|
+
</div>
|
|
1532
|
+
</div>
|
|
1533
|
+
|
|
1534
|
+
<SheetFooter>
|
|
1535
|
+
<Button
|
|
1536
|
+
type="button"
|
|
1537
|
+
variant="outline"
|
|
1538
|
+
onClick={() => setCreateCategorySheetOpen(false)}
|
|
1539
|
+
disabled={creatingCategory}
|
|
1540
|
+
>
|
|
1541
|
+
{t('deleteDialog.actions.cancel')}
|
|
1542
|
+
</Button>
|
|
1543
|
+
<Button
|
|
1544
|
+
type="button"
|
|
1545
|
+
onClick={handleCreateCategory}
|
|
1546
|
+
disabled={creatingCategory}
|
|
1547
|
+
>
|
|
1548
|
+
{creatingCategory ? (
|
|
1549
|
+
<>
|
|
1550
|
+
<Loader2 className="mr-2 size-4 animate-spin" />
|
|
1551
|
+
Criando...
|
|
1552
|
+
</>
|
|
1553
|
+
) : (
|
|
1554
|
+
t('form.fields.categories.createAction')
|
|
1555
|
+
)}
|
|
1556
|
+
</Button>
|
|
1557
|
+
</SheetFooter>
|
|
1558
|
+
</SheetContent>
|
|
1559
|
+
</Sheet>
|
|
1560
|
+
|
|
1415
1561
|
{/* ── Delete dialog ────────────────────���────────────────────────────── */}
|
|
1416
1562
|
<Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
|
|
1417
1563
|
<DialogContent className="max-w-3xl">
|
|
@@ -143,6 +143,9 @@ export function EnterpriseCourseCreateSheet({
|
|
|
143
143
|
primaryContrastColor: getContrastColor(data.primaryColor),
|
|
144
144
|
secondaryColor: data.secondaryColor,
|
|
145
145
|
secondaryContrastColor: getContrastColor(data.secondaryColor),
|
|
146
|
+
operationsProjectId: data.operationsProjectId
|
|
147
|
+
? Number(data.operationsProjectId)
|
|
148
|
+
: null,
|
|
146
149
|
};
|
|
147
150
|
|
|
148
151
|
const response = await request<ApiCreatedCourse>({
|