@hed-hog/lms 0.0.305 → 0.0.309

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.
Files changed (130) hide show
  1. package/dist/course/course-structure.controller.d.ts +60 -0
  2. package/dist/course/course-structure.controller.d.ts.map +1 -1
  3. package/dist/course/course-structure.controller.js +79 -0
  4. package/dist/course/course-structure.controller.js.map +1 -1
  5. package/dist/course/course-structure.service.d.ts +61 -1
  6. package/dist/course/course-structure.service.d.ts.map +1 -1
  7. package/dist/course/course-structure.service.js +326 -1
  8. package/dist/course/course-structure.service.js.map +1 -1
  9. package/dist/course/course.controller.d.ts +52 -4
  10. package/dist/course/course.controller.d.ts.map +1 -1
  11. package/dist/course/course.service.d.ts +52 -5
  12. package/dist/course/course.service.d.ts.map +1 -1
  13. package/dist/course/course.service.js +81 -60
  14. package/dist/course/course.service.js.map +1 -1
  15. package/dist/course/dto/create-course-structure-lesson.dto.d.ts.map +1 -1
  16. package/dist/course/dto/create-course-structure-lesson.dto.js +5 -1
  17. package/dist/course/dto/create-course-structure-lesson.dto.js.map +1 -1
  18. package/dist/course/dto/create-course.dto.d.ts +1 -1
  19. package/dist/course/dto/create-course.dto.d.ts.map +1 -1
  20. package/dist/course/dto/create-course.dto.js +4 -1
  21. package/dist/course/dto/create-course.dto.js.map +1 -1
  22. package/dist/course/dto/move-lesson.dto.d.ts +10 -0
  23. package/dist/course/dto/move-lesson.dto.d.ts.map +1 -0
  24. package/dist/{enterprise/dto/add-enterprise-lead.dto.js → course/dto/move-lesson.dto.js} +12 -6
  25. package/dist/course/dto/move-lesson.dto.js.map +1 -0
  26. package/dist/course/dto/paste-lessons.dto.d.ts +4 -0
  27. package/dist/course/dto/paste-lessons.dto.d.ts.map +1 -0
  28. package/dist/course/dto/paste-lessons.dto.js +24 -0
  29. package/dist/course/dto/paste-lessons.dto.js.map +1 -0
  30. package/dist/course/dto/reorder-lessons.dto.d.ts +5 -0
  31. package/dist/course/dto/reorder-lessons.dto.d.ts.map +1 -0
  32. package/dist/course/dto/reorder-lessons.dto.js +24 -0
  33. package/dist/course/dto/reorder-lessons.dto.js.map +1 -0
  34. package/dist/course/dto/reorder-sessions.dto.d.ts +5 -0
  35. package/dist/course/dto/reorder-sessions.dto.d.ts.map +1 -0
  36. package/dist/course/dto/reorder-sessions.dto.js +24 -0
  37. package/dist/course/dto/reorder-sessions.dto.js.map +1 -0
  38. package/dist/training/training.controller.js +1 -1
  39. package/dist/training/training.controller.js.map +1 -1
  40. package/hedhog/data/dashboard_component.yaml +152 -152
  41. package/hedhog/data/dashboard_item.yaml +166 -166
  42. package/hedhog/data/image_type.yaml +20 -0
  43. package/hedhog/data/menu.yaml +2 -2
  44. package/hedhog/data/route.yaml +60 -6
  45. package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +146 -165
  46. package/hedhog/frontend/app/_components/course-avatar.tsx.ejs +70 -0
  47. package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +372 -22
  48. package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +437 -77
  49. package/hedhog/frontend/app/classes/page.tsx.ejs +311 -289
  50. package/hedhog/frontend/app/courses/[id]/_components/CourseCertificateCard.tsx.ejs +10 -7
  51. package/hedhog/frontend/app/courses/[id]/_components/CourseClassificationCard.tsx.ejs +23 -32
  52. package/hedhog/frontend/app/courses/[id]/_components/CourseContentCard.tsx.ejs +3 -9
  53. package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +26 -16
  54. package/hedhog/frontend/app/courses/[id]/_components/CourseFlagsCard.tsx.ejs +19 -5
  55. package/hedhog/frontend/app/courses/[id]/_components/CourseMainInfoCard.tsx.ejs +10 -14
  56. package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +131 -107
  57. package/hedhog/frontend/app/courses/[id]/_components/CourseRelationsCard.tsx.ejs +10 -7
  58. package/hedhog/frontend/app/courses/[id]/_components/CourseSectionCard.tsx.ejs +38 -19
  59. package/hedhog/frontend/app/courses/[id]/_components/CourseSummaryCard.tsx.ejs +1 -1
  60. package/hedhog/frontend/app/courses/[id]/_components/course-edit-types.ts.ejs +1 -1
  61. package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +336 -1057
  62. package/hedhog/frontend/app/courses/[id]/structure/_components/confirm-dialog.tsx.ejs +45 -0
  63. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +362 -0
  64. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-panel.tsx.ejs +111 -0
  65. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-skeleton.tsx.ejs +64 -0
  66. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +134 -0
  67. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-course.tsx.ejs +113 -0
  68. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +314 -0
  69. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-panel.tsx.ejs +62 -0
  70. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-session.tsx.ejs +174 -0
  71. package/hedhog/frontend/app/courses/[id]/structure/_components/drag-handle.tsx.ejs +58 -0
  72. package/hedhog/frontend/app/courses/[id]/structure/_components/drag-overlay.tsx.ejs +52 -0
  73. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-bulk.tsx.ejs +276 -0
  74. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +1216 -0
  75. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +1827 -0
  76. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-session.tsx.ejs +443 -0
  77. package/hedhog/frontend/app/courses/[id]/structure/_components/highlighted-text.tsx.ejs +41 -0
  78. package/hedhog/frontend/app/courses/[id]/structure/_components/mock-data.ts.ejs +184 -0
  79. package/hedhog/frontend/app/courses/[id]/structure/_components/multi-select-bar.tsx.ejs +264 -0
  80. package/hedhog/frontend/app/courses/[id]/structure/_components/search-filter.tsx.ejs +96 -0
  81. package/hedhog/frontend/app/courses/[id]/structure/_components/session-picker-dialog.tsx.ejs +74 -0
  82. package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +136 -0
  83. package/hedhog/frontend/app/courses/[id]/structure/_components/sortable-tree-row.tsx.ejs +80 -0
  84. package/hedhog/frontend/app/courses/[id]/structure/_components/store.ts.ejs +948 -0
  85. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-context-menu.tsx.ejs +525 -0
  86. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +150 -0
  87. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-helpers.ts.ejs +182 -0
  88. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-course.tsx.ejs +52 -0
  89. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +271 -0
  90. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-session.tsx.ejs +167 -0
  91. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row.tsx.ejs +108 -0
  92. package/hedhog/frontend/app/courses/[id]/structure/_components/types.ts.ejs +122 -0
  93. package/hedhog/frontend/app/courses/[id]/structure/_components/use-course-structure-shortcuts.ts.ejs +318 -0
  94. package/hedhog/frontend/app/courses/[id]/structure/_components/use-tree-display-settings.ts.ejs +97 -0
  95. package/hedhog/frontend/app/courses/[id]/structure/_data/adapters/course-structure.adapter.ts.ejs +347 -0
  96. package/hedhog/frontend/app/courses/[id]/structure/_data/course-structure-contract.ts.ejs +195 -0
  97. package/hedhog/frontend/app/courses/[id]/structure/_data/services/course-structure.service.ts.ejs +420 -0
  98. package/hedhog/frontend/app/courses/[id]/structure/_data/types/api-course.types.ts.ejs +254 -0
  99. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +987 -0
  100. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-query.ts.ejs +86 -0
  101. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure.ts.ejs +160 -0
  102. package/hedhog/frontend/app/courses/[id]/structure/page.tsx.ejs +10 -3212
  103. package/hedhog/frontend/app/courses/page.tsx.ejs +45 -26
  104. package/hedhog/frontend/app/enterprise/[id]/page.tsx.ejs +317 -317
  105. package/hedhog/frontend/app/enterprise/_components/enterprise-class-create-sheet.tsx.ejs +1 -0
  106. package/hedhog/frontend/app/enterprise/_components/enterprise-mocks.ts.ejs +12 -1
  107. package/hedhog/frontend/app/enterprise/_components/enterprise-related-tab.tsx.ejs +44 -7
  108. package/hedhog/frontend/app/enterprise/_components/enterprise-types.ts.ejs +96 -96
  109. package/hedhog/frontend/app/page.tsx.ejs +5 -5
  110. package/hedhog/frontend/app/{training → paths}/page.tsx.ejs +29 -7
  111. package/hedhog/frontend/messages/en.json +88 -10
  112. package/hedhog/frontend/messages/pt.json +88 -10
  113. package/hedhog/table/course.yaml +16 -16
  114. package/hedhog/table/image_type.yaml +14 -0
  115. package/package.json +6 -6
  116. package/src/class-group/class-group.service.ts +413 -413
  117. package/src/class-group/dto/create-class-group.dto.ts +77 -77
  118. package/src/course/course-structure.controller.ts +63 -0
  119. package/src/course/course-structure.service.ts +390 -3
  120. package/src/course/course.service.ts +214 -182
  121. package/src/course/dto/create-course-structure-lesson.dto.ts +3 -2
  122. package/src/course/dto/create-course.dto.ts +19 -16
  123. package/src/course/dto/move-lesson.dto.ts +17 -0
  124. package/src/course/dto/paste-lessons.dto.ts +9 -0
  125. package/src/course/dto/reorder-lessons.dto.ts +10 -0
  126. package/src/course/dto/reorder-sessions.dto.ts +10 -0
  127. package/src/training/training.controller.ts +1 -1
  128. package/dist/enterprise/dto/add-enterprise-lead.dto.d.ts +0 -4
  129. package/dist/enterprise/dto/add-enterprise-lead.dto.d.ts.map +0 -1
  130. package/dist/enterprise/dto/add-enterprise-lead.dto.js.map +0 -1
