@hed-hog/lms 0.0.330 → 0.0.338

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 (128) hide show
  1. package/dist/class-group/class-group.controller.d.ts +3 -3
  2. package/dist/class-group/class-group.service.d.ts +3 -3
  3. package/dist/course/course.service.d.ts.map +1 -1
  4. package/dist/course/course.service.js +12 -20
  5. package/dist/course/course.service.js.map +1 -1
  6. package/dist/enterprise/enterprise.controller.d.ts +72 -0
  7. package/dist/enterprise/enterprise.controller.d.ts.map +1 -1
  8. package/dist/enterprise/enterprise.controller.js +10 -0
  9. package/dist/enterprise/enterprise.controller.js.map +1 -1
  10. package/dist/enterprise/enterprise.service.d.ts +78 -0
  11. package/dist/enterprise/enterprise.service.d.ts.map +1 -1
  12. package/dist/enterprise/enterprise.service.js +413 -40
  13. package/dist/enterprise/enterprise.service.js.map +1 -1
  14. package/dist/enterprise/training/training-admin.controller.d.ts +6 -3
  15. package/dist/enterprise/training/training-admin.controller.d.ts.map +1 -1
  16. package/dist/enterprise/training/training-admin.controller.js +10 -6
  17. package/dist/enterprise/training/training-admin.controller.js.map +1 -1
  18. package/dist/enterprise/training/training-admin.service.d.ts +8 -2
  19. package/dist/enterprise/training/training-admin.service.d.ts.map +1 -1
  20. package/dist/enterprise/training/training-admin.service.js +108 -52
  21. package/dist/enterprise/training/training-admin.service.js.map +1 -1
  22. package/dist/enterprise/training/training-viewer.controller.d.ts +3 -0
  23. package/dist/enterprise/training/training-viewer.controller.d.ts.map +1 -1
  24. package/dist/evaluation/evaluation.controller.d.ts +4 -4
  25. package/dist/evaluation/evaluation.service.d.ts +4 -4
  26. package/dist/instructor/dto/create-instructor-skill.dto.d.ts +0 -4
  27. package/dist/instructor/dto/create-instructor-skill.dto.d.ts.map +1 -1
  28. package/dist/instructor/dto/create-instructor-skill.dto.js +0 -21
  29. package/dist/instructor/dto/create-instructor-skill.dto.js.map +1 -1
  30. package/dist/instructor/dto/update-instructor-skill.dto.d.ts +0 -4
  31. package/dist/instructor/dto/update-instructor-skill.dto.d.ts.map +1 -1
  32. package/dist/instructor/dto/update-instructor-skill.dto.js +0 -22
  33. package/dist/instructor/dto/update-instructor-skill.dto.js.map +1 -1
  34. package/dist/instructor/instructor-skill.controller.d.ts +4 -4
  35. package/dist/instructor/instructor-skill.service.d.ts +4 -7
  36. package/dist/instructor/instructor-skill.service.d.ts.map +1 -1
  37. package/dist/instructor/instructor-skill.service.js +2 -89
  38. package/dist/instructor/instructor-skill.service.js.map +1 -1
  39. package/dist/instructor/instructor.controller.d.ts +20 -0
  40. package/dist/instructor/instructor.controller.d.ts.map +1 -1
  41. package/dist/instructor/instructor.controller.js +19 -0
  42. package/dist/instructor/instructor.controller.js.map +1 -1
  43. package/dist/instructor/instructor.service.d.ts +25 -0
  44. package/dist/instructor/instructor.service.d.ts.map +1 -1
  45. package/dist/instructor/instructor.service.js +70 -18
  46. package/dist/instructor/instructor.service.js.map +1 -1
  47. package/dist/lms.module.d.ts.map +1 -1
  48. package/dist/lms.module.js.map +1 -1
  49. package/hedhog/data/route.yaml +23 -1
  50. package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +42 -24
  51. package/hedhog/frontend/app/_components/create-lms-instructor-sheet.tsx.ejs +591 -0
  52. package/hedhog/frontend/app/certificates/issued/page.tsx.ejs +6 -1
  53. package/hedhog/frontend/app/certificates/models/page.tsx.ejs +7 -2
  54. package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +17 -17
  55. package/hedhog/frontend/app/classes/page.tsx.ejs +6 -1
  56. package/hedhog/frontend/app/courses/[id]/_components/CourseClassificationCard.tsx.ejs +3 -33
  57. package/hedhog/frontend/app/courses/[id]/_components/CourseContentCard.tsx.ejs +9 -9
  58. package/hedhog/frontend/app/courses/[id]/_components/CourseMainInfoCard.tsx.ejs +109 -0
  59. package/hedhog/frontend/app/courses/[id]/_components/CourseMultiEntityPicker.tsx.ejs +42 -15
  60. package/hedhog/frontend/app/courses/[id]/_components/CourseRelationsCard.tsx.ejs +76 -81
  61. package/hedhog/frontend/app/courses/[id]/_components/CourseSummaryCard.tsx.ejs +60 -0
  62. package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +3 -3
  63. package/hedhog/frontend/app/courses/[id]/structure/_components/course-scheduled-classes-tab.tsx.ejs +406 -0
  64. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +1 -1
  65. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +134 -0
  66. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-course.tsx.ejs +113 -0
  67. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +314 -0
  68. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-session.tsx.ejs +174 -0
  69. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +242 -33
  70. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +228 -152
  71. package/hedhog/frontend/app/courses/[id]/structure/_components/mock-data.ts.ejs +185 -0
  72. package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +71 -31
  73. package/hedhog/frontend/app/courses/page.tsx.ejs +6 -1
  74. package/hedhog/frontend/app/enterprise/[id]/page.tsx.ejs +37 -41
  75. package/hedhog/frontend/app/enterprise/_components/enterprise-activity-timeline.tsx.ejs +87 -0
  76. package/hedhog/frontend/app/enterprise/_components/enterprise-admin-create-sheet.tsx.ejs +4 -0
  77. package/hedhog/frontend/app/enterprise/_components/enterprise-administrators-tab.tsx.ejs +31 -5
  78. package/hedhog/frontend/app/enterprise/_components/enterprise-classes-tab.tsx.ejs +79 -20
  79. package/hedhog/frontend/app/enterprise/_components/enterprise-company-identity-card.tsx.ejs +11 -2
  80. package/hedhog/frontend/app/enterprise/_components/enterprise-course-edit-sheet.tsx.ejs +201 -0
  81. package/hedhog/frontend/app/enterprise/_components/enterprise-courses-tab.tsx.ejs +55 -24
  82. package/hedhog/frontend/app/enterprise/_components/enterprise-detail-sheet.tsx.ejs +430 -296
  83. package/hedhog/frontend/app/enterprise/_components/enterprise-mocks.ts.ejs +277 -0
  84. package/hedhog/frontend/app/enterprise/_components/enterprise-overview-analytics.tsx.ejs +205 -0
  85. package/hedhog/frontend/app/enterprise/_components/enterprise-person-edit-sheet.tsx.ejs +97 -0
  86. package/hedhog/frontend/app/enterprise/_components/enterprise-sheet.tsx.ejs +82 -57
  87. package/hedhog/frontend/app/enterprise/_components/enterprise-student-create-sheet.tsx.ejs +4 -0
  88. package/hedhog/frontend/app/enterprise/_components/enterprise-students-tab.tsx.ejs +60 -22
  89. package/hedhog/frontend/app/enterprise/_components/enterprise-types.ts.ejs +54 -0
  90. package/hedhog/frontend/app/enterprise/_components/enterprise-user-create-sheet.tsx.ejs +211 -0
  91. package/hedhog/frontend/app/enterprise/page.tsx.ejs +39 -7
  92. package/hedhog/frontend/app/evaluations/_components/evaluation-topic-form-sheet.tsx.ejs +1 -1
  93. package/hedhog/frontend/app/exams/[id]/questions/page.tsx.ejs +6 -1
  94. package/hedhog/frontend/app/exams/page.tsx.ejs +12 -3
  95. package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +51 -104
  96. package/hedhog/frontend/app/instructors/_components/instructor-form-sheet.tsx.ejs +712 -427
  97. package/hedhog/frontend/app/instructors/page.tsx.ejs +77 -53
  98. package/hedhog/frontend/app/paths/page.tsx.ejs +14 -5
  99. package/hedhog/frontend/app/reports/courses/page.tsx.ejs +5 -5
  100. package/hedhog/frontend/app/reports/dashboard/page.tsx.ejs +8 -8
  101. package/hedhog/frontend/app/reports/evaluations/page.tsx.ejs +6 -1
  102. package/hedhog/frontend/app/reports/page.tsx.ejs +7 -7
  103. package/hedhog/frontend/app/reports/students/page.tsx.ejs +6 -6
  104. package/hedhog/frontend/app/training/page.tsx.ejs +8 -3
  105. package/hedhog/frontend/messages/en.json +394 -55
  106. package/hedhog/frontend/messages/pt.json +389 -48
  107. package/hedhog/frontend/widgets/active-classes-kpi.tsx.ejs +1 -1
  108. package/hedhog/frontend/widgets/active-courses-kpi.tsx.ejs +1 -1
  109. package/hedhog/frontend/widgets/approval-rate-kpi.tsx.ejs +1 -1
  110. package/hedhog/frontend/widgets/class-calendar.tsx.ejs +2 -2
  111. package/hedhog/frontend/widgets/completion-rate-kpi.tsx.ejs +1 -1
  112. package/hedhog/frontend/widgets/issued-certificates-kpi.tsx.ejs +1 -1
  113. package/hedhog/frontend/widgets/total-students-kpi.tsx.ejs +1 -1
  114. package/hedhog/table/enterprise_student_license_event.yaml +30 -0
  115. package/hedhog/table/instructor_qualification.yaml +1 -1
  116. package/hedhog/table/instructor_skill.yaml +0 -11
  117. package/package.json +8 -8
  118. package/src/course/course.service.ts +12 -24
  119. package/src/enterprise/enterprise.controller.ts +5 -0
  120. package/src/enterprise/enterprise.service.ts +507 -29
  121. package/src/enterprise/training/training-admin.controller.ts +4 -0
  122. package/src/enterprise/training/training-admin.service.ts +115 -51
  123. package/src/instructor/dto/create-instructor-skill.dto.ts +0 -17
  124. package/src/instructor/dto/update-instructor-skill.dto.ts +0 -18
  125. package/src/instructor/instructor-skill.service.ts +2 -97
  126. package/src/instructor/instructor.controller.ts +16 -0
  127. package/src/instructor/instructor.service.ts +85 -10
  128. package/src/lms.module.ts +1 -0
