@nualang/nualang-ui-components 0.1.1353 → 0.1.1355

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.
Files changed (35) hide show
  1. package/dist/Dialogs/CreatePhrase/CreatePhrase.js +43 -0
  2. package/dist/Dialogs/CreatePhraseGroupDialog/CreatePhraseGroupDialog.js +1 -6
  3. package/dist/Dialogs/GeneratePhrases/GeneratePhrases.js +27 -62
  4. package/dist/Dialogs/GroupedFeedbackDialog/GroupedFeedbackDialog.js +146 -47
  5. package/dist/Dialogs/GroupedFeedbackDialog/package.json +6 -0
  6. package/dist/Editors/PhraseList/PhraseList.js +42 -40
  7. package/dist/Editors/Phrases/Phrases.js +24 -10
  8. package/dist/Exercises/Meaning/Meaning.js +788 -0
  9. package/dist/Exercises/PhraseGroup/Games/MeaningGame/MeaningGame.js +86 -0
  10. package/dist/Exercises/PhraseGroup/Games/index.js +2 -1
  11. package/dist/Exercises/PhraseGroup/PhraseGroup.js +6 -3
  12. package/dist/Exercises/PhraseGroup/PhraseGroupGameOptions/PhraseGroupGame/PhraseGroupGame.js +104 -84
  13. package/dist/Exercises/PhraseGroup/PhraseGroupGameOptions/PhraseGroupGames.js +2 -0
  14. package/dist/Exercises/PhraseGroup/PhraseGroupInfo/PhraseGroupInfo.js +22 -32
  15. package/dist/Exercises/Roleplay/Roleplay.js +2 -1
  16. package/dist/Exercises/Roleplay/RoleplayGameOptions/RoleplayGames.js +11 -4
  17. package/dist/Forms/CreateRoleplay/Steps/RoleplaySettings/RoleplaySettings.js +5 -2
  18. package/dist/Forms/UpdatePhraseList/UpdatePhraseList.js +8 -0
  19. package/dist/Forms/UpdateRoleplay/UpdateRoleplay.js +2 -1
  20. package/dist/Lists/Phrases/Phrases.js +16 -0
  21. package/dist/Misc/PhraseDisplay/PhraseDisplay.js +123 -0
  22. package/dist/Navigation/Breadcrumbs/Breadcrumbs.js +13 -16
  23. package/dist/Screens/Activity/Exercise/Attempt/Attempt.js +1 -1
  24. package/dist/Screens/Classrooms/ViewClassroom/ViewClassroom.js +6 -2
  25. package/dist/Screens/Courses/ViewCourse/ViewTopic/ViewTopic.js +94 -104
  26. package/dist/Tables/Attempt/Attempt.js +2 -2
  27. package/dist/Tables/Progress/Progress.js +33 -2
  28. package/dist/Tables/Progress/ProgressList.js +94 -5
  29. package/dist/Tables/Progress/ProgressTable.js +103 -3
  30. package/dist/Tables/Progress/ProgressTableRow.js +17 -4
  31. package/dist/Tables/Progress/cells/index.js +44 -0
  32. package/dist/Tables/Progress/useProgressUrlParams.js +18 -2
  33. package/dist/Tables/Progress/viewState.js +5 -3
  34. package/dist/hooks/useExerciseState.js +24 -4
  35. package/package.json +1 -1
