@hed-hog/lms 0.0.328 → 0.0.330

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 (52) hide show
  1. package/dist/instructor/instructor.service.d.ts.map +1 -1
  2. package/dist/instructor/instructor.service.js +22 -16
  3. package/dist/instructor/instructor.service.js.map +1 -1
  4. package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +18 -8
  5. package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +7 -5
  6. package/hedhog/frontend/app/_components/create-lms-person-sheet.tsx.ejs +5 -9
  7. package/hedhog/frontend/app/_components/create-lms-student-person-sheet.tsx.ejs +5 -9
  8. package/hedhog/frontend/app/certificates/models/LeftPanel.tsx.ejs +15 -14
  9. package/hedhog/frontend/app/certificates/models/RightPanel.tsx.ejs +66 -29
  10. package/hedhog/frontend/app/certificates/models/TemplateEditorPage.tsx.ejs +4 -2
  11. package/hedhog/frontend/app/certificates/models/TopBar.tsx.ejs +44 -34
  12. package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +10 -10
  13. package/hedhog/frontend/app/classes/page.tsx.ejs +23 -15
  14. package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +5 -3
  15. package/hedhog/frontend/app/courses/[id]/structure/_components/confirm-dialog.tsx.ejs +5 -3
  16. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-panel.tsx.ejs +9 -7
  17. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-skeleton.tsx.ejs +3 -1
  18. package/hedhog/frontend/app/courses/[id]/structure/_components/drag-handle.tsx.ejs +4 -2
  19. package/hedhog/frontend/app/courses/[id]/structure/_components/editor-bulk.tsx.ejs +24 -23
  20. package/hedhog/frontend/app/courses/[id]/structure/_components/multi-select-bar.tsx.ejs +21 -19
  21. package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +7 -5
  22. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +18 -16
  23. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +13 -11
  24. package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-session.tsx.ejs +5 -3
  25. package/hedhog/frontend/app/courses/[id]/structure/_components/use-course-structure-shortcuts.ts.ejs +14 -9
  26. package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +42 -25
  27. package/hedhog/frontend/app/enterprise/_components/enterprise-admin-create-sheet.tsx.ejs +3 -1
  28. package/hedhog/frontend/app/enterprise/_components/enterprise-administrators-tab.tsx.ejs +10 -8
  29. package/hedhog/frontend/app/enterprise/_components/enterprise-classes-tab.tsx.ejs +22 -20
  30. package/hedhog/frontend/app/enterprise/_components/enterprise-course-create-sheet.tsx.ejs +3 -3
  31. package/hedhog/frontend/app/enterprise/_components/enterprise-courses-tab.tsx.ejs +21 -19
  32. package/hedhog/frontend/app/enterprise/_components/enterprise-sheet.tsx.ejs +34 -36
  33. package/hedhog/frontend/app/enterprise/_components/enterprise-student-create-sheet.tsx.ejs +3 -1
  34. package/hedhog/frontend/app/enterprise/_components/enterprise-students-tab.tsx.ejs +7 -5
  35. package/hedhog/frontend/app/enterprise/page.tsx.ejs +106 -54
  36. package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +79 -59
  37. package/hedhog/frontend/app/instructors/_components/instructor-form-sheet.tsx.ejs +92 -26
  38. package/hedhog/frontend/app/instructors/page.tsx.ejs +4 -2
  39. package/hedhog/frontend/messages/en.json +619 -13
  40. package/hedhog/frontend/messages/pt.json +619 -13
  41. package/package.json +7 -7
  42. package/src/instructor/instructor.service.ts +22 -19
  43. package/hedhog/frontend/app/_components/create-lms-instructor-sheet.tsx.ejs +0 -591
  44. package/hedhog/frontend/app/courses/[id]/_components/CourseMainInfoCard.tsx.ejs +0 -109
  45. package/hedhog/frontend/app/courses/[id]/_components/CourseSummaryCard.tsx.ejs +0 -60
  46. package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +0 -134
  47. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-course.tsx.ejs +0 -113
  48. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +0 -314
  49. package/hedhog/frontend/app/courses/[id]/structure/_components/detail-session.tsx.ejs +0 -174
  50. package/hedhog/frontend/app/courses/[id]/structure/_components/mock-data.ts.ejs +0 -185
  51. package/hedhog/frontend/app/enterprise/_components/enterprise-mocks.ts.ejs +0 -277
  52. package/hedhog/frontend/app/enterprise/_components/enterprise-user-create-sheet.tsx.ejs +0 -207