@@ -81,6 +81,7 @@ let EnterpriseService = class EnterpriseService {
81
81
  id: true,
82
82
  name: true,
83
83
  type: true,
84
+ avatar_id: true,
84
85
  },
85
86
  },
86
87
  _count: {
@@ -135,6 +136,140 @@ let EnterpriseService = class EnterpriseService {
135
136
  await this.assertEnterpriseExists(id);
136
137
  return this.prisma.enterprise.update({ where: { id }, data: dto });
137
138
  }
139
+ async getOverview(id) {
140
+ const enterprise = await this.getById(id);
141
+ if (!enterprise)
142
+ return null;
143
+ const eventModel = this.prisma.enterprise_student_license_event;
144
+ const now = new Date();
145
+ const timelineStart = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() - 11, 1));
146
+ const [studentRows, scheduledClasses, licenseEvents, recentCourses, recentClasses, recentStudents, recentAdmins,] = await Promise.all([
147
+ this.prisma.enterprise_student.findMany({
148
+ where: { enterprise_id: id },
149
+ select: {
150
+ person_id: true,
151
+ status: true,
152
+ created_at: true,
153
+ person: { select: { id: true, name: true } },
154
+ },
155
+ }),
156
+ this.prisma.enterprise_class_group.findMany({
157
+ where: {
158
+ enterprise_id: id,
159
+ course_class_group: { status: { in: ['open', 'ongoing'] } },
160
+ },
161
+ select: {
162
+ created_at: true,
163
+ course_class_group: {
164
+ select: {
165
+ id: true,
166
+ code: true,
167
+ title: true,
168
+ status: true,
169
+ capacity: true,
170
+ course: { select: { title: true } },
171
+ _count: {
172
+ select: {
173
+ course_enrollment: {
174
+ where: { status: { not: 'cancelled' } },
175
+ },
176
+ },
177
+ },
178
+ },
179
+ },
180
+ },
181
+ }),
182
+ eventModel
183
+ ? eventModel
184
+ .findMany({
185
+ where: { enterprise_id: id },
186
+ orderBy: { created_at: 'asc' },
187
+ select: {
188
+ person_id: true,
189
+ event_type: true,
190
+ previous_status: true,
191
+ next_status: true,
192
+ created_at: true,
193
+ person: { select: { id: true, name: true } },
194
+ },
195
+ })
196
+ .catch(() => [])
197
+ : Promise.resolve([]),
198
+ this.prisma.enterprise_course.findMany({
199
+ where: { enterprise_id: id },
200
+ take: 5,
201
+ orderBy: { created_at: 'desc' },
202
+ select: {
203
+ created_at: true,
204
+ course: { select: { id: true, title: true } },
205
+ },
206
+ }),
207
+ this.prisma.enterprise_class_group.findMany({
208
+ where: { enterprise_id: id },
209
+ take: 5,
210
+ orderBy: { created_at: 'desc' },
211
+ select: {
212
+ created_at: true,
213
+ course_class_group: {
214
+ select: {
215
+ id: true,
216
+ code: true,
217
+ title: true,
218
+ course: { select: { title: true } },
219
+ },
220
+ },
221
+ },
222
+ }),
223
+ this.prisma.enterprise_student.findMany({
224
+ where: { enterprise_id: id },
225
+ take: 5,
226
+ orderBy: { created_at: 'desc' },
227
+ select: {
228
+ created_at: true,
229
+ person: { select: { id: true, name: true } },
230
+ },
231
+ }),
232
+ this.prisma.enterprise_user.findMany({
233
+ where: { enterprise_id: id },
234
+ take: 5,
235
+ orderBy: { created_at: 'desc' },
236
+ select: {
237
+ created_at: true,
238
+ role: true,
239
+ user: { select: { id: true, name: true } },
240
+ },
241
+ }),
242
+ ]);
243
+ const used = studentRows.length;
244
+ const limit = enterprise.licenseLimit;
245
+ const available = limit === null ? null : Math.max(limit - used, 0);
246
+ const percent = limit && limit > 0 ? Math.min(100, Math.round((used / limit) * 100)) : 0;
247
+ const capacity = scheduledClasses.reduce((sum, row) => { var _a, _b; return sum + Math.max((_b = (_a = row.course_class_group) === null || _a === void 0 ? void 0 : _a.capacity) !== null && _b !== void 0 ? _b : 0, 0); }, 0);
248
+ const seatsUsed = scheduledClasses.reduce((sum, row) => { var _a, _b, _c; return sum + ((_c = (_b = (_a = row.course_class_group) === null || _a === void 0 ? void 0 : _a._count) === null || _b === void 0 ? void 0 : _b.course_enrollment) !== null && _c !== void 0 ? _c : 0); }, 0);
249
+ return {
250
+ account: enterprise,
251
+ kpis: {
252
+ students: enterprise.studentsCount,
253
+ classes: enterprise.classesCount,
254
+ courses: enterprise.coursesCount,
255
+ administrators: enterprise.adminsCount + enterprise.managersCount,
256
+ portalEnabled: enterprise.portalEnabled,
257
+ },
258
+ licenseUsage: {
259
+ used,
260
+ limit,
261
+ available,
262
+ percent,
263
+ },
264
+ scheduledSeats: {
265
+ used: seatsUsed,
266
+ open: Math.max(capacity - seatsUsed, 0),
267
+ capacity,
268
+ },
269
+ licenseTimeline: this.buildLicenseTimeline(studentRows, licenseEvents, timelineStart, now),
270
+ activities: this.buildEnterpriseActivities(licenseEvents, recentCourses, recentClasses, recentStudents, recentAdmins),
271
+ };
272
+ }
138
273
  async delete(id) {
139
274
  await this.assertEnterpriseExists(id);
140
275
  return this.prisma.enterprise.delete({ where: { id } });
@@ -149,6 +284,154 @@ let EnterpriseService = class EnterpriseService {
149
284
  throw new common_1.NotFoundException(`Enterprise #${id} not found`);
150
285
  return exists;
151
286
  }
287
+ async recordLicenseEvent(params) {
288
+ var _a, _b;
289
+ const eventModel = this.prisma.enterprise_student_license_event;
290
+ if (!eventModel)
291
+ return;
292
+ try {
293
+ await eventModel.create({
294
+ data: {
295
+ enterprise_id: params.enterpriseId,
296
+ person_id: params.personId,
297
+ event_type: params.eventType,
298
+ previous_status: (_a = params.previousStatus) !== null && _a !== void 0 ? _a : null,
299
+ next_status: (_b = params.nextStatus) !== null && _b !== void 0 ? _b : null,
300
+ },
301
+ });
302
+ }
303
+ catch (_c) {
304
+ // The YAML/DB apply step may not have run yet in older environments.
305
+ }
306
+ }
307
+ monthKey(date) {
308
+ const year = date.getUTCFullYear();
309
+ const month = String(date.getUTCMonth() + 1).padStart(2, '0');
310
+ return `${year}-${month}`;
311
+ }
312
+ monthLabel(date) {
313
+ return date.toLocaleDateString('pt-BR', {
314
+ month: 'short',
315
+ year: '2-digit',
316
+ timeZone: 'UTC',
317
+ });
318
+ }
319
+ buildLicenseTimeline(studentRows, eventRows, start, end) {
320
+ const eventsByPerson = new Set(eventRows
321
+ .filter((event) => event.event_type === 'assigned')
322
+ .map((event) => event.person_id));
323
+ const syntheticEvents = studentRows
324
+ .filter((student) => !eventsByPerson.has(student.person_id))
325
+ .map((student) => ({
326
+ person_id: student.person_id,
327
+ event_type: 'assigned',
328
+ previous_status: null,
329
+ next_status: 'active',
330
+ created_at: student.created_at,
331
+ }));
332
+ const allEvents = [...eventRows, ...syntheticEvents].sort((a, b) => a.created_at.getTime() - b.created_at.getTime());
333
+ let running = 0;
334
+ for (const event of allEvents) {
335
+ if (event.created_at >= start)
336
+ break;
337
+ running += this.getLicenseEventDelta(event);
338
+ running = Math.max(running, 0);
339
+ }
340
+ const points = [];
341
+ const cursor = new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), 1));
342
+ while (cursor <= end) {
343
+ const key = this.monthKey(cursor);
344
+ const monthEvents = allEvents.filter((event) => this.monthKey(event.created_at) === key);
345
+ const assigned = monthEvents.filter((event) => this.getLicenseEventDelta(event) > 0).length;
346
+ const revoked = monthEvents.filter((event) => this.getLicenseEventDelta(event) < 0).length;
347
+ for (const event of monthEvents) {
348
+ running += this.getLicenseEventDelta(event);
349
+ running = Math.max(running, 0);
350
+ }
351
+ points.push({
352
+ period: key,
353
+ label: this.monthLabel(cursor),
354
+ used: running,
355
+ assigned,
356
+ revoked,
357
+ });
358
+ cursor.setUTCMonth(cursor.getUTCMonth() + 1);
359
+ }
360
+ return points;
361
+ }
362
+ getLicenseEventDelta(event) {
363
+ if (event.event_type === 'assigned')
364
+ return 1;
365
+ if (event.event_type === 'revoked')
366
+ return -1;
367
+ if (event.event_type === 'status_changed') {
368
+ const wasActive = event.previous_status !== 'inactive';
369
+ const isActive = event.next_status !== 'inactive';
370
+ if (!wasActive && isActive)
371
+ return 1;
372
+ if (wasActive && !isActive)
373
+ return -1;
374
+ }
375
+ return 0;
376
+ }
377
+ buildEnterpriseActivities(licenseEvents, courses, classes, students, admins) {
378
+ return [
379
+ ...licenseEvents.slice(-10).map((event) => {
380
+ var _a, _b, _c, _d;
381
+ return ({
382
+ id: `license-${(_b = (_a = event.person) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'unknown'}-${event.created_at.getTime()}`,
383
+ type: event.event_type,
384
+ title: event.event_type === 'revoked'
385
+ ? 'Licenca removida'
386
+ : 'Licenca atribuida',
387
+ description: (_d = (_c = event.person) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : 'Aluno',
388
+ createdAt: event.created_at,
389
+ });
390
+ }),
391
+ ...courses.map((row) => {
392
+ var _a, _b, _c, _d;
393
+ return ({
394
+ id: `course-${(_b = (_a = row.course) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'unknown'}-${row.created_at.getTime()}`,
395
+ type: 'course',
396
+ title: 'Curso vinculado',
397
+ description: (_d = (_c = row.course) === null || _c === void 0 ? void 0 : _c.title) !== null && _d !== void 0 ? _d : 'Curso',
398
+ createdAt: row.created_at,
399
+ });
400
+ }),
401
+ ...classes.map((row) => {
402
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
403
+ return ({
404
+ id: `class-${(_b = (_a = row.course_class_group) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'unknown'}-${row.created_at.getTime()}`,
405
+ type: 'class',
406
+ title: 'Turma vinculada',
407
+ description: (_j = (_f = (_d = (_c = row.course_class_group) === null || _c === void 0 ? void 0 : _c.code) !== null && _d !== void 0 ? _d : (_e = row.course_class_group) === null || _e === void 0 ? void 0 : _e.title) !== null && _f !== void 0 ? _f : (_h = (_g = row.course_class_group) === null || _g === void 0 ? void 0 : _g.course) === null || _h === void 0 ? void 0 : _h.title) !== null && _j !== void 0 ? _j : 'Turma',
408
+ createdAt: row.created_at,
409
+ });
410
+ }),
411
+ ...students.map((row) => {
412
+ var _a, _b, _c, _d;
413
+ return ({
414
+ id: `student-${(_b = (_a = row.person) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'unknown'}-${row.created_at.getTime()}`,
415
+ type: 'student',
416
+ title: 'Aluno adicionado',
417
+ description: (_d = (_c = row.person) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : 'Aluno',
418
+ createdAt: row.created_at,
419
+ });
420
+ }),
421
+ ...admins.map((row) => {
422
+ var _a, _b, _c;
423
+ return ({
424
+ id: `admin-${(_b = (_a = row.user) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'unknown'}-${row.created_at.getTime()}`,
425
+ type: 'admin',
426
+ title: 'Administrador adicionado',
427
+ description: ((_c = row.user) === null || _c === void 0 ? void 0 : _c.name) ? `${row.user.name} (${row.role})` : row.role,
428
+ createdAt: row.created_at,
429
+ });
430
+ }),
431
+ ]
432
+ .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
433
+ .slice(0, 12);
434
+ }
152
435
  async resolveRoleId(slug) {
153
436
  var _a;
154
437
  const role = await this.prisma.role.findUnique({
@@ -218,6 +501,7 @@ let EnterpriseService = class EnterpriseService {
218
501
  id: true,
219
502
  name: true,
220
503
  last_login_at: true,
504
+ photo_id: true,
221
505
  user_identifier: {
222
506
  where: { type: 'email' },
223
507
  select: { value: true },
@@ -235,16 +519,17 @@ let EnterpriseService = class EnterpriseService {
235
519
  pageSize,
236
520
  lastPage: Math.max(1, Math.ceil(total / pageSize)),
237
521
  data: rows.map((r) => {
238
- var _a, _b, _c, _d, _e, _f, _g, _h;
522
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
239
523
  return ({
240
524
  id: r.id,
241
525
  userId: r.user_id,
242
526
  personId: r.person_id,
243
527
  name: (_b = (_a = r.user) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : null,
244
528
  email: (_f = (_e = (_d = (_c = r.user) === null || _c === void 0 ? void 0 : _c.user_identifier) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.value) !== null && _f !== void 0 ? _f : null,
529
+ photoId: (_h = (_g = r.user) === null || _g === void 0 ? void 0 : _g.photo_id) !== null && _h !== void 0 ? _h : null,
245
530
  role: r.role,
246
531
  status: r.status,
247
- lastAccessAt: (_h = (_g = r.user) === null || _g === void 0 ? void 0 : _g.last_login_at) !== null && _h !== void 0 ? _h : null,
532
+ lastAccessAt: (_k = (_j = r.user) === null || _j === void 0 ? void 0 : _j.last_login_at) !== null && _k !== void 0 ? _k : null,
248
533
  });
249
534
  }),
250
535
  };
@@ -336,6 +621,16 @@ let EnterpriseService = class EnterpriseService {
336
621
  status: true,
337
622
  level: true,
338
623
  offering_type: true,
624
+ course_image: {
625
+ where: { image_type: { slug: 'course-logo' } },
626
+ take: 1,
627
+ select: {
628
+ file_id: true,
629
+ file: {
630
+ select: { id: true },
631
+ },
632
+ },
633
+ },
339
634
  },
340
635
  },
341
636
  },
@@ -348,17 +643,19 @@ let EnterpriseService = class EnterpriseService {
348
643
  pageSize,
349
644
  lastPage: Math.max(1, Math.ceil(total / pageSize)),
350
645
  data: rows.map((r) => {
351
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
352
- return ({
646
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
647
+ const courseLogo = (_c = (_b = (_a = r.course) === null || _a === void 0 ? void 0 : _a.course_image) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : null;
648
+ return {
353
649
  id: r.id,
354
650
  courseId: r.course_id,
355
651
  contractedAt: r.contracted_at,
356
- title: (_b = (_a = r.course) === null || _a === void 0 ? void 0 : _a.title) !== null && _b !== void 0 ? _b : null,
357
- slug: (_d = (_c = r.course) === null || _c === void 0 ? void 0 : _c.slug) !== null && _d !== void 0 ? _d : null,
358
- status: (_f = (_e = r.course) === null || _e === void 0 ? void 0 : _e.status) !== null && _f !== void 0 ? _f : null,
359
- level: (_h = (_g = r.course) === null || _g === void 0 ? void 0 : _g.level) !== null && _h !== void 0 ? _h : null,
360
- modality: (_k = (_j = r.course) === null || _j === void 0 ? void 0 : _j.offering_type) !== null && _k !== void 0 ? _k : null,
361
- });
652
+ title: (_e = (_d = r.course) === null || _d === void 0 ? void 0 : _d.title) !== null && _e !== void 0 ? _e : null,
653
+ slug: (_g = (_f = r.course) === null || _f === void 0 ? void 0 : _f.slug) !== null && _g !== void 0 ? _g : null,
654
+ status: (_j = (_h = r.course) === null || _h === void 0 ? void 0 : _h.status) !== null && _j !== void 0 ? _j : null,
655
+ level: (_l = (_k = r.course) === null || _k === void 0 ? void 0 : _k.level) !== null && _l !== void 0 ? _l : null,
656
+ modality: (_o = (_m = r.course) === null || _m === void 0 ? void 0 : _m.offering_type) !== null && _o !== void 0 ? _o : null,
657
+ logoFileId: (_r = (_q = (_p = courseLogo === null || courseLogo === void 0 ? void 0 : courseLogo.file) === null || _p === void 0 ? void 0 : _p.id) !== null && _q !== void 0 ? _q : courseLogo === null || courseLogo === void 0 ? void 0 : courseLogo.file_id) !== null && _r !== void 0 ? _r : null,
658
+ };
362
659
  }),
363
660
  };
364
661
  }
@@ -425,7 +722,43 @@ let EnterpriseService = class EnterpriseService {
425
722
  start_date: true,
426
723
  end_date: true,
427
724
  capacity: true,
428
- course: { select: { id: true, title: true, slug: true } },
725
+ _count: {
726
+ select: {
727
+ course_enrollment: {
728
+ where: {
729
+ status: { not: 'cancelled' },
730
+ },
731
+ },
732
+ },
733
+ },
734
+ instructor: {
735
+ select: {
736
+ id: true,
737
+ person: {
738
+ select: {
739
+ name: true,
740
+ avatar_id: true,
741
+ },
742
+ },
743
+ },
744
+ },
745
+ course: {
746
+ select: {
747
+ id: true,
748
+ title: true,
749
+ slug: true,
750
+ course_image: {
751
+ where: { image_type: { slug: 'course-logo' } },
752
+ take: 1,
753
+ select: {
754
+ file_id: true,
755
+ file: {
756
+ select: { id: true },
757
+ },
758
+ },
759
+ },
760
+ },
761
+ },
429
762
  },
430
763
  },
431
764
  },
@@ -438,20 +771,26 @@ let EnterpriseService = class EnterpriseService {
438
771
  pageSize,
439
772
  lastPage: Math.max(1, Math.ceil(total / pageSize)),
440
773
  data: rows.map((r) => {
441
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
442
- return ({
774
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16;
775
+ const courseLogo = (_d = (_c = (_b = (_a = r.course_class_group) === null || _a === void 0 ? void 0 : _a.course) === null || _b === void 0 ? void 0 : _b.course_image) === null || _c === void 0 ? void 0 : _c[0]) !== null && _d !== void 0 ? _d : null;
776
+ return {
443
777
  id: r.id,
444
778
  courseClassGroupId: r.course_class_group_id,
445
- code: (_b = (_a = r.course_class_group) === null || _a === void 0 ? void 0 : _a.code) !== null && _b !== void 0 ? _b : null,
446
- title: (_d = (_c = r.course_class_group) === null || _c === void 0 ? void 0 : _c.title) !== null && _d !== void 0 ? _d : null,
447
- status: (_f = (_e = r.course_class_group) === null || _e === void 0 ? void 0 : _e.status) !== null && _f !== void 0 ? _f : null,
448
- deliveryMode: (_h = (_g = r.course_class_group) === null || _g === void 0 ? void 0 : _g.delivery_mode) !== null && _h !== void 0 ? _h : null,
449
- startDate: (_k = (_j = r.course_class_group) === null || _j === void 0 ? void 0 : _j.start_date) !== null && _k !== void 0 ? _k : null,
450
- endDate: (_m = (_l = r.course_class_group) === null || _l === void 0 ? void 0 : _l.end_date) !== null && _m !== void 0 ? _m : null,
451
- capacity: (_p = (_o = r.course_class_group) === null || _o === void 0 ? void 0 : _o.capacity) !== null && _p !== void 0 ? _p : null,
452
- courseTitle: (_s = (_r = (_q = r.course_class_group) === null || _q === void 0 ? void 0 : _q.course) === null || _r === void 0 ? void 0 : _r.title) !== null && _s !== void 0 ? _s : null,
453
- courseSlug: (_v = (_u = (_t = r.course_class_group) === null || _t === void 0 ? void 0 : _t.course) === null || _u === void 0 ? void 0 : _u.slug) !== null && _v !== void 0 ? _v : null,
454
- });
779
+ code: (_f = (_e = r.course_class_group) === null || _e === void 0 ? void 0 : _e.code) !== null && _f !== void 0 ? _f : null,
780
+ title: (_h = (_g = r.course_class_group) === null || _g === void 0 ? void 0 : _g.title) !== null && _h !== void 0 ? _h : null,
781
+ status: (_k = (_j = r.course_class_group) === null || _j === void 0 ? void 0 : _j.status) !== null && _k !== void 0 ? _k : null,
782
+ deliveryMode: (_m = (_l = r.course_class_group) === null || _l === void 0 ? void 0 : _l.delivery_mode) !== null && _m !== void 0 ? _m : null,
783
+ startDate: (_p = (_o = r.course_class_group) === null || _o === void 0 ? void 0 : _o.start_date) !== null && _p !== void 0 ? _p : null,
784
+ endDate: (_r = (_q = r.course_class_group) === null || _q === void 0 ? void 0 : _q.end_date) !== null && _r !== void 0 ? _r : null,
785
+ capacity: (_t = (_s = r.course_class_group) === null || _s === void 0 ? void 0 : _s.capacity) !== null && _t !== void 0 ? _t : null,
786
+ enrolledCount: (_w = (_v = (_u = r.course_class_group) === null || _u === void 0 ? void 0 : _u._count) === null || _v === void 0 ? void 0 : _v.course_enrollment) !== null && _w !== void 0 ? _w : 0,
787
+ instructorId: (_z = (_y = (_x = r.course_class_group) === null || _x === void 0 ? void 0 : _x.instructor) === null || _y === void 0 ? void 0 : _y.id) !== null && _z !== void 0 ? _z : null,
788
+ instructorName: (_3 = (_2 = (_1 = (_0 = r.course_class_group) === null || _0 === void 0 ? void 0 : _0.instructor) === null || _1 === void 0 ? void 0 : _1.person) === null || _2 === void 0 ? void 0 : _2.name) !== null && _3 !== void 0 ? _3 : null,
789
+ instructorAvatarId: (_7 = (_6 = (_5 = (_4 = r.course_class_group) === null || _4 === void 0 ? void 0 : _4.instructor) === null || _5 === void 0 ? void 0 : _5.person) === null || _6 === void 0 ? void 0 : _6.avatar_id) !== null && _7 !== void 0 ? _7 : null,
790
+ courseTitle: (_10 = (_9 = (_8 = r.course_class_group) === null || _8 === void 0 ? void 0 : _8.course) === null || _9 === void 0 ? void 0 : _9.title) !== null && _10 !== void 0 ? _10 : null,
791
+ courseSlug: (_13 = (_12 = (_11 = r.course_class_group) === null || _11 === void 0 ? void 0 : _11.course) === null || _12 === void 0 ? void 0 : _12.slug) !== null && _13 !== void 0 ? _13 : null,
792
+ logoFileId: (_16 = (_15 = (_14 = courseLogo === null || courseLogo === void 0 ? void 0 : courseLogo.file) === null || _14 === void 0 ? void 0 : _14.id) !== null && _15 !== void 0 ? _15 : courseLogo === null || courseLogo === void 0 ? void 0 : courseLogo.file_id) !== null && _16 !== void 0 ? _16 : null,
793
+ };
455
794
  }),
456
795
  };
457
796
  }
@@ -490,6 +829,12 @@ let EnterpriseService = class EnterpriseService {
490
829
  await this.prisma.enterprise_student.create({
491
830
  data: { enterprise_id: enterpriseId, person_id, status: 'active' },
492
831
  });
832
+ await this.recordLicenseEvent({
833
+ enterpriseId,
834
+ personId: person_id,
835
+ eventType: 'assigned',
836
+ nextStatus: 'active',
837
+ });
493
838
  }
494
839
  }
495
840
  return link;
@@ -531,6 +876,7 @@ let EnterpriseService = class EnterpriseService {
531
876
  select: {
532
877
  id: true,
533
878
  name: true,
879
+ avatar_id: true,
534
880
  contact: {
535
881
  where: { contact_type: { code: 'EMAIL' }, is_primary: true },
536
882
  select: { value: true },
@@ -548,12 +894,13 @@ let EnterpriseService = class EnterpriseService {
548
894
  pageSize,
549
895
  lastPage: Math.max(1, Math.ceil(total / pageSize)),
550
896
  data: rows.map((r) => {
551
- var _a, _b, _c, _d, _e, _f;
897
+ var _a, _b, _c, _d, _e, _f, _g, _h;
552
898
  return ({
553
899
  id: r.id,
554
900
  personId: r.person_id,
555
901
  name: (_b = (_a = r.person) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : null,
556
902
  email: (_f = (_e = (_d = (_c = r.person) === null || _c === void 0 ? void 0 : _c.contact) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.value) !== null && _f !== void 0 ? _f : null,
903
+ avatarId: (_h = (_g = r.person) === null || _g === void 0 ? void 0 : _g.avatar_id) !== null && _h !== void 0 ? _h : null,
557
904
  status: r.status,
558
905
  createdAt: r.created_at,
559
906
  });
@@ -561,6 +908,7 @@ let EnterpriseService = class EnterpriseService {
561
908
  };
562
909
  }
563
910
  async addStudent(enterpriseId, dto) {
911
+ var _a;
564
912
  await this.assertEnterpriseExists(enterpriseId);
565
913
  const person = await this.prisma.person.findUnique({
566
914
  where: { id: dto.person_id },
@@ -574,34 +922,58 @@ let EnterpriseService = class EnterpriseService {
574
922
  });
575
923
  if (duplicate)
576
924
  throw new common_1.ConflictException(`Person #${dto.person_id} is already a student of enterprise #${enterpriseId}`);
577
- return this.prisma.enterprise_student.create({
925
+ const created = await this.prisma.enterprise_student.create({
578
926
  data: Object.assign({ enterprise_id: enterpriseId }, dto),
579
927
  });
928
+ await this.recordLicenseEvent({
929
+ enterpriseId,
930
+ personId: dto.person_id,
931
+ eventType: 'assigned',
932
+ nextStatus: (_a = dto.status) !== null && _a !== void 0 ? _a : 'pending',
933
+ });
934
+ return created;
580
935
  }
581
936
  async updateStudent(enterpriseId, personId, dto) {
582
937
  await this.assertEnterpriseExists(enterpriseId);
583
938
  const existing = await this.prisma.enterprise_student.findFirst({
584
939
  where: { enterprise_id: enterpriseId, person_id: personId },
585
- select: { id: true },
940
+ select: { id: true, status: true },
586
941
  });
587
942
  if (!existing)
588
943
  throw new common_1.NotFoundException(`Person #${personId} is not a student of enterprise #${enterpriseId}`);
589
- return this.prisma.enterprise_student.update({
944
+ const updated = await this.prisma.enterprise_student.update({
590
945
  where: { id: existing.id },
591
946
  data: dto,
592
947
  });
948
+ if (dto.status && dto.status !== existing.status) {
949
+ await this.recordLicenseEvent({
950
+ enterpriseId,
951
+ personId,
952
+ eventType: 'status_changed',
953
+ previousStatus: existing.status,
954
+ nextStatus: dto.status,
955
+ });
956
+ }
957
+ return updated;
593
958
  }
594
959
  async removeStudent(enterpriseId, personId) {
595
960
  await this.assertEnterpriseExists(enterpriseId);
596
961
  const existing = await this.prisma.enterprise_student.findFirst({
597
962
  where: { enterprise_id: enterpriseId, person_id: personId },
598
- select: { id: true },
963
+ select: { id: true, status: true },
599
964
  });
600
965
  if (!existing)
601
966
  throw new common_1.NotFoundException(`Person #${personId} is not a student of enterprise #${enterpriseId}`);
602
- return this.prisma.enterprise_student.delete({
967
+ const deleted = await this.prisma.enterprise_student.delete({
603
968
  where: { id: existing.id },
604
969
  });
970
+ await this.recordLicenseEvent({
971
+ enterpriseId,
972
+ personId,
973
+ eventType: 'revoked',
974
+ previousStatus: existing.status,
975
+ });
976
+ return deleted;
605
977
  }
606
978
  // ─── Stats / options ──────────────────────────────────────────────────────────
607
979
  async getStats() {
@@ -795,7 +1167,7 @@ let EnterpriseService = class EnterpriseService {
795
1167
  return profiles;
796
1168
  }
797
1169
  mapEnterprise(e, extra) {
798
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
1170
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
799
1171
  const { _count, person } = e;
800
1172
  const pc = (_a = extra === null || extra === void 0 ? void 0 : extra.personCompany) !== null && _a !== void 0 ? _a : null;
801
1173
  return {
@@ -814,18 +1186,19 @@ let EnterpriseService = class EnterpriseService {
814
1186
  ? {
815
1187
  id: person.id,
816
1188
  name: person.name,
817
- tradeName: (_f = pc === null || pc === void 0 ? void 0 : pc.trade_name) !== null && _f !== void 0 ? _f : null,
818
- industry: (_g = pc === null || pc === void 0 ? void 0 : pc.industry) !== null && _g !== void 0 ? _g : null,
819
- website: (_h = pc === null || pc === void 0 ? void 0 : pc.website) !== null && _h !== void 0 ? _h : null,
820
- lifecycleStage: (_j = pc === null || pc === void 0 ? void 0 : pc.account_lifecycle_stage) !== null && _j !== void 0 ? _j : null,
1189
+ avatarId: (_f = person.avatar_id) !== null && _f !== void 0 ? _f : null,
1190
+ tradeName: (_g = pc === null || pc === void 0 ? void 0 : pc.trade_name) !== null && _g !== void 0 ? _g : null,
1191
+ industry: (_h = pc === null || pc === void 0 ? void 0 : pc.industry) !== null && _h !== void 0 ? _h : null,
1192
+ website: (_j = pc === null || pc === void 0 ? void 0 : pc.website) !== null && _j !== void 0 ? _j : null,
1193
+ lifecycleStage: (_k = pc === null || pc === void 0 ? void 0 : pc.account_lifecycle_stage) !== null && _k !== void 0 ? _k : null,
821
1194
  }
822
1195
  : null,
823
- usersCount: (_k = _count === null || _count === void 0 ? void 0 : _count.enterprise_user) !== null && _k !== void 0 ? _k : 0,
824
- studentsCount: (_l = extra === null || extra === void 0 ? void 0 : extra.studentsCount) !== null && _l !== void 0 ? _l : 0,
825
- managersCount: (_m = extra === null || extra === void 0 ? void 0 : extra.managersCount) !== null && _m !== void 0 ? _m : 0,
826
- adminsCount: (_o = extra === null || extra === void 0 ? void 0 : extra.adminsCount) !== null && _o !== void 0 ? _o : 0,
827
- coursesCount: (_p = _count === null || _count === void 0 ? void 0 : _count.enterprise_course) !== null && _p !== void 0 ? _p : 0,
828
- classesCount: (_q = _count === null || _count === void 0 ? void 0 : _count.enterprise_class_group) !== null && _q !== void 0 ? _q : 0,
1196
+ usersCount: (_l = _count === null || _count === void 0 ? void 0 : _count.enterprise_user) !== null && _l !== void 0 ? _l : 0,
1197
+ studentsCount: (_m = extra === null || extra === void 0 ? void 0 : extra.studentsCount) !== null && _m !== void 0 ? _m : 0,
1198
+ managersCount: (_o = extra === null || extra === void 0 ? void 0 : extra.managersCount) !== null && _o !== void 0 ? _o : 0,
1199
+ adminsCount: (_p = extra === null || extra === void 0 ? void 0 : extra.adminsCount) !== null && _p !== void 0 ? _p : 0,
1200
+ coursesCount: (_q = _count === null || _count === void 0 ? void 0 : _count.enterprise_course) !== null && _q !== void 0 ? _q : 0,
1201
+ classesCount: (_r = _count === null || _count === void 0 ? void 0 : _count.enterprise_class_group) !== null && _r !== void 0 ? _r : 0,
829
1202
  };
830
1203
  }
831
1204
  };