@@ -56,6 +56,7 @@ function CreatePhrase({
56
56
  validatePhraseRecognition,
57
57
  verificationStatus,
58
58
  makeChatGptApiRequest,
59
+ difficulty,
59
60
  ...otherProps
60
61
  }) {
61
62
  const translationInputRef = useRef();
@@ -78,6 +79,7 @@ function CreatePhrase({
78
79
  const [definition, setDefinition] = useState("");
79
80
  const [definitionList, setDefinitionList] = useState(otherProps.definitions || []);
80
81
  const [autoTranslatedText, setAutoTranslatedText] = useState(false);
82
+ const [autoGeneratedDefinitions, setAutoGeneratedDefinitions] = useState(false);
81
83
  const [checkingRecogniton, setCheckingRecogniton] = useState(false);
82
84
  const [recognised, setRecognised] = useState(false);
83
85
  const [notRecognised, setNotRecognised] = useState(false);
@@ -287,6 +289,39 @@ function CreatePhrase({
287
289
  setIsSubmitting(false);
288
290
  }
289
291
  };
292
+ const generateDefinitions = async () => {
293
+ try {
294
+ setIsSubmitting(true);
295
+ let chatGptResponse = await makeChatGptApiRequest({
296
+ model: "gpt-4o",
297
+ promptKey: "generateDefinitions",
298
+ promptVariables: {
299
+ learnLang,
300
+ forLang,
301
+ siteLanguage,
302
+ difficulty,
303
+ phrases: [{
304
+ phrase,
305
+ translations: translationList
306
+ }],
307
+ generateDefinitions: true
308
+ }
309
+ });
310
+ const definitions = chatGptResponse?.result?.[0]?.definitions;
311
+ if (!validateResponse(definitions)) {
312
+ throw new Error("Invalid AI response");
313
+ }
314
+ setAutoGeneratedDefinitions(definitions[0]);
315
+ setDefinitionList(prevDefinitionList => {
316
+ const newDefinitions = definitions.filter(text => !prevDefinitionList.includes(text));
317
+ return [...prevDefinitionList, ...newDefinitions];
318
+ });
319
+ } catch (error) {
320
+ console.error("Error fetching definitions from OpenAI:", error.message);
321
+ } finally {
322
+ setIsSubmitting(false);
323
+ }
324
+ };
290
325
  const handleEditTranslation = (event, index) => {
291
326
  const {
292
327
  target: {
@@ -320,6 +355,7 @@ function CreatePhrase({
320
355
  setDefinitionList([]);
321
356
  setSelectedImage(initialSelectedImagestate);
322
357
  setAutoTranslatedText("");
358
+ setAutoGeneratedDefinitions("");
323
359
  };
324
360
  const removePhraseImage = () => {
325
361
  setSelectedImage({
@@ -495,6 +531,13 @@ function CreatePhrase({
495
531
  className: classes.alternativeVersionButton,
496
532
  startIcon: /*#__PURE__*/_jsx(AutoFixHighIcon, {}),
497
533
  children: t("auto_generate_phrase_translation")
534
+ }), learnLang !== forLang && /*#__PURE__*/_jsx(DefaultButton, {
535
+ onClick: generateDefinitions,
536
+ disabled: !phrase || Array.isArray(definitionList) && definitionList.includes(autoGeneratedDefinitions),
537
+ size: "sm",
538
+ className: classes.alternativeVersionButton,
539
+ startIcon: /*#__PURE__*/_jsx(AutoFixHighIcon, {}),
540
+ children: t("auto_generate_definitions")
498
541
  }), learnLang !== forLang && (import.meta.env.REACT_APP_STAGE === "dev" || window.location.host === "localhost:9009") && /*#__PURE__*/_jsx(Box, {
499
542
  sx: {
500
543
  display: "inline-flex",
@@ -6,7 +6,6 @@ import Dialog from "@mui/material/Dialog";
6
6
  import DialogTitle from "@mui/material/DialogTitle";
7
7
  import DialogContent from "@mui/material/DialogContent";
8
8
  import DialogActions from "@mui/material/DialogActions";
9
- import CircularProgress from "@mui/material/CircularProgress";
10
9
  import Grid from "@mui/material/Grid";
11
10
  import ImageSelector from "../../Forms/ImageSelector/ImageSelector";
12
11
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -132,11 +131,7 @@ export default function CreatePhraseGroupDialog({
132
131
  color: "primary",
133
132
  variant: "contained",
134
133
  disabled: !name.trim() || isLoading,
135
- startIcon: isLoading ? /*#__PURE__*/_jsx(CircularProgress, {
136
- size: 16,
137
- color: "inherit"
138
- }) : null,
139
- children: isLoading ? t("creating") || "Creating..." : t("create") || "Create"
134
+ children: t("create") || "Create"
140
135
  })]
141
136
  })]
142
137
  });
@@ -1,12 +1,13 @@
1
1
  import { useState, useEffect } from "react";
2
2
  import ResponsiveDialog from "../ResponsiveDialog/ResponsiveDialog";
3
3
  import { AutoFixHigh } from "@mui/icons-material";
4
- import { Alert, Grid, InputAdornment, LinearProgress, MenuItem, Slider, TextField, Tooltip, Typography, ListItem, ListItemText, useMediaQuery, FormControlLabel, Switch, Box } from "@mui/material";
4
+ import { Alert, Grid, InputAdornment, LinearProgress, MenuItem, Slider, TextField, Tooltip, Typography, ListItem, useMediaQuery, FormControlLabel, Switch, Box, List } from "@mui/material";
5
5
  import { useTheme } from "@mui/material/styles";
6
6
  import { Link } from "react-router";
7
7
  import InfoIcon from "@mui/icons-material/Info";
8
8
  import NualaCreating from "../../Misc/NualaCreating/NualaCreating";
9
9
  import InputHelper from "../../Forms/InputHelper/InputHelper";
10
+ import PhraseDisplay from "../../Misc/PhraseDisplay/PhraseDisplay";
10
11
  import { makeStyles } from "tss-react/mui";
11
12
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
12
13
  const useStyles = makeStyles()(theme => ({
@@ -19,80 +20,43 @@ const useStyles = makeStyles()(theme => ({
19
20
  width: "60%",
20
21
  wordBreak: "break-word",
21
22
  overflowWrap: "break-word"
22
- },
23
- avatar: {
24
- cursor: "pointer",
25
- margin: theme.spacing()
26
- },
27
- avatarNoClick: {
28
- margin: theme.spacing()
29
23
  }
30
24
  }));
31
25
  function Phrase({
32
26
  alternativeVersions,
33
27
  translations,
34
28
  definitions,
35
- phrase
29
+ phrase,
30
+ t
36
31
  }) {
37
32
  const theme = useTheme();
38
33
  const {
39
34
  classes
40
35
  } = useStyles();
41
36
  const isLargeScreen = useMediaQuery(theme.breakpoints.up("sm"));
42
- const primary = `${phrase}${Array.isArray(alternativeVersions) && alternativeVersions.length ? " - " : ""}${(alternativeVersions || []).join(", ")}`;
43
-
44
- // Show translations first, then definitions (if any) on a new line.
45
- const secondaryParts = [];
46
- if (Array.isArray(translations) && translations.length) {
47
- secondaryParts.push((translations || []).join(", "));
48
- }
49
- if (Array.isArray(definitions) && definitions.length) {
50
- secondaryParts.push((definitions || []).join(", "));
51
- }
52
- const secondary = secondaryParts.join("\n");
53
- console.log({
54
- primary,
55
- secondary
56
- });
57
- console.log("Phrase render", {
58
- phrase,
59
- translations,
60
- definitions,
61
- alternativeVersions
62
- });
63
- return /*#__PURE__*/_jsx(ListItem, {
64
- "data-cy": "phrase-list-item",
65
- children: isLargeScreen ? /*#__PURE__*/_jsx(Grid, {
66
- container: true,
67
- sx: {
68
- width: "100%"
69
- },
70
- className: classes.phraseText,
71
- children: /*#__PURE__*/_jsx(ListItemText, {
72
- className: classes.phrases,
73
- primary: primary,
74
- secondary: secondary,
75
- secondaryTypographyProps: {
76
- style: {
77
- whiteSpace: "pre-line"
78
- }
79
- }
80
- })
81
- }) : /*#__PURE__*/_jsx(Grid, {
82
- container: true,
37
+ return /*#__PURE__*/_jsx(List, {
38
+ dense: true,
39
+ disablePadding: true,
40
+ children: /*#__PURE__*/_jsx(ListItem, {
41
+ "data-cy": "phrase-list-item",
42
+ divider: true,
83
43
  sx: {
84
- width: "100%"
44
+ flexDirection: "column",
45
+ alignItems: "flex-start",
46
+ py: 2
85
47
  },
86
- className: classes.phraseTextSmall,
87
- children: /*#__PURE__*/_jsx(ListItemText, {
88
- className: classes.phrases,
89
- primary: primary,
90
- secondary: secondary,
91
- secondaryTypographyProps: {
92
- style: {
93
- whiteSpace: "pre-line"
94
- }
95
- }
48
+ children: /*#__PURE__*/_jsx(Box, {
49
+ className: isLargeScreen ? classes.phraseText : classes.phraseTextSmall,
50
+ children: /*#__PURE__*/_jsx(PhraseDisplay, {
51
+ phrase: phrase,
52
+ translations: translations,
53
+ definitions: definitions,
54
+ alternativeVersions: alternativeVersions,
55
+ t: t,
56
+ variant: "body2",
57
+ showIcons: true,
58
+ showImage: false
59
+ })
96
60
  })
97
61
  })
98
62
  });
@@ -388,7 +352,8 @@ function GeneratePhrases({
388
352
  children: [/*#__PURE__*/_jsx(Typography, {
389
353
  children: t("generated_phrases")
390
354
  }), generatedPhrases.map((phrase, index) => /*#__PURE__*/_jsx(Phrase, {
391
- ...phrase
355
+ ...phrase,
356
+ t: t
392
357
  }, index))]
393
358
  }), errorMessage && /*#__PURE__*/_jsx(Grid, {
394
359
  mt: 2,
@@ -1,13 +1,22 @@
1
1
  import { useMemo, useEffect, useState, useRef, useCallback } from "react";
2
- import { Dialog, DialogContent, IconButton, Box, Typography, AppBar, Toolbar, CircularProgress, Button, Checkbox, Paper, Divider, Tooltip, Skeleton, Grid } from "@mui/material";
2
+ import { Dialog, DialogContent, IconButton, Box, Typography, AppBar, Toolbar, CircularProgress, Button, Checkbox, Paper, Divider, Tooltip, Skeleton, Grid, TextField, LinearProgress, Alert } from "@mui/material";
3
+ import { Link } from "react-router";
4
+ import MuiLink from "@mui/material/Link";
3
5
  import CloseIcon from "@mui/icons-material/Close";
4
6
  import { red, orange, green, grey } from "@mui/material/colors";
5
7
  import FeedbackCard from "../../Cards/FeedbackCard/FeedbackCard";
6
8
  import AutoFixHighIcon from "@mui/icons-material/AutoFixHigh";
7
9
  import NualaHeadphonesBackground from "../../img/NualaHeadphonesBackground.svg";
8
10
  import CheckCircleIcon from "@mui/icons-material/CheckCircle";
11
+ import { AutoFixHigh } from "@mui/icons-material";
9
12
  import useConfirm from "../../hooks/useConfirm";
10
13
  import NualaCreating from "../../Misc/NualaCreating/NualaCreating";
14
+ import ResponsiveDialog from "../ResponsiveDialog/ResponsiveDialog";
15
+ import PDFViewer from "../PDFViewer/PDFViewer";
16
+ import level1Rubric from "../PDFViewer/rubrics/level1Rubric.pdf";
17
+ import level2Rubric from "../PDFViewer/rubrics/level2Rubric.pdf";
18
+ import level3Rubric from "../PDFViewer/rubrics/level3Rubric.pdf";
19
+ import level4Rubric from "../PDFViewer/rubrics/level4Rubric.pdf";
11
20
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
12
21
  export default function GroupFeedbackDialog({
13
22
  open = false,
@@ -44,7 +53,20 @@ export default function GroupFeedbackDialog({
44
53
  const [hasReachedBottom, setHasReachedBottom] = useState(false);
45
54
  const [isGeneratingAll, setIsGeneratingAll] = useState(false);
46
55
  const [isGeneratingIndividual, setIsGeneratingIndividual] = useState(false);
56
+ const [customFeedbackOpen, setCustomFeedbackOpen] = useState(false);
57
+ const [customFeedbackText, setCustomFeedbackText] = useState("");
58
+ const [openPDF, setOpenPDF] = useState(false);
59
+ const [pageNumber, setPageNumber] = useState(1);
60
+ const [scale, setScale] = useState(1);
47
61
  const isAnyGenerating = isGeneratingAll || isGeneratingIndividual;
62
+ const pendingGenerateRef = useRef(null);
63
+ const rubricMap = {
64
+ 1: level1Rubric,
65
+ 2: level2Rubric,
66
+ 3: level3Rubric,
67
+ 4: level4Rubric
68
+ };
69
+ const pdfUrl = rubricMap[selectedRecording?.level] || level1Rubric;
48
70
  const [confirm] = useConfirm(t);
49
71
  const bottomRefCallback = useCallback(node => {
50
72
  if (node) {
@@ -59,6 +81,12 @@ export default function GroupFeedbackDialog({
59
81
  node._observer = observer;
60
82
  }
61
83
  }, []);
84
+ const handleOpenPDF = () => {
85
+ setOpenPDF(true);
86
+ };
87
+ const handleClosePDF = () => {
88
+ setOpenPDF(false);
89
+ };
62
90
  useEffect(() => {
63
91
  // dialog is shared between discussions, so reset when teacher selects another discussion
64
92
  setGenerateAllUsed(false);
@@ -69,7 +97,42 @@ export default function GroupFeedbackDialog({
69
97
  setCanSubmit({});
70
98
  setHasReachedBottom(false);
71
99
  setIsGeneratingAll(false);
100
+ pendingGenerateRef.current = null;
72
101
  }, [groupedId]);
102
+ const openCustomPromptForAll = () => {
103
+ pendingGenerateRef.current = {
104
+ type: "all"
105
+ };
106
+ setCustomFeedbackText("");
107
+ setCustomFeedbackOpen(true);
108
+ };
109
+ const openCustomPromptForSingle = discussionData => {
110
+ pendingGenerateRef.current = {
111
+ type: "single",
112
+ payload: discussionData
113
+ };
114
+ setCustomFeedbackText("");
115
+ setCustomFeedbackOpen(true);
116
+ };
117
+ const handleCustomPromptCancel = () => {
118
+ setCustomFeedbackOpen(false);
119
+ pendingGenerateRef.current = null;
120
+ setCustomFeedbackText("");
121
+ };
122
+ const handleCustomPromptContinue = async () => {
123
+ try {
124
+ const pending = pendingGenerateRef.current;
125
+ pendingGenerateRef.current = null;
126
+ if (!pending) return;
127
+ if (pending.type === "all") {
128
+ await handleGenerateFeedbackForAll();
129
+ } else if (pending.type === "single") {
130
+ await handleGenerateFeedback(pending.payload);
131
+ }
132
+ } finally {
133
+ setCustomFeedbackOpen(false);
134
+ }
135
+ };
73
136
  useEffect(() => {
74
137
  if (pendingSubmissions === 0 && submitTrigger !== null) {
75
138
  setCheckedSubmissions({});
@@ -137,7 +200,9 @@ export default function GroupFeedbackDialog({
137
200
  }).filter(member => member.name !== "Unknown");
138
201
  };
139
202
  const handleGenerateFeedback = async discussionData => {
140
- if (handleBatchGradeConversations) {
203
+ if (!handleBatchGradeConversations) return;
204
+ setIsGeneratingIndividual(true);
205
+ try {
141
206
  const joinedMembersWithNames = getJoinedMembersNames(discussionData.joinedMembers || [], userData);
142
207
  await handleBatchGradeConversations([{
143
208
  meetingId: discussionData.meetingId || discussionData.meetingID,
@@ -148,8 +213,11 @@ export default function GroupFeedbackDialog({
148
213
  meetingPrompt: discussionData.meetingPrompt,
149
214
  learnLang: learnLang,
150
215
  joinedMembers: discussionData.joinedMembers || [],
151
- joinedMembersNames: joinedMembersWithNames
216
+ joinedMembersNames: joinedMembersWithNames,
217
+ customFeedback: customFeedbackText
152
218
  }]);
219
+ } finally {
220
+ setIsGeneratingIndividual(false);
153
221
  }
154
222
  };
155
223
  const handleGenerateFeedbackForAll = async () => {
@@ -171,7 +239,8 @@ export default function GroupFeedbackDialog({
171
239
  meetingPrompt: discussion.meetingPrompt || submissionForThisDiscussion.meetingPrompt,
172
240
  learnLang: learnLang,
173
241
  joinedMembers: submissionForThisDiscussion.joinedMembers || [],
174
- joinedMembersNames: joinedMembersWithNames
242
+ joinedMembersNames: joinedMembersWithNames,
243
+ customFeedback: customFeedbackText
175
244
  };
176
245
  });
177
246
  if (conversationsToGrade.length > 0 && handleBatchGradeConversations) {
@@ -478,7 +547,7 @@ export default function GroupFeedbackDialog({
478
547
  color: "secondary",
479
548
  endIcon: /*#__PURE__*/_jsx(AutoFixHighIcon, {}),
480
549
  disabled: selectedCount === 0 || isGeneratingAll,
481
- onClick: handleGenerateFeedbackForAll,
550
+ onClick: openCustomPromptForAll,
482
551
  sx: {
483
552
  fontWeight: 600
484
553
  },
@@ -528,7 +597,7 @@ export default function GroupFeedbackDialog({
528
597
  hasSubmission: hasSubmission,
529
598
  aiGrade: aiGrade[discussionData.meetingId || discussionData.meetingID] || {},
530
599
  existingFeedback: feedbackByMeetingId[feedbackMeetingId] || {},
531
- onGenerateFeedback: () => handleGenerateFeedback(discussionData),
600
+ onGenerateFeedback: () => openCustomPromptForSingle(discussionData),
532
601
  onSubmitFeedback: handleSubmitFeedback,
533
602
  setSelectedRecording: setSelectedRecording,
534
603
  selectedRecording: selectedRecording,
@@ -556,53 +625,83 @@ export default function GroupFeedbackDialog({
556
625
  })]
557
626
  })
558
627
  })]
559
- }), /*#__PURE__*/_jsx(Dialog, {
560
- open: isAnyGenerating,
628
+ }), /*#__PURE__*/_jsx(ResponsiveDialog, {
629
+ open: customFeedbackOpen,
630
+ handleClose: handleCustomPromptCancel,
631
+ handleSubmit: handleCustomPromptContinue,
632
+ submitText: t("generate_feedback"),
561
633
  maxWidth: "sm",
562
- fullWidth: true,
563
- PaperProps: {
564
- sx: {
565
- borderRadius: 3,
566
- overflow: "visible"
567
- }
568
- },
569
- children: /*#__PURE__*/_jsx(DialogContent, {
570
- sx: {
571
- p: 4
572
- },
573
- children: /*#__PURE__*/_jsx(Grid, {
574
- container: true,
634
+ dialogTitle: isAnyGenerating ? t("generating_feedback") : t("generate_feedback"),
635
+ isSubmitDisabled: isAnyGenerating,
636
+ isExperimentalFeature: true,
637
+ startIcon: /*#__PURE__*/_jsx(AutoFixHigh, {}),
638
+ children: /*#__PURE__*/_jsxs(_Fragment, {
639
+ children: [/*#__PURE__*/_jsx(Grid, {
640
+ textAlign: "center",
641
+ sx: {
642
+ ...(!isAnyGenerating && {
643
+ display: "none"
644
+ })
645
+ },
646
+ mx: 2,
647
+ size: 12,
648
+ children: /*#__PURE__*/_jsx(NualaCreating, {})
649
+ }), /*#__PURE__*/_jsx(Grid, {
575
650
  sx: {
576
- width: "100%"
651
+ ...(!isAnyGenerating && {
652
+ display: "none"
653
+ })
577
654
  },
578
- children: /*#__PURE__*/_jsxs(Grid, {
655
+ mt: 2,
656
+ size: 12,
657
+ children: /*#__PURE__*/_jsx(LinearProgress, {})
658
+ }), !isAnyGenerating && /*#__PURE__*/_jsxs(Grid, {
659
+ container: true,
660
+ spacing: 2,
661
+ children: [/*#__PURE__*/_jsx(Grid, {
579
662
  size: 12,
580
- sx: {
581
- display: "flex",
582
- flexDirection: "column",
583
- alignItems: "center",
584
- justifyContent: "center",
585
- textAlign: "center",
586
- gap: 3,
587
- py: 2
663
+ children: /*#__PURE__*/_jsxs(Alert, {
664
+ severity: "info",
665
+ children: [t("experimental_feature_desc"), " - ", " ", /*#__PURE__*/_jsxs(Link, {
666
+ to: "/contact",
667
+ children: [t("contact_form"), "."]
668
+ })]
669
+ })
670
+ }), /*#__PURE__*/_jsx(Grid, {
671
+ size: {
672
+ xs: 12
588
673
  },
589
- children: [/*#__PURE__*/_jsx(Typography, {
590
- variant: "h5",
591
- sx: {
592
- fontWeight: 600,
593
- color: "text.primary"
594
- },
595
- children: t("generating_feedback")
596
- }), /*#__PURE__*/_jsx(Box, {
597
- sx: {
598
- maxWidth: 500,
599
- width: "100%"
600
- },
601
- children: /*#__PURE__*/_jsx(NualaCreating, {})
602
- })]
603
- })
604
- })
674
+ children: /*#__PURE__*/_jsxs(Typography, {
675
+ variant: "body2",
676
+ children: [t("generate_feedback_view_the"), " ", /*#__PURE__*/_jsx(MuiLink, {
677
+ component: "button",
678
+ variant: "body2",
679
+ onClick: handleOpenPDF,
680
+ children: t("generate_feedback_rubric_name")
681
+ }), ", ", t("generate_feedback_rubric_desc")]
682
+ })
683
+ }), /*#__PURE__*/_jsx(Grid, {
684
+ size: 12,
685
+ children: /*#__PURE__*/_jsx(TextField, {
686
+ value: customFeedbackText,
687
+ onChange: e => setCustomFeedbackText(e.target.value),
688
+ placeholder: t("custom_feedback_placeholder"),
689
+ multiline: true,
690
+ minRows: 4,
691
+ fullWidth: true
692
+ })
693
+ })]
694
+ })]
605
695
  })
696
+ }), /*#__PURE__*/_jsx(PDFViewer, {
697
+ open: openPDF,
698
+ handleClose: handleClosePDF,
699
+ pdfUrl: pdfUrl,
700
+ pageNumber: pageNumber,
701
+ setPageNumber: setPageNumber,
702
+ scale: scale,
703
+ setScale: setScale,
704
+ t: t
606
705
  })]
607
706
  });
608
707
  }
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "grouped-feedback-dialog",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "main": "./GroupedFeedbackDialog.js"
6
+ }
@@ -86,7 +86,6 @@ function PhraseList({
86
86
  isCreatePhraseDialogOpen,
87
87
  setIsCreatePhraseDialogOpen,
88
88
  handleAddPhrase,
89
- topicName,
90
89
  validatePhraseRecognition,
91
90
  difficulty,
92
91
  topicGoal,
@@ -107,12 +106,6 @@ function PhraseList({
107
106
  const handleChangeTab = (event, newValue) => {
108
107
  setTabValue(newValue);
109
108
  };
110
- useEffect(() => {
111
- if (!isSmallScreen && tabValue === 2) {
112
- setTabValue(0);
113
- }
114
- }, [isSmallScreen]); // Only run when screen changes
115
-
116
109
  const updatePhrases = async phrases => {
117
110
  try {
118
111
  handleUpdatePhrases(courseId, sectionId, topicId, phrases);
@@ -208,41 +201,50 @@ function PhraseList({
208
201
  })]
209
202
  })
210
203
  })]
211
- }), tabValue === 0 ? /*#__PURE__*/_jsx(PhrasesEditor, {
212
- t: t,
213
- phrases: phrases,
214
- isCreator: isCreator,
215
- isMember: isMember,
216
- handleTranslate: handleTranslate,
217
- handleUpdatePhrase: updatePhrase,
218
- handleRemovePhrase: handleRemovePhrase,
219
- uploadAudio: uploadAudio,
220
- handleSpeak: handleSpeak,
221
- updatePhrases: updatePhrases,
222
- learnLang: learnLang,
223
- forLang: forLang,
224
- voices: voices,
225
- userAttributes: userAttributes,
226
- disablePadding: true,
227
- forLangCharacters: forLangCharacters,
228
- learnLangCharacters: learnLangCharacters,
229
- fileSizeLimit: fileSizeLimit,
230
- handleSpreadsheetSaveChanges: handleSpreadsheetSaveChanges,
231
- isUploadPhrasesDialogOpen: isUploadPhrasesDialogOpen,
232
- setIsUploadPhrasesDialogOpen: setIsUploadPhrasesDialogOpen,
233
- isCreatePhraseDialogOpen: isCreatePhraseDialogOpen,
234
- setIsCreatePhraseDialogOpen: setIsCreatePhraseDialogOpen,
235
- handleAddPhrase: handleAddPhrase,
236
- topicName: topicName,
237
- validatePhraseRecognition: validatePhraseRecognition,
238
- siteLanguage: siteLanguage,
239
- makeChatGptApiRequest: makeChatGptApiRequest,
240
- difficulty: difficulty,
241
- subscription: subscription,
242
- topicGoal: topicGoal,
243
- verificationStatus: verificationStatus
204
+ }), tabValue === 0 ? /*#__PURE__*/_jsx(Box, {
205
+ className: hidden ? classes.paneFull : classes.pane,
206
+ sx: {
207
+ overflowY: "auto"
208
+ },
209
+ children: /*#__PURE__*/_jsx(PhrasesEditor, {
210
+ t: t,
211
+ phrases: phrases,
212
+ isCreator: isCreator,
213
+ isMember: isMember,
214
+ handleTranslate: handleTranslate,
215
+ handleUpdatePhrase: updatePhrase,
216
+ handleRemovePhrase: handleRemovePhrase,
217
+ uploadAudio: uploadAudio,
218
+ handleSpeak: handleSpeak,
219
+ updatePhrases: updatePhrases,
220
+ learnLang: learnLang,
221
+ forLang: forLang,
222
+ voices: voices,
223
+ userAttributes: userAttributes,
224
+ disablePadding: true,
225
+ forLangCharacters: forLangCharacters,
226
+ learnLangCharacters: learnLangCharacters,
227
+ fileSizeLimit: fileSizeLimit,
228
+ handleSpreadsheetSaveChanges: handleSpreadsheetSaveChanges,
229
+ isUploadPhrasesDialogOpen: isUploadPhrasesDialogOpen,
230
+ setIsUploadPhrasesDialogOpen: setIsUploadPhrasesDialogOpen,
231
+ isCreatePhraseDialogOpen: isCreatePhraseDialogOpen,
232
+ setIsCreatePhraseDialogOpen: setIsCreatePhraseDialogOpen,
233
+ handleAddPhrase: handleAddPhrase,
234
+ validatePhraseRecognition: validatePhraseRecognition,
235
+ siteLanguage: siteLanguage,
236
+ makeChatGptApiRequest: makeChatGptApiRequest,
237
+ difficulty: difficulty,
238
+ subscription: subscription,
239
+ topicGoal: topicGoal,
240
+ verificationStatus: verificationStatus,
241
+ phraseListName: initialValues.phraseListName
242
+ })
244
243
  }) : null, tabValue === 1 ? /*#__PURE__*/_jsx(Box, {
245
244
  className: hidden ? classes.paneFull : classes.pane,
245
+ sx: {
246
+ overflowY: "auto"
247
+ },
246
248
  children: /*#__PURE__*/_jsx(UpdatePhraseList, {
247
249
  t: t,
248
250
  touched: touched,