@nualang/nualang-ui-components 0.1.1374 → 0.1.1377

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { useState, useEffect } from "react";
2
- import { Grid, Box, FormControlLabel, Switch, Typography, Slider, TextField, InputAdornment, Tooltip } from "@mui/material";
2
+ import { Grid, Box, FormControlLabel, Switch, Typography, Slider, TextField, InputAdornment, Tooltip, Checkbox, ListItemText, OutlinedInput, Select, InputLabel, FormControl, MenuItem } from "@mui/material";
3
3
  import InfoIcon from "@mui/icons-material/Info";
4
4
  import Alert from "@mui/material/Alert";
5
5
  import LinearProgress from "@mui/material/LinearProgress";
@@ -51,10 +51,12 @@ function GenerateBotDialog({
51
51
  bot,
52
52
  siteLanguage,
53
53
  topicPhrases,
54
+ phraseLists,
54
55
  updateRivescriptJSON,
55
56
  initialTopicGoal
56
57
  }) {
57
58
  const [usePhrasesContext, setUsePhrasesContext] = useState(true);
59
+ const [selectedPhraseListIds, setSelectedPhraseListIds] = useState(["all"]);
58
60
  const [topicGoal, setTopicGoal] = useState("");
59
61
  const [phrases, setPhrases] = useState([]);
60
62
  const [isBotGenerating, setIsBotGenerating] = useState(false);
@@ -84,9 +86,24 @@ function GenerateBotDialog({
84
86
  setPhrases([...topicPhrases]);
85
87
  }
86
88
  }, [initialTopicGoal, topicPhrases]);
89
+ const isPhrasesSwitchDisabled = phrases.length === 0 || !phraseLists || phraseLists.length === 0 || !phraseLists.some(pl => pl.phrases && pl.phrases.length > 0);
90
+ useEffect(() => {
91
+ if (isPhrasesSwitchDisabled) {
92
+ setUsePhrasesContext(false);
93
+ }
94
+ }, [isPhrasesSwitchDisabled]);
87
95
  const handleCloseDialog = () => {
88
96
  setIsGenerateBotDialogOpen(false);
89
97
  };
98
+ const effectivePhrases = !phraseLists || phraseLists.length === 0 || selectedPhraseListIds.includes("all") ? phrases : phraseLists.filter(pl => selectedPhraseListIds.includes(pl.id)).flatMap(pl => pl.phrases);
99
+ const handlePhraseListChange = event => {
100
+ const newValue = event.target.value;
101
+ if (newValue[newValue.length - 1] === "all") {
102
+ setSelectedPhraseListIds(["all"]);
103
+ } else {
104
+ setSelectedPhraseListIds(newValue.filter(v => v !== "all"));
105
+ }
106
+ };
90
107
 
91
108
  // const removeExtraTextFromChatGptResponse = (response) => {
92
109
  // let stack = [];
@@ -170,7 +187,7 @@ function GenerateBotDialog({
170
187
  siteLanguage: siteLanguage,
171
188
  difficulty: bot.difficulty,
172
189
  sampleQuestionArray: sampleQuestionArray,
173
- phrases: phrases,
190
+ phrases: effectivePhrases,
174
191
  usePhrasesContext: usePhrasesContext
175
192
  }
176
193
  });
@@ -336,7 +353,7 @@ function GenerateBotDialog({
336
353
  label: "",
337
354
  control: /*#__PURE__*/_jsx(_Fragment, {
338
355
  children: /*#__PURE__*/_jsx(Tooltip, {
339
- title: phrases.length === 0 ? t("topic_no_phrases") : "",
356
+ title: isPhrasesSwitchDisabled ? t("topic_no_phrases") : "",
340
357
  children: /*#__PURE__*/_jsx("span", {
341
358
  children: /*#__PURE__*/_jsx(Switch, {
342
359
  checked: usePhrasesContext,
@@ -349,12 +366,46 @@ function GenerateBotDialog({
349
366
  sx: {
350
367
  marginLeft: 0.5
351
368
  },
352
- disabled: phrases.length === 0
369
+ disabled: isPhrasesSwitchDisabled
353
370
  })
354
371
  })
355
372
  })
356
373
  })
357
374
  })]
375
+ }), usePhrasesContext && phraseLists && phraseLists.length > 0 && /*#__PURE__*/_jsx(Grid, {
376
+ mb: 2,
377
+ size: 12,
378
+ mt: 2,
379
+ children: /*#__PURE__*/_jsxs(FormControl, {
380
+ fullWidth: true,
381
+ size: "small",
382
+ children: [/*#__PURE__*/_jsx(InputLabel, {
383
+ children: t("phrase_lists")
384
+ }), /*#__PURE__*/_jsxs(Select, {
385
+ multiple: true,
386
+ value: selectedPhraseListIds,
387
+ onChange: handlePhraseListChange,
388
+ input: /*#__PURE__*/_jsx(OutlinedInput, {
389
+ label: t("phrase_lists")
390
+ }),
391
+ renderValue: selected => selected.includes("all") ? t("all") : phraseLists.filter(pl => selected.includes(pl.id)).map(pl => pl.name).join(", "),
392
+ children: [/*#__PURE__*/_jsxs(MenuItem, {
393
+ value: "all",
394
+ children: [/*#__PURE__*/_jsx(Checkbox, {
395
+ checked: selectedPhraseListIds.includes("all")
396
+ }), /*#__PURE__*/_jsx(ListItemText, {
397
+ primary: t("all")
398
+ })]
399
+ }), phraseLists.map(pl => /*#__PURE__*/_jsxs(MenuItem, {
400
+ value: pl.id,
401
+ children: [/*#__PURE__*/_jsx(Checkbox, {
402
+ checked: selectedPhraseListIds.includes(pl.id)
403
+ }), /*#__PURE__*/_jsx(ListItemText, {
404
+ primary: pl.name
405
+ })]
406
+ }, pl.id))]
407
+ })]
408
+ })
358
409
  })]
