@nualang/nualang-ui-components 0.1.1410 → 0.1.1411
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/AssignmentCard/AssignmentCard.js +1 -1
- package/dist/Cards/FeedbackCard/FeedbackCard.js +1 -1
- package/dist/Dialogs/BotPreview/BotPreview.js +1 -1
- package/dist/Dialogs/InviteDialog/InviteDialog.js +2 -2
- package/dist/Editors/Bot/Bot.js +16 -21
- package/dist/Editors/Bot/Editor/Editor.js +2 -2
- package/dist/Editors/Roleplay/Roleplay.js +16 -11
- package/dist/Exercises/Bot/Bot.js +12 -8
- package/dist/Exercises/ListenAndSpeak/ListenAndSpeak.js +12 -20
- package/dist/Exercises/Listener/Listener.js +15 -22
- package/dist/Exercises/Meaning/Meaning.js +12 -8
- package/dist/Exercises/MeaningReadWrite/MeaningReadWriteGame.js +17 -20
- package/dist/Exercises/Pronouncer/Pronouncer.js +13 -8
- package/dist/Exercises/Roleplay/OriginalRoleplay.js +6 -3
- package/dist/Exercises/Roleplay/Roleplay.js +1 -0
- package/dist/Exercises/Translator/Translator.js +14 -8
- package/dist/Forms/FeedbackForm/FeedbackForm.js +2 -2
- package/dist/Forms/ImageSelector/ImageSelector.js +3 -3
- package/dist/Forms/PdfUploader/PdfUploader.js +2 -2
- package/dist/Forms/Settings/Settings.js +1 -1
- package/dist/Live/Game/Game.js +12 -8
- package/dist/Live/GameMembers/GameMembers.js +3 -3
- package/dist/Live/GameSettings/GameSettings.js +1 -1
- package/dist/Live/HowToJoin/HowToJoin.js +28 -11
- package/dist/Live/LiveListener/LiveListener.js +1 -4
- package/dist/Misc/ImageLibrary/ImageLibrary.js +3 -3
- package/dist/Navigation/ResponsiveTabs/ResponsiveTabs.js +29 -15
- package/dist/hooks/useConfirm.js +1 -1
- package/dist/utils/joyride.js +127 -0
- package/package.json +1 -1
|
@@ -200,11 +200,11 @@ function InviteDialog({
|
|
|
200
200
|
return /*#__PURE__*/_jsx(ResponsiveDialog, {
|
|
201
201
|
open: open,
|
|
202
202
|
handleClose: handleClose,
|
|
203
|
-
dialogTitle: t("
|
|
203
|
+
dialogTitle: t("invite_students"),
|
|
204
204
|
handleSubmit: isWaysideClassroom ? () => {
|
|
205
205
|
window.open(learningSiteURL, "wayside-window");
|
|
206
206
|
} : null,
|
|
207
|
-
submitText: isWaysideClassroom ? t("
|
|
207
|
+
submitText: isWaysideClassroom ? t("visit_learning_site") : null,
|
|
208
208
|
children: isWaysideClassroom ? /*#__PURE__*/_jsx(_Fragment, {
|
|
209
209
|
children: /*#__PURE__*/_jsxs(DialogContentText, {
|
|
210
210
|
sx: {
|
package/dist/Editors/Bot/Bot.js
CHANGED
|
@@ -26,6 +26,7 @@ import Editor from "./Editor/Editor";
|
|
|
26
26
|
|
|
27
27
|
// utils
|
|
28
28
|
import { jsonToRivescript, rivescriptToJson } from "../../utils/index";
|
|
29
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
29
30
|
import useDebounce from "../../hooks/useDebounce";
|
|
30
31
|
import useRecognition from "../../hooks/useRecognition";
|
|
31
32
|
import { botErrorMessage } from "../../utils/constants";
|
|
@@ -217,16 +218,6 @@ function Bot({
|
|
|
217
218
|
}),
|
|
218
219
|
spotlightPadding: 8,
|
|
219
220
|
target: "#editorSidebar"
|
|
220
|
-
}, {
|
|
221
|
-
content: /*#__PURE__*/_jsxs("div", {
|
|
222
|
-
children: [/*#__PURE__*/_jsx("h2", {
|
|
223
|
-
children: t("bot_editor_flow_chart")
|
|
224
|
-
}), /*#__PURE__*/_jsx("br", {}), /*#__PURE__*/_jsx("p", {
|
|
225
|
-
children: t("bot_editor_flow_chart_desc")
|
|
226
|
-
})]
|
|
227
|
-
}),
|
|
228
|
-
spotlightPadding: 8,
|
|
229
|
-
target: "#editorFlowChart"
|
|
230
221
|
}, {
|
|
231
222
|
content: /*#__PURE__*/_jsx("h2", {
|
|
232
223
|
children: t("bot_editor_share")
|
|
@@ -260,10 +251,11 @@ function Bot({
|
|
|
260
251
|
};
|
|
261
252
|
useEffect(() => {
|
|
262
253
|
if (open && !localStorage.getItem("bot-editor-tour-completed")) {
|
|
263
|
-
setJoyrideState(prevState => ({
|
|
254
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
264
255
|
...prevState,
|
|
265
|
-
run: true
|
|
266
|
-
|
|
256
|
+
run: true,
|
|
257
|
+
steps
|
|
258
|
+
})));
|
|
267
259
|
}
|
|
268
260
|
}, [open]);
|
|
269
261
|
useEffect(() => {
|
|
@@ -303,10 +295,11 @@ function Bot({
|
|
|
303
295
|
}));
|
|
304
296
|
}
|
|
305
297
|
if (tabValue === 0 && !localStorage.getItem(`bot-editor-tour-completed`)) {
|
|
306
|
-
setJoyrideState(prevState => ({
|
|
298
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
307
299
|
...prevState,
|
|
308
|
-
run: true
|
|
309
|
-
|
|
300
|
+
run: true,
|
|
301
|
+
steps
|
|
302
|
+
})));
|
|
310
303
|
}
|
|
311
304
|
}, [tabValue]);
|
|
312
305
|
const handleChangeTab = (event, newValue) => {
|
|
@@ -670,13 +663,14 @@ function Bot({
|
|
|
670
663
|
}), /*#__PURE__*/_jsx("div", {
|
|
671
664
|
className: "grow-1"
|
|
672
665
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
673
|
-
title: t("
|
|
666
|
+
title: t("rewatch_tutorial"),
|
|
674
667
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
675
668
|
color: "inherit",
|
|
676
|
-
onClick: () => setJoyrideState({
|
|
677
|
-
...
|
|
678
|
-
run: true
|
|
679
|
-
|
|
669
|
+
onClick: () => startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
670
|
+
...prevState,
|
|
671
|
+
run: true,
|
|
672
|
+
steps
|
|
673
|
+
}))),
|
|
680
674
|
size: "large",
|
|
681
675
|
children: /*#__PURE__*/_jsx(LightbulbIcon, {})
|
|
682
676
|
})
|
|
@@ -825,6 +819,7 @@ function Bot({
|
|
|
825
819
|
close: t("close"),
|
|
826
820
|
last: t("last"),
|
|
827
821
|
next: t("next"),
|
|
822
|
+
nextWithProgress: t("next_with_progress"),
|
|
828
823
|
skip: t("skip")
|
|
829
824
|
},
|
|
830
825
|
options: {
|
|
@@ -475,7 +475,7 @@ function Editor({
|
|
|
475
475
|
width: "100%"
|
|
476
476
|
},
|
|
477
477
|
children: [/*#__PURE__*/_jsx(Tooltip, {
|
|
478
|
-
title: isDisabled ? t("
|
|
478
|
+
title: isDisabled ? t("please_select_a_textfield") : t("formatting_options"),
|
|
479
479
|
children: /*#__PURE__*/_jsx("span", {
|
|
480
480
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
481
481
|
color: "inherit",
|
|
@@ -489,7 +489,7 @@ function Editor({
|
|
|
489
489
|
})
|
|
490
490
|
})
|
|
491
491
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
492
|
-
title: isDisabled ? t("
|
|
492
|
+
title: isDisabled ? t("please_select_a_textfield") : t("insert_link"),
|
|
493
493
|
children: /*#__PURE__*/_jsx("span", {
|
|
494
494
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
495
495
|
color: "inherit",
|
|
@@ -26,6 +26,7 @@ import useExerciseState from "../../hooks/useExerciseState";
|
|
|
26
26
|
import useConfirm from "../../hooks/useConfirm";
|
|
27
27
|
import { handleScriptDownload } from "../../hooks/handleScriptDownload";
|
|
28
28
|
import { formatMarkdownNewlines } from "../../utils";
|
|
29
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
29
30
|
import DefaultButton from "../../Misc/DefaultColourButton/DefaultColourButton";
|
|
30
31
|
import { removeExtraWhiteSpaces } from "../../utils/index";
|
|
31
32
|
import GenerateQuestion from "../../Dialogs/GenerateQuestion/GenerateQuestion";
|
|
@@ -388,18 +389,20 @@ function Roleplay({
|
|
|
388
389
|
}));
|
|
389
390
|
}
|
|
390
391
|
if (tabValue === 0 && !localStorage.getItem(`roleplay-editor-tour-completed`)) {
|
|
391
|
-
setJoyrideState(prevState => ({
|
|
392
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
392
393
|
...prevState,
|
|
393
|
-
run: true
|
|
394
|
-
|
|
394
|
+
run: true,
|
|
395
|
+
steps
|
|
396
|
+
})));
|
|
395
397
|
}
|
|
396
398
|
}, [tabValue]);
|
|
397
399
|
useEffect(() => {
|
|
398
400
|
if (open && !localStorage.getItem(`roleplay-editor-tour-completed`)) {
|
|
399
|
-
setJoyrideState(prevState => ({
|
|
401
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
400
402
|
...prevState,
|
|
401
|
-
run: true
|
|
402
|
-
|
|
403
|
+
run: true,
|
|
404
|
+
steps
|
|
405
|
+
})));
|
|
403
406
|
}
|
|
404
407
|
}, [open]);
|
|
405
408
|
|
|
@@ -719,13 +722,14 @@ function Roleplay({
|
|
|
719
722
|
},
|
|
720
723
|
children: roleplay.roleplayName
|
|
721
724
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
722
|
-
title: t("
|
|
725
|
+
title: t("rewatch_tutorial"),
|
|
723
726
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
724
727
|
color: "inherit",
|
|
725
|
-
onClick: () => setJoyrideState({
|
|
726
|
-
...
|
|
727
|
-
run: true
|
|
728
|
-
|
|
728
|
+
onClick: () => startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
729
|
+
...prevState,
|
|
730
|
+
run: true,
|
|
731
|
+
steps
|
|
732
|
+
}))),
|
|
729
733
|
size: "large",
|
|
730
734
|
children: /*#__PURE__*/_jsx(LightbulbIcon, {})
|
|
731
735
|
})
|
|
@@ -937,6 +941,7 @@ function Roleplay({
|
|
|
937
941
|
close: t("close"),
|
|
938
942
|
last: t("last"),
|
|
939
943
|
next: t("next"),
|
|
944
|
+
nextWithProgress: t("next_with_progress"),
|
|
940
945
|
skip: t("skip")
|
|
941
946
|
},
|
|
942
947
|
options: {
|
|
@@ -21,6 +21,7 @@ import useExerciseState from "../../hooks/useExerciseState";
|
|
|
21
21
|
import VoiceSpeedSelector from "../../Misc/VoiceSpeed/VoiceSpeed";
|
|
22
22
|
import ReportProblem from "../../Misc/ReportProblem/ReportProblem";
|
|
23
23
|
import NualaSignInImage from "../../img/nuala_sign_in.svg";
|
|
24
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
24
25
|
import { useTheme } from "@mui/material/styles";
|
|
25
26
|
import config from "../../config";
|
|
26
27
|
import { useNavigate } from "react-router";
|
|
@@ -393,10 +394,11 @@ function Bot({
|
|
|
393
394
|
}, [currentPhrase, bot, isSpeaking]);
|
|
394
395
|
useEffect(() => {
|
|
395
396
|
if (open && !run && !localStorage.getItem(`bot-exercise-tour-completed`)) {
|
|
396
|
-
setJoyrideState(prevState => ({
|
|
397
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
397
398
|
...prevState,
|
|
398
|
-
run: true
|
|
399
|
-
|
|
399
|
+
run: true,
|
|
400
|
+
steps
|
|
401
|
+
})));
|
|
400
402
|
} else {
|
|
401
403
|
if (open && !joyrideRewatched && !run && bot.studentInstructions && bot.studentInstructions !== "") {
|
|
402
404
|
handleClickOpenInstructions();
|
|
@@ -424,15 +426,16 @@ function Bot({
|
|
|
424
426
|
|
|
425
427
|
const topBarActions = /*#__PURE__*/_jsxs(_Fragment, {
|
|
426
428
|
children: [/*#__PURE__*/_jsx(Tooltip, {
|
|
427
|
-
title: t("
|
|
429
|
+
title: t("rewatch_tutorial"),
|
|
428
430
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
429
431
|
color: "inherit",
|
|
430
432
|
onClick: () => {
|
|
431
433
|
setJoyrideRewatched(true);
|
|
432
|
-
setJoyrideState({
|
|
433
|
-
...
|
|
434
|
-
run: true
|
|
435
|
-
|
|
434
|
+
startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
435
|
+
...prevState,
|
|
436
|
+
run: true,
|
|
437
|
+
steps
|
|
438
|
+
})));
|
|
436
439
|
},
|
|
437
440
|
size: "large",
|
|
438
441
|
children: /*#__PURE__*/_jsx(LightbulbIcon, {})
|
|
@@ -698,6 +701,7 @@ function Bot({
|
|
|
698
701
|
close: t("close"),
|
|
699
702
|
last: t("last"),
|
|
700
703
|
next: t("next"),
|
|
704
|
+
nextWithProgress: t("next_with_progress"),
|
|
701
705
|
skip: t("skip")
|
|
702
706
|
},
|
|
703
707
|
options: {
|
|
@@ -22,12 +22,11 @@ import ExerciseBottomBar from "../../Misc/ExerciseBottomBar/ExerciseBottomBar";
|
|
|
22
22
|
import useExerciseState from "../../hooks/useExerciseState";
|
|
23
23
|
import useExerciseDocumentTitle from "../../hooks/useExerciseDocumentTitle";
|
|
24
24
|
import useRecognition from "../../hooks/useRecognition";
|
|
25
|
-
import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
|
|
26
25
|
import VoiceSpeedSelector from "../../Misc/VoiceSpeed/VoiceSpeed";
|
|
27
26
|
import ReportProblem from "../../Misc/ReportProblem/ReportProblem";
|
|
28
|
-
import ChatBubble from "../../Misc/ChatBubble/ChatBubble";
|
|
29
27
|
import WaveFormLite from "../../Misc/WaveFormLite/WaveFormLite";
|
|
30
28
|
import { removeExtraWhiteSpaces, removeAllSymbols } from "../../utils";
|
|
29
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
31
30
|
import getVoiceImages from "../../utils/voiceImages";
|
|
32
31
|
import { useNavigate } from "react-router";
|
|
33
32
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -340,16 +339,6 @@ function ListenAndSpeak({
|
|
|
340
339
|
}),
|
|
341
340
|
placement: "center",
|
|
342
341
|
target: "body"
|
|
343
|
-
}, {
|
|
344
|
-
content: /*#__PURE__*/_jsxs("div", {
|
|
345
|
-
children: [/*#__PURE__*/_jsx("h2", {
|
|
346
|
-
children: t("pronunciation_exercise_speak")
|
|
347
|
-
}), /*#__PURE__*/_jsx("br", {}), /*#__PURE__*/_jsx("p", {
|
|
348
|
-
children: t("listen_and_speak_exercise_speak_desc")
|
|
349
|
-
})]
|
|
350
|
-
}),
|
|
351
|
-
spotlightPadding: 8,
|
|
352
|
-
target: "#speakButton"
|
|
353
342
|
}, {
|
|
354
343
|
content: /*#__PURE__*/_jsx("div", {
|
|
355
344
|
children: /*#__PURE__*/_jsx("h2", {
|
|
@@ -429,10 +418,11 @@ function ListenAndSpeak({
|
|
|
429
418
|
}, [isSpeaking, isSocketConnected]);
|
|
430
419
|
useEffect(() => {
|
|
431
420
|
if (open && !localStorage.getItem(`meaning-listen-and-speak-exercise-tour-completed`)) {
|
|
432
|
-
setJoyrideState(prevState => ({
|
|
421
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
433
422
|
...prevState,
|
|
434
|
-
run: true
|
|
435
|
-
|
|
423
|
+
run: true,
|
|
424
|
+
steps
|
|
425
|
+
})));
|
|
436
426
|
} else if (open && !run && !joyrideRewatched && localStorage.getItem(`meaning-listen-and-speak-exercise-tour-completed`)) {
|
|
437
427
|
handlePronunciationTourFinished();
|
|
438
428
|
}
|
|
@@ -524,15 +514,16 @@ function ListenAndSpeak({
|
|
|
524
514
|
children: t("meaning")
|
|
525
515
|
})
|
|
526
516
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
527
|
-
title: t("
|
|
517
|
+
title: t("rewatch_tutorial"),
|
|
528
518
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
529
519
|
color: "inherit",
|
|
530
520
|
onClick: () => {
|
|
531
521
|
setJoyrideRewatched(true);
|
|
532
|
-
setJoyrideState({
|
|
533
|
-
...
|
|
534
|
-
run: true
|
|
535
|
-
|
|
522
|
+
startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
523
|
+
...prevState,
|
|
524
|
+
run: true,
|
|
525
|
+
steps
|
|
526
|
+
})));
|
|
536
527
|
},
|
|
537
528
|
size: "large",
|
|
538
529
|
children: /*#__PURE__*/_jsx(LightbulbIcon, {})
|
|
@@ -950,6 +941,7 @@ function ListenAndSpeak({
|
|
|
950
941
|
close: t("close"),
|
|
951
942
|
last: t("last"),
|
|
952
943
|
next: t("next"),
|
|
944
|
+
nextWithProgress: t("next_with_progress"),
|
|
953
945
|
skip: t("skip")
|
|
954
946
|
},
|
|
955
947
|
options: {
|
|
@@ -30,6 +30,7 @@ import { Sortable, SortableGridDndContextWrapper } from "../../utils/dragAndDrop
|
|
|
30
30
|
|
|
31
31
|
// utils
|
|
32
32
|
import { capitalize, removeExtraWhiteSpaces } from "../../utils/index";
|
|
33
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
33
34
|
import useWordBankFocus from "../../hooks/useWordBankFocus";
|
|
34
35
|
import getVoiceImages from "../../utils/voiceImages";
|
|
35
36
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
@@ -379,16 +380,6 @@ function Listener({
|
|
|
379
380
|
}),
|
|
380
381
|
spotlightPadding: 8,
|
|
381
382
|
target: "#speakButton"
|
|
382
|
-
}, {
|
|
383
|
-
content: /*#__PURE__*/_jsxs("div", {
|
|
384
|
-
children: [/*#__PURE__*/_jsx("h2", {
|
|
385
|
-
children: t("listening_exercise_voice_options")
|
|
386
|
-
}), /*#__PURE__*/_jsx("br", {}), /*#__PURE__*/_jsx("p", {
|
|
387
|
-
children: t("listening_exercise_voice_options_desc")
|
|
388
|
-
})]
|
|
389
|
-
}),
|
|
390
|
-
spotlightPadding: 8,
|
|
391
|
-
target: "#voiceOptions"
|
|
392
383
|
}, {
|
|
393
384
|
content: /*#__PURE__*/_jsxs("div", {
|
|
394
385
|
children: [/*#__PURE__*/_jsx("h2", {
|
|
@@ -480,10 +471,11 @@ function Listener({
|
|
|
480
471
|
}, [useWordBank]);
|
|
481
472
|
useEffect(() => {
|
|
482
473
|
if (open && !run && !localStorage.getItem(`listening-exercise-tour-completed`)) {
|
|
483
|
-
setJoyrideState(prevState => ({
|
|
474
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
484
475
|
...prevState,
|
|
485
|
-
run: true
|
|
486
|
-
|
|
476
|
+
run: true,
|
|
477
|
+
steps
|
|
478
|
+
})));
|
|
487
479
|
} else if (open && !run && !joyrideRewatched && localStorage.getItem(`listening-exercise-tour-completed`)) {
|
|
488
480
|
handleListeningTourFinished();
|
|
489
481
|
setTimeout(() => setWordBankTooltipOpen(true), 1000);
|
|
@@ -586,15 +578,16 @@ function Listener({
|
|
|
586
578
|
},
|
|
587
579
|
children: t("listening")
|
|
588
580
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
589
|
-
title: t("
|
|
581
|
+
title: t("rewatch_tutorial"),
|
|
590
582
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
591
583
|
color: "inherit",
|
|
592
584
|
onClick: () => {
|
|
593
585
|
setJoyrideRewatched(true);
|
|
594
|
-
setJoyrideState({
|
|
595
|
-
...
|
|
596
|
-
run: true
|
|
597
|
-
|
|
586
|
+
startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
587
|
+
...prevState,
|
|
588
|
+
run: true,
|
|
589
|
+
steps
|
|
590
|
+
})));
|
|
598
591
|
},
|
|
599
592
|
size: "large",
|
|
600
593
|
children: /*#__PURE__*/_jsx(LightbulbIcon, {})
|
|
@@ -735,6 +728,7 @@ function Listener({
|
|
|
735
728
|
marginLeft: 1
|
|
736
729
|
},
|
|
737
730
|
children: learnLang !== "irish" && /*#__PURE__*/_jsx(Box, {
|
|
731
|
+
id: "speakButton",
|
|
738
732
|
sx: theme => ({
|
|
739
733
|
[theme.breakpoints.down("md")]: {
|
|
740
734
|
minWidth: 185
|
|
@@ -886,6 +880,7 @@ function Listener({
|
|
|
886
880
|
})
|
|
887
881
|
})
|
|
888
882
|
}), isWordBankEnabled && /*#__PURE__*/_jsx(Grid, {
|
|
883
|
+
id: "useWordBank",
|
|
889
884
|
children: /*#__PURE__*/_jsx(Tooltip, {
|
|
890
885
|
title: t("use_wordbank_if_stuck"),
|
|
891
886
|
enterDelay: 500,
|
|
@@ -909,10 +904,7 @@ function Listener({
|
|
|
909
904
|
run: false
|
|
910
905
|
}));
|
|
911
906
|
},
|
|
912
|
-
startIcon: /*#__PURE__*/_jsx(Bank, {})
|
|
913
|
-
// Commented out to fix lint warning - jsx-no-duplicate-props
|
|
914
|
-
// id="useWordBank"
|
|
915
|
-
,
|
|
907
|
+
startIcon: /*#__PURE__*/_jsx(Bank, {}),
|
|
916
908
|
children: t("use_word_bank")
|
|
917
909
|
})
|
|
918
910
|
})
|
|
@@ -1010,6 +1002,7 @@ function Listener({
|
|
|
1010
1002
|
close: t("close"),
|
|
1011
1003
|
last: t("last"),
|
|
1012
1004
|
next: t("next"),
|
|
1005
|
+
nextWithProgress: t("next_with_progress"),
|
|
1013
1006
|
skip: t("skip")
|
|
1014
1007
|
},
|
|
1015
1008
|
options: {
|
|
@@ -26,6 +26,7 @@ import { useTheme } from "@mui/material/styles";
|
|
|
26
26
|
import getVoiceImages from "../../utils/voiceImages";
|
|
27
27
|
import { useNavigate } from "react-router";
|
|
28
28
|
import { removeExtraWhiteSpaces, shuffle } from "../../utils/index";
|
|
29
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
29
30
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
30
31
|
const useStyles = makeStyles()(theme => ({
|
|
31
32
|
appBar: {
|
|
@@ -335,10 +336,11 @@ function Meaning({
|
|
|
335
336
|
};
|
|
336
337
|
useEffect(() => {
|
|
337
338
|
if (open && !run && !localStorage.getItem("meaning-exercise-tour-completed")) {
|
|
338
|
-
setJoyrideState(prev => ({
|
|
339
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prev => ({
|
|
339
340
|
...prev,
|
|
340
|
-
run: true
|
|
341
|
-
|
|
341
|
+
run: true,
|
|
342
|
+
steps
|
|
343
|
+
})));
|
|
342
344
|
} else if (open && !run && !joyrideRewatched && localStorage.getItem("meaning-exercise-tour-completed")) {
|
|
343
345
|
handleTranslationTourFinished();
|
|
344
346
|
}
|
|
@@ -454,15 +456,16 @@ function Meaning({
|
|
|
454
456
|
},
|
|
455
457
|
children: t("meaning")
|
|
456
458
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
457
|
-
title: t("
|
|
459
|
+
title: t("rewatch_tutorial"),
|
|
458
460
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
459
461
|
color: "inherit",
|
|
460
462
|
onClick: () => {
|
|
461
463
|
setJoyrideRewatched(true);
|
|
462
|
-
setJoyrideState({
|
|
463
|
-
...
|
|
464
|
-
run: true
|
|
465
|
-
|
|
464
|
+
startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
465
|
+
...prevState,
|
|
466
|
+
run: true,
|
|
467
|
+
steps
|
|
468
|
+
})));
|
|
466
469
|
},
|
|
467
470
|
size: "large",
|
|
468
471
|
children: /*#__PURE__*/_jsx(LightbulbIcon, {})
|
|
@@ -787,6 +790,7 @@ function Meaning({
|
|
|
787
790
|
close: t("close"),
|
|
788
791
|
last: t("last"),
|
|
789
792
|
next: t("next"),
|
|
793
|
+
nextWithProgress: t("next_with_progress"),
|
|
790
794
|
skip: t("skip")
|
|
791
795
|
},
|
|
792
796
|
options: {
|
|
@@ -5,6 +5,7 @@ import { useTheme } from "@mui/material/styles";
|
|
|
5
5
|
import { makeStyles } from "tss-react/mui";
|
|
6
6
|
import useExerciseState from "../../hooks/useExerciseState";
|
|
7
7
|
import { removeExtraWhiteSpaces } from "../../utils/index";
|
|
8
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
8
9
|
import { Grid, Slide, IconButton, Dialog, AppBar, Toolbar, Tooltip, Typography, Box } from "@mui/material";
|
|
9
10
|
import { styled } from "@mui/system";
|
|
10
11
|
import LightbulbIcon from "@mui/icons-material/Lightbulb";
|
|
@@ -268,19 +269,12 @@ export default function MeaningReadWrite({
|
|
|
268
269
|
}),
|
|
269
270
|
spotlightPadding: 8,
|
|
270
271
|
target: "#skipButton"
|
|
271
|
-
},
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}, {
|
|
278
|
-
content: /*#__PURE__*/_jsx("h2", {
|
|
279
|
-
children: t("exercise_mute")
|
|
280
|
-
}),
|
|
281
|
-
spotlightPadding: 8,
|
|
282
|
-
target: "#mute"
|
|
283
|
-
}, {
|
|
272
|
+
},
|
|
273
|
+
// No change_voice_speed or exercise_mute step: this exercise has neither control.
|
|
274
|
+
// It speaks only through the answer result dialogs, and that path calls the raw
|
|
275
|
+
// handleSpeak prop rather than the muteSound-aware speak() from useExerciseState,
|
|
276
|
+
// so a mute button here would not silence anything the learner hears.
|
|
277
|
+
{
|
|
284
278
|
content: /*#__PURE__*/_jsx("h2", {
|
|
285
279
|
children: t("exercise_restart")
|
|
286
280
|
}),
|
|
@@ -298,10 +292,11 @@ export default function MeaningReadWrite({
|
|
|
298
292
|
} = joyrideState;
|
|
299
293
|
useEffect(() => {
|
|
300
294
|
if (open && !run && !localStorage.getItem("meaning-read-write-exercise-tour-completed")) {
|
|
301
|
-
setJoyrideState(prev => ({
|
|
295
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prev => ({
|
|
302
296
|
...prev,
|
|
303
|
-
run: true
|
|
304
|
-
|
|
297
|
+
run: true,
|
|
298
|
+
steps
|
|
299
|
+
})));
|
|
305
300
|
} else if (open && !run && !joyrideRewatched && localStorage.getItem("meaning-read-write-exercise-tour-completed")) {
|
|
306
301
|
handleTranslationTourFinished();
|
|
307
302
|
}
|
|
@@ -429,10 +424,11 @@ export default function MeaningReadWrite({
|
|
|
429
424
|
color: "inherit",
|
|
430
425
|
onClick: () => {
|
|
431
426
|
setJoyrideRewatched(true);
|
|
432
|
-
setJoyrideState({
|
|
433
|
-
...
|
|
434
|
-
run: true
|
|
435
|
-
|
|
427
|
+
startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
428
|
+
...prevState,
|
|
429
|
+
run: true,
|
|
430
|
+
steps
|
|
431
|
+
})));
|
|
436
432
|
},
|
|
437
433
|
size: "large",
|
|
438
434
|
children: /*#__PURE__*/_jsx(LightbulbIcon, {})
|
|
@@ -714,6 +710,7 @@ export default function MeaningReadWrite({
|
|
|
714
710
|
close: t("close"),
|
|
715
711
|
last: t("last"),
|
|
716
712
|
next: t("next"),
|
|
713
|
+
nextWithProgress: t("next_with_progress"),
|
|
717
714
|
skip: t("skip")
|
|
718
715
|
},
|
|
719
716
|
options: {
|
|
@@ -28,6 +28,7 @@ import ReportProblem from "../../Misc/ReportProblem/ReportProblem";
|
|
|
28
28
|
import ChatBubble from "../../Misc/ChatBubble/ChatBubble";
|
|
29
29
|
import WaveFormLite from "../../Misc/WaveFormLite/WaveFormLite";
|
|
30
30
|
import { removeExtraWhiteSpaces, removeAllSymbols } from "../../utils";
|
|
31
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
31
32
|
import getVoiceImages from "../../utils/voiceImages";
|
|
32
33
|
import { useNavigate } from "react-router";
|
|
33
34
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -429,10 +430,11 @@ function Pronouncer({
|
|
|
429
430
|
}, [isSpeaking, isSocketConnected]);
|
|
430
431
|
useEffect(() => {
|
|
431
432
|
if (open && !localStorage.getItem(`pronunciation-exercise-tour-completed`)) {
|
|
432
|
-
setJoyrideState(prevState => ({
|
|
433
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
433
434
|
...prevState,
|
|
434
|
-
run: true
|
|
435
|
-
|
|
435
|
+
run: true,
|
|
436
|
+
steps
|
|
437
|
+
})));
|
|
436
438
|
} else if (open && !run && !joyrideRewatched && localStorage.getItem(`pronunciation-exercise-tour-completed`)) {
|
|
437
439
|
handlePronunciationTourFinished();
|
|
438
440
|
}
|
|
@@ -508,15 +510,16 @@ function Pronouncer({
|
|
|
508
510
|
},
|
|
509
511
|
children: t("pronunciation")
|
|
510
512
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
511
|
-
title: t("
|
|
513
|
+
title: t("rewatch_tutorial"),
|
|
512
514
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
513
515
|
color: "inherit",
|
|
514
516
|
onClick: () => {
|
|
515
517
|
setJoyrideRewatched(true);
|
|
516
|
-
setJoyrideState({
|
|
517
|
-
...
|
|
518
|
-
run: true
|
|
519
|
-
|
|
518
|
+
startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
519
|
+
...prevState,
|
|
520
|
+
run: true,
|
|
521
|
+
steps
|
|
522
|
+
})));
|
|
520
523
|
},
|
|
521
524
|
size: "large",
|
|
522
525
|
children: /*#__PURE__*/_jsx(LightbulbIcon, {})
|
|
@@ -723,6 +726,7 @@ function Pronouncer({
|
|
|
723
726
|
muteSound: muteSound,
|
|
724
727
|
t: t
|
|
725
728
|
}), learnLang !== "irish" && /*#__PURE__*/_jsx(Box, {
|
|
729
|
+
id: "speakButton",
|
|
726
730
|
children: /*#__PURE__*/_jsx(WaveFormLite, {
|
|
727
731
|
src: pollyResult ? pollyResult : "",
|
|
728
732
|
controls: false,
|
|
@@ -959,6 +963,7 @@ function Pronouncer({
|
|
|
959
963
|
close: t("close"),
|
|
960
964
|
last: t("last"),
|
|
961
965
|
next: t("next"),
|
|
966
|
+
nextWithProgress: t("next_with_progress"),
|
|
962
967
|
skip: t("skip")
|
|
963
968
|
},
|
|
964
969
|
options: {
|
|
@@ -28,6 +28,7 @@ import { formatMarkdownNewlines, randomId } from "../../utils/index";
|
|
|
28
28
|
import VoiceSpeedSelector from "../../Misc/VoiceSpeed/VoiceSpeed";
|
|
29
29
|
import ReportProblem from "../../Misc/ReportProblem/ReportProblem";
|
|
30
30
|
import { removeExtraWhiteSpaces } from "../../utils";
|
|
31
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
31
32
|
import DefaultButton from "../../Misc/DefaultColourButton/DefaultColourButton";
|
|
32
33
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
33
34
|
const useStyles = makeStyles()((theme, {
|
|
@@ -579,10 +580,11 @@ function Roleplay({
|
|
|
579
580
|
};
|
|
580
581
|
useEffect(() => {
|
|
581
582
|
if (open && !localStorage.getItem(`roleplay-exercise-tour-completed`)) {
|
|
582
|
-
setJoyrideState(prevState => ({
|
|
583
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
583
584
|
...prevState,
|
|
584
|
-
run: true
|
|
585
|
-
|
|
585
|
+
run: true,
|
|
586
|
+
steps
|
|
587
|
+
})));
|
|
586
588
|
}
|
|
587
589
|
}, [open]);
|
|
588
590
|
useEffect(() => {
|
|
@@ -922,6 +924,7 @@ function Roleplay({
|
|
|
922
924
|
close: t("close"),
|
|
923
925
|
last: t("last"),
|
|
924
926
|
next: t("next"),
|
|
927
|
+
nextWithProgress: t("next_with_progress"),
|
|
925
928
|
skip: t("skip")
|
|
926
929
|
},
|
|
927
930
|
options: {
|
|
@@ -33,6 +33,7 @@ import { useNavigate } from "react-router";
|
|
|
33
33
|
|
|
34
34
|
// utils
|
|
35
35
|
import { capitalize, removeExtraWhiteSpaces, removeAllSymbols } from "../../utils/index";
|
|
36
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
36
37
|
import useWordBankFocus from "../../hooks/useWordBankFocus";
|
|
37
38
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
38
39
|
const useStyles = makeStyles()(theme => ({
|
|
@@ -475,10 +476,11 @@ function Translator({
|
|
|
475
476
|
}, [useWordBank]);
|
|
476
477
|
useEffect(() => {
|
|
477
478
|
if (open && !run && !localStorage.getItem(`translation-exercise-tour-completed`)) {
|
|
478
|
-
setJoyrideState(prevState => ({
|
|
479
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
479
480
|
...prevState,
|
|
480
|
-
run: true
|
|
481
|
-
|
|
481
|
+
run: true,
|
|
482
|
+
steps
|
|
483
|
+
})));
|
|
482
484
|
} else if (open && !run && !joyrideRewatched && localStorage.getItem(`translation-exercise-tour-completed`)) {
|
|
483
485
|
handleTranslationTourFinished();
|
|
484
486
|
setTimeout(() => setWordBankTooltipOpen(true), 1000);
|
|
@@ -586,15 +588,16 @@ function Translator({
|
|
|
586
588
|
},
|
|
587
589
|
children: t("translation")
|
|
588
590
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
589
|
-
title: t("
|
|
591
|
+
title: t("rewatch_tutorial"),
|
|
590
592
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
591
593
|
color: "inherit",
|
|
592
594
|
onClick: () => {
|
|
593
595
|
setJoyrideRewatched(true);
|
|
594
|
-
setJoyrideState({
|
|
595
|
-
...
|
|
596
|
-
run: true
|
|
597
|
-
|
|
596
|
+
startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
597
|
+
...prevState,
|
|
598
|
+
run: true,
|
|
599
|
+
steps
|
|
600
|
+
})));
|
|
598
601
|
},
|
|
599
602
|
size: "large",
|
|
600
603
|
children: /*#__PURE__*/_jsx(LightbulbIcon, {})
|
|
@@ -754,6 +757,7 @@ function Translator({
|
|
|
754
757
|
t: t,
|
|
755
758
|
languageTag: languageTag
|
|
756
759
|
}), learnLang !== "irish" && /*#__PURE__*/_jsx(Box, {
|
|
760
|
+
id: "speakButton",
|
|
757
761
|
children: /*#__PURE__*/_jsx(WaveFormLite, {
|
|
758
762
|
src: pollyResult ? pollyResult : "",
|
|
759
763
|
controls: false,
|
|
@@ -911,6 +915,7 @@ function Translator({
|
|
|
911
915
|
})]
|
|
912
916
|
})
|
|
913
917
|
}), isWordBankEnabled && /*#__PURE__*/_jsx(Grid, {
|
|
918
|
+
id: "useWordBank",
|
|
914
919
|
children: /*#__PURE__*/_jsx(Tooltip, {
|
|
915
920
|
title: t("use_wordbank_if_stuck"),
|
|
916
921
|
enterDelay: 500,
|
|
@@ -1009,6 +1014,7 @@ function Translator({
|
|
|
1009
1014
|
close: t("close"),
|
|
1010
1015
|
last: t("last"),
|
|
1011
1016
|
next: t("next"),
|
|
1017
|
+
nextWithProgress: t("next_with_progress"),
|
|
1012
1018
|
skip: t("skip")
|
|
1013
1019
|
},
|
|
1014
1020
|
options: {
|
|
@@ -48,7 +48,7 @@ function FeedbackForm({
|
|
|
48
48
|
const theme = useTheme();
|
|
49
49
|
const [allSelected, setAllSelected] = useState("false");
|
|
50
50
|
const handleAttendeeChange = event => {
|
|
51
|
-
if (event.target.value === t("
|
|
51
|
+
if (event.target.value === t("all")) {
|
|
52
52
|
setAllSelected(true);
|
|
53
53
|
handleChange({
|
|
54
54
|
target: {
|
|
@@ -305,7 +305,7 @@ function FeedbackForm({
|
|
|
305
305
|
label: "Student",
|
|
306
306
|
disabled: attendeesData?.length < 1,
|
|
307
307
|
children: [{
|
|
308
|
-
username: t("
|
|
308
|
+
username: t("all")
|
|
309
309
|
}, ...attendeesData].map((attendee, index) => /*#__PURE__*/_jsx(MenuItem, {
|
|
310
310
|
value: index === 0 ? "All" : attendeesData[index - 1],
|
|
311
311
|
children: /*#__PURE__*/_jsxs(Box, {
|
|
@@ -524,7 +524,7 @@ function ImageSelector({
|
|
|
524
524
|
children: /*#__PURE__*/_jsx(Typography, {
|
|
525
525
|
component: "p",
|
|
526
526
|
variant: "body1",
|
|
527
|
-
children: t("
|
|
527
|
+
children: t("Drag_and_drop_image_from_your_computer")
|
|
528
528
|
})
|
|
529
529
|
})]
|
|
530
530
|
}), /*#__PURE__*/_jsxs("div", {
|
|
@@ -542,7 +542,7 @@ function ImageSelector({
|
|
|
542
542
|
className: classes.button,
|
|
543
543
|
onClick: () => setIsImageLibraryOpen(!isImageLibraryOpen),
|
|
544
544
|
startIcon: /*#__PURE__*/_jsx(CollectionsIcon, {}),
|
|
545
|
-
children: t("
|
|
545
|
+
children: t("image_library")
|
|
546
546
|
}), /*#__PURE__*/_jsx("input", {
|
|
547
547
|
accept: "image/*",
|
|
548
548
|
className: classes.input,
|
|
@@ -556,7 +556,7 @@ function ImageSelector({
|
|
|
556
556
|
className: classes.button,
|
|
557
557
|
component: "span",
|
|
558
558
|
startIcon: /*#__PURE__*/_jsx(CloudUploadIcon, {}),
|
|
559
|
-
children: t("
|
|
559
|
+
children: t("upload_image")
|
|
560
560
|
})
|
|
561
561
|
}), /*#__PURE__*/_jsx(DefaultButton, {
|
|
562
562
|
variant: "outlined",
|
|
@@ -214,7 +214,7 @@ function PdfUploader({
|
|
|
214
214
|
},
|
|
215
215
|
children: [/*#__PURE__*/_jsx(Grid, {
|
|
216
216
|
children: /*#__PURE__*/_jsx(Tooltip, {
|
|
217
|
-
title: t("
|
|
217
|
+
title: t("previous"),
|
|
218
218
|
children: /*#__PURE__*/_jsx("span", {
|
|
219
219
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
220
220
|
size: "large",
|
|
@@ -231,7 +231,7 @@ function PdfUploader({
|
|
|
231
231
|
})
|
|
232
232
|
}), /*#__PURE__*/_jsx(Grid, {
|
|
233
233
|
children: /*#__PURE__*/_jsx(Tooltip, {
|
|
234
|
-
title: t("
|
|
234
|
+
title: t("next"),
|
|
235
235
|
children: /*#__PURE__*/_jsx("span", {
|
|
236
236
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
237
237
|
size: "large",
|
package/dist/Live/Game/Game.js
CHANGED
|
@@ -24,6 +24,7 @@ import GameSettings from "../GameSettings/GameSettings";
|
|
|
24
24
|
import FinalScoreDrawer from "../Misc/FinalScoreDrawer/FinalScoreDrawer";
|
|
25
25
|
import RewardEarned from "../../Dialogs/RewardEarned/RewardEarned";
|
|
26
26
|
import LiveGameTutorial from "../../Dialogs/LiveGameTutorial/LiveGameTutorial";
|
|
27
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
27
28
|
import HelpIcon from "@mui/icons-material/Help";
|
|
28
29
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
29
30
|
const useStyles = makeStyles()(theme => ({
|
|
@@ -244,10 +245,11 @@ export default function Game({
|
|
|
244
245
|
});
|
|
245
246
|
useEffect(() => {
|
|
246
247
|
if (open && isCreator && !localStorage.getItem(`nualang-live-tour-completed`)) {
|
|
247
|
-
setJoyrideState(prevState => ({
|
|
248
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
248
249
|
...prevState,
|
|
249
|
-
run: true
|
|
250
|
-
|
|
250
|
+
run: true,
|
|
251
|
+
steps
|
|
252
|
+
})));
|
|
251
253
|
}
|
|
252
254
|
}, [open, isCreator]);
|
|
253
255
|
const handleJoyrideCallback = data => {
|
|
@@ -368,13 +370,14 @@ export default function Game({
|
|
|
368
370
|
children: /*#__PURE__*/_jsx(SettingsIcon, {})
|
|
369
371
|
})
|
|
370
372
|
}), /*#__PURE__*/_jsx(Tooltip, {
|
|
371
|
-
title: t("
|
|
373
|
+
title: t("rewatch_tutorial"),
|
|
372
374
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
373
375
|
color: "inherit",
|
|
374
|
-
onClick: () => setJoyrideState({
|
|
375
|
-
...
|
|
376
|
-
run: true
|
|
377
|
-
|
|
376
|
+
onClick: () => startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
377
|
+
...prevState,
|
|
378
|
+
run: true,
|
|
379
|
+
steps
|
|
380
|
+
}))),
|
|
378
381
|
size: "large",
|
|
379
382
|
children: /*#__PURE__*/_jsx(LightbulbIcon, {})
|
|
380
383
|
})
|
|
@@ -650,6 +653,7 @@ export default function Game({
|
|
|
650
653
|
close: t("close"),
|
|
651
654
|
last: t("last"),
|
|
652
655
|
next: t("next"),
|
|
656
|
+
nextWithProgress: t("next_with_progress"),
|
|
653
657
|
skip: t("skip")
|
|
654
658
|
},
|
|
655
659
|
options: {
|
|
@@ -69,7 +69,7 @@ export default function GameMembers({
|
|
|
69
69
|
id: "search",
|
|
70
70
|
name: "search",
|
|
71
71
|
"data-cy": "search",
|
|
72
|
-
label: t("
|
|
72
|
+
label: t("search"),
|
|
73
73
|
value: searchText,
|
|
74
74
|
onChange: ev => setSearchText(ev.target.value),
|
|
75
75
|
margin: "dense",
|
|
@@ -94,7 +94,7 @@ export default function GameMembers({
|
|
|
94
94
|
setMembersInRoomOpen(!membersInRoomOpen);
|
|
95
95
|
},
|
|
96
96
|
children: [/*#__PURE__*/_jsx(ListItemText, {
|
|
97
|
-
primary: "
|
|
97
|
+
primary: t("in_game")
|
|
98
98
|
}), /*#__PURE__*/_jsx(Typography, {
|
|
99
99
|
sx: {
|
|
100
100
|
pr: 1
|
|
@@ -134,7 +134,7 @@ export default function GameMembers({
|
|
|
134
134
|
setMembersNotInRoomOpen(!membersNotInRoomOpen);
|
|
135
135
|
},
|
|
136
136
|
children: [/*#__PURE__*/_jsx(ListItemText, {
|
|
137
|
-
primary: "
|
|
137
|
+
primary: t("not_in_game")
|
|
138
138
|
}), /*#__PURE__*/_jsx(Typography, {
|
|
139
139
|
sx: {
|
|
140
140
|
pr: 1
|
|
@@ -5,7 +5,20 @@ import SwipeableDrawer from "@mui/material/SwipeableDrawer";
|
|
|
5
5
|
import { useTheme } from "@mui/material/styles";
|
|
6
6
|
import { QRCode } from "react-qrcode-logo";
|
|
7
7
|
import nualangImage from "../../img/nualangSquareIcon.svg";
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
// Sentinel handed to i18next as the interpolation value so we can split the
|
|
10
|
+
// translated sentence and drop a React node in the placeholder's position.
|
|
11
|
+
// Splitting on the real value would break when it is empty or repeated, and
|
|
12
|
+
// splitting on the raw "{{name}}" token would not work because i18next has
|
|
13
|
+
// already substituted it.
|
|
14
|
+
import { Fragment as _Fragment, jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
15
|
+
const PLACEHOLDER = "\u0000";
|
|
16
|
+
function withNode(sentence, node) {
|
|
17
|
+
const [before, after = ""] = sentence.split(PLACEHOLDER);
|
|
18
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
19
|
+
children: [before, node, after]
|
|
20
|
+
});
|
|
21
|
+
}
|
|
9
22
|
export default function HowToJoin({
|
|
10
23
|
t,
|
|
11
24
|
classroomName,
|
|
@@ -30,11 +43,11 @@ export default function HowToJoin({
|
|
|
30
43
|
variant: "h5",
|
|
31
44
|
component: "h1",
|
|
32
45
|
gutterBottom: true,
|
|
33
|
-
children: "
|
|
46
|
+
children: t("how_to_join_title")
|
|
34
47
|
}), /*#__PURE__*/_jsx(Typography, {
|
|
35
48
|
variant: "body1",
|
|
36
49
|
gutterBottom: true,
|
|
37
|
-
children: "
|
|
50
|
+
children: t("how_to_join_intro")
|
|
38
51
|
}), /*#__PURE__*/_jsxs(List, {
|
|
39
52
|
sx: {
|
|
40
53
|
listStyleType: "decimal",
|
|
@@ -48,20 +61,22 @@ export default function HowToJoin({
|
|
|
48
61
|
primary: /*#__PURE__*/_jsx(Typography, {
|
|
49
62
|
component: "span",
|
|
50
63
|
variant: "body1",
|
|
51
|
-
children: "
|
|
64
|
+
children: t("how_to_join_sign_in")
|
|
52
65
|
})
|
|
53
66
|
})
|
|
54
67
|
}), /*#__PURE__*/_jsx(ListItem, {
|
|
55
68
|
children: /*#__PURE__*/_jsx(ListItemText, {
|
|
56
|
-
primary: /*#__PURE__*/
|
|
69
|
+
primary: /*#__PURE__*/_jsx(Typography, {
|
|
57
70
|
component: "span",
|
|
58
71
|
variant: "body1",
|
|
59
|
-
children:
|
|
72
|
+
children: withNode(t("how_to_join_open_classroom", {
|
|
73
|
+
classroom: PLACEHOLDER
|
|
74
|
+
}), /*#__PURE__*/_jsx(Link, {
|
|
60
75
|
href: classroomURL,
|
|
61
76
|
target: "_blank",
|
|
62
77
|
rel: "noreferrer",
|
|
63
78
|
children: classroomName
|
|
64
|
-
})
|
|
79
|
+
}))
|
|
65
80
|
})
|
|
66
81
|
})
|
|
67
82
|
}), /*#__PURE__*/_jsx(Box, {
|
|
@@ -81,12 +96,14 @@ export default function HowToJoin({
|
|
|
81
96
|
})
|
|
82
97
|
}), /*#__PURE__*/_jsx(ListItem, {
|
|
83
98
|
children: /*#__PURE__*/_jsx(ListItemText, {
|
|
84
|
-
primary: /*#__PURE__*/
|
|
99
|
+
primary: /*#__PURE__*/_jsx(Typography, {
|
|
85
100
|
component: "span",
|
|
86
101
|
variant: "body1",
|
|
87
|
-
children:
|
|
102
|
+
children: withNode(t("how_to_join_find_button", {
|
|
103
|
+
button: PLACEHOLDER
|
|
104
|
+
}), /*#__PURE__*/_jsx("b", {
|
|
88
105
|
children: t("join_live_game")
|
|
89
|
-
})
|
|
106
|
+
}))
|
|
90
107
|
})
|
|
91
108
|
})
|
|
92
109
|
}), /*#__PURE__*/_jsx(ListItem, {
|
|
@@ -94,7 +111,7 @@ export default function HowToJoin({
|
|
|
94
111
|
primary: /*#__PURE__*/_jsx(Typography, {
|
|
95
112
|
component: "span",
|
|
96
113
|
variant: "body1",
|
|
97
|
-
children: "
|
|
114
|
+
children: t("how_to_join_get_ready")
|
|
98
115
|
})
|
|
99
116
|
})
|
|
100
117
|
})]
|
|
@@ -450,10 +450,7 @@ function LiveListener({
|
|
|
450
450
|
onClick: () => {
|
|
451
451
|
handleUseWordBank();
|
|
452
452
|
},
|
|
453
|
-
startIcon: /*#__PURE__*/_jsx(Bank, {})
|
|
454
|
-
// Commented out to fix lint warning - jsx-no-duplicate-props
|
|
455
|
-
// id="useWordBank"
|
|
456
|
-
,
|
|
453
|
+
startIcon: /*#__PURE__*/_jsx(Bank, {}),
|
|
457
454
|
children: t("use_word_bank")
|
|
458
455
|
})
|
|
459
456
|
})
|
|
@@ -104,7 +104,7 @@ const Search = ({
|
|
|
104
104
|
className: className,
|
|
105
105
|
onChange: e => setSearchText(e.target.value),
|
|
106
106
|
type: "text",
|
|
107
|
-
placeholder: t("
|
|
107
|
+
placeholder: t("search_images"),
|
|
108
108
|
value: searchText,
|
|
109
109
|
margin: "dense",
|
|
110
110
|
variant: "outlined",
|
|
@@ -213,7 +213,7 @@ function ImageLibrary({
|
|
|
213
213
|
id: "selectedCategory",
|
|
214
214
|
name: "selectedCategory",
|
|
215
215
|
"data-cy": "selectedCategory",
|
|
216
|
-
label: t("
|
|
216
|
+
label: t("categories"),
|
|
217
217
|
value: selectedCategory || "",
|
|
218
218
|
onClick: event => {
|
|
219
219
|
handleCategoryClick(event.target.dataset.value);
|
|
@@ -237,7 +237,7 @@ function ImageLibrary({
|
|
|
237
237
|
className: classes.categories,
|
|
238
238
|
children: [/*#__PURE__*/_jsx(Typography, {
|
|
239
239
|
className: classes.categoriesTitle,
|
|
240
|
-
children: t("
|
|
240
|
+
children: t("categories")
|
|
241
241
|
}), /*#__PURE__*/_jsx(List, {
|
|
242
242
|
className: classes.list,
|
|
243
243
|
component: "nav",
|
|
@@ -17,6 +17,7 @@ import { makeStyles } from "tss-react/mui";
|
|
|
17
17
|
import Typography from "@mui/material/Typography";
|
|
18
18
|
import NewText from "../../img/NewText.svg";
|
|
19
19
|
import { Joyride, STATUS } from "react-joyride";
|
|
20
|
+
import { startJoyrideWhenReady } from "../../utils/joyride";
|
|
20
21
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
21
22
|
function TabPanel(props) {
|
|
22
23
|
const {
|
|
@@ -192,25 +193,27 @@ function ResponsiveTabs({
|
|
|
192
193
|
spotlightPadding: 8,
|
|
193
194
|
target: "#discussGroupedDiscussions"
|
|
194
195
|
}, {
|
|
196
|
+
// Submissions no longer have their own list — they were combined into the
|
|
197
|
+
// grouped discussions view, so this step points at the same container.
|
|
195
198
|
content: /*#__PURE__*/_jsxs("div", {
|
|
196
199
|
children: [/*#__PURE__*/_jsx("h2", {
|
|
197
|
-
children: t("
|
|
200
|
+
children: t("discuss_submissions")
|
|
198
201
|
}), /*#__PURE__*/_jsx("br", {}), /*#__PURE__*/_jsx("p", {
|
|
199
|
-
children: t("
|
|
202
|
+
children: t("discuss_submissions_desc")
|
|
200
203
|
})]
|
|
201
204
|
}),
|
|
202
205
|
spotlightPadding: 8,
|
|
203
|
-
target: "#
|
|
206
|
+
target: "#discussGroupedDiscussions"
|
|
204
207
|
}, {
|
|
205
208
|
content: /*#__PURE__*/_jsxs("div", {
|
|
206
209
|
children: [/*#__PURE__*/_jsx("h2", {
|
|
207
|
-
children: t("
|
|
210
|
+
children: t("discuss_refresh_discussions")
|
|
208
211
|
}), /*#__PURE__*/_jsx("br", {}), /*#__PURE__*/_jsx("p", {
|
|
209
|
-
children: t("
|
|
212
|
+
children: t("discuss_refresh_discussions_desc")
|
|
210
213
|
})]
|
|
211
214
|
}),
|
|
212
215
|
spotlightPadding: 8,
|
|
213
|
-
target: "#
|
|
216
|
+
target: "#discussRefreshScheduled"
|
|
214
217
|
}];
|
|
215
218
|
const discussTabIndex = tabs.findIndex(tab => tab.id === "Discuss");
|
|
216
219
|
const [joyrideState, setJoyrideState] = useState({
|
|
@@ -229,19 +232,28 @@ function ResponsiveTabs({
|
|
|
229
232
|
creatorRun,
|
|
230
233
|
creatorSteps
|
|
231
234
|
} = creatorJoyrideState;
|
|
235
|
+
|
|
236
|
+
// The video chat flags resolve async, and the creator's Discuss tab is rendered on
|
|
237
|
+
// `isCreator` alone - it does not wait for `isVideoChatEnabledInSettings`. So a
|
|
238
|
+
// creator can already be sitting on Discuss when the setting flips on, with neither
|
|
239
|
+
// `value` nor `discussTabIndex` changing. Keep the flags in the deps so the tour still
|
|
240
|
+
// starts, and guard on `run`/`creatorRun` so a flag change mid-tour does not cancel
|
|
241
|
+
// the tour's poll and restart it from the first step.
|
|
232
242
|
useEffect(() => {
|
|
233
|
-
if (discussTabIndex === value && !isCreator && !localStorage.getItem(`student-discuss-tour-completed`) && isVideoChatEnabled && isVideoChatEnabledInSettings) {
|
|
234
|
-
setJoyrideState(prevState => ({
|
|
243
|
+
if (discussTabIndex === value && !isCreator && !run && !localStorage.getItem(`student-discuss-tour-completed`) && isVideoChatEnabled && isVideoChatEnabledInSettings) {
|
|
244
|
+
return startJoyrideWhenReady(joyrideSteps, steps => setJoyrideState(prevState => ({
|
|
235
245
|
...prevState,
|
|
236
|
-
run: true
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
246
|
+
run: true,
|
|
247
|
+
steps
|
|
248
|
+
})));
|
|
249
|
+
} else if (discussTabIndex === value && isCreator && !creatorRun && !localStorage.getItem(`creator-discuss-tour-completed`) && isVideoChatEnabled && isVideoChatEnabledInSettings) {
|
|
250
|
+
return startJoyrideWhenReady(creatorJoyrideSteps, creatorSteps => setCreatorJoyrideState(prevState => ({
|
|
240
251
|
...prevState,
|
|
241
|
-
creatorRun: true
|
|
242
|
-
|
|
252
|
+
creatorRun: true,
|
|
253
|
+
creatorSteps
|
|
254
|
+
})));
|
|
243
255
|
}
|
|
244
|
-
}, [value, discussTabIndex]);
|
|
256
|
+
}, [value, discussTabIndex, isCreator, isVideoChatEnabled, isVideoChatEnabledInSettings, run, creatorRun]);
|
|
245
257
|
const handleJoyrideCallback = data => {
|
|
246
258
|
const {
|
|
247
259
|
status,
|
|
@@ -336,6 +348,7 @@ function ResponsiveTabs({
|
|
|
336
348
|
close: t("close"),
|
|
337
349
|
last: t("last"),
|
|
338
350
|
next: t("next"),
|
|
351
|
+
nextWithProgress: t("next_with_progress"),
|
|
339
352
|
skip: t("skip")
|
|
340
353
|
},
|
|
341
354
|
options: {
|
|
@@ -358,6 +371,7 @@ function ResponsiveTabs({
|
|
|
358
371
|
close: t("close"),
|
|
359
372
|
last: t("last"),
|
|
360
373
|
next: t("next"),
|
|
374
|
+
nextWithProgress: t("next_with_progress"),
|
|
361
375
|
skip: t("skip")
|
|
362
376
|
},
|
|
363
377
|
options: {
|
package/dist/hooks/useConfirm.js
CHANGED
|
@@ -4,7 +4,7 @@ export default function useConfirm(t) {
|
|
|
4
4
|
const confirmed = await ConfirmDialog({
|
|
5
5
|
title: title || t("confirmation"),
|
|
6
6
|
text: text || t("are_you_sure"),
|
|
7
|
-
submitText: submitText || t("
|
|
7
|
+
submitText: submitText || t("yes"),
|
|
8
8
|
isDelete: isDelete,
|
|
9
9
|
isArchive: isArchive,
|
|
10
10
|
isUnarchive: isUnarchive,
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for keeping react-joyride tours in sync with what is actually on screen.
|
|
3
|
+
*
|
|
4
|
+
* When a step's target is not in the DOM, react-joyride polls for it for
|
|
5
|
+
* `targetWaitTimeout` (1s by default) while showing its loading spinner, then emits
|
|
6
|
+
* TARGET_NOT_FOUND and jumps to the next step. To the user that reads as a step that
|
|
7
|
+
* "loads" and then gets skipped, and the "x of y" progress count includes steps they
|
|
8
|
+
* never see.
|
|
9
|
+
*
|
|
10
|
+
* Most of our tours target elements that are conditionally rendered - the speak button
|
|
11
|
+
* is hidden for Irish, the word bank toggle depends on course settings, the skip button
|
|
12
|
+
* is hidden in live games - so resolving the steps against the live DOM before the tour
|
|
13
|
+
* starts is what keeps the tour honest.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const DEFAULT_TIMEOUT = 1000;
|
|
17
|
+
const DEFAULT_INTERVAL = 50;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Whether an element and all of its ancestors are visible.
|
|
21
|
+
*
|
|
22
|
+
* Mirrors react-joyride's own check. Being in the DOM is not enough for it: a target
|
|
23
|
+
* inside a `keepMounted` drawer or a closed MUI modal is present but hidden, and
|
|
24
|
+
* joyride treats that exactly like a missing target - spinner, then skip.
|
|
25
|
+
* @param element The element to check
|
|
26
|
+
* @returns {boolean}
|
|
27
|
+
*/
|
|
28
|
+
const isElementVisible = element => {
|
|
29
|
+
if (!element) return false;
|
|
30
|
+
let node = element;
|
|
31
|
+
while (node && node !== document.body) {
|
|
32
|
+
if (node instanceof HTMLElement) {
|
|
33
|
+
const {
|
|
34
|
+
display,
|
|
35
|
+
visibility
|
|
36
|
+
} = getComputedStyle(node);
|
|
37
|
+
if (display === "none" || visibility === "hidden") return false;
|
|
38
|
+
}
|
|
39
|
+
node = node.parentElement;
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Returns true when a joyride step's target is on screen.
|
|
46
|
+
*
|
|
47
|
+
* A step with no target is never resolvable, and it is not merely useless: joyride
|
|
48
|
+
* validates the array with `steps.every(...)`, so one target-less step makes the whole
|
|
49
|
+
* array invalid, `setSteps` is skipped and the tour silently runs the stale list it
|
|
50
|
+
* already had. Those steps have to be dropped, not passed through.
|
|
51
|
+
*
|
|
52
|
+
* `body` is always present. Function targets are left for joyride to resolve, since
|
|
53
|
+
* calling one here would repeat whatever work it does.
|
|
54
|
+
* @param step A joyride step
|
|
55
|
+
* @returns {boolean}
|
|
56
|
+
*/
|
|
57
|
+
export const isJoyrideTargetPresent = step => {
|
|
58
|
+
const target = step && step.target;
|
|
59
|
+
if (!target) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (typeof target === "function") {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
if (typeof target === "object") {
|
|
66
|
+
return "current" in target && isElementVisible(target.current);
|
|
67
|
+
}
|
|
68
|
+
if (typeof target !== "string") {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
if (target === "body") {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
return isElementVisible(document.querySelector(target));
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error(`Invalid joyride target selector: ${target}`, error);
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Drops the steps whose target is not currently rendered. Only useful once the tour's
|
|
84
|
+
* targets have had a chance to mount - prefer `startJoyrideWhenReady` for that.
|
|
85
|
+
* @param steps The full list of joyride steps
|
|
86
|
+
* @returns {Array} The steps that have a target on screen
|
|
87
|
+
*/
|
|
88
|
+
export const resolveJoyrideSteps = (steps = []) => steps.filter(isJoyrideTargetPresent);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Resolves a tour's steps once its targets have mounted, then hands them to `onReady`.
|
|
92
|
+
*
|
|
93
|
+
* Exercises put their tour inside a MUI `Dialog`, and a portal only renders its
|
|
94
|
+
* children on the render after the component that opens it commits. Filtering straight
|
|
95
|
+
* away in an effect would therefore drop every step, so poll until either every target
|
|
96
|
+
* has appeared or `timeout` is reached - whatever is missing by then is a target this
|
|
97
|
+
* screen does not render at all.
|
|
98
|
+
* @param steps The full list of joyride steps
|
|
99
|
+
* @param onReady Called once with the steps that have a target on screen
|
|
100
|
+
* @param options.timeout How long to wait for missing targets, in ms
|
|
101
|
+
* @param options.interval How often to re-check, in ms
|
|
102
|
+
* @returns {Function} Cancels the pending check - use it as an effect cleanup
|
|
103
|
+
*/
|
|
104
|
+
export const startJoyrideWhenReady = (steps = [], onReady, options = {}) => {
|
|
105
|
+
const {
|
|
106
|
+
timeout = DEFAULT_TIMEOUT,
|
|
107
|
+
interval = DEFAULT_INTERVAL
|
|
108
|
+
} = options;
|
|
109
|
+
let timeoutId = null;
|
|
110
|
+
let cancelled = false;
|
|
111
|
+
let waited = 0;
|
|
112
|
+
const check = () => {
|
|
113
|
+
if (cancelled) return;
|
|
114
|
+
const resolved = resolveJoyrideSteps(steps);
|
|
115
|
+
if (resolved.length === steps.length || waited >= timeout) {
|
|
116
|
+
onReady(resolved);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
waited += interval;
|
|
120
|
+
timeoutId = setTimeout(check, interval);
|
|
121
|
+
};
|
|
122
|
+
check();
|
|
123
|
+
return () => {
|
|
124
|
+
cancelled = true;
|
|
125
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
126
|
+
};
|
|
127
|
+
};
|