@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.
Files changed (29) hide show
  1. package/dist/Assignments/AssignmentCourseSelection/AssignmentCourseSelection.js +1 -6
  2. package/dist/Assignments/AssignmentExerciseSelection/AssignmentExerciseSelection.js +3 -9
  3. package/dist/Assignments/AssignmentExerciseSelector/AssignmentExerciseSelector.js +0 -2
  4. package/dist/Assignments/AssignmentSelectExercise/AssignmentSelectExercise.js +0 -2
  5. package/dist/Assignments/CreateAssignmentDialog/CreateAssignmentDialog.js +3 -6
  6. package/dist/Cards/FeedbackCard/FeedbackCard.js +365 -0
  7. package/dist/Cards/RecordingCard/RecordingCard.js +161 -120
  8. package/dist/Cards/ScheduleCard/ScheduleCard.js +97 -57
  9. package/dist/Dialogs/GenerateDiscussion/GenerateDiscussion.js +171 -0
  10. package/dist/Dialogs/GroupedFeedbackDialog/GroupedFeedbackDialog.js +273 -0
  11. package/dist/Dialogs/RecordingDialog/RecordingDialog.js +61 -43
  12. package/dist/Forms/CreateMeetingMultiStepForm/CreateMeetingMultiStepForm.js +15 -3
  13. package/dist/Forms/CreateMeetingMultiStepForm/MeetingForm.js +144 -113
  14. package/dist/Lists/CourseOutline/CourseOutline.js +11 -26
  15. package/dist/Screens/Classrooms/ViewClassroom/ViewClassroom.js +7 -3
  16. package/dist/Screens/Courses/ViewCourse/ViewCourse.js +3 -1
  17. package/dist/Screens/Courses/ViewCourse/ViewTopic/ViewTopic.js +2 -2
  18. package/dist/Tables/MeetingPrompstList/MeetingPromptsList.js +23 -31
  19. package/dist/Tables/Progress/Progress.js +0 -1
  20. package/dist/Tables/Progress/ProgressTable.js +46 -30
  21. package/dist/Tables/Progress/utils.js +4 -4
  22. package/dist/Tables/ScheduleListCards/ScheduleListCards.js +2 -86
  23. package/dist/img/NualaHeadphonesBackground.svg +39 -0
  24. package/dist/img/aaronAvatar.png +0 -0
  25. package/dist/img/connorAvatar.png +0 -0
  26. package/dist/img/jamieAvatar.png +0 -0
  27. package/dist/img/stephenAvatar.png +0 -0
  28. package/dist/utils/index.js +6 -29
  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, true);
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, isChallengeModeEnabled]);
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
+ };