@@ -44,6 +44,7 @@ import {
44
44
  SquareArrowOutUpRight,
45
45
  Users,
46
46
  } from 'lucide-react';
47
+ import { useTranslations } from 'next-intl';
47
48
  import { useMemo, useState } from 'react';
48
49
  import { EnterpriseDetailSheet } from './_components/enterprise-detail-sheet';
49
50
  import { EnterpriseSheet } from './_components/enterprise-sheet';
@@ -69,16 +70,10 @@ const STATUS_VARIANT: Record<
69
70
  suspended: 'destructive',
70
71
  };
71
72
 
72
- const STATUS_LABEL: Record<EnterpriseStatus, string> = {
73
- active: 'Active',
74
- trial: 'Trial',
75
- inactive: 'Inactive',
76
- suspended: 'Suspended',
77
- };
78
-
79
73
  // ── Page ──────────────────────────────────────────────────────────────────────
80
74
 
81
75
  export default function EnterprisePage() {
76
+ const t = useTranslations('lms.EnterprisePage');
82
77
  const [search, setSearch] = useState('');
83
78
  const [statusFilter, setStatusFilter] = useState('all');
84
79
  const [crmFilter, setCrmFilter] = useState('all');
@@ -205,42 +200,48 @@ export default function EnterprisePage() {
205
200
  return [
206
201
  {
207
202
  key: 'total',
208
- title: 'Total Accounts',
203
+ title: t('kpis.total.label'),
209
204
  value: total,
210
- description: 'All enterprise accounts',
205
+ description: t('kpis.total.description'),
211
206
  icon: Building2,
212
207
  accentClassName: 'from-slate-500/20 via-slate-400/10 to-transparent',
213
208
  iconContainerClassName: 'bg-slate-100 text-slate-700',
214
209
  },
215
210
  {
216
211
  key: 'active',
217
- title: 'Active',
212
+ title: t('kpis.active.label'),
218
213
  value: active,
219
- description: 'Currently active accounts',
214
+ description: t('kpis.active.description'),
220
215
  icon: Users,
221
216
  accentClassName: 'from-green-500/20 via-emerald-500/10 to-transparent',
222
217
  iconContainerClassName: 'bg-green-50 text-green-600',
223
218
  },
224
219
  {
225
220
  key: 'trial',
226
- title: 'Trial',
221
+ title: t.has('kpis.trial.label') ? t('kpis.trial.label') : 'Trial',
227
222
  value: trial,
228
- description: 'In trial period',
223
+ description: t.has('kpis.trial.description')
224
+ ? t('kpis.trial.description')
225
+ : 'In trial period',
229
226
  icon: CalendarDays,
230
227
  accentClassName: 'from-amber-500/20 via-orange-500/10 to-transparent',
231
228
  iconContainerClassName: 'bg-amber-50 text-amber-600',
232
229
  },
233
230
  {
234
231
  key: 'portal',
235
- title: 'Portal Enabled',
232
+ title: t.has('kpis.portal.label')
233
+ ? t('kpis.portal.label')
234
+ : 'Portal Enabled',
236
235
  value: withPortal,
237
- description: 'Self-service portal access',
236
+ description: t.has('kpis.portal.description')
237
+ ? t('kpis.portal.description')
238
+ : 'Self-service portal access',
238
239
  icon: Globe,
239
240
  accentClassName: 'from-blue-500/20 via-cyan-500/10 to-transparent',
240
241
  iconContainerClassName: 'bg-blue-50 text-blue-600',
241
242
  },
242
243
  ];
243
- }, [stats]);
244
+ }, [stats, t]);
244
245
 
