@nualang/nualang-ui-components 0.1.1251 → 0.1.1252
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Cards/Course/Course.js +27 -15
- package/dist/Forms/ChipInput/ChipInput.js +46 -7
- package/dist/Forms/CreateCourse/CreateCourse.js +3 -1
- package/dist/Forms/CreateCourse/Steps/CourseSettings/CourseSettings.js +52 -7
- package/dist/Forms/UpdateCourse/UpdateCourse.js +12 -4
- package/dist/Lists/Courses/Courses.js +2 -0
- package/dist/Screens/Classrooms/ViewClassroom/ViewClassroom.js +10 -2
- package/dist/Screens/Courses/Courses.js +4 -2
- package/dist/Screens/Courses/ViewCourse/ViewCourse.js +2 -1
- package/package.json +1 -1
|
@@ -51,7 +51,8 @@ function OverflowMenu({
|
|
|
51
51
|
handleDuplicateCourse,
|
|
52
52
|
course,
|
|
53
53
|
classroomId,
|
|
54
|
-
isClassroomArchived = false
|
|
54
|
+
isClassroomArchived = false,
|
|
55
|
+
canDuplicateCourse
|
|
55
56
|
}) {
|
|
56
57
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.Menu, {
|
|
57
58
|
id: `card-menu-${courseId}`,
|
|
@@ -86,19 +87,26 @@ function OverflowMenu({
|
|
|
86
87
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
87
88
|
children: t("leave_course")
|
|
88
89
|
})]
|
|
89
|
-
}),
|
|
90
|
-
children:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
90
|
+
}), !isClassroomArchived && /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
91
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
|
|
92
|
+
title: !canDuplicateCourse ? t("duplicate_disabled_tooltip") : "",
|
|
93
|
+
disableHoverListener: canDuplicateCourse,
|
|
94
|
+
arrow: true,
|
|
95
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
|
|
96
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.MenuItem, {
|
|
97
|
+
onClick: async () => {
|
|
98
|
+
await handleDuplicateCourse(course, classroomId);
|
|
99
|
+
},
|
|
100
|
+
disabled: !canDuplicateCourse || course.duplicated,
|
|
101
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_CardElements.CardMenuIcon, {
|
|
102
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_FileCopy.default, {
|
|
103
|
+
fontSize: "small"
|
|
104
|
+
})
|
|
105
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Typography, {
|
|
106
|
+
children: t("duplicate_course")
|
|
107
|
+
})]
|
|
98
108
|
})
|
|
99
|
-
})
|
|
100
|
-
children: t("duplicate_course")
|
|
101
|
-
})]
|
|
109
|
+
})
|
|
102
110
|
})
|
|
103
111
|
}), handleRemoveCourse && !isClassroomArchived && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.MenuItem, {
|
|
104
112
|
onClick: () => handleRemoveCourse(courseId),
|
|
@@ -209,7 +217,8 @@ function CourseCard({
|
|
|
209
217
|
ariaText = "",
|
|
210
218
|
classroomId,
|
|
211
219
|
cardTitleComponent = "h2",
|
|
212
|
-
isClassroomArchived = false
|
|
220
|
+
isClassroomArchived = false,
|
|
221
|
+
email
|
|
213
222
|
}) {
|
|
214
223
|
const [placeholderRef, visible] = (0, _reactIntersectionObserver.useInView)({
|
|
215
224
|
rootMargin: "320px",
|
|
@@ -314,6 +323,8 @@ function CourseCard({
|
|
|
314
323
|
// const memberCount = membersQuery.isSuccess ? membersQuery.data.Items.length : 0;
|
|
315
324
|
|
|
316
325
|
const isPlaysVisible = !disablePlays && exerciseStartTotal > -1;
|
|
326
|
+
const isCollaborator = Array.isArray(course.collaborators) && course.collaborators.some(collab => (typeof collab === 'string' ? collab : collab?.S) === email);
|
|
327
|
+
const canDuplicateCourse = isCreator || course.isShareable === 'everyone' || course.isShareable === 'collaborators' && isCollaborator;
|
|
317
328
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_CardElements.CardContainer, {
|
|
318
329
|
sx: disableRaised ? {} : _CardElements.classes.hover,
|
|
319
330
|
raised: disableRaised ? false : anchorEl || isOutlineOpen,
|
|
@@ -526,7 +537,8 @@ function CourseCard({
|
|
|
526
537
|
handleRemoveCourse: handleRemoveCourse,
|
|
527
538
|
handleDuplicateCourse: handleDuplicateCourse,
|
|
528
539
|
course: course,
|
|
529
|
-
isClassroomArchived: isClassroomArchived
|
|
540
|
+
isClassroomArchived: isClassroomArchived,
|
|
541
|
+
canDuplicateCourse: canDuplicateCourse
|
|
530
542
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Members.default, {
|
|
531
543
|
getMemberDetails: getMemberDetails,
|
|
532
544
|
t: t,
|
|
@@ -4,25 +4,62 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
+
var _react = require("react");
|
|
7
8
|
var _CustomChipInput = _interopRequireDefault(require("../../Misc/CustomChipInput/CustomChipInput"));
|
|
8
9
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
9
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
// already present, just ensure it's used
|
|
12
|
+
|
|
10
13
|
function ChipInput(props) {
|
|
11
14
|
const {
|
|
15
|
+
t,
|
|
12
16
|
name = "",
|
|
13
17
|
value = [],
|
|
14
18
|
handleChange = () => {},
|
|
15
19
|
label,
|
|
16
20
|
delimiter = /[\s,]+/
|
|
17
21
|
} = props;
|
|
22
|
+
const [errorMessage, setErrorMessage] = (0, _react.useState)("");
|
|
23
|
+
const genericDomains = ['gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com', 'icloud.com'];
|
|
18
24
|
const handleAddChip = chip => {
|
|
19
25
|
const newChips = chip.split(delimiter).map(c => c.trim().toLowerCase()).filter(Boolean);
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
if (props.restrictCollaboratorDomains) {
|
|
27
|
+
const allowedDomain = props.userEmail?.split('@')[1];
|
|
28
|
+
const validChips = newChips.filter(c => {
|
|
29
|
+
const emailPattern = /^[^@]+@[^@]+\.[^@]+$/;
|
|
30
|
+
if (!emailPattern.test(c)) {
|
|
31
|
+
setErrorMessage(t("invalid_email_format"));
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
const domain = c.split('@')[1];
|
|
35
|
+
if (genericDomains.includes(domain)) {
|
|
36
|
+
setErrorMessage(t("generic_email_domain_error"));
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
if (domain !== allowedDomain) {
|
|
40
|
+
setErrorMessage(t("email_domain_mismatch_error", {
|
|
41
|
+
domain: allowedDomain
|
|
42
|
+
}));
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
});
|
|
47
|
+
if (validChips.length === 0) return;
|
|
48
|
+
setErrorMessage("");
|
|
49
|
+
handleChange({
|
|
50
|
+
target: {
|
|
51
|
+
name: name,
|
|
52
|
+
value: [...value, ...validChips]
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
handleChange({
|
|
57
|
+
target: {
|
|
58
|
+
name: name,
|
|
59
|
+
value: [...value, ...newChips]
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
26
63
|
};
|
|
27
64
|
const deleteChip = chip => {
|
|
28
65
|
handleChange({
|
|
@@ -37,7 +74,9 @@ function ChipInput(props) {
|
|
|
37
74
|
...props,
|
|
38
75
|
onAdd: handleAddChip,
|
|
39
76
|
onDelete: deleteChip,
|
|
40
|
-
delimiter: delimiter
|
|
77
|
+
delimiter: delimiter,
|
|
78
|
+
helperText: errorMessage || props.helperText,
|
|
79
|
+
error: !!errorMessage || props.error
|
|
41
80
|
});
|
|
42
81
|
}
|
|
43
82
|
var _default = exports.default = ChipInput;
|
|
@@ -20,14 +20,20 @@ function CourseSettings({
|
|
|
20
20
|
errors,
|
|
21
21
|
handleChange,
|
|
22
22
|
handleBlur,
|
|
23
|
-
subscription
|
|
23
|
+
subscription,
|
|
24
|
+
attributes
|
|
24
25
|
}) {
|
|
25
26
|
const {
|
|
26
27
|
visibility,
|
|
27
28
|
enrolmentKey,
|
|
28
29
|
allowedDomains,
|
|
29
|
-
collaborators
|
|
30
|
+
collaborators,
|
|
31
|
+
isShareable,
|
|
32
|
+
duplicated
|
|
30
33
|
} = values;
|
|
34
|
+
const {
|
|
35
|
+
email
|
|
36
|
+
} = attributes || {};
|
|
31
37
|
const generateRandomEnrolmentKey = (0, _react.useCallback)(() => {
|
|
32
38
|
return String(Math.floor(Math.random() * 90000) + 10000);
|
|
33
39
|
}, []);
|
|
@@ -85,11 +91,44 @@ function CourseSettings({
|
|
|
85
91
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormControlLabel, {
|
|
86
92
|
value: "public",
|
|
87
93
|
control: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Radio, {}),
|
|
88
|
-
label: t("public")
|
|
94
|
+
label: t("public"),
|
|
95
|
+
disabled: duplicated
|
|
89
96
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormControlLabel, {
|
|
90
97
|
value: "private",
|
|
91
98
|
control: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Radio, {}),
|
|
92
|
-
label: t("private")
|
|
99
|
+
label: t("private"),
|
|
100
|
+
disabled: duplicated
|
|
101
|
+
})]
|
|
102
|
+
})]
|
|
103
|
+
})
|
|
104
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Grid, {
|
|
105
|
+
size: {
|
|
106
|
+
xs: 12,
|
|
107
|
+
md: 12
|
|
108
|
+
},
|
|
109
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.FormControl, {
|
|
110
|
+
component: "fieldset",
|
|
111
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormLabel, {
|
|
112
|
+
component: "legend",
|
|
113
|
+
children: t("duplication")
|
|
114
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_material.RadioGroup, {
|
|
115
|
+
"aria-label": "duplication",
|
|
116
|
+
name: "isShareable",
|
|
117
|
+
value: isShareable,
|
|
118
|
+
onChange: handleChange,
|
|
119
|
+
onBlur: handleBlur,
|
|
120
|
+
helperText: touched.isShareable ? errors.isShareable : "",
|
|
121
|
+
error: touched.isShareable && Boolean(errors.isShareable),
|
|
122
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormControlLabel, {
|
|
123
|
+
value: "everyone",
|
|
124
|
+
control: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Radio, {}),
|
|
125
|
+
label: t("everyone"),
|
|
126
|
+
disabled: duplicated
|
|
127
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.FormControlLabel, {
|
|
128
|
+
value: "collaborators",
|
|
129
|
+
control: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Radio, {}),
|
|
130
|
+
label: t("collaborators"),
|
|
131
|
+
disabled: duplicated
|
|
93
132
|
})]
|
|
94
133
|
})]
|
|
95
134
|
})
|
|
@@ -176,7 +215,9 @@ function CourseSettings({
|
|
|
176
215
|
margin: "normal",
|
|
177
216
|
variant: "outlined",
|
|
178
217
|
multiline: true,
|
|
179
|
-
fullWidth: true
|
|
218
|
+
fullWidth: true,
|
|
219
|
+
restrictCollaboratorDomains: duplicated,
|
|
220
|
+
userEmail: email
|
|
180
221
|
}), !subscription.isPaidUser && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
|
|
181
222
|
title: subscription.isUpgradePossible ? t("upgrade_plan_explanation") : t("upgrade_subscription_student"),
|
|
182
223
|
placement: "top",
|
|
@@ -195,7 +236,9 @@ function CourseSettings({
|
|
|
195
236
|
margin: "normal",
|
|
196
237
|
variant: "outlined",
|
|
197
238
|
multiline: true,
|
|
198
|
-
fullWidth: true
|
|
239
|
+
fullWidth: true,
|
|
240
|
+
restrictCollaboratorDomains: duplicated,
|
|
241
|
+
userEmail: email
|
|
199
242
|
})
|
|
200
243
|
})]
|
|
201
244
|
})
|
|
@@ -212,6 +255,8 @@ CourseSettings.validationSchema = Yup.object().shape({
|
|
|
212
255
|
otherwise: () => Yup.string().nullable()
|
|
213
256
|
}),
|
|
214
257
|
allowedDomains: Yup.array(Yup.string().test("noSpecialChars", "no_special_characters", value => !(0, _index.containsInvalidSymbols)(value)).matches(_index.domainPattern, "Must be a valid domain e.g 'schooldomain.com'")).nullable(),
|
|
215
|
-
collaborators: Yup.array(Yup.string().test("noSpecialChars", "no_special_characters", value => !(0, _index.containsInvalidSymbols)(value))).nullable()
|
|
258
|
+
collaborators: Yup.array(Yup.string().test("noSpecialChars", "no_special_characters", value => !(0, _index.containsInvalidSymbols)(value))).nullable(),
|
|
259
|
+
isShareable: Yup.string().required("required"),
|
|
260
|
+
duplicated: Yup.bool()
|
|
216
261
|
});
|
|
217
262
|
var _default = exports.default = CourseSettings;
|
|
@@ -31,7 +31,9 @@ function UpdateCourse({
|
|
|
31
31
|
allowedDomains: [],
|
|
32
32
|
tags: [],
|
|
33
33
|
collaborators: [],
|
|
34
|
-
picture: null
|
|
34
|
+
picture: null,
|
|
35
|
+
isShareable: "",
|
|
36
|
+
duplicated: false
|
|
35
37
|
},
|
|
36
38
|
difficulties = ["A1", "A2", "B1", "B2", "C1", "C2"],
|
|
37
39
|
onSubmit,
|
|
@@ -40,7 +42,8 @@ function UpdateCourse({
|
|
|
40
42
|
forLanguages,
|
|
41
43
|
fileSizeLimit,
|
|
42
44
|
subscription,
|
|
43
|
-
verificationStatus
|
|
45
|
+
verificationStatus,
|
|
46
|
+
attributes
|
|
44
47
|
}) {
|
|
45
48
|
const difficultyOptions = difficulties.map((d, idx) => {
|
|
46
49
|
const keyId = `crearolax${(0, _index.randomId)()}${idx}`;
|
|
@@ -64,7 +67,9 @@ function UpdateCourse({
|
|
|
64
67
|
picture,
|
|
65
68
|
banner,
|
|
66
69
|
tags,
|
|
67
|
-
collaborators
|
|
70
|
+
collaborators,
|
|
71
|
+
isShareable,
|
|
72
|
+
duplicated
|
|
68
73
|
} = initialValues;
|
|
69
74
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
70
75
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_formik.Formik, {
|
|
@@ -137,7 +142,9 @@ function UpdateCourse({
|
|
|
137
142
|
visibility,
|
|
138
143
|
enrolmentKey,
|
|
139
144
|
allowedDomains,
|
|
140
|
-
collaborators
|
|
145
|
+
collaborators,
|
|
146
|
+
isShareable,
|
|
147
|
+
duplicated
|
|
141
148
|
},
|
|
142
149
|
enableReinitialize: enableReinitialize,
|
|
143
150
|
validationSchema: _Steps.CourseSettings.validationSchema,
|
|
@@ -171,6 +178,7 @@ function UpdateCourse({
|
|
|
171
178
|
className: classes.formContent,
|
|
172
179
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Steps.CourseSettings, {
|
|
173
180
|
t: t,
|
|
181
|
+
attributes: attributes,
|
|
174
182
|
subscription: subscription,
|
|
175
183
|
handleChange: handleChange,
|
|
176
184
|
handleSubmit: handleSubmit,
|
|
@@ -32,6 +32,7 @@ function CourseList({
|
|
|
32
32
|
disableActions,
|
|
33
33
|
classroomId,
|
|
34
34
|
isClassroomArchived = false,
|
|
35
|
+
email,
|
|
35
36
|
...otherProps
|
|
36
37
|
}) {
|
|
37
38
|
const [items, ref] = (0, _useListScroll.default)({
|
|
@@ -96,6 +97,7 @@ function CourseList({
|
|
|
96
97
|
handleDuplicateCourse: handleDuplicateCourse,
|
|
97
98
|
classroomId: classroomId,
|
|
98
99
|
isClassroomArchived: isClassroomArchived,
|
|
100
|
+
email: email,
|
|
99
101
|
...otherProps
|
|
100
102
|
}, course.courseId)
|
|
101
103
|
}, course.courseId);
|
|
@@ -395,6 +395,7 @@ function Classroom({
|
|
|
395
395
|
preferred_username,
|
|
396
396
|
isUserInternal,
|
|
397
397
|
assignedCourses,
|
|
398
|
+
email,
|
|
398
399
|
...otherProps
|
|
399
400
|
}) {
|
|
400
401
|
const {
|
|
@@ -794,6 +795,12 @@ function Classroom({
|
|
|
794
795
|
handleRemoveCourse(course);
|
|
795
796
|
}
|
|
796
797
|
};
|
|
798
|
+
const duplicateCourse = async course => {
|
|
799
|
+
const confirmed = await confirm(t("duplicate_course"), t("duplicate_course_confirmation"));
|
|
800
|
+
if (confirmed) {
|
|
801
|
+
handleDuplicateCourse(course);
|
|
802
|
+
}
|
|
803
|
+
};
|
|
797
804
|
const deleteClassroom = async id => {
|
|
798
805
|
const confirmed = await confirm(t("delete_classroom"), t("delete_classroom_confirmation"), "", true, t("classroom_deletion_note", {
|
|
799
806
|
courseCount: courses ? courses.length : 0
|
|
@@ -858,9 +865,10 @@ function Classroom({
|
|
|
858
865
|
memberId: memberId,
|
|
859
866
|
username: username,
|
|
860
867
|
disableActions: !(isMember || isCreator),
|
|
861
|
-
handleDuplicateCourse:
|
|
868
|
+
handleDuplicateCourse: duplicateCourse,
|
|
862
869
|
classroomId: classroomId,
|
|
863
|
-
isClassroomArchived: isArchived
|
|
870
|
+
isClassroomArchived: isArchived,
|
|
871
|
+
email: email
|
|
864
872
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
865
873
|
id: "add-courses-fab",
|
|
866
874
|
children: isCreator ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_ClassCourses.default, {
|
|
@@ -63,7 +63,8 @@ function Courses({
|
|
|
63
63
|
getCourseMembers,
|
|
64
64
|
username,
|
|
65
65
|
memberId,
|
|
66
|
-
handleDuplicateCourse
|
|
66
|
+
handleDuplicateCourse,
|
|
67
|
+
email
|
|
67
68
|
}) {
|
|
68
69
|
const {
|
|
69
70
|
classes
|
|
@@ -136,7 +137,8 @@ function Courses({
|
|
|
136
137
|
memberId: memberId,
|
|
137
138
|
username: username,
|
|
138
139
|
handleDuplicateCourse: handleDuplicateCourse,
|
|
139
|
-
cardTitleComponent: "h2"
|
|
140
|
+
cardTitleComponent: "h2",
|
|
141
|
+
email: email
|
|
140
142
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Box, {
|
|
141
143
|
py: 2,
|
|
142
144
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Courses2.default, {
|
|
@@ -701,7 +701,8 @@ function Course({
|
|
|
701
701
|
onSubmit: handleUpdateCourse,
|
|
702
702
|
fileSizeLimit: fileSizeLimit,
|
|
703
703
|
subscription: subscription,
|
|
704
|
-
verificationStatus: verificationStatus
|
|
704
|
+
verificationStatus: verificationStatus,
|
|
705
|
+
attributes: attributes
|
|
705
706
|
})
|
|
706
707
|
}, `tab-content-settings`)
|
|
707
708
|
}] : [])];
|