@hed-hog/lms 0.0.358 → 0.0.364
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/bitcode-wallet/bitcode-wallet.service.d.ts +65 -0
- package/dist/bitcode-wallet/bitcode-wallet.service.d.ts.map +1 -1
- package/dist/bitcode-wallet/bitcode-wallet.service.js +72 -0
- package/dist/bitcode-wallet/bitcode-wallet.service.js.map +1 -1
- package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.d.ts +8 -0
- package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.d.ts.map +1 -0
- package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.js +40 -0
- package/dist/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.js.map +1 -0
- package/dist/class-group/class-group.controller.d.ts +16 -16
- package/dist/class-group/class-group.service.d.ts +12 -12
- package/dist/course/course-audio-transcription.service.d.ts +3 -2
- package/dist/course/course-audio-transcription.service.d.ts.map +1 -1
- package/dist/course/course-audio-transcription.service.js +49 -8
- package/dist/course/course-audio-transcription.service.js.map +1 -1
- package/dist/course/course-lesson.controller.d.ts +4 -0
- package/dist/course/course-lesson.controller.d.ts.map +1 -1
- package/dist/course/course-lesson.controller.js +10 -0
- package/dist/course/course-lesson.controller.js.map +1 -1
- package/dist/course/course-structure.controller.d.ts +11 -4
- package/dist/course/course-structure.controller.d.ts.map +1 -1
- package/dist/course/course-structure.controller.js +14 -0
- package/dist/course/course-structure.controller.js.map +1 -1
- package/dist/course/course-structure.service.d.ts +15 -1
- package/dist/course/course-structure.service.d.ts.map +1 -1
- package/dist/course/course-structure.service.js +139 -4
- package/dist/course/course-structure.service.js.map +1 -1
- package/dist/course/course-video-conversion.service.d.ts +8 -0
- package/dist/course/course-video-conversion.service.d.ts.map +1 -1
- package/dist/course/course-video-conversion.service.js +87 -51
- package/dist/course/course-video-conversion.service.js.map +1 -1
- package/dist/course/course.controller.d.ts +73 -1
- package/dist/course/course.controller.d.ts.map +1 -1
- package/dist/course/course.controller.js +27 -3
- package/dist/course/course.controller.js.map +1 -1
- package/dist/course/course.module.d.ts.map +1 -1
- package/dist/course/course.module.js +15 -3
- package/dist/course/course.module.js.map +1 -1
- package/dist/course/course.service.d.ts +108 -4
- package/dist/course/course.service.d.ts.map +1 -1
- package/dist/course/course.service.js +631 -30
- package/dist/course/course.service.js.map +1 -1
- package/dist/course/dto/cleanup-course-storage.dto.d.ts +6 -0
- package/dist/course/dto/cleanup-course-storage.dto.d.ts.map +1 -0
- package/dist/course/dto/cleanup-course-storage.dto.js +33 -0
- package/dist/course/dto/cleanup-course-storage.dto.js.map +1 -0
- package/dist/course/dto/cleanup-upload-history.dto.d.ts +9 -0
- package/dist/course/dto/cleanup-upload-history.dto.d.ts.map +1 -0
- package/dist/course/dto/cleanup-upload-history.dto.js +36 -0
- package/dist/course/dto/cleanup-upload-history.dto.js.map +1 -0
- package/dist/course/dto/create-course-bulk-job.dto.d.ts +4 -0
- package/dist/course/dto/create-course-bulk-job.dto.d.ts.map +1 -0
- package/dist/course/dto/create-course-bulk-job.dto.js +21 -0
- package/dist/course/dto/create-course-bulk-job.dto.js.map +1 -0
- package/dist/course/lms-bulk-upload-automation.service.d.ts +39 -0
- package/dist/course/lms-bulk-upload-automation.service.d.ts.map +1 -0
- package/dist/course/lms-bulk-upload-automation.service.js +443 -0
- package/dist/course/lms-bulk-upload-automation.service.js.map +1 -0
- package/dist/course/lms-bulk-upload-infra.service.d.ts +31 -0
- package/dist/course/lms-bulk-upload-infra.service.d.ts.map +1 -0
- package/dist/course/lms-bulk-upload-infra.service.js +277 -0
- package/dist/course/lms-bulk-upload-infra.service.js.map +1 -0
- package/dist/course/lms-bulk-upload.constants.d.ts +4 -0
- package/dist/course/lms-bulk-upload.constants.d.ts.map +1 -0
- package/dist/course/lms-bulk-upload.constants.js +7 -0
- package/dist/course/lms-bulk-upload.constants.js.map +1 -0
- package/dist/course/lms-bulk-upload.controller.d.ts +153 -0
- package/dist/course/lms-bulk-upload.controller.d.ts.map +1 -0
- package/dist/course/lms-bulk-upload.controller.js +129 -0
- package/dist/course/lms-bulk-upload.controller.js.map +1 -0
- package/dist/course/lms-bulk-upload.service.d.ts +181 -0
- package/dist/course/lms-bulk-upload.service.d.ts.map +1 -0
- package/dist/course/lms-bulk-upload.service.js +754 -0
- package/dist/course/lms-bulk-upload.service.js.map +1 -0
- package/dist/course/lms-setting.controller.d.ts +7 -1
- package/dist/course/lms-setting.controller.d.ts.map +1 -1
- package/dist/course/lms-setting.controller.js +26 -3
- package/dist/course/lms-setting.controller.js.map +1 -1
- package/dist/enterprise/enterprise.controller.d.ts +20 -20
- package/dist/enterprise/enterprise.service.d.ts +20 -20
- package/dist/enterprise/training/training-admin.controller.d.ts +11 -11
- package/dist/enterprise/training/training-admin.service.d.ts +11 -11
- package/dist/enterprise/training/training-instructor.controller.d.ts +2 -2
- package/dist/enterprise/training/training-instructor.service.d.ts +2 -2
- package/dist/enterprise/training/training-student.controller.d.ts +1 -1
- package/dist/enterprise/training/training-student.service.d.ts +1 -1
- package/dist/enterprise/training/training-viewer.controller.d.ts +2 -2
- package/dist/evaluation/evaluation.controller.d.ts +8 -8
- package/dist/evaluation/evaluation.service.d.ts +8 -8
- package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.d.ts +6 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.d.ts.map +1 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.js +34 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-map.dto.js.map +1 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.d.ts +28 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.d.ts.map +1 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.js +123 -0
- package/dist/lesson-xp-map/dto/create-lesson-xp-segment.dto.js.map +1 -0
- package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.d.ts +4 -0
- package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.d.ts.map +1 -0
- package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.js +22 -0
- package/dist/lesson-xp-map/dto/review-lesson-xp-map.dto.js.map +1 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.d.ts +10 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.d.ts.map +1 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.js +52 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-map.dto.js.map +1 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.d.ts +15 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.d.ts.map +1 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.js +86 -0
- package/dist/lesson-xp-map/dto/update-lesson-xp-segment.dto.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.d.ts +26 -0
- package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.js +304 -0
- package/dist/lesson-xp-map/lesson-xp-ai-calculation.service.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.controller.d.ts +87 -0
- package/dist/lesson-xp-map/lesson-xp-map.controller.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.controller.js +185 -0
- package/dist/lesson-xp-map/lesson-xp-map.controller.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.module.d.ts +3 -0
- package/dist/lesson-xp-map/lesson-xp-map.module.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.module.js +34 -0
- package/dist/lesson-xp-map/lesson-xp-map.module.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.service.d.ts +84 -0
- package/dist/lesson-xp-map/lesson-xp-map.service.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-map.service.js +353 -0
- package/dist/lesson-xp-map/lesson-xp-map.service.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-segment.controller.d.ts +10 -0
- package/dist/lesson-xp-map/lesson-xp-segment.controller.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-segment.controller.js +63 -0
- package/dist/lesson-xp-map/lesson-xp-segment.controller.js.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-segment.service.d.ts +27 -0
- package/dist/lesson-xp-map/lesson-xp-segment.service.d.ts.map +1 -0
- package/dist/lesson-xp-map/lesson-xp-segment.service.js +194 -0
- package/dist/lesson-xp-map/lesson-xp-segment.service.js.map +1 -0
- package/dist/libraries/lms/tsconfig.tsbuildinfo +1 -0
- package/dist/lms.module.d.ts.map +1 -1
- package/dist/lms.module.js +17 -2
- package/dist/lms.module.js.map +1 -1
- package/dist/platforma/dto/update-profile.dto.d.ts +17 -0
- package/dist/platforma/dto/update-profile.dto.d.ts.map +1 -0
- package/dist/platforma/dto/update-profile.dto.js +87 -0
- package/dist/platforma/dto/update-profile.dto.js.map +1 -0
- package/dist/platforma/platforma.controller.d.ts +94 -7
- package/dist/platforma/platforma.controller.d.ts.map +1 -1
- package/dist/platforma/platforma.controller.js +85 -2
- package/dist/platforma/platforma.controller.js.map +1 -1
- package/dist/platforma/platforma.service.d.ts +27 -0
- package/dist/platforma/platforma.service.d.ts.map +1 -0
- package/dist/platforma/platforma.service.js +274 -0
- package/dist/platforma/platforma.service.js.map +1 -0
- package/dist/student-xp/student-xp.controller.d.ts +41 -0
- package/dist/student-xp/student-xp.controller.d.ts.map +1 -0
- package/dist/student-xp/student-xp.controller.js +114 -0
- package/dist/student-xp/student-xp.controller.js.map +1 -0
- package/dist/student-xp/student-xp.module.d.ts +3 -0
- package/dist/student-xp/student-xp.module.d.ts.map +1 -0
- package/dist/student-xp/student-xp.module.js +25 -0
- package/dist/student-xp/student-xp.module.js.map +1 -0
- package/dist/student-xp/student-xp.service.d.ts +65 -0
- package/dist/student-xp/student-xp.service.d.ts.map +1 -0
- package/dist/student-xp/student-xp.service.js +197 -0
- package/dist/student-xp/student-xp.service.js.map +1 -0
- package/dist/xp-catalog/dto/create-xp-area.dto.d.ts +12 -0
- package/dist/xp-catalog/dto/create-xp-area.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/create-xp-area.dto.js +63 -0
- package/dist/xp-catalog/dto/create-xp-area.dto.js.map +1 -0
- package/dist/xp-catalog/dto/create-xp-learning-type.dto.d.ts +11 -0
- package/dist/xp-catalog/dto/create-xp-learning-type.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/create-xp-learning-type.dto.js +57 -0
- package/dist/xp-catalog/dto/create-xp-learning-type.dto.js.map +1 -0
- package/dist/xp-catalog/dto/create-xp-skill.dto.d.ts +11 -0
- package/dist/xp-catalog/dto/create-xp-skill.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/create-xp-skill.dto.js +57 -0
- package/dist/xp-catalog/dto/create-xp-skill.dto.js.map +1 -0
- package/dist/xp-catalog/dto/update-xp-area.dto.d.ts +12 -0
- package/dist/xp-catalog/dto/update-xp-area.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/update-xp-area.dto.js +66 -0
- package/dist/xp-catalog/dto/update-xp-area.dto.js.map +1 -0
- package/dist/xp-catalog/dto/update-xp-learning-type.dto.d.ts +11 -0
- package/dist/xp-catalog/dto/update-xp-learning-type.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/update-xp-learning-type.dto.js +60 -0
- package/dist/xp-catalog/dto/update-xp-learning-type.dto.js.map +1 -0
- package/dist/xp-catalog/dto/update-xp-skill.dto.d.ts +11 -0
- package/dist/xp-catalog/dto/update-xp-skill.dto.d.ts.map +1 -0
- package/dist/xp-catalog/dto/update-xp-skill.dto.js +60 -0
- package/dist/xp-catalog/dto/update-xp-skill.dto.js.map +1 -0
- package/dist/xp-catalog/xp-area.controller.d.ts +25 -0
- package/dist/xp-catalog/xp-area.controller.d.ts.map +1 -0
- package/dist/xp-catalog/xp-area.controller.js +105 -0
- package/dist/xp-catalog/xp-area.controller.js.map +1 -0
- package/dist/xp-catalog/xp-area.service.d.ts +35 -0
- package/dist/xp-catalog/xp-area.service.d.ts.map +1 -0
- package/dist/xp-catalog/xp-area.service.js +168 -0
- package/dist/xp-catalog/xp-area.service.js.map +1 -0
- package/dist/xp-catalog/xp-catalog.module.d.ts +3 -0
- package/dist/xp-catalog/xp-catalog.module.d.ts.map +1 -0
- package/dist/xp-catalog/xp-catalog.module.js +29 -0
- package/dist/xp-catalog/xp-catalog.module.js.map +1 -0
- package/dist/xp-catalog/xp-learning-type.controller.d.ts +20 -0
- package/dist/xp-catalog/xp-learning-type.controller.d.ts.map +1 -0
- package/dist/xp-catalog/xp-learning-type.controller.js +96 -0
- package/dist/xp-catalog/xp-learning-type.controller.js.map +1 -0
- package/dist/xp-catalog/xp-learning-type.service.d.ts +30 -0
- package/dist/xp-catalog/xp-learning-type.service.d.ts.map +1 -0
- package/dist/xp-catalog/xp-learning-type.service.js +146 -0
- package/dist/xp-catalog/xp-learning-type.service.js.map +1 -0
- package/dist/xp-catalog/xp-skill.controller.d.ts +26 -0
- package/dist/xp-catalog/xp-skill.controller.d.ts.map +1 -0
- package/dist/xp-catalog/xp-skill.controller.js +113 -0
- package/dist/xp-catalog/xp-skill.controller.js.map +1 -0
- package/dist/xp-catalog/xp-skill.service.d.ts +37 -0
- package/dist/xp-catalog/xp-skill.service.d.ts.map +1 -0
- package/dist/xp-catalog/xp-skill.service.js +174 -0
- package/dist/xp-catalog/xp-skill.service.js.map +1 -0
- package/hedhog/data/menu.yaml +101 -0
- package/hedhog/data/role.yaml +8 -0
- package/hedhog/data/route.yaml +547 -0
- package/hedhog/data/setting_group.yaml +33 -0
- package/hedhog/data/xp_area.yaml +164 -0
- package/hedhog/data/xp_learning_type.yaml +131 -0
- package/hedhog/data/xp_skill.yaml +1834 -0
- package/hedhog/frontend/app/achievements/page.tsx.ejs +108 -118
- package/hedhog/frontend/app/bitcodes/page.tsx.ejs +22 -34
- package/hedhog/frontend/app/bulk-upload-sessions/page.tsx.ejs +1453 -0
- package/hedhog/frontend/app/certificates/models/page.tsx.ejs +21 -45
- package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +40 -74
- package/hedhog/frontend/app/classes/page.tsx.ejs +56 -85
- package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +3 -2
- package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +48 -5
- package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +4 -4
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-operations-tab.tsx.ejs +19 -2
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-overview-tab.tsx.ejs +1170 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +16 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +2 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-xp-overview-tab.tsx.ejs +623 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson-xp-tab.tsx.ejs +1458 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +55 -2
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +442 -104
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +296 -49
- package/hedhog/frontend/app/courses/[id]/structure/_components/sortable-tree-row.tsx.ejs +3 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/store.ts.ejs +1 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +101 -85
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +21 -1
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row.tsx.ejs +3 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/use-tree-display-settings.ts.ejs +7 -1
- package/hedhog/frontend/app/courses/[id]/structure/_components/xp-premium-pills.tsx.ejs +44 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-content-overview.ts.ejs +54 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +52 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-xp-overview.ts.ejs +76 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-lesson-xp-map.ts.ejs +128 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-transcription-segments.ts.ejs +30 -0
- package/hedhog/frontend/app/courses/[id]/structure/_utils/xp-color-config.ts.ejs +115 -0
- package/hedhog/frontend/app/courses/_components/CourseDeleteDialog.tsx.ejs +223 -0
- package/hedhog/frontend/app/courses/_components/CourseRowActions.tsx.ejs +89 -0
- package/hedhog/frontend/app/courses/page.tsx.ejs +400 -230
- package/hedhog/frontend/app/enterprise/page.tsx.ejs +39 -63
- package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +53 -77
- package/hedhog/frontend/app/exams/page.tsx.ejs +54 -90
- package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +23 -36
- package/hedhog/frontend/app/instructors/page.tsx.ejs +72 -81
- package/hedhog/frontend/app/paths/page.tsx.ejs +40 -68
- package/hedhog/frontend/app/training/page.tsx.ejs +40 -68
- package/hedhog/frontend/app/xp/areas/page.tsx.ejs +782 -0
- package/hedhog/frontend/app/xp/learning-types/page.tsx.ejs +690 -0
- package/hedhog/frontend/app/xp/skills/page.tsx.ejs +811 -0
- package/hedhog/frontend/messages/en.json +386 -3
- package/hedhog/frontend/messages/pt.json +386 -3
- package/hedhog/table/lesson_xp_map.yaml +50 -0
- package/hedhog/table/lesson_xp_segment.yaml +40 -0
- package/hedhog/table/lesson_xp_segment_area.yaml +24 -0
- package/hedhog/table/lesson_xp_segment_learning_type.yaml +24 -0
- package/hedhog/table/lesson_xp_segment_skill.yaml +24 -0
- package/hedhog/table/lms_bulk_upload_item.yaml +44 -0
- package/hedhog/table/lms_bulk_upload_session.yaml +42 -0
- package/hedhog/table/student_area_xp.yaml +30 -0
- package/hedhog/table/student_learning_type_xp.yaml +30 -0
- package/hedhog/table/student_skill_xp.yaml +30 -0
- package/hedhog/table/student_xp_event.yaml +34 -0
- package/hedhog/table/xp_area.yaml +39 -0
- package/hedhog/table/xp_learning_type.yaml +34 -0
- package/hedhog/table/xp_skill.yaml +39 -0
- package/package.json +9 -8
- package/src/bitcode-wallet/bitcode-wallet.service.ts +113 -0
- package/src/bitcode-wallet/dto/create-current-bitcode-wallet-transaction.dto.ts +32 -0
- package/src/course/course-audio-transcription.service.ts +58 -21
- package/src/course/course-lesson.controller.ts +6 -1
- package/src/course/course-structure.controller.ts +10 -0
- package/src/course/course-structure.service.ts +174 -1
- package/src/course/course-video-conversion.service.ts +113 -75
- package/src/course/course.controller.ts +22 -3
- package/src/course/course.module.ts +15 -3
- package/src/course/course.service.ts +847 -30
- package/src/course/dto/cleanup-course-storage.dto.ts +22 -0
- package/src/course/dto/cleanup-upload-history.dto.ts +26 -0
- package/src/course/dto/create-course-bulk-job.dto.ts +6 -0
- package/src/course/lms-bulk-upload-automation.service.ts +560 -0
- package/src/course/lms-bulk-upload-infra.service.ts +327 -0
- package/src/course/lms-bulk-upload.constants.ts +5 -0
- package/src/course/lms-bulk-upload.controller.ts +103 -0
- package/src/course/lms-bulk-upload.service.ts +1029 -0
- package/src/course/lms-setting.controller.ts +28 -1
- package/src/lesson-xp-map/dto/create-lesson-xp-map.dto.ts +17 -0
- package/src/lesson-xp-map/dto/create-lesson-xp-segment.dto.ts +102 -0
- package/src/lesson-xp-map/dto/review-lesson-xp-map.dto.ts +7 -0
- package/src/lesson-xp-map/dto/update-lesson-xp-map.dto.ts +36 -0
- package/src/lesson-xp-map/dto/update-lesson-xp-segment.dto.ts +78 -0
- package/src/lesson-xp-map/lesson-xp-ai-calculation.service.ts +396 -0
- package/src/lesson-xp-map/lesson-xp-map.controller.ts +116 -0
- package/src/lesson-xp-map/lesson-xp-map.module.ts +21 -0
- package/src/lesson-xp-map/lesson-xp-map.service.ts +442 -0
- package/src/lesson-xp-map/lesson-xp-segment.controller.ts +36 -0
- package/src/lesson-xp-map/lesson-xp-segment.service.ts +229 -0
- package/src/lms.module.ts +17 -2
- package/src/platforma/dto/update-profile.dto.ts +59 -0
- package/src/platforma/platforma.controller.ts +57 -2
- package/src/platforma/platforma.service.ts +268 -0
- package/src/student-xp/student-xp.controller.ts +76 -0
- package/src/student-xp/student-xp.module.ts +12 -0
- package/src/student-xp/student-xp.service.ts +236 -0
- package/src/xp-catalog/dto/create-xp-area.dto.ts +40 -0
- package/src/xp-catalog/dto/create-xp-learning-type.dto.ts +35 -0
- package/src/xp-catalog/dto/create-xp-skill.dto.ts +35 -0
- package/src/xp-catalog/dto/update-xp-area.dto.ts +43 -0
- package/src/xp-catalog/dto/update-xp-learning-type.dto.ts +38 -0
- package/src/xp-catalog/dto/update-xp-skill.dto.ts +38 -0
- package/src/xp-catalog/xp-area.controller.ts +64 -0
- package/src/xp-catalog/xp-area.service.ts +196 -0
- package/src/xp-catalog/xp-catalog.module.ts +16 -0
- package/src/xp-catalog/xp-learning-type.controller.ts +59 -0
- package/src/xp-catalog/xp-learning-type.service.ts +170 -0
- package/src/xp-catalog/xp-skill.controller.ts +71 -0
- package/src/xp-catalog/xp-skill.service.ts +205 -0
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
useReorderLessonsMutation,
|
|
28
28
|
useReorderSessionsMutation,
|
|
29
29
|
} from '../_data/use-course-structure-mutations';
|
|
30
|
+
import { useCourseXpOverviewQuery } from '../_data/use-course-xp-overview';
|
|
30
31
|
import { TreeDragOverlay } from './drag-overlay';
|
|
31
32
|
import { SortableTreeRow } from './sortable-tree-row';
|
|
32
33
|
import { useStructureStore } from './store';
|
|
@@ -88,6 +89,20 @@ export function CourseTreeDnd() {
|
|
|
88
89
|
[sessions]
|
|
89
90
|
);
|
|
90
91
|
|
|
92
|
+
const { data: courseXpOverview } = useCourseXpOverviewQuery(
|
|
93
|
+
course?.id ?? null
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const lessonsWithXpMap = useMemo(
|
|
97
|
+
() =>
|
|
98
|
+
new Set(
|
|
99
|
+
(courseXpOverview?.lessons ?? [])
|
|
100
|
+
.filter((lesson) => lesson.hasMap)
|
|
101
|
+
.map((lesson) => String(lesson.courseLessonId))
|
|
102
|
+
),
|
|
103
|
+
[courseXpOverview]
|
|
104
|
+
);
|
|
105
|
+
|
|
91
106
|
const isSearchActive = filterQuery.trim().length > 0;
|
|
92
107
|
const dragDisabled = isSearchActive;
|
|
93
108
|
|
|
@@ -375,6 +390,7 @@ export function CourseTreeDnd() {
|
|
|
375
390
|
sessionIndicatorMap={sessionIndicatorMap}
|
|
376
391
|
visibleItems={items}
|
|
377
392
|
dragDisabled={dragDisabled}
|
|
393
|
+
lessonsWithXpMap={lessonsWithXpMap}
|
|
378
394
|
/>
|
|
379
395
|
</div>
|
|
380
396
|
))}
|
|
@@ -44,6 +44,7 @@ export function CourseTree() {
|
|
|
44
44
|
() => buildSessionIndicatorMap(lessons),
|
|
45
45
|
[lessons]
|
|
46
46
|
);
|
|
47
|
+
const lessonsWithXpMap = useMemo(() => new Set<string>(), []);
|
|
47
48
|
|
|
48
49
|
const estimateSize = useCallback(
|
|
49
50
|
(index: number) => ROW_HEIGHT[items[index]?.type ?? 'lesson'] ?? 32,
|
|
@@ -131,6 +132,7 @@ export function CourseTree() {
|
|
|
131
132
|
lessonCountMap={lessonCountMap}
|
|
132
133
|
sessionIndicatorMap={sessionIndicatorMap}
|
|
133
134
|
visibleItems={items}
|
|
135
|
+
lessonsWithXpMap={lessonsWithXpMap}
|
|
134
136
|
/>
|
|
135
137
|
</div>
|
|
136
138
|
);
|
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
4
|
+
import {
|
|
5
|
+
Card,
|
|
6
|
+
CardContent,
|
|
7
|
+
CardDescription,
|
|
8
|
+
CardHeader,
|
|
9
|
+
CardTitle,
|
|
10
|
+
} from '@/components/ui/card';
|
|
11
|
+
import {
|
|
12
|
+
ChartContainer,
|
|
13
|
+
ChartTooltip,
|
|
14
|
+
ChartTooltipContent,
|
|
15
|
+
} from '@/components/ui/chart';
|
|
16
|
+
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
17
|
+
import { Skeleton } from '@/components/ui/skeleton';
|
|
18
|
+
import {
|
|
19
|
+
BarChart3,
|
|
20
|
+
BookOpen,
|
|
21
|
+
ChartPie,
|
|
22
|
+
Layers3,
|
|
23
|
+
Sparkles,
|
|
24
|
+
Target,
|
|
25
|
+
} from 'lucide-react';
|
|
26
|
+
import { useTranslations } from 'next-intl';
|
|
27
|
+
import { useMemo } from 'react';
|
|
28
|
+
import {
|
|
29
|
+
Bar,
|
|
30
|
+
BarChart,
|
|
31
|
+
CartesianGrid,
|
|
32
|
+
Cell,
|
|
33
|
+
Pie,
|
|
34
|
+
PieChart,
|
|
35
|
+
XAxis,
|
|
36
|
+
YAxis,
|
|
37
|
+
} from 'recharts';
|
|
38
|
+
import { useCourseXpOverviewQuery } from '../_data/use-course-xp-overview';
|
|
39
|
+
import {
|
|
40
|
+
resolveXpAreaColor,
|
|
41
|
+
resolveXpLearningTypeColor,
|
|
42
|
+
resolveXpSkillColor,
|
|
43
|
+
} from '../_utils/xp-color-config';
|
|
44
|
+
import { XpHighlightPill, XpMetaPill } from './xp-premium-pills';
|
|
45
|
+
|
|
46
|
+
type XpAreaOption = {
|
|
47
|
+
id: number;
|
|
48
|
+
name: string;
|
|
49
|
+
color: string | null;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
function formatCompactNumber(value: number, locale: string) {
|
|
53
|
+
return new Intl.NumberFormat(locale, {
|
|
54
|
+
notation: 'compact',
|
|
55
|
+
maximumFractionDigits: value >= 100 ? 0 : 1,
|
|
56
|
+
}).format(value);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function formatPercentage(value: number, locale: string) {
|
|
60
|
+
return new Intl.NumberFormat(locale, {
|
|
61
|
+
minimumFractionDigits: 0,
|
|
62
|
+
maximumFractionDigits: 1,
|
|
63
|
+
}).format(value);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getTopItems<T>(items: T[], maxItems = 5) {
|
|
67
|
+
return items.slice(0, maxItems);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface Props {
|
|
71
|
+
courseId: string;
|
|
72
|
+
locale: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function CourseXpOverviewTab({ courseId, locale }: Props) {
|
|
76
|
+
const t = useTranslations('lms.CursoEditPage.structureEditor.xpOverview');
|
|
77
|
+
const { request } = useApp();
|
|
78
|
+
const { data, isLoading, isError } = useCourseXpOverviewQuery(courseId);
|
|
79
|
+
const { data: areaOptions = [] } = useQuery<XpAreaOption[]>({
|
|
80
|
+
queryKey: ['lms-xp-areas-all'],
|
|
81
|
+
enabled: Boolean(courseId),
|
|
82
|
+
queryFn: async () => {
|
|
83
|
+
const response = await request<XpAreaOption[]>({
|
|
84
|
+
url: '/lms/xp/areas/all',
|
|
85
|
+
method: 'GET',
|
|
86
|
+
});
|
|
87
|
+
return response.data;
|
|
88
|
+
},
|
|
89
|
+
placeholderData: [],
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const areaColorLookup = useMemo(
|
|
93
|
+
() => new Map(areaOptions.map((area) => [area.id, area.color])),
|
|
94
|
+
[areaOptions]
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const kpiItems = useMemo(() => {
|
|
98
|
+
if (!data) return [];
|
|
99
|
+
|
|
100
|
+
return [
|
|
101
|
+
{
|
|
102
|
+
key: 'totalXp',
|
|
103
|
+
title: t('kpis.totalXp'),
|
|
104
|
+
value: data.summary.totalXp,
|
|
105
|
+
description: t('kpis.totalXpDescription'),
|
|
106
|
+
icon: Sparkles,
|
|
107
|
+
accentClassName: 'from-cyan-500 via-sky-500 to-blue-500',
|
|
108
|
+
iconContainerClassName:
|
|
109
|
+
'bg-cyan-500/10 text-cyan-600 dark:text-cyan-400',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
key: 'mappedLessons',
|
|
113
|
+
title: t('kpis.mappedLessons'),
|
|
114
|
+
value: `${data.summary.mappedLessons}/${data.summary.totalLessons}`,
|
|
115
|
+
description: t('kpis.mappedLessonsDescription'),
|
|
116
|
+
icon: BookOpen,
|
|
117
|
+
accentClassName: 'from-emerald-500 via-teal-500 to-green-500',
|
|
118
|
+
iconContainerClassName:
|
|
119
|
+
'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
key: 'areas',
|
|
123
|
+
title: 'Áreas macro',
|
|
124
|
+
value: data.areas.length,
|
|
125
|
+
description: 'Principais áreas mapeadas no curso',
|
|
126
|
+
icon: Layers3,
|
|
127
|
+
accentClassName: 'from-amber-500 via-orange-500 to-rose-500',
|
|
128
|
+
iconContainerClassName:
|
|
129
|
+
'bg-amber-500/10 text-amber-600 dark:text-amber-400',
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
key: 'skills',
|
|
133
|
+
title: 'Skills únicas',
|
|
134
|
+
value: data.skills.length,
|
|
135
|
+
description: 'Quantidade total de skills do curso',
|
|
136
|
+
icon: Target,
|
|
137
|
+
accentClassName: 'from-violet-500 via-fuchsia-500 to-purple-500',
|
|
138
|
+
iconContainerClassName:
|
|
139
|
+
'bg-violet-500/10 text-violet-600 dark:text-violet-400',
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
}, [data, t]);
|
|
143
|
+
|
|
144
|
+
const areaData = getTopItems(data?.areas ?? [], 6);
|
|
145
|
+
const skillData = getTopItems(data?.skills ?? [], 6);
|
|
146
|
+
const learningTypeData = getTopItems(data?.learningTypes ?? [], 4);
|
|
147
|
+
|
|
148
|
+
const areaChartConfig = useMemo(
|
|
149
|
+
() =>
|
|
150
|
+
Object.fromEntries(
|
|
151
|
+
areaData.map((item, index) => [
|
|
152
|
+
item.slug,
|
|
153
|
+
{
|
|
154
|
+
label: item.name,
|
|
155
|
+
color: resolveXpAreaColor({
|
|
156
|
+
areaId: item.xpAreaId,
|
|
157
|
+
areaSlug: item.slug,
|
|
158
|
+
index,
|
|
159
|
+
persistedColor: areaColorLookup.get(item.xpAreaId),
|
|
160
|
+
}),
|
|
161
|
+
},
|
|
162
|
+
])
|
|
163
|
+
),
|
|
164
|
+
[areaColorLookup, areaData]
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const skillChartConfig = useMemo(
|
|
168
|
+
() =>
|
|
169
|
+
Object.fromEntries(
|
|
170
|
+
skillData.map((item, index) => [
|
|
171
|
+
item.slug,
|
|
172
|
+
{
|
|
173
|
+
label: item.name,
|
|
174
|
+
color: resolveXpSkillColor({
|
|
175
|
+
skillId: item.xpSkillId,
|
|
176
|
+
skillSlug: item.slug,
|
|
177
|
+
index,
|
|
178
|
+
}),
|
|
179
|
+
},
|
|
180
|
+
])
|
|
181
|
+
),
|
|
182
|
+
[skillData]
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const overviewHighlights = useMemo(() => {
|
|
186
|
+
if (!data) return [];
|
|
187
|
+
|
|
188
|
+
const topArea = data.areas[0];
|
|
189
|
+
const topSkill = data.skills[0];
|
|
190
|
+
|
|
191
|
+
return [
|
|
192
|
+
topArea
|
|
193
|
+
? {
|
|
194
|
+
key: 'top-area',
|
|
195
|
+
label: 'Área líder',
|
|
196
|
+
value: `${topArea.name} ${formatPercentage(topArea.sharePercent, locale)}%`,
|
|
197
|
+
tone: 'sky' as const,
|
|
198
|
+
}
|
|
199
|
+
: null,
|
|
200
|
+
topSkill
|
|
201
|
+
? {
|
|
202
|
+
key: 'top-skill',
|
|
203
|
+
label: 'Skill líder',
|
|
204
|
+
value: `${topSkill.name} ${formatPercentage(topSkill.sharePercent, locale)}%`,
|
|
205
|
+
tone: 'amber' as const,
|
|
206
|
+
}
|
|
207
|
+
: null,
|
|
208
|
+
{
|
|
209
|
+
key: 'coverage',
|
|
210
|
+
label: 'Cobertura',
|
|
211
|
+
value: `${data.summary.mappedLessons}/${data.summary.totalLessons} aulas`,
|
|
212
|
+
tone: 'emerald' as const,
|
|
213
|
+
},
|
|
214
|
+
].filter(Boolean);
|
|
215
|
+
}, [data, locale]);
|
|
216
|
+
|
|
217
|
+
if (isLoading) {
|
|
218
|
+
return (
|
|
219
|
+
<div className="flex flex-col gap-3">
|
|
220
|
+
<div className="grid grid-cols-2 gap-3 xl:grid-cols-4">
|
|
221
|
+
{Array.from({ length: 4 }).map((_, index) => (
|
|
222
|
+
<Skeleton key={index} className="h-24 rounded-xl" />
|
|
223
|
+
))}
|
|
224
|
+
</div>
|
|
225
|
+
<div className="grid gap-3 xl:grid-cols-2">
|
|
226
|
+
<Skeleton className="h-72 rounded-xl" />
|
|
227
|
+
<Skeleton className="h-72 rounded-xl" />
|
|
228
|
+
</div>
|
|
229
|
+
<Skeleton className="h-36 rounded-xl" />
|
|
230
|
+
</div>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (isError || !data) {
|
|
235
|
+
return (
|
|
236
|
+
<Card className="border-dashed bg-muted/20">
|
|
237
|
+
<CardHeader>
|
|
238
|
+
<CardTitle className="text-sm font-semibold">
|
|
239
|
+
{t('errorTitle')}
|
|
240
|
+
</CardTitle>
|
|
241
|
+
<CardDescription>{t('errorDescription')}</CardDescription>
|
|
242
|
+
</CardHeader>
|
|
243
|
+
</Card>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (data.summary.mappedLessons === 0) {
|
|
248
|
+
return (
|
|
249
|
+
<Card className="border-dashed bg-muted/20">
|
|
250
|
+
<CardHeader>
|
|
251
|
+
<CardTitle className="text-sm font-semibold">
|
|
252
|
+
{t('emptyTitle')}
|
|
253
|
+
</CardTitle>
|
|
254
|
+
<CardDescription>{t('emptyDescription')}</CardDescription>
|
|
255
|
+
</CardHeader>
|
|
256
|
+
</Card>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return (
|
|
261
|
+
<div className="flex flex-col gap-2.5">
|
|
262
|
+
<div className="rounded-2xl border border-border/70 bg-linear-to-br from-background via-background to-muted/30 px-2.5 py-2 shadow-[0_14px_34px_-28px_rgba(15,23,42,0.45)] backdrop-blur-sm sm:px-3 sm:py-2.5">
|
|
263
|
+
<div className="flex flex-wrap items-start justify-between gap-3 border-b border-border/50 pb-2">
|
|
264
|
+
<div className="min-w-0">
|
|
265
|
+
<div className="text-[10px] font-semibold uppercase tracking-[0.22em] text-cyan-700/80 dark:text-cyan-300/80">
|
|
266
|
+
Course XP overview
|
|
267
|
+
</div>
|
|
268
|
+
<div className="mt-1 text-sm font-semibold text-foreground">
|
|
269
|
+
Panorama do mapeamento do curso
|
|
270
|
+
</div>
|
|
271
|
+
<div className="mt-0.5 text-xs text-muted-foreground">
|
|
272
|
+
Leitura consolidada de áreas macro, skills e tipos de aprendizado.
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
<div className="flex flex-wrap gap-1.5">
|
|
276
|
+
{overviewHighlights.map((item) =>
|
|
277
|
+
item ? (
|
|
278
|
+
<XpHighlightPill
|
|
279
|
+
key={item.key}
|
|
280
|
+
label={item.label}
|
|
281
|
+
value={item.value}
|
|
282
|
+
tone={item.tone}
|
|
283
|
+
/>
|
|
284
|
+
) : null
|
|
285
|
+
)}
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
<div className="mt-2">
|
|
290
|
+
<KpiCardsGrid
|
|
291
|
+
items={kpiItems.map((item) => ({
|
|
292
|
+
...item,
|
|
293
|
+
layout: 'compact' as const,
|
|
294
|
+
}))}
|
|
295
|
+
columns={4}
|
|
296
|
+
className="gap-2.5"
|
|
297
|
+
cardClassName="shadow-[0_12px_24px_-22px_rgba(15,23,42,0.45)] transition-all duration-200 hover:-translate-y-0.5 hover:shadow-[0_18px_34px_-22px_rgba(15,23,42,0.5)]"
|
|
298
|
+
/>
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
301
|
+
|
|
302
|
+
<div className="grid gap-3 xl:grid-cols-[minmax(0,1.06fr)_minmax(0,0.94fr)]">
|
|
303
|
+
<Card className="min-w-0 overflow-hidden border-border/70 bg-card/95 py-0 gap-0! shadow-[0_18px_40px_-32px_rgba(15,23,42,0.45)]">
|
|
304
|
+
<CardHeader className="border-b border-border/70 bg-linear-to-r from-teal-500/12 via-cyan-500/6 to-transparent pt-2.5 pb-1.5!">
|
|
305
|
+
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
306
|
+
<div className="flex min-w-0 items-start gap-3">
|
|
307
|
+
<div className="flex size-9 shrink-0 items-center justify-center rounded-2xl bg-teal-500/10 text-teal-600 ring-1 ring-inset ring-teal-500/15 dark:text-teal-400">
|
|
308
|
+
<ChartPie className="size-4" />
|
|
309
|
+
</div>
|
|
310
|
+
<div className="min-w-0">
|
|
311
|
+
<div className="text-[10px] font-semibold uppercase tracking-[0.22em] text-teal-600/80 dark:text-teal-400/80">
|
|
312
|
+
Macro areas
|
|
313
|
+
</div>
|
|
314
|
+
<CardTitle className="mt-1 text-sm font-semibold">
|
|
315
|
+
{t('charts.macroAreas.title')}
|
|
316
|
+
</CardTitle>
|
|
317
|
+
<CardDescription className="mt-0.5">
|
|
318
|
+
{t('charts.macroAreas.description')}
|
|
319
|
+
</CardDescription>
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
<div className="rounded-full border border-teal-500/15 bg-teal-500/10 px-2.5 py-1 text-[10px] font-semibold text-teal-700 shadow-sm transition-all duration-200 hover:-translate-y-0.5 hover:bg-teal-500/15 hover:shadow-md dark:text-teal-300">
|
|
323
|
+
{data.areas.length} áreas
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
</CardHeader>
|
|
327
|
+
<CardContent className="grid gap-2.5 px-2.5 py-2.5 sm:px-3 md:grid-cols-[minmax(0,188px)_minmax(0,1fr)] md:items-start">
|
|
328
|
+
<ChartContainer config={areaChartConfig} className="h-48 w-full">
|
|
329
|
+
<PieChart>
|
|
330
|
+
<Pie
|
|
331
|
+
data={areaData}
|
|
332
|
+
dataKey="xp"
|
|
333
|
+
nameKey="name"
|
|
334
|
+
innerRadius={48}
|
|
335
|
+
outerRadius={72}
|
|
336
|
+
paddingAngle={2.5}
|
|
337
|
+
animationDuration={900}
|
|
338
|
+
strokeWidth={3}
|
|
339
|
+
stroke="hsl(var(--background))"
|
|
340
|
+
>
|
|
341
|
+
{areaData.map((entry, index) => (
|
|
342
|
+
<Cell
|
|
343
|
+
key={entry.xpAreaId}
|
|
344
|
+
fill={resolveXpAreaColor({
|
|
345
|
+
areaId: entry.xpAreaId,
|
|
346
|
+
areaSlug: entry.slug,
|
|
347
|
+
index,
|
|
348
|
+
persistedColor: areaColorLookup.get(entry.xpAreaId),
|
|
349
|
+
})}
|
|
350
|
+
/>
|
|
351
|
+
))}
|
|
352
|
+
</Pie>
|
|
353
|
+
<ChartTooltip
|
|
354
|
+
content={
|
|
355
|
+
<ChartTooltipContent
|
|
356
|
+
hideIndicator
|
|
357
|
+
formatter={(value, _name, item) => {
|
|
358
|
+
const payload = item?.payload as
|
|
359
|
+
| {
|
|
360
|
+
name?: string;
|
|
361
|
+
lessonCount?: number;
|
|
362
|
+
segmentCount?: number;
|
|
363
|
+
}
|
|
364
|
+
| undefined;
|
|
365
|
+
return (
|
|
366
|
+
<div className="flex min-w-48 flex-col gap-1 text-xs">
|
|
367
|
+
<span className="font-medium text-foreground">
|
|
368
|
+
{payload?.name}
|
|
369
|
+
</span>
|
|
370
|
+
<span className="text-muted-foreground">
|
|
371
|
+
{formatCompactNumber(Number(value ?? 0), locale)}{' '}
|
|
372
|
+
XP
|
|
373
|
+
</span>
|
|
374
|
+
<span className="text-muted-foreground">
|
|
375
|
+
{payload?.lessonCount ?? 0} aulas ·{' '}
|
|
376
|
+
{payload?.segmentCount ?? 0} segmentos
|
|
377
|
+
</span>
|
|
378
|
+
</div>
|
|
379
|
+
);
|
|
380
|
+
}}
|
|
381
|
+
/>
|
|
382
|
+
}
|
|
383
|
+
/>
|
|
384
|
+
</PieChart>
|
|
385
|
+
</ChartContainer>
|
|
386
|
+
|
|
387
|
+
<div className="grid gap-1.5">
|
|
388
|
+
{areaData.map((item, index) => (
|
|
389
|
+
<div
|
|
390
|
+
key={item.xpAreaId}
|
|
391
|
+
className="rounded-2xl border border-border/60 bg-linear-to-br from-background via-background to-sky-500/5 px-3 py-2 shadow-[0_14px_28px_-24px_rgba(15,23,42,0.45)] transition-all duration-200 hover:-translate-y-0.5 hover:border-sky-500/20 hover:to-sky-500/10 hover:shadow-[0_18px_34px_-22px_rgba(15,23,42,0.5)]"
|
|
392
|
+
>
|
|
393
|
+
<div className="flex items-center gap-2">
|
|
394
|
+
<span
|
|
395
|
+
className="size-2.5 rounded-full"
|
|
396
|
+
style={{
|
|
397
|
+
backgroundColor: resolveXpAreaColor({
|
|
398
|
+
areaId: item.xpAreaId,
|
|
399
|
+
areaSlug: item.slug,
|
|
400
|
+
index,
|
|
401
|
+
persistedColor: areaColorLookup.get(item.xpAreaId),
|
|
402
|
+
}),
|
|
403
|
+
}}
|
|
404
|
+
/>
|
|
405
|
+
<span className="min-w-0 flex-1 truncate text-sm font-medium text-foreground">
|
|
406
|
+
{item.name}
|
|
407
|
+
</span>
|
|
408
|
+
<span className="rounded-full border border-border/50 bg-background/90 px-2 py-0.5 text-[10px] font-semibold text-muted-foreground shadow-sm transition-all duration-200 hover:border-border hover:bg-background hover:text-foreground hover:shadow-md">
|
|
409
|
+
{formatPercentage(item.sharePercent, locale)}%
|
|
410
|
+
</span>
|
|
411
|
+
</div>
|
|
412
|
+
<div className="mt-1.5 flex flex-wrap gap-1">
|
|
413
|
+
<XpMetaPill
|
|
414
|
+
value={`${formatCompactNumber(item.xp, locale)} XP`}
|
|
415
|
+
/>
|
|
416
|
+
<XpMetaPill value={`${item.lessonCount} aulas`} />
|
|
417
|
+
<XpMetaPill value={`${item.segmentCount} seg.`} />
|
|
418
|
+
</div>
|
|
419
|
+
</div>
|
|
420
|
+
))}
|
|
421
|
+
</div>
|
|
422
|
+
</CardContent>
|
|
423
|
+
</Card>
|
|
424
|
+
|
|
425
|
+
<Card className="min-w-0 overflow-hidden border-border/70 bg-card/95 py-0 gap-0! shadow-[0_18px_40px_-32px_rgba(15,23,42,0.45)]">
|
|
426
|
+
<CardHeader className="border-b border-border/70 bg-linear-to-r from-orange-500/12 via-amber-500/6 to-transparent pt-2.5 pb-1.5!">
|
|
427
|
+
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
428
|
+
<div className="flex min-w-0 items-start gap-3">
|
|
429
|
+
<div className="flex size-9 shrink-0 items-center justify-center rounded-2xl bg-orange-500/10 text-orange-600 ring-1 ring-inset ring-orange-500/15 dark:text-orange-400">
|
|
430
|
+
<BarChart3 className="size-4" />
|
|
431
|
+
</div>
|
|
432
|
+
<div className="min-w-0">
|
|
433
|
+
<div className="text-[10px] font-semibold uppercase tracking-[0.22em] text-orange-600/80 dark:text-orange-400/80">
|
|
434
|
+
Skill density
|
|
435
|
+
</div>
|
|
436
|
+
<CardTitle className="mt-1 text-sm font-semibold">
|
|
437
|
+
{t('charts.skills.title')}
|
|
438
|
+
</CardTitle>
|
|
439
|
+
<CardDescription className="mt-0.5">
|
|
440
|
+
{t('charts.skills.description')}
|
|
441
|
+
</CardDescription>
|
|
442
|
+
</div>
|
|
443
|
+
</div>
|
|
444
|
+
<div className="rounded-full border border-orange-500/15 bg-orange-500/10 px-2.5 py-1 text-[10px] font-semibold text-orange-700 shadow-sm transition-all duration-200 hover:-translate-y-0.5 hover:bg-orange-500/15 hover:shadow-md dark:text-orange-300">
|
|
445
|
+
{data.skills.length} skills
|
|
446
|
+
</div>
|
|
447
|
+
</div>
|
|
448
|
+
</CardHeader>
|
|
449
|
+
<CardContent className="flex flex-col gap-2.5 px-2.5 py-2.5 sm:px-3">
|
|
450
|
+
<ChartContainer config={skillChartConfig} className="h-48 w-full">
|
|
451
|
+
<BarChart
|
|
452
|
+
data={skillData}
|
|
453
|
+
layout="vertical"
|
|
454
|
+
margin={{ left: 10, right: 10 }}
|
|
455
|
+
barCategoryGap={10}
|
|
456
|
+
>
|
|
457
|
+
<CartesianGrid horizontal={false} strokeDasharray="3 3" />
|
|
458
|
+
<XAxis type="number" tickLine={false} axisLine={false} />
|
|
459
|
+
<YAxis
|
|
460
|
+
dataKey="name"
|
|
461
|
+
type="category"
|
|
462
|
+
width={120}
|
|
463
|
+
tickLine={false}
|
|
464
|
+
axisLine={false}
|
|
465
|
+
/>
|
|
466
|
+
<ChartTooltip
|
|
467
|
+
cursor={false}
|
|
468
|
+
content={
|
|
469
|
+
<ChartTooltipContent
|
|
470
|
+
hideLabel
|
|
471
|
+
formatter={(value, _name, item) => {
|
|
472
|
+
const payload = item?.payload as
|
|
473
|
+
| {
|
|
474
|
+
name?: string;
|
|
475
|
+
lessonCount?: number;
|
|
476
|
+
segmentCount?: number;
|
|
477
|
+
}
|
|
478
|
+
| undefined;
|
|
479
|
+
return (
|
|
480
|
+
<div className="flex min-w-48 flex-col gap-1 text-xs">
|
|
481
|
+
<span className="font-medium text-foreground">
|
|
482
|
+
{payload?.name}
|
|
483
|
+
</span>
|
|
484
|
+
<span className="text-muted-foreground">
|
|
485
|
+
{formatCompactNumber(Number(value ?? 0), locale)}{' '}
|
|
486
|
+
XP
|
|
487
|
+
</span>
|
|
488
|
+
<span className="text-muted-foreground">
|
|
489
|
+
{payload?.lessonCount ?? 0} aulas ·{' '}
|
|
490
|
+
{payload?.segmentCount ?? 0} segmentos
|
|
491
|
+
</span>
|
|
492
|
+
</div>
|
|
493
|
+
);
|
|
494
|
+
}}
|
|
495
|
+
/>
|
|
496
|
+
}
|
|
497
|
+
/>
|
|
498
|
+
<Bar
|
|
499
|
+
dataKey="xp"
|
|
500
|
+
radius={[0, 10, 10, 0]}
|
|
501
|
+
animationDuration={950}
|
|
502
|
+
>
|
|
503
|
+
{skillData.map((entry, index) => (
|
|
504
|
+
<Cell
|
|
505
|
+
key={entry.xpSkillId}
|
|
506
|
+
fill={resolveXpSkillColor({
|
|
507
|
+
skillId: entry.xpSkillId,
|
|
508
|
+
skillSlug: entry.slug,
|
|
509
|
+
index,
|
|
510
|
+
})}
|
|
511
|
+
/>
|
|
512
|
+
))}
|
|
513
|
+
</Bar>
|
|
514
|
+
</BarChart>
|
|
515
|
+
</ChartContainer>
|
|
516
|
+
|
|
517
|
+
<div className="grid grid-cols-[repeat(auto-fit,minmax(220px,1fr))] gap-1.5">
|
|
518
|
+
{skillData.map((item, index) => (
|
|
519
|
+
<div
|
|
520
|
+
key={item.xpSkillId}
|
|
521
|
+
className="rounded-2xl border border-border/60 bg-linear-to-br from-background via-background to-orange-500/5 px-3 py-2 shadow-[0_14px_28px_-24px_rgba(15,23,42,0.45)] transition-all duration-200 hover:-translate-y-0.5 hover:border-orange-500/20 hover:to-orange-500/10 hover:shadow-[0_18px_34px_-22px_rgba(15,23,42,0.5)]"
|
|
522
|
+
>
|
|
523
|
+
<div className="flex flex-wrap items-center justify-between gap-2">
|
|
524
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
525
|
+
<span
|
|
526
|
+
className="size-2 rounded-full"
|
|
527
|
+
style={{
|
|
528
|
+
backgroundColor: resolveXpSkillColor({
|
|
529
|
+
skillId: item.xpSkillId,
|
|
530
|
+
skillSlug: item.slug,
|
|
531
|
+
index,
|
|
532
|
+
}),
|
|
533
|
+
}}
|
|
534
|
+
/>
|
|
535
|
+
<span className="truncate text-sm font-medium text-foreground">
|
|
536
|
+
{item.name}
|
|
537
|
+
</span>
|
|
538
|
+
</div>
|
|
539
|
+
<span className="rounded-full border border-border/50 bg-background/90 px-2 py-0.5 text-[10px] font-semibold text-muted-foreground shadow-sm transition-all duration-200 hover:border-border hover:bg-background hover:text-foreground hover:shadow-md">
|
|
540
|
+
{formatPercentage(item.sharePercent, locale)}%
|
|
541
|
+
</span>
|
|
542
|
+
</div>
|
|
543
|
+
<div className="mt-1.5 flex flex-wrap gap-1">
|
|
544
|
+
<XpMetaPill
|
|
545
|
+
value={`${formatCompactNumber(item.xp, locale)} XP`}
|
|
546
|
+
/>
|
|
547
|
+
<XpMetaPill value={`${item.lessonCount} aulas`} />
|
|
548
|
+
<XpMetaPill value={`${item.segmentCount} seg.`} />
|
|
549
|
+
</div>
|
|
550
|
+
</div>
|
|
551
|
+
))}
|
|
552
|
+
</div>
|
|
553
|
+
</CardContent>
|
|
554
|
+
</Card>
|
|
555
|
+
</div>
|
|
556
|
+
|
|
557
|
+
{learningTypeData.length > 0 && (
|
|
558
|
+
<Card className="min-w-0 overflow-hidden border-border/70 bg-card/95 py-0 gap-0! shadow-[0_18px_40px_-32px_rgba(15,23,42,0.45)]">
|
|
559
|
+
<CardHeader className="border-b border-border/70 bg-linear-to-r from-violet-500/10 via-fuchsia-500/5 to-transparent pt-2.5 pb-1.5!">
|
|
560
|
+
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
561
|
+
<div className="flex min-w-0 items-start gap-3">
|
|
562
|
+
<div className="flex size-9 shrink-0 items-center justify-center rounded-2xl bg-violet-500/10 text-violet-600 ring-1 ring-inset ring-violet-500/15 dark:text-violet-400">
|
|
563
|
+
<Sparkles className="size-4" />
|
|
564
|
+
</div>
|
|
565
|
+
<div className="min-w-0">
|
|
566
|
+
<div className="text-[10px] font-semibold uppercase tracking-[0.22em] text-violet-600/80 dark:text-violet-400/80">
|
|
567
|
+
Learning mix
|
|
568
|
+
</div>
|
|
569
|
+
<CardTitle className="mt-1 text-sm font-semibold">
|
|
570
|
+
{t('charts.learningTypes.title')}
|
|
571
|
+
</CardTitle>
|
|
572
|
+
<CardDescription className="mt-0.5">
|
|
573
|
+
{t('charts.learningTypes.description')}
|
|
574
|
+
</CardDescription>
|
|
575
|
+
</div>
|
|
576
|
+
</div>
|
|
577
|
+
<div className="rounded-full border border-violet-500/15 bg-violet-500/10 px-2.5 py-1 text-[10px] font-semibold text-violet-700 shadow-sm transition-all duration-200 hover:-translate-y-0.5 hover:bg-violet-500/15 hover:shadow-md dark:text-violet-300">
|
|
578
|
+
{learningTypeData.length} tipos
|
|
579
|
+
</div>
|
|
580
|
+
</div>
|
|
581
|
+
</CardHeader>
|
|
582
|
+
<CardContent className="grid grid-cols-[repeat(auto-fit,minmax(220px,1fr))] content-start gap-2 px-2.5 py-2.5 sm:px-3">
|
|
583
|
+
{learningTypeData.map((item, index) => (
|
|
584
|
+
<div
|
|
585
|
+
key={item.xpLearningTypeId}
|
|
586
|
+
className="flex h-full flex-col justify-start gap-1.5 rounded-2xl border border-border/60 bg-linear-to-br from-background via-background to-violet-500/5 px-3 py-2 shadow-[0_14px_28px_-24px_rgba(15,23,42,0.45)] transition-all duration-200 hover:-translate-y-0.5 hover:border-violet-500/20 hover:to-violet-500/10 hover:shadow-[0_18px_34px_-22px_rgba(15,23,42,0.5)]"
|
|
587
|
+
>
|
|
588
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
589
|
+
<div className="flex min-w-0 flex-1 items-center gap-2">
|
|
590
|
+
<span
|
|
591
|
+
className="size-2.5 rounded-full"
|
|
592
|
+
style={{
|
|
593
|
+
backgroundColor: resolveXpLearningTypeColor({
|
|
594
|
+
learningTypeId: item.xpLearningTypeId,
|
|
595
|
+
learningTypeSlug: item.slug,
|
|
596
|
+
index,
|
|
597
|
+
}),
|
|
598
|
+
}}
|
|
599
|
+
/>
|
|
600
|
+
<span className="min-w-0 flex-1 truncate text-sm font-medium text-foreground">
|
|
601
|
+
{item.name}
|
|
602
|
+
</span>
|
|
603
|
+
</div>
|
|
604
|
+
<span className="rounded-full border border-border/50 bg-background/90 px-2 py-0.5 text-[10px] font-semibold text-muted-foreground shadow-sm transition-all duration-200 hover:border-border hover:bg-background hover:text-foreground hover:shadow-md">
|
|
605
|
+
x{formatPercentage(item.multiplier, locale)}
|
|
606
|
+
</span>
|
|
607
|
+
</div>
|
|
608
|
+
<div className="flex flex-wrap gap-1">
|
|
609
|
+
<XpMetaPill
|
|
610
|
+
value={`${formatCompactNumber(item.xp, locale)} XP`}
|
|
611
|
+
/>
|
|
612
|
+
<XpMetaPill
|
|
613
|
+
value={`${formatPercentage(item.sharePercent, locale)}% share`}
|
|
614
|
+
/>
|
|
615
|
+
</div>
|
|
616
|
+
</div>
|
|
617
|
+
))}
|
|
618
|
+
</CardContent>
|
|
619
|
+
</Card>
|
|
620
|
+
)}
|
|
621
|
+
</div>
|
|
622
|
+
);
|
|
623
|
+
}
|