245
246
  const accounts = enterpriseList?.data ?? [];
246
247
  const totalItems = enterpriseList?.total ?? 0;
@@ -271,11 +272,19 @@ export default function EnterprisePage() {
271
272
  value: statusFilter,
272
273
  onChange: handleStatusFilter,
273
274
  options: [
274
- { value: 'all', label: 'All statuses' },
275
- { value: 'active', label: 'Active' },
276
- { value: 'trial', label: 'Trial' },
277
- { value: 'inactive', label: 'Inactive' },
278
- { value: 'suspended', label: 'Suspended' },
275
+ { value: 'all', label: t('filters.allStatuses') },
276
+ { value: 'active', label: t('status.active') },
277
+ {
278
+ value: 'trial',
279
+ label: t.has('status.trial') ? t('status.trial') : 'Trial',
280
+ },
281
+ { value: 'inactive', label: t('status.inactive') },
282
+ {
283
+ value: 'suspended',
284
+ label: t.has('status.suspended')
285
+ ? t('status.suspended')
286
+ : 'Suspended',
287
+ },
279
288
  ],
280
289
  },
281
290
  {
@@ -283,7 +292,15 @@ export default function EnterprisePage() {
283
292
  type: 'select',
284
293
  value: crmFilter,
285
294
  onChange: handleCrmFilter,
286
- options: [{ value: 'all', label: 'All CRM accounts' }, ...crmOptions],
295
+ options: [
296
+ {
297
+ value: 'all',
298
+ label: t.has('filters.allCrmAccounts')
299
+ ? t('filters.allCrmAccounts')
300
+ : 'All CRM accounts',
301
+ },
302
+ ...crmOptions,
303
+ ],
287
304
  // options populated from API
288
305
  },
289
306
  ];
