@nualang/nualang-ui-components 0.1.1304 → 0.1.1306
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/Assignments/AssignmentCourseSelection/AssignmentCourseSelection.js +1 -6
- package/dist/Assignments/AssignmentExerciseSelection/AssignmentExerciseSelection.js +3 -9
- package/dist/Assignments/AssignmentExerciseSelector/AssignmentExerciseSelector.js +0 -2
- package/dist/Assignments/AssignmentSelectExercise/AssignmentSelectExercise.js +0 -2
- package/dist/Assignments/CreateAssignmentDialog/CreateAssignmentDialog.js +3 -6
- package/dist/Cards/FeedbackCard/FeedbackCard.js +365 -0
- package/dist/Cards/RecordingCard/RecordingCard.js +161 -120
- package/dist/Cards/ScheduleCard/ScheduleCard.js +97 -57
- package/dist/Dialogs/GenerateDiscussion/GenerateDiscussion.js +171 -0
- package/dist/Dialogs/GroupedFeedbackDialog/GroupedFeedbackDialog.js +273 -0
- package/dist/Dialogs/RecordingDialog/RecordingDialog.js +61 -43
- package/dist/Forms/CreateMeetingMultiStepForm/CreateMeetingMultiStepForm.js +15 -3
- package/dist/Forms/CreateMeetingMultiStepForm/MeetingForm.js +144 -113
- package/dist/Lists/CourseOutline/CourseOutline.js +11 -26
- package/dist/Screens/Classrooms/ViewClassroom/ViewClassroom.js +7 -3
- package/dist/Screens/Courses/ViewCourse/ViewCourse.js +3 -1
- package/dist/Screens/Courses/ViewCourse/ViewTopic/ViewTopic.js +2 -2
- package/dist/Tables/MeetingPrompstList/MeetingPromptsList.js +23 -31
- package/dist/Tables/Progress/Progress.js +0 -1
- package/dist/Tables/Progress/ProgressTable.js +46 -30
- package/dist/Tables/Progress/utils.js +4 -4
- package/dist/Tables/ScheduleListCards/ScheduleListCards.js +2 -86
- package/dist/img/NualaHeadphonesBackground.svg +39 -0
- package/dist/img/aaronAvatar.png +0 -0
- package/dist/img/connorAvatar.png +0 -0
- package/dist/img/jamieAvatar.png +0 -0
- package/dist/img/stephenAvatar.png +0 -0
- package/dist/utils/index.js +6 -29
- package/package.json +1 -1
|
@@ -31,7 +31,6 @@ function Course({
|
|
|
31
31
|
lastClickedExerciseId,
|
|
32
32
|
handleRemoveExercise,
|
|
33
33
|
isPreview,
|
|
34
|
-
isChallengeModeEnabled = false,
|
|
35
34
|
isChallengeModeStudent
|
|
36
35
|
}) {
|
|
37
36
|
const numOfIds = lastClickedExerciseId ? lastClickedExerciseId.split("|") : [];
|
|
@@ -88,7 +87,7 @@ function Course({
|
|
|
88
87
|
}
|
|
89
88
|
});
|
|
90
89
|
if (courseSections && memberCourseCompletions && selectedExercises) {
|
|
91
|
-
const sectionsWithProgress = calcCompletions(courseSections.filter(section => assignedSectionIds.has(section.sectionId)), memberCourseCompletions, selectedExercises,
|
|
90
|
+
const sectionsWithProgress = calcCompletions(courseSections.filter(section => assignedSectionIds.has(section.sectionId)), memberCourseCompletions, selectedExercises, isChallengeModeStudent);
|
|
92
91
|
const percentCompletion = calcPercentageCompletion(sectionsWithProgress);
|
|
93
92
|
setCourseSectionCompletion(percentCompletion);
|
|
94
93
|
}
|
|
@@ -177,7 +176,6 @@ function Course({
|
|
|
177
176
|
progressHelpers: progressHelpers,
|
|
178
177
|
memberCourseCompletions: memberCourseCompletions,
|
|
179
178
|
lastClickedExerciseId: lastClickedExerciseId,
|
|
180
|
-
isChallengeModeEnabled: isChallengeModeEnabled,
|
|
181
179
|
isChallengeModeStudent: isChallengeModeStudent
|
|
182
180
|
})
|
|
183
181
|
})
|
|
@@ -208,7 +206,6 @@ function Course({
|
|
|
208
206
|
course: course,
|
|
209
207
|
handleRemoveExercise: handleRemoveExercise,
|
|
210
208
|
isPreview: isPreview,
|
|
211
|
-
isChallengeModeEnabled: isChallengeModeEnabled,
|
|
212
209
|
isChallengeModeStudent: isChallengeModeStudent
|
|
213
210
|
})
|
|
214
211
|
})
|
|
@@ -236,7 +233,6 @@ function AssignmentCourseSelection({
|
|
|
236
233
|
lastClickedExerciseId,
|
|
237
234
|
handleRemoveExercise,
|
|
238
235
|
isPreview,
|
|
239
|
-
isChallengeModeEnabled = false,
|
|
240
236
|
isChallengeModeStudent,
|
|
241
237
|
...otherProps
|
|
242
238
|
}) {
|
|
@@ -264,7 +260,6 @@ function AssignmentCourseSelection({
|
|
|
264
260
|
lastClickedExerciseId: lastClickedExerciseId,
|
|
265
261
|
handleRemoveExercise: handleRemoveExercise,
|
|
266
262
|
isPreview: isPreview,
|
|
267
|
-
isChallengeModeEnabled: isChallengeModeEnabled,
|
|
268
263
|
isChallengeModeStudent: isChallengeModeStudent
|
|
269
264
|
}, course.courseId || index))
|
|
270
265
|
});
|
|
@@ -48,7 +48,6 @@ function Exercise({
|
|
|
48
48
|
lastClickedExerciseId,
|
|
49
49
|
isPreview,
|
|
50
50
|
handleRemoveExercise = null,
|
|
51
|
-
isChallengeModeEnabled = false,
|
|
52
51
|
isChallengeModeStudent
|
|
53
52
|
}) {
|
|
54
53
|
const [listeningHidden, setListeningHidden] = useState(false);
|
|
@@ -269,8 +268,7 @@ function Exercise({
|
|
|
269
268
|
isCreator: isCreator,
|
|
270
269
|
lastClickedExerciseId: lastClickedExerciseId,
|
|
271
270
|
handleRemoveExercise: handleRemoveExercise,
|
|
272
|
-
isPreview: isPreview
|
|
273
|
-
isChallengeModeEnabled: isChallengeModeEnabled
|
|
271
|
+
isPreview: isPreview
|
|
274
272
|
})
|
|
275
273
|
})
|
|
276
274
|
}), name.toLowerCase() === "bots" && /*#__PURE__*/_jsx(Collapse, {
|
|
@@ -298,7 +296,6 @@ function Exercise({
|
|
|
298
296
|
lastClickedExerciseId: lastClickedExerciseId,
|
|
299
297
|
handleRemoveExercise: handleRemoveExercise,
|
|
300
298
|
isPreview: isPreview,
|
|
301
|
-
isChallengeModeEnabled: isChallengeModeEnabled,
|
|
302
299
|
isChallengeModeStudent: isChallengeModeStudent
|
|
303
300
|
})
|
|
304
301
|
})
|
|
@@ -885,19 +882,16 @@ function SectionList({
|
|
|
885
882
|
course,
|
|
886
883
|
handleRemoveExercise,
|
|
887
884
|
isPreview,
|
|
888
|
-
isChallengeModeEnabled = false,
|
|
889
885
|
isChallengeModeStudent,
|
|
890
886
|
...otherProps
|
|
891
887
|
}) {
|
|
892
888
|
const [courseSectionWithProgress, setCourseSectionWithProgress] = useState([]);
|
|
893
889
|
useEffect(() => {
|
|
894
890
|
if (sections && memberCourseCompletions && selectedExercises) {
|
|
895
|
-
const sectionsWithProgress = calcCompletions(sections, memberCourseCompletions, selectedExercises,
|
|
896
|
-
includeChallengeBots: isChallengeModeEnabled
|
|
897
|
-
});
|
|
891
|
+
const sectionsWithProgress = calcCompletions(sections, memberCourseCompletions, selectedExercises, isChallengeModeStudent);
|
|
898
892
|
setCourseSectionWithProgress(sectionsWithProgress);
|
|
899
893
|
}
|
|
900
|
-
}, [sections, memberCourseCompletions, selectedExercises,
|
|
894
|
+
}, [sections, memberCourseCompletions, selectedExercises, isChallengeModeStudent]);
|
|
901
895
|
const courseSections = courseSectionWithProgress && courseSectionWithProgress.length ? courseSectionWithProgress : sections;
|
|
902
896
|
return /*#__PURE__*/_jsx(_Fragment, {
|
|
903
897
|
children: courseSections.length > 0 ? courseSections.map((section, index) => {
|
|
@@ -20,7 +20,6 @@ function AssignmentExerciseSelector({
|
|
|
20
20
|
lastClickedExerciseId,
|
|
21
21
|
handleRemoveExercise,
|
|
22
22
|
isPreview,
|
|
23
|
-
isChallengeModeEnabled = false,
|
|
24
23
|
isChallengeModeStudent
|
|
25
24
|
}) {
|
|
26
25
|
return /*#__PURE__*/_jsx(Box, {
|
|
@@ -43,7 +42,6 @@ function AssignmentExerciseSelector({
|
|
|
43
42
|
lastClickedExerciseId: lastClickedExerciseId,
|
|
44
43
|
handleRemoveExercise: handleRemoveExercise,
|
|
45
44
|
isPreview: isPreview,
|
|
46
|
-
isChallengeModeEnabled: isChallengeModeEnabled,
|
|
47
45
|
isChallengeModeStudent: isChallengeModeStudent
|
|
48
46
|
})
|
|
49
47
|
});
|
|
@@ -20,7 +20,6 @@ function AssignmentSelectExercise({
|
|
|
20
20
|
preferred_username,
|
|
21
21
|
progressHelpers,
|
|
22
22
|
memberCourseCompletions,
|
|
23
|
-
isChallengeModeEnabled = false,
|
|
24
23
|
isChallengeModeStudent
|
|
25
24
|
}) {
|
|
26
25
|
const [isExerciseSelected, setIsExerciseSelected] = useState(false);
|
|
@@ -94,7 +93,6 @@ function AssignmentSelectExercise({
|
|
|
94
93
|
preferred_username: preferred_username,
|
|
95
94
|
progressHelpers: progressHelpers,
|
|
96
95
|
memberCourseCompletions: memberCourseCompletions,
|
|
97
|
-
isChallengeModeEnabled: isChallengeModeEnabled,
|
|
98
96
|
isChallengeModeStudent: isChallengeModeStudent
|
|
99
97
|
})
|
|
100
98
|
})]
|
|
@@ -50,8 +50,7 @@ export default function CreateAssignmentDialog({
|
|
|
50
50
|
initialData = {},
|
|
51
51
|
dialogTitle,
|
|
52
52
|
userEmail = "",
|
|
53
|
-
assignedStudents
|
|
54
|
-
isChallengeModeEnabled = false
|
|
53
|
+
assignedStudents
|
|
55
54
|
}) {
|
|
56
55
|
const {
|
|
57
56
|
classes
|
|
@@ -447,8 +446,7 @@ export default function CreateAssignmentDialog({
|
|
|
447
446
|
viewOnly: true,
|
|
448
447
|
useCase: "assignment-view",
|
|
449
448
|
handleRemoveExercise: handleRemoveExercise,
|
|
450
|
-
isPreview: true
|
|
451
|
-
isChallengeModeEnabled: isChallengeModeEnabled
|
|
449
|
+
isPreview: true
|
|
452
450
|
})]
|
|
453
451
|
})
|
|
454
452
|
}), /*#__PURE__*/_jsx(Card, {
|
|
@@ -637,8 +635,7 @@ export default function CreateAssignmentDialog({
|
|
|
637
635
|
useCase: "assignment-select",
|
|
638
636
|
selectedExercises: selectedExercises,
|
|
639
637
|
setSelectedExercises: setSelectedExercises,
|
|
640
|
-
setSubmittedExercises: setSubmittedExercises
|
|
641
|
-
isChallengeModeEnabled: isChallengeModeEnabled
|
|
638
|
+
setSubmittedExercises: setSubmittedExercises
|
|
642
639
|
})]
|
|
643
640
|
});
|
|
644
641
|
}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from "react";
|
|
2
|
+
import { Card, CardContent, CardActions, Typography, Avatar, Box, Button, TextField, Chip, Grid } from "@mui/material";
|
|
3
|
+
import { grey, green } from "@mui/material/colors";
|
|
4
|
+
import AutoFixHighIcon from "@mui/icons-material/AutoFixHigh";
|
|
5
|
+
import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline";
|
|
6
|
+
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
|
|
7
|
+
import { Formik } from "formik";
|
|
8
|
+
import * as Yup from "yup";
|
|
9
|
+
import RecordingDialog from "../../Dialogs/RecordingDialog/RecordingDialog";
|
|
10
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
11
|
+
export default function FeedbackCard({
|
|
12
|
+
t = x => x,
|
|
13
|
+
discussionData = {},
|
|
14
|
+
userData = [],
|
|
15
|
+
hasSubmission = false,
|
|
16
|
+
aiGrade = {},
|
|
17
|
+
onGenerateFeedback = () => {},
|
|
18
|
+
onSubmitFeedback = () => {},
|
|
19
|
+
setSelectedRecording = () => {},
|
|
20
|
+
s3Url = "",
|
|
21
|
+
conversation = {},
|
|
22
|
+
existingFeedback = {}
|
|
23
|
+
}) {
|
|
24
|
+
const [isRecordingDialogOpen, setIsRecordingDialogOpen] = useState(false);
|
|
25
|
+
const [hasBeenEdited, setHasBeenEdited] = useState(false);
|
|
26
|
+
const [isSubmitted, setIsSubmitted] = useState(false);
|
|
27
|
+
const [aiJustGenerated, setAiJustGenerated] = useState(false);
|
|
28
|
+
const formikRef = useRef(null);
|
|
29
|
+
const initialValuesRef = useRef(null);
|
|
30
|
+
const selectedMembers = userData.filter(u => [discussionData?.meetingMembers || discussionData?.userIds].flat().includes(u?.memberId));
|
|
31
|
+
const joinedMembers = discussionData?.joinedMembers || [];
|
|
32
|
+
let attendedMembers = [];
|
|
33
|
+
let notAttendedMembers = [];
|
|
34
|
+
if (hasSubmission) {
|
|
35
|
+
attendedMembers = selectedMembers.filter(m => joinedMembers.includes(m?.memberId));
|
|
36
|
+
notAttendedMembers = selectedMembers.filter(m => !joinedMembers.includes(m?.memberId));
|
|
37
|
+
}
|
|
38
|
+
const hasFeedbackSubmitted = hasSubmission && attendedMembers.every(member => {
|
|
39
|
+
const feedback = existingFeedback[member.memberId];
|
|
40
|
+
return feedback && feedback.feedbackText && feedback.feedbackText.trim() !== "";
|
|
41
|
+
});
|
|
42
|
+
const getInitialValues = () => {
|
|
43
|
+
const feedbackData = {};
|
|
44
|
+
if (hasSubmission) {
|
|
45
|
+
attendedMembers.forEach(student => {
|
|
46
|
+
const existingStudentFeedback = existingFeedback[student.memberId];
|
|
47
|
+
feedbackData[student.memberId] = {
|
|
48
|
+
feedbackText: existingStudentFeedback?.feedbackText || ""
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
notAttendedMembers.forEach(student => {
|
|
52
|
+
feedbackData[student.memberId] = {
|
|
53
|
+
feedbackText: existingFeedback[student.memberId]?.feedbackText || t("not_present")
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
selectedMembers.forEach(student => {
|
|
58
|
+
feedbackData[student.memberId] = {
|
|
59
|
+
feedbackText: existingFeedback[student.memberId]?.feedbackText || ""
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
feedbackData
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
const attendeesInThisDiscussion = userData.filter(user => [discussionData?.meetingMembers || discussionData?.userIds].flat().includes(user?.memberId));
|
|
68
|
+
const handleOpenRecordingDialog = () => {
|
|
69
|
+
if (hasSubmission) {
|
|
70
|
+
setSelectedRecording({
|
|
71
|
+
meetingId: discussionData?.meetingId,
|
|
72
|
+
extMeetingId: discussionData?.extMeetingId,
|
|
73
|
+
creator: discussionData?.creator || discussionData?.userId,
|
|
74
|
+
meetingCreator: discussionData?.meetingCreator
|
|
75
|
+
});
|
|
76
|
+
setIsRecordingDialogOpen(true);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
const initialVals = getInitialValues();
|
|
81
|
+
const previous = initialValuesRef.current;
|
|
82
|
+
const hasChanged = JSON.stringify(previous) !== JSON.stringify(initialVals);
|
|
83
|
+
if (hasChanged) {
|
|
84
|
+
initialValuesRef.current = initialVals;
|
|
85
|
+
setIsSubmitted(false);
|
|
86
|
+
}
|
|
87
|
+
}, [existingFeedback, hasSubmission, selectedMembers, attendedMembers, notAttendedMembers, t]);
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
const formik = formikRef.current;
|
|
90
|
+
if (!formik) return;
|
|
91
|
+
if (!hasSubmission || !aiGrade || Object.keys(aiGrade).length === 0) return;
|
|
92
|
+
if (!aiJustGenerated) return;
|
|
93
|
+
userData.forEach(student => {
|
|
94
|
+
const keyVariants = [student.username, `${student.username}Student`, student.username?.replace(/\s+/g, "")];
|
|
95
|
+
const aiData = keyVariants.map(k => aiGrade?.[k]).find(v => v && typeof v === "object") || null;
|
|
96
|
+
if (aiData?.Feedback) {
|
|
97
|
+
formik.setFieldValue(`feedbackData.${student.memberId}.feedbackText`, aiData.Feedback);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
setHasBeenEdited(true);
|
|
101
|
+
setIsSubmitted(false);
|
|
102
|
+
setAiJustGenerated(false);
|
|
103
|
+
}, [aiGrade, hasSubmission, userData, aiJustGenerated]);
|
|
104
|
+
const handleGenerateAI = async () => {
|
|
105
|
+
setAiJustGenerated(true);
|
|
106
|
+
await onGenerateFeedback(discussionData);
|
|
107
|
+
};
|
|
108
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
109
|
+
children: [/*#__PURE__*/_jsx(Formik, {
|
|
110
|
+
innerRef: formikRef,
|
|
111
|
+
initialValues: getInitialValues(),
|
|
112
|
+
validationSchema: getFeedbackValidationSchema(attendedMembers.map(m => m.memberId)),
|
|
113
|
+
onSubmit: async (values, {
|
|
114
|
+
setSubmitting
|
|
115
|
+
}) => {
|
|
116
|
+
setSubmitting(true);
|
|
117
|
+
try {
|
|
118
|
+
const allStudents = selectedMembers.map(m => m.memberId);
|
|
119
|
+
const feedbackDataWithAbsent = {
|
|
120
|
+
...values.feedbackData
|
|
121
|
+
};
|
|
122
|
+
notAttendedMembers.forEach(student => {
|
|
123
|
+
feedbackDataWithAbsent[student.memberId] = {
|
|
124
|
+
feedbackText: t("not_present")
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
await onSubmitFeedback({
|
|
128
|
+
feedbackData: feedbackDataWithAbsent,
|
|
129
|
+
selectedAttendee: allStudents,
|
|
130
|
+
discussionData
|
|
131
|
+
});
|
|
132
|
+
initialValuesRef.current = JSON.parse(JSON.stringify(values));
|
|
133
|
+
setHasBeenEdited(false);
|
|
134
|
+
setIsSubmitted(true);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error("Error submitting feedback:", error);
|
|
137
|
+
} finally {
|
|
138
|
+
setSubmitting(false);
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
enableReinitialize: false,
|
|
142
|
+
children: ({
|
|
143
|
+
values,
|
|
144
|
+
handleSubmit,
|
|
145
|
+
setFieldValue,
|
|
146
|
+
isSubmitting
|
|
147
|
+
}) => {
|
|
148
|
+
const isFormValid = () => {
|
|
149
|
+
if (!hasSubmission) return false;
|
|
150
|
+
return attendedMembers.every(member => {
|
|
151
|
+
const feedback = values.feedbackData[member.memberId];
|
|
152
|
+
return feedback?.feedbackText && feedback.feedbackText.trim() !== "";
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
const hasChanges = () => {
|
|
156
|
+
if (!initialValuesRef.current) return false;
|
|
157
|
+
return attendedMembers.some(member => {
|
|
158
|
+
const current = values.feedbackData[member.memberId]?.feedbackText || "";
|
|
159
|
+
const initial = initialValuesRef.current.feedbackData[member.memberId]?.feedbackText || "";
|
|
160
|
+
return current !== initial;
|
|
161
|
+
});
|
|
162
|
+
};
|
|
163
|
+
const canSubmit = hasSubmission && !isSubmitting && isFormValid() && (hasChanges() || hasBeenEdited) && !isSubmitted;
|
|
164
|
+
return /*#__PURE__*/_jsx("form", {
|
|
165
|
+
onSubmit: handleSubmit,
|
|
166
|
+
children: /*#__PURE__*/_jsxs(Card, {
|
|
167
|
+
sx: {
|
|
168
|
+
mb: 3,
|
|
169
|
+
borderRadius: 3,
|
|
170
|
+
boxShadow: 3,
|
|
171
|
+
overflow: "hidden"
|
|
172
|
+
},
|
|
173
|
+
children: [/*#__PURE__*/_jsx(Box, {
|
|
174
|
+
sx: {
|
|
175
|
+
px: 3,
|
|
176
|
+
pt: 2,
|
|
177
|
+
pb: 1,
|
|
178
|
+
fontWeight: 600,
|
|
179
|
+
color: "text.secondary"
|
|
180
|
+
},
|
|
181
|
+
children: /*#__PURE__*/_jsxs(Grid, {
|
|
182
|
+
container: true,
|
|
183
|
+
alignItems: "center",
|
|
184
|
+
spacing: 3,
|
|
185
|
+
children: [/*#__PURE__*/_jsx(Grid, {
|
|
186
|
+
size: {
|
|
187
|
+
xs: 12,
|
|
188
|
+
md: 2.5
|
|
189
|
+
},
|
|
190
|
+
children: /*#__PURE__*/_jsx(Typography, {
|
|
191
|
+
variant: "subtitle2",
|
|
192
|
+
children: t("student")
|
|
193
|
+
})
|
|
194
|
+
}), /*#__PURE__*/_jsx(Grid, {
|
|
195
|
+
size: {
|
|
196
|
+
xs: 12,
|
|
197
|
+
md: 9.5
|
|
198
|
+
},
|
|
199
|
+
children: /*#__PURE__*/_jsx(Typography, {
|
|
200
|
+
variant: "subtitle2",
|
|
201
|
+
children: t("feedback")
|
|
202
|
+
})
|
|
203
|
+
})]
|
|
204
|
+
})
|
|
205
|
+
}), /*#__PURE__*/_jsx(CardContent, {
|
|
206
|
+
sx: {
|
|
207
|
+
px: 3,
|
|
208
|
+
pt: 1
|
|
209
|
+
},
|
|
210
|
+
children: [...selectedMembers].sort((a, b) => {
|
|
211
|
+
const aJoined = joinedMembers.includes(a.memberId);
|
|
212
|
+
const bJoined = joinedMembers.includes(b.memberId);
|
|
213
|
+
return aJoined === bJoined ? 0 : aJoined ? -1 : 1;
|
|
214
|
+
}).map(student => {
|
|
215
|
+
const isAbsent = hasSubmission && !joinedMembers.includes(student.memberId);
|
|
216
|
+
const disabled = !hasSubmission || isAbsent;
|
|
217
|
+
const studentFeedback = values.feedbackData[student.memberId] || {};
|
|
218
|
+
return /*#__PURE__*/_jsx(Box, {
|
|
219
|
+
sx: {
|
|
220
|
+
py: 2
|
|
221
|
+
},
|
|
222
|
+
children: /*#__PURE__*/_jsxs(Grid, {
|
|
223
|
+
container: true,
|
|
224
|
+
alignItems: "flex-start",
|
|
225
|
+
spacing: 3,
|
|
226
|
+
children: [/*#__PURE__*/_jsx(Grid, {
|
|
227
|
+
size: {
|
|
228
|
+
xs: 12,
|
|
229
|
+
md: 2.5
|
|
230
|
+
},
|
|
231
|
+
children: /*#__PURE__*/_jsxs(Box, {
|
|
232
|
+
display: "flex",
|
|
233
|
+
alignItems: "center",
|
|
234
|
+
gap: 2,
|
|
235
|
+
children: [/*#__PURE__*/_jsx(Avatar, {
|
|
236
|
+
alt: student.username,
|
|
237
|
+
src: student.userImage,
|
|
238
|
+
sx: {
|
|
239
|
+
width: 48,
|
|
240
|
+
height: 48,
|
|
241
|
+
filter: isAbsent ? "grayscale(100%)" : "none"
|
|
242
|
+
}
|
|
243
|
+
}), /*#__PURE__*/_jsx(Typography, {
|
|
244
|
+
fontWeight: 600,
|
|
245
|
+
sx: {
|
|
246
|
+
color: isAbsent ? grey[500] : "text.primary"
|
|
247
|
+
},
|
|
248
|
+
children: student.username
|
|
249
|
+
})]
|
|
250
|
+
})
|
|
251
|
+
}), /*#__PURE__*/_jsx(Grid, {
|
|
252
|
+
size: {
|
|
253
|
+
xs: 12,
|
|
254
|
+
md: 9.5
|
|
255
|
+
},
|
|
256
|
+
children: /*#__PURE__*/_jsx(TextField, {
|
|
257
|
+
variant: "outlined",
|
|
258
|
+
fullWidth: true,
|
|
259
|
+
multiline: true,
|
|
260
|
+
disabled: disabled,
|
|
261
|
+
value: studentFeedback.feedbackText || "",
|
|
262
|
+
onChange: e => {
|
|
263
|
+
setFieldValue(`feedbackData.${student.memberId}.feedbackText`, e.target.value);
|
|
264
|
+
setHasBeenEdited(true);
|
|
265
|
+
setIsSubmitted(false);
|
|
266
|
+
},
|
|
267
|
+
placeholder: t("Write your feedback here")
|
|
268
|
+
})
|
|
269
|
+
})]
|
|
270
|
+
})
|
|
271
|
+
}, student.memberId);
|
|
272
|
+
})
|
|
273
|
+
}), /*#__PURE__*/_jsxs(CardActions, {
|
|
274
|
+
sx: {
|
|
275
|
+
px: 3,
|
|
276
|
+
py: 2,
|
|
277
|
+
justifyContent: "space-between",
|
|
278
|
+
alignItems: "center",
|
|
279
|
+
flexWrap: "wrap",
|
|
280
|
+
gap: 1.5
|
|
281
|
+
},
|
|
282
|
+
children: [/*#__PURE__*/_jsxs(Box, {
|
|
283
|
+
sx: {
|
|
284
|
+
display: "flex",
|
|
285
|
+
gap: 1.5
|
|
286
|
+
},
|
|
287
|
+
children: [!hasSubmission && /*#__PURE__*/_jsx(Chip, {
|
|
288
|
+
label: t("group_not_submitted"),
|
|
289
|
+
color: "warning",
|
|
290
|
+
variant: "filled",
|
|
291
|
+
icon: /*#__PURE__*/_jsx(ErrorOutlineIcon, {}),
|
|
292
|
+
sx: {
|
|
293
|
+
fontWeight: 500,
|
|
294
|
+
borderRadius: "20px"
|
|
295
|
+
}
|
|
296
|
+
}), hasFeedbackSubmitted && /*#__PURE__*/_jsx(Chip, {
|
|
297
|
+
label: t("feedback_submitted"),
|
|
298
|
+
color: "success",
|
|
299
|
+
variant: "filled",
|
|
300
|
+
icon: /*#__PURE__*/_jsx(CheckCircleIcon, {}),
|
|
301
|
+
sx: {
|
|
302
|
+
fontWeight: 500,
|
|
303
|
+
borderRadius: "20px",
|
|
304
|
+
bgcolor: green[600]
|
|
305
|
+
}
|
|
306
|
+
})]
|
|
307
|
+
}), /*#__PURE__*/_jsxs(Box, {
|
|
308
|
+
sx: {
|
|
309
|
+
display: "flex",
|
|
310
|
+
gap: 1.5,
|
|
311
|
+
ml: "auto"
|
|
312
|
+
},
|
|
313
|
+
children: [/*#__PURE__*/_jsx(Button, {
|
|
314
|
+
variant: "outlined",
|
|
315
|
+
disabled: !hasSubmission,
|
|
316
|
+
onClick: handleOpenRecordingDialog,
|
|
317
|
+
children: t("view_recording")
|
|
318
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
319
|
+
variant: "contained",
|
|
320
|
+
color: "secondary",
|
|
321
|
+
disabled: !hasSubmission,
|
|
322
|
+
onClick: handleGenerateAI,
|
|
323
|
+
endIcon: /*#__PURE__*/_jsx(AutoFixHighIcon, {}),
|
|
324
|
+
children: t("generate_feedback")
|
|
325
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
326
|
+
type: "submit",
|
|
327
|
+
variant: "contained",
|
|
328
|
+
disabled: !canSubmit,
|
|
329
|
+
children: isSubmitting ? t("submitting") : t("submit_feedback")
|
|
330
|
+
})]
|
|
331
|
+
})]
|
|
332
|
+
})]
|
|
333
|
+
})
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}), /*#__PURE__*/_jsx(RecordingDialog, {
|
|
337
|
+
t: t,
|
|
338
|
+
open: isRecordingDialogOpen,
|
|
339
|
+
handleClose: () => setIsRecordingDialogOpen(false),
|
|
340
|
+
meetingID: discussionData?.meetingID || discussionData?.meetingId,
|
|
341
|
+
meetingPrompt: discussionData?.meetingPrompt,
|
|
342
|
+
meetingTopic: discussionData?.meetingTopic,
|
|
343
|
+
isTeacher: true,
|
|
344
|
+
attendeesData: attendeesInThisDiscussion,
|
|
345
|
+
conversation: conversation,
|
|
346
|
+
s3Url: s3Url,
|
|
347
|
+
playerRef: {
|
|
348
|
+
current: null
|
|
349
|
+
},
|
|
350
|
+
aiGrade: aiGrade,
|
|
351
|
+
hasBadLanguage: discussionData?.hasBadLanguage || false
|
|
352
|
+
})]
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
const getFeedbackValidationSchema = attendedMemberIds => {
|
|
356
|
+
return Yup.object().shape({
|
|
357
|
+
feedbackData: Yup.object().test("all-attended-filled", "All attended students must have feedback", function (value) {
|
|
358
|
+
if (!attendedMemberIds || attendedMemberIds.length === 0) return true;
|
|
359
|
+
return attendedMemberIds.every(memberId => {
|
|
360
|
+
const feedback = value?.[memberId];
|
|
361
|
+
return feedback?.feedbackText && feedback.feedbackText.trim() !== "";
|
|
362
|
+
});
|
|
363
|
+
})
|
|
364
|
+
});
|
|
365
|
+
};
|