@selfcommunity/react-ui 0.10.2-courses.192 → 0.10.2-courses.193
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/lib/cjs/components/EditCourse/Requests.js +3 -3
- package/lib/cjs/components/EditCourse/Users.js +14 -4
- package/lib/cjs/components/Notification/Course/Course.d.ts +15 -0
- package/lib/cjs/components/Notification/Course/Course.js +75 -0
- package/lib/cjs/components/Notification/Course/index.d.ts +3 -0
- package/lib/cjs/components/Notification/Course/index.js +5 -0
- package/lib/cjs/components/Notification/Notification.js +8 -0
- package/lib/cjs/components/SnippetNotifications/SnippetNotifications.js +8 -0
- package/lib/cjs/components/ToastNotifications/ToastNotifications.js +8 -0
- package/lib/cjs/constants/PubSub.d.ts +3 -1
- package/lib/cjs/constants/PubSub.js +2 -0
- package/lib/cjs/shared/CourseUsersTable/CourseUsersTable.js +24 -3
- package/lib/cjs/shared/CourseUsersTable/RemoveButton.d.ts +10 -0
- package/lib/cjs/shared/CourseUsersTable/RemoveButton.js +51 -0
- package/lib/cjs/shared/CourseUsersTable/RequestButton.d.ts +3 -2
- package/lib/cjs/shared/CourseUsersTable/RequestButton.js +14 -10
- package/lib/cjs/types/course.d.ts +9 -0
- package/lib/esm/components/EditCourse/Requests.js +4 -4
- package/lib/esm/components/EditCourse/Users.js +15 -5
- package/lib/esm/components/Notification/Course/Course.d.ts +15 -0
- package/lib/esm/components/Notification/Course/Course.js +72 -0
- package/lib/esm/components/Notification/Course/index.d.ts +3 -0
- package/lib/esm/components/Notification/Course/index.js +2 -0
- package/lib/esm/components/Notification/Notification.js +8 -0
- package/lib/esm/components/SnippetNotifications/SnippetNotifications.js +8 -0
- package/lib/esm/components/ToastNotifications/ToastNotifications.js +8 -0
- package/lib/esm/constants/PubSub.d.ts +3 -1
- package/lib/esm/constants/PubSub.js +2 -0
- package/lib/esm/shared/CourseUsersTable/CourseUsersTable.js +25 -4
- package/lib/esm/shared/CourseUsersTable/RemoveButton.d.ts +10 -0
- package/lib/esm/shared/CourseUsersTable/RemoveButton.js +48 -0
- package/lib/esm/shared/CourseUsersTable/RequestButton.d.ts +3 -2
- package/lib/esm/shared/CourseUsersTable/RequestButton.js +16 -12
- package/lib/esm/types/course.d.ts +9 -0
- package/lib/umd/react-ui.js +1 -1
- package/package.json +8 -8
|
@@ -67,7 +67,7 @@ function Requests(props) {
|
|
|
67
67
|
}
|
|
68
68
|
}, [state.isLoadingNext, state.initialized, course, dispatch, endpointQueryParams]);
|
|
69
69
|
// HANDLERS
|
|
70
|
-
const
|
|
70
|
+
const handleRejectUser = (0, react_1.useCallback)((_msg, user) => {
|
|
71
71
|
dispatch({
|
|
72
72
|
type: widget_1.actionWidgetTypes.SET_RESULTS,
|
|
73
73
|
payload: { count: state.results.length - 1, results: state.results.filter((result) => result.id !== user.id) }
|
|
@@ -84,11 +84,11 @@ function Requests(props) {
|
|
|
84
84
|
}
|
|
85
85
|
}, [scUserContext.user, _init]);
|
|
86
86
|
(0, react_1.useEffect)(() => {
|
|
87
|
-
updatedUsers.current = pubsub_js_1.default.subscribe(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.
|
|
87
|
+
updatedUsers.current = pubsub_js_1.default.subscribe(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.SCCourseEventType.REJECT_MEMBER}`, handleRejectUser);
|
|
88
88
|
return () => {
|
|
89
89
|
updatedUsers.current && pubsub_js_1.default.unsubscribe(updatedUsers.current);
|
|
90
90
|
};
|
|
91
|
-
}, [
|
|
91
|
+
}, [handleRejectUser]);
|
|
92
92
|
return ((0, jsx_runtime_1.jsxs)(material_1.Box, { children: [(0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "h6", className: classes.contrastColor }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.editCourse.tab.requests.title", defaultMessage: "ui.editCourse.tab.requests.title", values: { requestsNumber: state.results.length } }) })), (0, jsx_runtime_1.jsx)(material_1.Stack, Object.assign({ className: classes.usersStatusWrapper }, { children: (0, jsx_runtime_1.jsx)(Status_1.default, { course: course, handleTabChange: handleTabChange }) })), (0, jsx_runtime_1.jsx)(CourseUsersTable_1.default, { course: course, state: state, dispatch: dispatch, headerCells: headerCells, mode: course_1.SCCourseUsersTableModeType.REQUESTS, emptyStatusTitle: "ui.courseUsersTable.empty.requests.title" })] }));
|
|
93
93
|
}
|
|
94
94
|
exports.default = (0, react_1.memo)(Requests);
|
|
@@ -35,7 +35,8 @@ const headerCells = [
|
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
id: 'ui.editCourse.tab.users.table.header.latestActivity'
|
|
38
|
-
}
|
|
38
|
+
},
|
|
39
|
+
{}
|
|
39
40
|
];
|
|
40
41
|
function Users(props) {
|
|
41
42
|
// PROPS
|
|
@@ -58,6 +59,7 @@ function Users(props) {
|
|
|
58
59
|
const { enqueueSnackbar } = (0, notistack_1.useSnackbar)();
|
|
59
60
|
// REFS
|
|
60
61
|
const updatedUsers = (0, react_1.useRef)(null);
|
|
62
|
+
const removedUsers = (0, react_1.useRef)(null);
|
|
61
63
|
// CALLBACKS
|
|
62
64
|
const _init = (0, react_1.useCallback)(() => {
|
|
63
65
|
if (!state.initialized && !state.isLoadingNext) {
|
|
@@ -76,6 +78,12 @@ function Users(props) {
|
|
|
76
78
|
const handleAddUser = (0, react_1.useCallback)((_msg, user) => {
|
|
77
79
|
dispatch({ type: widget_1.actionWidgetTypes.LOAD_PREVIOUS_SUCCESS, payload: { count: state.count + 1, results: [user], initialized: true } });
|
|
78
80
|
}, [state.count, dispatch]);
|
|
81
|
+
const handleRemoveUser = (0, react_1.useCallback)((_msg, user) => {
|
|
82
|
+
dispatch({
|
|
83
|
+
type: widget_1.actionWidgetTypes.SET_RESULTS,
|
|
84
|
+
payload: { count: state.count - 1, results: state.results.filter((result) => result.id !== user.id), initialized: true }
|
|
85
|
+
});
|
|
86
|
+
}, [state.count, state.results, dispatch]);
|
|
79
87
|
// EFFECTS
|
|
80
88
|
(0, react_1.useEffect)(() => {
|
|
81
89
|
let _t;
|
|
@@ -87,11 +95,13 @@ function Users(props) {
|
|
|
87
95
|
}
|
|
88
96
|
}, [scUserContext.user, _init]);
|
|
89
97
|
(0, react_1.useEffect)(() => {
|
|
90
|
-
updatedUsers.current = pubsub_js_1.default.subscribe(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.
|
|
98
|
+
updatedUsers.current = pubsub_js_1.default.subscribe(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.SCCourseEventType.ADD_MEMBER}`, handleAddUser);
|
|
99
|
+
removedUsers.current = pubsub_js_1.default.subscribe(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.SCCourseEventType.REMOVE_MEMBER}`, handleRemoveUser);
|
|
91
100
|
return () => {
|
|
92
101
|
updatedUsers.current && pubsub_js_1.default.unsubscribe(updatedUsers.current);
|
|
102
|
+
removedUsers.current && pubsub_js_1.default.unsubscribe(removedUsers.current);
|
|
93
103
|
};
|
|
94
|
-
}, [handleAddUser]);
|
|
104
|
+
}, [handleAddUser, handleRemoveUser]);
|
|
95
105
|
const handleConfirm = (0, react_1.useCallback)((newUsers) => {
|
|
96
106
|
const data = {
|
|
97
107
|
joined: newUsers.map((user) => user.id)
|
|
@@ -116,7 +126,7 @@ function Users(props) {
|
|
|
116
126
|
});
|
|
117
127
|
});
|
|
118
128
|
}, [course, dispatch]);
|
|
119
|
-
return ((0, jsx_runtime_1.jsxs)(material_1.Box, { children: [(0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "h6", className: classes.contrastColor }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.editCourse.tab.users.title", defaultMessage: "ui.editCourse.tab.users.title", values: { usersNumber: state.
|
|
129
|
+
return ((0, jsx_runtime_1.jsxs)(material_1.Box, { children: [(0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "h6", className: classes.contrastColor }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.editCourse.tab.users.title", defaultMessage: "ui.editCourse.tab.users.title", values: { usersNumber: state.count } }) })), (0, jsx_runtime_1.jsxs)(material_1.Stack, Object.assign({ className: classes.usersStatusWrapper }, { children: [(0, jsx_runtime_1.jsx)(Status_1.default, { course: course, handleTabChange: handleTabChange }), (0, jsx_runtime_1.jsx)(AddUsersButton_1.default, { label: "ui.editCourse.tab.users.addUsersButton.label", endpoint: {
|
|
120
130
|
url: () => api_services_1.Endpoints.GetCourseSuggestedUsers.url({ id: course.id }),
|
|
121
131
|
method: api_services_1.Endpoints.GetCourseSuggestedUsers.method
|
|
122
132
|
}, onConfirm: handleConfirm })] })), (0, jsx_runtime_1.jsx)(CourseUsersTable_1.default, { course: course, state: state, dispatch: dispatch, headerCells: headerCells, mode: course_1.SCCourseUsersTableModeType.EDIT, emptyStatusTitle: "ui.courseUsersTable.empty.users.title", emptyStatusDescription: "ui.courseUsersTable.empty.users.description" })] }));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SCNotificationCourseActivityType } from '@selfcommunity/types';
|
|
2
|
+
import { NotificationItemProps } from '../../../shared/NotificationItem';
|
|
3
|
+
export interface NotificationCourseProps extends Pick<NotificationItemProps, Exclude<keyof NotificationItemProps, 'image' | 'disableTypography' | 'primary' | 'primaryTypographyProps' | 'secondary' | 'secondaryTypographyProps' | 'actions' | 'footer' | 'isNew'>> {
|
|
4
|
+
/**
|
|
5
|
+
* Notification obj
|
|
6
|
+
* @default null
|
|
7
|
+
*/
|
|
8
|
+
notificationObject: SCNotificationCourseActivityType;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* This component render the content of the notification of type course
|
|
12
|
+
* @constructor
|
|
13
|
+
* @param props
|
|
14
|
+
*/
|
|
15
|
+
export default function CourseNotification(props: NotificationCourseProps): JSX.Element;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const styles_1 = require("@mui/material/styles");
|
|
7
|
+
const material_1 = require("@mui/material");
|
|
8
|
+
const react_core_1 = require("@selfcommunity/react-core");
|
|
9
|
+
const react_intl_1 = require("react-intl");
|
|
10
|
+
const DateTimeAgo_1 = tslib_1.__importDefault(require("../../../shared/DateTimeAgo"));
|
|
11
|
+
const classnames_1 = tslib_1.__importDefault(require("classnames"));
|
|
12
|
+
const types_1 = require("../../../types");
|
|
13
|
+
const NotificationItem_1 = tslib_1.__importDefault(require("../../../shared/NotificationItem"));
|
|
14
|
+
const lab_1 = require("@mui/lab");
|
|
15
|
+
const UserDeletedSnackBar_1 = tslib_1.__importDefault(require("../../../shared/UserDeletedSnackBar"));
|
|
16
|
+
const UserAvatar_1 = tslib_1.__importDefault(require("../../../shared/UserAvatar"));
|
|
17
|
+
const constants_1 = require("../constants");
|
|
18
|
+
const Course_1 = tslib_1.__importDefault(require("../../Course"));
|
|
19
|
+
const HiddenPlaceholder_1 = tslib_1.__importDefault(require("../../../shared/HiddenPlaceholder"));
|
|
20
|
+
const classes = {
|
|
21
|
+
root: `${constants_1.PREFIX}-course-root`,
|
|
22
|
+
avatar: `${constants_1.PREFIX}-avatar`,
|
|
23
|
+
actions: `${constants_1.PREFIX}-actions`,
|
|
24
|
+
seeButton: `${constants_1.PREFIX}see-button`,
|
|
25
|
+
activeAt: `${constants_1.PREFIX}-active-at`,
|
|
26
|
+
snippetTime: `${constants_1.PREFIX}-snippet-time`,
|
|
27
|
+
username: `${constants_1.PREFIX}-username`
|
|
28
|
+
};
|
|
29
|
+
const Root = (0, styles_1.styled)(NotificationItem_1.default, {
|
|
30
|
+
name: constants_1.PREFIX,
|
|
31
|
+
slot: 'CourseRoot'
|
|
32
|
+
})(() => ({}));
|
|
33
|
+
/**
|
|
34
|
+
* This component render the content of the notification of type course
|
|
35
|
+
* @constructor
|
|
36
|
+
* @param props
|
|
37
|
+
*/
|
|
38
|
+
function CourseNotification(props) {
|
|
39
|
+
// PROPS
|
|
40
|
+
const { notificationObject, id = `n_${props.notificationObject['sid']}`, className, template = types_1.SCNotificationObjectTemplateType.DETAIL } = props, rest = tslib_1.__rest(props, ["notificationObject", "id", "className", "template"]);
|
|
41
|
+
// CONTEXT
|
|
42
|
+
const scRoutingContext = (0, react_core_1.useSCRouting)();
|
|
43
|
+
// STATE
|
|
44
|
+
const [openAlert, setOpenAlert] = (0, react_1.useState)(false);
|
|
45
|
+
// CONST
|
|
46
|
+
const isSnippetTemplate = template === types_1.SCNotificationObjectTemplateType.SNIPPET;
|
|
47
|
+
const isToastTemplate = template === types_1.SCNotificationObjectTemplateType.TOAST;
|
|
48
|
+
if (!notificationObject.course) {
|
|
49
|
+
return (0, jsx_runtime_1.jsx)(HiddenPlaceholder_1.default, {});
|
|
50
|
+
}
|
|
51
|
+
// RENDER
|
|
52
|
+
if (isSnippetTemplate || isToastTemplate) {
|
|
53
|
+
return ((0, jsx_runtime_1.jsx)(Root, Object.assign({ id: id, className: (0, classnames_1.default)(classes.root, className, `${constants_1.PREFIX}-${template}`), template: template, isNew: notificationObject.is_new, disableTypography: true, image: (0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({}, (!notificationObject.course.created_by.deleted && {
|
|
54
|
+
to: scRoutingContext.url(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, notificationObject.course.created_by)
|
|
55
|
+
}), { onClick: notificationObject.course.created_by.deleted ? () => setOpenAlert(true) : null }, { children: (0, jsx_runtime_1.jsx)(UserAvatar_1.default, Object.assign({ hide: !notificationObject.course.created_by.community_badge, smaller: true }, { children: (0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: notificationObject.course.created_by.username, variant: "circular", src: notificationObject.course.created_by.avatar, classes: { root: classes.avatar } }) })) })), primary: (0, jsx_runtime_1.jsxs)(material_1.Box, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({}, (!notificationObject.course.created_by.deleted && {
|
|
56
|
+
to: scRoutingContext.url(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, notificationObject.course.created_by)
|
|
57
|
+
}), { onClick: notificationObject.course.created_by.deleted ? () => setOpenAlert(true) : null, className: classes.username }, { children: notificationObject.course.created_by.username })), ' ', (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: `ui.notification.course.${notificationObject.type}`, defaultMessage: `ui.notification.course.${notificationObject.type}`, values: {
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
|
59
|
+
// @ts-ignore
|
|
60
|
+
course: notificationObject.course.name,
|
|
61
|
+
link: (...chunks) => (0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({ to: scRoutingContext.url(react_core_1.SCRoutes.COURSE_ROUTE_NAME, notificationObject.course) }, { children: chunks }))
|
|
62
|
+
} })] }), footer: isToastTemplate ? ((0, jsx_runtime_1.jsxs)(material_1.Stack, Object.assign({ direction: "row", justifyContent: "space-between", alignItems: "center", spacing: 2 }, { children: [(0, jsx_runtime_1.jsx)(DateTimeAgo_1.default, { date: notificationObject.active_at }), (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ color: "primary" }, { children: (0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({ to: scRoutingContext.url(react_core_1.SCRoutes.COURSE_ROUTE_NAME, notificationObject.course) }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.notification.course.button.see", defaultMessage: "ui.notification.course.button.see" }) })) }))] }))) : ((0, jsx_runtime_1.jsx)(DateTimeAgo_1.default, { date: notificationObject.active_at, className: classes.snippetTime })) }, rest)));
|
|
63
|
+
}
|
|
64
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Root, Object.assign({ id: id, className: (0, classnames_1.default)(classes.root, className, `${constants_1.PREFIX}-${template}`), template: template, isNew: notificationObject.is_new, disableTypography: true, image: (0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({}, (!notificationObject.course.created_by.deleted && {
|
|
65
|
+
to: scRoutingContext.url(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, notificationObject.course.created_by)
|
|
66
|
+
}), { onClick: notificationObject.course.created_by.deleted ? () => setOpenAlert(true) : null }, { children: (0, jsx_runtime_1.jsx)(UserAvatar_1.default, Object.assign({ hide: !notificationObject.course.created_by.community_badge, smaller: true }, { children: (0, jsx_runtime_1.jsx)(material_1.Avatar, { className: classes.avatar, alt: notificationObject.course.created_by.username, variant: "circular", src: notificationObject.course.created_by.avatar }) })) })), primary: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({}, (!notificationObject.course.created_by.deleted && {
|
|
67
|
+
to: scRoutingContext.url(react_core_1.SCRoutes.USER_PROFILE_ROUTE_NAME, notificationObject.course.created_by)
|
|
68
|
+
}), { onClick: notificationObject.course.created_by.deleted ? () => setOpenAlert(true) : null, className: classes.username }, { children: notificationObject.course.created_by.username })), ' ', (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: `ui.notification.course.${notificationObject.type}`, defaultMessage: `ui.notification.course.${notificationObject.type}`, values: {
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
course: notificationObject.course.name,
|
|
72
|
+
link: (...chunks) => (0, jsx_runtime_1.jsx)(react_core_1.Link, Object.assign({ to: scRoutingContext.url(react_core_1.SCRoutes.COURSE_ROUTE_NAME, notificationObject.course) }, { children: chunks }))
|
|
73
|
+
} }), (0, jsx_runtime_1.jsx)(Course_1.default, { course: notificationObject.course, actions: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {}), template: types_1.SCCourseTemplateType.SNIPPET, elevation: 0 })] }), actions: (0, jsx_runtime_1.jsxs)(material_1.Stack, Object.assign({ direction: "row", justifyContent: "space-between", alignItems: "center", spacing: 2 }, { children: [(0, jsx_runtime_1.jsx)(DateTimeAgo_1.default, { date: notificationObject.active_at, className: classes.activeAt }), (0, jsx_runtime_1.jsx)(lab_1.LoadingButton, Object.assign({ color: 'primary', variant: "outlined", size: "small", classes: { root: classes.seeButton }, component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.COURSE_ROUTE_NAME, notificationObject.course) }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.notification.course.button.see", defaultMessage: "ui.notification.course.button.see" }) }))] })) }, rest)), openAlert && (0, jsx_runtime_1.jsx)(UserDeletedSnackBar_1.default, { open: openAlert, handleClose: () => setOpenAlert(false) })] }));
|
|
74
|
+
}
|
|
75
|
+
exports.default = CourseNotification;
|
|
@@ -39,6 +39,7 @@ const UserDeletedSnackBar_1 = tslib_1.__importDefault(require("../../shared/User
|
|
|
39
39
|
const UserAvatar_1 = tslib_1.__importDefault(require("../../shared/UserAvatar"));
|
|
40
40
|
const constants_1 = require("./constants");
|
|
41
41
|
const Group_1 = tslib_1.__importDefault(require("./Group"));
|
|
42
|
+
const Course_1 = tslib_1.__importDefault(require("./Course"));
|
|
42
43
|
const messages = (0, react_intl_1.defineMessages)({
|
|
43
44
|
receivePrivateMessage: {
|
|
44
45
|
id: 'ui.notification.receivePrivateMessage',
|
|
@@ -309,6 +310,13 @@ function UserNotification(inProps) {
|
|
|
309
310
|
n.type === types_1.SCNotificationTypologyType.USER_REQUESTED_TO_JOIN_EVENT) {
|
|
310
311
|
return (0, jsx_runtime_1.jsx)(Event_1.default, { notificationObject: n }, i);
|
|
311
312
|
}
|
|
313
|
+
else if (n.type === types_1.SCNotificationTypologyType.USER_ADDED_TO_COURSE ||
|
|
314
|
+
n.type === types_1.SCNotificationTypologyType.USER_COMMENTED_A_COURSE_LESSON ||
|
|
315
|
+
n.type === types_1.SCNotificationTypologyType.USER_INVITED_TO_JOIN_COURSE ||
|
|
316
|
+
n.type === types_1.SCNotificationTypologyType.USER_ACCEPTED_TO_JOIN_COURSE ||
|
|
317
|
+
n.type === types_1.SCNotificationTypologyType.USER_REQUESTED_TO_JOIN_COURSE) {
|
|
318
|
+
return (0, jsx_runtime_1.jsx)(Course_1.default, { notificationObject: n }, i);
|
|
319
|
+
}
|
|
312
320
|
else if (n.type === types_1.SCNotificationTypologyType.LIVE_STREAM_STARTED) {
|
|
313
321
|
return (0, jsx_runtime_1.jsx)(LiveStream_1.default, { notificationObject: n }, i);
|
|
314
322
|
}
|
|
@@ -37,6 +37,7 @@ const constants_1 = require("./constants");
|
|
|
37
37
|
const Group_1 = tslib_1.__importDefault(require("../Notification/Group"));
|
|
38
38
|
const Event_1 = tslib_1.__importDefault(require("../Notification/Event/Event"));
|
|
39
39
|
const LiveStream_1 = tslib_1.__importDefault(require("../Notification/LiveStream"));
|
|
40
|
+
const Course_1 = tslib_1.__importDefault(require("../Notification/Course"));
|
|
40
41
|
const classes = {
|
|
41
42
|
root: `${constants_1.PREFIX}-root`,
|
|
42
43
|
notificationsWrap: `${constants_1.PREFIX}-notifications-wrap`,
|
|
@@ -270,6 +271,13 @@ function SnippetNotifications(inProps) {
|
|
|
270
271
|
n.type === types_2.SCNotificationTypologyType.USER_REQUESTED_TO_JOIN_EVENT) {
|
|
271
272
|
return (0, jsx_runtime_1.jsx)(Event_1.default, { notificationObject: n, template: types_1.SCNotificationObjectTemplateType.SNIPPET }, i);
|
|
272
273
|
}
|
|
274
|
+
else if (n.type === types_2.SCNotificationTypologyType.USER_ADDED_TO_COURSE ||
|
|
275
|
+
n.type === types_2.SCNotificationTypologyType.USER_COMMENTED_A_COURSE_LESSON ||
|
|
276
|
+
n.type === types_2.SCNotificationTypologyType.USER_INVITED_TO_JOIN_COURSE ||
|
|
277
|
+
n.type === types_2.SCNotificationTypologyType.USER_ACCEPTED_TO_JOIN_COURSE ||
|
|
278
|
+
n.type === types_2.SCNotificationTypologyType.USER_REQUESTED_TO_JOIN_COURSE) {
|
|
279
|
+
return (0, jsx_runtime_1.jsx)(Course_1.default, { notificationObject: n, template: types_1.SCNotificationObjectTemplateType.SNIPPET }, i);
|
|
280
|
+
}
|
|
273
281
|
else if (type === types_2.SCNotificationTypologyType.LIVE_STREAM_STARTED) {
|
|
274
282
|
content = (0, jsx_runtime_1.jsx)(LiveStream_1.default, { notificationObject: n, template: types_1.SCNotificationObjectTemplateType.SNIPPET }, i);
|
|
275
283
|
}
|
|
@@ -28,6 +28,7 @@ const Contribution_1 = tslib_1.__importDefault(require("../Notification/Contribu
|
|
|
28
28
|
const Group_1 = tslib_1.__importDefault(require("../Notification/Group"));
|
|
29
29
|
const Event_1 = tslib_1.__importDefault(require("../Notification/Event/Event"));
|
|
30
30
|
const LiveStream_1 = tslib_1.__importDefault(require("../Notification/LiveStream"));
|
|
31
|
+
const Course_1 = tslib_1.__importDefault(require("../Notification/Course"));
|
|
31
32
|
const Root = (0, styles_1.styled)(material_1.Box, {
|
|
32
33
|
name: constants_1.PREFIX,
|
|
33
34
|
slot: 'Root'
|
|
@@ -127,6 +128,13 @@ function UserToastNotifications(inProps) {
|
|
|
127
128
|
type === types_1.SCNotificationTypologyType.USER_REQUESTED_TO_JOIN_EVENT) {
|
|
128
129
|
content = (0, jsx_runtime_1.jsx)(Event_1.default, { notificationObject: n.notification_obj, template: types_2.SCNotificationObjectTemplateType.TOAST });
|
|
129
130
|
}
|
|
131
|
+
else if (type === types_1.SCNotificationTypologyType.USER_ADDED_TO_COURSE ||
|
|
132
|
+
n.type === types_1.SCNotificationTypologyType.USER_COMMENTED_A_COURSE_LESSON ||
|
|
133
|
+
type === types_1.SCNotificationTypologyType.USER_INVITED_TO_JOIN_COURSE ||
|
|
134
|
+
type === types_1.SCNotificationTypologyType.USER_ACCEPTED_TO_JOIN_COURSE ||
|
|
135
|
+
type === types_1.SCNotificationTypologyType.USER_REQUESTED_TO_JOIN_COURSE) {
|
|
136
|
+
content = (0, jsx_runtime_1.jsx)(Course_1.default, { notificationObject: n.notification_obj, template: types_2.SCNotificationObjectTemplateType.TOAST });
|
|
137
|
+
}
|
|
130
138
|
else if (type === types_1.SCNotificationTypologyType.LIVE_STREAM_STARTED) {
|
|
131
139
|
content = (0, jsx_runtime_1.jsx)(LiveStream_1.default, { notificationObject: n.notification_obj, template: types_2.SCNotificationObjectTemplateType.TOAST });
|
|
132
140
|
}
|
|
@@ -29,7 +29,9 @@ export declare enum SCCourseEventType {
|
|
|
29
29
|
EDIT = "edit",
|
|
30
30
|
DELETE = "delete",
|
|
31
31
|
ADD_MEMBER = "members.add_member",
|
|
32
|
-
INVITE_MEMBER = "members.invite_member"
|
|
32
|
+
INVITE_MEMBER = "members.invite_member",
|
|
33
|
+
REMOVE_MEMBER = "members.remove_member",
|
|
34
|
+
REJECT_MEMBER = "members.reject_member"
|
|
33
35
|
}
|
|
34
36
|
/**
|
|
35
37
|
* Category event types
|
|
@@ -35,6 +35,8 @@ var SCCourseEventType;
|
|
|
35
35
|
SCCourseEventType["DELETE"] = "delete";
|
|
36
36
|
SCCourseEventType["ADD_MEMBER"] = "members.add_member";
|
|
37
37
|
SCCourseEventType["INVITE_MEMBER"] = "members.invite_member";
|
|
38
|
+
SCCourseEventType["REMOVE_MEMBER"] = "members.remove_member";
|
|
39
|
+
SCCourseEventType["REJECT_MEMBER"] = "members.reject_member";
|
|
38
40
|
})(SCCourseEventType = exports.SCCourseEventType || (exports.SCCourseEventType = {}));
|
|
39
41
|
/**
|
|
40
42
|
* Category event types
|
|
@@ -20,6 +20,9 @@ const ChangeUsersStatus_1 = tslib_1.__importDefault(require("./ChangeUsersStatus
|
|
|
20
20
|
const react_core_1 = require("@selfcommunity/react-core");
|
|
21
21
|
const RequestButton_1 = tslib_1.__importDefault(require("./RequestButton"));
|
|
22
22
|
const course_1 = require("../../types/course");
|
|
23
|
+
const RemoveButton_1 = tslib_1.__importDefault(require("./RemoveButton"));
|
|
24
|
+
const ConfirmDialog_1 = tslib_1.__importDefault(require("../ConfirmDialog/ConfirmDialog"));
|
|
25
|
+
const course_2 = require("../../types/course");
|
|
23
26
|
const classes = {
|
|
24
27
|
root: `${constants_1.PREFIX}-root`,
|
|
25
28
|
search: `${constants_1.PREFIX}-search`,
|
|
@@ -34,7 +37,7 @@ const Root = (0, material_1.styled)(material_1.Box, {
|
|
|
34
37
|
overridesResolver: (_props, styles) => styles.root
|
|
35
38
|
})(() => ({}));
|
|
36
39
|
function filteredUsers(users, value) {
|
|
37
|
-
return users.filter((user) => (user.username || user.real_name).includes(value));
|
|
40
|
+
return users.filter((user) => (user.username || user.real_name).toLowerCase().includes(value.toLowerCase()));
|
|
38
41
|
}
|
|
39
42
|
function CourseUsersTable(inProps) {
|
|
40
43
|
// PROPS
|
|
@@ -47,6 +50,9 @@ function CourseUsersTable(inProps) {
|
|
|
47
50
|
const [users, setUsers] = (0, react_1.useState)(null);
|
|
48
51
|
const [tempUsers, setTempUsers] = (0, react_1.useState)(null);
|
|
49
52
|
const [value, setValue] = (0, react_1.useState)('');
|
|
53
|
+
const [dialog, setDialog] = (0, react_1.useState)(null);
|
|
54
|
+
// REFS
|
|
55
|
+
const ref = (0, react_1.useRef)(null);
|
|
50
56
|
// CONTEXTS
|
|
51
57
|
const scUserContext = (0, react_core_1.useSCUser)();
|
|
52
58
|
// HOOKS
|
|
@@ -88,6 +94,19 @@ function CourseUsersTable(inProps) {
|
|
|
88
94
|
utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error);
|
|
89
95
|
});
|
|
90
96
|
}, [state.next, dispatch]);
|
|
97
|
+
const handleOpenDialog = (0, react_1.useCallback)((tab) => {
|
|
98
|
+
setDialog(tab);
|
|
99
|
+
}, [setDialog]);
|
|
100
|
+
const handleConfirm = (0, react_1.useCallback)(() => {
|
|
101
|
+
switch (dialog.tab) {
|
|
102
|
+
case course_2.SCCourseEditTabType.USERS:
|
|
103
|
+
ref.current.handleManageUser(dialog.user);
|
|
104
|
+
break;
|
|
105
|
+
case course_2.SCCourseEditTabType.REQUESTS:
|
|
106
|
+
ref.current.handleManageUser(dialog.request);
|
|
107
|
+
}
|
|
108
|
+
handleOpenDialog(null);
|
|
109
|
+
}, [dialog, handleOpenDialog]);
|
|
91
110
|
if (!users) {
|
|
92
111
|
return (0, jsx_runtime_1.jsx)(Skeleton_1.default, {});
|
|
93
112
|
}
|
|
@@ -97,11 +116,13 @@ function CourseUsersTable(inProps) {
|
|
|
97
116
|
}), InputProps: {
|
|
98
117
|
startAdornment: ((0, jsx_runtime_1.jsx)(material_1.InputAdornment, Object.assign({ position: "start" }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "search" }) })))
|
|
99
118
|
}, value: value, onChange: handleChange, disabled: users.length === 0 && value.length === 0, fullWidth: true, className: classes.search }), (0, jsx_runtime_1.jsx)(material_1.TableContainer, { children: (0, jsx_runtime_1.jsxs)(material_1.Table, { children: [(0, jsx_runtime_1.jsx)(material_1.TableHead, { children: (0, jsx_runtime_1.jsx)(material_1.TableRow, { children: headerCells.map((cell, i, array) => {
|
|
100
|
-
if (
|
|
119
|
+
if (i === array.length - 1) {
|
|
101
120
|
return (0, jsx_runtime_1.jsx)(material_1.TableCell, { width: "14%" }, i);
|
|
102
121
|
}
|
|
103
122
|
return ((0, jsx_runtime_1.jsx)(material_1.TableCell, Object.assign({ width: mode === course_1.SCCourseUsersTableModeType.DASHBOARD ? '20%' : '25%' }, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2" }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: cell.id, defaultMessage: cell.id }) })) }), i));
|
|
104
123
|
}) }) }), (0, jsx_runtime_1.jsxs)(material_1.TableBody, { children: [users.length > 0 &&
|
|
105
|
-
users.map((user, i) => ((0, jsx_runtime_1.jsxs)(material_1.TableRow, { children: [(0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsxs)(material_1.Stack, Object.assign({ className: classes.avatarWrapper }, { children: [(0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: user.username, src: user.avatar }), (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2" }, { children: user.username }))] })) }), mode === course_1.SCCourseUsersTableModeType.DASHBOARD && ((0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsxs)(material_1.Stack, Object.assign({ className: classes.progressWrapper }, { children: [(0, jsx_runtime_1.jsx)(material_1.LinearProgress, { className: classes.progress, variant: "determinate", value: user.user_completion_rate }), (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body1" }, { children: `${Math.round(user.user_completion_rate)}%` }))] })) })), mode === course_1.SCCourseUsersTableModeType.EDIT && ((0, jsx_runtime_1.jsx)(material_1.TableCell, { children: user.join_status !== types_1.SCCourseJoinStatusType.CREATOR && scUserContext.user.id !== user.id ? ((0, jsx_runtime_1.jsx)(ChangeUsersStatus_1.default, { course: course, user: user })) : ((0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2" }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: `ui.editCourse.tab.users.table.select.${user.join_status}`, defaultMessage: `ui.editCourse.tab.users.table.select.${user.join_status}` }) }))) })), (0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2" }, { children: new Date(mode === course_1.SCCourseUsersTableModeType.REQUESTS ? user.date_joined : user.joined_at || new Date()).toLocaleDateString() })) }), (0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2" }, { children: new Date(mode === course_1.SCCourseUsersTableModeType.REQUESTS ? user.date_joined : user.last_active_at || new Date()).toLocaleDateString() })) }), mode === course_1.SCCourseUsersTableModeType.
|
|
124
|
+
users.map((user, i) => ((0, jsx_runtime_1.jsxs)(material_1.TableRow, { children: [(0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsxs)(material_1.Stack, Object.assign({ className: classes.avatarWrapper }, { children: [(0, jsx_runtime_1.jsx)(material_1.Avatar, { alt: user.username, src: user.avatar }), (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2" }, { children: user.username }))] })) }), mode === course_1.SCCourseUsersTableModeType.DASHBOARD && ((0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsxs)(material_1.Stack, Object.assign({ className: classes.progressWrapper }, { children: [(0, jsx_runtime_1.jsx)(material_1.LinearProgress, { className: classes.progress, variant: "determinate", value: user.user_completion_rate }), (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body1" }, { children: `${Math.round(user.user_completion_rate)}%` }))] })) })), mode === course_1.SCCourseUsersTableModeType.EDIT && ((0, jsx_runtime_1.jsx)(material_1.TableCell, { children: user.join_status !== types_1.SCCourseJoinStatusType.CREATOR && scUserContext.user.id !== user.id ? ((0, jsx_runtime_1.jsx)(ChangeUsersStatus_1.default, { course: course, user: user })) : ((0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2" }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: `ui.editCourse.tab.users.table.select.${user.join_status}`, defaultMessage: `ui.editCourse.tab.users.table.select.${user.join_status}` }) }))) })), (0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2" }, { children: new Date(mode === course_1.SCCourseUsersTableModeType.REQUESTS ? user.date_joined : user.joined_at || new Date()).toLocaleDateString() })) }), (0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2" }, { children: new Date(mode === course_1.SCCourseUsersTableModeType.REQUESTS ? user.date_joined : user.last_active_at || new Date()).toLocaleDateString() })) }), mode === course_1.SCCourseUsersTableModeType.EDIT &&
|
|
125
|
+
user.join_status !== types_1.SCCourseJoinStatusType.CREATOR &&
|
|
126
|
+
scUserContext.user.id !== user.id ? ((0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsx)(RemoveButton_1.default, { ref: ref, course: course, user: user, handleOpenDialog: handleOpenDialog }) })) : (mode === course_1.SCCourseUsersTableModeType.EDIT && (0, jsx_runtime_1.jsx)(material_1.TableCell, {})), mode === course_1.SCCourseUsersTableModeType.DASHBOARD && ((0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsx)(SeeProgressButton_1.default, { course: course, user: user }) })), mode === course_1.SCCourseUsersTableModeType.REQUESTS && ((0, jsx_runtime_1.jsx)(material_1.TableCell, { children: (0, jsx_runtime_1.jsx)(RequestButton_1.default, { ref: ref, course: course, user: user, handleOpenDialog: handleOpenDialog }) }))] }, i))), state.isLoadingNext && (0, jsx_runtime_1.jsx)(RowSkeleton_1.default, { editMode: mode !== course_1.SCCourseUsersTableModeType.DASHBOARD })] })] }) }), users.length > 0 && ((0, jsx_runtime_1.jsx)(lab_1.LoadingButton, Object.assign({ size: "small", variant: "outlined", color: "inherit", loading: state.isLoadingNext, disabled: !state.next, className: classes.loadingButton, onClick: handleNext }, { children: (0, jsx_runtime_1.jsx)(material_1.Typography, Object.assign({ variant: "body2" }, { children: (0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.courseUsersTable.btn.label", defaultMessage: "ui.courseUsersTable.btn.label" }) })) }))), users.length === 0 && value.length === 0 && (0, jsx_runtime_1.jsx)(EmptyStatus_1.default, { icon: "face", title: emptyStatusTitle, description: emptyStatusDescription }), dialog && (0, jsx_runtime_1.jsx)(ConfirmDialog_1.default, { open: true, onClose: () => handleOpenDialog(null), onConfirm: handleConfirm })] })));
|
|
106
127
|
}
|
|
107
128
|
exports.default = (0, react_1.memo)(CourseUsersTable);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { SCCourseType, SCUserType } from '@selfcommunity/types';
|
|
3
|
+
import { SCCourseEditManageUserProps, SCCourseEditManageUserRef } from '../../types/course';
|
|
4
|
+
interface RemoveButtonProps {
|
|
5
|
+
course: SCCourseType;
|
|
6
|
+
user: SCUserType;
|
|
7
|
+
handleOpenDialog: (tab: SCCourseEditManageUserProps) => void;
|
|
8
|
+
}
|
|
9
|
+
declare const _default: import("react").MemoExoticComponent<import("react").ForwardRefExoticComponent<RemoveButtonProps & import("react").RefAttributes<SCCourseEditManageUserRef>>>;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const lab_1 = require("@mui/lab");
|
|
6
|
+
const material_1 = require("@mui/material");
|
|
7
|
+
const api_services_1 = require("@selfcommunity/api-services");
|
|
8
|
+
const react_1 = require("react");
|
|
9
|
+
const Errors_1 = require("../../constants/Errors");
|
|
10
|
+
const utils_1 = require("@selfcommunity/utils");
|
|
11
|
+
const react_intl_1 = require("react-intl");
|
|
12
|
+
const notistack_1 = require("notistack");
|
|
13
|
+
const pubsub_js_1 = tslib_1.__importDefault(require("pubsub-js"));
|
|
14
|
+
const PubSub_1 = require("../../constants/PubSub");
|
|
15
|
+
const course_1 = require("../../types/course");
|
|
16
|
+
function RemoveButton(props, ref) {
|
|
17
|
+
// PROPS
|
|
18
|
+
const { course, user, handleOpenDialog } = props;
|
|
19
|
+
// STATES
|
|
20
|
+
const [loading, setLoading] = (0, react_1.useState)(false);
|
|
21
|
+
// HOOKS
|
|
22
|
+
const { enqueueSnackbar } = (0, notistack_1.useSnackbar)();
|
|
23
|
+
// HANDLERS
|
|
24
|
+
const handleSubmit = (0, react_1.useCallback)((userToRemove) => {
|
|
25
|
+
setLoading(true);
|
|
26
|
+
const params = {
|
|
27
|
+
user: userToRemove.id
|
|
28
|
+
};
|
|
29
|
+
api_services_1.CourseService.leaveOrRemoveCourseRequest(course.id, params)
|
|
30
|
+
.then(() => {
|
|
31
|
+
setLoading(false);
|
|
32
|
+
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.SCCourseEventType.REMOVE_MEMBER}`, userToRemove);
|
|
33
|
+
enqueueSnackbar((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.editCourse.tab.users.table.snackbar.removed", defaultMessage: "ui.editCourse.tab.users.table.snackbar.removed" }), {
|
|
34
|
+
variant: 'success',
|
|
35
|
+
autoHideDuration: 3000
|
|
36
|
+
});
|
|
37
|
+
})
|
|
38
|
+
.catch((error) => {
|
|
39
|
+
utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error);
|
|
40
|
+
enqueueSnackbar((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.common.error.action", defaultMessage: "ui.common.error.action" }), {
|
|
41
|
+
variant: 'error',
|
|
42
|
+
autoHideDuration: 3000
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
}, [course, setLoading]);
|
|
46
|
+
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
47
|
+
handleManageUser: (userToRemove) => handleSubmit(userToRemove)
|
|
48
|
+
}), [handleSubmit]);
|
|
49
|
+
return ((0, jsx_runtime_1.jsx)(lab_1.LoadingButton, Object.assign({ size: "small", color: "inherit", variant: "outlined", onClick: () => handleOpenDialog({ tab: course_1.SCCourseEditTabType.USERS, user }), loading: loading, disabled: loading }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "close" }) })));
|
|
50
|
+
}
|
|
51
|
+
exports.default = (0, react_1.memo)((0, react_1.forwardRef)(RemoveButton));
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { SCCourseType, SCUserType } from '@selfcommunity/types';
|
|
3
|
+
import { SCCourseEditManageUserProps, SCCourseEditManageUserRef } from '../../types/course';
|
|
3
4
|
interface RequestButtonProps {
|
|
4
5
|
course: SCCourseType;
|
|
5
6
|
user: SCUserType;
|
|
7
|
+
handleOpenDialog: (tab: SCCourseEditManageUserProps) => void;
|
|
6
8
|
}
|
|
7
|
-
declare
|
|
8
|
-
declare const _default: import("react").MemoExoticComponent<typeof RequestButton>;
|
|
9
|
+
declare const _default: import("react").MemoExoticComponent<import("react").ForwardRefExoticComponent<RequestButtonProps & import("react").RefAttributes<SCCourseEditManageUserRef>>>;
|
|
9
10
|
export default _default;
|
|
@@ -13,12 +13,13 @@ const notistack_1 = require("notistack");
|
|
|
13
13
|
const constants_1 = require("./constants");
|
|
14
14
|
const pubsub_js_1 = tslib_1.__importDefault(require("pubsub-js"));
|
|
15
15
|
const PubSub_1 = require("../../constants/PubSub");
|
|
16
|
+
const course_1 = require("../../types/course");
|
|
16
17
|
const classes = {
|
|
17
18
|
requestButtonWrapper: `${constants_1.PREFIX}-request-button-wrapper`
|
|
18
19
|
};
|
|
19
|
-
function RequestButton(props) {
|
|
20
|
+
function RequestButton(props, ref) {
|
|
20
21
|
// PROPS
|
|
21
|
-
const { course, user } = props;
|
|
22
|
+
const { course, user, handleOpenDialog } = props;
|
|
22
23
|
// STATES
|
|
23
24
|
const [acceptLoading, setAcceptLoading] = (0, react_1.useState)(false);
|
|
24
25
|
const [rejectLoading, setRejectLoading] = (0, react_1.useState)(false);
|
|
@@ -33,8 +34,8 @@ function RequestButton(props) {
|
|
|
33
34
|
api_services_1.CourseService.inviteOrAcceptUsersToCourse(course.id, data)
|
|
34
35
|
.then(() => {
|
|
35
36
|
setAcceptLoading(false);
|
|
36
|
-
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.
|
|
37
|
-
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.
|
|
37
|
+
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.SCCourseEventType.ADD_MEMBER}`, user);
|
|
38
|
+
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.SCCourseEventType.REJECT_MEMBER}`, user);
|
|
38
39
|
enqueueSnackbar((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.editCourse.tab.requests.table.snackbar.accepted", defaultMessage: "ui.editCourse.tab.requests.table.snackbar.accepted" }), {
|
|
39
40
|
variant: 'success',
|
|
40
41
|
autoHideDuration: 3000
|
|
@@ -48,15 +49,15 @@ function RequestButton(props) {
|
|
|
48
49
|
});
|
|
49
50
|
});
|
|
50
51
|
}, [course, user, setAcceptLoading]);
|
|
51
|
-
const handleReject = (0, react_1.useCallback)(() => {
|
|
52
|
+
const handleReject = (0, react_1.useCallback)((userToReject) => {
|
|
52
53
|
setRejectLoading(true);
|
|
53
54
|
const params = {
|
|
54
|
-
user:
|
|
55
|
+
user: userToReject.id
|
|
55
56
|
};
|
|
56
57
|
api_services_1.CourseService.leaveOrRemoveCourseRequest(course.id, params)
|
|
57
58
|
.then(() => {
|
|
58
59
|
setRejectLoading(false);
|
|
59
|
-
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.
|
|
60
|
+
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.COURSE}.${PubSub_1.SCCourseEventType.REJECT_MEMBER}`, userToReject);
|
|
60
61
|
enqueueSnackbar((0, jsx_runtime_1.jsx)(react_intl_1.FormattedMessage, { id: "ui.editCourse.tab.requests.table.snackbar.rejected", defaultMessage: "ui.editCourse.tab.requests.table.snackbar.rejected" }), {
|
|
61
62
|
variant: 'success',
|
|
62
63
|
autoHideDuration: 3000
|
|
@@ -69,7 +70,10 @@ function RequestButton(props) {
|
|
|
69
70
|
autoHideDuration: 3000
|
|
70
71
|
});
|
|
71
72
|
});
|
|
72
|
-
}, [course,
|
|
73
|
-
|
|
73
|
+
}, [course, setRejectLoading]);
|
|
74
|
+
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
75
|
+
handleManageUser: (userToReject) => handleReject(userToReject)
|
|
76
|
+
}), [handleReject]);
|
|
77
|
+
return ((0, jsx_runtime_1.jsxs)(material_1.Stack, Object.assign({ className: classes.requestButtonWrapper }, { children: [(0, jsx_runtime_1.jsx)(lab_1.LoadingButton, Object.assign({ size: "small", color: "primary", variant: "outlined", onClick: handleAccept, loading: acceptLoading, disabled: acceptLoading }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "check" }) })), (0, jsx_runtime_1.jsx)(lab_1.LoadingButton, Object.assign({ size: "small", color: "inherit", variant: "outlined", onClick: () => handleOpenDialog({ tab: course_1.SCCourseEditTabType.REQUESTS, request: user }), loading: rejectLoading, disabled: rejectLoading }, { children: (0, jsx_runtime_1.jsx)(material_1.Icon, { children: "close" }) }))] })));
|
|
74
78
|
}
|
|
75
|
-
exports.default = (0, react_1.memo)(RequestButton);
|
|
79
|
+
exports.default = (0, react_1.memo)((0, react_1.forwardRef)(RequestButton));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SCUserType } from '@selfcommunity/types';
|
|
1
2
|
export declare enum SCCourseTemplateType {
|
|
2
3
|
SNIPPET = "snippet",
|
|
3
4
|
PREVIEW = "preview"
|
|
@@ -23,3 +24,11 @@ export declare enum SCCourseUsersTableModeType {
|
|
|
23
24
|
EDIT = "edit",
|
|
24
25
|
REQUESTS = "requests"
|
|
25
26
|
}
|
|
27
|
+
export interface SCCourseEditManageUserProps {
|
|
28
|
+
tab: SCCourseEditTabType;
|
|
29
|
+
user?: SCUserType;
|
|
30
|
+
request?: SCUserType;
|
|
31
|
+
}
|
|
32
|
+
export interface SCCourseEditManageUserRef {
|
|
33
|
+
handleManageUser: (user: SCUserType) => void;
|
|
34
|
+
}
|
|
@@ -12,7 +12,7 @@ import { actionWidgetTypes, dataWidgetReducer, stateWidgetInitializer } from '..
|
|
|
12
12
|
import { CourseService } from '@selfcommunity/api-services';
|
|
13
13
|
import { PREFIX } from './constants';
|
|
14
14
|
import PubSub from 'pubsub-js';
|
|
15
|
-
import {
|
|
15
|
+
import { SCCourseEventType, SCTopicType } from '../../constants/PubSub';
|
|
16
16
|
import { SCCourseUsersTableModeType } from '../../types/course';
|
|
17
17
|
const classes = {
|
|
18
18
|
usersStatusWrapper: `${PREFIX}-users-status-wrapper`,
|
|
@@ -64,7 +64,7 @@ function Requests(props) {
|
|
|
64
64
|
}
|
|
65
65
|
}, [state.isLoadingNext, state.initialized, course, dispatch, endpointQueryParams]);
|
|
66
66
|
// HANDLERS
|
|
67
|
-
const
|
|
67
|
+
const handleRejectUser = useCallback((_msg, user) => {
|
|
68
68
|
dispatch({
|
|
69
69
|
type: actionWidgetTypes.SET_RESULTS,
|
|
70
70
|
payload: { count: state.results.length - 1, results: state.results.filter((result) => result.id !== user.id) }
|
|
@@ -81,11 +81,11 @@ function Requests(props) {
|
|
|
81
81
|
}
|
|
82
82
|
}, [scUserContext.user, _init]);
|
|
83
83
|
useEffect(() => {
|
|
84
|
-
updatedUsers.current = PubSub.subscribe(`${SCTopicType.COURSE}.${
|
|
84
|
+
updatedUsers.current = PubSub.subscribe(`${SCTopicType.COURSE}.${SCCourseEventType.REJECT_MEMBER}`, handleRejectUser);
|
|
85
85
|
return () => {
|
|
86
86
|
updatedUsers.current && PubSub.unsubscribe(updatedUsers.current);
|
|
87
87
|
};
|
|
88
|
-
}, [
|
|
88
|
+
}, [handleRejectUser]);
|
|
89
89
|
return (_jsxs(Box, { children: [_jsx(Typography, Object.assign({ variant: "h6", className: classes.contrastColor }, { children: _jsx(FormattedMessage, { id: "ui.editCourse.tab.requests.title", defaultMessage: "ui.editCourse.tab.requests.title", values: { requestsNumber: state.results.length } }) })), _jsx(Stack, Object.assign({ className: classes.usersStatusWrapper }, { children: _jsx(Status, { course: course, handleTabChange: handleTabChange }) })), _jsx(CourseUsersTable, { course: course, state: state, dispatch: dispatch, headerCells: headerCells, mode: SCCourseUsersTableModeType.REQUESTS, emptyStatusTitle: "ui.courseUsersTable.empty.requests.title" })] }));
|
|
90
90
|
}
|
|
91
91
|
export default memo(Requests);
|
|
@@ -14,7 +14,7 @@ import { SCCache, useSCUser } from '@selfcommunity/react-core';
|
|
|
14
14
|
import { actionWidgetTypes, dataWidgetReducer, stateWidgetInitializer } from '../../utils/widget';
|
|
15
15
|
import { CourseService, Endpoints } from '@selfcommunity/api-services';
|
|
16
16
|
import PubSub from 'pubsub-js';
|
|
17
|
-
import {
|
|
17
|
+
import { SCCourseEventType, SCTopicType } from '../../constants/PubSub';
|
|
18
18
|
import { SCCourseUsersTableModeType } from '../../types/course';
|
|
19
19
|
const classes = {
|
|
20
20
|
usersStatusWrapper: `${PREFIX}-users-status-wrapper`,
|
|
@@ -32,7 +32,8 @@ const headerCells = [
|
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
id: 'ui.editCourse.tab.users.table.header.latestActivity'
|
|
35
|
-
}
|
|
35
|
+
},
|
|
36
|
+
{}
|
|
36
37
|
];
|
|
37
38
|
function Users(props) {
|
|
38
39
|
// PROPS
|
|
@@ -55,6 +56,7 @@ function Users(props) {
|
|
|
55
56
|
const { enqueueSnackbar } = useSnackbar();
|
|
56
57
|
// REFS
|
|
57
58
|
const updatedUsers = useRef(null);
|
|
59
|
+
const removedUsers = useRef(null);
|
|
58
60
|
// CALLBACKS
|
|
59
61
|
const _init = useCallback(() => {
|
|
60
62
|
if (!state.initialized && !state.isLoadingNext) {
|
|
@@ -73,6 +75,12 @@ function Users(props) {
|
|
|
73
75
|
const handleAddUser = useCallback((_msg, user) => {
|
|
74
76
|
dispatch({ type: actionWidgetTypes.LOAD_PREVIOUS_SUCCESS, payload: { count: state.count + 1, results: [user], initialized: true } });
|
|
75
77
|
}, [state.count, dispatch]);
|
|
78
|
+
const handleRemoveUser = useCallback((_msg, user) => {
|
|
79
|
+
dispatch({
|
|
80
|
+
type: actionWidgetTypes.SET_RESULTS,
|
|
81
|
+
payload: { count: state.count - 1, results: state.results.filter((result) => result.id !== user.id), initialized: true }
|
|
82
|
+
});
|
|
83
|
+
}, [state.count, state.results, dispatch]);
|
|
76
84
|
// EFFECTS
|
|
77
85
|
useEffect(() => {
|
|
78
86
|
let _t;
|
|
@@ -84,11 +92,13 @@ function Users(props) {
|
|
|
84
92
|
}
|
|
85
93
|
}, [scUserContext.user, _init]);
|
|
86
94
|
useEffect(() => {
|
|
87
|
-
updatedUsers.current = PubSub.subscribe(`${SCTopicType.COURSE}.${
|
|
95
|
+
updatedUsers.current = PubSub.subscribe(`${SCTopicType.COURSE}.${SCCourseEventType.ADD_MEMBER}`, handleAddUser);
|
|
96
|
+
removedUsers.current = PubSub.subscribe(`${SCTopicType.COURSE}.${SCCourseEventType.REMOVE_MEMBER}`, handleRemoveUser);
|
|
88
97
|
return () => {
|
|
89
98
|
updatedUsers.current && PubSub.unsubscribe(updatedUsers.current);
|
|
99
|
+
removedUsers.current && PubSub.unsubscribe(removedUsers.current);
|
|
90
100
|
};
|
|
91
|
-
}, [handleAddUser]);
|
|
101
|
+
}, [handleAddUser, handleRemoveUser]);
|
|
92
102
|
const handleConfirm = useCallback((newUsers) => {
|
|
93
103
|
const data = {
|
|
94
104
|
joined: newUsers.map((user) => user.id)
|
|
@@ -113,7 +123,7 @@ function Users(props) {
|
|
|
113
123
|
});
|
|
114
124
|
});
|
|
115
125
|
}, [course, dispatch]);
|
|
116
|
-
return (_jsxs(Box, { children: [_jsx(Typography, Object.assign({ variant: "h6", className: classes.contrastColor }, { children: _jsx(FormattedMessage, { id: "ui.editCourse.tab.users.title", defaultMessage: "ui.editCourse.tab.users.title", values: { usersNumber: state.
|
|
126
|
+
return (_jsxs(Box, { children: [_jsx(Typography, Object.assign({ variant: "h6", className: classes.contrastColor }, { children: _jsx(FormattedMessage, { id: "ui.editCourse.tab.users.title", defaultMessage: "ui.editCourse.tab.users.title", values: { usersNumber: state.count } }) })), _jsxs(Stack, Object.assign({ className: classes.usersStatusWrapper }, { children: [_jsx(Status, { course: course, handleTabChange: handleTabChange }), _jsx(AddUsersButton, { label: "ui.editCourse.tab.users.addUsersButton.label", endpoint: {
|
|
117
127
|
url: () => Endpoints.GetCourseSuggestedUsers.url({ id: course.id }),
|
|
118
128
|
method: Endpoints.GetCourseSuggestedUsers.method
|
|
119
129
|
}, onConfirm: handleConfirm })] })), _jsx(CourseUsersTable, { course: course, state: state, dispatch: dispatch, headerCells: headerCells, mode: SCCourseUsersTableModeType.EDIT, emptyStatusTitle: "ui.courseUsersTable.empty.users.title", emptyStatusDescription: "ui.courseUsersTable.empty.users.description" })] }));
|