@hed-hog/lms 0.0.350 → 0.0.351
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/certificate/certificate.controller.d.ts +2 -2
- package/dist/certificate/certificate.controller.d.ts.map +1 -1
- package/dist/certificate/certificate.controller.js +8 -6
- package/dist/certificate/certificate.controller.js.map +1 -1
- package/dist/certificate/certificate.service.d.ts +5 -2
- package/dist/certificate/certificate.service.d.ts.map +1 -1
- package/dist/certificate/certificate.service.js +70 -6
- package/dist/certificate/certificate.service.js.map +1 -1
- package/dist/course/course-structure.controller.d.ts +24 -10
- package/dist/course/course-structure.controller.d.ts.map +1 -1
- package/dist/course/course-structure.controller.js +23 -2
- package/dist/course/course-structure.controller.js.map +1 -1
- package/dist/course/course-structure.service.d.ts +16 -8
- package/dist/course/course-structure.service.d.ts.map +1 -1
- package/dist/course/course-structure.service.js +61 -30
- package/dist/course/course-structure.service.js.map +1 -1
- package/dist/course/course-video-conversion.service.d.ts +37 -0
- package/dist/course/course-video-conversion.service.d.ts.map +1 -0
- package/dist/course/course-video-conversion.service.js +308 -0
- package/dist/course/course-video-conversion.service.js.map +1 -0
- package/dist/course/course.controller.d.ts +17 -0
- package/dist/course/course.controller.d.ts.map +1 -1
- package/dist/course/course.controller.js +23 -0
- 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 -2
- package/dist/course/course.module.js.map +1 -1
- package/dist/course/course.service.d.ts +15 -0
- package/dist/course/course.service.d.ts.map +1 -1
- package/dist/course/course.service.js +103 -49
- package/dist/course/course.service.js.map +1 -1
- package/dist/course/dto/create-course-structure-lesson.dto.d.ts +5 -1
- package/dist/course/dto/create-course-structure-lesson.dto.d.ts.map +1 -1
- package/dist/course/dto/create-course-structure-lesson.dto.js +16 -2
- package/dist/course/dto/create-course-structure-lesson.dto.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 +9 -0
- package/dist/course/dto/create-course.dto.js.map +1 -1
- package/dist/enterprise/enterprise.controller.d.ts +3 -3
- package/dist/enterprise/enterprise.controller.d.ts.map +1 -1
- package/dist/enterprise/enterprise.controller.js +0 -1
- package/dist/enterprise/enterprise.controller.js.map +1 -1
- package/dist/enterprise/enterprise.service.d.ts +3 -3
- package/dist/evaluation/evaluation.service.d.ts.map +1 -1
- package/dist/evaluation/evaluation.service.js +9 -2
- package/dist/evaluation/evaluation.service.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lms.module.d.ts.map +1 -1
- package/dist/lms.module.js +3 -0
- package/dist/lms.module.js.map +1 -1
- package/dist/video-resolution-profile/dto/create-video-resolution-profile.dto.d.ts +6 -0
- package/dist/video-resolution-profile/dto/create-video-resolution-profile.dto.d.ts.map +1 -0
- package/dist/video-resolution-profile/dto/create-video-resolution-profile.dto.js +33 -0
- package/dist/video-resolution-profile/dto/create-video-resolution-profile.dto.js.map +1 -0
- package/dist/video-resolution-profile/dto/update-video-resolution-profile.dto.d.ts +6 -0
- package/dist/video-resolution-profile/dto/update-video-resolution-profile.dto.d.ts.map +1 -0
- package/dist/video-resolution-profile/dto/update-video-resolution-profile.dto.js +33 -0
- package/dist/video-resolution-profile/dto/update-video-resolution-profile.dto.js.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.controller.d.ts +38 -0
- package/dist/video-resolution-profile/video-resolution-profile.controller.d.ts.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.controller.js +89 -0
- package/dist/video-resolution-profile/video-resolution-profile.controller.js.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.mcp-tools.d.ts +26 -0
- package/dist/video-resolution-profile/video-resolution-profile.mcp-tools.d.ts.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.mcp-tools.js +160 -0
- package/dist/video-resolution-profile/video-resolution-profile.mcp-tools.js.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.module.d.ts +3 -0
- package/dist/video-resolution-profile/video-resolution-profile.module.d.ts.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.module.js +26 -0
- package/dist/video-resolution-profile/video-resolution-profile.module.js.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.service.d.ts +45 -0
- package/dist/video-resolution-profile/video-resolution-profile.service.d.ts.map +1 -0
- package/dist/video-resolution-profile/video-resolution-profile.service.js +117 -0
- package/dist/video-resolution-profile/video-resolution-profile.service.js.map +1 -0
- package/hedhog/data/menu.yaml +17 -0
- package/hedhog/data/route.yaml +133 -0
- package/hedhog/data/video_resolution_profile.yaml +7 -0
- package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +269 -324
- package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +124 -70
- package/hedhog/frontend/app/_components/create-lms-instructor-sheet.tsx.ejs +7 -4
- package/hedhog/frontend/app/_components/create-lms-person-sheet.tsx.ejs +2 -2
- package/hedhog/frontend/app/_components/create-lms-student-person-sheet.tsx.ejs +2 -2
- package/hedhog/frontend/app/_lib/editor/templateSerializer.ts.ejs +34 -4
- package/hedhog/frontend/app/_lib/editor/types.ts.ejs +28 -3
- package/hedhog/frontend/app/achievements/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/bitcodes/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/certificates/issued/page.tsx.ejs +7 -3
- package/hedhog/frontend/app/certificates/models/CanvasStage.tsx.ejs +29 -8
- package/hedhog/frontend/app/certificates/models/LeftPanel.tsx.ejs +14 -0
- package/hedhog/frontend/app/certificates/models/RightPanel.tsx.ejs +194 -9
- package/hedhog/frontend/app/certificates/models/page.tsx.ejs +15 -5
- package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +9 -5
- package/hedhog/frontend/app/classes/page.tsx.ejs +73 -47
- package/hedhog/frontend/app/courses/[id]/_components/CourseCertificateCard.tsx.ejs +19 -9
- package/hedhog/frontend/app/courses/[id]/_components/CourseClassificationCard.tsx.ejs +24 -1
- package/hedhog/frontend/app/courses/[id]/_components/CourseContentCard.tsx.ejs +1 -1
- package/hedhog/frontend/app/courses/[id]/_components/CourseMainInfoCard.tsx.ejs +1 -1
- package/hedhog/frontend/app/courses/[id]/_components/CourseRelationsCard.tsx.ejs +28 -16
- package/hedhog/frontend/app/courses/[id]/_components/CourseSectionCard.tsx.ejs +11 -6
- package/hedhog/frontend/app/courses/[id]/_components/CourseSummaryCard.tsx.ejs +7 -4
- package/hedhog/frontend/app/courses/[id]/_components/course-edit-types.ts.ejs +1 -0
- package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +24 -87
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +892 -411
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +1004 -293
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-session.tsx.ejs +11 -11
- package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +62 -52
- package/hedhog/frontend/app/courses/[id]/structure/_components/types.ts.ejs +2 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/adapters/course-structure.adapter.ts.ejs +19 -6
- package/hedhog/frontend/app/courses/[id]/structure/_data/services/course-structure.service.ts.ejs +86 -1
- package/hedhog/frontend/app/courses/[id]/structure/_data/types/api-course.types.ts.ejs +3 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +1 -0
- package/hedhog/frontend/app/courses/page.tsx.ejs +112 -89
- package/hedhog/frontend/app/enterprise/[id]/page.tsx.ejs +1 -1
- package/hedhog/frontend/app/enterprise/_components/enterprise-admin-create-sheet.tsx.ejs +10 -3
- package/hedhog/frontend/app/enterprise/_components/enterprise-detail-sheet.tsx.ejs +8 -4
- package/hedhog/frontend/app/enterprise/_components/enterprise-person-edit-sheet.tsx.ejs +2 -2
- package/hedhog/frontend/app/enterprise/_components/enterprise-sheet.tsx.ejs +10 -4
- package/hedhog/frontend/app/enterprise/_components/enterprise-student-create-sheet.tsx.ejs +10 -3
- package/hedhog/frontend/app/enterprise/_components/enterprise-user-create-sheet.tsx.ejs +10 -3
- package/hedhog/frontend/app/evaluations/_components/evaluation-topic-form-sheet.tsx.ejs +10 -3
- package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +23 -9
- package/hedhog/frontend/app/exams/page.tsx.ejs +14 -6
- package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +9 -3
- package/hedhog/frontend/app/instructors/_components/instructor-form-sheet.tsx.ejs +190 -17
- package/hedhog/frontend/app/layout.tsx.ejs +5 -1
- package/hedhog/frontend/app/paths/page.tsx.ejs +13 -5
- package/hedhog/frontend/app/reports/evaluations/page.tsx.ejs +10 -10
- package/hedhog/frontend/app/training/page.tsx.ejs +13 -5
- package/hedhog/frontend/app/video-resolution-profiles/page.tsx.ejs +607 -0
- package/hedhog/frontend/messages/en.json +250 -9
- package/hedhog/frontend/messages/pt.json +250 -9
- package/hedhog/table/course.yaml +4 -0
- package/hedhog/table/course_lesson_file.yaml +8 -0
- package/hedhog/table/course_video_resolution_profile.yaml +22 -0
- package/hedhog/table/video_resolution_profile.yaml +18 -0
- package/package.json +7 -6
- package/src/certificate/certificate.controller.ts +19 -14
- package/src/certificate/certificate.service.ts +106 -11
- package/src/course/course-structure.controller.ts +24 -2
- package/src/course/course-structure.service.ts +21 -4
- package/src/course/course-video-conversion.service.ts +415 -0
- package/src/course/course.controller.ts +18 -0
- package/src/course/course.module.ts +15 -2
- package/src/course/course.service.ts +72 -2
- package/src/course/dto/create-course-structure-lesson.dto.ts +13 -2
- package/src/course/dto/create-course.dto.ts +8 -0
- package/src/enterprise/enterprise.controller.ts +0 -1
- package/src/evaluation/evaluation.service.ts +9 -2
- package/src/index.ts +1 -0
- package/src/lms.module.ts +3 -0
- package/src/video-resolution-profile/dto/create-video-resolution-profile.dto.ts +16 -0
- package/src/video-resolution-profile/dto/update-video-resolution-profile.dto.ts +16 -0
- package/src/video-resolution-profile/video-resolution-profile.controller.ts +62 -0
- package/src/video-resolution-profile/video-resolution-profile.mcp-tools.ts +128 -0
- package/src/video-resolution-profile/video-resolution-profile.module.ts +13 -0
- package/src/video-resolution-profile/video-resolution-profile.service.ts +117 -0
|
@@ -48,12 +48,12 @@ import {
|
|
|
48
48
|
import { Separator } from '@/components/ui/separator';
|
|
49
49
|
import {
|
|
50
50
|
Sheet,
|
|
51
|
-
SheetContent,
|
|
52
51
|
SheetDescription,
|
|
53
52
|
SheetFooter,
|
|
54
53
|
SheetHeader,
|
|
55
54
|
SheetTitle,
|
|
56
55
|
} from '@/components/ui/sheet';
|
|
56
|
+
import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
|
|
57
57
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
58
58
|
import {
|
|
59
59
|
Table,
|
|
@@ -642,7 +642,10 @@ export default function QuestoesPage() {
|
|
|
642
642
|
});
|
|
643
643
|
|
|
644
644
|
const questaoSchema = z.object({
|
|
645
|
-
subjectId: z.coerce
|
|
645
|
+
subjectId: z.coerce
|
|
646
|
+
.number()
|
|
647
|
+
.int()
|
|
648
|
+
.min(1, t('sheet.validation.subjectRequired')),
|
|
646
649
|
enunciado: z.string().min(5, t('sheet.validation.statementMin')),
|
|
647
650
|
explicacao: z.string().optional(),
|
|
648
651
|
questionType: z.enum([
|
|
@@ -739,7 +742,6 @@ export default function QuestoesPage() {
|
|
|
739
742
|
setCurrentPage(1);
|
|
740
743
|
}
|
|
741
744
|
|
|
742
|
-
|
|
743
745
|
async function loadQuestionSubjectOptions(args: {
|
|
744
746
|
page: number;
|
|
745
747
|
pageSize: number;
|
|
@@ -1586,7 +1588,11 @@ export default function QuestoesPage() {
|
|
|
1586
1588
|
|
|
1587
1589
|
{/* Create/Edit Sheet */}
|
|
1588
1590
|
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
|
|
1589
|
-
<
|
|
1591
|
+
<ResizableSheetContent
|
|
1592
|
+
sheetId="lms-exam-questions-form-sheet"
|
|
1593
|
+
defaultWidth={560}
|
|
1594
|
+
minWidth={420}
|
|
1595
|
+
maxWidth={920}
|
|
1590
1596
|
side="right"
|
|
1591
1597
|
className="flex w-full flex-col sm:max-w-lg overflow-y-auto"
|
|
1592
1598
|
>
|
|
@@ -1616,20 +1622,28 @@ export default function QuestoesPage() {
|
|
|
1616
1622
|
value={field.value || null}
|
|
1617
1623
|
valueType="number"
|
|
1618
1624
|
placeholder={t('sheet.fields.subjectPlaceholder')}
|
|
1619
|
-
searchPlaceholder={t(
|
|
1625
|
+
searchPlaceholder={t(
|
|
1626
|
+
'sheet.fields.subjectSearchPlaceholder'
|
|
1627
|
+
)}
|
|
1620
1628
|
entityLabel={t('sheet.fields.subjectEntityLabel')}
|
|
1621
1629
|
noResultsLabel={t('sheet.fields.subjectNoResults')}
|
|
1622
1630
|
options={assuntosLocais}
|
|
1623
1631
|
loadOptions={loadQuestionSubjectOptions}
|
|
1624
1632
|
getOptionLabel={(option) => option.name}
|
|
1625
|
-
getOptionDescription={(option) =>
|
|
1633
|
+
getOptionDescription={(option) =>
|
|
1634
|
+
option.description ?? undefined
|
|
1635
|
+
}
|
|
1626
1636
|
createTitle={t('sheet.fields.subjectCreateTitle')}
|
|
1627
|
-
createDescription={t(
|
|
1637
|
+
createDescription={t(
|
|
1638
|
+
'sheet.fields.subjectCreateDescription'
|
|
1639
|
+
)}
|
|
1628
1640
|
createFields={[
|
|
1629
1641
|
{
|
|
1630
1642
|
name: 'name',
|
|
1631
1643
|
label: t('sheet.fields.subjectCreateNameLabel'),
|
|
1632
|
-
placeholder: t(
|
|
1644
|
+
placeholder: t(
|
|
1645
|
+
'sheet.fields.subjectCreateNamePlaceholder'
|
|
1646
|
+
),
|
|
1633
1647
|
required: true,
|
|
1634
1648
|
},
|
|
1635
1649
|
]}
|
|
@@ -1983,7 +1997,7 @@ export default function QuestoesPage() {
|
|
|
1983
1997
|
</SheetFooter>
|
|
1984
1998
|
</form>
|
|
1985
1999
|
</Form>
|
|
1986
|
-
</
|
|
2000
|
+
</ResizableSheetContent>
|
|
1987
2001
|
</Sheet>
|
|
1988
2002
|
|
|
1989
2003
|
{/* Delete Dialog */}
|
|
@@ -43,12 +43,12 @@ import {
|
|
|
43
43
|
} from '@/components/ui/select';
|
|
44
44
|
import {
|
|
45
45
|
Sheet,
|
|
46
|
-
SheetContent,
|
|
47
46
|
SheetDescription,
|
|
48
47
|
SheetFooter,
|
|
49
48
|
SheetHeader,
|
|
50
49
|
SheetTitle,
|
|
51
50
|
} from '@/components/ui/sheet';
|
|
51
|
+
import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
|
|
52
52
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
53
53
|
import { Switch } from '@/components/ui/switch';
|
|
54
54
|
import {
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
TableHeader,
|
|
60
60
|
TableRow,
|
|
61
61
|
} from '@/components/ui/table';
|
|
62
|
+
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
62
63
|
import { usePersistedViewMode } from '@/hooks/use-persisted-view-mode';
|
|
63
64
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
64
65
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
@@ -83,7 +84,6 @@ import {
|
|
|
83
84
|
import { useTranslations } from 'next-intl';
|
|
84
85
|
import { useRouter } from 'next/navigation';
|
|
85
86
|
import { useEffect, useMemo, useState } from 'react';
|
|
86
|
-
import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
|
|
87
87
|
import { Controller, useForm, useWatch } from 'react-hook-form';
|
|
88
88
|
import { toast } from 'sonner';
|
|
89
89
|
import { z } from 'zod';
|
|
@@ -787,7 +787,9 @@ export default function ExamesPage() {
|
|
|
787
787
|
<motion.div key={exame.id} variants={fadeUp}>
|
|
788
788
|
<Card
|
|
789
789
|
className="group relative h-95 cursor-pointer overflow-hidden border-border/70 shadow-sm transition-all duration-200 hover:border-border hover:shadow-md"
|
|
790
|
-
onDoubleClick={() =>
|
|
790
|
+
onDoubleClick={() =>
|
|
791
|
+
router.push(`/lms/exams/${exame.id}`)
|
|
792
|
+
}
|
|
791
793
|
title={t('cards.tooltip')}
|
|
792
794
|
>
|
|
793
795
|
<div
|
|
@@ -966,7 +968,9 @@ export default function ExamesPage() {
|
|
|
966
968
|
<TableRow
|
|
967
969
|
key={exame.id}
|
|
968
970
|
className="cursor-pointer"
|
|
969
|
-
onDoubleClick={() =>
|
|
971
|
+
onDoubleClick={() =>
|
|
972
|
+
router.push(`/lms/exams/${exame.id}`)
|
|
973
|
+
}
|
|
970
974
|
title={t('cards.tooltip')}
|
|
971
975
|
>
|
|
972
976
|
<TableCell>
|
|
@@ -1076,7 +1080,11 @@ export default function ExamesPage() {
|
|
|
1076
1080
|
|
|
1077
1081
|
{/* Sheet */}
|
|
1078
1082
|
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
|
|
1079
|
-
<
|
|
1083
|
+
<ResizableSheetContent
|
|
1084
|
+
sheetId="lms-exams-form-sheet"
|
|
1085
|
+
defaultWidth={560}
|
|
1086
|
+
minWidth={420}
|
|
1087
|
+
maxWidth={920}
|
|
1080
1088
|
side="right"
|
|
1081
1089
|
className="flex w-full flex-col sm:max-w-lg overflow-y-auto"
|
|
1082
1090
|
>
|
|
@@ -1325,7 +1333,7 @@ export default function ExamesPage() {
|
|
|
1325
1333
|
</Button>
|
|
1326
1334
|
</SheetFooter>
|
|
1327
1335
|
</form>
|
|
1328
|
-
</
|
|
1336
|
+
</ResizableSheetContent>
|
|
1329
1337
|
</Sheet>
|
|
1330
1338
|
|
|
1331
1339
|
{/* Delete Dialog */}
|
|
@@ -43,10 +43,10 @@ import {
|
|
|
43
43
|
} from '@/components/ui/select';
|
|
44
44
|
import {
|
|
45
45
|
Sheet,
|
|
46
|
-
SheetContent,
|
|
47
46
|
SheetHeader,
|
|
48
47
|
SheetTitle,
|
|
49
48
|
} from '@/components/ui/sheet';
|
|
49
|
+
import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
|
|
50
50
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
51
51
|
import {
|
|
52
52
|
Table,
|
|
@@ -176,7 +176,13 @@ function SkillFormSheet({
|
|
|
176
176
|
|
|
177
177
|
return (
|
|
178
178
|
<Sheet open={open} onOpenChange={onOpenChange}>
|
|
179
|
-
<
|
|
179
|
+
<ResizableSheetContent
|
|
180
|
+
sheetId="lms-instructor-skills-form-sheet"
|
|
181
|
+
defaultWidth={520}
|
|
182
|
+
minWidth={400}
|
|
183
|
+
maxWidth={860}
|
|
184
|
+
className="w-full overflow-y-auto sm:max-w-md"
|
|
185
|
+
>
|
|
180
186
|
<SheetHeader>
|
|
181
187
|
<SheetTitle>
|
|
182
188
|
{skillToEdit ? t('sheet.editTitle') : t('sheet.createTitle')}
|
|
@@ -250,7 +256,7 @@ function SkillFormSheet({
|
|
|
250
256
|
</div>
|
|
251
257
|
</form>
|
|
252
258
|
</Form>
|
|
253
|
-
</
|
|
259
|
+
</ResizableSheetContent>
|
|
254
260
|
</Sheet>
|
|
255
261
|
);
|
|
256
262
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { PersonPicker } from '@/app/(app)/(libraries)/
|
|
4
|
-
import { PersonFormSheet } from '@/app/(app)/(libraries)/
|
|
3
|
+
import { PersonPicker } from '@/app/(app)/(libraries)/crm/_components/person-picker';
|
|
4
|
+
import { PersonFormSheet } from '@/app/(app)/(libraries)/crm/person/_components/person-form-sheet';
|
|
5
5
|
import type {
|
|
6
6
|
ContactTypeOption,
|
|
7
7
|
DocumentTypeOption,
|
|
8
8
|
Person,
|
|
9
|
-
} from '@/app/(app)/(libraries)/
|
|
9
|
+
} from '@/app/(app)/(libraries)/crm/person/_components/person-types';
|
|
10
10
|
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
|
11
11
|
import { Badge } from '@/components/ui/badge';
|
|
12
12
|
import { Button } from '@/components/ui/button';
|
|
@@ -23,12 +23,12 @@ import {
|
|
|
23
23
|
} from '@/components/ui/select';
|
|
24
24
|
import {
|
|
25
25
|
Sheet,
|
|
26
|
-
SheetContent,
|
|
27
26
|
SheetDescription,
|
|
28
27
|
SheetFooter,
|
|
29
28
|
SheetHeader,
|
|
30
29
|
SheetTitle,
|
|
31
30
|
} from '@/components/ui/sheet';
|
|
31
|
+
import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
|
|
32
32
|
import { Switch } from '@/components/ui/switch';
|
|
33
33
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
34
34
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
@@ -69,6 +69,27 @@ type ClassGroupItem = {
|
|
|
69
69
|
totalSlots: number | null;
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
+
type EvaluationItem = {
|
|
73
|
+
id: number;
|
|
74
|
+
topicName: string;
|
|
75
|
+
topicDescription: string | null;
|
|
76
|
+
targetType: string;
|
|
77
|
+
targetName: string;
|
|
78
|
+
score: number;
|
|
79
|
+
comment: string | null;
|
|
80
|
+
evaluatorName: string | null;
|
|
81
|
+
evaluatorId: number | null;
|
|
82
|
+
courseName: string | null;
|
|
83
|
+
courseId: number | null;
|
|
84
|
+
className: string | null;
|
|
85
|
+
classId: number | null;
|
|
86
|
+
instructorName: string | null;
|
|
87
|
+
instructorId: number | null;
|
|
88
|
+
createdAt: string;
|
|
89
|
+
topicAvgScore: number;
|
|
90
|
+
topicRatingCount: number;
|
|
91
|
+
};
|
|
92
|
+
|
|
72
93
|
function toKebabCase(str: string) {
|
|
73
94
|
return (
|
|
74
95
|
str
|
|
@@ -127,6 +148,8 @@ export function InstructorFormSheet({
|
|
|
127
148
|
const [classSheetOpen, setClassSheetOpen] = useState(false);
|
|
128
149
|
const [editingClassId, setEditingClassId] = useState<number | null>(null);
|
|
129
150
|
const TURMAS_PAGE_SIZE = 6;
|
|
151
|
+
const [avaliacoesPage, setAvaliacoesPage] = useState(1);
|
|
152
|
+
const AVALIACOES_PAGE_SIZE = 6;
|
|
130
153
|
const isEditing = typeof instructorId === 'number' && instructorId > 0;
|
|
131
154
|
const qualificationOptions = [
|
|
132
155
|
{
|
|
@@ -329,6 +352,38 @@ export function InstructorFormSheet({
|
|
|
329
352
|
const turmasData = turmasResult?.data ?? [];
|
|
330
353
|
const turmasLastPage = turmasResult?.lastPage ?? 1;
|
|
331
354
|
|
|
355
|
+
const {
|
|
356
|
+
data: avaliacoesResult,
|
|
357
|
+
isLoading: loadingAvaliacoes,
|
|
358
|
+
} = useQuery<{
|
|
359
|
+
data: EvaluationItem[];
|
|
360
|
+
total: number;
|
|
361
|
+
lastPage: number;
|
|
362
|
+
}>({
|
|
363
|
+
queryKey: ['lms-instructor-avaliacoes', instructorId, avaliacoesPage],
|
|
364
|
+
queryFn: async () => {
|
|
365
|
+
if (!instructorId) return { data: [], total: 0, lastPage: 1 };
|
|
366
|
+
const params = new URLSearchParams({
|
|
367
|
+
instructorId: String(instructorId),
|
|
368
|
+
page: String(avaliacoesPage),
|
|
369
|
+
pageSize: String(AVALIACOES_PAGE_SIZE),
|
|
370
|
+
});
|
|
371
|
+
const response = await request<{
|
|
372
|
+
data: EvaluationItem[];
|
|
373
|
+
total: number;
|
|
374
|
+
lastPage: number;
|
|
375
|
+
}>({
|
|
376
|
+
url: `/lms/evaluations?${params.toString()}`,
|
|
377
|
+
method: 'GET',
|
|
378
|
+
});
|
|
379
|
+
return response.data;
|
|
380
|
+
},
|
|
381
|
+
enabled: isEditing && open && activeTab === 'avaliacoes',
|
|
382
|
+
placeholderData: (prev) => prev,
|
|
383
|
+
});
|
|
384
|
+
const avaliacoesData = avaliacoesResult?.data ?? [];
|
|
385
|
+
const avaliacoesLastPage = avaliacoesResult?.lastPage ?? 1;
|
|
386
|
+
|
|
332
387
|
useEffect(() => {
|
|
333
388
|
const timeout = setTimeout(() => {
|
|
334
389
|
setDebouncedTurmasSearch(turmasSearchInput.trim());
|
|
@@ -377,7 +432,7 @@ export function InstructorFormSheet({
|
|
|
377
432
|
}
|
|
378
433
|
}, [isEditing, existingInstructor, open, reset]);
|
|
379
434
|
|
|
380
|
-
// Reset to first tab and turmas page when sheet closes
|
|
435
|
+
// Reset to first tab and turmas/avaliacoes page when sheet closes
|
|
381
436
|
useEffect(() => {
|
|
382
437
|
if (!open) {
|
|
383
438
|
setActiveTab('detalhes');
|
|
@@ -387,6 +442,7 @@ export function InstructorFormSheet({
|
|
|
387
442
|
setTurmasStatusFilter('all');
|
|
388
443
|
setClassSheetOpen(false);
|
|
389
444
|
setEditingClassId(null);
|
|
445
|
+
setAvaliacoesPage(1);
|
|
390
446
|
}
|
|
391
447
|
}, [open]);
|
|
392
448
|
|
|
@@ -489,9 +545,13 @@ export function InstructorFormSheet({
|
|
|
489
545
|
return (
|
|
490
546
|
<>
|
|
491
547
|
<Sheet open={open} onOpenChange={handleSheetClose}>
|
|
492
|
-
<
|
|
548
|
+
<ResizableSheetContent
|
|
549
|
+
sheetId="lms-instructors-form-sheet"
|
|
550
|
+
defaultWidth={640}
|
|
551
|
+
minWidth={460}
|
|
552
|
+
maxWidth={1100}
|
|
493
553
|
side="right"
|
|
494
|
-
className="flex w-full
|
|
554
|
+
className="flex w-full flex-col overflow-hidden p-0"
|
|
495
555
|
>
|
|
496
556
|
{/* ── Instructor header (edit mode) ── */}
|
|
497
557
|
{isEditing && existingInstructor ? (
|
|
@@ -1136,15 +1196,128 @@ export function InstructorFormSheet({
|
|
|
1136
1196
|
value="avaliacoes"
|
|
1137
1197
|
className="flex min-h-0 flex-1 flex-col overflow-hidden data-[state=inactive]:hidden"
|
|
1138
1198
|
>
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
<
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1199
|
+
<div className="flex min-h-0 flex-1 flex-col">
|
|
1200
|
+
{/* List area */}
|
|
1201
|
+
<div className="flex-1 overflow-y-auto px-6 py-4">
|
|
1202
|
+
{loadingAvaliacoes ? (
|
|
1203
|
+
<div className="flex flex-col gap-3">
|
|
1204
|
+
{Array.from({ length: 3 }).map((_, i) => (
|
|
1205
|
+
<div
|
|
1206
|
+
key={i}
|
|
1207
|
+
className="flex flex-col gap-2 rounded-lg border p-4"
|
|
1208
|
+
>
|
|
1209
|
+
<div className="flex items-center justify-between">
|
|
1210
|
+
<div className="h-4 w-32 animate-pulse rounded bg-muted" />
|
|
1211
|
+
<div className="h-4 w-16 animate-pulse rounded bg-muted" />
|
|
1212
|
+
</div>
|
|
1213
|
+
<div className="h-3 w-48 animate-pulse rounded bg-muted" />
|
|
1214
|
+
<div className="h-3 w-64 animate-pulse rounded bg-muted" />
|
|
1215
|
+
</div>
|
|
1216
|
+
))}
|
|
1217
|
+
</div>
|
|
1218
|
+
) : avaliacoesData.length === 0 ? (
|
|
1219
|
+
<div className="flex flex-col items-center justify-center py-12 text-center">
|
|
1220
|
+
<Star className="mb-3 h-10 w-10 text-muted-foreground/40" />
|
|
1221
|
+
<p className="text-sm font-medium text-muted-foreground">
|
|
1222
|
+
{t('form.evaluations.emptyTitle')}
|
|
1223
|
+
</p>
|
|
1224
|
+
<p className="mt-1 text-xs text-muted-foreground">
|
|
1225
|
+
{t('form.evaluations.emptyDescription')}
|
|
1226
|
+
</p>
|
|
1227
|
+
</div>
|
|
1228
|
+
) : (
|
|
1229
|
+
<div className="flex flex-col gap-3">
|
|
1230
|
+
{avaliacoesData.map((ev) => (
|
|
1231
|
+
<div
|
|
1232
|
+
key={ev.id}
|
|
1233
|
+
className="flex flex-col gap-2 rounded-lg border p-4"
|
|
1234
|
+
>
|
|
1235
|
+
{/* Header: topic name + score */}
|
|
1236
|
+
<div className="flex items-start justify-between gap-2">
|
|
1237
|
+
<p className="text-sm font-medium leading-snug">
|
|
1238
|
+
{ev.topicName}
|
|
1239
|
+
</p>
|
|
1240
|
+
<div className="flex shrink-0 items-center gap-1">
|
|
1241
|
+
{Array.from({ length: 5 }).map((_, i) => (
|
|
1242
|
+
<Star
|
|
1243
|
+
key={i}
|
|
1244
|
+
className={`h-3.5 w-3.5 ${
|
|
1245
|
+
i < Math.round(ev.score / 2)
|
|
1246
|
+
? 'fill-amber-400 text-amber-400'
|
|
1247
|
+
: 'fill-none text-muted-foreground/40'
|
|
1248
|
+
}`}
|
|
1249
|
+
/>
|
|
1250
|
+
))}
|
|
1251
|
+
<span className="ml-1 text-xs font-medium tabular-nums text-muted-foreground">
|
|
1252
|
+
{ev.score.toFixed(1)}{t('form.evaluations.of')}10
|
|
1253
|
+
</span>
|
|
1254
|
+
</div>
|
|
1255
|
+
</div>
|
|
1256
|
+
|
|
1257
|
+
{/* Target + course/class info */}
|
|
1258
|
+
<div className="flex flex-wrap items-center gap-x-2 gap-y-1">
|
|
1259
|
+
{ev.className && (
|
|
1260
|
+
<span className="text-xs text-muted-foreground">
|
|
1261
|
+
<BookOpen className="mr-0.5 inline h-3 w-3" />
|
|
1262
|
+
{ev.className}
|
|
1263
|
+
</span>
|
|
1264
|
+
)}
|
|
1265
|
+
{ev.courseName && (
|
|
1266
|
+
<span className="text-xs text-muted-foreground">
|
|
1267
|
+
· {ev.courseName}
|
|
1268
|
+
</span>
|
|
1269
|
+
)}
|
|
1270
|
+
</div>
|
|
1271
|
+
|
|
1272
|
+
{/* Evaluator + date */}
|
|
1273
|
+
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
1274
|
+
<span>
|
|
1275
|
+
{ev.evaluatorName ?? t('form.evaluations.anonymous')}
|
|
1276
|
+
</span>
|
|
1277
|
+
<span>·</span>
|
|
1278
|
+
<span>
|
|
1279
|
+
{new Date(ev.createdAt).toLocaleDateString()}
|
|
1280
|
+
</span>
|
|
1281
|
+
</div>
|
|
1282
|
+
|
|
1283
|
+
{/* Comment */}
|
|
1284
|
+
{ev.comment && (
|
|
1285
|
+
<p className="line-clamp-2 text-xs text-muted-foreground italic">
|
|
1286
|
+
"{ev.comment}"
|
|
1287
|
+
</p>
|
|
1288
|
+
)}
|
|
1289
|
+
</div>
|
|
1290
|
+
))}
|
|
1291
|
+
</div>
|
|
1292
|
+
)}
|
|
1293
|
+
</div>
|
|
1294
|
+
|
|
1295
|
+
{/* Pagination */}
|
|
1296
|
+
{avaliacoesLastPage > 1 && (
|
|
1297
|
+
<div className="flex shrink-0 items-center justify-center gap-2 border-t px-6 py-3">
|
|
1298
|
+
<Button
|
|
1299
|
+
type="button"
|
|
1300
|
+
variant="outline"
|
|
1301
|
+
size="icon"
|
|
1302
|
+
disabled={avaliacoesPage <= 1}
|
|
1303
|
+
onClick={() => setAvaliacoesPage((p) => p - 1)}
|
|
1304
|
+
>
|
|
1305
|
+
<ChevronLeft className="h-4 w-4" />
|
|
1306
|
+
</Button>
|
|
1307
|
+
<span className="text-xs text-muted-foreground">
|
|
1308
|
+
{avaliacoesPage} / {avaliacoesLastPage}
|
|
1309
|
+
</span>
|
|
1310
|
+
<Button
|
|
1311
|
+
type="button"
|
|
1312
|
+
variant="outline"
|
|
1313
|
+
size="icon"
|
|
1314
|
+
disabled={avaliacoesPage >= avaliacoesLastPage}
|
|
1315
|
+
onClick={() => setAvaliacoesPage((p) => p + 1)}
|
|
1316
|
+
>
|
|
1317
|
+
<ChevronRight className="h-4 w-4" />
|
|
1318
|
+
</Button>
|
|
1319
|
+
</div>
|
|
1320
|
+
)}
|
|
1148
1321
|
</div>
|
|
1149
1322
|
</TabsContent>
|
|
1150
1323
|
</Tabs>
|
|
@@ -1343,7 +1516,7 @@ export function InstructorFormSheet({
|
|
|
1343
1516
|
</SheetFooter>
|
|
1344
1517
|
</form>
|
|
1345
1518
|
)}
|
|
1346
|
-
</
|
|
1519
|
+
</ResizableSheetContent>
|
|
1347
1520
|
</Sheet>
|
|
1348
1521
|
|
|
1349
1522
|
<ClassFormSheet
|
|
@@ -47,12 +47,12 @@ import {
|
|
|
47
47
|
import { Separator } from '@/components/ui/separator';
|
|
48
48
|
import {
|
|
49
49
|
Sheet,
|
|
50
|
-
SheetContent,
|
|
51
50
|
SheetDescription,
|
|
52
51
|
SheetFooter,
|
|
53
52
|
SheetHeader,
|
|
54
53
|
SheetTitle,
|
|
55
54
|
} from '@/components/ui/sheet';
|
|
55
|
+
import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
|
|
56
56
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
57
57
|
import { Switch } from '@/components/ui/switch';
|
|
58
58
|
import {
|
|
@@ -1883,7 +1883,11 @@ export default function TrainingPage() {
|
|
|
1883
1883
|
|
|
1884
1884
|
{/* Sheet */}
|
|
1885
1885
|
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
|
|
1886
|
-
<
|
|
1886
|
+
<ResizableSheetContent
|
|
1887
|
+
sheetId="lms-paths-form-sheet"
|
|
1888
|
+
defaultWidth={560}
|
|
1889
|
+
minWidth={420}
|
|
1890
|
+
maxWidth={920}
|
|
1887
1891
|
side="right"
|
|
1888
1892
|
className="flex w-full flex-col sm:max-w-lg overflow-y-auto"
|
|
1889
1893
|
>
|
|
@@ -2241,7 +2245,7 @@ export default function TrainingPage() {
|
|
|
2241
2245
|
</Button>
|
|
2242
2246
|
</SheetFooter>
|
|
2243
2247
|
</form>
|
|
2244
|
-
</
|
|
2248
|
+
</ResizableSheetContent>
|
|
2245
2249
|
</Sheet>
|
|
2246
2250
|
|
|
2247
2251
|
<CourseFormSheet
|
|
@@ -2257,7 +2261,11 @@ export default function TrainingPage() {
|
|
|
2257
2261
|
/>
|
|
2258
2262
|
|
|
2259
2263
|
<Sheet open={examSheetOpen} onOpenChange={setExamSheetOpen}>
|
|
2260
|
-
<
|
|
2264
|
+
<ResizableSheetContent
|
|
2265
|
+
sheetId="lms-paths-create-exam-sheet"
|
|
2266
|
+
defaultWidth={560}
|
|
2267
|
+
minWidth={420}
|
|
2268
|
+
maxWidth={920}
|
|
2261
2269
|
side="right"
|
|
2262
2270
|
className="flex w-full flex-col sm:max-w-lg overflow-y-auto"
|
|
2263
2271
|
>
|
|
@@ -2370,7 +2378,7 @@ export default function TrainingPage() {
|
|
|
2370
2378
|
</Button>
|
|
2371
2379
|
</SheetFooter>
|
|
2372
2380
|
</form>
|
|
2373
|
-
</
|
|
2381
|
+
</ResizableSheetContent>
|
|
2374
2382
|
</Sheet>
|
|
2375
2383
|
|
|
2376
2384
|
{/* Delete Dialog */}
|
|
@@ -25,12 +25,8 @@ import {
|
|
|
25
25
|
PopoverContent,
|
|
26
26
|
PopoverTrigger,
|
|
27
27
|
} from '@/components/ui/popover';
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
SheetContent,
|
|
31
|
-
SheetHeader,
|
|
32
|
-
SheetTitle,
|
|
33
|
-
} from '@/components/ui/sheet';
|
|
28
|
+
import { Sheet, SheetHeader, SheetTitle } from '@/components/ui/sheet';
|
|
29
|
+
import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
|
|
34
30
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
35
31
|
import {
|
|
36
32
|
Table,
|
|
@@ -981,7 +977,11 @@ export default function EvaluationsReportPage() {
|
|
|
981
977
|
|
|
982
978
|
{/* Detail Sheet */}
|
|
983
979
|
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
|
|
984
|
-
<
|
|
980
|
+
<ResizableSheetContent
|
|
981
|
+
sheetId="lms-reports-evaluations-detail-sheet"
|
|
982
|
+
defaultWidth={640}
|
|
983
|
+
minWidth={460}
|
|
984
|
+
maxWidth={1080}
|
|
985
985
|
side="right"
|
|
986
986
|
className="w-full overflow-y-auto p-0 sm:max-w-xl"
|
|
987
987
|
>
|
|
@@ -1166,7 +1166,7 @@ export default function EvaluationsReportPage() {
|
|
|
1166
1166
|
<div className="grid grid-cols-2 gap-3">
|
|
1167
1167
|
<button
|
|
1168
1168
|
type="button"
|
|
1169
|
-
onClick={() => window.open('/
|
|
1169
|
+
onClick={() => window.open('/crm/accounts', '_blank')}
|
|
1170
1170
|
className="flex items-center gap-3 rounded-lg border border-border/50 bg-card p-3 text-left transition-colors hover:bg-muted/40"
|
|
1171
1171
|
>
|
|
1172
1172
|
<Avatar className="size-9 shrink-0">
|
|
@@ -1188,7 +1188,7 @@ export default function EvaluationsReportPage() {
|
|
|
1188
1188
|
<button
|
|
1189
1189
|
type="button"
|
|
1190
1190
|
onClick={() =>
|
|
1191
|
-
window.open('/
|
|
1191
|
+
window.open('/crm/accounts', '_blank')
|
|
1192
1192
|
}
|
|
1193
1193
|
className="flex items-center gap-3 rounded-lg border border-border/50 bg-card p-3 text-left transition-colors hover:bg-muted/40"
|
|
1194
1194
|
>
|
|
@@ -1276,7 +1276,7 @@ export default function EvaluationsReportPage() {
|
|
|
1276
1276
|
</div>
|
|
1277
1277
|
</>
|
|
1278
1278
|
)}
|
|
1279
|
-
</
|
|
1279
|
+
</ResizableSheetContent>
|
|
1280
1280
|
</Sheet>
|
|
1281
1281
|
</Page>
|
|
1282
1282
|
);
|
|
@@ -46,12 +46,12 @@ import {
|
|
|
46
46
|
import { Separator } from '@/components/ui/separator';
|
|
47
47
|
import {
|
|
48
48
|
Sheet,
|
|
49
|
-
SheetContent,
|
|
50
49
|
SheetDescription,
|
|
51
50
|
SheetFooter,
|
|
52
51
|
SheetHeader,
|
|
53
52
|
SheetTitle,
|
|
54
53
|
} from '@/components/ui/sheet';
|
|
54
|
+
import { ResizableSheetContent } from '@/components/ui/resizable-sheet-content';
|
|
55
55
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
56
56
|
import { Switch } from '@/components/ui/switch';
|
|
57
57
|
import {
|
|
@@ -1873,7 +1873,11 @@ export default function TrainingPage() {
|
|
|
1873
1873
|
|
|
1874
1874
|
{/* Sheet */}
|
|
1875
1875
|
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
|
|
1876
|
-
<
|
|
1876
|
+
<ResizableSheetContent
|
|
1877
|
+
sheetId="lms-training-form-sheet"
|
|
1878
|
+
defaultWidth={560}
|
|
1879
|
+
minWidth={420}
|
|
1880
|
+
maxWidth={920}
|
|
1877
1881
|
side="right"
|
|
1878
1882
|
className="flex w-full flex-col sm:max-w-lg overflow-y-auto"
|
|
1879
1883
|
>
|
|
@@ -2216,7 +2220,7 @@ export default function TrainingPage() {
|
|
|
2216
2220
|
</Button>
|
|
2217
2221
|
</SheetFooter>
|
|
2218
2222
|
</form>
|
|
2219
|
-
</
|
|
2223
|
+
</ResizableSheetContent>
|
|
2220
2224
|
</Sheet>
|
|
2221
2225
|
|
|
2222
2226
|
<CourseFormSheet
|
|
@@ -2232,7 +2236,11 @@ export default function TrainingPage() {
|
|
|
2232
2236
|
/>
|
|
2233
2237
|
|
|
2234
2238
|
<Sheet open={examSheetOpen} onOpenChange={setExamSheetOpen}>
|
|
2235
|
-
<
|
|
2239
|
+
<ResizableSheetContent
|
|
2240
|
+
sheetId="lms-training-create-exam-sheet"
|
|
2241
|
+
defaultWidth={560}
|
|
2242
|
+
minWidth={420}
|
|
2243
|
+
maxWidth={920}
|
|
2236
2244
|
side="right"
|
|
2237
2245
|
className="flex w-full flex-col sm:max-w-lg overflow-y-auto"
|
|
2238
2246
|
>
|
|
@@ -2345,7 +2353,7 @@ export default function TrainingPage() {
|
|
|
2345
2353
|
</Button>
|
|
2346
2354
|
</SheetFooter>
|
|
2347
2355
|
</form>
|
|
2348
|
-
</
|
|
2356
|
+
</ResizableSheetContent>
|
|
2349
2357
|
</Sheet>
|
|
2350
2358
|
|
|
2351
2359
|
{/* Delete Dialog */}
|