@nualang/nualang-ui-components 0.1.1350 → 0.1.1353

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 (83) hide show
  1. package/README.md +24 -8
  2. package/dist/Cards/Classroom/Classroom.js +0 -4
  3. package/dist/Cards/Course/Course.js +0 -5
  4. package/dist/Dialogs/CreatePhraseGroupDialog/CreatePhraseGroupDialog.js +143 -0
  5. package/dist/Dialogs/Feedback/FeedbackDialog.js +1 -4
  6. package/dist/Dialogs/GenerateDefinitions/GenerateDefinitions.js +205 -0
  7. package/dist/Dialogs/GenerateDefinitions/package.json +6 -0
  8. package/dist/Dialogs/GeneratePhrases/GeneratePhrases.js +33 -3
  9. package/dist/Dialogs/UploadPhrases/UploadPhrases.js +75 -14
  10. package/dist/Dialogs/UploadPhrases/upload-phrases-csv.png +0 -0
  11. package/dist/Editors/PhraseList/PhraseList.js +263 -0
  12. package/dist/Editors/Phrases/Phrases.js +92 -11
  13. package/dist/Exercises/Listener/Listener.js +4 -2
  14. package/dist/Exercises/PhraseGroup/Games/ListeningGame/ListeningGame.js +89 -0
  15. package/dist/Exercises/PhraseGroup/Games/PronunciationGame/PronunciationGame.js +85 -0
  16. package/dist/Exercises/PhraseGroup/Games/TranslationGame/TranslationGame.js +90 -0
  17. package/dist/Exercises/PhraseGroup/Games/index.js +4 -0
  18. package/dist/Exercises/PhraseGroup/PhraseGroup.js +245 -0
  19. package/dist/Exercises/PhraseGroup/PhraseGroup.test.js +28 -0
  20. package/dist/Exercises/PhraseGroup/PhraseGroupGameOptions/PhraseGroupGame/PhraseGroupGame.js +259 -0
  21. package/dist/Exercises/PhraseGroup/PhraseGroupGameOptions/PhraseGroupGames.js +62 -0
  22. package/dist/Exercises/PhraseGroup/PhraseGroupInfo/PhraseGroupInfo.js +145 -0
  23. package/dist/Exercises/PhraseGroup/package.json +7 -0
  24. package/dist/Exercises/Pronouncer/Pronouncer.js +4 -2
  25. package/dist/Exercises/Translator/Translator.js +4 -2
  26. package/dist/Forms/UpdatePhraseList/UpdatePhraseList.js +175 -0
  27. package/dist/Lists/Classrooms/Classrooms.js +0 -1
  28. package/dist/Lists/CourseOutline/CourseOutline.js +0 -6
  29. package/dist/Lists/Courses/Courses.js +0 -6
  30. package/dist/Lists/Exercises/Exercises.js +589 -1012
  31. package/dist/Lists/Members/Members.js +17 -29
  32. package/dist/Lists/Phrases/Phrases.js +155 -107
  33. package/dist/Misc/ChatBubble/ChatBubble.js +7 -2
  34. package/dist/Misc/HoverText/HoverText.js +18 -7
  35. package/dist/Misc/RubyText/RubyText.js +27 -0
  36. package/dist/Screens/Activity/Exercise/Attempt/Attempt.js +1 -3
  37. package/dist/Screens/Classrooms/Classrooms.js +0 -3
  38. package/dist/Screens/Classrooms/SearchClassrooms/SearchClassrooms.js +0 -2
  39. package/dist/Screens/Classrooms/ViewClassroom/ViewClassroom.js +141 -15
  40. package/dist/Screens/Courses/Courses.js +0 -6
  41. package/dist/Screens/Courses/SearchCourses/SearchCourses.js +0 -2
  42. package/dist/Screens/Courses/ViewCourse/ViewCourse.js +1 -9
  43. package/dist/Screens/Courses/ViewCourse/ViewTopic/ViewTopic.js +62 -197
  44. package/dist/Screens/Dashboard/Dashboard.js +1 -5
  45. package/dist/Screens/Profile/Profile.js +2 -262
  46. package/dist/Screens/Search/Search.js +0 -2
  47. package/dist/Tables/ClassroomRows/ClassroomRows.js +1 -4
  48. package/dist/Tables/CourseRows/CourseRows.js +1 -4
  49. package/dist/Tables/Progress/Header.js +557 -0
  50. package/dist/Tables/Progress/Progress.js +54 -349
  51. package/dist/Tables/Progress/ProgressList.js +21 -43
  52. package/dist/Tables/Progress/ProgressList.test.js +48 -0
  53. package/dist/Tables/Progress/ProgressTable.js +58 -1027
  54. package/dist/Tables/Progress/ProgressTable.test.js +258 -0
  55. package/dist/Tables/Progress/ProgressTableRow.js +270 -0
  56. package/dist/Tables/Progress/README.md +53 -0
  57. package/dist/Tables/Progress/TableToolbar.js +130 -0
  58. package/dist/Tables/Progress/TableToolbar.test.js +69 -0
  59. package/dist/Tables/Progress/cells/index.js +446 -0
  60. package/dist/Tables/Progress/cells/index.test.js +345 -0
  61. package/dist/Tables/Progress/constants.js +6 -0
  62. package/dist/Tables/Progress/exportToExcel.js +224 -0
  63. package/dist/Tables/Progress/exportToExcel.test.js +135 -0
  64. package/dist/Tables/Progress/helpers.js +42 -0
  65. package/dist/Tables/Progress/helpers.test.js +23 -0
  66. package/dist/Tables/Progress/sorting.js +78 -0
  67. package/dist/Tables/Progress/sorting.test.js +69 -0
  68. package/dist/Tables/Progress/styledComponents.js +156 -0
  69. package/dist/Tables/Progress/useProgressUrlParams.js +147 -0
  70. package/dist/Tables/Progress/useProgressUrlParams.test.js +183 -0
  71. package/dist/Tables/Progress/utils.js +2 -2
  72. package/dist/Tables/Progress/utils.test.js +129 -0
  73. package/dist/Tables/Progress/viewState.js +25 -0
  74. package/dist/hooks/useExerciseState.js +8 -3
  75. package/dist/hooks/usePhonetics.js +42 -0
  76. package/dist/utils/japaneseTokenizer.js +55 -0
  77. package/package.json +7 -2
  78. package/dist/Screens/Bots/Bots.js +0 -240
  79. package/dist/Screens/Bots/SearchBots/SearchBots.js +0 -280
  80. package/dist/Screens/Bots/SearchBots/package.json +0 -6
  81. package/dist/Screens/Bots/package.json +0 -6
  82. package/dist/Screens/Roleplays/SearchRoleplays/SearchRoleplays.js +0 -290
  83. package/dist/Screens/Roleplays/SearchRoleplays/package.json +0 -6