359
410
  }), errorMessage && /*#__PURE__*/_jsx(Grid, {
360
411
  mt: 2,
@@ -4,7 +4,7 @@ import { jsonrepair } from "jsonrepair";
4
4
  import RemoveRedEyeOutlinedIcon from "@mui/icons-material/RemoveRedEyeOutlined";
5
5
  import AutoFixHighIcon from "@mui/icons-material/AutoFixHigh";
6
6
  import InfoIcon from "@mui/icons-material/Info";
7
- import { Grid, Button, Box, TextField, MenuItem, IconButton, FormControlLabel, Switch, Typography, Tooltip, FormGroup, Slider, InputAdornment } from "@mui/material";
7
+ import { Grid, Button, Box, TextField, MenuItem, IconButton, FormControlLabel, Switch, Typography, Tooltip, Slider, InputAdornment, Checkbox, ListItemText, OutlinedInput, Select, InputLabel, FormControl } from "@mui/material";
8
8
  import LoadingButton from "@mui/lab/LoadingButton";
9
9
  import Alert from "@mui/material/Alert";
10
10
  import LinearProgress from "@mui/material/LinearProgress";
@@ -53,12 +53,14 @@ function GenerateRoleplayDialog({
53
53
  pdfVectorStoreCreationStatus,
54
54
  siteLanguage,
55
55
  phrases,
56
+ phraseLists,
56
57
  topicId,
57
58
  initialTopicGoal
58
59
  }) {
59
60
  const [isPreviewDialogOpen, setIsPreviewDialogOpen] = useState(false);
60
61
  const [usePdfContext, setUsePdfContext] = useState(false);
61
62
  const [usePhrasesContext, setUsePhrasesContext] = useState(phrases && phrases.length > 0);
63
+ const [selectedPhraseListIds, setSelectedPhraseListIds] = useState(["all"]);
62
64
  const [topicGoal, setTopicGoal] = useState("");
63
65
  const [isRoleplayGenerating, setIsRoleplayGenerating] = useState(false);
64
66
  const [generatedRoleplay, setGeneratedRoleplay] = useState([]);
@@ -176,7 +178,7 @@ function GenerateRoleplayDialog({
176
178
  const roleplayDifficulty = values.roleplayDifficulty;
177
179
  const basePrompt = usePdfContext ? `Create an informative conversation between 2 people ${values?.actor1?.name && values?.actor2?.name ? `'${values.actor1.name}' and '${values.actor2.name}' ` : ""} about the topic '${values.roleplayTopic}' in the language ${learnLang}. The conversation should be ${i18nLanguage === "en-US" ? "ACTFL" : "CEFR"} level '${t(roleplayDifficulty)}.'` : `Create a conversation between 2 people ${values?.actor1?.name && values?.actor2?.name ? `'${values.actor1.name}' and '${values.actor2?.name}' ` : ""} about the topic '${values.roleplayTopic}' in the language ${learnLang}. The conversation should be ${i18nLanguage === "en-US" ? "ACTFL" : "CEFR"} level '${t(roleplayDifficulty)}.'`;
178
180
  const topicGoalPrompt = topicGoal ? ` The conversation should be guided by the following goal: '${topicGoal}'.` : "";
179
- const promptWithPhrases = usePhrasesContext ? ` Additionally, use the following phrases as part of the conversation, where appropriate to the topic '${values.roleplayTopic}': ${phrases.map(phrase => phrase.phrase).join(", ")}. Only use these phrases if they fit naturally into the conversation.` : "";
181
+ const promptWithPhrases = usePhrasesContext ? ` Additionally, use the following phrases as part of the conversation, where appropriate to the topic '${values.roleplayTopic}': ${effectivePhrases.map(phrase => phrase.phrase).join(", ")}. Only use these phrases if they fit naturally into the conversation.` : "";
180
182
  const finalPrompt = `${basePrompt}${topicGoalPrompt}${promptWithPhrases}`;
181
183
 
182
184
  // Add explicit JSON formatting instructions with roleplay length
@@ -213,7 +215,7 @@ function GenerateRoleplayDialog({
213
215
  usePdfContext: usePdfContext,
214
216
  topicGoal: topicGoal,
215
217
  usePhrasesContext: usePhrasesContext,
216
- phrases: phrases,
218
+ phrases: effectivePhrases,
217
219
  questionLang: questionLang,
218
220
  generateQuestions: generateQuestions,
219
221
  actor1: values.actor1,
@@ -309,7 +311,18 @@ function GenerateRoleplayDialog({
309
311
  } else {
310
312
  isSubmitDisabled = !(generatedRoleplay.length !== 0 && !isRoleplayGenerating && previewMessages.length > 1);
311
313
  }
312
- const isPhrasesSwitchDisabled = !topicId || !phrases || phrases.length === 0;
314
+ const isPhrasesSwitchDisabled = !topicId || !phrases || phrases.length === 0 || !phraseLists || phraseLists.length === 0 || !phrases.some(p => phraseLists.some(pl => pl.id === p.phraseListId));
315
+ const effectivePhrases = !phraseLists || phraseLists.length === 0 || selectedPhraseListIds.includes("all") ? phrases : phrases.filter(p => selectedPhraseListIds.includes(p.phraseListId));
316
+ const handlePhraseListChange = event => {
317
+ const newValue = event.target.value;
318
+ if (newValue[newValue.length - 1] === "all") {
319
+ setSelectedPhraseListIds(["all"]);
320
+ } else if (newValue.filter(v => v !== "all").length === 0) {
321
+ setSelectedPhraseListIds(["all"]);
322
+ } else {
323
+ setSelectedPhraseListIds(newValue.filter(v => v !== "all"));
324
+ }
325
+ };
313
326
  useEffect(() => {
314
327
  if (!generateQuestions) {
315
328
  setValues(prevValues => ({
@@ -323,6 +336,11 @@ function GenerateRoleplayDialog({
323
336
  }));
324
337
  }
325
338
  }, [generateQuestions]);
339
+ useEffect(() => {
340
+ if (isPhrasesSwitchDisabled) {
341
+ setUsePhrasesContext(false);
342
+ }
343
+ }, [isPhrasesSwitchDisabled]);
326
344
  return /*#__PURE__*/_jsxs(ResponsiveDialog, {
327
345
  open: isGenerateRoleplayDialogOpen,
328
346
  handleClose: handleCloseDialog,
@@ -468,47 +486,37 @@ function GenerateRoleplayDialog({
468
486
  min: 4,
469
487
  max: 12
470
488
  })]
471
- }), /*#__PURE__*/_jsx(FormGroup, {
472
- children: /*#__PURE__*/_jsx(Grid, {
473
- marginBottom: 1,
474
- size: 12,
475
- children: /*#__PURE__*/_jsx(Box, {
489
+ }), /*#__PURE__*/_jsxs(Grid, {
490
+ marginBottom: 1,
491
+ size: 12,
492
+ children: [/*#__PURE__*/_jsx(Typography, {
493
+ children: /*#__PURE__*/_jsxs(Box, {
494
+ pt: 2,
476
495
  display: "flex",
477
496
  alignItems: "center",
478
- justifyContent: "space-between",
479
- children: /*#__PURE__*/_jsx(FormControlLabel, {
480
- control: /*#__PURE__*/_jsx(Switch, {
481
- checked: generateQuestions,
482
- onChange: e => setGenerateQuestions(e.target.checked),
483
- inputProps: {
484
- "aria-label": "Generate Questions"
485
- },
486
- color: "primary"
487
- }),
488
- label: /*#__PURE__*/_jsxs(Box, {
489
- display: "flex",
490
- alignItems: "center",
491
- children: [/*#__PURE__*/_jsx(Typography, {
492
- children: t("generate_questions")
493
- }), /*#__PURE__*/_jsx(Tooltip, {
494
- title: t("enable_gen_questions"),
495
- placement: "top",
496
- children: /*#__PURE__*/_jsx(InfoIcon, {
497
- fontSize: "small",
498
- style: {
499
- marginLeft: 4,
500
- color: "lightgrey"
501
- } // Light grey color for info icon
502
- })
503
- })]
504
- }),
505
- labelPlacement: "start",
506
- sx: {
507
- marginRight: 0
508
- }
509
- })
497
+ children: [t("generate_questions"), /*#__PURE__*/_jsx(Tooltip, {
498
+ title: t("enable_gen_questions"),
499
+ placement: "top",
500
+ children: /*#__PURE__*/_jsx(InfoIcon, {
501
+ fontSize: "small",
502
+ style: {
503
+ marginLeft: 4,
504
+ color: "lightgrey"
505
+ }
506
+ })
507
+ })]
510
508
  })
511
- })
509
+ }), /*#__PURE__*/_jsx(FormControlLabel, {
510
+ label: "",
511
+ control: /*#__PURE__*/_jsx(Switch, {
512
+ checked: generateQuestions,
513
+ onChange: e => setGenerateQuestions(e.target.checked),
514
+ inputProps: {
515
+ "aria-label": "Generate Questions"
516
+ },
517
+ color: "primary"
518
+ })
519
+ })]
512
520
  }), generateQuestions && /*#__PURE__*/_jsxs(_Fragment, {
513
521
  children: [finalForLang !== learnLang.charAt(0).toUpperCase() + learnLang.slice(1) && /*#__PURE__*/_jsx(Grid, {
514
522
  mb: 2,
@@ -549,48 +557,74 @@ function GenerateRoleplayDialog({
549
557
  max: Math.floor(values?.roleplayLengthNumber / 2)
550
558
  })]
551
559
  })]
552
- }), topicId && /*#__PURE__*/_jsx(FormGroup, {
553
- children: /*#__PURE__*/_jsx(Grid, {
560
+ }), topicId && /*#__PURE__*/_jsxs(_Fragment, {
561
+ children: [/*#__PURE__*/_jsxs(Grid, {
554
562
  marginBottom: 1,
555
563
  size: 12,
556
- children: /*#__PURE__*/_jsx(Box, {
557
- display: "flex",
558
- alignItems: "center",
559
- justifyContent: "space-between",
560
- children: /*#__PURE__*/_jsx(FormControlLabel, {
561
- control: /*#__PURE__*/_jsx(Switch, {
562
- checked: usePhrasesContext,
563
- onChange: e => setUsePhrasesContext(e.target.checked),
564
- inputProps: {
565
- "aria-label": "Use context from topic phrases"
566
- },
567
- color: "primary",
568
- disabled: isPhrasesSwitchDisabled
564
+ children: [/*#__PURE__*/_jsx(Typography, {
565
+ children: /*#__PURE__*/_jsxs(Box, {
566
+ pt: 2,
567
+ display: "flex",
568
+ alignItems: "center",
569
+ children: [t("use_topic_phrases"), /*#__PURE__*/_jsx(Tooltip, {
570
+ title: isPhrasesSwitchDisabled ? t("add_phrase_context") : t("enable_phrase_context"),
571
+ placement: "top",
572
+ children: /*#__PURE__*/_jsx(InfoIcon, {
573
+ fontSize: "small",
574
+ style: {
575
+ marginLeft: 4,
576
+ color: "lightgrey"
577
+ }
578
+ })
579
+ })]
580
+ })
581
+ }), /*#__PURE__*/_jsx(FormControlLabel, {
582
+ label: "",
583
+ control: /*#__PURE__*/_jsx(Switch, {
584
+ checked: usePhrasesContext,
585
+ onChange: e => setUsePhrasesContext(e.target.checked),
586
+ inputProps: {
587
+ "aria-label": "Use context from topic phrases"
588
+ },
589
+ color: "primary",
590
+ disabled: isPhrasesSwitchDisabled
591
+ })
592
+ })]
593
+ }), usePhrasesContext && phraseLists && phraseLists.length > 0 && /*#__PURE__*/_jsx(Grid, {
594
+ mb: 2,
595
+ size: 12,
596
+ mt: 2,
597
+ children: /*#__PURE__*/_jsxs(FormControl, {
598
+ fullWidth: true,
599
+ size: "small",
600
+ children: [/*#__PURE__*/_jsx(InputLabel, {
601
+ children: t("phrase_lists")
602
+ }), /*#__PURE__*/_jsxs(Select, {
603
+ multiple: true,
604
+ value: selectedPhraseListIds,
605
+ onChange: handlePhraseListChange,
606
+ input: /*#__PURE__*/_jsx(OutlinedInput, {
607
+ label: t("phrase_lists")
569
608
  }),
570
- label: /*#__PURE__*/_jsxs(Box, {
571
- display: "flex",
572
- alignItems: "center",
573
- children: [/*#__PURE__*/_jsx(Typography, {
574
- children: t("use_topic_phrases")
575
- }), /*#__PURE__*/_jsx(Tooltip, {
576
- title: isPhrasesSwitchDisabled ? t("add_phrase_context") : t("enable_phrase_context"),
577
- placement: "top",
578
- children: /*#__PURE__*/_jsx(InfoIcon, {
579
- fontSize: "small",
580
- style: {
581
- marginLeft: 4,
582
- color: "lightgrey"
583
- } // Light grey color for info icon
584
- })
609
+ renderValue: selected => selected.includes("all") ? t("all") : phraseLists.filter(pl => selected.includes(pl.id)).map(pl => pl.name).join(", "),
610
+ children: [/*#__PURE__*/_jsxs(MenuItem, {
611
+ value: "all",
612
+ children: [/*#__PURE__*/_jsx(Checkbox, {
613
+ checked: selectedPhraseListIds.includes("all")
614
+ }), /*#__PURE__*/_jsx(ListItemText, {
615
+ primary: t("all")
585
616
  })]
586
- }),
587
- labelPlacement: "start",
588
- sx: {
589
- marginRight: 0
590
- }
591
- })
617
+ }), phraseLists.map(pl => /*#__PURE__*/_jsxs(MenuItem, {
618
+ value: pl.id,
619
+ children: [/*#__PURE__*/_jsx(Checkbox, {
620
+ checked: selectedPhraseListIds.includes(pl.id)
621
+ }), /*#__PURE__*/_jsx(ListItemText, {
622
+ primary: pl.name
623
+ })]
624
+ }, pl.id))]
625
+ })]
592
626
  })
593
- })
627
+ })]
594
628
  })]
595
629
  }), import.meta.env.REACT_APP_STAGE === "dev" && !isRoleplayGenerating && pdfDetails && pdfVectorStoreCreationStatus === "CREATION_COMPLETE" && /*#__PURE__*/_jsxs(Grid, {
596
630
  size: 12,
@@ -106,6 +106,7 @@ function Bot({
106
106
  generateRiveFile,
107
107
  siteLanguage,
108
108
  topicPhrases,
109
+ phraseLists,
109
110
  courseId,
110
111
  sectionId,
111
112
  topicId,
@@ -766,6 +767,7 @@ function Bot({
766
767
  learnLang: learnLang,
767
768
  siteLanguage: siteLanguage,
768
769
  topicPhrases: topicPhrases,
770
+ phraseLists: phraseLists,
769
771
  updateRivescriptJSON: updateRivescriptJSON,
770
772
  courseId: courseId,
771
773
  sectionId: sectionId,
@@ -87,6 +87,7 @@ function Editor({
87
87
  siteLanguage,
88
88
  learnLang,
89
89
  topicPhrases,
90
+ phraseLists,
90
91
  updateRivescriptJSON,
91
92
  courseId,
92
93
  sectionId,
@@ -537,6 +538,7 @@ function Editor({
537
538
  bot: bot,
538
539
  siteLanguage: siteLanguage,
539
540
  topicPhrases: topicPhrases,
541
+ phraseLists: phraseLists,
540
542
  updateRivescriptJSON: updateRivescriptJSON,
541
543
  initialTopicGoal: initialTopicGoal
542
544
  })]
@@ -88,6 +88,8 @@ function PhraseList({
88
88
  touched,
89
89
  initialValues,
90
90
  onSubmit,
91
+ onSubmitInfo,
92
+ onSubmitExerciseSettings,
91
93
  handleChange,
92
94
  handleUpdatePhrases,
93
95
  handlePlayPhraseList,
@@ -370,6 +372,8 @@ function PhraseList({
370
372
  voiceOptions: voices,
371
373
  isUserInternal: isUserInternal,
372
374
  onSubmit: onSubmit,
375
+ onSubmitInfo: onSubmitInfo,
376
+ onSubmitExerciseSettings: onSubmitExerciseSettings,
373
377
  handleSpeak: handleSpeak,
374
378
  fileSizeLimit: fileSizeLimit,
375
379
  verificationStatus: verificationStatus
@@ -275,6 +275,7 @@ function Roleplay({
275
275
  makeCandooAIQuery,
276
276
  siteLanguage,
277
277
  phrases,
278
+ phraseLists,
278
279
  topicId,
279
280
  initialTopicGoal,
280
281
  isUserInternal,
@@ -915,6 +916,7 @@ function Roleplay({
915
916
  actor2: roleplay.actor2
916
917
  },
917
918
  phrases: phrases,
919
+ phraseLists: phraseLists,
918
920
  topicId: topicId,
919
921
  initialTopicGoal: initialTopicGoal,
920
922
  autoSelect: true
@@ -45,6 +45,8 @@ export default function UpdatePhraseList({
45
45
  t = text => text,
46
46
  initialValues: rawInitialValues = {},
47
47
  onSubmit,
48
+ onSubmitInfo,
49
+ onSubmitExerciseSettings,
48
50
  learnLang,
49
51
  isUserInternal,
50
52
  enableReinitialize,
@@ -56,44 +58,47 @@ export default function UpdatePhraseList({
56
58
  const {
57
59
  classes
58
60
  } = useStyles();
59
- const initialValues = {
60
- phraseListName: "",
61
- description: "",
62
- shuffleEnabled: "enabled",
63
- voice: null,
64
- voicePitch: null,
65
- voiceLanguageCode: null,
66
- hiddenPhraseGroupGames: {},
67
- isKeyboardHiddenPhraseGroupGames: {},
68
- hiddenWordBankPhraseGroupGames: {},
69
- ...rawInitialValues
61
+ const infoInitialValues = {
62
+ phraseListName: rawInitialValues.phraseListName ?? "",
63
+ description: rawInitialValues.description ?? "",
64
+ picture: rawInitialValues.picture ?? ""
70
65
  };
66
+ const exerciseInitialValues = {
67
+ shuffleEnabled: rawInitialValues.shuffleEnabled ?? "enabled",
68
+ voice: rawInitialValues.voice ?? null,
69
+ voicePitch: rawInitialValues.voicePitch ?? null,
70
+ voiceLanguageCode: rawInitialValues.voiceLanguageCode ?? null,
71
+ hiddenPhraseGroupGames: rawInitialValues.hiddenPhraseGroupGames ?? {},
72
+ isKeyboardHiddenPhraseGroupGames: rawInitialValues.isKeyboardHiddenPhraseGroupGames ?? {},
73
+ hiddenWordBankPhraseGroupGames: rawInitialValues.hiddenWordBankPhraseGroupGames ?? {}
74
+ };
75
+ const handleSubmitInfo = onSubmitInfo ?? onSubmit;
76
+ const handleSubmitExercise = onSubmitExerciseSettings ?? onSubmit;
71
77
  return /*#__PURE__*/_jsx("div", {
72
78
  className: classes.container,
73
- children: /*#__PURE__*/_jsx(Formik, {
74
- initialValues: initialValues,
75
- enableReinitialize: enableReinitialize,
76
- onSubmit: onSubmit,
77
- children: ({
78
- handleChange,
79
- handleSubmit,
80
- handleBlur,
81
- isSubmitting,
82
- dirty,
83
- values,
84
- errors,
85
- touched,
86
- setFieldValue
87
- }) => /*#__PURE__*/_jsx("form", {
88
- onSubmit: handleSubmit,
89
- children: /*#__PURE__*/_jsxs(Grid, {
90
- container: true,
91
- sx: {
92
- width: "100%"
93
- },
94
- spacing: 1,
95
- children: [/*#__PURE__*/_jsx(Grid, {
96
- size: 12,
79
+ children: /*#__PURE__*/_jsxs(Grid, {
80
+ container: true,
81
+ sx: {
82
+ width: "100%"
83
+ },
84
+ spacing: 1,
85
+ children: [/*#__PURE__*/_jsx(Grid, {
86
+ size: 12,
87
+ children: /*#__PURE__*/_jsx(Formik, {
88
+ initialValues: infoInitialValues,
89
+ enableReinitialize: enableReinitialize,
90
+ onSubmit: handleSubmitInfo,
91
+ children: ({
92
+ handleChange,
93
+ handleSubmit,
94
+ handleBlur,
95
+ isSubmitting,
96
+ dirty,
97
+ values,
98
+ errors,
99
+ touched
100
+ }) => /*#__PURE__*/_jsx("form", {
101
+ onSubmit: handleSubmit,
97
102
  children: /*#__PURE__*/_jsxs(Card, {
98
103
  children: [/*#__PURE__*/_jsx(CardHeader, {
99
104
  title: /*#__PURE__*/_jsx(Typography, {
@@ -185,10 +190,37 @@ export default function UpdatePhraseList({
185
190
  })]
186
191
  })]
187
192
  })
193
+ }), /*#__PURE__*/_jsx(Divider, {}), /*#__PURE__*/_jsx(CardActions, {
194
+ className: classes.padding,
195
+ children: /*#__PURE__*/_jsx(Button, {
196
+ type: "submit",
197
+ color: "primary",
198
+ variant: "contained",
199
+ disabled: isSubmitting || !dirty,
200
+ children: t("save_changes")
201
+ })
188
202
  })]
189
203
  })
190
- }), /*#__PURE__*/_jsx(Grid, {
191
- size: 12,
204
+ })
205
+ })
206
+ }), /*#__PURE__*/_jsx(Grid, {
207
+ size: 12,
208
+ children: /*#__PURE__*/_jsx(Formik, {
209
+ initialValues: exerciseInitialValues,
210
+ enableReinitialize: enableReinitialize,
211
+ onSubmit: handleSubmitExercise,
212
+ children: ({
213
+ handleChange,
214
+ handleSubmit,
215
+ handleBlur,
216
+ isSubmitting,
217
+ dirty,
218
+ values,
219
+ errors,
220
+ touched,
221
+ setFieldValue
222
+ }) => /*#__PURE__*/_jsx("form", {
223
+ onSubmit: handleSubmit,
192
224
  children: /*#__PURE__*/_jsxs(Card, {
193
225
  children: [/*#__PURE__*/_jsx(CardHeader, {
194
226
  title: /*#__PURE__*/_jsx(Typography, {
@@ -443,9 +475,9 @@ export default function UpdatePhraseList({
443
475
  })
444
476
  })]
445
477
  })
446
- })]
478
+ })
447
479
  })
448
- })
480
+ })]
449
481
  })
450
482
  });
451
483
  }
@@ -1145,6 +1145,7 @@ function CourseOutline({
1145
1145
  isClassroomArchived = false,
1146
1146
  classroomId,
1147
1147
  isChallengeModeStudent = false,
1148
+ isReadWriteModeStudent = false,
1148
1149
  ...otherProps
1149
1150
  }) {
1150
1151
  const [percentageCompletion, setPercentageCompletion] = useState({
@@ -1155,7 +1156,7 @@ function CourseOutline({
1155
1156
  const [sects, setSects] = useState([]);
1156
1157
  useEffect(() => {
1157
1158
  if (isMember) {
1158
- const sectionsWithProgress = calcCompletions(sections, completions, null, isChallengeModeStudent);
1159
+ const sectionsWithProgress = calcCompletions(sections, completions, null, isChallengeModeStudent, isReadWriteModeStudent);
1159
1160
  const percentCompletion = calcPercentageCompletion(sectionsWithProgress);
1160
1161
  setSects(sectionsWithProgress);
1161
1162
  setPercentageCompletion(percentCompletion);
@@ -1167,7 +1168,7 @@ function CourseOutline({
1167
1168
  percentage: 0
1168
1169
  });
1169
1170
  }
1170
- }, [isMember, isChallengeModeStudent, JSON.stringify(sections), JSON.stringify(completions)]);
1171
+ }, [isMember, isChallengeModeStudent, isReadWriteModeStudent, JSON.stringify(sections), JSON.stringify(completions)]);
1171
1172
  const moveSection = useCallback((dragIndex, hoverIndex) => {
1172
1173
  const dragSection = sects[dragIndex];
1173
1174
  const newSections = update(sects, {
@@ -508,6 +508,7 @@ function Classroom({
508
508
  email,
509
509
  isLoadingAssignments,
510
510
  isChallengeModeStudent,
511
+ isReadWriteModeStudent,
511
512
  makeChatGptApiRequest,
512
513
  siteLanguage
513
514
  }) {
@@ -1000,7 +1001,8 @@ function Classroom({
1000
1001
  completionHelpers: completionHelpers,
1001
1002
  preferred_username: preferred_username,
1002
1003
  isLoadingAssignments: isLoadingAssignments,
1003
- isChallengeModeStudent: isChallengeModeStudent
1004
+ isChallengeModeStudent: isChallengeModeStudent,
1005
+ isReadWriteModeStudent: isReadWriteModeStudent
1004
1006
  })
1005
1007
  }, `tab-content-assignments`)
1006
1008
  }, ...(isVideoChatEnabled && isNualangLiveEnabled && (isMember && isVideoChatEnabledInSettings || isCreator) ? [{
@@ -1714,6 +1716,7 @@ export default function ViewClassroom({
1714
1716
  createdGame,
1715
1717
  isNualangLiveEnabled,
1716
1718
  isChallengeModeStudent,
1719
+ isReadWriteModeStudent,
1717
1720
  handleCreateAssignment,
1718
1721
  handleEditAssignment,
1719
1722
  assignments,
@@ -1804,6 +1807,7 @@ export default function ViewClassroom({
1804
1807
  createdGame: createdGame,
1805
1808
  isNualangLiveEnabled: isNualangLiveEnabled,
1806
1809
  isChallengeModeStudent: isChallengeModeStudent,
1810
+ isReadWriteModeStudent: isReadWriteModeStudent,
1807
1811
  handleCreateAssignment: handleCreateAssignment,
1808
1812
  handleEditAssignment: handleEditAssignment,
1809
1813
  assignments: assignments,
@@ -324,6 +324,7 @@ function Course({
324
324
  loading,
325
325
  featureFlags,
326
326
  isChallengeModeStudent,
327
+ isReadWriteModeStudent,
327
328
  ...otherProps
328
329
  }) {
329
330
  const {
@@ -644,7 +645,8 @@ function Course({
644
645
  courseSettings: courseSettings,
645
646
  verificationStatus: verificationStatus,
646
647
  handleDeletePDF: handleDeleteSectionPDF,
647
- isChallengeModeStudent: isChallengeModeStudent
648
+ isChallengeModeStudent: isChallengeModeStudent,
649
+ isReadWriteModeStudent: isReadWriteModeStudent
648
650
  })
649
651
  })
650
652
  }), !isLoading && !isSectionsLoading && sections.length === 0 && /*#__PURE__*/_jsx(SectionsNotFound, {
@@ -1010,6 +1012,8 @@ export default function ViewCourse({
1010
1012
  addCourseToClassroom,
1011
1013
  openSnackbar,
1012
1014
  handleDeleteCourseVideo,
1015
+ isChallengeModeStudent,
1016
+ isReadWriteModeStudent,
1013
1017
  ...otherProps
1014
1018
  }) {
1015
1019
  const {
@@ -1034,6 +1038,8 @@ export default function ViewCourse({
1034
1038
  addCourseToClassroom: addCourseToClassroom,
1035
1039
  openSnackbar: openSnackbar,
1036
1040
  isStudent: isStudent,
1041
+ isChallengeModeStudent: isChallengeModeStudent,
1042
+ isReadWriteModeStudent: isReadWriteModeStudent,
1037
1043
  ...otherProps
1038
1044
  })
1039
1045
  }), !isLoading && Object.keys(safeCourse).length === 0 && /*#__PURE__*/_jsx(CourseNotFound, {
@@ -100,7 +100,6 @@ const useStyles = makeStyles()(theme => ({
100
100
  position: "relative"
101
101
  }
102
102
  }));
103
- console.log("ViewTopic render");
104
103
  function OverflowMenu({
105
104
  t,
106
105
  topicId,
@@ -510,14 +509,14 @@ function Topic({
510
509
  const handleCloseViewPdf = () => setIsViewPdfOpen(false);
511
510
  const topicCompletion = useMemo(() => {
512
511
  if (isMember && topic?.topicId && topic?.completions?.length) {
513
- return calcTopicCompletions(topic, topic.completions, false, null, isChallengeModeStudent).completion;
512
+ return calcTopicCompletions(topic, topic.completions, false, null, isChallengeModeStudent, isReadWriteModeStudent).completion;
514
513
  }
515
514
  return {
516
515
  completed: 0,
517
516
  total: 0,
518
517
  percentage: 0
519
518
  };
520
- }, [isMember, topic?.topicId, topic?.completions?.length, isChallengeModeStudent]);
519
+ }, [isMember, topic?.topicId, topic?.completions?.length, isChallengeModeStudent, isReadWriteModeStudent]);
521
520
  const {
522
521
  percentage,
523
522
  completed,
@@ -17,6 +17,7 @@ export default function useClassroomState({
17
17
  const classroomMemberData = queryClient.getQueryData(classrooms.classroomKeys.itemMember(classroomId, username, memberId));
18
18
  const [isMember, setIsMember] = useState(classroomMemberData?.Item ? true : false);
19
19
  const [isChallengeModeStudent, setisChallengeModeStudent] = useState(classroomMemberData?.Item?.assignedLabels && classroomMemberData?.Item?.assignedLabels.isChallengeModeStudent === true);
20
+ const [isReadWriteModeStudent, setIsReadWriteModeStudent] = useState(classroomMemberData?.Item?.assignedLabels && classroomMemberData?.Item?.assignedLabels.isReadWriteModeStudent === true);
20
21
  let filters = {
21
22
  limit: config.limits.classroomMembers
22
23
  };
@@ -38,14 +39,17 @@ export default function useClassroomState({
38
39
  if (memberQuery.isSuccess) {
39
40
  const isClassroomMember = memberQuery.data && memberQuery.data.Item ? true : false;
40
41
  const isChallengeModeStudent = memberQuery.data?.Item?.assignedLabels && memberQuery.data?.Item?.assignedLabels.isChallengeModeStudent === true;
42
+ const isReadWriteModeStudent = memberQuery.data?.Item?.assignedLabels && memberQuery.data?.Item?.assignedLabels.isReadWriteModeStudent === true;
41
43
  setIsMember(isClassroomMember);
42
44
  setisChallengeModeStudent(isChallengeModeStudent);
45
+ setIsReadWriteModeStudent(isReadWriteModeStudent);
43
46
  }
44
47
  }, [memberQuery.data, memberQuery.isSuccess, memberId]);
45
48
  return {
46
49
  isMember,
47
50
  membersQuery,
48
51
  memberQuery,
49
- isChallengeModeStudent
52
+ isChallengeModeStudent,
53
+ isReadWriteModeStudent
50
54
  };
51
55
  }
@@ -126,7 +126,7 @@ export const getScoreValues = (type, id, completions) => {
126
126
  }, avgPronunciationScore];
127
127
  }
128
128
  };
129
- export const calcTopicCompletions = (topic, completions = [], isSectionHidden, assignmentExercises, includeChallengeBots = false) => {
129
+ export const calcTopicCompletions = (topic, completions = [], isSectionHidden, assignmentExercises, includeChallengeBots = false, isReadWriteModeStudent = false) => {
130
130
  let isRoleplaysHidden;
131
131
  let isPronunciationHidden;
132
132
  let isBotsHidden;
@@ -212,7 +212,16 @@ export const calcTopicCompletions = (topic, completions = [], isSectionHidden, a
212
212
  let numberOfCompletedRoleplayExercises = 0;
213
213
 
214
214
  // Define all possible roleplay exercises and their config
215
- const roleplayExercises = [{
215
+ const roleplayExercises = isReadWriteModeStudent ? [{
216
+ name: "roleplay-story",
217
+ hiddenKey: null
218
+ }, {
219
+ name: "roleplay-fill-in-the-blanks",
220
+ hiddenKey: "isFillInTheBlanksHidden"
221
+ }, {
222
+ name: "roleplay-act-it-out",
223
+ hiddenKey: "isActItOutHidden"
224
+ }] : [{
216
225
  name: "roleplay-story",
217
226
  hiddenKey: null
218
227
  }, {
@@ -330,9 +339,9 @@ export const calcTopicCompletions = (topic, completions = [], isSectionHidden, a
330
339
  }
331
340
  };
332
341
  };
333
- export const calcCompletions = (sections = [], completions = [], assignmentExercises, includeChallengeBots = false) => sections.map(section => {
342
+ export const calcCompletions = (sections = [], completions = [], assignmentExercises, includeChallengeBots = false, isReadWriteModeStudent = false) => sections.map(section => {
334
343
  const topics = section.topics.map(topic => {
335
- return calcTopicCompletions(topic, completions, section.isHidden, assignmentExercises?.filter(e => e.courseSectionTopicId === `${topic.courseSectionId}|${topic.topicId}`), includeChallengeBots);
344
+ return calcTopicCompletions(topic, completions, section.isHidden, assignmentExercises?.filter(e => e.courseSectionTopicId === `${topic.courseSectionId}|${topic.topicId}`), includeChallengeBots, isReadWriteModeStudent);
336
345
  });
337
346
  const sectionExerciseCount = topics.reduce((currentValue, topic) => topic.completion.total + currentValue, 0);
338
347
  const sectionCompletedExerciseCount = topics.reduce((currentValue, topic) => topic.completion.completed + currentValue, 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nualang/nualang-ui-components",
3
- "version": "0.1.1374",
3
+ "version": "0.1.1377",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "files": [