@hed-hog/lms 0.0.329 → 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.
- package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +18 -8
- package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +7 -5
- 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/classes/[id]/page.tsx.ejs +10 -10
- package/hedhog/frontend/app/classes/page.tsx.ejs +23 -15
- package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +5 -3
- package/hedhog/frontend/app/courses/[id]/structure/_components/confirm-dialog.tsx.ejs +5 -3
- 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/multi-select-bar.tsx.ejs +21 -19
- package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +7 -5
- 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/_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/instructor-skills/page.tsx.ejs +79 -59
- package/hedhog/frontend/app/instructors/page.tsx.ejs +4 -2
- package/hedhog/frontend/messages/en.json +619 -13
- package/hedhog/frontend/messages/pt.json +619 -13
- package/package.json +7 -7
package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
24
|
+
import { useTranslations } from 'next-intl';
|
|
24
25
|
import { toast } from 'sonner';
|
|
25
26
|
|
|
26
27
|
import { useApp } from '@hed-hog/next-app-provider';
|
|
@@ -73,6 +74,7 @@ interface UpdateCourseVars {
|
|
|
73
74
|
* cache entry so the header immediately reflects the new title/slug.
|
|
74
75
|
*/
|
|
75
76
|
export function useUpdateCourseMutation() {
|
|
77
|
+
const t = useTranslations('lms.courseStructure');
|
|
76
78
|
const { request } = useApp();
|
|
77
79
|
const queryClient = useQueryClient();
|
|
78
80
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -106,13 +108,13 @@ export function useUpdateCourseMutation() {
|
|
|
106
108
|
},
|
|
107
109
|
};
|
|
108
110
|
});
|
|
109
|
-
toast.success('
|
|
111
|
+
toast.success(t('mutations.course.saveSuccess'));
|
|
110
112
|
},
|
|
111
113
|
onError: () => {
|
|
112
114
|
void queryClient.invalidateQueries({
|
|
113
115
|
queryKey: courseStructureQueryKey(courseId),
|
|
114
116
|
});
|
|
115
|
-
toast.error('
|
|
117
|
+
toast.error(t('mutations.course.saveError'));
|
|
116
118
|
},
|
|
117
119
|
});
|
|
118
120
|
}
|
|
@@ -128,6 +130,7 @@ export function useUpdateCourseMutation() {
|
|
|
128
130
|
* The newly created session becomes the active/selected item.
|
|
129
131
|
*/
|
|
130
132
|
export function useCreateSessionMutation() {
|
|
133
|
+
const t = useTranslations('lms.courseStructure');
|
|
131
134
|
const { request } = useApp();
|
|
132
135
|
const queryClient = useQueryClient();
|
|
133
136
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -153,13 +156,13 @@ export function useCreateSessionMutation() {
|
|
|
153
156
|
void queryClient.invalidateQueries({
|
|
154
157
|
queryKey: courseStructureQueryKey(courseId),
|
|
155
158
|
});
|
|
156
|
-
toast.success('
|
|
159
|
+
toast.success(t('mutations.session.createSuccess'));
|
|
157
160
|
},
|
|
158
161
|
onError: () => {
|
|
159
162
|
void queryClient.invalidateQueries({
|
|
160
163
|
queryKey: courseStructureQueryKey(courseId),
|
|
161
164
|
});
|
|
162
|
-
toast.error('
|
|
165
|
+
toast.error(t('mutations.session.createError'));
|
|
163
166
|
},
|
|
164
167
|
});
|
|
165
168
|
}
|
|
@@ -179,6 +182,7 @@ interface UpdateSessionVars {
|
|
|
179
182
|
* Persists the form values and updates the store on success.
|
|
180
183
|
*/
|
|
181
184
|
export function useUpdateSessionMutation() {
|
|
185
|
+
const t = useTranslations('lms.courseStructure');
|
|
182
186
|
const { request } = useApp();
|
|
183
187
|
const queryClient = useQueryClient();
|
|
184
188
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -214,14 +218,14 @@ export function useUpdateSessionMutation() {
|
|
|
214
218
|
};
|
|
215
219
|
}
|
|
216
220
|
);
|
|
217
|
-
toast.success('
|
|
221
|
+
toast.success(t('mutations.session.saveSuccess'));
|
|
218
222
|
},
|
|
219
223
|
onError: () => {
|
|
220
224
|
// Fall back to server truth
|
|
221
225
|
void queryClient.invalidateQueries({
|
|
222
226
|
queryKey: courseStructureQueryKey(courseId),
|
|
223
227
|
});
|
|
224
|
-
toast.error('
|
|
228
|
+
toast.error(t('mutations.session.saveError'));
|
|
225
229
|
},
|
|
226
230
|
});
|
|
227
231
|
}
|
|
@@ -241,6 +245,7 @@ interface CreateLessonVars {
|
|
|
241
245
|
* The newly created lesson becomes the active/selected item.
|
|
242
246
|
*/
|
|
243
247
|
export function useCreateLessonMutation() {
|
|
248
|
+
const t = useTranslations('lms.courseStructure');
|
|
244
249
|
const { request } = useApp();
|
|
245
250
|
const queryClient = useQueryClient();
|
|
246
251
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -271,13 +276,13 @@ export function useCreateLessonMutation() {
|
|
|
271
276
|
void queryClient.invalidateQueries({
|
|
272
277
|
queryKey: courseStructureQueryKey(courseId),
|
|
273
278
|
});
|
|
274
|
-
toast.success('
|
|
279
|
+
toast.success(t('mutations.lesson.createSuccess'));
|
|
275
280
|
},
|
|
276
281
|
onError: () => {
|
|
277
282
|
void queryClient.invalidateQueries({
|
|
278
283
|
queryKey: courseStructureQueryKey(courseId),
|
|
279
284
|
});
|
|
280
|
-
toast.error('
|
|
285
|
+
toast.error(t('mutations.lesson.createError'));
|
|
281
286
|
},
|
|
282
287
|
});
|
|
283
288
|
}
|
|
@@ -304,6 +309,7 @@ interface UpdateLessonVars {
|
|
|
304
309
|
* Persists the form values and updates the store on success.
|
|
305
310
|
*/
|
|
306
311
|
export function useUpdateLessonMutation() {
|
|
312
|
+
const t = useTranslations('lms.courseStructure');
|
|
307
313
|
const { request } = useApp();
|
|
308
314
|
const queryClient = useQueryClient();
|
|
309
315
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -340,13 +346,13 @@ export function useUpdateLessonMutation() {
|
|
|
340
346
|
};
|
|
341
347
|
}
|
|
342
348
|
);
|
|
343
|
-
toast.success('
|
|
349
|
+
toast.success(t('mutations.lesson.saveSuccess'));
|
|
344
350
|
},
|
|
345
351
|
onError: () => {
|
|
346
352
|
void queryClient.invalidateQueries({
|
|
347
353
|
queryKey: courseStructureQueryKey(courseId),
|
|
348
354
|
});
|
|
349
|
-
toast.error('
|
|
355
|
+
toast.error(t('mutations.lesson.saveError'));
|
|
350
356
|
},
|
|
351
357
|
});
|
|
352
358
|
}
|
|
@@ -366,6 +372,7 @@ interface DeleteSessionVars {
|
|
|
366
372
|
* from the Zustand store. Selection is reset to the course root.
|
|
367
373
|
*/
|
|
368
374
|
export function useDeleteSessionMutation() {
|
|
375
|
+
const t = useTranslations('lms.courseStructure');
|
|
369
376
|
const { request } = useApp();
|
|
370
377
|
const queryClient = useQueryClient();
|
|
371
378
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -389,13 +396,13 @@ export function useDeleteSessionMutation() {
|
|
|
389
396
|
};
|
|
390
397
|
}
|
|
391
398
|
);
|
|
392
|
-
toast.success('
|
|
399
|
+
toast.success(t('mutations.session.deleteSuccess'));
|
|
393
400
|
},
|
|
394
401
|
onError: () => {
|
|
395
402
|
void queryClient.invalidateQueries({
|
|
396
403
|
queryKey: courseStructureQueryKey(courseId),
|
|
397
404
|
});
|
|
398
|
-
toast.error('
|
|
405
|
+
toast.error(t('mutations.session.deleteError'));
|
|
399
406
|
},
|
|
400
407
|
});
|
|
401
408
|
}
|
|
@@ -415,6 +422,7 @@ interface DeleteLessonVars {
|
|
|
415
422
|
* Deletes a lesson and removes it from the Zustand store.
|
|
416
423
|
*/
|
|
417
424
|
export function useDeleteLessonMutation() {
|
|
425
|
+
const t = useTranslations('lms.courseStructure');
|
|
418
426
|
const { request } = useApp();
|
|
419
427
|
const queryClient = useQueryClient();
|
|
420
428
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -433,13 +441,13 @@ export function useDeleteLessonMutation() {
|
|
|
433
441
|
? { ...old, lessons: old.lessons.filter((l) => l.id !== lid) }
|
|
434
442
|
: old
|
|
435
443
|
);
|
|
436
|
-
toast.success('
|
|
444
|
+
toast.success(t('mutations.lesson.deleteSuccess'));
|
|
437
445
|
},
|
|
438
446
|
onError: () => {
|
|
439
447
|
void queryClient.invalidateQueries({
|
|
440
448
|
queryKey: courseStructureQueryKey(courseId),
|
|
441
449
|
});
|
|
442
|
-
toast.error('
|
|
450
|
+
toast.error(t('mutations.lesson.deleteError'));
|
|
443
451
|
},
|
|
444
452
|
});
|
|
445
453
|
}
|
|
@@ -466,6 +474,7 @@ interface BulkDeleteVars {
|
|
|
466
474
|
* 5. Show partial-error toast when some items fail.
|
|
467
475
|
*/
|
|
468
476
|
export function useBulkDeleteMutation() {
|
|
477
|
+
const t = useTranslations('lms.courseStructure');
|
|
469
478
|
const { request } = useApp();
|
|
470
479
|
const queryClient = useQueryClient();
|
|
471
480
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -538,7 +547,7 @@ export function useBulkDeleteMutation() {
|
|
|
538
547
|
void queryClient.invalidateQueries({
|
|
539
548
|
queryKey: courseStructureQueryKey(courseId),
|
|
540
549
|
});
|
|
541
|
-
toast.error('
|
|
550
|
+
toast.error(t('mutations.item.deleteError'));
|
|
542
551
|
},
|
|
543
552
|
});
|
|
544
553
|
}
|
|
@@ -561,6 +570,7 @@ interface ReorderSessionsVars {
|
|
|
561
570
|
* On error: rolls back via setStructureFromApi with the previous snapshot.
|
|
562
571
|
*/
|
|
563
572
|
export function useReorderSessionsMutation() {
|
|
573
|
+
const t = useTranslations('lms.courseStructure');
|
|
564
574
|
const { request } = useApp();
|
|
565
575
|
const queryClient = useQueryClient();
|
|
566
576
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -600,7 +610,7 @@ export function useReorderSessionsMutation() {
|
|
|
600
610
|
if (context?.previousCache) {
|
|
601
611
|
queryClient.setQueryData(qKey, context.previousCache);
|
|
602
612
|
}
|
|
603
|
-
toast.error('
|
|
613
|
+
toast.error(t('mutations.session.reorderError'));
|
|
604
614
|
},
|
|
605
615
|
});
|
|
606
616
|
}
|
|
@@ -624,6 +634,7 @@ interface ReorderLessonsVars {
|
|
|
624
634
|
* On error: rolls back via setStructureFromApi with the previous snapshot.
|
|
625
635
|
*/
|
|
626
636
|
export function useReorderLessonsMutation() {
|
|
637
|
+
const t = useTranslations('lms.courseStructure');
|
|
627
638
|
const { request } = useApp();
|
|
628
639
|
const queryClient = useQueryClient();
|
|
629
640
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -662,7 +673,7 @@ export function useReorderLessonsMutation() {
|
|
|
662
673
|
if (context?.previousCache) {
|
|
663
674
|
queryClient.setQueryData(qKey, context.previousCache);
|
|
664
675
|
}
|
|
665
|
-
toast.error('
|
|
676
|
+
toast.error(t('mutations.lesson.reorderError'));
|
|
666
677
|
},
|
|
667
678
|
});
|
|
668
679
|
}
|
|
@@ -687,6 +698,7 @@ interface MoveLessonVars {
|
|
|
687
698
|
* On error: rolls back via setStructureFromApi with the previous snapshot.
|
|
688
699
|
*/
|
|
689
700
|
export function useMoveLessonMutation() {
|
|
701
|
+
const t = useTranslations('lms.courseStructure');
|
|
690
702
|
const { request } = useApp();
|
|
691
703
|
const queryClient = useQueryClient();
|
|
692
704
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -729,7 +741,7 @@ export function useMoveLessonMutation() {
|
|
|
729
741
|
if (context?.previousCache) {
|
|
730
742
|
queryClient.setQueryData(qKey, context.previousCache);
|
|
731
743
|
}
|
|
732
|
-
toast.error('
|
|
744
|
+
toast.error(t('mutations.lesson.moveError'));
|
|
733
745
|
},
|
|
734
746
|
});
|
|
735
747
|
}
|
|
@@ -745,6 +757,7 @@ export function useMoveLessonMutation() {
|
|
|
745
757
|
* Non-optimistic: waits for API then adds real items to store.
|
|
746
758
|
*/
|
|
747
759
|
export function useDuplicateSessionMutation() {
|
|
760
|
+
const t = useTranslations('lms.courseStructure');
|
|
748
761
|
const { request } = useApp();
|
|
749
762
|
const queryClient = useQueryClient();
|
|
750
763
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -763,13 +776,13 @@ export function useDuplicateSessionMutation() {
|
|
|
763
776
|
void queryClient.invalidateQueries({
|
|
764
777
|
queryKey: courseStructureQueryKey(courseId),
|
|
765
778
|
});
|
|
766
|
-
toast.success(
|
|
779
|
+
toast.success(t('mutations.session.duplicateSuccess'));
|
|
767
780
|
},
|
|
768
781
|
onError: () => {
|
|
769
782
|
void queryClient.invalidateQueries({
|
|
770
783
|
queryKey: courseStructureQueryKey(courseId),
|
|
771
784
|
});
|
|
772
|
-
toast.error('
|
|
785
|
+
toast.error(t('mutations.session.duplicateError'));
|
|
773
786
|
},
|
|
774
787
|
});
|
|
775
788
|
}
|
|
@@ -785,6 +798,7 @@ export function useDuplicateSessionMutation() {
|
|
|
785
798
|
* Non-optimistic: waits for API then adds the real item to store.
|
|
786
799
|
*/
|
|
787
800
|
export function useDuplicateLessonMutation() {
|
|
801
|
+
const t = useTranslations('lms.courseStructure');
|
|
788
802
|
const { request } = useApp();
|
|
789
803
|
const queryClient = useQueryClient();
|
|
790
804
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -805,13 +819,13 @@ export function useDuplicateLessonMutation() {
|
|
|
805
819
|
void queryClient.invalidateQueries({
|
|
806
820
|
queryKey: courseStructureQueryKey(courseId),
|
|
807
821
|
});
|
|
808
|
-
toast.success('
|
|
822
|
+
toast.success(t('mutations.lesson.duplicateSuccess'));
|
|
809
823
|
},
|
|
810
824
|
onError: () => {
|
|
811
825
|
void queryClient.invalidateQueries({
|
|
812
826
|
queryKey: courseStructureQueryKey(courseId),
|
|
813
827
|
});
|
|
814
|
-
toast.error('
|
|
828
|
+
toast.error(t('mutations.lesson.duplicateError'));
|
|
815
829
|
},
|
|
816
830
|
});
|
|
817
831
|
}
|
|
@@ -827,6 +841,7 @@ export function useDuplicateLessonMutation() {
|
|
|
827
841
|
* Non-optimistic: waits for API then adds the new items to store.
|
|
828
842
|
*/
|
|
829
843
|
export function usePasteLessonsMutation() {
|
|
844
|
+
const t = useTranslations('lms.courseStructure');
|
|
830
845
|
const { request } = useApp();
|
|
831
846
|
const queryClient = useQueryClient();
|
|
832
847
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -864,7 +879,7 @@ export function usePasteLessonsMutation() {
|
|
|
864
879
|
void queryClient.invalidateQueries({
|
|
865
880
|
queryKey: courseStructureQueryKey(courseId),
|
|
866
881
|
});
|
|
867
|
-
toast.error('
|
|
882
|
+
toast.error(t('mutations.lesson.pasteError'));
|
|
868
883
|
},
|
|
869
884
|
});
|
|
870
885
|
}
|
|
@@ -880,6 +895,7 @@ export function usePasteLessonsMutation() {
|
|
|
880
895
|
* Non-optimistic: fires duplicate requests serially, then adds all results.
|
|
881
896
|
*/
|
|
882
897
|
export function usePasteSessionsMutation() {
|
|
898
|
+
const t = useTranslations('lms.courseStructure');
|
|
883
899
|
const { request } = useApp();
|
|
884
900
|
const queryClient = useQueryClient();
|
|
885
901
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -914,7 +930,7 @@ export function usePasteSessionsMutation() {
|
|
|
914
930
|
void queryClient.invalidateQueries({
|
|
915
931
|
queryKey: courseStructureQueryKey(courseId),
|
|
916
932
|
});
|
|
917
|
-
toast.error('
|
|
933
|
+
toast.error(t('mutations.session.pasteError'));
|
|
918
934
|
},
|
|
919
935
|
});
|
|
920
936
|
}
|
|
@@ -929,6 +945,7 @@ export function usePasteSessionsMutation() {
|
|
|
929
945
|
* On error: rolls back store to snapshot.
|
|
930
946
|
*/
|
|
931
947
|
export function useMoveLessonsMutation() {
|
|
948
|
+
const t = useTranslations('lms.courseStructure');
|
|
932
949
|
const { request } = useApp();
|
|
933
950
|
const queryClient = useQueryClient();
|
|
934
951
|
const courseId = useStructureStore((s) => s.courseId);
|
|
@@ -981,7 +998,7 @@ export function useMoveLessonsMutation() {
|
|
|
981
998
|
if (context?.previousCache) {
|
|
982
999
|
queryClient.setQueryData(qKey, context.previousCache);
|
|
983
1000
|
}
|
|
984
|
-
toast.error('
|
|
1001
|
+
toast.error(t('mutations.lesson.moveBatchError'));
|
|
985
1002
|
},
|
|
986
1003
|
});
|
|
987
1004
|
}
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
import { useApp } from '@hed-hog/next-app-provider';
|
|
30
30
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
31
31
|
import { Eye, EyeOff, Loader2, RefreshCw } from 'lucide-react';
|
|
32
|
+
import { useTranslations } from 'next-intl';
|
|
32
33
|
import { useEffect, useState } from 'react';
|
|
33
34
|
import { useForm } from 'react-hook-form';
|
|
34
35
|
import { toast } from 'sonner';
|
|
@@ -95,6 +96,7 @@ export function EnterpriseAdminCreateSheet({
|
|
|
95
96
|
onOpenChange,
|
|
96
97
|
onCreated,
|
|
97
98
|
}: EnterpriseAdminCreateSheetProps) {
|
|
99
|
+
const t = useTranslations('lms.EnterprisePage');
|
|
98
100
|
const { request } = useApp();
|
|
99
101
|
const [saving, setSaving] = useState(false);
|
|
100
102
|
const [showPassword, setShowPassword] = useState(false);
|
|
@@ -154,7 +156,7 @@ export function EnterpriseAdminCreateSheet({
|
|
|
154
156
|
onCreated?.(newUser);
|
|
155
157
|
handleOpenChange(false);
|
|
156
158
|
} catch {
|
|
157
|
-
toast.error('
|
|
159
|
+
toast.error(t('sheet.adminCreated'));
|
|
158
160
|
} finally {
|
|
159
161
|
setSaving(false);
|
|
160
162
|
}
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
} from '@/components/ui/table';
|
|
22
22
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
23
23
|
import { Trash2 } from 'lucide-react';
|
|
24
|
+
import { useTranslations } from 'next-intl';
|
|
24
25
|
import { useCallback, useState } from 'react';
|
|
25
26
|
import { toast } from 'sonner';
|
|
26
27
|
import { EnterpriseAdminCreateSheet } from './enterprise-admin-create-sheet';
|
|
@@ -52,6 +53,7 @@ export function AdministratorsTab({
|
|
|
52
53
|
enterpriseId: number;
|
|
53
54
|
onMutate?: () => void;
|
|
54
55
|
}) {
|
|
56
|
+
const t = useTranslations('lms.EnterprisePage');
|
|
55
57
|
const { request } = useApp();
|
|
56
58
|
const [search, setSearch] = useState('');
|
|
57
59
|
const [page, setPage] = useState(1);
|
|
@@ -104,9 +106,9 @@ export function AdministratorsTab({
|
|
|
104
106
|
data: { role },
|
|
105
107
|
}).then(() => refetch());
|
|
106
108
|
toast.promise(promise, {
|
|
107
|
-
loading: '
|
|
108
|
-
success: '
|
|
109
|
-
error: '
|
|
109
|
+
loading: t('sheet.adminRoleUpdating'),
|
|
110
|
+
success: t('sheet.adminRoleUpdated'),
|
|
111
|
+
error: t('sheet.adminRoleUpdateError'),
|
|
110
112
|
});
|
|
111
113
|
try {
|
|
112
114
|
await promise;
|
|
@@ -127,9 +129,9 @@ export function AdministratorsTab({
|
|
|
127
129
|
onMutate?.();
|
|
128
130
|
});
|
|
129
131
|
toast.promise(promise, {
|
|
130
|
-
loading: '
|
|
131
|
-
success: '
|
|
132
|
-
error: '
|
|
132
|
+
loading: t('sheet.adminRemoving'),
|
|
133
|
+
success: t('sheet.adminRemoved'),
|
|
134
|
+
error: t('sheet.adminRemoveError'),
|
|
133
135
|
});
|
|
134
136
|
try {
|
|
135
137
|
await promise;
|
|
@@ -153,7 +155,7 @@ export function AdministratorsTab({
|
|
|
153
155
|
refetch();
|
|
154
156
|
onMutate?.();
|
|
155
157
|
} catch {
|
|
156
|
-
toast.error('
|
|
158
|
+
toast.error(t('sheet.adminAddError'));
|
|
157
159
|
}
|
|
158
160
|
}
|
|
159
161
|
|
|
@@ -320,7 +322,7 @@ export function AdministratorsTab({
|
|
|
320
322
|
data: { user_id: user.userId, role: user.role },
|
|
321
323
|
});
|
|
322
324
|
} catch {
|
|
323
|
-
toast.error('
|
|
325
|
+
toast.error(t('sheet.adminLinkError'));
|
|
324
326
|
}
|
|
325
327
|
setCreateSheetOpen(false);
|
|
326
328
|
refetch();
|
|
@@ -22,6 +22,7 @@ import { formatDate } from '@/lib/format-date';
|
|
|
22
22
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
23
23
|
import { CalendarDays, SquareArrowOutUpRight, Trash2 } from 'lucide-react';
|
|
24
24
|
import { useRouter } from 'next/navigation';
|
|
25
|
+
import { useTranslations } from 'next-intl';
|
|
25
26
|
import { useCallback, useState } from 'react';
|
|
26
27
|
import { toast } from 'sonner';
|
|
27
28
|
import { EnterpriseClassCreateSheet } from './enterprise-class-create-sheet';
|
|
@@ -93,6 +94,7 @@ export function ClassesTab({
|
|
|
93
94
|
}) {
|
|
94
95
|
const router = useRouter();
|
|
95
96
|
const { request, currentLocaleCode, getSettingValue } = useApp();
|
|
97
|
+
const t = useTranslations('lms.EnterpriseDetailPage.relatedClasses');
|
|
96
98
|
|
|
97
99
|
const [search, setSearch] = useState('');
|
|
98
100
|
const [statusFilter, setStatusFilter] = useState<
|
|
@@ -144,11 +146,11 @@ export function ClassesTab({
|
|
|
144
146
|
url: `/lms/enterprise/${enterpriseId}/classes/${classGroupId}`,
|
|
145
147
|
method: 'DELETE',
|
|
146
148
|
});
|
|
147
|
-
toast.success('
|
|
149
|
+
toast.success(t('messages.removeSuccess'));
|
|
148
150
|
refetch();
|
|
149
151
|
onMutate?.();
|
|
150
152
|
} catch {
|
|
151
|
-
toast.error('
|
|
153
|
+
toast.error(t('messages.removeError'));
|
|
152
154
|
}
|
|
153
155
|
}
|
|
154
156
|
|
|
@@ -168,7 +170,7 @@ export function ClassesTab({
|
|
|
168
170
|
refetch();
|
|
169
171
|
onMutate?.();
|
|
170
172
|
} catch {
|
|
171
|
-
toast.error('
|
|
173
|
+
toast.error(t('messages.addError'));
|
|
172
174
|
}
|
|
173
175
|
}
|
|
174
176
|
|
|
@@ -180,7 +182,7 @@ export function ClassesTab({
|
|
|
180
182
|
setSearch(v);
|
|
181
183
|
setPage(1);
|
|
182
184
|
}}
|
|
183
|
-
searchPlaceholder=
|
|
185
|
+
searchPlaceholder={t('searchPlaceholder')}
|
|
184
186
|
filters={
|
|
185
187
|
<Select
|
|
186
188
|
value={statusFilter}
|
|
@@ -190,19 +192,19 @@ export function ClassesTab({
|
|
|
190
192
|
}}
|
|
191
193
|
>
|
|
192
194
|
<SelectTrigger className="w-44">
|
|
193
|
-
<SelectValue placeholder=
|
|
195
|
+
<SelectValue placeholder={t('filters.allStatuses')} />
|
|
194
196
|
</SelectTrigger>
|
|
195
197
|
<SelectContent>
|
|
196
|
-
<SelectItem value="all">
|
|
197
|
-
<SelectItem value="open">
|
|
198
|
-
<SelectItem value="ongoing">
|
|
199
|
-
<SelectItem value="completed">
|
|
200
|
-
<SelectItem value="cancelled">
|
|
198
|
+
<SelectItem value="all">{t('filters.allStatuses')}</SelectItem>
|
|
199
|
+
<SelectItem value="open">{t('status.open')}</SelectItem>
|
|
200
|
+
<SelectItem value="ongoing">{t('status.ongoing')}</SelectItem>
|
|
201
|
+
<SelectItem value="completed">{t('status.completed')}</SelectItem>
|
|
202
|
+
<SelectItem value="cancelled">{t('status.cancelled')}</SelectItem>
|
|
201
203
|
</SelectContent>
|
|
202
204
|
</Select>
|
|
203
205
|
}
|
|
204
|
-
pickerPlaceholder=
|
|
205
|
-
pickerEntityLabel=
|
|
206
|
+
pickerPlaceholder={t('pickerPlaceholder')}
|
|
207
|
+
pickerEntityLabel={t('pickerEntityLabel')}
|
|
206
208
|
pickerValue={pickerValue}
|
|
207
209
|
onPickerChange={(value, option) => {
|
|
208
210
|
setPickerValue(value);
|
|
@@ -236,9 +238,9 @@ export function ClassesTab({
|
|
|
236
238
|
</div>
|
|
237
239
|
)}
|
|
238
240
|
onCreateNew={() => setCreateSheetOpen(true)}
|
|
239
|
-
createLabel=
|
|
241
|
+
createLabel={t('actions.create')}
|
|
240
242
|
onAdd={handleAdd}
|
|
241
|
-
addLabel=
|
|
243
|
+
addLabel={t('actions.add')}
|
|
242
244
|
addDisabled={!pickerClass}
|
|
243
245
|
currentPage={page}
|
|
244
246
|
pageSize={pageSize}
|
|
@@ -253,10 +255,10 @@ export function ClassesTab({
|
|
|
253
255
|
<div className="flex flex-col items-center justify-center py-16 text-center">
|
|
254
256
|
<CalendarDays className="mb-4 h-10 w-10 text-muted-foreground/30" />
|
|
255
257
|
<p className="text-sm font-medium text-muted-foreground">
|
|
256
|
-
|
|
258
|
+
{t('empty.title')}
|
|
257
259
|
</p>
|
|
258
260
|
<p className="mt-1 text-xs text-muted-foreground/60">
|
|
259
|
-
|
|
261
|
+
{t('empty.description')}
|
|
260
262
|
</p>
|
|
261
263
|
</div>
|
|
262
264
|
) : (
|
|
@@ -264,10 +266,10 @@ export function ClassesTab({
|
|
|
264
266
|
<Table>
|
|
265
267
|
<TableHeader>
|
|
266
268
|
<TableRow>
|
|
267
|
-
<TableHead>
|
|
268
|
-
<TableHead>
|
|
269
|
-
<TableHead>
|
|
270
|
-
<TableHead className="text-center">
|
|
269
|
+
<TableHead>{t('table.class')}</TableHead>
|
|
270
|
+
<TableHead>{t('table.status')}</TableHead>
|
|
271
|
+
<TableHead>{t('table.period')}</TableHead>
|
|
272
|
+
<TableHead className="text-center">{t('table.capacity')}</TableHead>
|
|
271
273
|
<TableHead className="w-10" />
|
|
272
274
|
</TableRow>
|
|
273
275
|
</TableHeader>
|
|
@@ -77,7 +77,7 @@ export function EnterpriseCourseCreateSheet({
|
|
|
77
77
|
enterpriseId,
|
|
78
78
|
onCreated,
|
|
79
79
|
}: EnterpriseCourseCreateSheetProps) {
|
|
80
|
-
const t = useTranslations('lms.
|
|
80
|
+
const t = useTranslations('lms.EnterprisePage');
|
|
81
81
|
const { request } = useApp();
|
|
82
82
|
const [saving, setSaving] = useState(false);
|
|
83
83
|
|
|
@@ -159,11 +159,11 @@ export function EnterpriseCourseCreateSheet({
|
|
|
159
159
|
data: { course_id: created.id },
|
|
160
160
|
});
|
|
161
161
|
|
|
162
|
-
toast.success(t('toasts.courseCreated'));
|
|
162
|
+
toast.success(t('form.toasts.courseCreated'));
|
|
163
163
|
onCreated?.();
|
|
164
164
|
onOpenChange(false);
|
|
165
165
|
} catch {
|
|
166
|
-
toast.error('
|
|
166
|
+
toast.error(t('form.toasts.courseCreateError'));
|
|
167
167
|
} finally {
|
|
168
168
|
setSaving(false);
|
|
169
169
|
}
|
|
@@ -22,6 +22,7 @@ import { formatDate } from '@/lib/format-date';
|
|
|
22
22
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
23
23
|
import { BookOpen, SquareArrowOutUpRight, Trash2 } from 'lucide-react';
|
|
24
24
|
import { useRouter } from 'next/navigation';
|
|
25
|
+
import { useTranslations } from 'next-intl';
|
|
25
26
|
import { useCallback, useState } from 'react';
|
|
26
27
|
import { toast } from 'sonner';
|
|
27
28
|
import { EnterpriseCourseCreateSheet } from './enterprise-course-create-sheet';
|
|
@@ -89,6 +90,7 @@ export function CoursesTab({
|
|
|
89
90
|
}) {
|
|
90
91
|
const router = useRouter();
|
|
91
92
|
const { request, getSettingValue, currentLocaleCode } = useApp();
|
|
93
|
+
const t = useTranslations('lms.EnterpriseDetailPage.relatedCourses');
|
|
92
94
|
|
|
93
95
|
const [search, setSearch] = useState('');
|
|
94
96
|
const [statusFilter, setStatusFilter] = useState<
|
|
@@ -142,11 +144,11 @@ export function CoursesTab({
|
|
|
142
144
|
url: `/lms/enterprise/${enterpriseId}/courses/${courseId}`,
|
|
143
145
|
method: 'DELETE',
|
|
144
146
|
});
|
|
145
|
-
toast.success('
|
|
147
|
+
toast.success(t('messages.removeSuccess'));
|
|
146
148
|
refetch();
|
|
147
149
|
onMutate?.();
|
|
148
150
|
} catch {
|
|
149
|
-
toast.error('
|
|
151
|
+
toast.error(t('messages.removeError'));
|
|
150
152
|
}
|
|
151
153
|
}
|
|
152
154
|
|
|
@@ -163,7 +165,7 @@ export function CoursesTab({
|
|
|
163
165
|
refetch();
|
|
164
166
|
onMutate?.();
|
|
165
167
|
} catch {
|
|
166
|
-
toast.error('
|
|
168
|
+
toast.error(t('messages.addError'));
|
|
167
169
|
}
|
|
168
170
|
}
|
|
169
171
|
|
|
@@ -175,7 +177,7 @@ export function CoursesTab({
|
|
|
175
177
|
setSearch(v);
|
|
176
178
|
setPage(1);
|
|
177
179
|
}}
|
|
178
|
-
searchPlaceholder=
|
|
180
|
+
searchPlaceholder={t('searchPlaceholder')}
|
|
179
181
|
filters={
|
|
180
182
|
<Select
|
|
181
183
|
value={statusFilter}
|
|
@@ -185,18 +187,18 @@ export function CoursesTab({
|
|
|
185
187
|
}}
|
|
186
188
|
>
|
|
187
189
|
<SelectTrigger className="w-40">
|
|
188
|
-
<SelectValue placeholder=
|
|
190
|
+
<SelectValue placeholder={t('filters.allStatuses')} />
|
|
189
191
|
</SelectTrigger>
|
|
190
192
|
<SelectContent>
|
|
191
|
-
<SelectItem value="all">
|
|
192
|
-
<SelectItem value="published">
|
|
193
|
-
<SelectItem value="draft">
|
|
194
|
-
<SelectItem value="archived">
|
|
193
|
+
<SelectItem value="all">{t('filters.allStatuses')}</SelectItem>
|
|
194
|
+
<SelectItem value="published">{t('status.published')}</SelectItem>
|
|
195
|
+
<SelectItem value="draft">{t('status.draft')}</SelectItem>
|
|
196
|
+
<SelectItem value="archived">{t('status.archived')}</SelectItem>
|
|
195
197
|
</SelectContent>
|
|
196
198
|
</Select>
|
|
197
199
|
}
|
|
198
|
-
pickerPlaceholder=
|
|
199
|
-
pickerEntityLabel=
|
|
200
|
+
pickerPlaceholder={t('pickerPlaceholder')}
|
|
201
|
+
pickerEntityLabel={t('pickerEntityLabel')}
|
|
200
202
|
pickerValue={pickerValue}
|
|
201
203
|
onPickerChange={(value, option) => {
|
|
202
204
|
setPickerValue(value);
|
|
@@ -228,9 +230,9 @@ export function CoursesTab({
|
|
|
228
230
|
</div>
|
|
229
231
|
)}
|
|
230
232
|
onCreateNew={() => setCreateSheetOpen(true)}
|
|
231
|
-
createLabel=
|
|
233
|
+
createLabel={t('actions.create')}
|
|
232
234
|
onAdd={handleAdd}
|
|
233
|
-
addLabel=
|
|
235
|
+
addLabel={t('actions.add')}
|
|
234
236
|
addDisabled={!pickerCourse}
|
|
235
237
|
currentPage={page}
|
|
236
238
|
pageSize={pageSize}
|
|
@@ -245,10 +247,10 @@ export function CoursesTab({
|
|
|
245
247
|
<div className="flex flex-col items-center justify-center py-16 text-center">
|
|
246
248
|
<BookOpen className="mb-4 h-10 w-10 text-muted-foreground/30" />
|
|
247
249
|
<p className="text-sm font-medium text-muted-foreground">
|
|
248
|
-
|
|
250
|
+
{t('empty.title')}
|
|
249
251
|
</p>
|
|
250
252
|
<p className="mt-1 text-xs text-muted-foreground/60">
|
|
251
|
-
|
|
253
|
+
{t('empty.description')}
|
|
252
254
|
</p>
|
|
253
255
|
</div>
|
|
254
256
|
) : (
|
|
@@ -256,10 +258,10 @@ export function CoursesTab({
|
|
|
256
258
|
<Table>
|
|
257
259
|
<TableHeader>
|
|
258
260
|
<TableRow>
|
|
259
|
-
<TableHead>
|
|
260
|
-
<TableHead>
|
|
261
|
-
<TableHead>
|
|
262
|
-
<TableHead>
|
|
261
|
+
<TableHead>{t('table.course')}</TableHead>
|
|
262
|
+
<TableHead>{t('table.modality')}</TableHead>
|
|
263
|
+
<TableHead>{t('table.status')}</TableHead>
|
|
264
|
+
<TableHead>{t('table.contracted')}</TableHead>
|
|
263
265
|
<TableHead className="w-10" />
|
|
264
266
|
</TableRow>
|
|
265
267
|
</TableHeader>
|