@hed-hog/lms 0.0.306 → 0.0.309
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/dist/course/course-structure.controller.d.ts +60 -0
- package/dist/course/course-structure.controller.d.ts.map +1 -1
- package/dist/course/course-structure.controller.js +79 -0
- package/dist/course/course-structure.controller.js.map +1 -1
- package/dist/course/course-structure.service.d.ts +61 -1
- package/dist/course/course-structure.service.d.ts.map +1 -1
- package/dist/course/course-structure.service.js +326 -1
- package/dist/course/course-structure.service.js.map +1 -1
- package/dist/course/course.controller.d.ts +52 -4
- package/dist/course/course.controller.d.ts.map +1 -1
- package/dist/course/course.service.d.ts +52 -5
- package/dist/course/course.service.d.ts.map +1 -1
- package/dist/course/course.service.js +78 -57
- package/dist/course/course.service.js.map +1 -1
- package/dist/course/dto/create-course-structure-lesson.dto.d.ts.map +1 -1
- package/dist/course/dto/create-course-structure-lesson.dto.js +5 -1
- package/dist/course/dto/create-course-structure-lesson.dto.js.map +1 -1
- package/dist/course/dto/create-course.dto.d.ts +1 -1
- package/dist/course/dto/create-course.dto.d.ts.map +1 -1
- package/dist/course/dto/create-course.dto.js +4 -1
- package/dist/course/dto/create-course.dto.js.map +1 -1
- package/dist/course/dto/move-lesson.dto.d.ts +10 -0
- package/dist/course/dto/move-lesson.dto.d.ts.map +1 -0
- package/dist/course/dto/move-lesson.dto.js +28 -0
- package/dist/course/dto/move-lesson.dto.js.map +1 -0
- package/dist/course/dto/paste-lessons.dto.d.ts +4 -0
- package/dist/course/dto/paste-lessons.dto.d.ts.map +1 -0
- package/dist/course/dto/paste-lessons.dto.js +24 -0
- package/dist/course/dto/paste-lessons.dto.js.map +1 -0
- package/dist/course/dto/reorder-lessons.dto.d.ts +5 -0
- package/dist/course/dto/reorder-lessons.dto.d.ts.map +1 -0
- package/dist/course/dto/reorder-lessons.dto.js +24 -0
- package/dist/course/dto/reorder-lessons.dto.js.map +1 -0
- package/dist/course/dto/reorder-sessions.dto.d.ts +5 -0
- package/dist/course/dto/reorder-sessions.dto.d.ts.map +1 -0
- package/dist/course/dto/reorder-sessions.dto.js +24 -0
- package/dist/course/dto/reorder-sessions.dto.js.map +1 -0
- package/dist/training/training.controller.js +1 -1
- package/dist/training/training.controller.js.map +1 -1
- package/hedhog/data/image_type.yaml +20 -0
- package/hedhog/data/menu.yaml +2 -2
- package/hedhog/data/route.yaml +60 -6
- package/hedhog/frontend/app/_components/class-form-sheet.tsx.ejs +146 -165
- package/hedhog/frontend/app/_components/course-avatar.tsx.ejs +70 -0
- package/hedhog/frontend/app/_components/course-form-sheet.tsx.ejs +372 -22
- package/hedhog/frontend/app/classes/[id]/page.tsx.ejs +437 -77
- package/hedhog/frontend/app/classes/page.tsx.ejs +311 -289
- package/hedhog/frontend/app/courses/[id]/_components/CourseCertificateCard.tsx.ejs +10 -7
- package/hedhog/frontend/app/courses/[id]/_components/CourseClassificationCard.tsx.ejs +23 -32
- package/hedhog/frontend/app/courses/[id]/_components/CourseContentCard.tsx.ejs +3 -9
- package/hedhog/frontend/app/courses/[id]/_components/CourseDangerZoneCard.tsx.ejs +26 -16
- package/hedhog/frontend/app/courses/[id]/_components/CourseFlagsCard.tsx.ejs +19 -5
- package/hedhog/frontend/app/courses/[id]/_components/CourseMainInfoCard.tsx.ejs +10 -14
- package/hedhog/frontend/app/courses/[id]/_components/CourseMediaCard.tsx.ejs +131 -107
- package/hedhog/frontend/app/courses/[id]/_components/CourseRelationsCard.tsx.ejs +10 -7
- package/hedhog/frontend/app/courses/[id]/_components/CourseSectionCard.tsx.ejs +38 -19
- package/hedhog/frontend/app/courses/[id]/_components/CourseSummaryCard.tsx.ejs +1 -1
- package/hedhog/frontend/app/courses/[id]/_components/course-edit-types.ts.ejs +1 -1
- package/hedhog/frontend/app/courses/[id]/page.tsx.ejs +336 -1057
- package/hedhog/frontend/app/courses/[id]/structure/_components/confirm-dialog.tsx.ejs +45 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-dnd.tsx.ejs +362 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-panel.tsx.ejs +111 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree-skeleton.tsx.ejs +64 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/course-tree.tsx.ejs +134 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/detail-course.tsx.ejs +113 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/detail-lesson.tsx.ejs +314 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/detail-panel.tsx.ejs +62 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/detail-session.tsx.ejs +174 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/drag-handle.tsx.ejs +58 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/drag-overlay.tsx.ejs +52 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-bulk.tsx.ejs +276 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-course.tsx.ejs +1216 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-lesson.tsx.ejs +1827 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/editor-session.tsx.ejs +443 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/highlighted-text.tsx.ejs +41 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/mock-data.ts.ejs +184 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/multi-select-bar.tsx.ejs +264 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/search-filter.tsx.ejs +96 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/session-picker-dialog.tsx.ejs +74 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/shortcuts-help.tsx.ejs +136 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/sortable-tree-row.tsx.ejs +80 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/store.ts.ejs +948 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-context-menu.tsx.ejs +525 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-display-settings-popover.tsx.ejs +150 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-helpers.ts.ejs +182 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-course.tsx.ejs +52 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-lesson.tsx.ejs +271 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row-session.tsx.ejs +167 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/tree-row.tsx.ejs +108 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/types.ts.ejs +122 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/use-course-structure-shortcuts.ts.ejs +318 -0
- package/hedhog/frontend/app/courses/[id]/structure/_components/use-tree-display-settings.ts.ejs +97 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/adapters/course-structure.adapter.ts.ejs +347 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/course-structure-contract.ts.ejs +195 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/services/course-structure.service.ts.ejs +420 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/types/api-course.types.ts.ejs +254 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-mutations.ts.ejs +987 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure-query.ts.ejs +86 -0
- package/hedhog/frontend/app/courses/[id]/structure/_data/use-course-structure.ts.ejs +160 -0
- package/hedhog/frontend/app/courses/[id]/structure/page.tsx.ejs +10 -3212
- package/hedhog/frontend/app/courses/page.tsx.ejs +45 -26
- package/hedhog/frontend/app/{training → paths}/page.tsx.ejs +29 -7
- package/hedhog/frontend/messages/en.json +88 -10
- package/hedhog/frontend/messages/pt.json +88 -10
- package/hedhog/table/course.yaml +1 -1
- package/hedhog/table/image_type.yaml +14 -0
- package/package.json +7 -7
- package/src/course/course-structure.controller.ts +63 -0
- package/src/course/course-structure.service.ts +390 -3
- package/src/course/course.service.ts +59 -27
- package/src/course/dto/create-course-structure-lesson.dto.ts +3 -2
- package/src/course/dto/create-course.dto.ts +4 -1
- package/src/course/dto/move-lesson.dto.ts +17 -0
- package/src/course/dto/paste-lessons.dto.ts +9 -0
- package/src/course/dto/reorder-lessons.dto.ts +10 -0
- package/src/course/dto/reorder-sessions.dto.ts +10 -0
- package/src/training/training.controller.ts +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import { CourseAvatar } from '@/app/(app)/(libraries)/lms/_components/course-avatar';
|
|
3
4
|
import {
|
|
4
5
|
EmptyState,
|
|
5
6
|
Page,
|
|
@@ -8,18 +9,11 @@ import {
|
|
|
8
9
|
SearchBar,
|
|
9
10
|
ViewModeToggle,
|
|
10
11
|
} from '@/components/entity-list';
|
|
12
|
+
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
|
11
13
|
import { Badge } from '@/components/ui/badge';
|
|
12
14
|
import { Button } from '@/components/ui/button';
|
|
13
15
|
import { Calendar } from '@/components/ui/calendar';
|
|
14
16
|
import { Card, CardContent } from '@/components/ui/card';
|
|
15
|
-
import {
|
|
16
|
-
Command,
|
|
17
|
-
CommandEmpty,
|
|
18
|
-
CommandGroup,
|
|
19
|
-
CommandInput,
|
|
20
|
-
CommandItem,
|
|
21
|
-
CommandList,
|
|
22
|
-
} from '@/components/ui/command';
|
|
23
17
|
import {
|
|
24
18
|
Dialog,
|
|
25
19
|
DialogContent,
|
|
@@ -83,7 +77,6 @@ import {
|
|
|
83
77
|
AlertTriangle,
|
|
84
78
|
BarChart3,
|
|
85
79
|
CalendarIcon,
|
|
86
|
-
ChevronsUpDown,
|
|
87
80
|
Clock,
|
|
88
81
|
Eye,
|
|
89
82
|
Laptop,
|
|
@@ -135,6 +128,7 @@ interface Turma {
|
|
|
135
128
|
professor: string;
|
|
136
129
|
sessionTitle?: string | null;
|
|
137
130
|
sessionRecurrenceSummary?: SessionRecurrenceSummary | null;
|
|
131
|
+
logoFileId?: number | null;
|
|
138
132
|
}
|
|
139
133
|
|
|
140
134
|
type SessionRecurrenceFrequency = 'daily' | 'weekly' | 'monthly' | 'yearly';
|
|
@@ -196,7 +190,12 @@ type ApiClassStats = {
|
|
|
196
190
|
};
|
|
197
191
|
|
|
198
192
|
type ApiCourseList = {
|
|
199
|
-
data: Array<{
|
|
193
|
+
data: Array<{
|
|
194
|
+
id: number;
|
|
195
|
+
title: string;
|
|
196
|
+
code?: string;
|
|
197
|
+
logoFileId?: number | null;
|
|
198
|
+
}>;
|
|
200
199
|
total?: number;
|
|
201
200
|
page?: number;
|
|
202
201
|
pageSize?: number;
|
|
@@ -226,6 +225,7 @@ type InstructorOption = {
|
|
|
226
225
|
id: number;
|
|
227
226
|
name: string;
|
|
228
227
|
personId?: number;
|
|
228
|
+
avatarId?: number | null;
|
|
229
229
|
qualificationSlugs?: string[];
|
|
230
230
|
};
|
|
231
231
|
|
|
@@ -239,6 +239,8 @@ type InstructorApiRow = {
|
|
|
239
239
|
label?: string;
|
|
240
240
|
personId?: number | string;
|
|
241
241
|
person_id?: number | string;
|
|
242
|
+
avatarId?: number | string | null;
|
|
243
|
+
avatar_id?: number | string | null;
|
|
242
244
|
qualificationSlugs?: string[];
|
|
243
245
|
};
|
|
244
246
|
|
|
@@ -260,10 +262,17 @@ function normalizeInstructorOption(
|
|
|
260
262
|
return null;
|
|
261
263
|
}
|
|
262
264
|
|
|
265
|
+
const rawAvatarId = item?.avatarId ?? item?.avatar_id;
|
|
266
|
+
const avatarId =
|
|
267
|
+
rawAvatarId !== undefined && rawAvatarId !== null
|
|
268
|
+
? Number(rawAvatarId) || null
|
|
269
|
+
: null;
|
|
270
|
+
|
|
263
271
|
return {
|
|
264
272
|
id,
|
|
265
273
|
name,
|
|
266
274
|
personId: Number(item?.personId ?? item?.person_id ?? 0) || undefined,
|
|
275
|
+
avatarId,
|
|
267
276
|
qualificationSlugs: Array.isArray(item?.qualificationSlugs)
|
|
268
277
|
? item.qualificationSlugs
|
|
269
278
|
: undefined,
|
|
@@ -483,22 +492,6 @@ function getTurmaSchema(t: (key: string) => string) {
|
|
|
483
492
|
});
|
|
484
493
|
}
|
|
485
494
|
|
|
486
|
-
if (values.sessionRecurrenceMode !== 'none') {
|
|
487
|
-
if (!values.sessionRecurrenceUntil) {
|
|
488
|
-
ctx.addIssue({
|
|
489
|
-
code: z.ZodIssueCode.custom,
|
|
490
|
-
path: ['sessionRecurrenceUntil'],
|
|
491
|
-
message: t('form.validation.sessionRecurrenceUntilRequired'),
|
|
492
|
-
});
|
|
493
|
-
} else if (values.sessionRecurrenceUntil < values.dataInicio) {
|
|
494
|
-
ctx.addIssue({
|
|
495
|
-
code: z.ZodIssueCode.custom,
|
|
496
|
-
path: ['sessionRecurrenceUntil'],
|
|
497
|
-
message: t('form.validation.sessionRecurrenceUntilAfterStart'),
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
495
|
const requiresDays =
|
|
503
496
|
values.sessionRecurrenceMode === 'weekly' ||
|
|
504
497
|
values.sessionRecurrenceMode === 'weekdays' ||
|
|
@@ -690,8 +683,6 @@ export default function TurmasPage() {
|
|
|
690
683
|
useState(false);
|
|
691
684
|
const [previousRecurrenceMode, setPreviousRecurrenceMode] =
|
|
692
685
|
useState<SessionRecurrenceMode>('none');
|
|
693
|
-
const [professorOpen, setProfessorOpen] = useState(false);
|
|
694
|
-
const [professorSearch, setProfessorSearch] = useState('');
|
|
695
686
|
const [createProfessorDialogOpen, setCreateProfessorDialogOpen] =
|
|
696
687
|
useState(false);
|
|
697
688
|
|
|
@@ -798,63 +789,6 @@ export default function TurmasPage() {
|
|
|
798
789
|
},
|
|
799
790
|
});
|
|
800
791
|
|
|
801
|
-
const {
|
|
802
|
-
data: professorOptions = [],
|
|
803
|
-
isFetching: loadingProfessores,
|
|
804
|
-
refetch: refetchProfessorOptions,
|
|
805
|
-
} = useQuery<InstructorOption[]>({
|
|
806
|
-
queryKey: ['lms-classes-professors', professorSearch],
|
|
807
|
-
queryFn: async () => {
|
|
808
|
-
const response = await request<
|
|
809
|
-
| InstructorApiRow[]
|
|
810
|
-
| {
|
|
811
|
-
data?: InstructorApiRow[];
|
|
812
|
-
items?: InstructorApiRow[];
|
|
813
|
-
rows?: InstructorApiRow[];
|
|
814
|
-
}
|
|
815
|
-
>({
|
|
816
|
-
url: '/lms/instructors',
|
|
817
|
-
method: 'GET',
|
|
818
|
-
params: {
|
|
819
|
-
page: 1,
|
|
820
|
-
pageSize: 100,
|
|
821
|
-
qualificationSlugs: ['class-sessions'],
|
|
822
|
-
...(professorSearch.trim() ? { search: professorSearch.trim() } : {}),
|
|
823
|
-
},
|
|
824
|
-
});
|
|
825
|
-
|
|
826
|
-
const payload = response.data;
|
|
827
|
-
const rows = Array.isArray(payload)
|
|
828
|
-
? payload
|
|
829
|
-
: Array.isArray(payload?.data)
|
|
830
|
-
? payload.data
|
|
831
|
-
: Array.isArray(payload?.items)
|
|
832
|
-
? payload.items
|
|
833
|
-
: Array.isArray(payload?.rows)
|
|
834
|
-
? payload.rows
|
|
835
|
-
: [];
|
|
836
|
-
|
|
837
|
-
const unique = new Map<number, InstructorOption>();
|
|
838
|
-
|
|
839
|
-
for (const row of rows) {
|
|
840
|
-
const normalized = normalizeInstructorOption(row);
|
|
841
|
-
if (!normalized) continue;
|
|
842
|
-
unique.set(normalized.id, normalized);
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
return Array.from(unique.values()).sort((a, b) =>
|
|
846
|
-
a.name.localeCompare(b.name)
|
|
847
|
-
);
|
|
848
|
-
},
|
|
849
|
-
initialData: [],
|
|
850
|
-
});
|
|
851
|
-
|
|
852
|
-
useEffect(() => {
|
|
853
|
-
if (professorOpen) {
|
|
854
|
-
void refetchProfessorOptions();
|
|
855
|
-
}
|
|
856
|
-
}, [professorOpen, refetchProfessorOptions]);
|
|
857
|
-
|
|
858
792
|
useEffect(() => {
|
|
859
793
|
if (courseSheetOpen) {
|
|
860
794
|
void refetchCategoryOptions();
|
|
@@ -936,6 +870,7 @@ export default function TurmasPage() {
|
|
|
936
870
|
|
|
937
871
|
useEffect(() => {
|
|
938
872
|
if (!sheetOpen || editingTurma || !createCodeSeed) return;
|
|
873
|
+
if (form.getFieldState('codigo').isDirty) return;
|
|
939
874
|
|
|
940
875
|
const nextCode = buildClassCode(
|
|
941
876
|
watchedFormValues.curso || undefined,
|
|
@@ -1019,9 +954,9 @@ export default function TurmasPage() {
|
|
|
1019
954
|
);
|
|
1020
955
|
|
|
1021
956
|
const recurrenceSummaryText = useMemo(() => {
|
|
1022
|
-
const until = watchedFormValues.
|
|
957
|
+
const until = watchedFormValues.dataFim
|
|
1023
958
|
? formatDateLocalized(
|
|
1024
|
-
watchedFormValues.
|
|
959
|
+
watchedFormValues.dataFim,
|
|
1025
960
|
getSettingValue,
|
|
1026
961
|
currentLocaleCode
|
|
1027
962
|
)
|
|
@@ -1036,7 +971,7 @@ export default function TurmasPage() {
|
|
|
1036
971
|
}, [
|
|
1037
972
|
t,
|
|
1038
973
|
watchedFormValues.sessionRecurrenceMode,
|
|
1039
|
-
watchedFormValues.
|
|
974
|
+
watchedFormValues.dataFim,
|
|
1040
975
|
getSettingValue,
|
|
1041
976
|
currentLocaleCode,
|
|
1042
977
|
]);
|
|
@@ -1097,23 +1032,19 @@ export default function TurmasPage() {
|
|
|
1097
1032
|
watchedFormValues.sessionRecurrenceMode === 'custom' &&
|
|
1098
1033
|
customRecurrenceFrequency === 'weekly';
|
|
1099
1034
|
|
|
1035
|
+
const weeklyNeedsDays = watchedFormValues.sessionRecurrenceMode === 'weekly';
|
|
1036
|
+
|
|
1100
1037
|
useEffect(() => {
|
|
1101
1038
|
if (!watchedFormValues.dataFim) {
|
|
1102
1039
|
return;
|
|
1103
1040
|
}
|
|
1104
1041
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
}
|
|
1112
|
-
}, [
|
|
1113
|
-
form,
|
|
1114
|
-
watchedFormValues.dataFim,
|
|
1115
|
-
watchedFormValues.sessionRecurrenceUntil,
|
|
1116
|
-
]);
|
|
1042
|
+
form.setValue('sessionRecurrenceUntil', watchedFormValues.dataFim, {
|
|
1043
|
+
shouldDirty: false,
|
|
1044
|
+
shouldTouch: false,
|
|
1045
|
+
shouldValidate: false,
|
|
1046
|
+
});
|
|
1047
|
+
}, [form, watchedFormValues.dataFim]);
|
|
1117
1048
|
|
|
1118
1049
|
useEffect(() => {
|
|
1119
1050
|
if (!watchedFormValues.dataInicio) {
|
|
@@ -1122,7 +1053,7 @@ export default function TurmasPage() {
|
|
|
1122
1053
|
|
|
1123
1054
|
const defaultDay = getDayCodeFromDate(watchedFormValues.dataInicio);
|
|
1124
1055
|
const recurrenceMode = watchedFormValues.sessionRecurrenceMode;
|
|
1125
|
-
const recurrenceDays =
|
|
1056
|
+
const recurrenceDays = form.getValues('sessionRecurrenceDaysOfWeek') ?? [];
|
|
1126
1057
|
|
|
1127
1058
|
if (recurrenceMode === 'weekly' && recurrenceDays.length === 0) {
|
|
1128
1059
|
form.setValue('sessionRecurrenceDaysOfWeek', [defaultDay], {
|
|
@@ -1133,20 +1064,27 @@ export default function TurmasPage() {
|
|
|
1133
1064
|
}
|
|
1134
1065
|
|
|
1135
1066
|
if (recurrenceMode === 'weekdays') {
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1067
|
+
const weekdaySet = ['MO', 'TU', 'WE', 'TH', 'FR'];
|
|
1068
|
+
const alreadySet =
|
|
1069
|
+
recurrenceDays.length === weekdaySet.length &&
|
|
1070
|
+
weekdaySet.every((d) =>
|
|
1071
|
+
recurrenceDays.includes(d as SessionRecurrenceDay)
|
|
1072
|
+
);
|
|
1073
|
+
if (!alreadySet) {
|
|
1074
|
+
form.setValue(
|
|
1075
|
+
'sessionRecurrenceDaysOfWeek',
|
|
1076
|
+
['MO', 'TU', 'WE', 'TH', 'FR'],
|
|
1077
|
+
{
|
|
1078
|
+
shouldDirty: false,
|
|
1079
|
+
shouldTouch: false,
|
|
1080
|
+
shouldValidate: false,
|
|
1081
|
+
}
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1145
1084
|
}
|
|
1146
1085
|
}, [
|
|
1147
1086
|
form,
|
|
1148
1087
|
watchedFormValues.dataInicio,
|
|
1149
|
-
watchedFormValues.sessionRecurrenceDaysOfWeek,
|
|
1150
1088
|
watchedFormValues.sessionRecurrenceMode,
|
|
1151
1089
|
]);
|
|
1152
1090
|
|
|
@@ -1182,28 +1120,40 @@ export default function TurmasPage() {
|
|
|
1182
1120
|
|
|
1183
1121
|
const professorNameById = useMemo<Map<number, string>>(() => {
|
|
1184
1122
|
const map = new Map<number, string>();
|
|
1185
|
-
for (const
|
|
1186
|
-
|
|
1123
|
+
for (const turma of classesResponse?.data ?? []) {
|
|
1124
|
+
if (turma.instructorId && turma.instructorName) {
|
|
1125
|
+
map.set(turma.instructorId, turma.instructorName);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
return map;
|
|
1129
|
+
}, [classesResponse]);
|
|
1130
|
+
|
|
1131
|
+
const courseLogoMap = useMemo<Map<number, number | null>>(() => {
|
|
1132
|
+
const map = new Map<number, number | null>();
|
|
1133
|
+
for (const course of coursesResponse?.data ?? []) {
|
|
1134
|
+
map.set(course.id, course.logoFileId ?? null);
|
|
1187
1135
|
}
|
|
1188
1136
|
return map;
|
|
1189
|
-
}, [
|
|
1137
|
+
}, [coursesResponse]);
|
|
1190
1138
|
|
|
1191
1139
|
const turmas = useMemo<Turma[]>(
|
|
1192
1140
|
() =>
|
|
1193
1141
|
(classesResponse?.data ?? []).map((item) => {
|
|
1194
1142
|
const mapped = mapApiClass(item);
|
|
1143
|
+
const logoFileId = courseLogoMap.get(mapped.cursoId) ?? null;
|
|
1144
|
+
const withLogo = { ...mapped, logoFileId };
|
|
1195
1145
|
if (
|
|
1196
|
-
(
|
|
1197
|
-
|
|
1146
|
+
(withLogo.professor === '-' || !withLogo.professor) &&
|
|
1147
|
+
withLogo.instructorId
|
|
1198
1148
|
) {
|
|
1199
|
-
const fallback = professorNameById.get(
|
|
1149
|
+
const fallback = professorNameById.get(withLogo.instructorId);
|
|
1200
1150
|
if (fallback) {
|
|
1201
|
-
return { ...
|
|
1151
|
+
return { ...withLogo, professor: fallback };
|
|
1202
1152
|
}
|
|
1203
1153
|
}
|
|
1204
|
-
return
|
|
1154
|
+
return withLogo;
|
|
1205
1155
|
}),
|
|
1206
|
-
[classesResponse, professorNameById]
|
|
1156
|
+
[classesResponse, professorNameById, courseLogoMap]
|
|
1207
1157
|
);
|
|
1208
1158
|
const previewTurma = useMemo<Turma | null>(() => {
|
|
1209
1159
|
if (!sheetOpen || !editingTurma) return null;
|
|
@@ -1413,7 +1363,7 @@ export default function TurmasPage() {
|
|
|
1413
1363
|
sessionRecurrenceDaysOfWeek:
|
|
1414
1364
|
recurrenceSummary?.daysOfWeek ??
|
|
1415
1365
|
(recurrenceMode === 'weekly' ? [defaultDay] : []),
|
|
1416
|
-
sessionRecurrenceUntil:
|
|
1366
|
+
sessionRecurrenceUntil: detailedTurma.dataFim,
|
|
1417
1367
|
sessionTitleMode:
|
|
1418
1368
|
response.data.sessionTitle &&
|
|
1419
1369
|
response.data.sessionTitle !==
|
|
@@ -1510,7 +1460,6 @@ export default function TurmasPage() {
|
|
|
1510
1460
|
async function handleCustomRecurrenceConfirm() {
|
|
1511
1461
|
const valid = await form.trigger([
|
|
1512
1462
|
'sessionRecurrenceInterval',
|
|
1513
|
-
'sessionRecurrenceUntil',
|
|
1514
1463
|
'sessionRecurrenceDaysOfWeek',
|
|
1515
1464
|
'dataInicio',
|
|
1516
1465
|
]);
|
|
@@ -1621,7 +1570,6 @@ export default function TurmasPage() {
|
|
|
1621
1570
|
});
|
|
1622
1571
|
|
|
1623
1572
|
toast.success(t('toasts.turmaUpdated'));
|
|
1624
|
-
await refetchProfessorOptions();
|
|
1625
1573
|
} else {
|
|
1626
1574
|
const response = await request<ApiClass>({
|
|
1627
1575
|
url: '/lms/classes',
|
|
@@ -1643,7 +1591,6 @@ export default function TurmasPage() {
|
|
|
1643
1591
|
});
|
|
1644
1592
|
|
|
1645
1593
|
toast.success(t('toasts.turmaCreated'));
|
|
1646
|
-
await refetchProfessorOptions();
|
|
1647
1594
|
await refetchClasses();
|
|
1648
1595
|
await refetchStats();
|
|
1649
1596
|
notifyLmsDashboardUpdated();
|
|
@@ -1700,7 +1647,6 @@ export default function TurmasPage() {
|
|
|
1700
1647
|
shouldValidate: true,
|
|
1701
1648
|
});
|
|
1702
1649
|
|
|
1703
|
-
await refetchProfessorOptions();
|
|
1704
1650
|
await refetchClasses();
|
|
1705
1651
|
};
|
|
1706
1652
|
|
|
@@ -2000,16 +1946,21 @@ export default function TurmasPage() {
|
|
|
2000
1946
|
title={t('cards.tooltip')}
|
|
2001
1947
|
>
|
|
2002
1948
|
<div
|
|
2003
|
-
className="absolute inset-x-0 top-0 h-1"
|
|
2004
|
-
style={
|
|
2005
|
-
|
|
2006
|
-
|
|
1949
|
+
className="absolute inset-x-0 top-0 h-1 bg-primary"
|
|
1950
|
+
style={
|
|
1951
|
+
turma.primaryColor
|
|
1952
|
+
? { backgroundColor: turma.primaryColor }
|
|
1953
|
+
: undefined
|
|
1954
|
+
}
|
|
2007
1955
|
/>
|
|
2008
1956
|
<CardContent className="p-5">
|
|
2009
1957
|
<div className="mb-4 flex items-start gap-3">
|
|
2010
|
-
<
|
|
2011
|
-
|
|
2012
|
-
|
|
1958
|
+
<CourseAvatar
|
|
1959
|
+
fileId={turma.logoFileId}
|
|
1960
|
+
title={turma.curso}
|
|
1961
|
+
className="size-12 rounded-xl"
|
|
1962
|
+
iconSize="size-6"
|
|
1963
|
+
/>
|
|
2013
1964
|
<div className="min-w-0 flex-1">
|
|
2014
1965
|
<div className="mb-1 flex items-start justify-between gap-2">
|
|
2015
1966
|
<h3 className="line-clamp-2 font-semibold leading-snug text-foreground">
|
|
@@ -2188,19 +2139,27 @@ export default function TurmasPage() {
|
|
|
2188
2139
|
title={t('cards.tooltip')}
|
|
2189
2140
|
>
|
|
2190
2141
|
<TableCell>
|
|
2191
|
-
<div className="min-w-0">
|
|
2192
|
-
<
|
|
2193
|
-
{turma.
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
<
|
|
2200
|
-
|
|
2201
|
-
</
|
|
2202
|
-
<
|
|
2203
|
-
|
|
2142
|
+
<div className="flex min-w-0 items-center gap-3">
|
|
2143
|
+
<CourseAvatar
|
|
2144
|
+
fileId={turma.logoFileId}
|
|
2145
|
+
title={turma.curso}
|
|
2146
|
+
className="size-8 shrink-0 rounded-lg"
|
|
2147
|
+
iconSize="size-4"
|
|
2148
|
+
/>
|
|
2149
|
+
<div className="min-w-0">
|
|
2150
|
+
<p className="truncate font-semibold text-foreground">
|
|
2151
|
+
{turma.curso}
|
|
2152
|
+
</p>
|
|
2153
|
+
<p className="mt-1 text-xs text-muted-foreground">
|
|
2154
|
+
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-[10px]">
|
|
2155
|
+
{turma.codigo}
|
|
2156
|
+
</code>
|
|
2157
|
+
<span className="mx-1.5 text-muted-foreground/50">
|
|
2158
|
+
|
|
|
2159
|
+
</span>
|
|
2160
|
+
<span>{turma.professor}</span>
|
|
2161
|
+
</p>
|
|
2162
|
+
</div>
|
|
2204
2163
|
</div>
|
|
2205
2164
|
</TableCell>
|
|
2206
2165
|
<TableCell>
|
|
@@ -2323,11 +2282,17 @@ export default function TurmasPage() {
|
|
|
2323
2282
|
<Input
|
|
2324
2283
|
id="codigo"
|
|
2325
2284
|
value={watchedFormValues.codigo ?? ''}
|
|
2326
|
-
readOnly
|
|
2327
2285
|
className="uppercase"
|
|
2286
|
+
onChange={(event) =>
|
|
2287
|
+
form.setValue('codigo', event.target.value.toUpperCase(), {
|
|
2288
|
+
shouldDirty: true,
|
|
2289
|
+
shouldTouch: true,
|
|
2290
|
+
shouldValidate: true,
|
|
2291
|
+
})
|
|
2292
|
+
}
|
|
2328
2293
|
/>
|
|
2329
2294
|
<FieldDescription>
|
|
2330
|
-
Codigo gerado automaticamente
|
|
2295
|
+
Codigo gerado automaticamente, mas pode ser editado.
|
|
2331
2296
|
</FieldDescription>
|
|
2332
2297
|
<FieldError>{form.formState.errors.codigo?.message}</FieldError>
|
|
2333
2298
|
</Field>
|
|
@@ -2339,7 +2304,15 @@ export default function TurmasPage() {
|
|
|
2339
2304
|
</FieldLabel>
|
|
2340
2305
|
<div className="flex items-end gap-2">
|
|
2341
2306
|
<div className="min-w-0 flex-1">
|
|
2342
|
-
<EntityPicker<
|
|
2307
|
+
<EntityPicker<
|
|
2308
|
+
{
|
|
2309
|
+
id: number;
|
|
2310
|
+
title: string;
|
|
2311
|
+
code?: string;
|
|
2312
|
+
logoFileId?: number | null;
|
|
2313
|
+
},
|
|
2314
|
+
TurmaForm
|
|
2315
|
+
>
|
|
2343
2316
|
form={form}
|
|
2344
2317
|
name="courseId"
|
|
2345
2318
|
valueType="number"
|
|
@@ -2351,6 +2324,33 @@ export default function TurmasPage() {
|
|
|
2351
2324
|
loadingLabel="Carregando cursos..."
|
|
2352
2325
|
noResultsLabel="Nenhum curso encontrado."
|
|
2353
2326
|
showCreateButton={false}
|
|
2327
|
+
renderOption={({ option }) => (
|
|
2328
|
+
<div className="flex items-center gap-2 py-0.5">
|
|
2329
|
+
<CourseAvatar
|
|
2330
|
+
fileId={option.logoFileId}
|
|
2331
|
+
title={option.title}
|
|
2332
|
+
className="size-8 shrink-0 rounded-lg"
|
|
2333
|
+
iconSize="size-4"
|
|
2334
|
+
/>
|
|
2335
|
+
<div className="min-w-0">
|
|
2336
|
+
<p className="truncate text-sm">{option.title}</p>
|
|
2337
|
+
<p className="truncate text-xs text-muted-foreground">
|
|
2338
|
+
{option.code ?? '—'} · #{option.id}
|
|
2339
|
+
</p>
|
|
2340
|
+
</div>
|
|
2341
|
+
</div>
|
|
2342
|
+
)}
|
|
2343
|
+
renderSelectedValue={({ option }) => (
|
|
2344
|
+
<div className="flex items-center gap-2">
|
|
2345
|
+
<CourseAvatar
|
|
2346
|
+
fileId={option?.logoFileId}
|
|
2347
|
+
title={option?.title ?? ''}
|
|
2348
|
+
className="size-5 shrink-0 rounded"
|
|
2349
|
+
iconSize="size-3"
|
|
2350
|
+
/>
|
|
2351
|
+
<span className="truncate">{option?.title}</span>
|
|
2352
|
+
</div>
|
|
2353
|
+
)}
|
|
2354
2354
|
onChange={(value, option) => {
|
|
2355
2355
|
const courseId =
|
|
2356
2356
|
typeof value === 'number' ? value : undefined;
|
|
@@ -2621,30 +2621,41 @@ export default function TurmasPage() {
|
|
|
2621
2621
|
{form.formState.errors.sessionRecurrenceMode?.message}
|
|
2622
2622
|
</FieldError>
|
|
2623
2623
|
</Field>
|
|
2624
|
+
</div>
|
|
2624
2625
|
|
|
2626
|
+
{weeklyNeedsDays && (
|
|
2625
2627
|
<Field>
|
|
2626
|
-
<FieldLabel>
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2628
|
+
<FieldLabel>
|
|
2629
|
+
{t('form.recurrence.customDialog.repeatOn')}
|
|
2630
|
+
</FieldLabel>
|
|
2631
|
+
<div className="flex flex-wrap gap-2">
|
|
2632
|
+
{recurrenceDayOptions.map((day) => {
|
|
2633
|
+
const active = (
|
|
2634
|
+
watchedFormValues.sessionRecurrenceDaysOfWeek ?? []
|
|
2635
|
+
).includes(day.value);
|
|
2636
|
+
|
|
2637
|
+
return (
|
|
2638
|
+
<Button
|
|
2639
|
+
key={day.value}
|
|
2640
|
+
type="button"
|
|
2641
|
+
variant={active ? 'default' : 'outline'}
|
|
2642
|
+
size="icon"
|
|
2643
|
+
className="rounded-full"
|
|
2644
|
+
onClick={() => toggleCustomRecurrenceDay(day.value)}
|
|
2645
|
+
>
|
|
2646
|
+
{day.label}
|
|
2647
|
+
</Button>
|
|
2648
|
+
);
|
|
2649
|
+
})}
|
|
2650
|
+
</div>
|
|
2643
2651
|
<FieldError>
|
|
2644
|
-
{
|
|
2652
|
+
{
|
|
2653
|
+
form.formState.errors.sessionRecurrenceDaysOfWeek
|
|
2654
|
+
?.message
|
|
2655
|
+
}
|
|
2645
2656
|
</FieldError>
|
|
2646
2657
|
</Field>
|
|
2647
|
-
|
|
2658
|
+
)}
|
|
2648
2659
|
|
|
2649
2660
|
<div className="grid gap-4 md:grid-cols-[minmax(0,0.55fr)_minmax(0,1fr)]">
|
|
2650
2661
|
<Field>
|
|
@@ -2812,107 +2823,139 @@ export default function TurmasPage() {
|
|
|
2812
2823
|
{t('form.fields.professor.label')}{' '}
|
|
2813
2824
|
<span className="text-destructive">*</span>
|
|
2814
2825
|
</FieldLabel>
|
|
2815
|
-
<
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2826
|
+
<div className="flex items-end gap-2">
|
|
2827
|
+
<div className="flex-1">
|
|
2828
|
+
<EntityPicker<InstructorOption, TurmaForm>
|
|
2829
|
+
form={form}
|
|
2830
|
+
name="instructorId"
|
|
2831
|
+
valueType="number"
|
|
2832
|
+
placeholder={t('form.fields.professor.placeholder')}
|
|
2833
|
+
initialSelectedLabel={watchedFormValues.professor ?? ''}
|
|
2834
|
+
searchPlaceholder={t('form.fields.professor.placeholder')}
|
|
2835
|
+
emptyStateDescription="Nenhum professor encontrado."
|
|
2836
|
+
noResultsLabel="Nenhum professor encontrado."
|
|
2837
|
+
showCreateButton={false}
|
|
2838
|
+
clearable={false}
|
|
2839
|
+
getOptionValue={(opt) => opt.id}
|
|
2840
|
+
getOptionLabel={(opt) => opt.name}
|
|
2841
|
+
onChange={(value, option) => {
|
|
2842
|
+
form.setValue(
|
|
2843
|
+
'instructorId',
|
|
2844
|
+
value as number | undefined,
|
|
2845
|
+
{
|
|
2846
|
+
shouldDirty: true,
|
|
2847
|
+
shouldTouch: true,
|
|
2848
|
+
shouldValidate: true,
|
|
2849
|
+
}
|
|
2850
|
+
);
|
|
2851
|
+
form.setValue('professor', option?.name ?? '', {
|
|
2852
|
+
shouldDirty: true,
|
|
2853
|
+
shouldTouch: true,
|
|
2854
|
+
shouldValidate: true,
|
|
2855
|
+
});
|
|
2856
|
+
}}
|
|
2857
|
+
loadOptions={async ({ page, pageSize, search }) => {
|
|
2858
|
+
const response = await request<
|
|
2859
|
+
| InstructorApiRow[]
|
|
2860
|
+
| {
|
|
2861
|
+
data?: InstructorApiRow[];
|
|
2862
|
+
items?: InstructorApiRow[];
|
|
2863
|
+
rows?: InstructorApiRow[];
|
|
2864
|
+
total?: number;
|
|
2865
|
+
lastPage?: number;
|
|
2866
|
+
}
|
|
2867
|
+
>({
|
|
2868
|
+
url: '/lms/instructors',
|
|
2869
|
+
method: 'GET',
|
|
2870
|
+
params: {
|
|
2871
|
+
page,
|
|
2872
|
+
pageSize,
|
|
2873
|
+
qualificationSlugs: ['class-sessions'],
|
|
2874
|
+
...(search.trim() ? { search: search.trim() } : {}),
|
|
2875
|
+
},
|
|
2876
|
+
});
|
|
2877
|
+
|
|
2878
|
+
const payload = response.data;
|
|
2879
|
+
const rows = Array.isArray(payload)
|
|
2880
|
+
? payload
|
|
2881
|
+
: Array.isArray(payload?.data)
|
|
2882
|
+
? payload.data
|
|
2883
|
+
: Array.isArray(payload?.items)
|
|
2884
|
+
? payload.items
|
|
2885
|
+
: Array.isArray(payload?.rows)
|
|
2886
|
+
? payload.rows
|
|
2887
|
+
: [];
|
|
2888
|
+
const lastPage =
|
|
2889
|
+
!Array.isArray(payload) && payload?.lastPage
|
|
2890
|
+
? payload.lastPage
|
|
2891
|
+
: 1;
|
|
2892
|
+
|
|
2893
|
+
const items = rows
|
|
2894
|
+
.map(normalizeInstructorOption)
|
|
2895
|
+
.filter((opt): opt is InstructorOption => opt !== null);
|
|
2896
|
+
|
|
2897
|
+
return { items, hasMore: page < lastPage };
|
|
2898
|
+
}}
|
|
2899
|
+
renderOption={({ option }) => {
|
|
2900
|
+
const initials = option.name
|
|
2901
|
+
.split(' ')
|
|
2902
|
+
.filter(Boolean)
|
|
2903
|
+
.slice(0, 2)
|
|
2904
|
+
.map((p) => p[0]?.toUpperCase() ?? '')
|
|
2905
|
+
.join('');
|
|
2906
|
+
const avatarUrl = option.avatarId
|
|
2907
|
+
? `${process.env.NEXT_PUBLIC_API_BASE_URL}/person/avatar/${option.avatarId}`
|
|
2908
|
+
: undefined;
|
|
2909
|
+
return (
|
|
2910
|
+
<div className="flex min-w-0 items-center gap-3 py-0.5">
|
|
2911
|
+
<Avatar className="h-8 w-8 shrink-0 rounded-lg border border-border/60">
|
|
2912
|
+
<AvatarImage src={avatarUrl} />
|
|
2913
|
+
<AvatarFallback className="rounded-lg bg-muted text-[11px] font-semibold text-foreground">
|
|
2914
|
+
{initials}
|
|
2915
|
+
</AvatarFallback>
|
|
2916
|
+
</Avatar>
|
|
2917
|
+
<span className="truncate text-sm">
|
|
2918
|
+
{option.name}
|
|
2919
|
+
</span>
|
|
2920
|
+
</div>
|
|
2921
|
+
);
|
|
2922
|
+
}}
|
|
2923
|
+
renderSelectedValue={({ option, label }) => {
|
|
2924
|
+
const name = option?.name ?? label;
|
|
2925
|
+
const initials = name
|
|
2926
|
+
.split(' ')
|
|
2927
|
+
.filter(Boolean)
|
|
2928
|
+
.slice(0, 2)
|
|
2929
|
+
.map((p) => p[0]?.toUpperCase() ?? '')
|
|
2930
|
+
.join('');
|
|
2931
|
+
const avatarUrl = option?.avatarId
|
|
2932
|
+
? `${process.env.NEXT_PUBLIC_API_BASE_URL}/person/avatar/${option.avatarId}`
|
|
2933
|
+
: undefined;
|
|
2934
|
+
return (
|
|
2935
|
+
<div className="flex items-center gap-2">
|
|
2936
|
+
<Avatar className="h-5 w-5 shrink-0 rounded">
|
|
2937
|
+
<AvatarImage src={avatarUrl} />
|
|
2938
|
+
<AvatarFallback className="rounded bg-muted text-[10px] font-semibold">
|
|
2939
|
+
{initials}
|
|
2940
|
+
</AvatarFallback>
|
|
2941
|
+
</Avatar>
|
|
2942
|
+
<span className="truncate">{name}</span>
|
|
2943
|
+
</div>
|
|
2944
|
+
);
|
|
2945
|
+
}}
|
|
2946
|
+
/>
|
|
2947
|
+
</div>
|
|
2948
|
+
<Button
|
|
2949
|
+
type="button"
|
|
2950
|
+
variant="outline"
|
|
2951
|
+
size="icon"
|
|
2952
|
+
className="shrink-0"
|
|
2953
|
+
onClick={() => setCreateProfessorDialogOpen(true)}
|
|
2954
|
+
aria-label="Cadastrar novo professor"
|
|
2955
|
+
>
|
|
2956
|
+
<Plus className="h-4 w-4" />
|
|
2957
|
+
</Button>
|
|
2958
|
+
</div>
|
|
2916
2959
|
<FieldError>
|
|
2917
2960
|
{form.formState.errors.professor?.message}
|
|
2918
2961
|
</FieldError>
|
|
@@ -3088,27 +3131,6 @@ export default function TurmasPage() {
|
|
|
3088
3131
|
</FieldError>
|
|
3089
3132
|
</Field>
|
|
3090
3133
|
)}
|
|
3091
|
-
|
|
3092
|
-
<Field>
|
|
3093
|
-
<FieldLabel>
|
|
3094
|
-
{t('form.recurrence.customDialog.endDate')}
|
|
3095
|
-
</FieldLabel>
|
|
3096
|
-
<Input
|
|
3097
|
-
type="date"
|
|
3098
|
-
min={watchedFormValues.dataInicio || undefined}
|
|
3099
|
-
value={watchedFormValues.sessionRecurrenceUntil ?? ''}
|
|
3100
|
-
onChange={(event) =>
|
|
3101
|
-
form.setValue('sessionRecurrenceUntil', event.target.value, {
|
|
3102
|
-
shouldDirty: true,
|
|
3103
|
-
shouldTouch: true,
|
|
3104
|
-
shouldValidate: true,
|
|
3105
|
-
})
|
|
3106
|
-
}
|
|
3107
|
-
/>
|
|
3108
|
-
<FieldError>
|
|
3109
|
-
{form.formState.errors.sessionRecurrenceUntil?.message}
|
|
3110
|
-
</FieldError>
|
|
3111
|
-
</Field>
|
|
3112
3134
|
</div>
|
|
3113
3135
|
|
|
3114
3136
|
<DialogFooter className="gap-2">
|