@hed-hog/lms 0.0.329 → 0.0.331
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +18 -8
- package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +10 -8
- package/hedhog/frontend/app/_components/create-lms-person-sheet.tsx.ejs +5 -9
- package/hedhog/frontend/app/_components/create-lms-student-person-sheet.tsx.ejs +5 -9
- package/hedhog/frontend/app/certificates/models/LeftPanel.tsx.ejs +15 -14
- package/hedhog/frontend/app/certificates/models/RightPanel.tsx.ejs +66 -29
- package/hedhog/frontend/app/certificates/models/TemplateEditorPage.tsx.ejs +4 -2
- package/hedhog/frontend/app/certificates/models/TopBar.tsx.ejs +44 -34
- package/hedhog/frontend/app/certificates/models/page.tsx.ejs +1 -1
- package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +27 -27
- package/hedhog/frontend/app/classes/page.tsx.ejs +23 -15
- package/hedhog/frontend/app/courses/[id]/_components/CourseMultiEntityPicker.tsx.ejs +2 -2
- package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +8 -6
- package/hedhog/frontend/app/courses/[id]/structure/_components/confirm-dialog.tsx.ejs +5 -3
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +1 -1
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-panel.tsx.ejs +9 -7
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-skeleton.tsx.ejs +3 -1
- package/hedhog/frontend/app/courses/[id]/structure/_components/drag-handle.tsx.ejs +4 -2
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-bulk.tsx.ejs +24 -23
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +228 -152
- package/hedhog/frontend/app/courses/[id]/structure/_components/multi-select-bar.tsx.ejs +21 -19
- package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +78 -36
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +18 -16
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +13 -11
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-session.tsx.ejs +5 -3
- package/hedhog/frontend/app/courses/[id]/structure/_components/use-course-structure-shortcuts.ts.ejs +14 -9
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +42 -25
- package/hedhog/frontend/app/enterprise/[id]/page.tsx.ejs +37 -41
- package/hedhog/frontend/app/enterprise/_components/enterprise-admin-create-sheet.tsx.ejs +3 -1
- package/hedhog/frontend/app/enterprise/_components/enterprise-administrators-tab.tsx.ejs +10 -8
- package/hedhog/frontend/app/enterprise/_components/enterprise-classes-tab.tsx.ejs +22 -20
- package/hedhog/frontend/app/enterprise/_components/enterprise-course-create-sheet.tsx.ejs +3 -3
- package/hedhog/frontend/app/enterprise/_components/enterprise-courses-tab.tsx.ejs +21 -19
- package/hedhog/frontend/app/enterprise/_components/enterprise-sheet.tsx.ejs +34 -36
- package/hedhog/frontend/app/enterprise/_components/enterprise-student-create-sheet.tsx.ejs +3 -1
- package/hedhog/frontend/app/enterprise/_components/enterprise-students-tab.tsx.ejs +7 -5
- package/hedhog/frontend/app/enterprise/page.tsx.ejs +106 -54
- package/hedhog/frontend/app/evaluations/_components/evaluation-topic-form-sheet.tsx.ejs +1 -1
- package/hedhog/frontend/app/exams/page.tsx.ejs +6 -2
- package/hedhog/frontend/app/instructor-skills/page.tsx.ejs +79 -59
- package/hedhog/frontend/app/instructors/_components/instructor-form-sheet.tsx.ejs +145 -119
- package/hedhog/frontend/app/instructors/page.tsx.ejs +75 -54
- package/hedhog/frontend/app/paths/page.tsx.ejs +11 -7
- package/hedhog/frontend/app/reports/courses/page.tsx.ejs +5 -5
- package/hedhog/frontend/app/reports/dashboard/page.tsx.ejs +8 -8
- package/hedhog/frontend/app/reports/page.tsx.ejs +7 -7
- package/hedhog/frontend/app/reports/students/page.tsx.ejs +6 -6
- package/hedhog/frontend/app/training/page.tsx.ejs +5 -5
- package/hedhog/frontend/messages/en.json +899 -45
- package/hedhog/frontend/messages/pt.json +894 -38
- package/hedhog/frontend/widgets/active-classes-kpi.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/active-courses-kpi.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/approval-rate-kpi.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/class-calendar.tsx.ejs +2 -2
- package/hedhog/frontend/widgets/completion-rate-kpi.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/issued-certificates-kpi.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/total-students-kpi.tsx.ejs +1 -1
- package/hedhog/table/instructor_qualification.yaml +1 -1
- package/hedhog/table/instructor_skill.yaml +1 -1
- package/package.json +7 -7
|
@@ -10,9 +10,11 @@ import {
|
|
|
10
10
|
AlertDialogHeader,
|
|
11
11
|
AlertDialogTitle,
|
|
12
12
|
} from '@/components/ui/alert-dialog';
|
|
13
|
+
import { useTranslations } from 'next-intl';
|
|
13
14
|
import { useStructureStore } from './store';
|
|
14
15
|
|
|
15
16
|
export function ConfirmDialog() {
|
|
17
|
+
const t = useTranslations('lms.CoursesPage.StructurePage.confirmDialog');
|
|
16
18
|
const confirmDialog = useStructureStore((s) => s.confirmDialog);
|
|
17
19
|
const closeConfirm = useStructureStore((s) => s.closeConfirm);
|
|
18
20
|
|
|
@@ -31,15 +33,15 @@ export function ConfirmDialog() {
|
|
|
31
33
|
)}
|
|
32
34
|
</AlertDialogHeader>
|
|
33
35
|
<AlertDialogFooter>
|
|
34
|
-
<AlertDialogCancel onClick={closeConfirm}>
|
|
36
|
+
<AlertDialogCancel onClick={closeConfirm}>{t('cancel')}</AlertDialogCancel>
|
|
35
37
|
<AlertDialogAction
|
|
36
38
|
onClick={handleConfirm}
|
|
37
39
|
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
38
40
|
>
|
|
39
|
-
|
|
41
|
+
{t('confirm')}
|
|
40
42
|
</AlertDialogAction>
|
|
41
43
|
</AlertDialogFooter>
|
|
42
44
|
</AlertDialogContent>
|
|
43
45
|
</AlertDialog>
|
|
44
46
|
);
|
|
45
|
-
}
|
|
47
|
+
}
|
|
@@ -295,7 +295,7 @@ export function CourseTreeDnd() {
|
|
|
295
295
|
<p className="text-sm font-medium text-foreground/70">
|
|
296
296
|
Nenhuma sessão
|
|
297
297
|
</p>
|
|
298
|
-
<p className="text-xs text-muted-foreground leading-relaxed max-w-
|
|
298
|
+
<p className="text-xs text-muted-foreground leading-relaxed max-w-45">
|
|
299
299
|
Adicione a primeira sessão para começar a organizar o conteúdo
|
|
300
300
|
do curso.
|
|
301
301
|
</p>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { Button } from '@/components/ui/button';
|
|
4
4
|
import { cn } from '@/lib/utils';
|
|
5
5
|
import { ChevronsDownUp, ChevronsUpDown, Loader2, Plus } from 'lucide-react';
|
|
6
|
+
import { useTranslations } from 'next-intl';
|
|
6
7
|
import { forwardRef, useMemo } from 'react';
|
|
7
8
|
import { useCreateSessionMutation } from '../_data/use-course-structure-mutations';
|
|
8
9
|
import { CourseTreeDnd } from './course-tree-dnd';
|
|
@@ -12,6 +13,7 @@ import { useStructureStore } from './store';
|
|
|
12
13
|
import { buildVisibleItems } from './tree-helpers';
|
|
13
14
|
|
|
14
15
|
export const CourseTreePanel = forwardRef<SearchFilterHandle>((_, ref) => {
|
|
16
|
+
const t = useTranslations('lms.CoursesPage.StructurePage');
|
|
15
17
|
const course = useStructureStore((s) => s.course);
|
|
16
18
|
const sessions = useStructureStore((s) => s.sessions);
|
|
17
19
|
const lessons = useStructureStore((s) => s.lessons);
|
|
@@ -57,10 +59,10 @@ export const CourseTreePanel = forwardRef<SearchFilterHandle>((_, ref) => {
|
|
|
57
59
|
)}
|
|
58
60
|
title={
|
|
59
61
|
allExpanded
|
|
60
|
-
? '
|
|
61
|
-
: '
|
|
62
|
+
? t('tree.collapseAllShortcut')
|
|
63
|
+
: t('tree.expandAllShortcut')
|
|
62
64
|
}
|
|
63
|
-
aria-label={allExpanded ? '
|
|
65
|
+
aria-label={allExpanded ? t('tree.collapseAll') : t('tree.expandAll')}
|
|
64
66
|
onClick={allExpanded ? collapseAll : expandAll}
|
|
65
67
|
disabled={isFiltering}
|
|
66
68
|
>
|
|
@@ -75,8 +77,8 @@ export const CourseTreePanel = forwardRef<SearchFilterHandle>((_, ref) => {
|
|
|
75
77
|
variant="ghost"
|
|
76
78
|
size="icon"
|
|
77
79
|
className="size-8 shrink-0"
|
|
78
|
-
title=
|
|
79
|
-
aria-label=
|
|
80
|
+
title={t('tree.addSession')}
|
|
81
|
+
aria-label={t('tree.addSession')}
|
|
80
82
|
disabled={createSession.isPending}
|
|
81
83
|
onClick={() => createSession.mutate()}
|
|
82
84
|
>
|
|
@@ -92,8 +94,8 @@ export const CourseTreePanel = forwardRef<SearchFilterHandle>((_, ref) => {
|
|
|
92
94
|
{isFiltering && resultCount !== undefined && (
|
|
93
95
|
<div className="px-3 py-1 text-[0.65rem] text-muted-foreground bg-muted/30 border-b shrink-0">
|
|
94
96
|
{resultCount === 0
|
|
95
|
-
? '
|
|
96
|
-
:
|
|
97
|
+
? t('search.noResults')
|
|
98
|
+
: t('search.results', { count: resultCount })}
|
|
97
99
|
</div>
|
|
98
100
|
)}
|
|
99
101
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Skeleton } from '@/components/ui/skeleton';
|
|
2
|
+
import { useTranslations } from 'next-intl';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* CourseTreeSkeleton
|
|
@@ -7,11 +8,12 @@ import { Skeleton } from '@/components/ui/skeleton';
|
|
|
7
8
|
* the API. Mimics the visual shape of session headers and lesson rows.
|
|
8
9
|
*/
|
|
9
10
|
export function CourseTreeSkeleton() {
|
|
11
|
+
const t = useTranslations('lms.CoursesPage.StructurePage');
|
|
10
12
|
return (
|
|
11
13
|
<div
|
|
12
14
|
className="flex flex-col gap-1 p-3"
|
|
13
15
|
aria-busy="true"
|
|
14
|
-
aria-label=
|
|
16
|
+
aria-label={t('loading')}
|
|
15
17
|
>
|
|
16
18
|
{/* Course header row */}
|
|
17
19
|
<div className="flex items-center gap-2 px-2 py-1.5">
|
|
@@ -4,6 +4,7 @@ import { cn } from '@/lib/utils';
|
|
|
4
4
|
import type { DraggableAttributes } from '@dnd-kit/core';
|
|
5
5
|
import type { SyntheticListenerMap } from '@dnd-kit/core/dist/hooks/utilities';
|
|
6
6
|
import { GripVertical } from 'lucide-react';
|
|
7
|
+
import { useTranslations } from 'next-intl';
|
|
7
8
|
|
|
8
9
|
interface DragHandleProps {
|
|
9
10
|
listeners?: SyntheticListenerMap;
|
|
@@ -23,6 +24,7 @@ export function DragHandle({
|
|
|
23
24
|
disabled,
|
|
24
25
|
className,
|
|
25
26
|
}: DragHandleProps) {
|
|
27
|
+
const t = useTranslations('lms.CoursesPage.StructurePage.dragHandle');
|
|
26
28
|
if (disabled) {
|
|
27
29
|
return (
|
|
28
30
|
<span
|
|
@@ -30,7 +32,7 @@ export function DragHandle({
|
|
|
30
32
|
'shrink-0 size-5 flex items-center justify-center opacity-20 cursor-not-allowed',
|
|
31
33
|
className
|
|
32
34
|
)}
|
|
33
|
-
title=
|
|
35
|
+
title={t('disabled')}
|
|
34
36
|
>
|
|
35
37
|
<GripVertical className="size-3.5" />
|
|
36
38
|
</span>
|
|
@@ -48,7 +50,7 @@ export function DragHandle({
|
|
|
48
50
|
'transition-colors touch-none',
|
|
49
51
|
className
|
|
50
52
|
)}
|
|
51
|
-
title=
|
|
53
|
+
title={t('enabled')}
|
|
52
54
|
// Prevent click events from bubbling to the row selection handler
|
|
53
55
|
onClick={(e) => e.stopPropagation()}
|
|
54
56
|
>
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
Video,
|
|
11
11
|
X,
|
|
12
12
|
} from 'lucide-react';
|
|
13
|
+
import { useTranslations } from 'next-intl';
|
|
13
14
|
import { useState } from 'react';
|
|
14
15
|
import { toast } from 'sonner';
|
|
15
16
|
|
|
@@ -43,6 +44,7 @@ const STATUS_LABELS: Record<LessonStatus, string> = {
|
|
|
43
44
|
// ── Component ─────────────────────────────────────────────────────────────────
|
|
44
45
|
|
|
45
46
|
export function EditorBulk() {
|
|
47
|
+
const t = useTranslations('lms.CoursesPage.StructurePage.bulkEditor');
|
|
46
48
|
const selectedIds = useStructureStore((s) => s.selectedIds);
|
|
47
49
|
const sessions = useStructureStore((s) => s.sessions);
|
|
48
50
|
const lessons = useStructureStore((s) => s.lessons);
|
|
@@ -74,8 +76,8 @@ export function EditorBulk() {
|
|
|
74
76
|
);
|
|
75
77
|
toast.success(
|
|
76
78
|
lines.length
|
|
77
|
-
?
|
|
78
|
-
: '
|
|
79
|
+
? t('toast.preview', { changes: lines.join(', ') })
|
|
80
|
+
: t('toast.none')
|
|
79
81
|
);
|
|
80
82
|
}
|
|
81
83
|
|
|
@@ -93,11 +95,11 @@ export function EditorBulk() {
|
|
|
93
95
|
)}
|
|
94
96
|
</div>
|
|
95
97
|
<div className="flex-1 min-w-0">
|
|
96
|
-
<p className="text-sm font-semibold">
|
|
98
|
+
<p className="text-sm font-semibold">{t('title')}</p>
|
|
97
99
|
<p className="text-[0.65rem] text-muted-foreground">
|
|
98
100
|
{selectedIds.size}{' '}
|
|
99
|
-
{allLessons ? '
|
|
100
|
-
|
|
101
|
+
{allLessons ? t('types.lessons') : allSessions ? t('types.sessions') : t('types.items')}{' '}
|
|
102
|
+
{t('types.selected')}
|
|
101
103
|
</p>
|
|
102
104
|
</div>
|
|
103
105
|
<Button
|
|
@@ -105,7 +107,7 @@ export function EditorBulk() {
|
|
|
105
107
|
size="icon"
|
|
106
108
|
className="size-7 shrink-0"
|
|
107
109
|
onClick={clearSelection}
|
|
108
|
-
title=
|
|
110
|
+
title={t('clearSelection')}
|
|
109
111
|
>
|
|
110
112
|
<X className="size-3.5" />
|
|
111
113
|
</Button>
|
|
@@ -148,7 +150,7 @@ export function EditorBulk() {
|
|
|
148
150
|
<Card>
|
|
149
151
|
<CardHeader className="px-3 pt-3 pb-2">
|
|
150
152
|
<CardTitle className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
|
151
|
-
|
|
153
|
+
{t('productionStatus')}
|
|
152
154
|
</CardTitle>
|
|
153
155
|
</CardHeader>
|
|
154
156
|
<CardContent className="px-3 pb-3">
|
|
@@ -157,14 +159,14 @@ export function EditorBulk() {
|
|
|
157
159
|
onValueChange={(v) => setStatus(v as LessonStatus)}
|
|
158
160
|
>
|
|
159
161
|
<SelectTrigger className="h-8 text-xs w-full">
|
|
160
|
-
<SelectValue placeholder=
|
|
162
|
+
<SelectValue placeholder={t('keepCurrent')} />
|
|
161
163
|
</SelectTrigger>
|
|
162
164
|
<SelectContent>
|
|
163
|
-
<SelectItem value="preparada">
|
|
164
|
-
<SelectItem value="gravada">
|
|
165
|
-
<SelectItem value="editada">
|
|
166
|
-
<SelectItem value="finalizada">
|
|
167
|
-
<SelectItem value="publicada">
|
|
165
|
+
<SelectItem value="preparada">{t('status.preparada')}</SelectItem>
|
|
166
|
+
<SelectItem value="gravada">{t('status.gravada')}</SelectItem>
|
|
167
|
+
<SelectItem value="editada">{t('status.editada')}</SelectItem>
|
|
168
|
+
<SelectItem value="finalizada">{t('status.finalizada')}</SelectItem>
|
|
169
|
+
<SelectItem value="publicada">{t('status.publicada')}</SelectItem>
|
|
168
170
|
</SelectContent>
|
|
169
171
|
</Select>
|
|
170
172
|
</CardContent>
|
|
@@ -175,7 +177,7 @@ export function EditorBulk() {
|
|
|
175
177
|
<Card>
|
|
176
178
|
<CardHeader className="px-3 pt-3 pb-2">
|
|
177
179
|
<CardTitle className="text-xs font-medium text-muted-foreground uppercase tracking-wider">
|
|
178
|
-
|
|
180
|
+
{t('visibilityTitle')}
|
|
179
181
|
</CardTitle>
|
|
180
182
|
</CardHeader>
|
|
181
183
|
<CardContent className="px-3 pb-3">
|
|
@@ -184,22 +186,22 @@ export function EditorBulk() {
|
|
|
184
186
|
onValueChange={(v) => setVisibility(v as Visibility)}
|
|
185
187
|
>
|
|
186
188
|
<SelectTrigger className="h-8 text-xs w-full">
|
|
187
|
-
<SelectValue placeholder=
|
|
189
|
+
<SelectValue placeholder={t('keepCurrent')} />
|
|
188
190
|
</SelectTrigger>
|
|
189
191
|
<SelectContent>
|
|
190
192
|
<SelectItem value="publico">
|
|
191
193
|
<span className="flex items-center gap-1.5">
|
|
192
|
-
<Eye className="size-3" />
|
|
194
|
+
<Eye className="size-3" /> {t('visibility.publico')}
|
|
193
195
|
</span>
|
|
194
196
|
</SelectItem>
|
|
195
197
|
<SelectItem value="privado">
|
|
196
198
|
<span className="flex items-center gap-1.5">
|
|
197
|
-
<EyeOff className="size-3" />
|
|
199
|
+
<EyeOff className="size-3" /> {t('visibility.privado')}
|
|
198
200
|
</span>
|
|
199
201
|
</SelectItem>
|
|
200
202
|
<SelectItem value="restrito">
|
|
201
203
|
<span className="flex items-center gap-1.5">
|
|
202
|
-
<Lock className="size-3" />
|
|
204
|
+
<Lock className="size-3" /> {t('visibility.restrito')}
|
|
203
205
|
</span>
|
|
204
206
|
</SelectItem>
|
|
205
207
|
</SelectContent>
|
|
@@ -213,13 +215,13 @@ export function EditorBulk() {
|
|
|
213
215
|
<CardHeader className="px-3 pt-3 pb-2">
|
|
214
216
|
<CardTitle className="text-xs font-medium text-muted-foreground uppercase tracking-wider flex items-center gap-1.5">
|
|
215
217
|
<FolderInput className="size-3" />
|
|
216
|
-
|
|
218
|
+
{t('moveToSession')}
|
|
217
219
|
</CardTitle>
|
|
218
220
|
</CardHeader>
|
|
219
221
|
<CardContent className="px-3 pb-3">
|
|
220
222
|
<Select value={targetSession} onValueChange={setTargetSession}>
|
|
221
223
|
<SelectTrigger className="h-8 text-xs w-full">
|
|
222
|
-
<SelectValue placeholder=
|
|
224
|
+
<SelectValue placeholder={t('selectSession')} />
|
|
223
225
|
</SelectTrigger>
|
|
224
226
|
<SelectContent>
|
|
225
227
|
{sessions.map((s) => (
|
|
@@ -238,8 +240,7 @@ export function EditorBulk() {
|
|
|
238
240
|
|
|
239
241
|
<div className="rounded-md border border-amber-200 bg-amber-50/60 dark:border-amber-800 dark:bg-amber-950/30 px-3 py-2">
|
|
240
242
|
<p className="text-[0.65rem] text-amber-700 dark:text-amber-400">
|
|
241
|
-
|
|
242
|
-
Clique em salvar para ver a pré-visualização.
|
|
243
|
+
{t('apiNotice')}
|
|
243
244
|
</p>
|
|
244
245
|
</div>
|
|
245
246
|
</div>
|
|
@@ -257,7 +258,7 @@ export function EditorBulk() {
|
|
|
257
258
|
onClick={clearSelection}
|
|
258
259
|
>
|
|
259
260
|
<X className="size-3 mr-1" />
|
|
260
|
-
|
|
261
|
+
{t('clearSelection')}
|
|
261
262
|
</Button>
|
|
262
263
|
<div className="flex-1" />
|
|
263
264
|
<Button
|