@@ -291,14 +308,16 @@ export default function EnterprisePage() {
291
308
  return (
292
309
  <Page>
293
310
  <PageHeader
311
+ title={t('title')}
312
+ description={t('description')}
294
313
  breadcrumbs={[
295
- { label: 'Home', href: '/' },
296
- { label: 'LMS', href: '/lms' },
297
- { label: 'Enterprise' },
314
+ { label: t('breadcrumbs.home'), href: '/' },
315
+ { label: t('breadcrumbs.lms'), href: '/lms' },
316
+ { label: t('breadcrumbs.enterprise') },
298
317
  ]}
299
318
  actions={[
300
319
  {
301
- label: 'New Account',
320
+ label: t('actions.new'),
302
321
  onClick: handleOpenCreate,
303
322
  icon: <Plus className="h-4 w-4" />,
304
323
  variant: 'default',
@@ -314,13 +333,13 @@ export default function EnterprisePage() {
314
333
  searchQuery={search}
315
334
  onSearchChange={handleSearch}
316
335
  onSearch={() => {}}
317
- placeholder="Search by name or CRM account..."
336
+ placeholder={t('filters.searchPlaceholder')}
318
337
  controls={controls}
319
338
  />
320
339
  </div>
321
340
  <div className="flex items-center gap-3">
322
341
  <span className="text-xs font-medium text-muted-foreground">
323
- View
342
+ {t.has('view.label') ? t('view.label') : 'View'}
324
343
  </span>
325
344
  <ToggleGroup
326
345
  type="single"
@@ -328,15 +347,23 @@ export default function EnterprisePage() {
328
347
  onValueChange={handleViewModeChange}
329
348
  variant="outline"
330
349
  size="sm"
331
- aria-label="View mode"
350
+ aria-label={
351
+ t.has('view.modeAriaLabel')
352
+ ? t('view.modeAriaLabel')
353
+ : 'View mode'
354
+ }
332
355
  >
333
356
  <ToggleGroupItem value="table" className="gap-1.5 px-2.5">
334
357
  <List className="h-4 w-4" />
335
- <span className="hidden sm:inline">Table</span>
358
+ <span className="hidden sm:inline">
359
+ {t.has('view.table') ? t('view.table') : 'Table'}
360
+ </span>
336
361
  </ToggleGroupItem>
337
362
  <ToggleGroupItem value="cards" className="gap-1.5 px-2.5">
338
363
  <LayoutGrid className="h-4 w-4" />
339
- <span className="hidden sm:inline">Cards</span>
364
+ <span className="hidden sm:inline">
365
+ {t.has('view.cards') ? t('view.cards') : 'Cards'}
366
+ </span>
340
367
  </ToggleGroupItem>
341
368
  </ToggleGroup>
342
369
  </div>
@@ -345,9 +372,9 @@ export default function EnterprisePage() {
345
372
  {accounts.length === 0 && !isLoading ? (
346
373
  <EmptyState
347
374
  icon={<Building2 className="h-10 w-10" />}
348
- title="No enterprise accounts found"
349
- description="Adjust your filters or create a new enterprise account."
350
- actionLabel="New Account"
375
+ title={t('empty.title')}
376
+ description={t('empty.description')}
377
+ actionLabel={t('actions.new')}
351
378
  onAction={handleOpenCreate}
352
379
  actionIcon={<Plus className="h-4 w-4" />}
353
380
  />
@@ -356,13 +383,25 @@ export default function EnterprisePage() {
356
383
  <Table>
357
384
  <TableHeader>
358
385
  <TableRow>
359
- <TableHead>Name</TableHead>
360
- <TableHead>Status</TableHead>
361
- <TableHead>CRM Account</TableHead>
362
- <TableHead className="text-center">Classes</TableHead>
363
- <TableHead className="text-center">Courses</TableHead>
364
- <TableHead className="text-center">Users</TableHead>
365
- <TableHead>Updated</TableHead>
386
+ <TableHead>{t('table.name')}</TableHead>
387
+ <TableHead>{t('table.status')}</TableHead>
388
+ <TableHead>
389
+ {t.has('table.crmAccount')
390
+ ? t('table.crmAccount')
391
+ : 'CRM Account'}
392
+ </TableHead>
393
+ <TableHead className="text-center">
394
+ {t.has('table.classes') ? t('table.classes') : 'Classes'}
395
+ </TableHead>
396
+ <TableHead className="text-center">
397
+ {t('table.activeCourses')}
398
+ </TableHead>
399
+ <TableHead className="text-center">
400
+ {t.has('table.users') ? t('table.users') : 'Users'}
401
+ </TableHead>
402
+ <TableHead>
403
+ {t.has('table.updated') ? t('table.updated') : 'Updated'}
404
+ </TableHead>
366
405
  <TableHead className="w-10" />
367
406
  </TableRow>
368
407
  </TableHeader>
@@ -381,14 +420,20 @@ export default function EnterprisePage() {
381
420
  <>
382
421
  <span className="opacity-30">·</span>
383
422
  <Globe className="h-3 w-3 text-primary/60" />
384
- <span className="text-primary/70">Portal</span>
423
+ <span className="text-primary/70">
424
+ {t.has('labels.portal')
425
+ ? t('labels.portal')
426
+ : 'Portal'}
427
+ </span>
385
428
  </>
386
429
  )}
387
430
  </p>
388
431
  </TableCell>
389
432
  <TableCell>
390
433
  <Badge variant={STATUS_VARIANT[account.status]}>
391
- {STATUS_LABEL[account.status]}
434
+ {t.has(`status.${account.status}`)
435
+ ? t(`status.${account.status}`)
436
+ : account.status}
392
437
  </Badge>
393
438
  </TableCell>
394
439
  <TableCell className="text-sm text-muted-foreground">
@@ -422,14 +467,14 @@ export default function EnterprisePage() {
422
467
  onClick={() => handleViewDetails(account)}
423
468
  >
424
469
  <SquareArrowOutUpRight className="mr-2 h-4 w-4" />
425
- View details
470
+ {t('actions.view')}
426
471
  </DropdownMenuItem>
427
472
  <DropdownMenuSeparator />
428
473
  <DropdownMenuItem
429
474
  onClick={() => handleOpenEdit(account)}
430
475
  >
431
476
  <Pencil className="mr-2 h-4 w-4" />
432
- Edit
477
+ {t('actions.edit')}
433
478
  </DropdownMenuItem>
434
479
  </DropdownMenuContent>
435
480
  </DropdownMenu>
@@ -453,7 +498,9 @@ export default function EnterprisePage() {
453
498
  <div className="min-w-0 flex-1">
454
499
  <div className="mb-1 flex flex-wrap items-center gap-1.5">
455
500
  <Badge variant={STATUS_VARIANT[account.status]}>
456
- {STATUS_LABEL[account.status]}
501
+ {t.has(`status.${account.status}`)
502
+ ? t(`status.${account.status}`)
503
+ : account.status}
457
504
  </Badge>
458
505
  {account.portalEnabled && (
459
506
  <Badge
@@ -461,7 +508,9 @@ export default function EnterprisePage() {
461
508
  className="border-blue-500/20 bg-blue-500/10 px-1.5 text-blue-600"
462
509
  >
463
510
  <Globe className="mr-1 h-3 w-3" />
464
- Portal
511
+ {t.has('labels.portal')
512
+ ? t('labels.portal')
513
+ : 'Portal'}
465
514
  </Badge>
466
515
  )}
467
516
  </div>
@@ -491,14 +540,14 @@ export default function EnterprisePage() {
491
540
  onClick={() => handleViewDetails(account)}
492
541
  >
493
542
  <SquareArrowOutUpRight className="mr-2 h-4 w-4" />
494
- View details
543
+ {t('actions.view')}
495
544
  </DropdownMenuItem>
496
545
  <DropdownMenuSeparator />
497
546
  <DropdownMenuItem
498
547
  onClick={() => handleOpenEdit(account)}
499
548
  >
500
549
  <Pencil className="mr-2 h-4 w-4" />
501
- Edit
550
+ {t('actions.edit')}
502
551
  </DropdownMenuItem>
503
552
  </DropdownMenuContent>
504
553
  </DropdownMenu>
@@ -508,7 +557,9 @@ export default function EnterprisePage() {
508
557
  {/* CRM */}
509
558
  {account.crmAccountName && (
510
559
  <p className="truncate text-xs text-muted-foreground">
511
- <span className="font-medium">CRM:</span>{' '}
560
+ <span className="font-medium">
561
+ {t.has('labels.crm') ? t('labels.crm') : 'CRM'}:
562
+ </span>{' '}
512
563
  {account.crmAccountName}
513
564
  </p>
514
565
  )}
@@ -521,7 +572,7 @@ export default function EnterprisePage() {
521
572
  {account.classesCount}
522
573
  </span>
523
574
  <span className="text-[10px] text-muted-foreground">
524
- Classes
575
+ {t.has('table.classes') ? t('table.classes') : 'Classes'}
525
576
  </span>
526
577
  </div>
527
578
  <div className="flex flex-col py-2">
@@ -530,7 +581,7 @@ export default function EnterprisePage() {
530
581
  {account.coursesCount}
531
582
  </span>
532
583
  <span className="text-[10px] text-muted-foreground">
533
- Courses
584
+ {t('table.activeCourses')}
534
585
  </span>
535
586
  </div>
536
587
  <div className="flex flex-col py-2">
@@ -539,14 +590,15 @@ export default function EnterprisePage() {
539
590
  {account.usersCount}
540
591
  </span>
541
592
  <span className="text-[10px] text-muted-foreground">
542
- Users
593
+ {t.has('table.users') ? t('table.users') : 'Users'}
543
594
  </span>
544
595
  </div>
545
596
  </div>
546
597
 
547
598
  {/* Footer */}
548
599
  <p className="text-right text-[10px] text-muted-foreground/60">
549
- Updated{' '}
600
+ {(t.has('labels.updated') ? t('labels.updated') : 'Updated') +
601
+ ' '}
550
602
  {formatDate(
551
603
  account.updatedAt,
552
604
  getSettingValue,