@nualang/nualang-ui-components 0.1.1332 → 0.1.1333

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.
@@ -1,10 +1,10 @@
1
1
  import React, { useState, useEffect } from "react";
2
2
  import PropTypes from "prop-types";
3
- import { Typography, Box, IconButton, Tooltip, Button, Skeleton, Select, MenuItem, FormControl, InputLabel } from "@mui/material";
3
+ import { Typography, Box, IconButton, Tooltip, Skeleton, Select, MenuItem, FormControl, InputLabel } from "@mui/material";
4
4
  import AssignmentCard from "../AssignmentCard/AssignmentCard";
5
5
  import Refresh from "@mui/icons-material/Refresh";
6
6
  import TeacherCreate from "../../img/teacher-create-2.svg";
7
- import Add from "@mui/icons-material/Add";
7
+ import InfiniteScroll from "../../Misc/InfiniteScroll/InfiniteScroll";
8
8
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
9
  const VISIBILITY_LEAD_MINUTES = 5; // how many minutes before scheduleDate it becomes visible to students
10
10
 
@@ -12,7 +12,6 @@ const AssignmentCardsList = ({
12
12
  t = text => text,
13
13
  assignments = [],
14
14
  isCreator,
15
- handleCreateAssignment,
16
15
  getCourses,
17
16
  getCourseSections,
18
17
  getRoleplays,
@@ -28,12 +27,13 @@ const AssignmentCardsList = ({
28
27
  lastAssignmentFetch,
29
28
  assignmentMembersById = {},
30
29
  isLoadingAssignments,
31
- members,
32
- courses,
33
- isChallengeModeStudent
30
+ isChallengeModeStudent,
31
+ scrollableTarget = null
34
32
  }) => {
35
33
  const [lastClickedExerciseId, setLastClickedExerciseId] = useState(null);
36
34
  const [filter, setFilter] = useState("all");
35
+ const BATCH_SIZE = 6;
36
+ const [cardsToShow, setCardsToShow] = useState(BATCH_SIZE);
37
37
  useEffect(() => {
38
38
  const stored = localStorage.getItem("lastClickedExercise");
39
39
  if (stored) {
@@ -49,6 +49,10 @@ const AssignmentCardsList = ({
49
49
  }, []);
50
50
  const now = new Date();
51
51
  const safeAssignments = Array.isArray(assignments) ? assignments : [];
52
+ useEffect(() => {
53
+ setCardsToShow(BATCH_SIZE);
54
+ if (window.scrollY > 100) window.scrollTo(0, 0);
55
+ }, [filter, safeAssignments.length]);
52
56
  const filteredAssignments = safeAssignments.filter(assignment => {
53
57
  if (!isCreator) {
54
58
  if (Array.isArray(assignment.assignedStudents) && !assignment.assignedStudents.includes(memberId)) {
@@ -73,14 +77,8 @@ const AssignmentCardsList = ({
73
77
  if (filter === "pastDue") {
74
78
  return assignment.dueDate && new Date(assignment.dueDate) < now;
75
79
  }
76
- if (filter === "dueNext") {
77
- return assignment.dueDate && new Date(assignment.dueDate) >= now;
78
- }
79
80
  return true;
80
81
  }).sort((a, b) => {
81
- if (filter === "dueNext") {
82
- return new Date(a.dueDate || 0) - new Date(b.dueDate || 0);
83
- }
84
82
  if (filter === "scheduled") {
85
83
  return new Date(a.scheduleDate || 0) - new Date(b.scheduleDate || 0);
86
84
  }
@@ -159,99 +157,120 @@ const AssignmentCardsList = ({
159
157
  });
160
158
  }
161
159
  if (!safeAssignments.length || filteredAssignments.length === 0) {
162
- return /*#__PURE__*/_jsx(Box, {
160
+ const getEmptyStateMessage = () => {
161
+ if (!safeAssignments.length) {
162
+ return {
163
+ title: t("no_assignments"),
164
+ description: isCreator ? t("assignments_description") : t("no_assignments_description")
165
+ };
166
+ }
167
+ switch (filter) {
168
+ case "scheduled":
169
+ return {
170
+ title: t("no_scheduled_assignments"),
171
+ description: null
172
+ };
173
+ case "pastDue":
174
+ return {
175
+ title: t("no_past_due_assignments"),
176
+ description: null
177
+ };
178
+ default:
179
+ return {
180
+ title: t("no_assignments"),
181
+ description: isCreator ? t("assignments_description") : t("no_assignments_description")
182
+ };
183
+ }
184
+ };
185
+ const emptyState = getEmptyStateMessage();
186
+ return /*#__PURE__*/_jsxs(Box, {
163
187
  mb: 1,
164
- children: /*#__PURE__*/_jsxs(Box, {
188
+ children: [isCreator && /*#__PURE__*/_jsxs(Box, {
189
+ display: "flex",
190
+ justifyContent: "space-between",
165
191
  alignItems: "center",
166
192
  sx: {
167
- my: 2
193
+ mb: 3,
194
+ mt: "8px"
168
195
  },
169
- display: "flex",
170
- flexDirection: "column",
171
- children: [/*#__PURE__*/_jsxs(Box, {
172
- display: "flex",
173
- alignItems: "center",
196
+ children: [/*#__PURE__*/_jsxs(FormControl, {
197
+ size: "large",
174
198
  sx: {
175
- width: "100%"
199
+ minWidth: 140,
200
+ marginTop: 1
176
201
  },
177
- children: [/*#__PURE__*/_jsx(Box, {
178
- sx: {
179
- flexGrow: 1,
180
- textAlign: "center",
181
- marginLeft: 5
182
- },
183
- children: /*#__PURE__*/_jsx(Typography, {
184
- variant: "h5",
185
- fontWeight: "bold",
186
- children: t("no_assignments")
187
- })
188
- }), /*#__PURE__*/_jsx(Tooltip, {
189
- placement: "left",
190
- title: t("refresh_assignments"),
191
- children: /*#__PURE__*/_jsx(IconButton, {
192
- onClick: refreshAssignments,
193
- "aria-label": "refresh",
194
- size: "large",
195
- children: /*#__PURE__*/_jsx(Refresh, {})
196
- })
202
+ children: [/*#__PURE__*/_jsx(InputLabel, {
203
+ children: t("view")
204
+ }), /*#__PURE__*/_jsxs(Select, {
205
+ value: filter,
206
+ onChange: e => setFilter(e.target.value),
207
+ label: t("view"),
208
+ autoWidth: true,
209
+ children: [/*#__PURE__*/_jsx(MenuItem, {
210
+ value: "all",
211
+ children: t("all")
212
+ }), /*#__PURE__*/_jsx(MenuItem, {
213
+ value: "pastDue",
214
+ children: t("past_due")
215
+ }), /*#__PURE__*/_jsx(MenuItem, {
216
+ value: "scheduled",
217
+ children: t("scheduled")
218
+ })]
197
219
  })]
198
- }), !isCreator ? /*#__PURE__*/_jsx(Typography, {
220
+ }), /*#__PURE__*/_jsx(Tooltip, {
221
+ placement: "left",
222
+ title: t("refresh_assignments"),
223
+ children: /*#__PURE__*/_jsx(IconButton, {
224
+ onClick: refreshAssignments,
225
+ "aria-label": "refresh",
226
+ size: "large",
227
+ children: /*#__PURE__*/_jsx(Refresh, {
228
+ fontSize: "inherit"
229
+ })
230
+ })
231
+ })]
232
+ }), /*#__PURE__*/_jsxs(Box, {
233
+ alignItems: "center",
234
+ sx: {
235
+ my: 2
236
+ },
237
+ display: "flex",
238
+ flexDirection: "column",
239
+ children: [/*#__PURE__*/_jsx(Typography, {
240
+ variant: "h5",
241
+ fontWeight: "bold",
199
242
  sx: {
200
- textAlign: "center",
201
- mt: 2,
202
- width: "70%"
243
+ textAlign: "center"
203
244
  },
204
- children: t("no_assignments_description")
205
- }) : /*#__PURE__*/_jsx(Typography, {
245
+ children: emptyState.title
246
+ }), /*#__PURE__*/_jsx(Typography, {
206
247
  sx: {
207
248
  textAlign: "center",
208
249
  mt: 2,
209
250
  width: "70%"
210
251
  },
211
- children: t("assignments_description")
212
- }), isCreator && (!members || members.length === 0 || !courses || courses.length === 0 ? /*#__PURE__*/_jsx(Tooltip, {
213
- title: t("no_members_tooltip"),
214
- children: /*#__PURE__*/_jsx("span", {
215
- children: /*#__PURE__*/_jsx(Button, {
216
- variant: "contained",
217
- color: "primary",
218
- sx: {
219
- mt: 2,
220
- textAlign: "center"
221
- },
222
- startIcon: /*#__PURE__*/_jsx(Add, {}),
223
- onClick: handleCreateAssignment,
224
- disabled: true,
225
- children: t("create_assignment")
226
- })
227
- })
228
- }) : /*#__PURE__*/_jsx(Button, {
229
- variant: "contained",
230
- color: "primary",
231
- sx: {
232
- mt: 2,
233
- textAlign: "center"
234
- },
235
- startIcon: /*#__PURE__*/_jsx(Add, {}),
236
- onClick: handleCreateAssignment,
237
- children: t("create_assignment")
238
- })), /*#__PURE__*/_jsx(Box, {
252
+ children: emptyState.description
253
+ }), /*#__PURE__*/_jsx(Box, {
239
254
  sx: {
240
255
  height: "100%",
241
256
  display: "flex",
242
257
  flexGrow: 1,
243
258
  alignItems: "center",
244
259
  justifyContent: "center",
245
- maxWidth: "400px",
260
+ maxWidth: 300,
246
261
  marginRight: "40px",
247
262
  paddingTop: "20px"
248
263
  },
249
264
  children: /*#__PURE__*/_jsx("img", {
250
265
  src: TeacherCreate,
251
- alt: "teacher-create"
266
+ alt: "teacher-create",
267
+ style: {
268
+ width: "100%",
269
+ height: "auto"
270
+ }
252
271
  })
253
272
  })]
254
- })
273
+ })]
255
274
  });
256
275
  }
257
276
  return /*#__PURE__*/_jsxs(Box, {
@@ -280,9 +299,6 @@ const AssignmentCardsList = ({
280
299
  children: [/*#__PURE__*/_jsx(MenuItem, {
281
300
  value: "all",
282
301
  children: t("all")
283
- }), /*#__PURE__*/_jsx(MenuItem, {
284
- value: "dueNext",
285
- children: t("due_next")
286
302
  }), /*#__PURE__*/_jsx(MenuItem, {
287
303
  value: "pastDue",
288
304
  children: t("past_due")
@@ -303,27 +319,33 @@ const AssignmentCardsList = ({
303
319
  })
304
320
  })
305
321
  })]
306
- }), filteredAssignments.map((assignment, index) => /*#__PURE__*/_jsx(AssignmentCard, {
307
- index: index,
308
- lastAssignmentFetch: lastAssignmentFetch,
309
- assignment: assignment,
310
- t: t,
311
- isCreator: isCreator,
312
- getCourses: getCourses,
313
- getCourseSections: getCourseSections,
314
- getRoleplays: getRoleplays,
315
- deleteAssignment: deleteAssignment,
316
- handleEditAssignment: handleEditAssignment,
317
- lastClickedExerciseId: lastClickedExerciseId,
318
- progressHelpers: progressHelpers,
319
- fetchMemberCourseCompletions: fetchMemberCourseCompletions,
320
- username: username,
321
- preferred_username: preferred_username,
322
- memberId: memberId,
323
- handleViewProgress: handleViewProgress,
324
- assignedStudents: assignmentMembersById[assignment.assignmentId] || [],
325
- isChallengeModeStudent: isChallengeModeStudent
326
- }, assignment.assignmentId))]
322
+ }), /*#__PURE__*/_jsx(InfiniteScroll, {
323
+ dataLength: Math.min(cardsToShow, filteredAssignments.length),
324
+ loadMore: () => setCardsToShow(prev => prev + BATCH_SIZE),
325
+ hasMore: cardsToShow < filteredAssignments.length,
326
+ scrollableTarget: scrollableTarget,
327
+ children: filteredAssignments.slice(0, cardsToShow).map((assignment, index) => /*#__PURE__*/_jsx(AssignmentCard, {
328
+ index: index,
329
+ lastAssignmentFetch: lastAssignmentFetch,
330
+ assignment: assignment,
331
+ t: t,
332
+ isCreator: isCreator,
333
+ getCourses: getCourses,
334
+ getCourseSections: getCourseSections,
335
+ getRoleplays: getRoleplays,
336
+ deleteAssignment: deleteAssignment,
337
+ handleEditAssignment: handleEditAssignment,
338
+ lastClickedExerciseId: lastClickedExerciseId,
339
+ progressHelpers: progressHelpers,
340
+ fetchMemberCourseCompletions: fetchMemberCourseCompletions,
341
+ username: username,
342
+ preferred_username: preferred_username,
343
+ memberId: memberId,
344
+ handleViewProgress: handleViewProgress,
345
+ assignedStudents: assignmentMembersById[assignment.assignmentId] || [],
346
+ isChallengeModeStudent: isChallengeModeStudent
347
+ }, assignment.assignmentId))
348
+ })]
327
349
  });
328
350
  };
329
351
  AssignmentCardsList.propTypes = {
@@ -348,6 +370,7 @@ AssignmentCardsList.propTypes = {
348
370
  isLoadingAssignments: PropTypes.bool,
349
371
  members: PropTypes.array,
350
372
  courses: PropTypes.array,
351
- isChallengeModeStudent: PropTypes.bool
373
+ isChallengeModeStudent: PropTypes.bool,
374
+ scrollableTarget: PropTypes.oneOfType([PropTypes.string, PropTypes.object])
352
375
  };
353
376
  export default AssignmentCardsList;
@@ -441,7 +441,7 @@ export default function Message({
441
441
  fontWeight: "bold",
442
442
  align: "left",
443
443
  children: name
444
- }), studentInappropriate && /*#__PURE__*/_jsx(Tooltip, {
444
+ }), studentInappropriate && isMyMessage && /*#__PURE__*/_jsx(Tooltip, {
445
445
  title: t("inappropriate_language_detected"),
446
446
  children: /*#__PURE__*/_jsx(WarningAmberIcon, {
447
447
  style: {
@@ -464,7 +464,6 @@ export default function Message({
464
464
  })
465
465
  })]
466
466
  }), !isListenOnly && /*#__PURE__*/_jsx(HoverText, {
467
- studentInappropriate: studentInappropriate,
468
467
  handleTranslate: handleTranslate,
469
468
  learnLang: learnLang,
470
469
  forLang: forLang,
@@ -491,7 +490,7 @@ export default function Message({
491
490
  style: {
492
491
  position: "relative"
493
492
  },
494
- children: [studentInappropriate && /*#__PURE__*/_jsx(Tooltip, {
493
+ children: [studentInappropriate && isMyMessage && /*#__PURE__*/_jsx(Tooltip, {
495
494
  title: t("inappropriate_language_detected"),
496
495
  children: /*#__PURE__*/_jsx(WarningAmberIcon, {
497
496
  className: classes.inappropriateIcon,
@@ -528,7 +527,6 @@ export default function Message({
528
527
  })
529
528
  })]
530
529
  }), !isListenOnly && /*#__PURE__*/_jsx(HoverText, {
531
- studentInappropriate: studentInappropriate,
532
530
  handleTranslate: handleTranslate,
533
531
  learnLang: learnLang,
534
532
  forLang: forLang,
@@ -391,6 +391,11 @@ function LiveListener({
391
391
  onChange: handleInputChange,
392
392
  onKeyDown: e => {
393
393
  if (e.key === "Enter") {
394
+ e.preventDefault();
395
+ e.stopPropagation();
396
+ if ((!listeningText || listeningText.trim() === "") && (!listeningWords || listeningWords.length === 0)) {
397
+ return;
398
+ }
394
399
  setIsAnswered(true);
395
400
  setCurrentAnswer(listeningText ? listeningText : listeningWords);
396
401
  e.stopPropagation();
@@ -587,9 +587,13 @@ function LiveTranslator({
587
587
  onChange: handleInputChange,
588
588
  onKeyDown: e => {
589
589
  if (e.key === "Enter") {
590
+ e.preventDefault();
591
+ e.stopPropagation();
592
+ if ((!translationText || translationText.trim() === "") && (!translationWords || translationWords.length === 0)) {
593
+ return;
594
+ }
590
595
  setIsAnswered(true);
591
596
  setCurrentAnswer(translationText ? translationText : translationWords);
592
- e.stopPropagation();
593
597
  }
594
598
  },
595
599
  id: "translationText",
@@ -54,6 +54,12 @@ function LanguageSelector({
54
54
  }, {
55
55
  value: "uk",
56
56
  label: "українська"
57
+ }, {
58
+ value: "zh",
59
+ label: "中文"
60
+ }, {
61
+ value: "ja",
62
+ label: "日本語"
57
63
  }]
58
64
  }) {
59
65
  const {
@@ -97,6 +97,26 @@ function ResponsiveTabs({
97
97
  sx: {
98
98
  "@media print": {
99
99
  display: "none"
100
+ },
101
+ "& .MuiTab-root": {
102
+ transition: theme.transitions.create(["background-color", "color"], {
103
+ duration: theme.transitions.duration.shorter
104
+ }),
105
+ "&:hover": {
106
+ backgroundColor: theme.palette.action.hover
107
+ },
108
+ "&.Mui-selected": {
109
+ color: theme.palette.primary.main,
110
+ "&:hover": {
111
+ backgroundColor: theme.palette.primary.light + "20"
112
+ }
113
+ },
114
+ "&.Mui-focusVisible": {
115
+ backgroundColor: theme.palette.action.focus
116
+ }
117
+ },
118
+ "& .MuiTabs-indicator": {
119
+ height: 3
100
120
  }
101
121
  },
102
122
  children: tabs.map(({
@@ -471,10 +471,17 @@ export default function Attempt({
471
471
  stop();
472
472
  setIsTranscriptPlaying(false);
473
473
  };
474
- const hasInappropriate = useMemo(() => (messages || []).some(m => m.studentInappropriate), [messages]);
474
+ const hasInappropriate = useMemo(() => {
475
+ if (!messages || messages.length === 0) {
476
+ return false;
477
+ }
478
+ return (messages || []).some(m => {
479
+ return m?.studentInappropriate;
480
+ });
481
+ }, [messages]);
475
482
  return /*#__PURE__*/_jsxs("div", {
476
483
  className: classes.root,
477
- children: [hasInappropriate && isCreator && /*#__PURE__*/_jsxs("div", {
484
+ children: [hasInappropriate && /*#__PURE__*/_jsxs("div", {
478
485
  style: {
479
486
  backgroundColor: "#ffcccc",
480
487
  padding: "10px",
@@ -318,6 +318,7 @@ function OverflowMenu({
318
318
  });
319
319
  }
320
320
  function ClassroomLoading({
321
+ isLoading,
321
322
  t = text => text
322
323
  }) {
323
324
  const {
@@ -409,9 +410,20 @@ function ClassroomLoading({
409
410
  t: t,
410
411
  courses: null
411
412
  })
412
- }), /*#__PURE__*/_jsxs(Box, {
413
+ }), /*#__PURE__*/_jsx(Box, {
414
+ py: 1,
415
+ children: /*#__PURE__*/_jsx(AssignmentCardsList, {
416
+ isLoadingAssignments: true,
417
+ t: t,
418
+ assignments: null
419
+ })
420
+ }), /*#__PURE__*/_jsx(Box, {
413
421
  py: 1,
414
- children: [t("loading"), "..."]
422
+ children: /*#__PURE__*/_jsx(ProgressTable, {
423
+ isLoading: isLoading,
424
+ t: t,
425
+ progress: null
426
+ })
415
427
  }), /*#__PURE__*/_jsx(Box, {
416
428
  py: 1,
417
429
  children: /*#__PURE__*/_jsx(MemberList, {
@@ -1024,7 +1036,7 @@ function Classroom({
1024
1036
  })
1025
1037
  })
1026
1038
  }), /*#__PURE__*/_jsx(_Fragment, {
1027
- children: isCreator && createdDiscussions?.length > 0 && /*#__PURE__*/_jsx("div", {
1039
+ children: isCreator && /*#__PURE__*/_jsx("div", {
1028
1040
  id: "discussGroupedDiscussions",
1029
1041
  children: /*#__PURE__*/_jsx(GroupedDiscussions, {
1030
1042
  t: t,
@@ -1057,7 +1069,7 @@ function Classroom({
1057
1069
  learnLang: classroom?.learnLang
1058
1070
  })
1059
1071
  })
1060
- }), !isCreator && discussions?.length > 0 && /*#__PURE__*/_jsx(Box, {
1072
+ }), !isCreator && /*#__PURE__*/_jsx(Box, {
1061
1073
  marginTop: "78px",
1062
1074
  children: /*#__PURE__*/_jsx("div", {
1063
1075
  id: "discussScheduled",
@@ -1071,7 +1083,7 @@ function Classroom({
1071
1083
  scheduleListData: discussions
1072
1084
  })
1073
1085
  })
1074
- }), !isCreator && recordingDiscussions?.length > 0 && /*#__PURE__*/_jsx("div", {
1086
+ }), !isCreator && /*#__PURE__*/_jsx("div", {
1075
1087
  id: "discussRecorded",
1076
1088
  children: /*#__PURE__*/_jsx(RecordingListCards, {
1077
1089
  t: t,
@@ -1089,9 +1101,6 @@ function Classroom({
1089
1101
  s3EventsUrl: s3EventsUrl,
1090
1102
  userData: classroomMembers || []
1091
1103
  })
1092
- }), isNoVideoChatContent && /*#__PURE__*/_jsx(DiscussionNotFound, {
1093
- t: t,
1094
- placeholderImageUrl: placeholderImageUrl
1095
1104
  })]
1096
1105
  }, `tab-content-video-chat-member`) : isCreator && isVideoChatEnabled && /*#__PURE__*/_jsx("div", {
1097
1106
  className: classes.placeholder,
@@ -1657,9 +1666,10 @@ export default function ViewClassroom({
1657
1666
  className: classes.root,
1658
1667
  children: [isLoading && Object.keys(classroom).length === 0 && /*#__PURE__*/_jsx(_Fragment, {
1659
1668
  children: /*#__PURE__*/_jsx(ClassroomLoading, {
1669
+ isLoading: isLoading,
1660
1670
  t: t
1661
1671
  })
1662
- }), !isLoading && classroom && Object.keys(classroom).length > 0 && /*#__PURE__*/_jsx(_Fragment, {
1672
+ }), classroom && Object.keys(classroom).length > 0 && /*#__PURE__*/_jsx(_Fragment, {
1663
1673
  children: /*#__PURE__*/_jsx(Classroom, {
1664
1674
  t: t,
1665
1675
  isLoading: isLoading,
@@ -42,7 +42,7 @@ function Onboard({
42
42
  img: "",
43
43
  role: "teach"
44
44
  }],
45
- languages = ["spanish", "french", "english", "italian", "german", "portuguese"],
45
+ languages = ["spanish", "french", "english", "italian", "german", "portuguese", "chinese", "japanese"],
46
46
  preferred_username,
47
47
  learnlang
48
48
  }) {