@nualang/nualang-ui-components 0.1.1295 → 0.1.1297
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/AssignmentCardsList/AssignmentCardsList.js +1 -1
- package/dist/Assignments/AssignmentCourseSelection/AssignmentCourseSelection.js +7 -2
- package/dist/Assignments/AssignmentExerciseSelection/AssignmentExerciseSelection.js +46 -57
- package/dist/Dialogs/AvatarDialog/AvatarDialog.js +2 -1
- package/dist/Forms/CreateBot/Steps/BotSettings/BotSettings.js +11 -3
- package/dist/Lists/CourseOutline/CourseOutline.js +12 -6
- package/dist/Lists/Exercises/Exercises.js +7 -25
- package/dist/Misc/AvatarSwitcher/AvatarSwitcher.js +2 -1
- package/dist/Screens/Courses/ViewCourse/ViewTopic/ViewTopic.js +17 -147
- package/package.json +8 -4
|
@@ -21,7 +21,7 @@ function Course({
|
|
|
21
21
|
handleSelectExercise,
|
|
22
22
|
selectedExercises,
|
|
23
23
|
useCase,
|
|
24
|
-
assignment,
|
|
24
|
+
assignment = {},
|
|
25
25
|
handleStartExercise,
|
|
26
26
|
isCreator,
|
|
27
27
|
viewOnly,
|
|
@@ -34,7 +34,12 @@ function Course({
|
|
|
34
34
|
isChallengeModeStudent
|
|
35
35
|
}) {
|
|
36
36
|
const numOfIds = lastClickedExerciseId ? lastClickedExerciseId.split("|") : [];
|
|
37
|
-
const [open, setOpen] = useState(
|
|
37
|
+
const [open, setOpen] = useState(false);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (lastClickedExerciseId && (numOfIds.length === 4 && lastClickedExerciseId.endsWith(`|${assignment?.assignmentId}`) || numOfIds.length === 5 && lastClickedExerciseId.split("|")[3] === assignment?.assignmentId)) {
|
|
40
|
+
setOpen(true);
|
|
41
|
+
}
|
|
42
|
+
}, [lastClickedExerciseId, assignment.assignmentId]);
|
|
38
43
|
const [selectedSectionIds, setSelectedSectionIds] = useState([]);
|
|
39
44
|
const [filteredSections, setFilteredSections] = useState([]);
|
|
40
45
|
const [courseSectionCompletion, setCourseSectionCompletion] = useState(null);
|
|
@@ -21,7 +21,6 @@ import { ProgressBadge, InProgressBadge } from "../../Lists/Exercises/Exercises"
|
|
|
21
21
|
import ColorLinearProgress from "../../Misc/ColorLinearProgress/ColorLinearProgress";
|
|
22
22
|
import { calcCompletions } from "../../utils";
|
|
23
23
|
import AssignmentBotSelection from "../AssignmentBotSelection/AssignmentBotSelection";
|
|
24
|
-
import { Clear } from "@mui/icons-material";
|
|
25
24
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
26
25
|
function Exercise({
|
|
27
26
|
name,
|
|
@@ -130,18 +129,13 @@ function Exercise({
|
|
|
130
129
|
setBotsOpen(!botsOpen);
|
|
131
130
|
};
|
|
132
131
|
useEffect(() => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (topic.hiddenExercises && topic.hiddenExercises.includes("pronunciation")) {
|
|
141
|
-
setPronunciationHidden(true);
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
}, [section]);
|
|
132
|
+
const currentTopicId = courseSectionTopicId.split("|")[2];
|
|
133
|
+
const currentTopic = section?.topics?.find(t => t.topicId === currentTopicId) || {};
|
|
134
|
+
const hidden = (currentTopic.hiddenExercises || []).map(x => String(x).toLowerCase());
|
|
135
|
+
setListeningHidden(hidden.includes("listening"));
|
|
136
|
+
setTranslationHidden(hidden.includes("translation"));
|
|
137
|
+
setPronunciationHidden(hidden.includes("pronunciation"));
|
|
138
|
+
}, [section, courseSectionTopicId]);
|
|
145
139
|
const isValidExercise = phrases.length >= 2 || name.toLowerCase() === "roleplays" || name.toLowerCase() === "bots";
|
|
146
140
|
if (name.toLowerCase() === "listening" && listeningHidden || name.toLowerCase() === "translation" && translationHidden || name.toLowerCase() === "pronunciation" && pronunciationHidden) {
|
|
147
141
|
return null;
|
|
@@ -418,72 +412,66 @@ function Topic({
|
|
|
418
412
|
const theme = useTheme();
|
|
419
413
|
const isLargeScreen = useMediaQuery(theme.breakpoints.up("sm"));
|
|
420
414
|
const topicRef = useRef(null);
|
|
421
|
-
const
|
|
422
|
-
|
|
415
|
+
const numOfIds = lastClickedExerciseId ? lastClickedExerciseId.split("|") : [];
|
|
416
|
+
|
|
417
|
+
// Define a single variable for clarity
|
|
418
|
+
const matchesLastClickedExercise = lastClickedExerciseId && (numOfIds.length === 4 && lastClickedExerciseId.endsWith(`|${assignment.assignmentId}`) && numOfIds[2] === topicId || numOfIds.length === 5 && numOfIds[3] === assignment.assignmentId && numOfIds[2] === topicId);
|
|
419
|
+
const [isExerciseListOpen, setExerciseListOpen] = useState(false);
|
|
420
|
+
useEffect(() => {
|
|
421
|
+
if (matchesLastClickedExercise) {
|
|
422
|
+
setExerciseListOpen(true);
|
|
423
|
+
}
|
|
424
|
+
}, [matchesLastClickedExercise]);
|
|
423
425
|
const [isWholeTopicSelected, setIsWholeTopicSelected] = useState(false);
|
|
424
426
|
useEffect(() => {
|
|
425
|
-
if (
|
|
427
|
+
if (matchesLastClickedExercise && topicRef.current) {
|
|
426
428
|
topicRef.current.scrollIntoView({
|
|
427
429
|
behavior: "smooth",
|
|
428
430
|
block: "start"
|
|
429
431
|
});
|
|
430
432
|
}
|
|
431
|
-
}, []);
|
|
433
|
+
}, [matchesLastClickedExercise, topicRef]);
|
|
434
|
+
const currentTopic = (section?.topics || []).find(t => t.topicId === topicId) || {};
|
|
435
|
+
const hidden = new Set((currentTopic.hiddenExercises || []).map(x => String(x).toLowerCase()));
|
|
436
|
+
const baseRegular = [{
|
|
437
|
+
name: "translation",
|
|
438
|
+
description: "translation_exercise_desc"
|
|
439
|
+
}, {
|
|
440
|
+
name: "listening",
|
|
441
|
+
description: "listening_exercise_desc"
|
|
442
|
+
}, {
|
|
443
|
+
name: "pronunciation",
|
|
444
|
+
description: "pronunciation_exercise_desc"
|
|
445
|
+
}].filter(e => !hidden.has(e.name));
|
|
432
446
|
let exercises;
|
|
433
447
|
switch (useCase) {
|
|
434
448
|
case "assignment-select":
|
|
435
|
-
exercises = [{
|
|
436
|
-
name: "translation",
|
|
437
|
-
description: `translation_exercise_desc`
|
|
438
|
-
}, {
|
|
439
|
-
name: "listening",
|
|
440
|
-
description: `listening_exercise_desc`
|
|
441
|
-
}, {
|
|
442
|
-
name: "pronunciation",
|
|
443
|
-
description: `pronunciation_exercise_desc`
|
|
444
|
-
}, {
|
|
449
|
+
exercises = [...baseRegular, {
|
|
445
450
|
name: "roleplays",
|
|
446
|
-
description:
|
|
451
|
+
description: "roleplay_exercise_desc"
|
|
447
452
|
}, {
|
|
448
453
|
name: "bots",
|
|
449
|
-
description:
|
|
454
|
+
description: "chatbot_exercise_desc"
|
|
450
455
|
}];
|
|
451
456
|
break;
|
|
452
457
|
case "assignment-view":
|
|
453
|
-
exercises = [{
|
|
454
|
-
name: "translation",
|
|
455
|
-
description: `translation_exercise_desc`
|
|
456
|
-
}, {
|
|
457
|
-
name: "listening",
|
|
458
|
-
description: `listening_exercise_desc`
|
|
459
|
-
}, {
|
|
460
|
-
name: "pronunciation",
|
|
461
|
-
description: `pronunciation_exercise_desc`
|
|
462
|
-
}, {
|
|
458
|
+
exercises = [...baseRegular, {
|
|
463
459
|
name: "roleplays",
|
|
464
|
-
description:
|
|
460
|
+
description: "roleplay_exercise_desc"
|
|
465
461
|
}, {
|
|
466
462
|
name: "bots",
|
|
467
|
-
description:
|
|
463
|
+
description: "chatbot_exercise_desc"
|
|
468
464
|
}].filter(exercise => selectedExercises?.some(e => e.name === exercise.name || exercise.name === "roleplays" && e.roleplayId || exercise.name === "bots" && e.botId));
|
|
469
465
|
break;
|
|
470
466
|
case "assignment-start":
|
|
471
|
-
exercises = [{
|
|
472
|
-
name: "translation",
|
|
473
|
-
description: `translation_exercise_desc`
|
|
474
|
-
}, {
|
|
475
|
-
name: "listening",
|
|
476
|
-
description: `listening_exercise_desc`
|
|
477
|
-
}, {
|
|
478
|
-
name: "pronunciation",
|
|
479
|
-
description: `pronunciation_exercise_desc`
|
|
480
|
-
}, {
|
|
467
|
+
exercises = [...baseRegular, {
|
|
481
468
|
name: "roleplays",
|
|
482
|
-
description:
|
|
469
|
+
description: "roleplay_exercise_desc"
|
|
483
470
|
}, {
|
|
484
471
|
name: "bots",
|
|
485
|
-
description:
|
|
472
|
+
description: "chatbot_exercise_desc"
|
|
486
473
|
}].filter(exercise => selectedExercises?.some(e => e.name === exercise.name || exercise.name === "roleplays" && e.roleplayId || exercise.name === "bots" && e.botId));
|
|
474
|
+
exercises = exercises.filter(ex => !["translation", "listening", "pronunciation"].includes(ex.name) || !hidden.has(ex.name));
|
|
487
475
|
break;
|
|
488
476
|
default:
|
|
489
477
|
exercises = [];
|
|
@@ -504,7 +492,8 @@ function Topic({
|
|
|
504
492
|
const expectedRoleplayCount = roleplays?.length * games?.length || 0;
|
|
505
493
|
const expectedBotCount = bots?.length || 0;
|
|
506
494
|
const totalExpected = (exercises?.filter(e => e.name !== "roleplays").length || 0) + expectedRoleplayCount + expectedBotCount;
|
|
507
|
-
const
|
|
495
|
+
const regularNames = new Set(baseRegular.map(e => e.name));
|
|
496
|
+
const selectedRegular = selectedExercises?.filter(e => e.courseSectionTopicId === courseSectionTopicId && !e.roleplayId && !e.botId && regularNames.has(e.name)).length || 0;
|
|
508
497
|
const selectedRoleplays = selectedExercises?.filter(exercise => exercise.roleplayId && roleplays?.some(roleplay => roleplay.roleplayId === exercise.roleplayId)).length || 0;
|
|
509
498
|
const selectedBots = selectedExercises?.filter(exercise => exercise.botId && bots?.some(bot => bot.botId === exercise.botId)).length || 0;
|
|
510
499
|
const totalSelected = selectedRegular + selectedRoleplays + selectedBots;
|
|
@@ -517,10 +506,10 @@ function Topic({
|
|
|
517
506
|
handleSelectExercise(removeExercises);
|
|
518
507
|
} else {
|
|
519
508
|
let exercisesToAdd = [];
|
|
520
|
-
|
|
509
|
+
baseRegular.forEach(exercise => {
|
|
521
510
|
if (!selectedExercises?.some(e => e.courseSectionTopicId === courseSectionTopicId && e.name === exercise.name)) {
|
|
522
511
|
exercisesToAdd.push({
|
|
523
|
-
courseSectionTopicId
|
|
512
|
+
courseSectionTopicId,
|
|
524
513
|
name: exercise.name
|
|
525
514
|
});
|
|
526
515
|
}
|
|
@@ -557,7 +546,7 @@ function Topic({
|
|
|
557
546
|
const selectedRoleplays = selectedExercises?.filter(e => e.courseSectionTopicId === courseSectionTopicId && e.roleplayId).length || 0;
|
|
558
547
|
const selectedBots = selectedExercises?.filter(e => e.courseSectionTopicId === courseSectionTopicId && e.botId).length || 0;
|
|
559
548
|
const selectedCount = selectedRegular + selectedRoleplays + selectedBots;
|
|
560
|
-
const totalRegular =
|
|
549
|
+
const totalRegular = baseRegular.length;
|
|
561
550
|
const totalRoleplays = (roleplays?.length || 0) * (games?.length || 0);
|
|
562
551
|
const totalBots = bots?.length || 0;
|
|
563
552
|
const totalCount = totalRegular + totalRoleplays + totalBots;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
-
import
|
|
2
|
+
import AvatarMod, { Piece } from "@nualang/avatars";
|
|
3
3
|
import AvatarSwitcher from "../../Misc/AvatarSwitcher/AvatarSwitcher";
|
|
4
4
|
import Box from "@mui/material/Box";
|
|
5
5
|
import Button from "@mui/material/Button";
|
|
@@ -24,6 +24,7 @@ import options from "./options";
|
|
|
24
24
|
import PropTypes from "prop-types";
|
|
25
25
|
import { useDropzone } from "react-dropzone";
|
|
26
26
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
27
|
+
const Avatar = AvatarMod.default || AvatarMod;
|
|
27
28
|
const getColor = (props, theme) => {
|
|
28
29
|
if (props.isDragAccept) {
|
|
29
30
|
return theme.palette.success.main;
|
|
@@ -120,16 +120,24 @@ function BotSettings({
|
|
|
120
120
|
className: classes.group,
|
|
121
121
|
name: "isChallengeBot",
|
|
122
122
|
value: isChallengeBot,
|
|
123
|
-
onChange:
|
|
123
|
+
onChange: e => {
|
|
124
|
+
const value = e.target.value === "true";
|
|
125
|
+
handleChange({
|
|
126
|
+
target: {
|
|
127
|
+
name: "isChallengeBot",
|
|
128
|
+
value
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
},
|
|
124
132
|
onBlur: handleBlur,
|
|
125
133
|
helperText: touched.isChallengeBot ? errors.isChallengeBot : "",
|
|
126
134
|
error: touched.isChallengeBot && Boolean(errors.isChallengeBot),
|
|
127
135
|
children: [/*#__PURE__*/_jsx(FormControlLabel, {
|
|
128
|
-
value: true,
|
|
136
|
+
value: "true",
|
|
129
137
|
control: /*#__PURE__*/_jsx(Radio, {}),
|
|
130
138
|
label: t("enabled")
|
|
131
139
|
}), /*#__PURE__*/_jsx(FormControlLabel, {
|
|
132
|
-
value: false,
|
|
140
|
+
value: "false",
|
|
133
141
|
control: /*#__PURE__*/_jsx(Radio, {}),
|
|
134
142
|
label: t("disabled")
|
|
135
143
|
})]
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { useEffect, useState, useCallback, useRef } from "react";
|
|
2
2
|
import { Link as RouterLink, useNavigate, useParams } from "react-router-dom";
|
|
3
|
-
import { ListSubheader, List, ListItem, ListItemIcon, ListItemText, ListItemAvatar, ListItemSecondaryAction, IconButton, Button, Collapse, Typography, Box, Tooltip,
|
|
4
|
-
import { useTheme
|
|
3
|
+
import { ListSubheader, List, ListItem, ListItemIcon, ListItemText, ListItemAvatar, ListItemSecondaryAction, IconButton, Button, Collapse, Typography, Box, Tooltip, Menu, MenuItem, Avatar } from "@mui/material";
|
|
4
|
+
import { useTheme } from "@mui/material/styles";
|
|
5
5
|
import { makeStyles } from "tss-react/mui";
|
|
6
|
-
import { withStyles } from "tss-react/mui";
|
|
7
6
|
import CheckBox from "@mui/icons-material/CheckBox";
|
|
8
7
|
import CheckBoxOutlineBlank from "@mui/icons-material/CheckBoxOutlineBlank";
|
|
9
8
|
import AddCircle from "@mui/icons-material/AddCircle";
|
|
@@ -26,7 +25,7 @@ import ImageSearchIcon from "@mui/icons-material/ImageSearch";
|
|
|
26
25
|
import Skeleton from "@mui/material/Skeleton";
|
|
27
26
|
import OndemandVideoIcon from "@mui/icons-material/OndemandVideo";
|
|
28
27
|
import ColorLinearProgress from "../../Misc/ColorLinearProgress/ColorLinearProgress";
|
|
29
|
-
import {
|
|
28
|
+
import { calcCompletions, calcPercentageCompletion } from "../../utils/index";
|
|
30
29
|
import SelectClassroom from "../../Dialogs/SelectClassroom/SelectClassroom";
|
|
31
30
|
import { CardInfoSectionItem } from "../../Cards/CardElements";
|
|
32
31
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
@@ -142,7 +141,7 @@ function ExerciseList({
|
|
|
142
141
|
})
|
|
143
142
|
}),
|
|
144
143
|
children: exercises.map((exercise, i) => {
|
|
145
|
-
const keyId = `exerc_${
|
|
144
|
+
const keyId = `exerc_${exercise.name}${i}`;
|
|
146
145
|
return /*#__PURE__*/_jsx(Exercise, {
|
|
147
146
|
t: t,
|
|
148
147
|
...exercise,
|
|
@@ -1152,7 +1151,14 @@ function CourseOutline({
|
|
|
1152
1151
|
classroomId,
|
|
1153
1152
|
...otherProps
|
|
1154
1153
|
}) {
|
|
1155
|
-
const [sects, setSects] = useState(
|
|
1154
|
+
const [sects, setSects] = useState([]);
|
|
1155
|
+
useEffect(() => {
|
|
1156
|
+
if (isMember) {
|
|
1157
|
+
setSects(calcCompletions(sections, completions));
|
|
1158
|
+
} else {
|
|
1159
|
+
setSects(sections);
|
|
1160
|
+
}
|
|
1161
|
+
}, [isMember, sections?.length, completions?.length]);
|
|
1156
1162
|
const moveSection = useCallback((dragIndex, hoverIndex) => {
|
|
1157
1163
|
const dragSection = sects[dragIndex];
|
|
1158
1164
|
const newSections = update(sects, {
|
|
@@ -1064,19 +1064,10 @@ function Exercises(props) {
|
|
|
1064
1064
|
}
|
|
1065
1065
|
});
|
|
1066
1066
|
}
|
|
1067
|
-
const [roleplaysArray, setRoleplaysArray] = useState(
|
|
1068
|
-
const roleplaysStringified = JSON.stringify(roleplays);
|
|
1067
|
+
const [roleplaysArray, setRoleplaysArray] = useState(roleplays);
|
|
1069
1068
|
const onDropRoleplay = () => {
|
|
1070
1069
|
updateRoleplays(roleplaysArray);
|
|
1071
1070
|
};
|
|
1072
|
-
useEffect(() => {
|
|
1073
|
-
if (roleplays && Array.isArray(roleplays) && roleplays.length && roleplays.length > 0) {
|
|
1074
|
-
const sortedRoleplays = [...roleplays].sort((a, b) => a.idx - b.idx);
|
|
1075
|
-
setRoleplaysArray(sortedRoleplays);
|
|
1076
|
-
} else if (roleplays && Array.isArray(roleplays)) {
|
|
1077
|
-
setRoleplaysArray(roleplays);
|
|
1078
|
-
}
|
|
1079
|
-
}, [roleplays, roleplaysStringified]);
|
|
1080
1071
|
const moveRoleplay = useCallback((dragIndex, hoverIndex) => {
|
|
1081
1072
|
const dragRoleplay = roleplaysArray[dragIndex];
|
|
1082
1073
|
const newRoleplays = update(roleplaysArray, {
|
|
@@ -1087,24 +1078,15 @@ function Exercises(props) {
|
|
|
1087
1078
|
});
|
|
1088
1079
|
setRoleplaysArray(newRoleplays);
|
|
1089
1080
|
}, [roleplaysArray]);
|
|
1090
|
-
const [botsArray, setBotsArray] = useState(
|
|
1091
|
-
|
|
1081
|
+
const [botsArray, setBotsArray] = useState(() => {
|
|
1082
|
+
if (!isChallengeModeStudent && !isCreator && !parentClassroom?.isCreator) {
|
|
1083
|
+
return bots.filter(bot => !bot.isChallengeBot || bot.isChallengeBot === false);
|
|
1084
|
+
}
|
|
1085
|
+
return bots;
|
|
1086
|
+
});
|
|
1092
1087
|
const onDropBot = () => {
|
|
1093
1088
|
updateBots(botsArray);
|
|
1094
1089
|
};
|
|
1095
|
-
useEffect(() => {
|
|
1096
|
-
if (bots && Array.isArray(bots) && bots.length && bots.length > 0) {
|
|
1097
|
-
const sortedBots = [...bots].sort((a, b) => a.idx - b.idx);
|
|
1098
|
-
setBotsArray(sortedBots);
|
|
1099
|
-
} else if (bots && Array.isArray(bots)) {
|
|
1100
|
-
setBotsArray(bots);
|
|
1101
|
-
}
|
|
1102
|
-
}, [bots, botsStringified]);
|
|
1103
|
-
useEffect(() => {
|
|
1104
|
-
if (!isChallengeModeStudent && !isCreator && !parentClassroom?.isCreator) {
|
|
1105
|
-
setBotsArray(bots.filter(bot => !bot.isChallengeBot || bot.isChallengeBot === false));
|
|
1106
|
-
}
|
|
1107
|
-
}, [bots, isChallengeModeStudent, isCreator]);
|
|
1108
1090
|
const moveBot = useCallback((dragIndex, hoverIndex) => {
|
|
1109
1091
|
const dragBot = botsArray[dragIndex];
|
|
1110
1092
|
const newBots = update(botsArray, {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useState, useEffect } from "react";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
|
-
import Avatar from "@nualang/avatars";
|
|
4
3
|
import sample from "lodash/sample";
|
|
5
4
|
import options from "../../Dialogs/AvatarDialog/options";
|
|
5
|
+
import AvatarMod from "@nualang/avatars";
|
|
6
6
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
7
|
+
const Avatar = AvatarMod.default || AvatarMod;
|
|
7
8
|
function AvatarSwitcher({
|
|
8
9
|
style = null
|
|
9
10
|
}) {
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { useState,
|
|
1
|
+
import { useState, useMemo } from "react";
|
|
2
2
|
import "regenerator-runtime/runtime";
|
|
3
3
|
import useMediaQuery from "@mui/material/useMediaQuery";
|
|
4
|
-
import { useTheme
|
|
4
|
+
import { useTheme } from "@mui/material/styles";
|
|
5
5
|
import { makeStyles } from "tss-react/mui";
|
|
6
|
-
import { withStyles } from "tss-react/mui";
|
|
7
6
|
import { Link as RouterLink, useParams, useNavigate } from "react-router-dom";
|
|
8
7
|
import { Typography, Avatar, Box, Menu, MenuItem, Button, Paper, Tooltip, Card, Grid, CardActionArea, CardContent } from "@mui/material";
|
|
9
8
|
import LiveTvIcon from "@mui/icons-material/LiveTv";
|
|
@@ -102,140 +101,6 @@ const useStyles = makeStyles()(theme => ({
|
|
|
102
101
|
position: "relative"
|
|
103
102
|
}
|
|
104
103
|
}));
|
|
105
|
-
const calcCompletions = (topic = {}, completions = [], _bots = [], _roleplays = []) => {
|
|
106
|
-
let isRoleplaysHidden;
|
|
107
|
-
let isPronunciationHidden;
|
|
108
|
-
let isBotsHidden;
|
|
109
|
-
let isListeningHidden;
|
|
110
|
-
let isTranslationHidden;
|
|
111
|
-
let isPhrases;
|
|
112
|
-
let completedExerciseCount = 0;
|
|
113
|
-
let totalExercises = 0;
|
|
114
|
-
if (topic.phrases && topic.phrases.length > 0) {
|
|
115
|
-
isPhrases = true;
|
|
116
|
-
}
|
|
117
|
-
if (topic.isTopicHidden) {
|
|
118
|
-
isRoleplaysHidden = true;
|
|
119
|
-
isBotsHidden = true;
|
|
120
|
-
isPronunciationHidden = true;
|
|
121
|
-
isListeningHidden = true;
|
|
122
|
-
isTranslationHidden = true;
|
|
123
|
-
} else if (topic && topic.hiddenExercises) {
|
|
124
|
-
topic.hiddenExercises.forEach(exercise => {
|
|
125
|
-
if (exercise === "roleplays") {
|
|
126
|
-
isRoleplaysHidden = true;
|
|
127
|
-
}
|
|
128
|
-
if (exercise === "chatbots") {
|
|
129
|
-
isBotsHidden = true;
|
|
130
|
-
}
|
|
131
|
-
if (exercise === "pronunciation") {
|
|
132
|
-
isPronunciationHidden = true;
|
|
133
|
-
}
|
|
134
|
-
if (exercise === "listening") {
|
|
135
|
-
isListeningHidden = true;
|
|
136
|
-
}
|
|
137
|
-
if (exercise === "translation") {
|
|
138
|
-
isTranslationHidden = true;
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
if (isPhrases) {
|
|
143
|
-
if (!isPronunciationHidden) {
|
|
144
|
-
totalExercises += 1;
|
|
145
|
-
}
|
|
146
|
-
if (!isListeningHidden) {
|
|
147
|
-
totalExercises += 1;
|
|
148
|
-
}
|
|
149
|
-
if (!isTranslationHidden) {
|
|
150
|
-
totalExercises += 1;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
const completedPronunciation = completions.filter(c => c.topicId === topic.topicId && c.exercise === "pronunciation").length;
|
|
154
|
-
const completedTranslation = completions.filter(c => c.topicId === topic.topicId && c.exercise === "translation").length;
|
|
155
|
-
const completedListening = completions.filter(c => c.topicId === topic.topicId && c.exercise === "listening").length;
|
|
156
|
-
completedExerciseCount += !isPronunciationHidden && completedPronunciation > 0 ? 1 : 0;
|
|
157
|
-
completedExerciseCount += !isTranslationHidden && completedTranslation > 0 ? 1 : 0;
|
|
158
|
-
completedExerciseCount += !isListeningHidden && completedListening > 0 ? 1 : 0;
|
|
159
|
-
let completedRoleplays = 0;
|
|
160
|
-
let completedBots = 0;
|
|
161
|
-
const roleplays = _roleplays.map(roleplay => {
|
|
162
|
-
if (isRoleplaysHidden || roleplay.isRoleplayHidden || topic.isTopicHidden) {
|
|
163
|
-
return {
|
|
164
|
-
...roleplay,
|
|
165
|
-
completedCount: 0
|
|
166
|
-
};
|
|
167
|
-
} else {
|
|
168
|
-
const completedCount = completions.reduce((acc, completion) => {
|
|
169
|
-
if (completion && completion.topicId === topic.topicId && completion.exercise.startsWith("roleplay") && completion.roleplayId === roleplay.roleplayId) {
|
|
170
|
-
acc += 1;
|
|
171
|
-
}
|
|
172
|
-
return acc;
|
|
173
|
-
}, 0);
|
|
174
|
-
if (completedCount > 0) {
|
|
175
|
-
completedRoleplays += 1;
|
|
176
|
-
completedExerciseCount += 1;
|
|
177
|
-
}
|
|
178
|
-
totalExercises += 1;
|
|
179
|
-
return {
|
|
180
|
-
...roleplay,
|
|
181
|
-
completedCount: completedCount
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
const bots = _bots.map(bot => {
|
|
186
|
-
if (isBotsHidden || bot.isBotHidden || topic.isTopicHidden) {
|
|
187
|
-
return {
|
|
188
|
-
...bot,
|
|
189
|
-
completedCount: 0
|
|
190
|
-
};
|
|
191
|
-
} else {
|
|
192
|
-
const completedCount = completions.reduce((acc, completion) => {
|
|
193
|
-
if (completion && completion.exercise === "bot" && completion.botId === bot.botId) {
|
|
194
|
-
acc += 1;
|
|
195
|
-
}
|
|
196
|
-
return acc;
|
|
197
|
-
}, 0);
|
|
198
|
-
if (completedCount > 0) {
|
|
199
|
-
completedBots += 1;
|
|
200
|
-
completedExerciseCount += 1;
|
|
201
|
-
}
|
|
202
|
-
totalExercises += 1;
|
|
203
|
-
return {
|
|
204
|
-
...bot,
|
|
205
|
-
completedCount: completedCount
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
return {
|
|
210
|
-
...topic,
|
|
211
|
-
roleplays: roleplays,
|
|
212
|
-
bots: bots,
|
|
213
|
-
completion: {
|
|
214
|
-
completed: completedExerciseCount,
|
|
215
|
-
total: totalExercises,
|
|
216
|
-
percentage: completedExerciseCount / totalExercises * 100,
|
|
217
|
-
pronunciation: {
|
|
218
|
-
completedCount: completedPronunciation
|
|
219
|
-
},
|
|
220
|
-
translation: {
|
|
221
|
-
completedCount: completedTranslation
|
|
222
|
-
},
|
|
223
|
-
listening: {
|
|
224
|
-
completedCount: completedListening
|
|
225
|
-
},
|
|
226
|
-
roleplays: {
|
|
227
|
-
completed: completedRoleplays,
|
|
228
|
-
total: roleplays.length,
|
|
229
|
-
percentage: completedRoleplays / roleplays.length * 100
|
|
230
|
-
},
|
|
231
|
-
bots: {
|
|
232
|
-
completed: completedBots,
|
|
233
|
-
total: bots.length,
|
|
234
|
-
percentage: completedBots / bots.length * 100
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
};
|
|
238
|
-
};
|
|
239
104
|
function OverflowMenu({
|
|
240
105
|
t,
|
|
241
106
|
topicId,
|
|
@@ -664,14 +529,16 @@ function Topic({
|
|
|
664
529
|
};
|
|
665
530
|
const [isCreatePhraseDialogOpen, setIsCreatePhraseDialogOpen] = useState(false);
|
|
666
531
|
const [isUploadPhrasesDialogOpen, setIsUploadPhrasesDialogOpen] = useState(false);
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
532
|
+
const topicCompletion = useMemo(() => {
|
|
533
|
+
if (isMember && topic?.topicId && topic?.completions?.length) {
|
|
534
|
+
return calcTopicCompletions(topic, topic.completions, false).completion;
|
|
535
|
+
}
|
|
536
|
+
return {
|
|
537
|
+
completed: 0,
|
|
538
|
+
total: 0,
|
|
539
|
+
percentage: 0
|
|
540
|
+
};
|
|
541
|
+
}, [isMember, topic?.topicId, topic?.completions?.length]);
|
|
675
542
|
const {
|
|
676
543
|
percentage,
|
|
677
544
|
completed,
|
|
@@ -697,7 +564,9 @@ function Topic({
|
|
|
697
564
|
} else {
|
|
698
565
|
initialTabValue = 0;
|
|
699
566
|
}
|
|
700
|
-
|
|
567
|
+
|
|
568
|
+
// if (!topic) {
|
|
569
|
+
if (topic && Object.keys(topic).length === 0) {
|
|
701
570
|
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
702
571
|
children: [/*#__PURE__*/_jsx("div", {
|
|
703
572
|
className: classes.cardTop,
|
|
@@ -1437,7 +1306,8 @@ export default function ViewTopic({
|
|
|
1437
1306
|
children: /*#__PURE__*/_jsx(Topic, {
|
|
1438
1307
|
t: t,
|
|
1439
1308
|
isLoading: isLoading,
|
|
1440
|
-
courseSettings: courseSettings
|
|
1309
|
+
courseSettings: courseSettings,
|
|
1310
|
+
...otherProps
|
|
1441
1311
|
})
|
|
1442
1312
|
}), !isLoading && topic && Object.keys(topic).length && /*#__PURE__*/_jsx(_Fragment, {
|
|
1443
1313
|
children: /*#__PURE__*/_jsx(Topic, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nualang/nualang-ui-components",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1297",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"@hookform/resolvers": "^3.6.0",
|
|
22
22
|
"@json2csv/plainjs": "^7.0.1",
|
|
23
23
|
"@nualang/avatars": "2.0.3",
|
|
24
|
-
"@nualang/nualang-api-and-queries": "^1.1.
|
|
24
|
+
"@nualang/nualang-api-and-queries": "^1.1.23",
|
|
25
25
|
"@stripe/react-stripe-js": "^2.1.1",
|
|
26
26
|
"@stripe/stripe-js": "^1.54.2",
|
|
27
27
|
"ajv-keywords": "^3.5.2",
|
|
@@ -129,11 +129,13 @@
|
|
|
129
129
|
"globals": "^16.0.0",
|
|
130
130
|
"intersection-observer": "^0.12.0",
|
|
131
131
|
"jsdom": "^27.0.0",
|
|
132
|
-
"msw": "^2.
|
|
132
|
+
"msw": "^2.11.3",
|
|
133
|
+
"msw-storybook-addon": "^2.0.5",
|
|
133
134
|
"prettier": "^3.2.5",
|
|
134
135
|
"react": "19.1.1",
|
|
135
136
|
"react-dom": "19.1.1",
|
|
136
137
|
"react-router-dom": "^6.30.0",
|
|
138
|
+
"rimraf": "^6.0.1",
|
|
137
139
|
"storybook": "^9.1.3",
|
|
138
140
|
"vitest": "^3.1.1",
|
|
139
141
|
"zx": "^8.5.4"
|
|
@@ -169,7 +171,9 @@
|
|
|
169
171
|
]
|
|
170
172
|
},
|
|
171
173
|
"msw": {
|
|
172
|
-
"workerDirectory":
|
|
174
|
+
"workerDirectory": [
|
|
175
|
+
"public"
|
|
176
|
+
]
|
|
173
177
|
},
|
|
174
178
|
"overrrides": {
|
|
175
179
|
"@emotion/react": "$@emotion/react",
|