@@ -0,0 +1,86 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * useCourseStructureQuery
5
+ *
6
+ * React Query hook that fetches the course structure from the real API,
7
+ * normalises the response via the adapter, and returns the flat arrays
8
+ * of sessions and lessons together with standard query state flags.
9
+ *
10
+ * This hook does NOT touch the Zustand store. The page is responsible for
11
+ * calling `setStructureFromApi` once data is available so that all
12
+ * store-driven mutations (drag-and-drop, rename, inline-edit, etc.) keep
13
+ * working during this first integration phase.
14
+ */
15
+
16
+ import { useApp, useQuery } from '@hed-hog/next-app-provider';
17
+
18
+ import type { Course, Lesson, Session } from '../_components/types';
19
+ import { normalizeStructureResponse } from './adapters/course-structure.adapter';
20
+ import { getCourseStructure } from './services/course-structure.service';
21
+
22
+ // ─────────────────────────────────────────────────────────────────────────────
23
+ // Query key factory (stable reference for invalidation / setQueryData)
24
+ // ─────────────────────────────────────────────────────────────────────────────
25
+
26
+ export const courseStructureQueryKey = (courseId: string) =>
27
+ ['course-structure', courseId] as const;
28
+
29
+ // ─────────────────────────────────────────────────────────────────────────────
30
+ // Cache data shape (matches the normalised response)
31
+ // ─────────────────────────────────────────────────────────────────────────────
32
+
33
+ export interface CourseStructureCacheData {
34
+ course: Course | null;
35
+ sessions: Session[];
36
+ lessons: Lesson[];
37
+ instructors: { id: number; name: string }[];
38
+ }
39
+
40
+ // ─────────────────────────────────────────────────────────────────────────────
41
+ // Return type
42
+ // ─────────────────────────────────────────────────────────────────────────────
43
+
44
+ export interface CourseStructureQueryResult {
45
+ course: Course | null;
46
+ sessions: Session[];
47
+ lessons: Lesson[];
48
+ instructors: { id: number; name: string }[];
49
+ isLoading: boolean;
50
+ isFetching: boolean;
51
+ isError: boolean;
52
+ error: unknown;
53
+ refetch: () => void;
54
+ }
55
+
56
+ // ─────────────────────────────────────────────────────────────────────────────
57
+ // Hook
58
+ // ─────────────────────────────────────────────────────────────────────────────
59
+
60
+ export function useCourseStructureQuery(
61
+ courseId: string
62
+ ): CourseStructureQueryResult {
63
+ const { request } = useApp();
64
+
65
+ const { data, isLoading, isFetching, isError, error, refetch } = useQuery({
66
+ queryKey: courseStructureQueryKey(courseId),
67
+ enabled: Boolean(courseId),
68
+ retry: 1,
69
+ queryFn: async () => {
70
+ const raw = await getCourseStructure(request, courseId);
71
+ return normalizeStructureResponse(raw);
72
+ },
73
+ });
74
+
75
+ return {
76
+ course: data?.course ?? null,
77
+ sessions: data?.sessions ?? [],
78
+ lessons: data?.lessons ?? [],
79
+ instructors: data?.instructors ?? [],
80
+ isLoading,
81
+ isFetching,
82
+ isError,
83
+ error,
84
+ refetch,
85
+ };
86
+ }
@@ -0,0 +1,160 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * useCourseStructure
5
+ *
6
+ * Data hook for the Course Structure screen.
7
+ *
8
+ * ┌─────────────────────────────────────────────────────────────────────────┐
9
+ * │ CURRENT IMPLEMENTATION — mock (Zustand store with seeded local data) │
10
+ * │ │
11
+ * │ HOW TO INTEGRATE WITH THE REAL API (React Query): │
12
+ * │ │
13
+ * │ Step 1 – Replace the query stubs with a real useQuery call: │
14
+ * │ const { data, isLoading, isError, isFetching } = useQuery({ │
15
+ * │ queryKey: ['course-structure', courseId], │
16
+ * │ queryFn: () => │
17
+ * │ apiClient.get<CourseStructureResponse>( │
18
+ * │ `/lms/courses/${courseId}/structure` │
19
+ * │ ), │
20
+ * │ }); │
21
+ * │ │
22
+ * │ Step 2 – Replace each mutation stub with useMutation: │
23
+ * │ const createSection = useMutation({ │
24
+ * │ mutationFn: () => │
25
+ * │ apiClient.post(`/lms/courses/${courseId}/sessions`), │
26
+ * │ onSuccess: () => │
27
+ * │ queryClient.invalidateQueries(['course-structure', courseId]), │
28
+ * │ }); │
29
+ * │ │
30
+ * │ Step 3 – Move course/sessions/lessons out of the Zustand store; │
31
+ * │ derive them from the query cache. Keep UI-only fields in the store: │
32
+ * │ selectedIds, expandedIds, filterQuery, clipboard, rename, dialogs. │
33
+ * │ │
34
+ * │ Step 4 – Track isDirty / isSaving from mutation.isPending. │
35
+ * └─────────────────────────────────────────────────────────────────────────┘
36
+ */
37
+
38
+ import { useStructureStore } from '../_components/store';
39
+ import type { CourseStructureHook } from './course-structure-contract';
40
+
41
+ /**
42
+ * @param _courseId - Course ID from the URL. Unused in the mock implementation
43
+ * but required by the future React Query call.
44
+ * TODO[API]: pass to queryKey + queryFn.
45
+ */
46
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
47
+ export function useCourseStructure(_courseId: string): CourseStructureHook {
48
+ // ── Data ─────────────────────────────────────────────────────────────────
49
+ // TODO[API]: Replace the three lines below with `data` from useQuery,
50
+ // then flatten `data.sessions` (each with nested lessons) into
51
+ // separate arrays before returning.
52
+ const course = useStructureStore((s) => s.course);
53
+ const sessions = useStructureStore((s) => s.sessions);
54
+ const lessons = useStructureStore((s) => s.lessons);
55
+
56
+ // ── Store actions ────────────────────────────────────────────────────────
57
+ // TODO[API]: Each action below will become a useMutation call.
58
+ // Keep the same function signature so call sites don't change.
59
+ const storeUpdateCourse = useStructureStore((s) => s.updateCourse);
60
+ const storeAddSession = useStructureStore((s) => s.addSession);
61
+ const storeUpdateSession = useStructureStore((s) => s.updateSession);
62
+ const storeDeleteSession = useStructureStore((s) => s.deleteSession);
63
+ const storeReorderSessions = useStructureStore((s) => s.reorderSessions);
64
+ const storeDuplicateSession = useStructureStore((s) => s.duplicateSession);
65
+ const storeAddLesson = useStructureStore((s) => s.addLesson);
66
+ const storeUpdateLesson = useStructureStore((s) => s.updateLesson);
67
+ const storeDeleteLesson = useStructureStore((s) => s.deleteLesson);
68
+ const storeMoveLesson = useStructureStore((s) => s.moveLesson);
69
+ const storeDuplicateLesson = useStructureStore((s) => s.duplicateLesson);
70
+ const storeDeleteSelected = useStructureStore((s) => s.deleteSelected);
71
+ const storeDuplicateSelected = useStructureStore((s) => s.duplicateSelected);
72
+ const storeMoveLessons = useStructureStore((s) => s.moveLessons);
73
+ const storeCopyItems = useStructureStore((s) => s.copyItems);
74
+ const storePasteSessions = useStructureStore((s) => s.pasteSessions);
75
+ const storePasteLessons = useStructureStore((s) => s.pasteLessons);
76
+
77
+ return {
78
+ // ── Query state stubs ───────────────────────────────────────────────────
79
+ // TODO[API]: Replace with { isLoading, isError, isFetching } from useQuery
80
+ isLoading: false,
81
+ isError: false,
82
+ isFetching: false,
83
+
84
+ // TODO[API]: isDirty = local state diverges from server snapshot
85
+ // isSaving = any mutation.isPending === true
86
+ isDirty: false,
87
+ isSaving: false,
88
+
89
+ // ── Data ─────────────────────────────────────────────────────────────
90
+ course,
91
+ sessions,
92
+ lessons,
93
+
94
+ // ── Course ────────────────────────────────────────────────────────────
95
+ // TODO[API]: PUT /lms/courses/:id
96
+ updateCourse: storeUpdateCourse,
97
+
98
+ saveOrder() {
99
+ // TODO[API]: Build SaveOrderRequest from current sessions/lessons order,
100
+ // then call:
101
+ // apiClient.put(`/lms/courses/${courseId}/order`, payload)
102
+ // .then(() => toast.success('Ordem salva'))
103
+ // .catch(() => toast.error('Erro ao salvar ordem'));
104
+ //
105
+ // For now this is a no-op — order is kept only in local state.
106
+ },
107
+
108
+ // ── Sections (sessions) ──────────────────────────────────────────────
109
+ // TODO[API]: POST /lms/courses/:id/sessions
110
+ createSection: () => {
111
+ storeAddSession();
112
+ },
113
+
114
+ // TODO[API]: PUT /lms/sessions/:id
115
+ updateSection: (id, data) => storeUpdateSession(id, data),
116
+
117
+ // TODO[API]: DELETE /lms/sessions/:id
118
+ deleteSection: (id) => storeDeleteSession(id),
119
+
120
+ // TODO[API]: PUT /lms/sessions/reorder { sessions: [{id, order}] }
121
+ reorderSections: storeReorderSessions,
122
+
123
+ // TODO[API]: POST /lms/sessions/:id/duplicate
124
+ duplicateSection: (id) => storeDuplicateSession(id),
125
+
126
+ // ── Lessons ──────────────────────────────────────────────────────────
127
+ // TODO[API]: POST /lms/sessions/:sessionId/lessons
128
+ createLesson: (sessionId) => {
129
+ storeAddLesson(sessionId);
130
+ },
131
+
132
+ // TODO[API]: PUT /lms/lessons/:id
133
+ updateLesson: (id, data) => storeUpdateLesson(id, data),
134
+
135
+ // TODO[API]: DELETE /lms/lessons/:id
136
+ deleteLesson: (id) => storeDeleteLesson(id),
137
+
138
+ // TODO[API]: PUT /lms/lessons/:id/move { toSessionId, toIndex }
139
+ moveLesson: (lessonId, toSessionId, toIndex) =>
140
+ storeMoveLesson(lessonId, toSessionId, toIndex ?? 0),
141
+
142
+ // TODO[API]: POST /lms/lessons/:id/duplicate
143
+ duplicateLesson: (id) => storeDuplicateLesson(id),
144
+
145
+ // ── Bulk ─────────────────────────────────────────────────────────────
146
+ // TODO[API]: fire one DELETE per selected id (or a batch endpoint)
147
+ deleteSelected: storeDeleteSelected,
148
+
149
+ // TODO[API]: fire one POST .../duplicate per selected id
150
+ duplicateSelected: storeDuplicateSelected,
151
+
152
+ // TODO[API]: fire one PUT /lms/lessons/:id/move per lessonId
153
+ moveLessons: (ids, toSessionId) => storeMoveLessons(ids, toSessionId),
154
+
155
+ // ── Clipboard (client-only — no API equivalent) ──────────────────────
156
+ copyItems: (ids, type) => storeCopyItems(ids, type),
157
+ pasteSessions: storePasteSessions,
158
+ pasteLessons: (toSessionId) => storePasteLessons(toSessionId),
159
+ };
160
+ }