@nualang/nualang-ui-components 0.1.1432 → 0.1.1433
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/AssignmentBotSelection/AssignmentBotSelection.js +211 -57
- package/dist/Assignments/AssignmentExerciseSelection/AssignmentExerciseSelection.js +5 -2
- package/dist/Assignments/AssignmentSelectExercise/AssignmentSelectExercise.js +15 -4
- package/dist/Chat/AudioOnly/AudioOnlyChat.js +698 -0
- package/dist/Chat/BottomBar/BottomBar.js +59 -63
- package/dist/Chat/Chat.js +57 -3
- package/dist/Dialogs/QuickCreateTopicDialog/QuickCreateTopicDialog.js +0 -5
- package/dist/Exercises/Bot/Bot.js +409 -21
- package/dist/Exercises/Bot/Bot.test.js +2 -1
- package/dist/Forms/ImageSelector/ImageSelector.js +72 -80
- package/dist/Lists/Exercises/Exercises.js +1 -1
- package/dist/Lists/Timeline/EventItem.js +2 -2
- package/dist/Tables/Progress/Progress.js +10 -0
- package/dist/Tables/Progress/ProgressList.js +102 -4
- package/dist/Tables/Progress/ProgressTable.js +104 -3
- package/dist/Tables/Progress/ProgressTableRow.js +18 -0
- package/dist/Tables/Progress/cells/index.js +7 -1
- package/dist/Tables/Progress/constants.js +10 -2
- package/dist/Tables/Progress/useProgressUrlParams.js +19 -1
- package/dist/Tables/Progress/utils.js +2 -0
- package/dist/Tables/Progress/viewState.js +4 -1
- package/dist/hooks/useExerciseState.js +36 -9
- package/dist/hooks/useRecognition.js +48 -10
- package/dist/utils/canvasUtils.js +66 -34
- package/dist/utils/index.js +2 -1
- package/package.json +1 -1
|
@@ -1,16 +1,30 @@
|
|
|
1
|
-
import { useState
|
|
2
|
-
import { Box, ListItemText, ListItemButton, Avatar, Checkbox, ListItemIcon, Badge, IconButton, Chip, Typography } from "@mui/material";
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Box, ListItemText, ListItemButton, Avatar, Checkbox, ListItemIcon, Badge, IconButton, Chip, Typography, Collapse, Tooltip } from "@mui/material";
|
|
3
3
|
import ClearIcon from "@mui/icons-material/Clear";
|
|
4
|
+
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
5
|
+
import ExpandLessIcon from "@mui/icons-material/ExpandLess";
|
|
6
|
+
import ForumIcon from "@mui/icons-material/Forum";
|
|
7
|
+
import HeadsetIcon from "@mui/icons-material/Headset";
|
|
4
8
|
import { Done, Timelapse } from "@mui/icons-material";
|
|
5
9
|
import { useNavigate, useParams } from "react-router";
|
|
6
10
|
import HtmlTooltipComponent from "../../Misc/HtmlTooltipComponent/HtmlTooltipComponent";
|
|
11
|
+
import { getBotContentTemplateType } from "../../utils";
|
|
7
12
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
13
|
const sxGreenColor = theme => ({
|
|
9
|
-
color: theme.palette.success ? theme.palette.success.dark : ""
|
|
14
|
+
color: theme.palette.success ? theme.palette.success.dark : "",
|
|
15
|
+
marginTop: theme.spacing(2),
|
|
16
|
+
marginRight: theme.spacing(2),
|
|
17
|
+
marginBottom: theme.spacing(2)
|
|
10
18
|
});
|
|
11
19
|
const sxInfoColor = theme => ({
|
|
12
|
-
color: theme.palette.info ? theme.palette.info.main : ""
|
|
20
|
+
color: theme.palette.info ? theme.palette.info.main : "",
|
|
21
|
+
marginTop: theme.spacing(2),
|
|
22
|
+
marginRight: theme.spacing(2),
|
|
23
|
+
marginBottom: theme.spacing(2)
|
|
13
24
|
});
|
|
25
|
+
const botModes = ["bot", "bot-listen-and-speak"];
|
|
26
|
+
const getModeIcon = mode => mode === "bot" ? /*#__PURE__*/_jsx(ForumIcon, {}) : /*#__PURE__*/_jsx(HeadsetIcon, {});
|
|
27
|
+
const getModeLabel = (mode, t) => mode === "bot" ? t("choose_mode_text_option") : t("audio_only_mode");
|
|
14
28
|
export function ProgressBadge({
|
|
15
29
|
completions
|
|
16
30
|
}) {
|
|
@@ -55,7 +69,7 @@ function Bot({
|
|
|
55
69
|
} = params;
|
|
56
70
|
const [courseId, sectionId, topicId] = courseSectionTopicId ? courseSectionTopicId.split("|") : "";
|
|
57
71
|
const [lastClickedAssignmentId, lastClickedBotId] = lastClickedExerciseId?.split("|").slice(-2) || [];
|
|
58
|
-
const addSearchParams =
|
|
72
|
+
const addSearchParams = mode => {
|
|
59
73
|
if (!classroomId || !courseId || !sectionId || !topicId || !bot?.botId) {
|
|
60
74
|
console.error("Missing required parameters for navigation");
|
|
61
75
|
return;
|
|
@@ -64,55 +78,103 @@ function Bot({
|
|
|
64
78
|
courseSectionTopicId: `${courseSectionTopicId}|${assignment.assignmentId}|${bot.botId}`
|
|
65
79
|
};
|
|
66
80
|
localStorage.setItem("lastClickedExercise", JSON.stringify(lastClickedExercise));
|
|
67
|
-
|
|
81
|
+
const modeParam = mode ? `&mode=${encodeURIComponent(mode)}` : "";
|
|
82
|
+
navigate(`/classrooms/${classroomId}/${courseId}/${sectionId}/${topicId}/bots/${bot?.botId}?assignmentId=${assignment.assignmentId}${modeParam}`);
|
|
68
83
|
};
|
|
69
84
|
const [open, setOpen] = useState(lastClickedBotId === bot.botId && lastClickedAssignmentId === assignment.assignmentId);
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
const botTemplateType = getBotContentTemplateType(bot.selectedTemplate);
|
|
86
|
+
const isPictureOrEmojiQuizBot = botTemplateType === "picture-quiz" || botTemplateType === "emoji-quiz";
|
|
87
|
+
// Picture/emoji quiz bots have no spoken content to listen to, so Listen &
|
|
88
|
+
// Speak is never a valid mode for them - only Chat can be assigned/played.
|
|
89
|
+
const availableModes = isPictureOrEmojiQuizBot ? ["bot"] : botModes;
|
|
90
|
+
const allModesValue = isPictureOrEmojiQuizBot ? "bot" : "all";
|
|
91
|
+
const selectedExercise = selectedExercises?.find(exercise => exercise.botId === bot.botId && exercise.courseSectionTopicId === courseSectionTopicId);
|
|
92
|
+
const isBotSelectedForAssignment = !!selectedExercise;
|
|
93
|
+
const effectiveMode = selectedExercise?.mode || "all";
|
|
94
|
+
const isAllModesSelected = isBotSelectedForAssignment && effectiveMode === allModesValue;
|
|
95
|
+
const isIndeterminate = isBotSelectedForAssignment && effectiveMode !== allModesValue;
|
|
96
|
+
const isModeSelected = mode => isBotSelectedForAssignment && (effectiveMode === "all" || effectiveMode === mode);
|
|
97
|
+
const handleToggleMode = mode => {
|
|
98
|
+
const otherMode = mode === "bot" ? "bot-listen-and-speak" : "bot";
|
|
99
|
+
const modeChecked = isModeSelected(mode);
|
|
100
|
+
const otherChecked = availableModes.includes(otherMode) && isModeSelected(otherMode);
|
|
101
|
+
if (modeChecked) {
|
|
102
|
+
if (otherChecked) {
|
|
103
|
+
handleSelectExercise([{
|
|
104
|
+
botId: bot.botId,
|
|
105
|
+
courseSectionTopicId,
|
|
106
|
+
mode: otherMode,
|
|
107
|
+
updateModeOnly: true
|
|
108
|
+
}]);
|
|
109
|
+
} else {
|
|
110
|
+
handleSelectExercise([{
|
|
111
|
+
botId: bot.botId,
|
|
112
|
+
courseSectionTopicId
|
|
113
|
+
}]);
|
|
114
|
+
}
|
|
115
|
+
} else if (otherChecked) {
|
|
116
|
+
handleSelectExercise([{
|
|
117
|
+
botId: bot.botId,
|
|
118
|
+
courseSectionTopicId,
|
|
119
|
+
mode: "all",
|
|
120
|
+
updateModeOnly: true
|
|
121
|
+
}]);
|
|
122
|
+
} else {
|
|
123
|
+
handleSelectExercise([{
|
|
124
|
+
botId: bot.botId,
|
|
125
|
+
courseSectionTopicId,
|
|
126
|
+
mode
|
|
127
|
+
}]);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const handleSelectAllModes = () => {
|
|
131
|
+
if (isAllModesSelected) {
|
|
132
|
+
handleSelectExercise([{
|
|
133
|
+
botId: bot.botId,
|
|
134
|
+
courseSectionTopicId
|
|
135
|
+
}]);
|
|
136
|
+
} else if (isBotSelectedForAssignment) {
|
|
137
|
+
handleSelectExercise([{
|
|
138
|
+
botId: bot.botId,
|
|
139
|
+
courseSectionTopicId,
|
|
140
|
+
mode: allModesValue,
|
|
141
|
+
updateModeOnly: true
|
|
142
|
+
}]);
|
|
143
|
+
} else {
|
|
144
|
+
handleSelectExercise([{
|
|
145
|
+
botId: bot.botId,
|
|
146
|
+
courseSectionTopicId,
|
|
147
|
+
mode: allModesValue
|
|
148
|
+
}]);
|
|
149
|
+
}
|
|
83
150
|
};
|
|
84
|
-
const getBotCompletion =
|
|
151
|
+
const getBotCompletion = mode => {
|
|
85
152
|
if (!Array.isArray(memberCourseCompletions) || memberCourseCompletions.length === 0) {
|
|
86
153
|
return 0;
|
|
87
154
|
}
|
|
88
|
-
const botCompletion = memberCourseCompletions.filter(completion => completion.botId === bot.botId);
|
|
155
|
+
const botCompletion = memberCourseCompletions.filter(completion => completion.botId === bot.botId && (!mode || completion.exercise === mode));
|
|
89
156
|
return botCompletion.length;
|
|
90
157
|
};
|
|
91
|
-
const getBotProgress =
|
|
92
|
-
const progress = topicProgress?.filter(progress => progress.botId === bot.botId && progress.existingMessages && progress.existingMessages !== null);
|
|
158
|
+
const getBotProgress = mode => {
|
|
159
|
+
const progress = topicProgress?.filter(progress => progress.botId === bot.botId && (!mode || progress.exercise === mode) && progress.existingMessages && progress.existingMessages !== null);
|
|
93
160
|
return progress?.length || 0;
|
|
94
161
|
};
|
|
95
|
-
return /*#__PURE__*/
|
|
96
|
-
children: /*#__PURE__*/_jsx("div", {
|
|
162
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
163
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
97
164
|
children: /*#__PURE__*/_jsxs(ListItemButton, {
|
|
98
|
-
onClick: () =>
|
|
99
|
-
if (useCase === "assignment-start") {
|
|
100
|
-
addSearchParams();
|
|
101
|
-
} else if (handleSelectExercise) {
|
|
102
|
-
handleClick();
|
|
103
|
-
}
|
|
104
|
-
},
|
|
165
|
+
onClick: () => setOpen(!open),
|
|
105
166
|
sx: {
|
|
106
167
|
display: "flex",
|
|
107
168
|
alignItems: "center",
|
|
108
169
|
justifyContent: "space-between",
|
|
109
|
-
flexDirection:
|
|
110
|
-
xs: "column",
|
|
111
|
-
sm: "row"
|
|
112
|
-
},
|
|
170
|
+
flexDirection: "row",
|
|
113
171
|
marginLeft: {
|
|
114
172
|
sm: "0px",
|
|
115
173
|
md: "60px"
|
|
174
|
+
},
|
|
175
|
+
gap: {
|
|
176
|
+
xs: 1,
|
|
177
|
+
sm: 2
|
|
116
178
|
}
|
|
117
179
|
},
|
|
118
180
|
children: [/*#__PURE__*/_jsxs(Box, {
|
|
@@ -171,39 +233,131 @@ function Bot({
|
|
|
171
233
|
}),
|
|
172
234
|
secondary: bot.description
|
|
173
235
|
})]
|
|
174
|
-
}),
|
|
236
|
+
}), /*#__PURE__*/_jsxs(Box, {
|
|
175
237
|
sx: {
|
|
176
|
-
|
|
238
|
+
display: "flex",
|
|
239
|
+
alignItems: "center",
|
|
240
|
+
gap: 1
|
|
177
241
|
},
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
242
|
+
children: [/*#__PURE__*/_jsx(IconButton, {
|
|
243
|
+
onClick: e => {
|
|
244
|
+
e.stopPropagation();
|
|
245
|
+
setOpen(!open);
|
|
246
|
+
},
|
|
247
|
+
sx: {
|
|
248
|
+
ml: 2
|
|
249
|
+
},
|
|
250
|
+
children: open ? /*#__PURE__*/_jsx(ExpandLessIcon, {
|
|
251
|
+
sx: {
|
|
252
|
+
color: "#757575"
|
|
253
|
+
}
|
|
254
|
+
}) : /*#__PURE__*/_jsx(ExpandMoreIcon, {
|
|
255
|
+
sx: {
|
|
256
|
+
color: "#757575"
|
|
257
|
+
}
|
|
258
|
+
})
|
|
259
|
+
}), useCase === "assignment-select" && /*#__PURE__*/_jsx(Tooltip, {
|
|
260
|
+
title: t("select_all"),
|
|
261
|
+
placement: "top",
|
|
262
|
+
children: /*#__PURE__*/_jsx(Checkbox, {
|
|
263
|
+
checked: isAllModesSelected,
|
|
264
|
+
indeterminate: isIndeterminate,
|
|
265
|
+
onChange: handleSelectAllModes,
|
|
266
|
+
onClick: event => {
|
|
267
|
+
event.stopPropagation();
|
|
268
|
+
},
|
|
269
|
+
sx: {
|
|
270
|
+
mr: 2
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
})]
|
|
274
|
+
})]
|
|
275
|
+
})
|
|
276
|
+
}), /*#__PURE__*/_jsx(Collapse, {
|
|
277
|
+
in: open,
|
|
278
|
+
timeout: "auto",
|
|
279
|
+
unmountOnExit: true,
|
|
280
|
+
children: /*#__PURE__*/_jsxs(Box, {
|
|
281
|
+
sx: {
|
|
282
|
+
ml: {
|
|
283
|
+
sm: 0,
|
|
284
|
+
md: 3.5
|
|
182
285
|
}
|
|
183
|
-
}
|
|
184
|
-
|
|
286
|
+
},
|
|
287
|
+
children: [useCase === "assignment-select" && availableModes.map(mode => /*#__PURE__*/_jsxs(ListItemButton, {
|
|
288
|
+
onClick: () => handleToggleMode(mode),
|
|
289
|
+
sx: {
|
|
290
|
+
display: "flex",
|
|
291
|
+
alignItems: "center",
|
|
292
|
+
justifyContent: "space-between",
|
|
293
|
+
flexDirection: "row",
|
|
294
|
+
marginLeft: {
|
|
295
|
+
sm: "0px",
|
|
296
|
+
md: "95px"
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
children: [/*#__PURE__*/_jsx(ListItemIcon, {
|
|
300
|
+
sx: {
|
|
301
|
+
display: {
|
|
302
|
+
xs: "none",
|
|
303
|
+
sm: "flex"
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
children: getModeIcon(mode)
|
|
307
|
+
}), /*#__PURE__*/_jsx(ListItemText, {
|
|
308
|
+
primary: getModeLabel(mode, t),
|
|
309
|
+
secondary: t(mode === "bot" ? "choose_mode_text_option_desc" : "audio_only_subtitle")
|
|
310
|
+
}), /*#__PURE__*/_jsx(ListItemIcon, {
|
|
311
|
+
children: /*#__PURE__*/_jsx(Checkbox, {
|
|
312
|
+
checked: isModeSelected(mode)
|
|
313
|
+
})
|
|
314
|
+
})]
|
|
315
|
+
}, mode)), (useCase === "assignment-view" || useCase === "assignment-start") && availableModes.map(mode => isModeSelected(mode) && /*#__PURE__*/_jsxs(ListItemButton, {
|
|
316
|
+
"data-cy": `assignment-bot-mode-${mode}`,
|
|
317
|
+
onClick: () => {
|
|
318
|
+
if (useCase === "assignment-start") addSearchParams(mode);
|
|
319
|
+
},
|
|
320
|
+
sx: {
|
|
321
|
+
display: "flex",
|
|
322
|
+
alignItems: "center",
|
|
323
|
+
justifyContent: "space-between",
|
|
324
|
+
flexDirection: "row",
|
|
325
|
+
marginLeft: {
|
|
326
|
+
sm: "0px",
|
|
327
|
+
md: "95px"
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
children: [/*#__PURE__*/_jsx(ListItemIcon, {
|
|
331
|
+
sx: {
|
|
332
|
+
display: {
|
|
333
|
+
xs: "none",
|
|
334
|
+
sm: "flex"
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
children: getModeIcon(mode)
|
|
338
|
+
}), /*#__PURE__*/_jsx(ListItemText, {
|
|
339
|
+
primary: getModeLabel(mode, t),
|
|
340
|
+
secondary: t(mode === "bot" ? "choose_mode_text_option_desc" : "audio_only_subtitle")
|
|
341
|
+
}), useCase === "assignment-start" && /*#__PURE__*/_jsxs(ListItemIcon, {
|
|
342
|
+
children: [/*#__PURE__*/_jsx(InProgressBadge, {
|
|
343
|
+
progressCount: getBotProgress(mode)
|
|
344
|
+
}), /*#__PURE__*/_jsx(ProgressBadge, {
|
|
345
|
+
completions: getBotCompletion(mode)
|
|
346
|
+
})]
|
|
347
|
+
}), useCase === "assignment-view" && isPreview && /*#__PURE__*/_jsx(IconButton, {
|
|
185
348
|
edge: "end",
|
|
186
|
-
"aria-label": "remove-bot",
|
|
349
|
+
"aria-label": "remove-bot-mode",
|
|
187
350
|
onClick: e => {
|
|
188
351
|
e.stopPropagation();
|
|
189
|
-
|
|
190
|
-
if (exerciseToRemove) {
|
|
191
|
-
handleRemoveExercise(exerciseToRemove);
|
|
192
|
-
}
|
|
352
|
+
handleToggleMode(mode);
|
|
193
353
|
},
|
|
194
354
|
children: /*#__PURE__*/_jsx(ClearIcon, {
|
|
195
355
|
fontSize: "small"
|
|
196
356
|
})
|
|
197
|
-
})
|
|
198
|
-
}), useCase === "assignment-start" && /*#__PURE__*/_jsxs(ListItemIcon, {
|
|
199
|
-
children: [/*#__PURE__*/_jsx(InProgressBadge, {
|
|
200
|
-
progressCount: getBotProgress()
|
|
201
|
-
}), /*#__PURE__*/_jsx(ProgressBadge, {
|
|
202
|
-
completions: getBotCompletion()
|
|
203
357
|
})]
|
|
204
|
-
})]
|
|
358
|
+
}, mode))]
|
|
205
359
|
})
|
|
206
|
-
})
|
|
360
|
+
})]
|
|
207
361
|
});
|
|
208
362
|
}
|
|
209
363
|
function AssignmentBotSelection({
|
|
@@ -17,7 +17,7 @@ import { progress as progressQuerys } from "@nualang/nualang-api-and-queries/Que
|
|
|
17
17
|
import { useNavigate, useParams } from "react-router";
|
|
18
18
|
import { ProgressBadge, InProgressBadge } from "../../Lists/Exercises/Exercises";
|
|
19
19
|
import ColorLinearProgress from "../../Misc/ColorLinearProgress/ColorLinearProgress";
|
|
20
|
-
import { calcCompletions } from "../../utils";
|
|
20
|
+
import { calcCompletions, getBotContentTemplateType } from "../../utils";
|
|
21
21
|
import AssignmentBotSelection from "../AssignmentBotSelection/AssignmentBotSelection";
|
|
22
22
|
import AssignmentPhraseListSelection from "../AssignmentPhraseListSelection/AssignmentPhraseListSelection";
|
|
23
23
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
@@ -508,9 +508,12 @@ function Topic({
|
|
|
508
508
|
});
|
|
509
509
|
bots?.forEach(bot => {
|
|
510
510
|
if (!selectedExercises?.some(e => e.botId === bot.botId)) {
|
|
511
|
+
const botTemplateType = getBotContentTemplateType(bot.selectedTemplate);
|
|
512
|
+
const isPictureOrEmojiQuizBot = botTemplateType === "picture-quiz" || botTemplateType === "emoji-quiz";
|
|
511
513
|
exercisesToAdd.push({
|
|
512
514
|
botId: bot.botId,
|
|
513
|
-
courseSectionTopicId: courseSectionTopicId
|
|
515
|
+
courseSectionTopicId: courseSectionTopicId,
|
|
516
|
+
mode: isPictureOrEmojiQuizBot ? "bot" : "all"
|
|
514
517
|
});
|
|
515
518
|
}
|
|
516
519
|
});
|
|
@@ -50,11 +50,22 @@ function AssignmentSelectExercise({
|
|
|
50
50
|
}
|
|
51
51
|
} else if (isBot) {
|
|
52
52
|
// For bots
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
|
|
53
|
+
const existingIndex = updatedExercises.findIndex(e => e.botId === exercise.botId && e.courseSectionTopicId === exercise.courseSectionTopicId);
|
|
54
|
+
if (existingIndex > -1) {
|
|
55
|
+
if (exercise.updateModeOnly) {
|
|
56
|
+
updatedExercises[existingIndex] = {
|
|
57
|
+
...updatedExercises[existingIndex],
|
|
58
|
+
mode: exercise.mode
|
|
59
|
+
};
|
|
60
|
+
} else {
|
|
61
|
+
updatedExercises = updatedExercises.filter((_, index) => index !== existingIndex);
|
|
62
|
+
}
|
|
56
63
|
} else {
|
|
57
|
-
|
|
64
|
+
const newExercise = {
|
|
65
|
+
...exercise
|
|
66
|
+
};
|
|
67
|
+
delete newExercise.updateModeOnly;
|
|
68
|
+
updatedExercises.push(newExercise);
|
|
58
69
|
}
|
|
59
70
|
} else {
|
|
60
71
|
// Unknown type — just push without unsafe undefined matching
|