@selfcommunity/react-ui 0.7.9-alpha.37 → 0.7.9-alpha.39
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/FeedUpdatesWidget/FeedUpdatesWidget.js +1 -1
- package/lib/cjs/components/GroupForm/GroupForm.js +19 -0
- package/lib/cjs/components/GroupHeader/GroupHeader.js +32 -1
- package/lib/cjs/components/GroupInfoWidget/GroupInfoWidget.js +28 -2
- package/lib/cjs/components/GroupMembersWidget/GroupMembersWidget.js +6 -3
- package/lib/cjs/components/GroupSettingsIconButton/GroupSettingsIconButton.js +13 -0
- package/lib/cjs/components/GroupSubscribeButton/GroupSubscribeButton.js +20 -7
- package/lib/cjs/components/Groups/Groups.d.ts +1 -1
- package/lib/cjs/components/Groups/Groups.js +2 -2
- package/lib/cjs/constants/PubSub.d.ts +27 -0
- package/lib/cjs/constants/PubSub.js +21 -0
- package/lib/esm/components/FeedUpdatesWidget/FeedUpdatesWidget.js +1 -1
- package/lib/esm/components/GroupForm/GroupForm.js +19 -0
- package/lib/esm/components/GroupHeader/GroupHeader.js +33 -2
- package/lib/esm/components/GroupInfoWidget/GroupInfoWidget.js +28 -2
- package/lib/esm/components/GroupMembersWidget/GroupMembersWidget.js +6 -3
- package/lib/esm/components/GroupSettingsIconButton/GroupSettingsIconButton.js +13 -0
- package/lib/esm/components/GroupSubscribeButton/GroupSubscribeButton.js +20 -7
- package/lib/esm/components/Groups/Groups.d.ts +1 -1
- package/lib/esm/components/Groups/Groups.js +2 -2
- package/lib/esm/constants/PubSub.d.ts +27 -0
- package/lib/esm/constants/PubSub.js +18 -0
- package/lib/umd/react-ui.js +1 -1
- package/package.json +3 -3
|
@@ -57,7 +57,7 @@ function FeedUpdatesWidget(inProps) {
|
|
|
57
57
|
const [updates, setUpdates] = (0, react_1.useState)(false);
|
|
58
58
|
// REFS
|
|
59
59
|
const updatesSubscription = (0, react_1.useRef)(null);
|
|
60
|
-
//
|
|
60
|
+
// Subscriber for pubsub callback
|
|
61
61
|
const subscriber = (msg, data) => {
|
|
62
62
|
if (subscriptionChannelUpdatesCallback(msg, data)) {
|
|
63
63
|
setUpdates(true);
|
|
@@ -15,10 +15,12 @@ const ChangeGroupPicture_1 = tslib_1.__importDefault(require("../ChangeGroupPict
|
|
|
15
15
|
const ChangeGroupCover_1 = tslib_1.__importDefault(require("../ChangeGroupCover"));
|
|
16
16
|
const Group_1 = require("../../constants/Group");
|
|
17
17
|
const GroupInviteButton_1 = tslib_1.__importDefault(require("../GroupInviteButton"));
|
|
18
|
+
const pubsub_js_1 = tslib_1.__importDefault(require("pubsub-js"));
|
|
18
19
|
const types_1 = require("@selfcommunity/types");
|
|
19
20
|
const Errors_1 = require("../../constants/Errors");
|
|
20
21
|
const api_services_1 = require("@selfcommunity/api-services");
|
|
21
22
|
const utils_1 = require("@selfcommunity/utils");
|
|
23
|
+
const PubSub_1 = require("../../constants/PubSub");
|
|
22
24
|
const messages = (0, react_intl_1.defineMessages)({
|
|
23
25
|
name: {
|
|
24
26
|
id: 'ui.groupForm.name.placeholder',
|
|
@@ -142,6 +144,22 @@ function GroupForm(inProps) {
|
|
|
142
144
|
setError(error);
|
|
143
145
|
}
|
|
144
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Notify when a group info changed
|
|
149
|
+
* @param data
|
|
150
|
+
*/
|
|
151
|
+
function notifyChanges(data) {
|
|
152
|
+
if (data) {
|
|
153
|
+
if (group) {
|
|
154
|
+
// Edit group
|
|
155
|
+
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.GROUP}.${PubSub_1.SCEventType.EDIT}`, data);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
// Create group
|
|
159
|
+
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.GROUP}.${PubSub_1.SCEventType.CREATE}`, data);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
145
163
|
const handleSubmit = () => {
|
|
146
164
|
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: true })));
|
|
147
165
|
const formData = new FormData();
|
|
@@ -168,6 +186,7 @@ function GroupForm(inProps) {
|
|
|
168
186
|
groupService
|
|
169
187
|
.then((data) => {
|
|
170
188
|
onSuccess && onSuccess(data);
|
|
189
|
+
notifyChanges(data);
|
|
171
190
|
onClose && onClose();
|
|
172
191
|
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: false })));
|
|
173
192
|
})
|
|
@@ -18,6 +18,8 @@ const GroupMembersButton_1 = tslib_1.__importDefault(require("../GroupMembersBut
|
|
|
18
18
|
const EditGroupButton_1 = tslib_1.__importDefault(require("../EditGroupButton"));
|
|
19
19
|
const GroupSubscribeButton_1 = tslib_1.__importDefault(require("../GroupSubscribeButton"));
|
|
20
20
|
const GroupInviteButton_1 = tslib_1.__importDefault(require("../GroupInviteButton"));
|
|
21
|
+
const PubSub_1 = require("../../constants/PubSub");
|
|
22
|
+
const pubsub_js_1 = tslib_1.__importDefault(require("pubsub-js"));
|
|
21
23
|
const classes = {
|
|
22
24
|
root: `${constants_1.PREFIX}-root`,
|
|
23
25
|
cover: `${constants_1.PREFIX}-cover`,
|
|
@@ -81,6 +83,8 @@ function GroupHeader(inProps) {
|
|
|
81
83
|
const scUserContext = (0, react_core_1.useSCUser)();
|
|
82
84
|
// HOOKS
|
|
83
85
|
const { scGroup, setSCGroup } = (0, react_core_1.useSCFetchGroup)({ id: groupId, group });
|
|
86
|
+
// REFS
|
|
87
|
+
const updatesSubscription = (0, react_1.useRef)(null);
|
|
84
88
|
// CONST
|
|
85
89
|
const isGroupAdmin = (0, react_1.useMemo)(() => { var _a; return scUserContext.user && ((_a = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _a === void 0 ? void 0 : _a.id) === scUserContext.user.id; }, [scUserContext.user, (_a = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _a === void 0 ? void 0 : _a.id]);
|
|
86
90
|
/**
|
|
@@ -107,6 +111,33 @@ function GroupHeader(inProps) {
|
|
|
107
111
|
const handleSubscribe = (group, status) => {
|
|
108
112
|
setSCGroup(Object.assign(Object.assign({}, group), { subscribers_counter: group.subscribers_counter + (status ? 1 : -1) }));
|
|
109
113
|
};
|
|
114
|
+
/**
|
|
115
|
+
* Subscriber for pubsub callback
|
|
116
|
+
*/
|
|
117
|
+
const onChangeGroupMembersHandler = (0, react_1.useCallback)((msg, data) => {
|
|
118
|
+
if (data && data.group.id === scGroup.id) {
|
|
119
|
+
let _group = Object.assign({}, scGroup);
|
|
120
|
+
if (msg === `${PubSub_1.SCTopicType.GROUP}.${PubSub_1.SCEventType.ADD_MEMBER}`) {
|
|
121
|
+
_group.subscribers_counter = _group.subscribers_counter + 1;
|
|
122
|
+
}
|
|
123
|
+
else if (msg === `${PubSub_1.SCTopicType.GROUP}.${PubSub_1.SCEventType.REMOVE_MEMBER}`) {
|
|
124
|
+
_group.subscribers_counter = Math.max(_group.subscribers_counter - 1, 0);
|
|
125
|
+
}
|
|
126
|
+
console.log(_group);
|
|
127
|
+
setSCGroup(_group);
|
|
128
|
+
}
|
|
129
|
+
}, [scGroup, setSCGroup]);
|
|
130
|
+
/**
|
|
131
|
+
* On mount, subscribe to receive groups updates (only edit)
|
|
132
|
+
*/
|
|
133
|
+
(0, react_1.useEffect)(() => {
|
|
134
|
+
if (scGroup) {
|
|
135
|
+
updatesSubscription.current = pubsub_js_1.default.subscribe(`${PubSub_1.SCTopicType.GROUP}.${PubSub_1.SCEventType.MEMBERS}`, onChangeGroupMembersHandler);
|
|
136
|
+
}
|
|
137
|
+
return () => {
|
|
138
|
+
updatesSubscription.current && pubsub_js_1.default.unsubscribe(updatesSubscription.current);
|
|
139
|
+
};
|
|
140
|
+
}, [scGroup]);
|
|
110
141
|
// RENDER
|
|
111
142
|
if (!scGroup) {
|
|
112
143
|
return react_1.default.createElement(Skeleton_1.default, null);
|
|
@@ -143,7 +174,7 @@ function GroupHeader(inProps) {
|
|
|
143
174
|
isGroupAdmin) && (react_1.default.createElement(material_1.Box, { className: classes.members },
|
|
144
175
|
react_1.default.createElement(material_1.Typography, { className: classes.membersCounter, component: "div" },
|
|
145
176
|
react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupHeader.members", defaultMessage: "ui.groupHeader.members", values: { total: scGroup.subscribers_counter } })),
|
|
146
|
-
react_1.default.createElement(GroupMembersButton_1.default, Object.assign({ groupId: scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, group: scGroup, autoHide: !isGroupAdmin }, GroupMembersButtonProps))))),
|
|
177
|
+
react_1.default.createElement(GroupMembersButton_1.default, Object.assign({ key: scGroup.subscribers_counter, groupId: scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, group: scGroup, autoHide: !isGroupAdmin }, GroupMembersButtonProps))))),
|
|
147
178
|
isGroupAdmin ? (react_1.default.createElement(GroupInviteButton_1.default, { group: scGroup, groupId: scGroup.id })) : (react_1.default.createElement(GroupSubscribeButton_1.default, Object.assign({ group: scGroup, onSubscribe: handleSubscribe }, GroupSubscribeButtonProps))))));
|
|
148
179
|
}
|
|
149
180
|
exports.default = GroupHeader;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
-
const react_1 = tslib_1.
|
|
4
|
+
const react_1 = tslib_1.__importStar(require("react"));
|
|
5
5
|
const styles_1 = require("@mui/material/styles");
|
|
6
6
|
const material_1 = require("@mui/material");
|
|
7
7
|
const classnames_1 = tslib_1.__importDefault(require("classnames"));
|
|
@@ -10,8 +10,10 @@ const system_1 = require("@mui/system");
|
|
|
10
10
|
const constants_1 = require("./constants");
|
|
11
11
|
const react_intl_1 = require("react-intl");
|
|
12
12
|
const types_1 = require("@selfcommunity/types");
|
|
13
|
+
const pubsub_js_1 = tslib_1.__importDefault(require("pubsub-js"));
|
|
13
14
|
const react_core_1 = require("@selfcommunity/react-core");
|
|
14
15
|
const Skeleton_1 = tslib_1.__importDefault(require("./Skeleton"));
|
|
16
|
+
const PubSub_1 = require("../../constants/PubSub");
|
|
15
17
|
const classes = {
|
|
16
18
|
root: `${constants_1.PREFIX}-root`,
|
|
17
19
|
title: `${constants_1.PREFIX}-title`,
|
|
@@ -62,9 +64,33 @@ function GroupInfoWidget(inProps) {
|
|
|
62
64
|
});
|
|
63
65
|
const { className, group, groupId, onHeightChange, onStateChange } = props, rest = tslib_1.__rest(props, ["className", "group", "groupId", "onHeightChange", "onStateChange"]);
|
|
64
66
|
// HOOKS
|
|
65
|
-
const { scGroup } = (0, react_core_1.useSCFetchGroup)({ id: groupId, group });
|
|
67
|
+
const { scGroup, setSCGroup } = (0, react_core_1.useSCFetchGroup)({ id: groupId, group });
|
|
66
68
|
// INTL
|
|
67
69
|
const intl = (0, react_intl_1.useIntl)();
|
|
70
|
+
// REFS
|
|
71
|
+
const updatesSubscription = (0, react_1.useRef)(null);
|
|
72
|
+
/**
|
|
73
|
+
* Subscriber for pubsub callback
|
|
74
|
+
*/
|
|
75
|
+
const onChangeGroupHandler = (0, react_1.useCallback)((_msg, data) => {
|
|
76
|
+
if (data && scGroup.id === data.id) {
|
|
77
|
+
setSCGroup(data);
|
|
78
|
+
}
|
|
79
|
+
}, [scGroup, setSCGroup]);
|
|
80
|
+
/**
|
|
81
|
+
* On mount, subscribe to receive groups updates (only edit)
|
|
82
|
+
*/
|
|
83
|
+
(0, react_1.useEffect)(() => {
|
|
84
|
+
if (scGroup) {
|
|
85
|
+
updatesSubscription.current = pubsub_js_1.default.subscribe(`${PubSub_1.SCTopicType.GROUP}.${PubSub_1.SCEventType.EDIT}`, onChangeGroupHandler);
|
|
86
|
+
}
|
|
87
|
+
return () => {
|
|
88
|
+
updatesSubscription.current && pubsub_js_1.default.unsubscribe(updatesSubscription.current);
|
|
89
|
+
};
|
|
90
|
+
}, [scGroup]);
|
|
91
|
+
/**
|
|
92
|
+
* Loading group
|
|
93
|
+
*/
|
|
68
94
|
if (!scGroup) {
|
|
69
95
|
return react_1.default.createElement(Skeleton_1.default, null);
|
|
70
96
|
}
|
|
@@ -207,9 +207,12 @@ function GroupMembersWidget(inProps) {
|
|
|
207
207
|
openDialog && (react_1.default.createElement(DialogRoot, Object.assign({ className: classes.dialogRoot, title: react_1.default.createElement(react_intl_1.FormattedMessage, { defaultMessage: "ui.groupMembersWidget.dialogTitle", id: "ui.groupMembersWidget.dialogTitle", values: { total: scGroup.subscribers_counter } }), onClose: handleToggleDialogOpen, open: openDialog }, DialogProps),
|
|
208
208
|
react_1.default.createElement(InfiniteScroll_1.default, { dataLength: state.results.length, next: handleNext, hasMoreNext: Boolean(state.next), loaderNext: react_1.default.createElement(User_1.UserSkeleton, Object.assign({ elevation: 0 }, UserProps)), height: isMobile ? '100%' : 400, endMessage: react_1.default.createElement(material_1.Typography, { className: classes.endMessage },
|
|
209
209
|
react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupMembersWidget.noMoreResults", defaultMessage: "ui.groupMembersWidget.noMoreResults" })) },
|
|
210
|
-
react_1.default.createElement(List_1.default, null, state.results.map((user) =>
|
|
211
|
-
|
|
212
|
-
|
|
210
|
+
react_1.default.createElement(List_1.default, null, state.results.map((user) => {
|
|
211
|
+
var _a;
|
|
212
|
+
return (react_1.default.createElement(material_1.ListItem, { key: user.id },
|
|
213
|
+
react_1.default.createElement(User_1.default, { elevation: 0, actions: isGroupAdmin ? (react_1.default.createElement(GroupSettingsIconButton_1.default, { group: scGroup, user: user, onRemoveSuccess: () => handleRefresh(user.id) })) : ((_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.id) !== user.id ? (react_1.default.createElement(material_1.Button, { size: "small", variant: "outlined", component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.USER_PRIVATE_MESSAGES_ROUTE_NAME, user) },
|
|
214
|
+
react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupSettingsIconButton.item.message", defaultMessage: "ui.groupSettingsIconButton.item.message" }))) : null, user: user, userId: user.id })));
|
|
215
|
+
})))))),
|
|
213
216
|
react_1.default.createElement(material_1.CardActions, { className: classes.actions },
|
|
214
217
|
react_1.default.createElement(GroupInviteButton_1.default, { groupId: scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, group: scGroup }))));
|
|
215
218
|
return (react_1.default.createElement(Root, Object.assign({ className: (0, classnames_1.default)(classes.root, className) }, rest), content));
|
|
@@ -11,6 +11,8 @@ const system_1 = require("@mui/system");
|
|
|
11
11
|
const react_core_1 = require("@selfcommunity/react-core");
|
|
12
12
|
const ConfirmDialog_1 = tslib_1.__importDefault(require("../../shared/ConfirmDialog/ConfirmDialog"));
|
|
13
13
|
const api_services_1 = require("@selfcommunity/api-services");
|
|
14
|
+
const PubSub_1 = require("../../constants/PubSub");
|
|
15
|
+
const pubsub_js_1 = tslib_1.__importDefault(require("pubsub-js"));
|
|
14
16
|
const PREFIX = 'SCGroupSettingsIconButton';
|
|
15
17
|
const classes = {
|
|
16
18
|
root: `${PREFIX}-root`,
|
|
@@ -84,12 +86,23 @@ function GroupSettingsIconButton(inProps) {
|
|
|
84
86
|
setOpenConfirmDialog(false);
|
|
85
87
|
setAnchorEl(null);
|
|
86
88
|
};
|
|
89
|
+
/**
|
|
90
|
+
* Notify UI when a user is removed from a group
|
|
91
|
+
* @param group
|
|
92
|
+
* @param user
|
|
93
|
+
*/
|
|
94
|
+
function notifyChanges(group, user) {
|
|
95
|
+
if (group && user) {
|
|
96
|
+
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.GROUP}.${PubSub_1.SCEventType.REMOVE_MEMBER}`, { group, user });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
87
99
|
/**
|
|
88
100
|
* Handles thread deletion
|
|
89
101
|
*/
|
|
90
102
|
function handleRemoveUser() {
|
|
91
103
|
api_services_1.GroupService.removeUserFromGroup(group.id, user.id)
|
|
92
104
|
.then(() => {
|
|
105
|
+
notifyChanges(group, user);
|
|
93
106
|
onRemoveSuccess && onRemoveSuccess();
|
|
94
107
|
handleCloseDialog();
|
|
95
108
|
})
|
|
@@ -11,6 +11,8 @@ const react_intl_1 = require("react-intl");
|
|
|
11
11
|
const classnames_1 = tslib_1.__importDefault(require("classnames"));
|
|
12
12
|
const system_1 = require("@mui/system");
|
|
13
13
|
const Errors_1 = require("../../constants/Errors");
|
|
14
|
+
const PubSub_1 = require("../../constants/PubSub");
|
|
15
|
+
const pubsub_js_1 = tslib_1.__importDefault(require("pubsub-js"));
|
|
14
16
|
const PREFIX = 'SCGroupSubscribeButton';
|
|
15
17
|
const classes = {
|
|
16
18
|
root: `${PREFIX}-root`
|
|
@@ -73,14 +75,25 @@ function GroupSubscribeButton(inProps) {
|
|
|
73
75
|
setStatus(scGroupsManager.subscriptionStatus(scGroup));
|
|
74
76
|
}
|
|
75
77
|
}, [authUserId, scGroupsManager.subscriptionStatus]);
|
|
76
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Notify UI when a member is added to a group
|
|
80
|
+
* @param group
|
|
81
|
+
* @param user
|
|
82
|
+
*/
|
|
83
|
+
function notifyChanges(group, user) {
|
|
84
|
+
if (group && user) {
|
|
85
|
+
pubsub_js_1.default.publish(`${PubSub_1.SCTopicType.GROUP}.${PubSub_1.SCEventType.ADD_MEMBER}`, { group, user });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const subscribe = (user) => {
|
|
77
89
|
scGroupsManager
|
|
78
|
-
.subscribe(scGroup,
|
|
90
|
+
.subscribe(scGroup, user === null || user === void 0 ? void 0 : user.id)
|
|
79
91
|
.then(() => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
92
|
+
const _status = scGroup.privacy === types_1.SCGroupPrivacyType.PRIVATE && scGroup.subscription_status !== types_1.SCGroupSubscriptionStatusType.INVITED
|
|
93
|
+
? types_1.SCGroupSubscriptionStatusType.REQUESTED
|
|
94
|
+
: types_1.SCGroupSubscriptionStatusType.SUBSCRIBED;
|
|
95
|
+
notifyChanges(scGroup, user);
|
|
96
|
+
onSubscribe && onSubscribe(scGroup, _status);
|
|
84
97
|
})
|
|
85
98
|
.catch((e) => {
|
|
86
99
|
utils_1.Logger.error(Errors_1.SCOPE_SC_UI, e);
|
|
@@ -101,7 +114,7 @@ function GroupSubscribeButton(inProps) {
|
|
|
101
114
|
scContext.settings.handleAnonymousAction();
|
|
102
115
|
}
|
|
103
116
|
else {
|
|
104
|
-
status === types_1.SCGroupSubscriptionStatusType.SUBSCRIBED && !(user === null || user === void 0 ? void 0 : user.id) ? unsubscribe() : (user === null || user === void 0 ? void 0 : user.id) ? subscribe(user
|
|
117
|
+
status === types_1.SCGroupSubscriptionStatusType.SUBSCRIBED && !(user === null || user === void 0 ? void 0 : user.id) ? unsubscribe() : (user === null || user === void 0 ? void 0 : user.id) ? subscribe(user) : subscribe();
|
|
105
118
|
}
|
|
106
119
|
};
|
|
107
120
|
/**
|
|
@@ -124,11 +124,11 @@ function Groups(inProps) {
|
|
|
124
124
|
if (!contentAvailability && !scUserContext.user) {
|
|
125
125
|
return react_1.default.createElement(HiddenPlaceholder_1.default, null);
|
|
126
126
|
}
|
|
127
|
-
const content = (react_1.default.createElement(react_1.default.Fragment, null, loading ? (react_1.default.createElement(Skeleton_1.default, null)) : (react_1.default.createElement(
|
|
127
|
+
const content = (react_1.default.createElement(react_1.default.Fragment, null, loading ? (react_1.default.createElement(Skeleton_1.default, null)) : (react_1.default.createElement(react_1.default.Fragment, null, !groups.length ? (react_1.default.createElement(material_1.Box, { className: classes.noResults },
|
|
128
128
|
react_1.default.createElement(material_1.Typography, { variant: "h4" },
|
|
129
129
|
react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.noGroups.title", defaultMessage: "ui.groups.noGroups.title" })),
|
|
130
130
|
react_1.default.createElement(material_1.Typography, { variant: "body1" },
|
|
131
|
-
react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.noGroups.subtitle", defaultMessage: "ui.groups.noGroups.subtitle" })))) : (react_1.default.createElement(
|
|
131
|
+
react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.noGroups.subtitle", defaultMessage: "ui.groups.noGroups.subtitle" })))) : (react_1.default.createElement(material_1.Grid, { container: true, spacing: { xs: 3 }, className: classes.groups }, groups.map((group) => (react_1.default.createElement(material_1.Grid, { item: true, xs: 12, sm: 8, md: 6, key: group.id, className: classes.item },
|
|
132
132
|
react_1.default.createElement(Group_1.default, Object.assign({ group: group, groupId: group.id, groupSubscribeButtonProps: { onSubscribe: handleSubscribe } }, GroupComponentProps)))))))))));
|
|
133
133
|
return (react_1.default.createElement(Root, Object.assign({ className: (0, classnames_1.default)(classes.root, className) }, rest), content));
|
|
134
134
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { SCUserType, SCGroupType } from '@selfcommunity/types';
|
|
2
|
+
/**
|
|
3
|
+
* Define topics for pubsub
|
|
4
|
+
*/
|
|
5
|
+
export declare enum SCTopicType {
|
|
6
|
+
GROUP = "group"
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Event types
|
|
10
|
+
*/
|
|
11
|
+
export declare enum SCEventType {
|
|
12
|
+
CREATE = "create",
|
|
13
|
+
EDIT = "edit",
|
|
14
|
+
MEMBERS = "members",
|
|
15
|
+
ADD_MEMBER = "members.add_member",
|
|
16
|
+
REMOVE_MEMBER = "members.remove_member"
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Event structure
|
|
20
|
+
*/
|
|
21
|
+
export interface SCGroupChangeEventType {
|
|
22
|
+
group: SCGroupType;
|
|
23
|
+
}
|
|
24
|
+
export interface SCGroupMembersEventType {
|
|
25
|
+
group: SCGroupType;
|
|
26
|
+
user?: SCUserType;
|
|
27
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SCEventType = exports.SCTopicType = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Define topics for pubsub
|
|
6
|
+
*/
|
|
7
|
+
var SCTopicType;
|
|
8
|
+
(function (SCTopicType) {
|
|
9
|
+
SCTopicType["GROUP"] = "group";
|
|
10
|
+
})(SCTopicType = exports.SCTopicType || (exports.SCTopicType = {}));
|
|
11
|
+
/**
|
|
12
|
+
* Event types
|
|
13
|
+
*/
|
|
14
|
+
var SCEventType;
|
|
15
|
+
(function (SCEventType) {
|
|
16
|
+
SCEventType["CREATE"] = "create";
|
|
17
|
+
SCEventType["EDIT"] = "edit";
|
|
18
|
+
SCEventType["MEMBERS"] = "members";
|
|
19
|
+
SCEventType["ADD_MEMBER"] = "members.add_member";
|
|
20
|
+
SCEventType["REMOVE_MEMBER"] = "members.remove_member";
|
|
21
|
+
})(SCEventType = exports.SCEventType || (exports.SCEventType = {}));
|
|
@@ -55,7 +55,7 @@ export default function FeedUpdatesWidget(inProps) {
|
|
|
55
55
|
const [updates, setUpdates] = useState(false);
|
|
56
56
|
// REFS
|
|
57
57
|
const updatesSubscription = useRef(null);
|
|
58
|
-
//
|
|
58
|
+
// Subscriber for pubsub callback
|
|
59
59
|
const subscriber = (msg, data) => {
|
|
60
60
|
if (subscriptionChannelUpdatesCallback(msg, data)) {
|
|
61
61
|
setUpdates(true);
|
|
@@ -13,10 +13,12 @@ import ChangeGroupPicture from '../ChangeGroupPicture';
|
|
|
13
13
|
import ChangeGroupCover from '../ChangeGroupCover';
|
|
14
14
|
import { GROUP_DESCRIPTION_MAX_LENGTH, GROUP_TITLE_MAX_LENGTH } from '../../constants/Group';
|
|
15
15
|
import GroupInviteButton from '../GroupInviteButton';
|
|
16
|
+
import PubSub from 'pubsub-js';
|
|
16
17
|
import { SCGroupPrivacyType } from '@selfcommunity/types';
|
|
17
18
|
import { SCOPE_SC_UI } from '../../constants/Errors';
|
|
18
19
|
import { formatHttpErrorCode, GroupService } from '@selfcommunity/api-services';
|
|
19
20
|
import { Logger } from '@selfcommunity/utils';
|
|
21
|
+
import { SCEventType, SCTopicType } from '../../constants/PubSub';
|
|
20
22
|
const messages = defineMessages({
|
|
21
23
|
name: {
|
|
22
24
|
id: 'ui.groupForm.name.placeholder',
|
|
@@ -140,6 +142,22 @@ export default function GroupForm(inProps) {
|
|
|
140
142
|
setError(error);
|
|
141
143
|
}
|
|
142
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Notify when a group info changed
|
|
147
|
+
* @param data
|
|
148
|
+
*/
|
|
149
|
+
function notifyChanges(data) {
|
|
150
|
+
if (data) {
|
|
151
|
+
if (group) {
|
|
152
|
+
// Edit group
|
|
153
|
+
PubSub.publish(`${SCTopicType.GROUP}.${SCEventType.EDIT}`, data);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
// Create group
|
|
157
|
+
PubSub.publish(`${SCTopicType.GROUP}.${SCEventType.CREATE}`, data);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
143
161
|
const handleSubmit = () => {
|
|
144
162
|
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: true })));
|
|
145
163
|
const formData = new FormData();
|
|
@@ -166,6 +184,7 @@ export default function GroupForm(inProps) {
|
|
|
166
184
|
groupService
|
|
167
185
|
.then((data) => {
|
|
168
186
|
onSuccess && onSuccess(data);
|
|
187
|
+
notifyChanges(data);
|
|
169
188
|
onClose && onClose();
|
|
170
189
|
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: false })));
|
|
171
190
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __rest } from "tslib";
|
|
2
|
-
import React, { useMemo } from 'react';
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
3
3
|
import { styled } from '@mui/material/styles';
|
|
4
4
|
import { Avatar, Box, Icon, Paper, Typography } from '@mui/material';
|
|
5
5
|
import { SCGroupPrivacyType, SCGroupSubscriptionStatusType } from '@selfcommunity/types';
|
|
@@ -16,6 +16,8 @@ import GroupMembersButton from '../GroupMembersButton';
|
|
|
16
16
|
import EditGroupButton from '../EditGroupButton';
|
|
17
17
|
import GroupSubscribeButton from '../GroupSubscribeButton';
|
|
18
18
|
import GroupInviteButton from '../GroupInviteButton';
|
|
19
|
+
import { SCEventType, SCTopicType } from '../../constants/PubSub';
|
|
20
|
+
import PubSub from 'pubsub-js';
|
|
19
21
|
const classes = {
|
|
20
22
|
root: `${PREFIX}-root`,
|
|
21
23
|
cover: `${PREFIX}-cover`,
|
|
@@ -79,6 +81,8 @@ export default function GroupHeader(inProps) {
|
|
|
79
81
|
const scUserContext = useSCUser();
|
|
80
82
|
// HOOKS
|
|
81
83
|
const { scGroup, setSCGroup } = useSCFetchGroup({ id: groupId, group });
|
|
84
|
+
// REFS
|
|
85
|
+
const updatesSubscription = useRef(null);
|
|
82
86
|
// CONST
|
|
83
87
|
const isGroupAdmin = useMemo(() => { var _a; return scUserContext.user && ((_a = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _a === void 0 ? void 0 : _a.id) === scUserContext.user.id; }, [scUserContext.user, (_a = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _a === void 0 ? void 0 : _a.id]);
|
|
84
88
|
/**
|
|
@@ -105,6 +109,33 @@ export default function GroupHeader(inProps) {
|
|
|
105
109
|
const handleSubscribe = (group, status) => {
|
|
106
110
|
setSCGroup(Object.assign(Object.assign({}, group), { subscribers_counter: group.subscribers_counter + (status ? 1 : -1) }));
|
|
107
111
|
};
|
|
112
|
+
/**
|
|
113
|
+
* Subscriber for pubsub callback
|
|
114
|
+
*/
|
|
115
|
+
const onChangeGroupMembersHandler = useCallback((msg, data) => {
|
|
116
|
+
if (data && data.group.id === scGroup.id) {
|
|
117
|
+
let _group = Object.assign({}, scGroup);
|
|
118
|
+
if (msg === `${SCTopicType.GROUP}.${SCEventType.ADD_MEMBER}`) {
|
|
119
|
+
_group.subscribers_counter = _group.subscribers_counter + 1;
|
|
120
|
+
}
|
|
121
|
+
else if (msg === `${SCTopicType.GROUP}.${SCEventType.REMOVE_MEMBER}`) {
|
|
122
|
+
_group.subscribers_counter = Math.max(_group.subscribers_counter - 1, 0);
|
|
123
|
+
}
|
|
124
|
+
console.log(_group);
|
|
125
|
+
setSCGroup(_group);
|
|
126
|
+
}
|
|
127
|
+
}, [scGroup, setSCGroup]);
|
|
128
|
+
/**
|
|
129
|
+
* On mount, subscribe to receive groups updates (only edit)
|
|
130
|
+
*/
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
if (scGroup) {
|
|
133
|
+
updatesSubscription.current = PubSub.subscribe(`${SCTopicType.GROUP}.${SCEventType.MEMBERS}`, onChangeGroupMembersHandler);
|
|
134
|
+
}
|
|
135
|
+
return () => {
|
|
136
|
+
updatesSubscription.current && PubSub.unsubscribe(updatesSubscription.current);
|
|
137
|
+
};
|
|
138
|
+
}, [scGroup]);
|
|
108
139
|
// RENDER
|
|
109
140
|
if (!scGroup) {
|
|
110
141
|
return React.createElement(GroupHeaderSkeleton, null);
|
|
@@ -141,6 +172,6 @@ export default function GroupHeader(inProps) {
|
|
|
141
172
|
isGroupAdmin) && (React.createElement(Box, { className: classes.members },
|
|
142
173
|
React.createElement(Typography, { className: classes.membersCounter, component: "div" },
|
|
143
174
|
React.createElement(FormattedMessage, { id: "ui.groupHeader.members", defaultMessage: "ui.groupHeader.members", values: { total: scGroup.subscribers_counter } })),
|
|
144
|
-
React.createElement(GroupMembersButton, Object.assign({ groupId: scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, group: scGroup, autoHide: !isGroupAdmin }, GroupMembersButtonProps))))),
|
|
175
|
+
React.createElement(GroupMembersButton, Object.assign({ key: scGroup.subscribers_counter, groupId: scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, group: scGroup, autoHide: !isGroupAdmin }, GroupMembersButtonProps))))),
|
|
145
176
|
isGroupAdmin ? (React.createElement(GroupInviteButton, { group: scGroup, groupId: scGroup.id })) : (React.createElement(GroupSubscribeButton, Object.assign({ group: scGroup, onSubscribe: handleSubscribe }, GroupSubscribeButtonProps))))));
|
|
146
177
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __rest } from "tslib";
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { useCallback, useEffect, useRef } from 'react';
|
|
3
3
|
import { styled } from '@mui/material/styles';
|
|
4
4
|
import { CardContent, Icon, Typography } from '@mui/material';
|
|
5
5
|
import classNames from 'classnames';
|
|
@@ -8,8 +8,10 @@ import { useThemeProps } from '@mui/system';
|
|
|
8
8
|
import { PREFIX } from './constants';
|
|
9
9
|
import { FormattedMessage, useIntl } from 'react-intl';
|
|
10
10
|
import { SCGroupPrivacyType } from '@selfcommunity/types';
|
|
11
|
+
import PubSub from 'pubsub-js';
|
|
11
12
|
import { useSCFetchGroup } from '@selfcommunity/react-core';
|
|
12
13
|
import GroupInfoWidgetSkeleton from './Skeleton';
|
|
14
|
+
import { SCEventType, SCTopicType } from '../../constants/PubSub';
|
|
13
15
|
const classes = {
|
|
14
16
|
root: `${PREFIX}-root`,
|
|
15
17
|
title: `${PREFIX}-title`,
|
|
@@ -60,9 +62,33 @@ export default function GroupInfoWidget(inProps) {
|
|
|
60
62
|
});
|
|
61
63
|
const { className, group, groupId, onHeightChange, onStateChange } = props, rest = __rest(props, ["className", "group", "groupId", "onHeightChange", "onStateChange"]);
|
|
62
64
|
// HOOKS
|
|
63
|
-
const { scGroup } = useSCFetchGroup({ id: groupId, group });
|
|
65
|
+
const { scGroup, setSCGroup } = useSCFetchGroup({ id: groupId, group });
|
|
64
66
|
// INTL
|
|
65
67
|
const intl = useIntl();
|
|
68
|
+
// REFS
|
|
69
|
+
const updatesSubscription = useRef(null);
|
|
70
|
+
/**
|
|
71
|
+
* Subscriber for pubsub callback
|
|
72
|
+
*/
|
|
73
|
+
const onChangeGroupHandler = useCallback((_msg, data) => {
|
|
74
|
+
if (data && scGroup.id === data.id) {
|
|
75
|
+
setSCGroup(data);
|
|
76
|
+
}
|
|
77
|
+
}, [scGroup, setSCGroup]);
|
|
78
|
+
/**
|
|
79
|
+
* On mount, subscribe to receive groups updates (only edit)
|
|
80
|
+
*/
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (scGroup) {
|
|
83
|
+
updatesSubscription.current = PubSub.subscribe(`${SCTopicType.GROUP}.${SCEventType.EDIT}`, onChangeGroupHandler);
|
|
84
|
+
}
|
|
85
|
+
return () => {
|
|
86
|
+
updatesSubscription.current && PubSub.unsubscribe(updatesSubscription.current);
|
|
87
|
+
};
|
|
88
|
+
}, [scGroup]);
|
|
89
|
+
/**
|
|
90
|
+
* Loading group
|
|
91
|
+
*/
|
|
66
92
|
if (!scGroup) {
|
|
67
93
|
return React.createElement(GroupInfoWidgetSkeleton, null);
|
|
68
94
|
}
|
|
@@ -205,9 +205,12 @@ export default function GroupMembersWidget(inProps) {
|
|
|
205
205
|
openDialog && (React.createElement(DialogRoot, Object.assign({ className: classes.dialogRoot, title: React.createElement(FormattedMessage, { defaultMessage: "ui.groupMembersWidget.dialogTitle", id: "ui.groupMembersWidget.dialogTitle", values: { total: scGroup.subscribers_counter } }), onClose: handleToggleDialogOpen, open: openDialog }, DialogProps),
|
|
206
206
|
React.createElement(InfiniteScroll, { dataLength: state.results.length, next: handleNext, hasMoreNext: Boolean(state.next), loaderNext: React.createElement(UserSkeleton, Object.assign({ elevation: 0 }, UserProps)), height: isMobile ? '100%' : 400, endMessage: React.createElement(Typography, { className: classes.endMessage },
|
|
207
207
|
React.createElement(FormattedMessage, { id: "ui.groupMembersWidget.noMoreResults", defaultMessage: "ui.groupMembersWidget.noMoreResults" })) },
|
|
208
|
-
React.createElement(List, null, state.results.map((user) =>
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
React.createElement(List, null, state.results.map((user) => {
|
|
209
|
+
var _a;
|
|
210
|
+
return (React.createElement(ListItem, { key: user.id },
|
|
211
|
+
React.createElement(User, { elevation: 0, actions: isGroupAdmin ? (React.createElement(GroupSettingsIconButton, { group: scGroup, user: user, onRemoveSuccess: () => handleRefresh(user.id) })) : ((_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.id) !== user.id ? (React.createElement(Button, { size: "small", variant: "outlined", component: Link, to: scRoutingContext.url(SCRoutes.USER_PRIVATE_MESSAGES_ROUTE_NAME, user) },
|
|
212
|
+
React.createElement(FormattedMessage, { id: "ui.groupSettingsIconButton.item.message", defaultMessage: "ui.groupSettingsIconButton.item.message" }))) : null, user: user, userId: user.id })));
|
|
213
|
+
})))))),
|
|
211
214
|
React.createElement(CardActions, { className: classes.actions },
|
|
212
215
|
React.createElement(GroupInviteButton, { groupId: scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, group: scGroup }))));
|
|
213
216
|
return (React.createElement(Root, Object.assign({ className: classNames(classes.root, className) }, rest), content));
|
|
@@ -9,6 +9,8 @@ import { useThemeProps } from '@mui/system';
|
|
|
9
9
|
import { Link, SCRoutes, useSCRouting, useSCUser } from '@selfcommunity/react-core';
|
|
10
10
|
import ConfirmDialog from '../../shared/ConfirmDialog/ConfirmDialog';
|
|
11
11
|
import { GroupService } from '@selfcommunity/api-services';
|
|
12
|
+
import { SCEventType, SCTopicType } from '../../constants/PubSub';
|
|
13
|
+
import PubSub from 'pubsub-js';
|
|
12
14
|
const PREFIX = 'SCGroupSettingsIconButton';
|
|
13
15
|
const classes = {
|
|
14
16
|
root: `${PREFIX}-root`,
|
|
@@ -82,12 +84,23 @@ export default function GroupSettingsIconButton(inProps) {
|
|
|
82
84
|
setOpenConfirmDialog(false);
|
|
83
85
|
setAnchorEl(null);
|
|
84
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Notify UI when a user is removed from a group
|
|
89
|
+
* @param group
|
|
90
|
+
* @param user
|
|
91
|
+
*/
|
|
92
|
+
function notifyChanges(group, user) {
|
|
93
|
+
if (group && user) {
|
|
94
|
+
PubSub.publish(`${SCTopicType.GROUP}.${SCEventType.REMOVE_MEMBER}`, { group, user });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
85
97
|
/**
|
|
86
98
|
* Handles thread deletion
|
|
87
99
|
*/
|
|
88
100
|
function handleRemoveUser() {
|
|
89
101
|
GroupService.removeUserFromGroup(group.id, user.id)
|
|
90
102
|
.then(() => {
|
|
103
|
+
notifyChanges(group, user);
|
|
91
104
|
onRemoveSuccess && onRemoveSuccess();
|
|
92
105
|
handleCloseDialog();
|
|
93
106
|
})
|
|
@@ -9,6 +9,8 @@ import { FormattedMessage } from 'react-intl';
|
|
|
9
9
|
import classNames from 'classnames';
|
|
10
10
|
import { useThemeProps } from '@mui/system';
|
|
11
11
|
import { SCOPE_SC_UI } from '../../constants/Errors';
|
|
12
|
+
import { SCEventType, SCTopicType } from '../../constants/PubSub';
|
|
13
|
+
import PubSub from 'pubsub-js';
|
|
12
14
|
const PREFIX = 'SCGroupSubscribeButton';
|
|
13
15
|
const classes = {
|
|
14
16
|
root: `${PREFIX}-root`
|
|
@@ -71,14 +73,25 @@ export default function GroupSubscribeButton(inProps) {
|
|
|
71
73
|
setStatus(scGroupsManager.subscriptionStatus(scGroup));
|
|
72
74
|
}
|
|
73
75
|
}, [authUserId, scGroupsManager.subscriptionStatus]);
|
|
74
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Notify UI when a member is added to a group
|
|
78
|
+
* @param group
|
|
79
|
+
* @param user
|
|
80
|
+
*/
|
|
81
|
+
function notifyChanges(group, user) {
|
|
82
|
+
if (group && user) {
|
|
83
|
+
PubSub.publish(`${SCTopicType.GROUP}.${SCEventType.ADD_MEMBER}`, { group, user });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const subscribe = (user) => {
|
|
75
87
|
scGroupsManager
|
|
76
|
-
.subscribe(scGroup,
|
|
88
|
+
.subscribe(scGroup, user === null || user === void 0 ? void 0 : user.id)
|
|
77
89
|
.then(() => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
const _status = scGroup.privacy === SCGroupPrivacyType.PRIVATE && scGroup.subscription_status !== SCGroupSubscriptionStatusType.INVITED
|
|
91
|
+
? SCGroupSubscriptionStatusType.REQUESTED
|
|
92
|
+
: SCGroupSubscriptionStatusType.SUBSCRIBED;
|
|
93
|
+
notifyChanges(scGroup, user);
|
|
94
|
+
onSubscribe && onSubscribe(scGroup, _status);
|
|
82
95
|
})
|
|
83
96
|
.catch((e) => {
|
|
84
97
|
Logger.error(SCOPE_SC_UI, e);
|
|
@@ -99,7 +112,7 @@ export default function GroupSubscribeButton(inProps) {
|
|
|
99
112
|
scContext.settings.handleAnonymousAction();
|
|
100
113
|
}
|
|
101
114
|
else {
|
|
102
|
-
status === SCGroupSubscriptionStatusType.SUBSCRIBED && !(user === null || user === void 0 ? void 0 : user.id) ? unsubscribe() : (user === null || user === void 0 ? void 0 : user.id) ? subscribe(user
|
|
115
|
+
status === SCGroupSubscriptionStatusType.SUBSCRIBED && !(user === null || user === void 0 ? void 0 : user.id) ? unsubscribe() : (user === null || user === void 0 ? void 0 : user.id) ? subscribe(user) : subscribe();
|
|
103
116
|
}
|
|
104
117
|
};
|
|
105
118
|
/**
|