package/README.md CHANGED
@@ -5,27 +5,27 @@ to `npm` and consumed from there by nualang web apps.
5
5
 
6
6
  ## Getting Started
7
7
  Clone this repository and then execute `npm install`. `npm start` will start
8
- [stoybook](https://storybook.js.org) and allow you to brrowse the available components.
8
+ [storybook](https://storybook.js.org) and allow you to browse the available components.
9
9
 
10
10
  ## Develop
11
- ```
11
+ ```bash
12
12
  npm start
13
13
  ```
14
14
 
15
15
  ## Create Local Package
16
16
  Compile and pack (This will create a '.tgz' file):
17
- ```
17
+ ```bash
18
18
  npm run localpack
19
19
  ```
20
20
 
21
21
  Install package (Inside webapp):
22
22
  ```
23
- npm i ../ui-components/fathomtech-nualang-ui-components-0.1.XXX.tgz
23
+ npm i ../ui-components/nualang-ui-components-0.1.XXX.tgz
24
24
  ```
25
25
 
26
26
  If webapp is caching previous versions (Add a character to the end of the .tgz, e.g 'a') and install again:
27
- ```
28
- yarn add ../ui-components/fathomtech-nualang-ui-components-0.1.XXXa.tgz
27
+ ```bash
28
+ yarn add ../ui-components/nualang-ui-components-0.1.XXXa.tgz
29
29
  ```
30
30
 
31
31
  ## Publish to npm
@@ -59,7 +59,23 @@ Check for any lint errors or warnings.
59
59
  Run the babel compiler to compile es6 to js.
60
60
 
61
61
  ### `npm run postversion`
62
- Publish a new version of the pacakage to npm. npm will complain
62
+ Publish a new version of the package to npm. npm will complain
63
63
 
64
64
  ### `npm run chromatic`
65
- Publish a new version of the pacakage to https://www.chromatic.com/
65
+ Publish a new version of the package to https://www.chromatic.com/
66
+
67
+ ## Testing & Coverage
68
+
69
+ Run unit tests with Vitest in watch mode:
70
+
71
+ ```bash
72
+ npm run vitest
73
+ ```
74
+
75
+ To generate code coverage (uses V8 provider):
76
+
77
+ ```bash
78
+ npm run test:coverage
79
+ ```
80
+
81
+ Coverage reports will be written to the `coverage` directory. A text summary is printed to the console; an LCOV file (`coverage/lcov.info`) and a JSON report are also generated. This coverage step is intentionally not wired into CI — run it locally when you want to inspect or publish coverage results.
@@ -3,7 +3,6 @@ import PropTypes from "prop-types";
3
3
  import { useInView } from "react-intersection-observer";
4
4
  import { Button, Box, Typography, IconButton, Menu, MenuItem, Tooltip, CardActions, CardActionArea, Divider, CircularProgress } from "@mui/material";
5
5
  import Skeleton from "@mui/material/Skeleton";
6
- import Rating from "@mui/material/Rating";
7
6
  import Group from "@mui/icons-material/Group";
8
7
  import ExitToApp from "@mui/icons-material/ExitToApp";
9
8
  import Add from "@mui/icons-material/Add";
@@ -12,7 +11,6 @@ import MoreVert from "@mui/icons-material/MoreVert";
12
11
 
13
12
  // components
14
13
  import MembersDialog from "../../Dialogs/Members/Members";
15
- import MembersList from "../../Lists/Members/Members";
16
14
  import { capitalize } from "../../utils/index";
17
15
  import PlaceholderImages from "../../utils/placeholder-images/index";
18
16
  import ProgressiveCardMedia from "../../Misc/ProgressiveCardMedia/ProgressiveCardMedia";
@@ -122,7 +120,6 @@ function ClassroomCard({
122
120
  handleLeaveClassroom,
123
121
  membersProps,
124
122
  getMemberDetails,
125
- getMemberInfo,
126
123
  memberPlaceholderImageUrl,
127
124
  getClassroomMember,
128
125
  getClassroomMembers,
@@ -370,7 +367,6 @@ Classroom.propTypes = {
370
367
  forLang: PropTypes.string.isRequired,
371
368
  isMember: PropTypes.bool,
372
369
  isCreator: PropTypes.bool,
373
- members: MembersList.propTypes,
374
370
  createdAt: PropTypes.number.isRequired,
375
371
  createdBy: PropTypes.string.isRequired,
376
372
  userImage: PropTypes.string
@@ -21,7 +21,6 @@ import DeleteIcon from "@mui/icons-material/Delete";
21
21
  // components
22
22
  import MembersDialog from "../../Dialogs/Members/Members";
23
23
  import CourseOutlineDialog from "../../Dialogs/CourseOutline/CourseOutline";
24
- import MembersList from "../../Lists/Members/Members";
25
24
  import PlaceholderImages from "../../utils/placeholder-images/index";
26
25
  import { capitalize, formatNumberTotal } from "../../utils/index";
27
26
  import PlayArrowIcon from "@mui/icons-material/PlayArrow";
@@ -233,7 +232,6 @@ function CourseCard({
233
232
  selectable,
234
233
  selected,
235
234
  getMemberDetails,
236
- getMemberInfo,
237
235
  memberPlaceholderImageUrl,
238
236
  getCourseSections,
239
237
  getCourseMember,
@@ -582,7 +580,6 @@ function CourseCard({
582
580
  isClassroomCreator: isClassroomCreator,
583
581
  isMember: isMember,
584
582
  isAdmin: isAdmin,
585
- viewCourse: viewCourse,
586
583
  startCourse: startCourse,
587
584
  leaveCourse: leaveCourse,
588
585
  handleRemoveCourse: handleRemoveCourse,
@@ -603,7 +600,6 @@ function CourseCard({
603
600
  open: isMembersOpen,
604
601
  handleClose: handleCloseMembers,
605
602
  isCreator: isClassroomCreator ?? isCreator,
606
- isCourseMember: true,
607
603
  members: membersQuery.isSuccess ? membersQuery.data.Items : [],
608
604
  ...membersProps
609
605
  }), /*#__PURE__*/_jsx(CourseOutlineDialog, {
@@ -644,7 +640,6 @@ MemoizedCourse.propTypes = {
644
640
  createdAt: PropTypes.number.isRequired,
645
641
  createdBy: PropTypes.string.isRequired,
646
642
  userImage: PropTypes.string,
647
- members: PropTypes.arrayOf(MembersList.propTypes),
648
643
  sections: PropTypes.arrayOf({
649
644
  sectionId: PropTypes.string.isRequired,
650
645
  sectionName: PropTypes.string.isRequired,
@@ -0,0 +1,143 @@
1
+ import { useState } from "react";
2
+ import TextField from "@mui/material/TextField";
3
+ import Box from "@mui/material/Box";
4
+ import Button from "@mui/material/Button";
5
+ import Dialog from "@mui/material/Dialog";
6
+ import DialogTitle from "@mui/material/DialogTitle";
7
+ import DialogContent from "@mui/material/DialogContent";
8
+ import DialogActions from "@mui/material/DialogActions";
9
+ import CircularProgress from "@mui/material/CircularProgress";
10
+ import Grid from "@mui/material/Grid";
11
+ import ImageSelector from "../../Forms/ImageSelector/ImageSelector";
12
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
+ export default function CreatePhraseGroupDialog({
14
+ open,
15
+ handleClose,
16
+ handleCreate,
17
+ onCreated,
18
+ t = text => text,
19
+ fileSizeLimit,
20
+ verificationStatus
21
+ }) {
22
+ const [name, setName] = useState("");
23
+ const [description, setDescription] = useState("");
24
+ const [isLoading, setIsLoading] = useState(false);
25
+ const [selectedImage, setSelectedImage] = useState({
26
+ image: "",
27
+ imageSelectionMethod: "default_image"
28
+ });
29
+ const handleImageSelection = event => {
30
+ const {
31
+ name,
32
+ value
33
+ } = event.target;
34
+ setSelectedImage(prev => ({
35
+ ...prev,
36
+ [name]: value
37
+ }));
38
+ };
39
+ const removeImage = () => {
40
+ setSelectedImage({
41
+ image: "",
42
+ imageSelectionMethod: "default_image"
43
+ });
44
+ };
45
+ const handleSubmit = async () => {
46
+ if (!name.trim()) return;
47
+ setIsLoading(true);
48
+ try {
49
+ const createdPhraseGroup = await handleCreate({
50
+ phraseGroupName: name.trim(),
51
+ description: description.trim()
52
+ });
53
+ resetAndClose();
54
+ if (onCreated && createdPhraseGroup) {
55
+ onCreated(createdPhraseGroup, selectedImage.image || null);
56
+ }
57
+ } catch (error) {
58
+ console.error("Failed to create phrase group:", error);
59
+ } finally {
60
+ setIsLoading(false);
61
+ }
62
+ };
63
+ const resetAndClose = () => {
64
+ setName("");
65
+ setDescription("");
66
+ setSelectedImage({
67
+ image: "",
68
+ imageSelectionMethod: "default_image"
69
+ });
70
+ handleClose();
71
+ };
72
+ return /*#__PURE__*/_jsxs(Dialog, {
73
+ open: open,
74
+ onClose: isLoading ? undefined : resetAndClose,
75
+ maxWidth: "sm",
76
+ fullWidth: true,
77
+ children: [/*#__PURE__*/_jsx(DialogTitle, {
78
+ children: t("create_phrase_group") || "Create Phrase List"
79
+ }), /*#__PURE__*/_jsx(DialogContent, {
80
+ children: /*#__PURE__*/_jsxs(Box, {
81
+ display: "flex",
82
+ flexDirection: "column",
83
+ gap: 2,
84
+ pt: 1,
85
+ children: [/*#__PURE__*/_jsx(TextField, {
86
+ label: t("phrase_group_name") || "Name",
87
+ value: name,
88
+ onChange: e => setName(e.target.value),
89
+ fullWidth: true,
90
+ autoFocus: true,
91
+ required: true,
92
+ disabled: isLoading,
93
+ inputProps: {
94
+ maxLength: 100
95
+ },
96
+ onKeyDown: e => e.key === "Enter" && handleSubmit()
97
+ }), /*#__PURE__*/_jsx(TextField, {
98
+ label: t("description") || "Description",
99
+ value: description,
100
+ onChange: e => setDescription(e.target.value),
101
+ fullWidth: true,
102
+ multiline: true,
103
+ rows: 3,
104
+ disabled: isLoading,
105
+ inputProps: {
106
+ maxLength: 300
107
+ }
108
+ }), /*#__PURE__*/_jsx(Grid, {
109
+ size: 12,
110
+ children: /*#__PURE__*/_jsx(ImageSelector, {
111
+ t: t,
112
+ name: "image",
113
+ value: selectedImage.image,
114
+ handleChange: handleImageSelection,
115
+ fileSizeLimit: fileSizeLimit,
116
+ removeImage: removeImage,
117
+ autoCrop: true,
118
+ autoSuggest: false,
119
+ selectedImage: selectedImage,
120
+ verificationStatus: verificationStatus
121
+ })
122
+ })]
123
+ })
124
+ }), /*#__PURE__*/_jsxs(DialogActions, {
125
+ children: [/*#__PURE__*/_jsx(Button, {
126
+ onClick: resetAndClose,
127
+ color: "primary",
128
+ disabled: isLoading,
129
+ children: t("cancel") || "Cancel"
130
+ }), /*#__PURE__*/_jsx(Button, {
131
+ onClick: handleSubmit,
132
+ color: "primary",
133
+ variant: "contained",
134
+ 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"
140
+ })]
141
+ })]
142
+ });
143
+ }
@@ -20,10 +20,7 @@ function FeedbackDialog({
20
20
  onSubmit,
21
21
  submitText,
22
22
  dialogTitle,
23
- updateFeedback,
24
- onChange,
25
- initialFeedbackContent,
26
- ...otherProps
23
+ initialFeedbackContent
27
24
  }) {
28
25
  const {
29
26
  classes
@@ -0,0 +1,205 @@
1
+ import { useState, useEffect } from "react";
2
+ import ResponsiveDialog from "../ResponsiveDialog/ResponsiveDialog";
3
+ import { AutoFixHigh } from "@mui/icons-material";
4
+ import { Alert, Box, Card, Grid, LinearProgress, Typography } from "@mui/material";
5
+ import NualaCreating from "../../Misc/NualaCreating/NualaCreating";
6
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
7
+ function GenerateDefinitions({
8
+ t,
9
+ open,
10
+ handleClose,
11
+ selectedPhraseObjects,
12
+ makeChatGptApiRequest,
13
+ handleUpdatePhrase,
14
+ learnLang,
15
+ forLang,
16
+ siteLanguage,
17
+ difficulty
18
+ }) {
19
+ const [isGenerating, setIsGenerating] = useState(false);
20
+ const [errorMessage, setErrorMessage] = useState(null);
21
+ const [generatedDefinitions, setGeneratedDefinitions] = useState([]);
22
+ const [isConfirming, setIsConfirming] = useState(false);
23
+ const hasResults = generatedDefinitions.length > 0;
24
+
25
+ // Auto-trigger generation when dialog opens
26
+ useEffect(() => {
27
+ if (open && selectedPhraseObjects.length > 0 && !hasResults && !isGenerating) {
28
+ handleGenerate();
29
+ }
30
+ }, [open]);
31
+ function validateResponse(results) {
32
+ if (!Array.isArray(results)) return false;
33
+ for (const item of results) {
34
+ if (!item || typeof item !== "object") return false;
35
+ if (!Array.isArray(item.definitions)) return false;
36
+ for (const def of item.definitions) {
37
+ if (typeof def !== "string" || def.trim() === "") return false;
38
+ }
39
+ }
40
+ return true;
41
+ }
42
+ const handleGenerate = async () => {
43
+ try {
44
+ setIsGenerating(true);
45
+ setErrorMessage(null);
46
+ const phrasesData = selectedPhraseObjects.map(p => ({
47
+ phraseId: p.phraseId,
48
+ phrase: p.phrase,
49
+ translations: p.translations || []
50
+ }));
51
+ const chatGptResponse = await makeChatGptApiRequest({
52
+ model: "gpt-4o",
53
+ promptKey: "generateDefinitions",
54
+ promptVariables: {
55
+ learnLang,
56
+ forLang,
57
+ siteLanguage,
58
+ difficulty,
59
+ phrases: phrasesData
60
+ }
61
+ });
62
+ const results = chatGptResponse.result;
63
+ if (!validateResponse(results)) {
64
+ throw new Error("Invalid AI response");
65
+ }
66
+ const merged = selectedPhraseObjects.map((original, index) => {
67
+ const generated = results.find(r => r.phraseId === original.phraseId) || results[index];
68
+ return {
69
+ phraseId: original.phraseId,
70
+ phrase: original.phrase,
71
+ oldDefinitions: original.definitions || [],
72
+ newDefinitions: generated ? generated.definitions : []
73
+ };
74
+ });
75
+ setGeneratedDefinitions(merged);
76
+ } catch (error) {
77
+ console.error(error);
78
+ setErrorMessage(t("generate_defintions_error"));
79
+ } finally {
80
+ setIsGenerating(false);
81
+ }
82
+ };
83
+ const handleConfirm = async () => {
84
+ try {
85
+ setIsConfirming(true);
86
+ for (const item of generatedDefinitions) {
87
+ const originalPhrase = selectedPhraseObjects.find(p => p.phraseId === item.phraseId);
88
+ await handleUpdatePhrase(item.phraseId, {
89
+ phrase: originalPhrase?.phrase || item.phrase,
90
+ translations: originalPhrase?.translations || [],
91
+ definitions: item.newDefinitions
92
+ });
93
+ }
94
+ setGeneratedDefinitions([]);
95
+ setIsConfirming(false);
96
+ handleClose();
97
+ } catch (error) {
98
+ console.error(error);
99
+ setIsConfirming(false);
100
+ setErrorMessage(t("save_definitions_error"));
101
+ }
102
+ };
103
+ const handleCancel = () => {
104
+ handleClose();
105
+ setGeneratedDefinitions([]);
106
+ setErrorMessage(null);
107
+ };
108
+ const handleDialogClose = () => {
109
+ setGeneratedDefinitions([]);
110
+ setErrorMessage(null);
111
+ handleClose();
112
+ };
113
+ return /*#__PURE__*/_jsxs(ResponsiveDialog, {
114
+ open: open,
115
+ closeText: hasResults ? t("cancel") : t("close"),
116
+ handleClose: hasResults ? handleCancel : handleDialogClose,
117
+ handleSubmit: hasResults ? handleConfirm : handleGenerate,
118
+ submitText: hasResults ? t("confirm") : t("generate_definitions"),
119
+ dialogTitle: isGenerating ? t("generating_definitions") : t("generate_definitions"),
120
+ isSubmitDisabled: isGenerating || isConfirming,
121
+ isExperimentalFeature: true,
122
+ startIcon: /*#__PURE__*/_jsx(AutoFixHigh, {}),
123
+ children: [/*#__PURE__*/_jsx(Grid, {
124
+ textAlign: "center",
125
+ sx: {
126
+ ...(!isGenerating && {
127
+ display: "none"
128
+ })
129
+ },
130
+ mx: 2,
131
+ size: 12,
132
+ children: /*#__PURE__*/_jsx(NualaCreating, {})
133
+ }), /*#__PURE__*/_jsx(Grid, {
134
+ sx: {
135
+ ...(!isGenerating && {
136
+ display: "none"
137
+ })
138
+ },
139
+ mt: 2,
140
+ size: 12,
141
+ children: /*#__PURE__*/_jsx(LinearProgress, {})
142
+ }), !isGenerating && /*#__PURE__*/_jsxs(_Fragment, {
143
+ children: [generatedDefinitions.length === 0 && !errorMessage && /*#__PURE__*/_jsx(Typography, {
144
+ variant: "body2",
145
+ color: "text.secondary",
146
+ children: t("generate_definitions_info")
147
+ }), hasResults && /*#__PURE__*/_jsxs(_Fragment, {
148
+ children: [/*#__PURE__*/_jsx(Typography, {
149
+ sx: {
150
+ mb: 1
151
+ },
152
+ children: t("review_generated_definitions")
153
+ }), generatedDefinitions.map(item => /*#__PURE__*/_jsxs(Card, {
154
+ variant: "outlined",
155
+ sx: {
156
+ mb: 2,
157
+ p: 2
158
+ },
159
+ children: [/*#__PURE__*/_jsx(Typography, {
160
+ variant: "subtitle1",
161
+ fontWeight: "bold",
162
+ children: item.phrase
163
+ }), item.oldDefinitions.length > 0 && /*#__PURE__*/_jsxs(Box, {
164
+ sx: {
165
+ mt: 1
166
+ },
167
+ children: [/*#__PURE__*/_jsxs(Typography, {
168
+ variant: "caption",
169
+ color: "text.secondary",
170
+ children: [t("current_definitions"), ":"]
171
+ }), item.oldDefinitions.map((def, i) => /*#__PURE__*/_jsx(Typography, {
172
+ variant: "body2",
173
+ sx: {
174
+ textDecoration: "line-through",
175
+ opacity: 0.6
176
+ },
177
+ children: def
178
+ }, i))]
179
+ }), /*#__PURE__*/_jsxs(Box, {
180
+ sx: {
181
+ mt: 1
182
+ },
183
+ children: [/*#__PURE__*/_jsxs(Typography, {
184
+ variant: "caption",
185
+ color: "success.main",
186
+ children: [t("new_definitions"), ":"]
187
+ }), item.newDefinitions.map((def, i) => /*#__PURE__*/_jsx(Typography, {
188
+ variant: "body2",
189
+ color: "success.main",
190
+ children: def
191
+ }, i))]
192
+ })]
193
+ }, item.phraseId))]
194
+ }), errorMessage && /*#__PURE__*/_jsx(Grid, {
195
+ mt: 2,
196
+ size: 12,
197
+ children: /*#__PURE__*/_jsx(Alert, {
198
+ severity: "warning",
199
+ children: errorMessage
200
+ })
201
+ })]
202
+ })]
203
+ });
204
+ }
205
+ export default GenerateDefinitions;
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "GenerateDefinitions",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "main": "./GenerateDefinitions.js"
6
+ }
@@ -1,7 +1,7 @@
1
- import { useState } from "react";
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 } from "@mui/material";
4
+ import { Alert, Grid, InputAdornment, LinearProgress, MenuItem, Slider, TextField, Tooltip, Typography, ListItem, ListItemText, useMediaQuery, FormControlLabel, Switch, Box } 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";
@@ -115,6 +115,7 @@ function GeneratePhrases({
115
115
  const [errorMessage, setErrorMessage] = useState(null);
116
116
  const [phraseType, setPhraseType] = useState("words");
117
117
  const [generatedPhrases, setGeneratedPhrases] = useState([]);
118
+ const [generateDefinitions, setGenerateDefinitions] = useState(true);
118
119
  const isPhrases = currentPhrases && currentPhrases.length > 0;
119
120
  const phrases = isPhrases ? currentPhrases.map(({
120
121
  phrase,
@@ -188,7 +189,8 @@ function GeneratePhrases({
188
189
  difficulty,
189
190
  phraseType,
190
191
  isPhrases,
191
- phrases
192
+ phrases,
193
+ generateDefinitions
192
194
  }
193
195
  });
194
196
  const phrasesArray = chatGptResponse.result;
@@ -217,6 +219,9 @@ function GeneratePhrases({
217
219
  const handleCancel = () => {
218
220
  setGeneratedPhrases([]);
219
221
  };
222
+ useEffect(() => {
223
+ setGenerateDefinitions(phraseType === 'words');
224
+ }, [phraseType]);
220
225
  return /*#__PURE__*/_jsxs(ResponsiveDialog, {
221
226
  open: open,
222
227
  closeText: generatedPhrases.length > 0 ? t("cancel") : t("close"),
@@ -353,6 +358,31 @@ function GeneratePhrases({
353
358
  min: 4,
354
359
  max: 16
355
360
  })]
361
+ }), /*#__PURE__*/_jsxs(Grid, {
362
+ size: 12,
363
+ children: [/*#__PURE__*/_jsx(Typography, {
364
+ children: /*#__PURE__*/_jsx(Box, {
365
+ children: t("generate_definitions")
366
+ })
367
+ }), /*#__PURE__*/_jsx(FormControlLabel, {
368
+ label: "",
369
+ control: /*#__PURE__*/_jsx(_Fragment, {
370
+ children: /*#__PURE__*/_jsx("span", {
371
+ children: /*#__PURE__*/_jsx(Switch, {
372
+ checked: generateDefinitions,
373
+ onChange: e => {
374
+ setGenerateDefinitions(e.target.checked);
375
+ },
376
+ inputProps: {
377
+ "aria-label": "controlled"
378
+ },
379
+ sx: {
380
+ marginLeft: 0.5
381
+ }
382
+ })
383
+ })
384
+ })
385
+ })]
356
386
  })]
357
387
  }), generatedPhrases.length > 0 && /*#__PURE__*/_jsxs(_Fragment, {
358
388
  children: [/*#__PURE__*/_jsx(Typography, {