@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
@@ -2452,13 +2452,13 @@ export default function TurmaDetalhePage() {
2452
2452
  },
2453
2453
  {
2454
2454
  key: 'next-session',
2455
- title: 'Proxima aula',
2455
+ title: t('kpis.nextClass'),
2456
2456
  value: nextSession
2457
2457
  ? format(nextSessionStartsAt!, 'dd/MM', { locale: dateLocale })
2458
- : 'Sem aula',
2458
+ : t('kpis.noClass'),
2459
2459
  description: nextSession
2460
2460
  ? `${nextSession.horaInicio} - ${nextSession.horaFim}`
2461
- : 'Crie a proxima sessao',
2461
+ : t('kpis.createNext'),
2462
2462
  icon: Clock,
2463
2463
  iconContainerClassName: 'bg-emerald-500/10 text-emerald-700',
2464
2464
  accentClassName: 'from-emerald-500/25 via-green-500/10 to-transparent',
@@ -2466,9 +2466,9 @@ export default function TurmaDetalhePage() {
2466
2466
  },
2467
2467
  {
2468
2468
  key: 'calendar',
2469
- title: 'Calendario',
2469
+ title: t('kpis.calendar'),
2470
2470
  value: totalSessionsCount,
2471
- description: `${completedSessionsCount} concluidas`,
2471
+ description: t('kpis.completed', { count: completedSessionsCount }),
2472
2472
  icon: CalendarIcon,
2473
2473
  iconContainerClassName: 'bg-violet-500/10 text-violet-700',
2474
2474
  accentClassName: 'from-violet-500/25 via-violet-500/10 to-transparent',
@@ -2582,7 +2582,7 @@ export default function TurmaDetalhePage() {
2582
2582
  variant: 'outline',
2583
2583
  },
2584
2584
  {
2585
- label: 'Editar turma',
2585
+ label: t('actions.editClass'),
2586
2586
  onClick: () => setEditSheetOpen(true),
2587
2587
  variant: 'default',
2588
2588
  },
@@ -2660,7 +2660,7 @@ export default function TurmaDetalhePage() {
2660
2660
  key={i}
2661
2661
  className="overflow-hidden border-border/70 py-0"
2662
2662
  >
2663
- <div className="h-1 w-full bg-gradient-to-r from-slate-300/70 via-slate-200 to-transparent" />
2663
+ <div className="h-1 w-full bg-linear-to-r from-slate-300/70 via-slate-200 to-transparent" />
2664
2664
  <CardContent className="p-4">
2665
2665
  <Skeleton className="mb-2 h-8 w-16" />
2666
2666
  <Skeleton className="h-4 w-28" />
@@ -2803,7 +2803,7 @@ export default function TurmaDetalhePage() {
2803
2803
  #
2804
2804
  </TableHead>
2805
2805
  <TableHead>Sessão</TableHead>
2806
- <TableHead className="w-[120px]">Data</TableHead>
2806
+ <TableHead className="w-30">Data</TableHead>
2807
2807
  <TableHead className="w-[105px]">Horário</TableHead>
2808
2808
  <TableHead className="w-[90px]">Tipo</TableHead>
2809
2809
  <TableHead>Instrutor</TableHead>
@@ -2814,7 +2814,7 @@ export default function TurmaDetalhePage() {
2814
2814
  Materiais
2815
2815
  </TableHead>
2816
2816
  <TableHead className="w-[90px]">Link</TableHead>
2817
- <TableHead className="w-[44px]" />
2817
+ <TableHead className="w-11" />
2818
2818
  </TableRow>
2819
2819
  </TableHeader>
2820
2820
  <TableBody>
@@ -3359,7 +3359,7 @@ export default function TurmaDetalhePage() {
3359
3359
  src={getPersonAvatarUrl(aluno.avatarId)}
3360
3360
  alt={aluno.nome}
3361
3361
  />
3362
- <AvatarFallback className="bg-gradient-to-br from-blue-100 to-blue-200 text-[11px] font-medium text-blue-700">
3362
+ <AvatarFallback className="bg-linear-to-br from-blue-100 to-blue-200 text-[11px] font-medium text-blue-700">
3363
3363
  {getPersonInitials(aluno.nome)}
3364
3364
  </AvatarFallback>
3365
3365
  </Avatar>
@@ -3616,7 +3616,7 @@ export default function TurmaDetalhePage() {
3616
3616
  {tClasses(`type.${aula.tipo}`)}
3617
3617
  </Badge>
3618
3618
  </TableCell>
3619
- <TableCell className="max-w-[180px] truncate text-sm text-muted-foreground">
3619
+ <TableCell className="max-w-45 truncate text-sm text-muted-foreground">
3620
3620
  {aula.meetingUrl || aula.local || '—'}
3621
3621
  </TableCell>
3622
3622
  <TableCell className="text-sm text-muted-foreground">
@@ -3857,7 +3857,7 @@ export default function TurmaDetalhePage() {
3857
3857
  <Table>
3858
3858
  <TableHeader>
3859
3859
  <TableRow className="bg-muted/40 hover:bg-muted/40">
3860
- <TableHead className="sticky left-0 z-10 min-w-[260px] bg-muted/40 font-semibold">
3860
+ <TableHead className="sticky left-0 z-10 min-w-65 bg-muted/40 font-semibold">
3861
3861
  {t('tabs.students')}
3862
3862
  </TableHead>
3863
3863
  {aulasState.map((aula) => {
@@ -3886,14 +3886,14 @@ export default function TurmaDetalhePage() {
3886
3886
  key={aluno.id}
3887
3887
  className="hover:bg-muted/30"
3888
3888
  >
3889
- <TableCell className="sticky left-0 z-10 min-w-[260px] border-r border-border/40 bg-background">
3889
+ <TableCell className="sticky left-0 z-10 min-w-65 border-r border-border/40 bg-background">
3890
3890
  <div className="flex min-w-0 items-center gap-3">
3891
3891
  <Avatar className="size-8 shrink-0">
3892
3892
  <AvatarImage
3893
3893
  src={getPersonAvatarUrl(aluno.avatarId)}
3894
3894
  alt={aluno.nome}
3895
3895
  />
3896
- <AvatarFallback className="bg-gradient-to-br from-blue-100 to-blue-200 text-[11px] font-medium text-blue-700">
3896
+ <AvatarFallback className="bg-linear-to-br from-blue-100 to-blue-200 text-[11px] font-medium text-blue-700">
3897
3897
  {getPersonInitials(aluno.nome)}
3898
3898
  </AvatarFallback>
3899
3899
  </Avatar>
@@ -4195,7 +4195,7 @@ export default function TurmaDetalhePage() {
4195
4195
  globalLinkTitleEditedRef.current =
4196
4196
  e.target.value.length > 0;
4197
4197
  }}
4198
- placeholder="Ex: Referência de estudo"
4198
+ placeholder={t('links.studyRefPlaceholder')}
4199
4199
  />
4200
4200
  </Field>
4201
4201
  <div className="flex gap-2">
@@ -4615,7 +4615,7 @@ export default function TurmaDetalhePage() {
4615
4615
  src={getPersonAvatarUrl(selectedStudentProfile.avatarId)}
4616
4616
  alt={selectedStudentProfile.nome}
4617
4617
  />
4618
- <AvatarFallback className="bg-gradient-to-br from-blue-100 to-blue-200 text-xs font-medium text-blue-700">
4618
+ <AvatarFallback className="bg-linear-to-br from-blue-100 to-blue-200 text-xs font-medium text-blue-700">
4619
4619
  {getPersonInitials(selectedStudentProfile.nome)}
4620
4620
  </AvatarFallback>
4621
4621
  </Avatar>
@@ -5655,7 +5655,7 @@ export default function TurmaDetalhePage() {
5655
5655
  linkTitleEditedRef.current =
5656
5656
  e.target.value.length > 0;
5657
5657
  }}
5658
- placeholder="Ex: Slides da aula"
5658
+ placeholder={t('links.lessonSlidesPlaceholder')}
5659
5659
  />
5660
5660
  </Field>
5661
5661
  <div className="flex gap-2">
@@ -95,6 +95,7 @@ import {
95
95
  import { useTranslations } from 'next-intl';
96
96
  import { useRouter } from 'next/navigation';
97
97
  import { useEffect, useMemo, useRef, useState } from 'react';
98
+ import { usePersistedPageSize } from '@/hooks/use-persisted-page-size';
98
99
  import type { DateRange } from 'react-day-picker';
99
100
  import { Controller, useForm, useWatch } from 'react-hook-form';
100
101
  import { toast } from 'sonner';
@@ -700,7 +701,11 @@ export default function TurmasPage() {
700
701
 
701
702
  // Pagination
702
703
  const [currentPage, setCurrentPage] = useState(1);
703
- const [pageSize, setPageSize] = useState(12);
704
+ const [pageSize, setPageSize] = usePersistedPageSize({
705
+ storageKey: 'pagination:global:pageSize',
706
+ defaultValue: 12,
707
+ allowedValues: PAGE_SIZES,
708
+ });
704
709
 
705
710
  // Double-click tracking
706
711
  const clickTimers = useRef<Map<number, ReturnType<typeof setTimeout>>>(
@@ -13,7 +13,7 @@ import {
13
13
  SelectTrigger,
14
14
  SelectValue,
15
15
  } from '@/components/ui/select';
16
- import { Palette, Settings2 } from 'lucide-react';
16
+ import { Settings2 } from 'lucide-react';
17
17
  import type { UseFormReturn } from 'react-hook-form';
18
18
 
19
19
  import { CourseSectionCard } from './CourseSectionCard';
@@ -33,23 +33,6 @@ type CourseClassificationCardProps = {
33
33
  offeringTypes: readonly SelectOption[];
34
34
  };
35
35
 
36
- function ColorPreview({ color, label }: { color: string; label: string }) {
37
- return (
38
- <div className="flex items-center gap-2 rounded-lg border border-border/60 bg-muted/20 px-2.5 py-1.5">
39
- <span
40
- className="h-4 w-4 shrink-0 rounded-full border border-black/10"
41
- style={{ backgroundColor: color }}
42
- />
43
- <div className="min-w-0">
44
- <p className="text-[10px] font-medium uppercase tracking-[0.14em] text-muted-foreground">
45
- {label}
46
- </p>
47
- <p className="truncate text-xs font-medium text-foreground">{color}</p>
48
- </div>
49
- </div>
50
- );
51
- }
52
-
53
36
  export function CourseClassificationCard({
54
37
  form,
55
38
  t,
@@ -57,10 +40,6 @@ export function CourseClassificationCard({
57
40
  statuses,
58
41
  offeringTypes,
59
42
  }: CourseClassificationCardProps) {
60
- const watchedPrimary = form.watch('primaryColor');
61
- const watchedSecondary = form.watch('secondaryColor');
62
- const watchedOfferingType = form.watch('tipoOferta');
63
-
64
43
  return (
65
44
  <CourseSectionCard
66
45
  title="Classificação e configuração"
@@ -156,7 +135,7 @@ export function CourseClassificationCard({
156
135
  <FormItem>
157
136
  <FormLabel>{t('form.fields.primaryColor.label')}</FormLabel>
158
137
  <FormControl>
159
- <div className="flex items-center gap-2 rounded-lg border border-border/60 bg-muted/20 px-2 py-1.5">
138
+ <div className="flex items-center gap-2">
160
139
  <Input
161
140
  type="color"
162
141
  value={field.value}
@@ -183,7 +162,7 @@ export function CourseClassificationCard({
183
162
  <FormItem>
184
163
  <FormLabel>{t('form.fields.secondaryColor.label')}</FormLabel>
185
164
  <FormControl>
186
- <div className="flex items-center gap-2 rounded-lg border border-border/60 bg-muted/20 px-2 py-1.5">
165
+ <div className="flex items-center gap-2">
187
166
  <Input
188
167
  type="color"
189
168
  value={field.value}
@@ -202,15 +181,6 @@ export function CourseClassificationCard({
202
181
  </FormItem>
203
182
  )}
204
183
  />
205
-
206
- <div className="space-y-2 rounded-lg border border-border/60 bg-linear-to-br from-muted/30 to-background p-3">
207
- <div className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground">
208
- <Palette className="h-3.5 w-3.5" />
209
- Preview
210
- </div>
211
- <ColorPreview color={watchedPrimary} label="Primária" />
212
- <ColorPreview color={watchedSecondary} label="Secundária" />
213
- </div>
214
184
  </div>
215
185
  </CourseSectionCard>
216
186
  );
@@ -1,3 +1,4 @@
1
+ import { RichTextEditor } from '@/components/rich-text-editor';
1
2
  import {
2
3
  FormControl,
3
4
  FormField,
@@ -5,7 +6,6 @@ import {
5
6
  FormLabel,
6
7
  FormMessage,
7
8
  } from '@/components/ui/form';
8
- import { Textarea } from '@/components/ui/textarea';
9
9
  import { FileText } from 'lucide-react';
10
10
  import type { UseFormReturn } from 'react-hook-form';
11
11
 
@@ -31,10 +31,10 @@ export function CourseContentCard({ form }: CourseContentCardProps) {
31
31
  <FormItem>
32
32
  <FormLabel>Objetivos do curso</FormLabel>
33
33
  <FormControl>
34
- <Textarea
35
- {...field}
36
- rows={3}
37
- placeholder="Explique o que o aluno será capaz de fazer ao concluir o curso."
34
+ <RichTextEditor
35
+ value={field.value || ''}
36
+ onChange={field.onChange}
37
+ className="w-full max-w-full"
38
38
  />
39
39
  </FormControl>
40
40
  <FormMessage />
@@ -49,10 +49,10 @@ export function CourseContentCard({ form }: CourseContentCardProps) {
49
49
  <FormItem>
50
50
  <FormLabel>Público-alvo</FormLabel>
51
51
  <FormControl>
52
- <Textarea
53
- {...field}
54
- rows={3}
55
- placeholder="Descreva para quem este curso foi pensado."
52
+ <RichTextEditor
53
+ value={field.value || ''}
54
+ onChange={field.onChange}
55
+ className="w-full max-w-full"
56
56
  />
57
57
  </FormControl>
58
58
  <FormMessage />
@@ -0,0 +1,109 @@
1
+ import { RichTextEditor } from '@/components/rich-text-editor';
2
+ import {
3
+ FormControl,
4
+ FormField,
5
+ FormItem,
6
+ FormLabel,
7
+ FormMessage,
8
+ } from '@/components/ui/form';
9
+ import { Input } from '@/components/ui/input';
10
+ import { Hash, NotebookPen } from 'lucide-react';
11
+ import type { UseFormReturn } from 'react-hook-form';
12
+
13
+ import { CourseSectionCard } from './CourseSectionCard';
14
+ import type { CourseEditFormValues, TranslationFn } from './course-edit-types';
15
+
16
+ type CourseMainInfoCardProps = {
17
+ form: UseFormReturn<CourseEditFormValues>;
18
+ t: TranslationFn;
19
+ };
20
+
21
+ export function CourseMainInfoCard({ form, t }: CourseMainInfoCardProps) {
22
+ return (
23
+ <CourseSectionCard
24
+ title={t('form.sections.basicInfo')}
25
+ description="Os identificadores e a comunicação principal do curso ficam aqui."
26
+ icon={NotebookPen}
27
+ >
28
+ <div className="grid gap-3 md:grid-cols-2">
29
+ <FormField
30
+ control={form.control}
31
+ name="slug"
32
+ render={({ field }) => (
33
+ <FormItem>
34
+ <FormLabel>{t('form.fields.slug.label')}</FormLabel>
35
+ <FormControl>
36
+ <div className="relative">
37
+ <Hash className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
38
+ <Input
39
+ {...field}
40
+ className="pl-9 font-mono"
41
+ placeholder={t('form.fields.slug.placeholder')}
42
+ onChange={(event) =>
43
+ field.onChange(
44
+ String(event.target.value || '').toLowerCase()
45
+ )
46
+ }
47
+ />
48
+ </div>
49
+ </FormControl>
50
+ <FormMessage />
51
+ </FormItem>
52
+ )}
53
+ />
54
+
55
+ <FormField
56
+ control={form.control}
57
+ name="nomeInterno"
58
+ render={({ field }) => (
59
+ <FormItem>
60
+ <FormLabel>{t('form.fields.internalName.label')}</FormLabel>
61
+ <FormControl>
62
+ <Input
63
+ {...field}
64
+ placeholder={t('form.fields.internalName.placeholder')}
65
+ />
66
+ </FormControl>
67
+ <FormMessage />
68
+ </FormItem>
69
+ )}
70
+ />
71
+
72
+ <FormField
73
+ control={form.control}
74
+ name="tituloComercial"
75
+ render={({ field }) => (
76
+ <FormItem className="md:col-span-2">
77
+ <FormLabel>{t('form.fields.title.label')}</FormLabel>
78
+ <FormControl>
79
+ <Input
80
+ {...field}
81
+ placeholder={t('form.fields.title.placeholder')}
82
+ />
83
+ </FormControl>
84
+ <FormMessage />
85
+ </FormItem>
86
+ )}
87
+ />
88
+
89
+ <FormField
90
+ control={form.control}
91
+ name="descricaoPublica"
92
+ render={({ field }) => (
93
+ <FormItem className="md:col-span-2">
94
+ <FormLabel>{t('form.fields.description.label')}</FormLabel>
95
+ <FormControl>
96
+ <RichTextEditor
97
+ value={field.value}
98
+ onChange={field.onChange}
99
+ className="w-full max-w-full"
100
+ />
101
+ </FormControl>
102
+ <FormMessage />
103
+ </FormItem>
104
+ )}
105
+ />
106
+ </div>
107
+ </CourseSectionCard>
108
+ );
109
+ }
@@ -1,9 +1,9 @@
1
1
  import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
2
+ import { Badge } from '@/components/ui/badge';
2
3
  import { Button } from '@/components/ui/button';
3
4
  import { EntityPicker } from '@/components/ui/entity-picker';
4
- import { Badge } from '@/components/ui/badge';
5
5
  import { cn } from '@/lib/utils';
6
- import { Grip, Plus, X } from 'lucide-react';
6
+ import { Grip, Pencil, Plus, X } from 'lucide-react';
7
7
  import { useMemo, useState } from 'react';
8
8
 
9
9
  import type { PickerOption } from './course-edit-types';
@@ -28,6 +28,7 @@ type CourseMultiEntityPickerProps = {
28
28
  }>;
29
29
  mapSearchToCreateValues?: (search: string) => Record<string, string>;
30
30
  onChange: (nextValue: string[]) => void;
31
+ onEditSelected?: (option: PickerOption) => void;
31
32
  emptyHint?: string;
32
33
  renderOptionMeta?: boolean;
33
34
  variant?: 'default' | 'instructor';
@@ -57,6 +58,7 @@ export function CourseMultiEntityPicker({
57
58
  createFields,
58
59
  mapSearchToCreateValues,
59
60
  onChange,
61
+ onEditSelected,
60
62
  emptyHint,
61
63
  renderOptionMeta = false,
62
64
  variant = 'default',
@@ -192,18 +194,33 @@ export function CourseMultiEntityPicker({
192
194
  </div>
193
195
  </div>
194
196
 
195
- <Button
196
- type="button"
197
- variant="ghost"
198
- size="icon"
199
- className="h-8 w-8 rounded-lg text-muted-foreground hover:text-foreground"
200
- onClick={() =>
201
- onChange(value.filter((item) => item !== option.value))
202
- }
203
- aria-label={`Remover ${option.label}`}
204
- >
205
- <X className="h-4 w-4" />
206
- </Button>
197
+ <div className="flex items-center gap-1">
198
+ {onEditSelected ? (
199
+ <Button
200
+ type="button"
201
+ variant="ghost"
202
+ size="icon"
203
+ className="h-8 w-8 rounded-lg text-muted-foreground hover:text-foreground"
204
+ onClick={() => onEditSelected(option)}
205
+ aria-label={`Editar ${option.label}`}
206
+ >
207
+ <Pencil className="h-4 w-4" />
208
+ </Button>
209
+ ) : null}
210
+
211
+ <Button
212
+ type="button"
213
+ variant="ghost"
214
+ size="icon"
215
+ className="h-8 w-8 rounded-lg text-muted-foreground hover:text-foreground"
216
+ onClick={() =>
217
+ onChange(value.filter((item) => item !== option.value))
218
+ }
219
+ aria-label={`Remover ${option.label}`}
220
+ >
221
+ <X className="h-4 w-4" />
222
+ </Button>
223
+ </div>
207
224
  </div>
208
225
  ) : (
209
226
  <Badge
@@ -211,7 +228,17 @@ export function CourseMultiEntityPicker({
211
228
  variant="secondary"
212
229
  className="flex items-center gap-1.5 rounded-full border border-border/60 bg-background px-3 py-1.5 text-xs font-medium text-foreground"
213
230
  >
214
- <span className="max-w-[180px] truncate">{option.label}</span>
231
+ <span className="max-w-45 truncate">{option.label}</span>
232
+ {onEditSelected ? (
233
+ <button
234
+ type="button"
235
+ className="cursor-pointer text-muted-foreground transition-colors hover:text-foreground"
236
+ onClick={() => onEditSelected(option)}
237
+ aria-label={`Editar ${option.label}`}
238
+ >
239
+ <Pencil className="h-3.5 w-3.5" />
240
+ </button>
241
+ ) : null}
215
242
  <button
216
243
  type="button"
217
244
  className="cursor-pointer text-muted-foreground transition-colors hover:text-foreground"