@nualang/nualang-ui-components 0.1.1397 → 0.1.1399

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.
@@ -28,6 +28,7 @@ import ArrowBack from "@mui/icons-material/ArrowBack";
28
28
  import Close from "@mui/icons-material/Close";
29
29
  import UpgradeSubscription from "../../Dialogs/UpgradeSubscription/UpgradeSubscription";
30
30
  import QuickCreateClassroomDialog from "../../Dialogs/QuickCreateClassroomDialog/QuickCreateClassroomDialog";
31
+ import QuickCreateCourseDialog from "../../Dialogs/QuickCreateCourseDialog/QuickCreateCourseDialog";
31
32
 
32
33
  // nav config
33
34
  import navigationImport from "../../Navigation/_nav";
@@ -217,11 +218,13 @@ function App({
217
218
  setIsCollapsed,
218
219
  isUserInternal,
219
220
  handleQuickCreateClassroom,
221
+ handleQuickCreateCourse,
220
222
  learnLang,
221
223
  forLang,
222
224
  fileSizeLimit,
223
225
  languages,
224
- forLanguages
226
+ forLanguages,
227
+ difficulties
225
228
  }) {
226
229
  const theme = useTheme();
227
230
  const isLgScreen = useMediaQuery(theme.breakpoints.up("md"));
@@ -230,6 +233,7 @@ function App({
230
233
  const [isAppContainerLoading, setIsAppContainerLoading] = useState(true);
231
234
  const [anchorEl, setAnchorEl] = useState(null);
232
235
  const [isCreateClassroomOpen, setIsCreateClassroomOpen] = useState(false);
236
+ const [isCreateCourseOpen, setIsCreateCourseOpen] = useState(false);
233
237
  const [isUpgradeSubscriptionOpen, setIsUpgradeSubscriptionOpen] = useState(false);
234
238
  const [isMobileSearchExpanded, setIsMobileSearchExpanded] = useState(false);
235
239
  const handleOpenUpgradeSubscriptionModal = () => {
@@ -277,8 +281,7 @@ function App({
277
281
  handleCloseCreate();
278
282
  };
279
283
  const handleCreateCourse = () => {
280
- navigate("/courses/create");
281
- handleCloseCreate();
284
+ setIsCreateCourseOpen(true);
282
285
  };
283
286
  const handleCreateAssignment = () => {
284
287
  navigate("/assignments/create");
@@ -440,6 +443,21 @@ function App({
440
443
  languages: languages,
441
444
  forLanguages: forLanguages,
442
445
  userImage: user ? user.picture : null
446
+ }), /*#__PURE__*/_jsx(QuickCreateCourseDialog, {
447
+ open: isCreateCourseOpen,
448
+ handleClose: () => setIsCreateCourseOpen(false),
449
+ handleCreate: async values => {
450
+ await handleQuickCreateCourse(values);
451
+ },
452
+ t: t,
453
+ learnLang: learnLang,
454
+ forLang: forLang,
455
+ languages: languages,
456
+ forLanguages: forLanguages,
457
+ difficulties: difficulties,
458
+ fileSizeLimit: fileSizeLimit,
459
+ verificationStatus: verificationStatus,
460
+ userImage: user ? user.picture : null
443
461
  }), /*#__PURE__*/_jsx(LanguageSelector, {
444
462
  t: t,
445
463
  currentLanguage: currentLanguage,
@@ -114,7 +114,7 @@ export default function QuickCreateClassroomDialog({
114
114
  children: /*#__PURE__*/_jsxs(Box, {
115
115
  display: "flex",
116
116
  flexDirection: "column",
117
- gap: 2,
117
+ gap: 1,
118
118
  pt: 1,
119
119
  children: [/*#__PURE__*/_jsx(TextField, {
120
120
  label: t("classroom_name") || "Classroom Name",
@@ -127,7 +127,8 @@ export default function QuickCreateClassroomDialog({
127
127
  inputProps: {
128
128
  maxLength: 100
129
129
  },
130
- onKeyDown: e => e.key === "Enter" && handleSubmit()
130
+ onKeyDown: e => e.key === "Enter" && handleSubmit(),
131
+ margin: "normal"
131
132
  }), /*#__PURE__*/_jsx(Grid, {
132
133
  size: 12,
133
134
  children: /*#__PURE__*/_jsx(LanguageSelector, {
@@ -0,0 +1,215 @@
1
+ import { useState, useEffect } from "react";
2
+ import TextField from "@mui/material/TextField";
3
+ import MenuItem from "@mui/material/MenuItem";
4
+ import Box from "@mui/material/Box";
5
+ import Button from "@mui/material/Button";
6
+ import Dialog from "@mui/material/Dialog";
7
+ import DialogTitle from "@mui/material/DialogTitle";
8
+ import DialogContent from "@mui/material/DialogContent";
9
+ import DialogActions from "@mui/material/DialogActions";
10
+ import Grid from "@mui/material/Grid";
11
+ import LanguageSelector from "../../Forms/LanguageSelector/LanguageSelector";
12
+ import ImageSelector from "../../Forms/ImageSelector/ImageSelector";
13
+ import PlaceholderImages from "../../utils/placeholder-images/index";
14
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
+ export default function QuickCreateCourseDialog({
16
+ open,
17
+ handleClose,
18
+ handleCreate,
19
+ onCreated,
20
+ t = text => text,
21
+ learnLang,
22
+ forLang,
23
+ languages,
24
+ forLanguages,
25
+ difficulties = ["A1", "A2", "B1", "B2", "C1", "C2"],
26
+ fileSizeLimit,
27
+ verificationStatus,
28
+ userImage
29
+ }) {
30
+ const defaultSelectedImage = {
31
+ image: PlaceholderImages.course,
32
+ imageSelectionMethod: "default_image"
33
+ };
34
+ const [courseName, setCourseName] = useState("");
35
+ const [difficulty, setDifficulty] = useState("");
36
+ const [courseLearnLang, setCourseLearnLang] = useState("");
37
+ const [courseForLang, setCourseForLang] = useState("");
38
+ const [isLoading, setIsLoading] = useState(false);
39
+ const [selectedImage, setSelectedImage] = useState(defaultSelectedImage);
40
+ const [picture, setPicture] = useState("");
41
+ useEffect(() => {
42
+ if (learnLang && courseLearnLang === "") {
43
+ setCourseLearnLang(learnLang);
44
+ }
45
+ }, [learnLang]);
46
+ useEffect(() => {
47
+ if (forLang && courseForLang === "") {
48
+ setCourseForLang(forLang);
49
+ }
50
+ }, [forLang]);
51
+ const handleImageSelection = event => {
52
+ const {
53
+ name,
54
+ value
55
+ } = event.target;
56
+ setSelectedImage(prev => ({
57
+ ...prev,
58
+ [name]: value
59
+ }));
60
+ setPicture(value);
61
+ };
62
+ const removeImage = () => {
63
+ setSelectedImage(defaultSelectedImage);
64
+ setPicture("");
65
+ };
66
+ const generateRandomEnrolmentKey = () => {
67
+ return String(Math.floor(Math.random() * 90000) + 10000);
68
+ };
69
+ const handleSubmit = async () => {
70
+ if (!courseName.trim() || !difficulty) return;
71
+ setIsLoading(true);
72
+ try {
73
+ const createdCourse = await handleCreate({
74
+ courseName: courseName.trim(),
75
+ description: `${t("course_description_default", {
76
+ learnLang: t(courseLearnLang)
77
+ })}`,
78
+ difficulty,
79
+ learnLang: courseLearnLang,
80
+ forLang: courseForLang,
81
+ picture: picture || PlaceholderImages.course,
82
+ visibility: "private",
83
+ enrolmentKey: generateRandomEnrolmentKey(),
84
+ allowedDomains: [],
85
+ tags: [],
86
+ collaborators: [],
87
+ userImage: userImage,
88
+ isShareable: "collaborators",
89
+ duplicated: false
90
+ });
91
+ resetAndClose();
92
+ if (onCreated && createdCourse) {
93
+ onCreated(createdCourse, selectedImage.image || null);
94
+ }
95
+ } catch (error) {
96
+ console.error("Failed to create course:", error);
97
+ } finally {
98
+ setIsLoading(false);
99
+ }
100
+ };
101
+ const resetAndClose = () => {
102
+ setCourseName("");
103
+ setDifficulty("");
104
+ setCourseLearnLang(learnLang || "");
105
+ setCourseForLang(forLang || "");
106
+ setSelectedImage(defaultSelectedImage);
107
+ setPicture("");
108
+ handleClose();
109
+ };
110
+ const isSubmitDisabled = !courseName.trim() || !difficulty || isLoading;
111
+ return /*#__PURE__*/_jsxs(Dialog, {
112
+ open: open,
113
+ onClose: isLoading ? undefined : resetAndClose,
114
+ maxWidth: "sm",
115
+ fullWidth: true,
116
+ children: [/*#__PURE__*/_jsx(DialogTitle, {
117
+ children: t("create_course") || "Create Course"
118
+ }), /*#__PURE__*/_jsx(DialogContent, {
119
+ children: /*#__PURE__*/_jsxs(Box, {
120
+ display: "flex",
121
+ flexDirection: "column",
122
+ gap: 1,
123
+ pt: 1,
124
+ children: [/*#__PURE__*/_jsx(TextField, {
125
+ label: t("course_name") || "Course Name",
126
+ value: courseName,
127
+ onChange: e => setCourseName(e.target.value),
128
+ fullWidth: true,
129
+ autoFocus: true,
130
+ required: true,
131
+ disabled: isLoading,
132
+ inputProps: {
133
+ maxLength: 200
134
+ },
135
+ onKeyDown: e => e.key === "Enter" && handleSubmit(),
136
+ margin: "normal"
137
+ }), /*#__PURE__*/_jsx(TextField, {
138
+ select: true,
139
+ label: t("difficulty") || "Difficulty",
140
+ value: difficulty,
141
+ onChange: e => setDifficulty(e.target.value),
142
+ fullWidth: true,
143
+ required: true,
144
+ disabled: isLoading,
145
+ margin: "normal",
146
+ children: difficulties.map(d => /*#__PURE__*/_jsx(MenuItem, {
147
+ value: d,
148
+ children: t(d)
149
+ }, d))
150
+ }), /*#__PURE__*/_jsx(Grid, {
151
+ size: 12,
152
+ children: /*#__PURE__*/_jsx(LanguageSelector, {
153
+ id: "learnLang",
154
+ name: "learnLang",
155
+ "data-cy": "learnLang",
156
+ label: t("the_language_course_teach"),
157
+ margin: "normal",
158
+ variant: "outlined",
159
+ fullWidth: true,
160
+ required: true,
161
+ t: t,
162
+ languages: languages,
163
+ value: courseLearnLang,
164
+ disabled: isLoading,
165
+ onChange: e => setCourseLearnLang(e.target.value)
166
+ })
167
+ }), /*#__PURE__*/_jsx(Grid, {
168
+ size: 12,
169
+ children: /*#__PURE__*/_jsx(LanguageSelector, {
170
+ id: "forLang",
171
+ name: "forLang",
172
+ "data-cy": "forLang",
173
+ label: t("the_language_students_course_speak"),
174
+ margin: "normal",
175
+ variant: "outlined",
176
+ fullWidth: true,
177
+ required: true,
178
+ t: t,
179
+ languages: forLanguages,
180
+ value: courseForLang,
181
+ disabled: isLoading,
182
+ onChange: e => setCourseForLang(e.target.value)
183
+ })
184
+ }), /*#__PURE__*/_jsx(Grid, {
185
+ size: 12,
186
+ children: /*#__PURE__*/_jsx(ImageSelector, {
187
+ t: t,
188
+ name: "image",
189
+ value: selectedImage.image,
190
+ handleChange: handleImageSelection,
191
+ fileSizeLimit: fileSizeLimit,
192
+ removeImage: removeImage,
193
+ autoCrop: true,
194
+ autoSuggest: false,
195
+ selectedImage: selectedImage,
196
+ verificationStatus: verificationStatus
197
+ })
198
+ })]
199
+ })
200
+ }), /*#__PURE__*/_jsxs(DialogActions, {
201
+ children: [/*#__PURE__*/_jsx(Button, {
202
+ onClick: resetAndClose,
203
+ color: "primary",
204
+ disabled: isLoading,
205
+ children: t("cancel") || "Cancel"
206
+ }), /*#__PURE__*/_jsx(Button, {
207
+ onClick: handleSubmit,
208
+ color: "primary",
209
+ variant: "contained",
210
+ disabled: isSubmitDisabled,
211
+ children: t("create") || "Create"
212
+ })]
213
+ })]
214
+ });
215
+ }
@@ -1,3 +1,4 @@
1
+ import { useState } from "react";
1
2
  import { makeStyles } from "tss-react/mui";
2
3
  import Typography from "@mui/material/Typography";
3
4
  import Button from "@mui/material/Button";
@@ -8,6 +9,7 @@ import Grid from "@mui/material/Grid";
8
9
  import Divider from "@mui/material/Divider";
9
10
  import Box from "@mui/material/Box";
10
11
  import CreateIcon from "@mui/icons-material/Create";
12
+ import QuickCreateCourseDialog from "../../Dialogs/QuickCreateCourseDialog/QuickCreateCourseDialog";
11
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
14
  const useStyles = makeStyles()(theme => ({
13
15
  placeholder: {
@@ -38,12 +40,21 @@ const useStyles = makeStyles()(theme => ({
38
40
  }));
39
41
  export default function ClassCoursesNotFound({
40
42
  t = text => text,
41
- handleCreateCourse,
42
- handleOpenCoursesModal
43
+ handleOpenCoursesModal,
44
+ handleQuickCreateCourse,
45
+ learnLang,
46
+ forLang,
47
+ languages,
48
+ forLanguages,
49
+ difficulties,
50
+ fileSizeLimit,
51
+ verificationStatus,
52
+ userImage
43
53
  }) {
44
54
  const {
45
55
  classes
46
56
  } = useStyles();
57
+ const [isCreateCourseOpen, setIsCreateCourseOpen] = useState(false);
47
58
  return /*#__PURE__*/_jsxs(Grid, {
48
59
  container: true,
49
60
  sx: {
@@ -148,11 +159,9 @@ export default function ClassCoursesNotFound({
148
159
  gutterBottom: true,
149
160
  children: t("create_your_own_description")
150
161
  }), /*#__PURE__*/_jsx(Box, {
151
- sx: {
152
- mb: 1.5
153
- },
154
- children: handleCreateCourse && /*#__PURE__*/_jsx(Button, {
155
- onClick: handleCreateCourse,
162
+ mb: 1.5,
163
+ children: handleQuickCreateCourse && /*#__PURE__*/_jsx(Button, {
164
+ onClick: () => setIsCreateCourseOpen(true),
156
165
  className: classes.button,
157
166
  variant: "contained",
158
167
  color: "primary",
@@ -169,6 +178,21 @@ export default function ClassCoursesNotFound({
169
178
  })
170
179
  })
171
180
  })
181
+ }), /*#__PURE__*/_jsx(QuickCreateCourseDialog, {
182
+ open: isCreateCourseOpen,
183
+ handleClose: () => setIsCreateCourseOpen(false),
184
+ handleCreate: async values => {
185
+ await handleQuickCreateCourse(values);
186
+ },
187
+ t: t,
188
+ learnLang: learnLang,
189
+ forLang: forLang,
190
+ languages: languages,
191
+ forLanguages: forLanguages,
192
+ difficulties: difficulties,
193
+ fileSizeLimit: fileSizeLimit,
194
+ verificationStatus: verificationStatus,
195
+ userImage: userImage
172
196
  })]
173
197
  });
174
198
  }
@@ -1,9 +1,11 @@
1
+ import { useState } from "react";
1
2
  import { makeStyles } from "tss-react/mui";
2
3
  import Typography from "@mui/material/Typography";
3
4
  import Button from "@mui/material/Button";
4
5
  import SearchIcon from "@mui/icons-material/Search";
5
6
  import AddIcon from "@mui/icons-material/Add";
6
7
  import CourseImage from "../../img/structuring.svg";
8
+ import QuickCreateCourseDialog from "../../Dialogs/QuickCreateCourseDialog/QuickCreateCourseDialog";
7
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
10
  const useStyles = makeStyles()(theme => ({
9
11
  placeholder: {
@@ -30,15 +32,24 @@ export default function CoursesNotFound({
30
32
  title = "No Courses Found",
31
33
  description = "Join or create your first course today",
32
34
  handleSearch,
33
- handleCreateCourse,
34
- handleOpenCoursesModal
35
+ handleOpenCoursesModal,
36
+ handleQuickCreateCourse,
37
+ learnLang,
38
+ forLang,
39
+ languages,
40
+ forLanguages,
41
+ difficulties,
42
+ fileSizeLimit,
43
+ verificationStatus,
44
+ userImage
35
45
  }) {
36
46
  const {
37
47
  classes
38
48
  } = useStyles();
39
- return /*#__PURE__*/_jsx("div", {
49
+ const [isCreateCourseOpen, setIsCreateCourseOpen] = useState(false);
50
+ return /*#__PURE__*/_jsxs("div", {
40
51
  className: classes.placeholder,
41
- children: /*#__PURE__*/_jsxs("div", {
52
+ children: [/*#__PURE__*/_jsxs("div", {
42
53
  className: classes.placeholderContent,
43
54
  children: [/*#__PURE__*/_jsx("img", {
44
55
  src: placeholderImageUrl,
@@ -63,8 +74,8 @@ export default function CoursesNotFound({
63
74
  endIcon: /*#__PURE__*/_jsx(SearchIcon, {}),
64
75
  role: "link",
65
76
  children: t("find_course")
66
- }), handleCreateCourse && /*#__PURE__*/_jsx(Button, {
67
- onClick: handleCreateCourse,
77
+ }), handleQuickCreateCourse && /*#__PURE__*/_jsx(Button, {
78
+ onClick: () => setIsCreateCourseOpen(true),
68
79
  className: classes.button,
69
80
  variant: "contained",
70
81
  color: "primary",
@@ -80,6 +91,21 @@ export default function CoursesNotFound({
80
91
  id: "add-courses-fab",
81
92
  children: t("add_courses")
82
93
  })]
83
- })
94
+ }), /*#__PURE__*/_jsx(QuickCreateCourseDialog, {
95
+ open: isCreateCourseOpen,
96
+ handleClose: () => setIsCreateCourseOpen(false),
97
+ handleCreate: async values => {
98
+ await handleQuickCreateCourse(values);
99
+ },
100
+ t: t,
101
+ learnLang: learnLang,
102
+ forLang: forLang,
103
+ languages: languages,
104
+ forLanguages: forLanguages,
105
+ difficulties: difficulties,
106
+ fileSizeLimit: fileSizeLimit,
107
+ verificationStatus: verificationStatus,
108
+ userImage: userImage
109
+ })]
84
110
  });
85
111
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nualang/nualang-ui-components",
3
- "version": "0.1.1397",
3
+ "version": "0.1.1399",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "files": [