@selfcommunity/react-ui 0.7.9-alpha.4 → 0.7.9-alpha.40
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/ChangeGroupCover/ChangeGroupCover.js +24 -1
- package/lib/cjs/components/ChangeGroupPicture/ChangeGroupPicture.js +32 -11
- package/lib/cjs/components/Composer/Attributes/Attributes.js +3 -3
- package/lib/cjs/components/Composer/Composer.js +3 -5
- package/lib/cjs/components/Composer/Content/ContentPost/ContentPost.js +4 -3
- package/lib/cjs/components/Composer/Layer/AudienceLayer/AudienceLayer.d.ts +1 -2
- package/lib/cjs/components/Composer/Layer/AudienceLayer/AudienceLayer.js +18 -6
- package/lib/cjs/components/EditGroupButton/EditGroupButton.js +4 -0
- package/lib/cjs/components/FeedObject/FeedObject.d.ts +1 -0
- package/lib/cjs/components/FeedObject/FeedObject.js +23 -6
- package/lib/cjs/components/FeedUpdatesWidget/FeedUpdatesWidget.js +1 -1
- package/lib/cjs/components/Group/Group.js +9 -3
- package/lib/cjs/components/GroupForm/GroupForm.js +31 -9
- package/lib/cjs/components/GroupHeader/GroupHeader.d.ts +6 -5
- package/lib/cjs/components/GroupHeader/GroupHeader.js +52 -11
- package/lib/cjs/components/GroupHeader/Skeleton.d.ts +2 -4
- package/lib/cjs/components/GroupHeader/Skeleton.js +10 -10
- package/lib/cjs/components/GroupInfoWidget/GroupInfoWidget.js +40 -7
- package/lib/cjs/components/GroupInviteButton/GroupInviteButton.js +8 -7
- package/lib/cjs/components/GroupMembersButton/GroupMembersButton.d.ts +5 -0
- package/lib/cjs/components/GroupMembersButton/GroupMembersButton.js +7 -2
- package/lib/cjs/components/GroupMembersWidget/GroupMembersWidget.js +29 -4
- package/lib/cjs/components/GroupRequestsWidget/GroupRequestsWidget.d.ts +11 -5
- package/lib/cjs/components/GroupRequestsWidget/GroupRequestsWidget.js +18 -7
- package/lib/cjs/components/GroupSettingsIconButton/GroupSettingsIconButton.d.ts +48 -0
- package/lib/cjs/components/GroupSettingsIconButton/GroupSettingsIconButton.js +145 -0
- package/lib/cjs/components/GroupSettingsIconButton/index.d.ts +3 -0
- package/lib/cjs/components/GroupSettingsIconButton/index.js +5 -0
- package/lib/cjs/components/GroupSubscribeButton/GroupSubscribeButton.d.ts +8 -3
- package/lib/cjs/components/GroupSubscribeButton/GroupSubscribeButton.js +31 -10
- package/lib/cjs/components/Groups/Groups.d.ts +28 -13
- package/lib/cjs/components/Groups/Groups.js +71 -89
- package/lib/cjs/components/NavigationMenuIconButton/NavigationMenuIconButton.js +1 -1
- package/lib/cjs/components/NavigationToolbarMobile/NavigationToolbarMobile.d.ts +4 -0
- package/lib/cjs/components/NavigationToolbarMobile/NavigationToolbarMobile.js +2 -3
- package/lib/cjs/components/Notification/Group/Group.d.ts +15 -0
- package/lib/cjs/components/Notification/Group/Group.js +78 -0
- package/lib/cjs/components/Notification/Group/index.d.ts +3 -0
- package/lib/cjs/components/Notification/Group/index.js +5 -0
- package/lib/cjs/components/Notification/Notification.js +31 -1
- package/lib/cjs/components/Notification/PrivateMessage/PrivateMessage.js +16 -5
- package/lib/cjs/components/PrivateMessageComponent/PrivateMessageComponent.d.ts +1 -1
- package/lib/cjs/components/PrivateMessageComponent/PrivateMessageComponent.js +10 -7
- package/lib/cjs/components/PrivateMessageSnippetItem/PrivateMessageSnippetItem.js +11 -6
- package/lib/cjs/components/PrivateMessageSnippets/PrivateMessageSnippets.d.ts +3 -3
- package/lib/cjs/components/PrivateMessageSnippets/PrivateMessageSnippets.js +24 -6
- package/lib/cjs/components/PrivateMessageThread/PrivateMessageThread.d.ts +6 -1
- package/lib/cjs/components/PrivateMessageThread/PrivateMessageThread.js +45 -20
- package/lib/cjs/components/SearchAutocomplete/SearchAutocomplete.js +22 -5
- package/lib/cjs/components/SnippetNotifications/SnippetNotifications.js +7 -0
- package/lib/cjs/components/ToastNotifications/ToastNotifications.js +7 -0
- package/lib/cjs/constants/PubSub.d.ts +27 -0
- package/lib/cjs/constants/PubSub.js +21 -0
- package/lib/cjs/index.d.ts +4 -2
- package/lib/cjs/index.js +9 -4
- package/lib/esm/components/ChangeGroupCover/ChangeGroupCover.js +24 -1
- package/lib/esm/components/ChangeGroupPicture/ChangeGroupPicture.js +32 -11
- package/lib/esm/components/Composer/Attributes/Attributes.js +3 -3
- package/lib/esm/components/Composer/Composer.js +3 -5
- package/lib/esm/components/Composer/Content/ContentPost/ContentPost.js +4 -3
- package/lib/esm/components/Composer/Layer/AudienceLayer/AudienceLayer.d.ts +1 -2
- package/lib/esm/components/Composer/Layer/AudienceLayer/AudienceLayer.js +18 -6
- package/lib/esm/components/EditGroupButton/EditGroupButton.js +5 -1
- package/lib/esm/components/FeedObject/FeedObject.d.ts +1 -0
- package/lib/esm/components/FeedObject/FeedObject.js +24 -7
- package/lib/esm/components/FeedUpdatesWidget/FeedUpdatesWidget.js +1 -1
- package/lib/esm/components/Group/Group.js +11 -5
- package/lib/esm/components/GroupForm/GroupForm.js +31 -9
- package/lib/esm/components/GroupHeader/GroupHeader.d.ts +6 -5
- package/lib/esm/components/GroupHeader/GroupHeader.js +54 -13
- package/lib/esm/components/GroupHeader/Skeleton.d.ts +2 -4
- package/lib/esm/components/GroupHeader/Skeleton.js +10 -10
- package/lib/esm/components/GroupInfoWidget/GroupInfoWidget.js +40 -7
- package/lib/esm/components/GroupInviteButton/GroupInviteButton.js +8 -7
- package/lib/esm/components/GroupMembersButton/GroupMembersButton.d.ts +5 -0
- package/lib/esm/components/GroupMembersButton/GroupMembersButton.js +8 -3
- package/lib/esm/components/GroupMembersWidget/GroupMembersWidget.js +31 -6
- package/lib/esm/components/GroupRequestsWidget/GroupRequestsWidget.d.ts +11 -5
- package/lib/esm/components/GroupRequestsWidget/GroupRequestsWidget.js +18 -7
- package/lib/esm/components/GroupSettingsIconButton/GroupSettingsIconButton.d.ts +48 -0
- package/lib/esm/components/GroupSettingsIconButton/GroupSettingsIconButton.js +142 -0
- package/lib/esm/components/GroupSettingsIconButton/index.d.ts +3 -0
- package/lib/esm/components/GroupSettingsIconButton/index.js +2 -0
- package/lib/esm/components/GroupSubscribeButton/GroupSubscribeButton.d.ts +8 -3
- package/lib/esm/components/GroupSubscribeButton/GroupSubscribeButton.js +32 -11
- package/lib/esm/components/Groups/Groups.d.ts +28 -13
- package/lib/esm/components/Groups/Groups.js +76 -94
- package/lib/esm/components/NavigationMenuIconButton/NavigationMenuIconButton.js +1 -1
- package/lib/esm/components/NavigationToolbarMobile/NavigationToolbarMobile.d.ts +4 -0
- package/lib/esm/components/NavigationToolbarMobile/NavigationToolbarMobile.js +2 -3
- package/lib/esm/components/Notification/Group/Group.d.ts +15 -0
- package/lib/esm/components/Notification/Group/Group.js +75 -0
- package/lib/esm/components/Notification/Group/index.d.ts +3 -0
- package/lib/esm/components/Notification/Group/index.js +2 -0
- package/lib/esm/components/Notification/Notification.js +31 -1
- package/lib/esm/components/Notification/PrivateMessage/PrivateMessage.js +16 -5
- package/lib/esm/components/PrivateMessageComponent/PrivateMessageComponent.d.ts +1 -1
- package/lib/esm/components/PrivateMessageComponent/PrivateMessageComponent.js +11 -8
- package/lib/esm/components/PrivateMessageSnippetItem/PrivateMessageSnippetItem.js +11 -6
- package/lib/esm/components/PrivateMessageSnippets/PrivateMessageSnippets.d.ts +3 -3
- package/lib/esm/components/PrivateMessageSnippets/PrivateMessageSnippets.js +26 -8
- package/lib/esm/components/PrivateMessageThread/PrivateMessageThread.d.ts +6 -1
- package/lib/esm/components/PrivateMessageThread/PrivateMessageThread.js +47 -22
- package/lib/esm/components/SearchAutocomplete/SearchAutocomplete.js +22 -5
- package/lib/esm/components/SnippetNotifications/SnippetNotifications.js +7 -0
- package/lib/esm/components/ToastNotifications/ToastNotifications.js +7 -0
- package/lib/esm/constants/PubSub.d.ts +27 -0
- package/lib/esm/constants/PubSub.js +18 -0
- package/lib/esm/index.d.ts +4 -2
- package/lib/esm/index.js +6 -4
- package/lib/umd/react-ui.js +1 -1
- package/package.json +6 -6
|
@@ -2,7 +2,7 @@ import { __rest } from "tslib";
|
|
|
2
2
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import { styled } from '@mui/material/styles';
|
|
4
4
|
import CardContent from '@mui/material/CardContent';
|
|
5
|
-
import { Avatar, Box, Button, CardActions, CardHeader, Collapse, Stack, Tooltip, Typography } from '@mui/material';
|
|
5
|
+
import { Avatar, Box, Button, CardActions, CardHeader, Chip, Collapse, Stack, Tooltip, Typography } from '@mui/material';
|
|
6
6
|
import FeedObjectSkeleton from './Skeleton';
|
|
7
7
|
import DateTimeAgo from '../../shared/DateTimeAgo';
|
|
8
8
|
import Bullet from '../../shared/Bullet';
|
|
@@ -40,6 +40,10 @@ const messages = defineMessages({
|
|
|
40
40
|
visibleToAll: {
|
|
41
41
|
id: 'ui.feedObject.visibleToAll',
|
|
42
42
|
defaultMessage: 'ui.feedObject.visibleToAll'
|
|
43
|
+
},
|
|
44
|
+
visibleToGroup: {
|
|
45
|
+
id: 'ui.feedObject.visibleToGroup',
|
|
46
|
+
defaultMessage: 'ui.feedObject.visibleToGroup'
|
|
43
47
|
}
|
|
44
48
|
});
|
|
45
49
|
const classes = {
|
|
@@ -47,6 +51,7 @@ const classes = {
|
|
|
47
51
|
deleted: `${PREFIX}-deleted`,
|
|
48
52
|
header: `${PREFIX}-header`,
|
|
49
53
|
category: `${PREFIX}-category`,
|
|
54
|
+
group: `${PREFIX}-group`,
|
|
50
55
|
avatar: `${PREFIX}-avatar`,
|
|
51
56
|
username: `${PREFIX}-username`,
|
|
52
57
|
activityAt: `${PREFIX}-activity-at`,
|
|
@@ -100,6 +105,7 @@ const Root = styled(Widget, {
|
|
|
100
105
|
|deleted|.SCFeedObject-deleted|Styles applied to the feed obj when is deleted (visible only for admin and moderator).|
|
|
101
106
|
|header|.SCFeedObject-header|Styles applied to the header of the card.|
|
|
102
107
|
|category|.SCFeedObject-category|Styles applied to the category element.|
|
|
108
|
+
|group|.SCFeedObject-group|Styles applied to the group element.|
|
|
103
109
|
|avatar|.SCFeedObject-avatar|Styles applied to the avatar element.|
|
|
104
110
|
|username|.SCFeedObject-username|Styles applied to the username element.|
|
|
105
111
|
|activityAt|.SCFeedObject-activity-at|Styles applied to the activity at section.|
|
|
@@ -167,7 +173,7 @@ export default function FeedObject(inProps) {
|
|
|
167
173
|
}, [onStateChange, onHeightChange]);
|
|
168
174
|
/**
|
|
169
175
|
* Update state object
|
|
170
|
-
* @param
|
|
176
|
+
* @param newObj
|
|
171
177
|
*/
|
|
172
178
|
const updateObject = (newObj) => {
|
|
173
179
|
setObj(newObj);
|
|
@@ -424,8 +430,13 @@ export default function FeedObject(inProps) {
|
|
|
424
430
|
template === SCFeedObjectTemplateType.DETAIL ||
|
|
425
431
|
template === SCFeedObjectTemplateType.SEARCH) {
|
|
426
432
|
objElement = (React.createElement(React.Fragment, null, obj ? (React.createElement(Box, { className: classNames({ [classes.deleted]: obj && obj.deleted }) },
|
|
427
|
-
obj.categories.length > 0 && (React.createElement("div", { className: classes.category },
|
|
428
|
-
React.createElement(
|
|
433
|
+
obj.categories.length > 0 && (React.createElement("div", { className: classes.category },
|
|
434
|
+
React.createElement(React.Fragment, null, obj.group && (React.createElement("div", { className: classes.group },
|
|
435
|
+
React.createElement(Chip, { color: "secondary", size: "small", key: obj.group.id, icon: React.createElement(Icon, null, "groups"), component: Link, to: scRoutingContext.url(SCRoutes.GROUP_ROUTE_NAME, obj.group), clickable: true })))),
|
|
436
|
+
obj.categories.map((c) => (React.createElement(Link, { to: scRoutingContext.url(SCRoutes.CATEGORY_ROUTE_NAME, c), key: c.id },
|
|
437
|
+
React.createElement(Typography, { variant: "overline" }, c.name)))))),
|
|
438
|
+
obj.group && !obj.categories.length && (React.createElement("div", { className: classes.group },
|
|
439
|
+
React.createElement(Chip, { color: "secondary", size: "small", key: obj.group.id, icon: React.createElement(Icon, null, "groups"), label: obj.group.name, component: Link, to: scRoutingContext.url(SCRoutes.GROUP_ROUTE_NAME, obj.group), clickable: true }))),
|
|
429
440
|
React.createElement(CardHeader, { className: classes.header, avatar: React.createElement(Link, Object.assign({}, (!obj.author.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, obj.author) }), { onClick: obj.author.deleted ? () => setOpenAlert(true) : null }),
|
|
430
441
|
React.createElement(UserAvatar, { hide: !obj.author.community_badge },
|
|
431
442
|
React.createElement(Avatar, { "aria-label": "recipe", src: obj.author.avatar, className: classes.avatar }, obj.author.username))), title: React.createElement(Link, Object.assign({}, (!obj.author.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, obj.author) }), { onClick: obj.author.deleted ? () => setOpenAlert(true) : null, className: classes.username }), obj.author.username), subheader: React.createElement(React.Fragment, null,
|
|
@@ -437,7 +448,8 @@ export default function FeedObject(inProps) {
|
|
|
437
448
|
React.createElement(Icon, null, "add_location_alt"), (_a = obj.location) === null || _a === void 0 ? void 0 :
|
|
438
449
|
_a.location))),
|
|
439
450
|
React.createElement(Bullet, null),
|
|
440
|
-
React.createElement(Box, { className: classes.tag }, obj.addressing.length > 0 ? (React.createElement(Tags, { tags: obj.addressing, TagChipProps: { disposable: false, clickable: false } })) : (React.createElement(Tooltip, { title: `${intl.formatMessage(messages.
|
|
451
|
+
React.createElement(Box, { className: classes.tag }, obj.addressing.length > 0 ? (React.createElement(Tags, { tags: obj.addressing, TagChipProps: { disposable: false, clickable: false } })) : obj.group ? (React.createElement(Tooltip, { title: `${intl.formatMessage(messages.visibleToGroup, { group: obj.group.name })}` },
|
|
452
|
+
React.createElement(Icon, { color: "disabled", fontSize: "small" }, "groups"))) : (React.createElement(Tooltip, { title: `${intl.formatMessage(messages.visibleToAll)}` },
|
|
441
453
|
React.createElement(Icon, { color: "disabled", fontSize: "small" }, "public"))))), action: renderHeaderAction() }),
|
|
442
454
|
React.createElement(CardContent, { classes: { root: classes.content } },
|
|
443
455
|
React.createElement(Box, { className: classes.titleSection }, 'title' in obj && (React.createElement(React.Fragment, null, template === SCFeedObjectTemplateType.DETAIL ? (React.createElement(Typography, { variant: "body1", gutterBottom: true, className: classes.title }, obj.title)) : (React.createElement(Link, { to: scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj)) },
|
|
@@ -466,8 +478,13 @@ export default function FeedObject(inProps) {
|
|
|
466
478
|
}
|
|
467
479
|
else if (template === SCFeedObjectTemplateType.SHARE) {
|
|
468
480
|
objElement = (React.createElement(React.Fragment, null, obj ? (React.createElement(React.Fragment, null,
|
|
469
|
-
obj.categories.length > 0 && (React.createElement("div", { className: classes.category },
|
|
470
|
-
React.createElement(
|
|
481
|
+
obj.categories.length > 0 && (React.createElement("div", { className: classes.category },
|
|
482
|
+
React.createElement(React.Fragment, null, obj.group && (React.createElement("div", { className: classes.group },
|
|
483
|
+
React.createElement(Chip, { color: "secondary", size: "small", key: obj.group.id, icon: React.createElement(Icon, null, "groups"), component: Link, to: scRoutingContext.url(SCRoutes.GROUP_ROUTE_NAME, obj.group), clickable: true })))),
|
|
484
|
+
obj.categories.map((c) => (React.createElement(Link, { to: scRoutingContext.url(SCRoutes.CATEGORY_ROUTE_NAME, c), key: c.id },
|
|
485
|
+
React.createElement(Typography, { variant: "overline" }, c.name)))))),
|
|
486
|
+
obj.group && !obj.categories.length && (React.createElement("div", { className: classes.group },
|
|
487
|
+
React.createElement(Chip, { color: "secondary", size: "small", key: obj.group.id, icon: React.createElement(Icon, null, "groups"), label: obj.group.name, component: Link, to: scRoutingContext.url(SCRoutes.GROUP_ROUTE_NAME, obj.group), clickable: true }))),
|
|
471
488
|
React.createElement(CardHeader, { classes: { root: classes.header }, avatar: React.createElement(Link, Object.assign({}, (!obj.author.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, obj.author) }), { onClick: obj.author.deleted ? () => setOpenAlert(true) : null, className: classes.username }),
|
|
472
489
|
React.createElement(UserAvatar, { hide: !obj.author.community_badge },
|
|
473
490
|
React.createElement(Avatar, { "aria-label": "recipe", src: obj.author.avatar, className: classes.avatar }, obj.author.username))), title: React.createElement(Link, Object.assign({}, (!obj.author.deleted && { to: scRoutingContext.url(SCRoutes.USER_PROFILE_ROUTE_NAME, obj.author) }), { onClick: obj.author.deleted ? () => setOpenAlert(true) : null, className: classes.username }), obj.author.username), subheader: React.createElement(Link, { to: scRoutingContext.url(getContributionRouteName(obj), getRouteData(obj)), className: classes.activityAt },
|
|
@@ -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);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { __rest } from "tslib";
|
|
2
|
-
import React, { useState } from 'react';
|
|
2
|
+
import React, { useMemo, useState } from 'react';
|
|
3
3
|
import { styled } from '@mui/material/styles';
|
|
4
4
|
import { Avatar, Icon, Stack } from '@mui/material';
|
|
5
|
-
import {
|
|
5
|
+
import { SCGroupPrivacyType } from '@selfcommunity/types';
|
|
6
|
+
import { Link, SCRoutes, useSCFetchGroup, useSCRouting, useSCUser } from '@selfcommunity/react-core';
|
|
6
7
|
import { defineMessages, useIntl } from 'react-intl';
|
|
7
8
|
import classNames from 'classnames';
|
|
8
9
|
import { useThemeProps } from '@mui/system';
|
|
@@ -56,16 +57,20 @@ const Root = styled(BaseItemButton, {
|
|
|
56
57
|
* @param inProps
|
|
57
58
|
*/
|
|
58
59
|
export default function Group(inProps) {
|
|
60
|
+
var _a;
|
|
59
61
|
// PROPS
|
|
60
62
|
const props = useThemeProps({
|
|
61
63
|
props: inProps,
|
|
62
64
|
name: PREFIX
|
|
63
65
|
});
|
|
64
|
-
const { groupId = null, group = null, className = null, elevation, hideActions = false, groupSubscribeButtonProps = {}
|
|
66
|
+
const { groupId = null, group = null, className = null, elevation, hideActions = false, groupSubscribeButtonProps = {} } = props, rest = __rest(props, ["groupId", "group", "className", "elevation", "hideActions", "groupSubscribeButtonProps"]);
|
|
65
67
|
// STATE
|
|
66
68
|
const { scGroup } = useSCFetchGroup({ id: groupId, group });
|
|
67
69
|
// CONTEXT
|
|
68
70
|
const scRoutingContext = useSCRouting();
|
|
71
|
+
const scUserContext = useSCUser();
|
|
72
|
+
// CONST
|
|
73
|
+
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]);
|
|
69
74
|
const [openAlert, setOpenAlert] = useState(false);
|
|
70
75
|
// INTL
|
|
71
76
|
const intl = useIntl();
|
|
@@ -75,7 +80,8 @@ export default function Group(inProps) {
|
|
|
75
80
|
*/
|
|
76
81
|
function renderAuthenticatedActions() {
|
|
77
82
|
return (React.createElement(Stack, { className: classes.actions, direction: "row", alignItems: "center", justifyContent: "center", spacing: 2 },
|
|
78
|
-
React.createElement(Icon, null,
|
|
83
|
+
React.createElement(Icon, null, (group === null || group === void 0 ? void 0 : group.privacy) === SCGroupPrivacyType.PRIVATE ? 'private' : 'public'),
|
|
84
|
+
isGroupAdmin && React.createElement(Icon, null, "face"),
|
|
79
85
|
React.createElement(GroupSubscribeButton, Object.assign({ group: group, groupId: groupId }, groupSubscribeButtonProps))));
|
|
80
86
|
}
|
|
81
87
|
/**
|
|
@@ -88,6 +94,6 @@ export default function Group(inProps) {
|
|
|
88
94
|
* Renders root object
|
|
89
95
|
*/
|
|
90
96
|
return (React.createElement(React.Fragment, null,
|
|
91
|
-
React.createElement(Root, Object.assign({ elevation: elevation }, rest, { className: classNames(classes.root, className), ButtonBaseProps:
|
|
97
|
+
React.createElement(Root, Object.assign({ elevation: elevation }, rest, { className: classNames(classes.root, className), ButtonBaseProps: { component: Link, to: scRoutingContext.url(SCRoutes.GROUP_ROUTE_NAME, scGroup) }, image: React.createElement(Avatar, { alt: scGroup.name, src: scGroup.image_medium, className: classes.avatar }), primary: scGroup.name, secondary: `${intl.formatMessage(messages.groupMembers, { total: scGroup.subscribers_counter })}`, actions: hideActions ? null : renderAuthenticatedActions() })),
|
|
92
98
|
openAlert && React.createElement(UserDeletedSnackBar, { open: openAlert, handleClose: () => setOpenAlert(false) })));
|
|
93
99
|
}
|
|
@@ -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();
|
|
@@ -153,8 +171,10 @@ export default function GroupForm(inProps) {
|
|
|
153
171
|
if (field.emotionalImageOriginalFile) {
|
|
154
172
|
formData.append('emotional_image_original', field.emotionalImageOriginalFile);
|
|
155
173
|
}
|
|
156
|
-
|
|
157
|
-
|
|
174
|
+
if (!group) {
|
|
175
|
+
for (const key in field.invitedUsers) {
|
|
176
|
+
formData.append(key, field.invitedUsers[key]);
|
|
177
|
+
}
|
|
158
178
|
}
|
|
159
179
|
let groupService;
|
|
160
180
|
if (group) {
|
|
@@ -166,6 +186,7 @@ export default function GroupForm(inProps) {
|
|
|
166
186
|
groupService
|
|
167
187
|
.then((data) => {
|
|
168
188
|
onSuccess && onSuccess(data);
|
|
189
|
+
notifyChanges(data);
|
|
169
190
|
onClose && onClose();
|
|
170
191
|
setField((prev) => (Object.assign(Object.assign({}, prev), { ['isSubmitting']: false })));
|
|
171
192
|
})
|
|
@@ -213,24 +234,25 @@ export default function GroupForm(inProps) {
|
|
|
213
234
|
React.createElement(Typography, { className: classNames(classes.switchLabel, { [classes.active]: !field.isPublic }) },
|
|
214
235
|
React.createElement(Icon, null, "private"),
|
|
215
236
|
React.createElement(FormattedMessage, { id: "ui.groupForm.privacy.private", defaultMessage: "ui.groupForm.privacy.private" })),
|
|
216
|
-
React.createElement(Switch, { className: classes.switch, checked: field.isPublic,
|
|
237
|
+
React.createElement(Switch, { className: classes.switch, checked: field.isPublic, onChange: () => setField((prev) => (Object.assign(Object.assign({}, prev), { ['isPublic']: !field.isPublic }))), disabled: group && group.privacy === SCGroupPrivacyType.PRIVATE }),
|
|
217
238
|
React.createElement(Typography, { className: classNames(classes.switchLabel, { [classes.active]: field.isPublic }) },
|
|
218
239
|
React.createElement(Icon, null, "public"),
|
|
219
240
|
React.createElement(FormattedMessage, { id: "ui.groupForm.privacy.public", defaultMessage: "ui.groupForm.privacy.public" }))),
|
|
220
|
-
React.createElement(Typography, { variant: "body2", className: classes.privacySectionInfo }, field.isPublic ? (React.createElement(FormattedMessage, { id: "ui.groupForm.privacy.public.info", defaultMessage: "ui.groupForm.privacy.public.info", values: { b: (chunks) => React.createElement("strong", null, chunks) } })) : (React.createElement(FormattedMessage, { id: "ui.groupForm.privacy.private.info", defaultMessage: "ui.groupForm.private.public.info", values: { b: (chunks) => React.createElement("strong", null, chunks) } })))),
|
|
221
|
-
React.createElement(Box, { className: classes.visibilitySection }, !field.isPublic && (React.createElement(React.Fragment, null,
|
|
241
|
+
React.createElement(Typography, { variant: "body2", className: classes.privacySectionInfo }, field.isPublic ? (React.createElement(FormattedMessage, { id: "ui.groupForm.privacy.public.info", defaultMessage: "ui.groupForm.privacy.public.info", values: { b: (chunks) => React.createElement("strong", null, chunks) } })) : (React.createElement(React.Fragment, null, group && group.privacy === SCGroupPrivacyType.PRIVATE ? (React.createElement(FormattedMessage, { id: "ui.groupForm.privacy.private.info.edit", defaultMessage: "ui.groupForm.private.public.info.edit", values: { b: (chunks) => React.createElement("strong", null, chunks) } })) : (React.createElement(FormattedMessage, { id: "ui.groupForm.privacy.private.info", defaultMessage: "ui.groupForm.private.public.info", values: { b: (chunks) => React.createElement("strong", null, chunks) } })))))),
|
|
242
|
+
React.createElement(Box, { className: classes.visibilitySection }, ((!field.isPublic && !group) || (group && !field.isPublic)) && (React.createElement(React.Fragment, null,
|
|
222
243
|
React.createElement(Typography, { variant: "h4" },
|
|
223
244
|
React.createElement(FormattedMessage, { id: "ui.groupForm.visibility.title", defaultMessage: "ui.groupForm.visibility.title", values: { b: (chunks) => React.createElement("strong", null, chunks) } })),
|
|
224
245
|
React.createElement(Stack, { direction: "row", spacing: 1, alignItems: "center" },
|
|
225
246
|
React.createElement(Typography, { className: classNames(classes.switchLabel, { [classes.active]: !field.isVisible }) },
|
|
226
247
|
React.createElement(Icon, null, "visibility_off"),
|
|
227
248
|
React.createElement(FormattedMessage, { id: "ui.groupForm.visibility.hidden", defaultMessage: "ui.groupForm.visibility.hidden" })),
|
|
228
|
-
React.createElement(Switch, { className: classes.switch, checked: field.isVisible,
|
|
249
|
+
React.createElement(Switch, { className: classes.switch, checked: field.isVisible, onChange: () => setField((prev) => (Object.assign(Object.assign({}, prev), { ['isVisible']: !field.isVisible }))) }),
|
|
229
250
|
React.createElement(Typography, { className: classNames(classes.switchLabel, { [classes.active]: field.isVisible }) },
|
|
230
251
|
React.createElement(Icon, null, "visibility"),
|
|
231
252
|
React.createElement(FormattedMessage, { id: "ui.groupForm.visibility.visible", defaultMessage: "ui.groupForm.visibility.visible" }))),
|
|
232
253
|
React.createElement(Typography, { variant: "body2", className: classes.visibilitySectionInfo }, !field.isVisible ? (React.createElement(FormattedMessage, { id: "ui.groupForm.visibility.hidden.info", defaultMessage: "ui.groupForm.visibility.hidden.info", values: { b: (chunks) => React.createElement("strong", null, chunks) } })) : (React.createElement(FormattedMessage, { id: "ui.groupForm.visibility.visible.info", defaultMessage: "ui.groupForm.visibility.visible.info", values: { b: (chunks) => React.createElement("strong", null, chunks) } }))))))),
|
|
233
|
-
React.createElement(
|
|
234
|
-
|
|
235
|
-
React.createElement(
|
|
254
|
+
!group && (React.createElement(React.Fragment, null,
|
|
255
|
+
React.createElement(Divider, null),
|
|
256
|
+
React.createElement(Box, { className: classes.inviteSection },
|
|
257
|
+
React.createElement(GroupInviteButton, { handleInvitations: handleInviteSection })))))));
|
|
236
258
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import { SCGroupType } from '@selfcommunity/types';
|
|
3
2
|
import { ChangeGroupCoverProps } from '../ChangeGroupCover';
|
|
4
3
|
import { ChangeGroupPictureProps } from '../ChangeGroupPicture';
|
|
5
4
|
import { GroupMembersButtonProps } from '../GroupMembersButton';
|
|
5
|
+
import { GroupSubscribeButtonProps } from '../GroupSubscribeButton';
|
|
6
6
|
export interface GroupHeaderProps {
|
|
7
7
|
/**
|
|
8
8
|
* Id of group object
|
|
@@ -35,14 +35,15 @@ export interface GroupHeaderProps {
|
|
|
35
35
|
*/
|
|
36
36
|
ChangeCoverProps?: ChangeGroupCoverProps;
|
|
37
37
|
/**
|
|
38
|
-
* Props to spread
|
|
38
|
+
* Props to spread group button followed
|
|
39
39
|
* @default {}
|
|
40
40
|
*/
|
|
41
|
-
|
|
41
|
+
GroupSubscribeButtonProps?: GroupSubscribeButtonProps;
|
|
42
42
|
/**
|
|
43
|
-
*
|
|
43
|
+
* Props to spread to the group memebers button
|
|
44
|
+
* @default {}
|
|
44
45
|
*/
|
|
45
|
-
|
|
46
|
+
GroupMembersButtonProps?: GroupMembersButtonProps;
|
|
46
47
|
/**
|
|
47
48
|
* Any other properties
|
|
48
49
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
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
|
-
import { SCGroupPrivacyType } from '@selfcommunity/types';
|
|
5
|
+
import { SCGroupPrivacyType, SCGroupSubscriptionStatusType } from '@selfcommunity/types';
|
|
6
6
|
import { SCPreferences, useSCFetchGroup, useSCPreferences, useSCUser } from '@selfcommunity/react-core';
|
|
7
7
|
import GroupHeaderSkeleton from './Skeleton';
|
|
8
8
|
import classNames from 'classnames';
|
|
@@ -14,6 +14,10 @@ import Bullet from '../../shared/Bullet';
|
|
|
14
14
|
import ChangeGroupPicture from '../ChangeGroupPicture';
|
|
15
15
|
import GroupMembersButton from '../GroupMembersButton';
|
|
16
16
|
import EditGroupButton from '../EditGroupButton';
|
|
17
|
+
import GroupSubscribeButton from '../GroupSubscribeButton';
|
|
18
|
+
import GroupInviteButton from '../GroupInviteButton';
|
|
19
|
+
import { SCEventType, SCTopicType } from '../../constants/PubSub';
|
|
20
|
+
import PubSub from 'pubsub-js';
|
|
17
21
|
const classes = {
|
|
18
22
|
root: `${PREFIX}-root`,
|
|
19
23
|
cover: `${PREFIX}-cover`,
|
|
@@ -70,22 +74,24 @@ export default function GroupHeader(inProps) {
|
|
|
70
74
|
props: inProps,
|
|
71
75
|
name: PREFIX
|
|
72
76
|
});
|
|
73
|
-
const { id = null, className = null, group, groupId = null, ChangePictureProps = {}, ChangeCoverProps = {},
|
|
77
|
+
const { id = null, className = null, group, groupId = null, ChangePictureProps = {}, ChangeCoverProps = {}, GroupSubscribeButtonProps = {}, GroupMembersButtonProps = {} } = props, rest = __rest(props, ["id", "className", "group", "groupId", "ChangePictureProps", "ChangeCoverProps", "GroupSubscribeButtonProps", "GroupMembersButtonProps"]);
|
|
74
78
|
// PREFERENCES
|
|
75
79
|
const scPreferences = useSCPreferences();
|
|
76
80
|
// CONTEXT
|
|
77
81
|
const scUserContext = useSCUser();
|
|
78
82
|
// HOOKS
|
|
79
83
|
const { scGroup, setSCGroup } = useSCFetchGroup({ id: groupId, group });
|
|
84
|
+
// REFS
|
|
85
|
+
const updatesSubscription = useRef(null);
|
|
80
86
|
// CONST
|
|
81
|
-
const
|
|
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]);
|
|
82
88
|
/**
|
|
83
89
|
* Handles Change Avatar
|
|
84
90
|
* @param avatar
|
|
85
91
|
*/
|
|
86
92
|
function handleChangeAvatar(avatar) {
|
|
87
|
-
if (
|
|
88
|
-
setSCGroup(Object.assign({}, scGroup, {
|
|
93
|
+
if (isGroupAdmin) {
|
|
94
|
+
setSCGroup(Object.assign({}, scGroup, { image_big: avatar }));
|
|
89
95
|
}
|
|
90
96
|
}
|
|
91
97
|
/**
|
|
@@ -93,10 +99,43 @@ export default function GroupHeader(inProps) {
|
|
|
93
99
|
* @param cover
|
|
94
100
|
*/
|
|
95
101
|
function handleChangeCover(cover) {
|
|
96
|
-
if (
|
|
102
|
+
if (isGroupAdmin) {
|
|
97
103
|
setSCGroup(Object.assign({}, scGroup, { emotional_image: cover }));
|
|
98
104
|
}
|
|
99
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Handles callback subscribe/unsubscribe group
|
|
108
|
+
*/
|
|
109
|
+
const handleSubscribe = (group, status) => {
|
|
110
|
+
setSCGroup(Object.assign(Object.assign({}, group), { subscribers_counter: group.subscribers_counter + (status ? 1 : -1) }));
|
|
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]);
|
|
100
139
|
// RENDER
|
|
101
140
|
if (!scGroup) {
|
|
102
141
|
return React.createElement(GroupHeaderSkeleton, null);
|
|
@@ -108,13 +147,13 @@ export default function GroupHeader(inProps) {
|
|
|
108
147
|
React.createElement(Paper, { style: _backgroundCover, classes: { root: classes.cover } },
|
|
109
148
|
React.createElement(Box, { className: classes.avatar },
|
|
110
149
|
React.createElement(Avatar, null,
|
|
111
|
-
React.createElement("img", { alt: "group", src: scGroup.
|
|
112
|
-
|
|
150
|
+
React.createElement("img", { alt: "group", src: scGroup.image_big ? scGroup.image_big : '' }))),
|
|
151
|
+
isGroupAdmin && (React.createElement(React.Fragment, null,
|
|
113
152
|
React.createElement(ChangeGroupPicture, Object.assign({ groupId: scGroup.id, onChange: handleChangeAvatar, className: classes.changePicture }, ChangePictureProps)),
|
|
114
153
|
React.createElement("div", { className: classes.changeCover },
|
|
115
154
|
React.createElement(ChangeGroupCover, Object.assign({ groupId: scGroup.id, onChange: handleChangeCover }, ChangeCoverProps)))))),
|
|
116
155
|
React.createElement(Box, { className: classes.info },
|
|
117
|
-
|
|
156
|
+
isGroupAdmin && React.createElement(EditGroupButton, { group: scGroup, groupId: scGroup.id, onEditSuccess: (data) => setSCGroup(data) }),
|
|
118
157
|
React.createElement(Typography, { variant: "h5", className: classes.name }, scGroup.name),
|
|
119
158
|
React.createElement(Box, { className: classes.visibility },
|
|
120
159
|
scGroup.privacy === SCGroupPrivacyType.PUBLIC ? (React.createElement(Typography, { className: classes.visibilityItem },
|
|
@@ -128,9 +167,11 @@ export default function GroupHeader(inProps) {
|
|
|
128
167
|
React.createElement(FormattedMessage, { id: "ui.groupHeader.visibility.visible", defaultMessage: "ui.groupHeader.visibility.visible" }))) : (React.createElement(Typography, { className: classes.visibilityItem },
|
|
129
168
|
React.createElement(Icon, null, "visibility_off"),
|
|
130
169
|
React.createElement(FormattedMessage, { id: "ui.groupHeader.visibility.hidden", defaultMessage: "ui.groupHeader.visibility.hidden" })))),
|
|
131
|
-
React.createElement(
|
|
170
|
+
React.createElement(React.Fragment, null, ((scGroup && scGroup.privacy === SCGroupPrivacyType.PUBLIC) ||
|
|
171
|
+
scGroup.subscription_status === SCGroupSubscriptionStatusType.SUBSCRIBED ||
|
|
172
|
+
isGroupAdmin) && (React.createElement(Box, { className: classes.members },
|
|
132
173
|
React.createElement(Typography, { className: classes.membersCounter, component: "div" },
|
|
133
174
|
React.createElement(FormattedMessage, { id: "ui.groupHeader.members", defaultMessage: "ui.groupHeader.members", values: { total: scGroup.subscribers_counter } })),
|
|
134
|
-
React.createElement(GroupMembersButton, Object.assign({ groupId: scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, group: scGroup }, GroupMembersButtonProps))),
|
|
135
|
-
|
|
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))))),
|
|
176
|
+
isGroupAdmin ? (React.createElement(GroupInviteButton, { group: scGroup, groupId: scGroup.id })) : (React.createElement(GroupSubscribeButton, Object.assign({ group: scGroup, onSubscribe: handleSubscribe }, GroupSubscribeButtonProps))))));
|
|
136
177
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* > API documentation for the Community-JS Group
|
|
2
|
+
* > API documentation for the Community-JS Group Header Skeleton component. Learn about the available props and the CSS API.
|
|
3
3
|
|
|
4
4
|
#### Import
|
|
5
5
|
|
|
@@ -18,9 +18,7 @@
|
|
|
18
18
|
|root|.SCGroupHeader-skeleton-root|Styles applied to the root element.|
|
|
19
19
|
|avatar|.SCGroupHeader-avatar|Styles applied to the avatar element.|
|
|
20
20
|
|cover|.SCGroupHeader-cover|Styles applied to the cover element.|
|
|
21
|
-
|
|
|
22
|
-
|section|.SCGroupHeader-section|Styles applied to the info section.|
|
|
23
|
-
|username|.SCGroupHeader-username|Styles applied to the username element.|
|
|
21
|
+
|info|.SCGroupHeader-info|Styles applied to the info info.|
|
|
24
22
|
*
|
|
25
23
|
*/
|
|
26
24
|
declare function GroupHeaderSkeleton(): JSX.Element;
|
|
@@ -7,16 +7,14 @@ const classes = {
|
|
|
7
7
|
root: `${PREFIX}-skeleton-root`,
|
|
8
8
|
cover: `${PREFIX}-cover`,
|
|
9
9
|
avatar: `${PREFIX}-avatar`,
|
|
10
|
-
|
|
11
|
-
section: `${PREFIX}-section`,
|
|
12
|
-
username: `${PREFIX}-username`
|
|
10
|
+
info: `${PREFIX}-info`
|
|
13
11
|
};
|
|
14
12
|
const Root = styled(Box, {
|
|
15
13
|
name: PREFIX,
|
|
16
14
|
slot: 'SkeletonRoot'
|
|
17
15
|
})(() => ({}));
|
|
18
16
|
/**
|
|
19
|
-
* > API documentation for the Community-JS Group
|
|
17
|
+
* > API documentation for the Community-JS Group Header Skeleton component. Learn about the available props and the CSS API.
|
|
20
18
|
|
|
21
19
|
#### Import
|
|
22
20
|
|
|
@@ -35,9 +33,7 @@ const Root = styled(Box, {
|
|
|
35
33
|
|root|.SCGroupHeader-skeleton-root|Styles applied to the root element.|
|
|
36
34
|
|avatar|.SCGroupHeader-avatar|Styles applied to the avatar element.|
|
|
37
35
|
|cover|.SCGroupHeader-cover|Styles applied to the cover element.|
|
|
38
|
-
|
|
|
39
|
-
|section|.SCGroupHeader-section|Styles applied to the info section.|
|
|
40
|
-
|username|.SCGroupHeader-username|Styles applied to the username element.|
|
|
36
|
+
|info|.SCGroupHeader-info|Styles applied to the info info.|
|
|
41
37
|
*
|
|
42
38
|
*/
|
|
43
39
|
function GroupHeaderSkeleton() {
|
|
@@ -46,8 +42,12 @@ function GroupHeaderSkeleton() {
|
|
|
46
42
|
React.createElement(Skeleton, { className: classes.cover, animation: "wave", variant: "rectangular" }),
|
|
47
43
|
React.createElement(Box, { className: classes.avatar },
|
|
48
44
|
React.createElement(Skeleton, { animation: "wave", variant: "circular", width: theme.selfcommunity.group.avatar.sizeLarge, height: theme.selfcommunity.group.avatar.sizeLarge })),
|
|
49
|
-
React.createElement(Box, { className: classes.
|
|
50
|
-
React.createElement(Typography, { variant: "h5"
|
|
51
|
-
React.createElement(Skeleton, { animation: "wave", sx: { height: 30, width:
|
|
45
|
+
React.createElement(Box, { className: classes.info },
|
|
46
|
+
React.createElement(Typography, { variant: "h5" },
|
|
47
|
+
React.createElement(Skeleton, { animation: "wave", sx: { height: 30, width: 200 } })),
|
|
48
|
+
React.createElement(Typography, null,
|
|
49
|
+
React.createElement(Skeleton, { animation: "wave", sx: { height: 20, width: 150 } })),
|
|
50
|
+
React.createElement(Typography, null,
|
|
51
|
+
React.createElement(Skeleton, { animation: "wave", sx: { height: 20, width: 100 } })))));
|
|
52
52
|
}
|
|
53
53
|
export default GroupHeaderSkeleton;
|
|
@@ -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,7 +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';
|
|
13
|
+
import GroupInfoWidgetSkeleton from './Skeleton';
|
|
14
|
+
import { SCEventType, SCTopicType } from '../../constants/PubSub';
|
|
12
15
|
const classes = {
|
|
13
16
|
root: `${PREFIX}-root`,
|
|
14
17
|
title: `${PREFIX}-title`,
|
|
@@ -17,6 +20,7 @@ const classes = {
|
|
|
17
20
|
privacyTitle: `${PREFIX}-privacy-title`,
|
|
18
21
|
visibility: `${PREFIX}-visibility`,
|
|
19
22
|
visibilityTitle: `${PREFIX}-visibility-title`,
|
|
23
|
+
admin: `${PREFIX}-admin`,
|
|
20
24
|
date: `${PREFIX}-date`
|
|
21
25
|
};
|
|
22
26
|
const Root = styled(Widget, {
|
|
@@ -59,9 +63,36 @@ export default function GroupInfoWidget(inProps) {
|
|
|
59
63
|
});
|
|
60
64
|
const { className, group, groupId, onHeightChange, onStateChange } = props, rest = __rest(props, ["className", "group", "groupId", "onHeightChange", "onStateChange"]);
|
|
61
65
|
// HOOKS
|
|
62
|
-
const { scGroup } = useSCFetchGroup({ id: groupId, group });
|
|
66
|
+
const { scGroup, setSCGroup } = useSCFetchGroup({ id: groupId, group });
|
|
63
67
|
// INTL
|
|
64
68
|
const intl = useIntl();
|
|
69
|
+
// REFS
|
|
70
|
+
const updatesSubscription = useRef(null);
|
|
71
|
+
/**
|
|
72
|
+
* Subscriber for pubsub callback
|
|
73
|
+
*/
|
|
74
|
+
const onChangeGroupHandler = useCallback((_msg, data) => {
|
|
75
|
+
if (data && scGroup.id === data.id) {
|
|
76
|
+
setSCGroup(data);
|
|
77
|
+
}
|
|
78
|
+
}, [scGroup, setSCGroup]);
|
|
79
|
+
/**
|
|
80
|
+
* On mount, subscribe to receive groups updates (only edit)
|
|
81
|
+
*/
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (scGroup) {
|
|
84
|
+
updatesSubscription.current = PubSub.subscribe(`${SCTopicType.GROUP}.${SCEventType.EDIT}`, onChangeGroupHandler);
|
|
85
|
+
}
|
|
86
|
+
return () => {
|
|
87
|
+
updatesSubscription.current && PubSub.unsubscribe(updatesSubscription.current);
|
|
88
|
+
};
|
|
89
|
+
}, [scGroup]);
|
|
90
|
+
/**
|
|
91
|
+
* Loading group
|
|
92
|
+
*/
|
|
93
|
+
if (!scGroup) {
|
|
94
|
+
return React.createElement(GroupInfoWidgetSkeleton, null);
|
|
95
|
+
}
|
|
65
96
|
/**
|
|
66
97
|
* Renders root object
|
|
67
98
|
*/
|
|
@@ -73,14 +104,14 @@ export default function GroupInfoWidget(inProps) {
|
|
|
73
104
|
React.createElement(Typography, { component: "div", className: classes.privacy }, scGroup.privacy === SCGroupPrivacyType.PUBLIC ? (React.createElement(React.Fragment, null,
|
|
74
105
|
React.createElement(Typography, { className: classes.privacyTitle },
|
|
75
106
|
React.createElement(Icon, null, "public"),
|
|
76
|
-
React.createElement(FormattedMessage, { id: "ui.
|
|
107
|
+
React.createElement(FormattedMessage, { id: "ui.groupInfoWidget.privacy.public", defaultMessage: "ui.groupInfoWidget.privacy.public" })),
|
|
77
108
|
React.createElement(Typography, { variant: "body2" },
|
|
78
|
-
React.createElement(FormattedMessage, { id: "ui.
|
|
109
|
+
React.createElement(FormattedMessage, { id: "ui.groupInfoWidget.privacy.public.info", defaultMessage: "ui.groupInfoWidget.privacy.public.info", values: { b: (chunks) => React.createElement("strong", null, chunks) } })))) : (React.createElement(React.Fragment, null,
|
|
79
110
|
React.createElement(Typography, { className: classes.privacyTitle },
|
|
80
111
|
React.createElement(Icon, null, "private"),
|
|
81
|
-
React.createElement(FormattedMessage, { id: "ui.
|
|
112
|
+
React.createElement(FormattedMessage, { id: "ui.groupInfoWidget.privacy.private", defaultMessage: "ui.groupInfoWidget.privacy.private" })),
|
|
82
113
|
React.createElement(Typography, { variant: "body2" },
|
|
83
|
-
React.createElement(FormattedMessage, { id: "ui.
|
|
114
|
+
React.createElement(FormattedMessage, { id: "ui.groupInfoWidget.privacy.private.info", defaultMessage: "ui.groupInfoWidget.private.public.info", values: { b: (chunks) => React.createElement("strong", null, chunks) } }))))),
|
|
84
115
|
scGroup.privacy === SCGroupPrivacyType.PRIVATE && (React.createElement(Typography, { component: "div", className: classes.visibility }, scGroup.visible ? (React.createElement(React.Fragment, null,
|
|
85
116
|
React.createElement(Typography, { className: classes.visibilityTitle },
|
|
86
117
|
React.createElement(Icon, null, "visibility"),
|
|
@@ -93,5 +124,7 @@ export default function GroupInfoWidget(inProps) {
|
|
|
93
124
|
React.createElement(Typography, { variant: "body2" },
|
|
94
125
|
React.createElement(FormattedMessage, { id: "ui.groupForm.visibility.hidden.info", defaultMessage: "ui.groupForm.visibility.hidden.info", values: { b: (chunks) => React.createElement("strong", null, chunks) } })))))),
|
|
95
126
|
React.createElement(Typography, { variant: "body2", className: classes.date },
|
|
96
|
-
React.createElement(FormattedMessage, { id: "ui.groupInfoWidget.date", defaultMessage: "ui.groupInfoWidget.date", values: { date: intl.formatDate(scGroup.created_at, { day: 'numeric', year: 'numeric', month: 'long' }) } }))
|
|
127
|
+
React.createElement(FormattedMessage, { id: "ui.groupInfoWidget.date", defaultMessage: "ui.groupInfoWidget.date", values: { date: intl.formatDate(scGroup.created_at, { day: 'numeric', year: 'numeric', month: 'long' }) } })),
|
|
128
|
+
React.createElement(Typography, { variant: "body2", className: classes.admin },
|
|
129
|
+
React.createElement(FormattedMessage, { id: "ui.groupInfoWidget.admin", defaultMessage: "ui.groupInfoWidget.admin", values: { b: (chunks) => React.createElement("strong", null, chunks), admin: scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by.username } })))));
|
|
97
130
|
}
|
|
@@ -89,11 +89,11 @@ export default function GroupInviteButton(inProps) {
|
|
|
89
89
|
const [loading, setLoading] = useState(false);
|
|
90
90
|
const [invited, setInvited] = useState([]);
|
|
91
91
|
function convertToInvitedUsersObject(data) {
|
|
92
|
-
const
|
|
92
|
+
const invite_users = {};
|
|
93
93
|
data.forEach((user, index) => {
|
|
94
|
-
|
|
94
|
+
invite_users[`invite_users[${index}]`] = user.id;
|
|
95
95
|
});
|
|
96
|
-
return
|
|
96
|
+
return invite_users;
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
99
99
|
* Memoized users invited ids
|
|
@@ -108,7 +108,7 @@ export default function GroupInviteButton(inProps) {
|
|
|
108
108
|
}, [invited]);
|
|
109
109
|
// HOOKS
|
|
110
110
|
const { scGroup } = useSCFetchGroup({ id: groupId, group });
|
|
111
|
-
const
|
|
111
|
+
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]);
|
|
112
112
|
// INTL
|
|
113
113
|
const intl = useIntl();
|
|
114
114
|
function fetchResults() {
|
|
@@ -179,6 +179,7 @@ export default function GroupInviteButton(inProps) {
|
|
|
179
179
|
.then(() => {
|
|
180
180
|
setIsSending(false);
|
|
181
181
|
setOpen(false);
|
|
182
|
+
setInvited([]);
|
|
182
183
|
})
|
|
183
184
|
.catch((error) => {
|
|
184
185
|
setOpen(false);
|
|
@@ -223,9 +224,9 @@ export default function GroupInviteButton(inProps) {
|
|
|
223
224
|
setList((prev) => [...prev, option]);
|
|
224
225
|
};
|
|
225
226
|
/**
|
|
226
|
-
* If
|
|
227
|
+
* If in group edit mode and logged-in user is not also the group manager, the component is hidden.
|
|
227
228
|
// */
|
|
228
|
-
if (!
|
|
229
|
+
if (group && !isGroupAdmin) {
|
|
229
230
|
return null;
|
|
230
231
|
}
|
|
231
232
|
/**
|
|
@@ -239,7 +240,7 @@ export default function GroupInviteButton(inProps) {
|
|
|
239
240
|
React.createElement(Icon, { fontSize: "medium" }, "arrow_back")),
|
|
240
241
|
React.createElement(Typography, { className: classes.dialogTitle },
|
|
241
242
|
React.createElement(FormattedMessage, { id: "ui.groupInviteButton.dialog.title", defaultMessage: "ui.groupInviteButton.dialog.title" })),
|
|
242
|
-
React.createElement(LoadingButton, { size: "small", color: "secondary", variant: "contained", onClick: handleSendInvitations, loading: isSending },
|
|
243
|
+
React.createElement(LoadingButton, { size: "small", color: "secondary", variant: "contained", onClick: handleSendInvitations, loading: isSending, disabled: !invited.length },
|
|
243
244
|
React.createElement(FormattedMessage, { id: "ui.groupInviteButton.dialog.button.end", defaultMessage: "ui.groupInviteButton.dialog.button.end" }))) },
|
|
244
245
|
React.createElement(Box, { className: classes.dialogContent },
|
|
245
246
|
React.createElement(Autocomplete, { className: classes.autocomplete, loading: loading, size: "small", multiple: true, freeSolo: true, disableClearable: true, options: suggested, onChange: handleChange, onInputChange: handleInputChange, inputValue: value, value: invited, getOptionLabel: (option) => (option ? option.username : '...'), isOptionEqualToValue: (option, value) => (option ? value.id === option.id : false), renderTags: () => null, renderOption: (props, option) => (React.createElement(Box, Object.assign({ component: "li" }, props),
|