@selfcommunity/react-ui 0.7.9-alpha.54 → 0.7.9-alpha.56

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.
Files changed (44) hide show
  1. package/lib/cjs/components/BottomNavigation/BottomNavigation.js +1 -1
  2. package/lib/cjs/components/FeedObject/Contributors/Contributors.js +1 -1
  3. package/lib/cjs/components/Group/Group.d.ts +5 -0
  4. package/lib/cjs/components/Group/Group.js +2 -2
  5. package/lib/cjs/components/GroupForm/GroupForm.js +2 -1
  6. package/lib/cjs/components/GroupInviteButton/GroupInviteButton.js +48 -13
  7. package/lib/cjs/components/GroupMembersButton/GroupMembersButton.js +1 -1
  8. package/lib/cjs/components/Groups/Groups.js +1 -8
  9. package/lib/cjs/components/NavigationToolbarMobile/NavigationToolbarMobile.d.ts +1 -0
  10. package/lib/cjs/components/NavigationToolbarMobile/NavigationToolbarMobile.js +9 -1
  11. package/lib/cjs/components/UserSubscribedGroupsWidget/Skeleton.d.ts +21 -0
  12. package/lib/cjs/components/UserSubscribedGroupsWidget/Skeleton.js +46 -0
  13. package/lib/cjs/components/UserSubscribedGroupsWidget/UserSubscribedGroupsWidget.d.ts +68 -0
  14. package/lib/cjs/components/UserSubscribedGroupsWidget/UserSubscribedGroupsWidget.js +183 -0
  15. package/lib/cjs/components/UserSubscribedGroupsWidget/constants.d.ts +1 -0
  16. package/lib/cjs/components/UserSubscribedGroupsWidget/constants.js +4 -0
  17. package/lib/cjs/components/UserSubscribedGroupsWidget/index.d.ts +4 -0
  18. package/lib/cjs/components/UserSubscribedGroupsWidget/index.js +8 -0
  19. package/lib/cjs/components/VoteAudienceButton/VoteAudienceButton.js +1 -1
  20. package/lib/cjs/index.d.ts +2 -1
  21. package/lib/cjs/index.js +5 -2
  22. package/lib/esm/components/BottomNavigation/BottomNavigation.js +1 -1
  23. package/lib/esm/components/FeedObject/Contributors/Contributors.js +1 -1
  24. package/lib/esm/components/Group/Group.d.ts +5 -0
  25. package/lib/esm/components/Group/Group.js +4 -4
  26. package/lib/esm/components/GroupForm/GroupForm.js +2 -1
  27. package/lib/esm/components/GroupInviteButton/GroupInviteButton.js +48 -13
  28. package/lib/esm/components/GroupMembersButton/GroupMembersButton.js +1 -1
  29. package/lib/esm/components/Groups/Groups.js +1 -8
  30. package/lib/esm/components/NavigationToolbarMobile/NavigationToolbarMobile.d.ts +1 -0
  31. package/lib/esm/components/NavigationToolbarMobile/NavigationToolbarMobile.js +11 -3
  32. package/lib/esm/components/UserSubscribedGroupsWidget/Skeleton.d.ts +21 -0
  33. package/lib/esm/components/UserSubscribedGroupsWidget/Skeleton.js +42 -0
  34. package/lib/esm/components/UserSubscribedGroupsWidget/UserSubscribedGroupsWidget.d.ts +68 -0
  35. package/lib/esm/components/UserSubscribedGroupsWidget/UserSubscribedGroupsWidget.js +180 -0
  36. package/lib/esm/components/UserSubscribedGroupsWidget/constants.d.ts +1 -0
  37. package/lib/esm/components/UserSubscribedGroupsWidget/constants.js +1 -0
  38. package/lib/esm/components/UserSubscribedGroupsWidget/index.d.ts +4 -0
  39. package/lib/esm/components/UserSubscribedGroupsWidget/index.js +4 -0
  40. package/lib/esm/components/VoteAudienceButton/VoteAudienceButton.js +1 -1
  41. package/lib/esm/index.d.ts +2 -1
  42. package/lib/esm/index.js +2 -1
  43. package/lib/umd/react-ui.js +1 -1
  44. package/package.json +5 -5
@@ -73,7 +73,7 @@ function BottomNavigation(inProps) {
73
73
  preferences[react_core_1.SCPreferences.CONFIGURATIONS_EXPLORE_STREAM_ENABLED].value ? (react_1.default.createElement(material_1.BottomNavigationAction, { key: "explore", className: classes.action, component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.EXPLORE_ROUTE_NAME, {}), value: scRoutingContext.url(react_core_1.SCRoutes.EXPLORE_ROUTE_NAME, {}), icon: react_1.default.createElement(material_1.Icon, null, "explore") })) : null,
74
74
  react_1.default.createElement(material_1.BottomNavigationAction, { key: "composer", className: (0, classnames_1.default)(classes.composer, classes.action), component: ComposerIconButton_1.default, disableRipple: true }),
75
75
  groupsEnabled && scUserContext.user ? (react_1.default.createElement(material_1.BottomNavigationAction, { key: "groups", className: classes.action, component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.GROUPS_ROUTE_NAME, {}), value: scRoutingContext.url(react_core_1.SCRoutes.GROUPS_ROUTE_NAME, {}), icon: react_1.default.createElement(material_1.Icon, null, "groups") })) : null,
76
- scUserContext.user ? (react_1.default.createElement(material_1.BottomNavigationAction, { key: "notifications", className: classes.action, component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}), value: scRoutingContext.url(react_core_1.SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}), icon: react_1.default.createElement(material_1.Badge, { badgeContent: scUserContext.user.unseen_notification_banners_counter + scUserContext.user.unseen_interactions_counter, color: "secondary" },
76
+ scUserContext.user && !groupsEnabled ? (react_1.default.createElement(material_1.BottomNavigationAction, { key: "notifications", className: classes.action, component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}), value: scRoutingContext.url(react_core_1.SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}), icon: react_1.default.createElement(material_1.Badge, { badgeContent: scUserContext.user.unseen_notification_banners_counter + scUserContext.user.unseen_interactions_counter, color: "secondary" },
77
77
  react_1.default.createElement(material_1.Icon, null, "notifications_active")) })) : null,
78
78
  privateMessagingEnabled && scUserContext.user ? (react_1.default.createElement(material_1.BottomNavigationAction, { key: "messages", className: classes.action, component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.USER_PRIVATE_MESSAGES_ROUTE_NAME, {}), value: scRoutingContext.url(react_core_1.SCRoutes.USER_PRIVATE_MESSAGES_ROUTE_NAME, {}), icon: react_1.default.createElement(material_1.Badge, { badgeContent: 0, color: "secondary" },
79
79
  react_1.default.createElement(material_1.Icon, null, "email")) })) : null
@@ -60,6 +60,6 @@ function ContributorsFeedObject(props) {
60
60
  openContributorsDialog && (react_1.default.createElement(BaseDialog_1.default, { title: react_1.default.createElement(react_intl_1.FormattedMessage, { defaultMessage: "ui.feedObject.contributors.title", id: "ui.feedObject.contributors.title", values: { total: contributorsObject.total } }), onClose: () => setOpenContributorsDialog(false), open: openContributorsDialog }, contributorsObject.isLoadingNext ? (react_1.default.createElement(CentralProgress_1.default, { size: 50 })) : (react_1.default.createElement(InfiniteScroll_1.default, { dataLength: contributorsObject.contributors.length, next: contributorsObject.getNextPage(), hasMoreNext: Boolean(contributorsObject.next), loaderNext: react_1.default.createElement(CentralProgress_1.default, { size: 30 }), height: 400, endMessage: react_1.default.createElement(material_1.Typography, { variant: "body2", align: "center", fontWeight: "bold" },
61
61
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.feedObject.contributors.noOtherContributors", defaultMessage: "ui.feedObject.contributors.noOtherContributors" })) },
62
62
  react_1.default.createElement(material_1.List, null, contributorsObject.contributors.map((c, i) => (react_1.default.createElement(material_1.ListItem, { key: i },
63
- react_1.default.createElement(User_1.default, { elevation: 0, user: c, key: c.id, sx: { m: 0 } }))))))))))) : null)))));
63
+ react_1.default.createElement(User_1.default, { elevation: 0, user: c, key: c.id, sx: { m: 0 }, onClick: () => setOpenContributorsDialog(false) }))))))))))) : null)))));
64
64
  }
65
65
  exports.default = ContributorsFeedObject;
@@ -27,6 +27,11 @@ export interface GroupProps extends WidgetProps {
27
27
  * @default false
28
28
  */
29
29
  hideActions?: boolean;
30
+ /**
31
+ * Prop to redirect the user to the group page
32
+ * @default false
33
+ */
34
+ actionRedirect?: boolean;
30
35
  /**
31
36
  * Props to spread to the button
32
37
  * @default {}
@@ -69,7 +69,7 @@ function Group(inProps) {
69
69
  props: inProps,
70
70
  name: constants_1.PREFIX
71
71
  });
72
- const { groupId = null, group = null, className = null, elevation, hideActions = false, groupSubscribeButtonProps = {} } = props, rest = tslib_1.__rest(props, ["groupId", "group", "className", "elevation", "hideActions", "groupSubscribeButtonProps"]);
72
+ const { groupId = null, group = null, className = null, elevation, hideActions = false, actionRedirect = false, groupSubscribeButtonProps = {} } = props, rest = tslib_1.__rest(props, ["groupId", "group", "className", "elevation", "hideActions", "actionRedirect", "groupSubscribeButtonProps"]);
73
73
  // STATE
74
74
  const { scGroup } = (0, react_core_1.useSCFetchGroup)({ id: groupId, group });
75
75
  // CONTEXT
@@ -87,7 +87,7 @@ function Group(inProps) {
87
87
  function renderAuthenticatedActions() {
88
88
  return (react_1.default.createElement(material_1.Stack, { className: classes.actions, direction: "row", alignItems: "center", justifyContent: "center", spacing: 2 },
89
89
  isGroupAdmin && react_1.default.createElement(material_1.Icon, null, "face"),
90
- react_1.default.createElement(GroupSubscribeButton_1.default, Object.assign({ group: group, groupId: groupId }, groupSubscribeButtonProps))));
90
+ actionRedirect ? (react_1.default.createElement(material_1.Button, { size: "small", variant: "outlined", component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.GROUP_ROUTE_NAME, scGroup) }, scGroup.privacy === types_1.SCGroupPrivacyType.PUBLIC ? (react_1.default.createElement(react_intl_1.FormattedMessage, { defaultMessage: "ui.groupSubscribeButton.enter", id: "ui.groupSubscribeButton.enter" })) : (react_1.default.createElement(react_intl_1.FormattedMessage, { defaultMessage: "ui.groupSubscribeButton.requestAccess", id: "ui.groupSubscribeButton.requestAccess" })))) : (react_1.default.createElement(GroupSubscribeButton_1.default, Object.assign({ group: group, groupId: groupId }, groupSubscribeButtonProps)))));
91
91
  }
92
92
  /**
93
93
  * Renders group object
@@ -92,6 +92,7 @@ const Root = (0, styles_1.styled)(BaseDialog_1.default, {
92
92
  * @param inProps
93
93
  */
94
94
  function GroupForm(inProps) {
95
+ var _a;
95
96
  //PROPS
96
97
  const props = (0, system_1.useThemeProps)({
97
98
  props: inProps,
@@ -227,7 +228,7 @@ function GroupForm(inProps) {
227
228
  endAdornment: react_1.default.createElement(material_1.Typography, { variant: "body2" }, Group_1.GROUP_TITLE_MAX_LENGTH - field.name.length)
228
229
  } }),
229
230
  react_1.default.createElement(material_1.TextField, { multiline: true, className: classes.description, placeholder: `${intl.formatMessage(messages.description)}`, margin: "normal", value: field.description, name: "description", onChange: handleChange, InputProps: {
230
- endAdornment: react_1.default.createElement(material_1.Typography, { variant: "body2" }, Group_1.GROUP_DESCRIPTION_MAX_LENGTH - field.description.length)
231
+ endAdornment: (react_1.default.createElement(material_1.Typography, { variant: "body2" }, ((_a = field.description) === null || _a === void 0 ? void 0 : _a.length) ? Group_1.GROUP_DESCRIPTION_MAX_LENGTH - field.description.length : Group_1.GROUP_DESCRIPTION_MAX_LENGTH))
231
232
  } }),
232
233
  react_1.default.createElement(material_1.Box, { className: classes.privacySection },
233
234
  react_1.default.createElement(material_1.Typography, { variant: "h4" },
@@ -88,6 +88,7 @@ function GroupInviteButton(inProps) {
88
88
  const [open, setOpen] = (0, react_1.useState)(false);
89
89
  const [isSending, setIsSending] = (0, react_1.useState)(false);
90
90
  const [value, setValue] = (0, react_1.useState)('');
91
+ const [suggested, setSuggested] = (0, react_1.useState)([]);
91
92
  const [list, setList] = (0, react_1.useState)([]);
92
93
  const [loading, setLoading] = (0, react_1.useState)(false);
93
94
  const [invited, setInvited] = (0, react_1.useState)([]);
@@ -126,17 +127,22 @@ function GroupInviteButton(inProps) {
126
127
  const intl = (0, react_intl_1.useIntl)();
127
128
  function fetchResults() {
128
129
  setLoading(true);
129
- let service;
130
- if (scGroup) {
131
- service = api_services_1.GroupService.getGroupSuggestedUsers(scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, value);
132
- }
133
- else {
134
- service = api_services_1.GroupService.getGroupsSuggestedUsers(value);
135
- }
136
- service
130
+ api_services_1.GroupService.getGroupSuggestedUsers(scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, value)
137
131
  .then((data) => {
138
132
  setLoading(false);
139
- setList(data.results);
133
+ setSuggested(data.results);
134
+ })
135
+ .catch((error) => {
136
+ setLoading(false);
137
+ utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error);
138
+ });
139
+ }
140
+ function fetchGeneralResults() {
141
+ setLoading(true);
142
+ api_services_1.GroupService.getGroupsSuggestedUsers(value)
143
+ .then((data) => {
144
+ setLoading(false);
145
+ setSuggested(data.results);
140
146
  })
141
147
  .catch((error) => {
142
148
  setLoading(false);
@@ -144,8 +150,30 @@ function GroupInviteButton(inProps) {
144
150
  });
145
151
  }
146
152
  (0, react_1.useEffect)(() => {
147
- fetchResults();
148
- }, [scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, value]);
153
+ if (scGroup === null || scGroup === void 0 ? void 0 : scGroup.id) {
154
+ api_services_1.GroupService.getGroupSuggestedUsers(scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, value).then((data) => {
155
+ setLoading(false);
156
+ setList(data.results);
157
+ });
158
+ }
159
+ else {
160
+ api_services_1.GroupService.getGroupsSuggestedUsers(value).then((data) => {
161
+ setLoading(false);
162
+ setList(data.results);
163
+ });
164
+ }
165
+ }, [scGroup === null || scGroup === void 0 ? void 0 : scGroup.id]);
166
+ /**
167
+ * If a value is entered in new message field, it fetches user suggested
168
+ */
169
+ (0, react_1.useEffect)(() => {
170
+ if (scGroup) {
171
+ fetchResults();
172
+ }
173
+ else {
174
+ fetchGeneralResults();
175
+ }
176
+ }, [value, scGroup]);
149
177
  /**
150
178
  * Handles dialog close
151
179
  */
@@ -182,7 +210,7 @@ function GroupInviteButton(inProps) {
182
210
  switch (reason) {
183
211
  case 'input':
184
212
  setValue(value);
185
- !value && setList([]);
213
+ !value && setSuggested([]);
186
214
  break;
187
215
  case 'reset':
188
216
  setValue(value);
@@ -212,6 +240,13 @@ function GroupInviteButton(inProps) {
212
240
  setInvited(invited.filter((v) => v !== option));
213
241
  setList((prev) => [...prev, option]);
214
242
  };
243
+ const filterOptions = (options, { inputValue }) => {
244
+ return options.filter((option) => {
245
+ const usernameMatch = option.username.toLowerCase().includes(inputValue.toLowerCase());
246
+ const nameMatch = option.real_name.toLowerCase().includes(inputValue.toLowerCase());
247
+ return usernameMatch || nameMatch;
248
+ });
249
+ };
215
250
  /**
216
251
  * If in group edit mode and logged-in user is not also the group manager, the component is hidden.
217
252
  // */
@@ -232,7 +267,7 @@ function GroupInviteButton(inProps) {
232
267
  react_1.default.createElement(lab_1.LoadingButton, { size: "small", color: "secondary", variant: "contained", onClick: handleSendInvitations, loading: isSending, disabled: !invited.length },
233
268
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupInviteButton.dialog.button.end", defaultMessage: "ui.groupInviteButton.dialog.button.end" }))) },
234
269
  react_1.default.createElement(material_1.Box, { className: classes.dialogContent },
235
- react_1.default.createElement(Autocomplete_1.default, { className: classes.autocomplete, loading: loading, size: "small", multiple: true, freeSolo: true, disableClearable: true, options: list, 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_1.default.createElement(material_1.Box, Object.assign({ component: "li" }, props),
270
+ react_1.default.createElement(Autocomplete_1.default, { className: classes.autocomplete, loading: loading, size: "small", multiple: true, freeSolo: true, disableClearable: true, options: suggested, onChange: handleChange, onInputChange: handleInputChange, inputValue: value, filterOptions: filterOptions, value: invited, getOptionLabel: (option) => (option ? option.username : '...'), isOptionEqualToValue: (option, value) => (option ? value.id === option.id : false), renderTags: () => null, renderOption: (props, option) => (react_1.default.createElement(material_1.Box, Object.assign({ component: "li" }, props),
236
271
  react_1.default.createElement(material_1.Avatar, { alt: option.username, src: option.avatar }),
237
272
  react_1.default.createElement(material_1.Typography, { ml: 1 }, option.username))), renderInput: (params) => (react_1.default.createElement(material_1.TextField, Object.assign({}, params, { variant: "outlined", placeholder: `${intl.formatMessage(messages.placeholder)}`, InputProps: Object.assign(Object.assign({}, params.InputProps), { className: classes.input, startAdornment: (react_1.default.createElement(react_1.default.Fragment, null,
238
273
  react_1.default.createElement(material_1.InputAdornment, { position: "start" },
@@ -135,6 +135,6 @@ function GroupMembersButton(inProps) {
135
135
  react_1.default.createElement(InfiniteScroll_1.default, { dataLength: members.length, next: fetchMembers, hasMoreNext: next !== null || loading, loaderNext: react_1.default.createElement(User_1.UserSkeleton, { elevation: 0 }), height: isMobile ? '100%' : 400, endMessage: react_1.default.createElement(material_1.Typography, { className: classes.endMessage },
136
136
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupMembersButton.noOtherMembers", defaultMessage: "ui.groupMembersButton.noOtherMembers" })) },
137
137
  react_1.default.createElement(material_1.List, null, members.map((member) => (react_1.default.createElement(material_1.ListItem, { key: member.id },
138
- react_1.default.createElement(User_1.default, { elevation: 0, user: member }))))))))));
138
+ react_1.default.createElement(User_1.default, { elevation: 0, user: member, onClick: handleToggleDialogOpen }))))))))));
139
139
  }
140
140
  exports.default = GroupMembersButton;
@@ -119,13 +119,6 @@ function Groups(inProps) {
119
119
  fetchGroups();
120
120
  }
121
121
  }, [contentAvailability, authUserId, search]);
122
- const handleSubscribe = (group) => {
123
- if (!general) {
124
- const newGroups = [...groups];
125
- const _updated = newGroups.filter((g) => g.id !== group.id);
126
- setGroups(_updated);
127
- }
128
- };
129
122
  const handleNext = (0, react_1.useMemo)(() => () => {
130
123
  if (!next) {
131
124
  return;
@@ -174,7 +167,7 @@ function Groups(inProps) {
174
167
  button: (chunk) => (react_1.default.createElement(material_1.Button, { color: "secondary", variant: "text", onClick: handleScrollUp }, chunk))
175
168
  } })) },
176
169
  react_1.default.createElement(material_1.Grid, { container: true, spacing: { xs: 2 }, className: classes.groups }, filteredGroups.map((group) => (react_1.default.createElement(material_1.Grid, { item: true, xs: 12, sm: 8, md: 6, key: group.id, className: classes.item },
177
- react_1.default.createElement(Group_1.default, Object.assign({ group: group, groupId: group.id, groupSubscribeButtonProps: { onSubscribe: handleSubscribe } }, GroupComponentProps)))))))))));
170
+ react_1.default.createElement(Group_1.default, Object.assign({ group: group, groupId: group.id, actionRedirect: true }, GroupComponentProps)))))))))));
178
171
  // RENDER
179
172
  if (!contentAvailability && !scUserContext.user) {
180
173
  return react_1.default.createElement(HiddenPlaceholder_1.default, null);
@@ -59,6 +59,7 @@ export interface NavigationToolbarMobileProps extends ToolbarProps {
59
59
  |logo|.SCNavigationToolbarMobile-logo|Styles applied to the logo element.|
60
60
  |search|.SCNavigationToolbarMobile-search|Styles applied to the search button element|
61
61
  |searchDialog|.SCNavigationToolbarMobile-search-dialog|Styles applied to the search dialog element|
62
+ |notifications|.SCNavigationToolbarMobile-notifications|Styles applied to the notifications button element|
62
63
  |settings|.SCNavigationToolbarMobile-settings|Styles applied to the settings button element|
63
64
  |settingsDialog|.SCNavigationToolbarMobile-settingsDialog|Styles applied to the settings dialog elements|
64
65
  |login|.SCNavigationToolbarMobile-login|Styles applied to the login element.|
@@ -13,11 +13,13 @@ const SearchDialog_1 = tslib_1.__importDefault(require("../SearchDialog"));
13
13
  const NavigationSettingsIconButton_1 = tslib_1.__importDefault(require("../NavigationSettingsIconButton"));
14
14
  const NavigationMenuIconButton_1 = tslib_1.__importDefault(require("../NavigationMenuIconButton"));
15
15
  const constants_1 = require("./constants");
16
+ const types_1 = require("@selfcommunity/types");
16
17
  const classes = {
17
18
  root: `${constants_1.PREFIX}-root`,
18
19
  logo: `${constants_1.PREFIX}-logo`,
19
20
  search: `${constants_1.PREFIX}-search`,
20
21
  searchDialog: `${constants_1.PREFIX}-search-dialog`,
22
+ notifications: `${constants_1.PREFIX}-notifications`,
21
23
  settings: `${constants_1.PREFIX}-settings`,
22
24
  settingsDialog: `${constants_1.PREFIX}-settings-dialog`,
23
25
  login: `${constants_1.PREFIX}-login`
@@ -52,6 +54,7 @@ const Root = (0, material_1.styled)(material_1.Toolbar, {
52
54
  |logo|.SCNavigationToolbarMobile-logo|Styles applied to the logo element.|
53
55
  |search|.SCNavigationToolbarMobile-search|Styles applied to the search button element|
54
56
  |searchDialog|.SCNavigationToolbarMobile-search-dialog|Styles applied to the search dialog element|
57
+ |notifications|.SCNavigationToolbarMobile-notifications|Styles applied to the notifications button element|
55
58
  |settings|.SCNavigationToolbarMobile-settings|Styles applied to the settings button element|
56
59
  |settingsDialog|.SCNavigationToolbarMobile-settingsDialog|Styles applied to the settings dialog elements|
57
60
  |login|.SCNavigationToolbarMobile-login|Styles applied to the login element.|
@@ -69,9 +72,11 @@ function NavigationToolbarMobile(inProps) {
69
72
  const scUserContext = (0, react_core_1.useSCUser)();
70
73
  const scRoutingContext = (0, react_core_1.useSCRouting)();
71
74
  // PREFERENCES
72
- const { preferences } = (0, react_core_1.useSCPreferences)();
75
+ const { preferences, features } = (0, react_core_1.useSCPreferences)();
73
76
  // STATE
74
77
  const [searchOpen, setSearchOpen] = (0, react_1.useState)(false);
78
+ // MEMO
79
+ const groupsEnabled = (0, react_1.useMemo)(() => features.includes(types_1.SCFeatureName.GROUPING), [features]);
75
80
  // HANDLERS
76
81
  const handleOpenSearch = (0, react_1.useCallback)(() => {
77
82
  setSearchOpen(true);
@@ -94,6 +99,9 @@ function NavigationToolbarMobile(inProps) {
94
99
  react_1.default.createElement(Icon_1.default, null, "search")),
95
100
  react_1.default.createElement(SearchDialog_1.default, { className: classes.searchDialog, fullScreen: true, open: searchOpen, SearchAutocompleteProps: Object.assign(Object.assign({}, SearchAutocompleteProps), { onClear: handleCloseSearch }) }))),
96
101
  endActions,
102
+ scUserContext.user && groupsEnabled && (react_1.default.createElement(material_1.IconButton, { className: classes.notifications, component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}) },
103
+ react_1.default.createElement(material_1.Badge, { badgeContent: scUserContext.user.unseen_notification_banners_counter + scUserContext.user.unseen_interactions_counter, color: "secondary" },
104
+ react_1.default.createElement(Icon_1.default, null, "notifications_active")))),
97
105
  scUserContext.user ? (react_1.default.createElement(NavigationSettingsIconButtonComponent, { className: classes.settings })) : (react_1.default.createElement(material_1.Button, { className: classes.login, color: "inherit", component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.SIGNIN_ROUTE_NAME, {}) },
98
106
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.appBar.navigation.login", defaultMessage: "ui.appBar.navigation.login" })))));
99
107
  }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * > API documentation for the Community-JS User Profile Categories Followed Widget Skeleton component. Learn about the available props and the CSS API.
3
+
4
+ #### Import
5
+
6
+ ```jsx
7
+ import {UserSubscribedGroupsWidgetSkeleton} from '@selfcommunity/react-ui';
8
+ ```
9
+
10
+ #### Component Name
11
+
12
+ The name `SCUserCategoriesFollowedWidget-skeleton-root` can be used when providing style overrides in the theme.
13
+
14
+ #### CSS
15
+
16
+ |Rule Name|Global class|Description|
17
+ |---|---|---|
18
+ |root|.SCUserSubscribedGroupsWidget-skeleton-root|Styles applied to the root element.|
19
+ *
20
+ */
21
+ export default function UserSubscribedGroupsWidgetSkeleton(props: any): JSX.Element;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ const Widget_1 = tslib_1.__importDefault(require("../Widget"));
6
+ const styles_1 = require("@mui/material/styles");
7
+ const material_1 = require("@mui/material");
8
+ const List_1 = tslib_1.__importDefault(require("@mui/material/List"));
9
+ const Skeleton_1 = tslib_1.__importDefault(require("../Group/Skeleton"));
10
+ const PREFIX = 'SCUserSubscribedGroupsWidgetSkeleton';
11
+ const classes = {
12
+ root: `${PREFIX}-skeleton-root`,
13
+ list: `${PREFIX}-list`
14
+ };
15
+ const Root = (0, styles_1.styled)(Widget_1.default, {
16
+ name: PREFIX,
17
+ slot: 'SkeletonRoot'
18
+ })(() => ({}));
19
+ /**
20
+ * > API documentation for the Community-JS User Profile Categories Followed Widget Skeleton component. Learn about the available props and the CSS API.
21
+
22
+ #### Import
23
+
24
+ ```jsx
25
+ import {UserSubscribedGroupsWidgetSkeleton} from '@selfcommunity/react-ui';
26
+ ```
27
+
28
+ #### Component Name
29
+
30
+ The name `SCUserCategoriesFollowedWidget-skeleton-root` can be used when providing style overrides in the theme.
31
+
32
+ #### CSS
33
+
34
+ |Rule Name|Global class|Description|
35
+ |---|---|---|
36
+ |root|.SCUserSubscribedGroupsWidget-skeleton-root|Styles applied to the root element.|
37
+ *
38
+ */
39
+ function UserSubscribedGroupsWidgetSkeleton(props) {
40
+ return (react_1.default.createElement(Root, Object.assign({ className: classes.root }, props),
41
+ react_1.default.createElement(material_1.CardContent, null,
42
+ react_1.default.createElement(List_1.default, { className: classes.list }, [...Array(3)].map((category, index) => (react_1.default.createElement(material_1.ListItem, { key: index },
43
+ react_1.default.createElement(Skeleton_1.default, { elevation: 0 })))))),
44
+ ");"));
45
+ }
46
+ exports.default = UserSubscribedGroupsWidgetSkeleton;
@@ -0,0 +1,68 @@
1
+ import { CacheStrategies } from '@selfcommunity/utils';
2
+ import { BaseDialogProps } from '../../shared/BaseDialog';
3
+ import { WidgetProps } from '../Widget';
4
+ import { VirtualScrollerItemProps } from '../../types/virtualScroller';
5
+ import { GroupProps } from '../Group';
6
+ export interface UserSubscribedGroupsWidgetProps extends VirtualScrollerItemProps, WidgetProps {
7
+ /**
8
+ * The user id
9
+ * @default null
10
+ */
11
+ userId: number;
12
+ /**
13
+ * Hides this component
14
+ * @default false
15
+ */
16
+ autoHide?: boolean;
17
+ /**
18
+ * Limit the number of groups to show
19
+ * @default false
20
+ */
21
+ limit?: number;
22
+ /**
23
+ * Props to spread to single group object
24
+ * @default empty object
25
+ */
26
+ GroupProps?: GroupProps;
27
+ /**
28
+ * Caching strategies
29
+ * @default CacheStrategies.CACHE_FIRST
30
+ */
31
+ cacheStrategy?: CacheStrategies;
32
+ /**
33
+ * Props to spread to subscribed groups dialog
34
+ * @default {}
35
+ */
36
+ DialogProps?: BaseDialogProps;
37
+ /**
38
+ * Other props
39
+ */
40
+ [p: string]: any;
41
+ }
42
+ /**
43
+ * > API documentation for the Community-JS User Profile Groups Subscribed Widget component. Learn about the available props and the CSS API.
44
+ *
45
+ *
46
+ * This component renders the list of the groups that the given user follows.
47
+ * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/UserSubscribedGroups)
48
+
49
+ #### Import
50
+ ```jsx
51
+ import {UserSubscribedGroupsWidget} from '@selfcommunity/react-ui';
52
+ ```
53
+ #### Component Name
54
+ The name `SCUserSubscribedGroupsWidget` can be used when providing style overrides in the theme.
55
+
56
+ #### CSS
57
+
58
+ |Rule Name|Global class|Description|
59
+ |---|---|---|
60
+ |root|.SCUserSubscribedGroupsWidget-root|Styles applied to the root element.|
61
+ |title|.SCUserSubscribedGroupsWidget-title|Styles applied to the title element.|
62
+ |noResults|.SCUserSubscribedGroupsWidget-no-results|Styles applied to no results section.|
63
+ |showMore|.SCUserSubscribedGroupsWidget-show-more|Styles applied to show more button element.|
64
+ |dialogRoot|.SCUserSubscribedGroupsWidget-dialog-root|Styles applied to the root dialog element.|
65
+ |endMessage|.SCUserSubscribedGroupsWidget-end-message|Styles applied to the end message element.|
66
+ * @param inProps
67
+ */
68
+ export default function UserSubscribedGroupsWidget(inProps: UserSubscribedGroupsWidgetProps): JSX.Element;
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importStar(require("react"));
5
+ const styles_1 = require("@mui/material/styles");
6
+ const List_1 = tslib_1.__importDefault(require("@mui/material/List"));
7
+ const material_1 = require("@mui/material");
8
+ const api_services_1 = require("@selfcommunity/api-services");
9
+ const utils_1 = require("@selfcommunity/utils");
10
+ const react_core_1 = require("@selfcommunity/react-core");
11
+ const widget_1 = require("../../utils/widget");
12
+ const types_1 = require("@selfcommunity/types");
13
+ const Errors_1 = require("../../constants/Errors");
14
+ const react_intl_1 = require("react-intl");
15
+ const Skeleton_1 = tslib_1.__importDefault(require("./Skeleton"));
16
+ const classnames_1 = tslib_1.__importDefault(require("classnames"));
17
+ const BaseDialog_1 = tslib_1.__importDefault(require("../../shared/BaseDialog"));
18
+ const Widget_1 = tslib_1.__importDefault(require("../Widget"));
19
+ const system_1 = require("@mui/system");
20
+ const HiddenPlaceholder_1 = tslib_1.__importDefault(require("../../shared/HiddenPlaceholder"));
21
+ const constants_1 = require("./constants");
22
+ const Group_1 = tslib_1.__importStar(require("../Group"));
23
+ const classes = {
24
+ root: `${constants_1.PREFIX}-root`,
25
+ title: `${constants_1.PREFIX}-title`,
26
+ noResults: `${constants_1.PREFIX}-no-results`,
27
+ showMore: `${constants_1.PREFIX}-show-more`,
28
+ dialogRoot: `${constants_1.PREFIX}-dialog-root`,
29
+ endMessage: `${constants_1.PREFIX}-end-message`
30
+ };
31
+ const Root = (0, styles_1.styled)(Widget_1.default, {
32
+ name: constants_1.PREFIX,
33
+ slot: 'Root'
34
+ })(() => ({}));
35
+ const DialogRoot = (0, styles_1.styled)(BaseDialog_1.default, {
36
+ name: constants_1.PREFIX,
37
+ slot: 'DialogRoot'
38
+ })(() => ({}));
39
+ /**
40
+ * > API documentation for the Community-JS User Profile Groups Subscribed Widget component. Learn about the available props and the CSS API.
41
+ *
42
+ *
43
+ * This component renders the list of the groups that the given user follows.
44
+ * Take a look at our <strong>demo</strong> component [here](/docs/sdk/community-js/react-ui/Components/UserSubscribedGroups)
45
+
46
+ #### Import
47
+ ```jsx
48
+ import {UserSubscribedGroupsWidget} from '@selfcommunity/react-ui';
49
+ ```
50
+ #### Component Name
51
+ The name `SCUserSubscribedGroupsWidget` can be used when providing style overrides in the theme.
52
+
53
+ #### CSS
54
+
55
+ |Rule Name|Global class|Description|
56
+ |---|---|---|
57
+ |root|.SCUserSubscribedGroupsWidget-root|Styles applied to the root element.|
58
+ |title|.SCUserSubscribedGroupsWidget-title|Styles applied to the title element.|
59
+ |noResults|.SCUserSubscribedGroupsWidget-no-results|Styles applied to no results section.|
60
+ |showMore|.SCUserSubscribedGroupsWidget-show-more|Styles applied to show more button element.|
61
+ |dialogRoot|.SCUserSubscribedGroupsWidget-dialog-root|Styles applied to the root dialog element.|
62
+ |endMessage|.SCUserSubscribedGroupsWidget-end-message|Styles applied to the end message element.|
63
+ * @param inProps
64
+ */
65
+ function UserSubscribedGroupsWidget(inProps) {
66
+ // PROPS
67
+ const props = (0, system_1.useThemeProps)({
68
+ props: inProps,
69
+ name: constants_1.PREFIX
70
+ });
71
+ const { userId, autoHide, limit = 3, className, GroupProps = {}, cacheStrategy = utils_1.CacheStrategies.NETWORK_ONLY, onHeightChange, onStateChange, DialogProps = {} } = props, rest = tslib_1.__rest(props, ["userId", "autoHide", "limit", "className", "GroupProps", "cacheStrategy", "onHeightChange", "onStateChange", "DialogProps"]);
72
+ // CONTEXT
73
+ const scUserContext = (0, react_core_1.useSCUser)();
74
+ const isMe = (0, react_1.useMemo)(() => scUserContext.user && userId === scUserContext.user.id, [scUserContext.user, userId]);
75
+ const { features } = (0, react_core_1.useSCPreferences)();
76
+ const groupsEnabled = (0, react_1.useMemo)(() => features.includes(types_1.SCFeatureName.GROUPING), [features]);
77
+ // STATE
78
+ const [state, dispatch] = (0, react_1.useReducer)(widget_1.dataWidgetReducer, {
79
+ isLoadingNext: false,
80
+ next: null,
81
+ cacheKey: react_core_1.SCCache.getWidgetStateCacheKey(react_core_1.SCCache.GROUPS_SUBSCRIBED_TOOLS_STATE_CACHE_PREFIX_KEY, userId),
82
+ cacheStrategy
83
+ }, widget_1.stateWidgetInitializer);
84
+ const [openDialog, setOpenDialog] = (0, react_1.useState)(false);
85
+ /**
86
+ * Initialize component
87
+ * Fetch data only if the component is not initialized and it is not loading data
88
+ */
89
+ const _initComponent = (0, react_1.useMemo)(() => () => {
90
+ if (!state.initialized && !state.isLoadingNext) {
91
+ api_services_1.GroupService.getUserSubscribedGroups(userId)
92
+ .then((groups) => {
93
+ dispatch({
94
+ type: widget_1.actionWidgetTypes.LOAD_NEXT_SUCCESS,
95
+ payload: {
96
+ count: groups.count,
97
+ results: groups.results,
98
+ initialized: true
99
+ }
100
+ });
101
+ })
102
+ .catch((error) => {
103
+ dispatch({ type: widget_1.actionWidgetTypes.LOAD_NEXT_FAILURE, payload: { errorLoadNext: error } });
104
+ utils_1.Logger.error(Errors_1.SCOPE_SC_UI, error);
105
+ });
106
+ }
107
+ }, [state.isLoadingNext, state.initialized, userId, dispatch]);
108
+ // EFFECTS
109
+ (0, react_1.useEffect)(() => {
110
+ let _t;
111
+ if (groupsEnabled || ((0, utils_1.isInteger)(userId) && scUserContext.user !== undefined)) {
112
+ _t = setTimeout(_initComponent);
113
+ return () => {
114
+ _t && clearTimeout(_t);
115
+ };
116
+ }
117
+ }, [scUserContext.user, groupsEnabled, userId]);
118
+ /**
119
+ * Virtual feed update
120
+ */
121
+ (0, react_1.useEffect)(() => {
122
+ onHeightChange && onHeightChange();
123
+ }, [state.results.length]);
124
+ (0, react_1.useEffect)(() => {
125
+ if ((!groupsEnabled && !scUserContext.user) || !(0, utils_1.isInteger)(userId)) {
126
+ return;
127
+ }
128
+ else if (cacheStrategy === utils_1.CacheStrategies.NETWORK_ONLY) {
129
+ onStateChange && onStateChange({ cacheStrategy: utils_1.CacheStrategies.CACHE_FIRST });
130
+ }
131
+ }, [groupsEnabled, cacheStrategy, scUserContext.user, userId]);
132
+ // HANDLERS
133
+ const handleOnSubscribe = (group) => {
134
+ if (isMe) {
135
+ const newGroups = [...state.results];
136
+ const index = newGroups.findIndex((u) => u.id === group.id);
137
+ if (index !== -1) {
138
+ if (group.subscription_status === types_1.SCGroupSubscriptionStatusType.SUBSCRIBED) {
139
+ newGroups[index].subscribers_counter = group.subscribers_counter - 1;
140
+ newGroups[index].subscription_status = null;
141
+ }
142
+ else {
143
+ newGroups[index].subscribers_counter =
144
+ group.privacy === types_1.SCGroupPrivacyType.PUBLIC ? group.subscribers_counter + 1 : group.subscribers_counter;
145
+ newGroups[index].subscription_status =
146
+ group.privacy === types_1.SCGroupPrivacyType.PUBLIC ? types_1.SCGroupSubscriptionStatusType.SUBSCRIBED : types_1.SCGroupSubscriptionStatusType.REQUESTED;
147
+ }
148
+ dispatch({ type: widget_1.actionWidgetTypes.SET_RESULTS, payload: { results: newGroups } });
149
+ }
150
+ }
151
+ };
152
+ const handleToggleDialogOpen = () => {
153
+ setOpenDialog((prev) => !prev);
154
+ };
155
+ // RENDER
156
+ if (!groupsEnabled || (autoHide && !state.count && state.initialized) || !userId) {
157
+ return react_1.default.createElement(HiddenPlaceholder_1.default, null);
158
+ }
159
+ if (!state.initialized) {
160
+ return react_1.default.createElement(Skeleton_1.default, null);
161
+ }
162
+ const content = (react_1.default.createElement(material_1.CardContent, null,
163
+ react_1.default.createElement(material_1.Typography, { className: classes.title, variant: "h5" },
164
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.userSubscribedGroupsWidget.title", defaultMessage: "ui.userSubscribedGroupsWidget.title", values: {
165
+ total: isMe ? state.results.filter((g) => g.subscription_status === types_1.SCGroupSubscriptionStatusType.SUBSCRIBED).length : state.count
166
+ } })),
167
+ !state.count ? (react_1.default.createElement(material_1.Typography, { className: classes.noResults, variant: "body2" },
168
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.userSubscribedGroupsWidget.subtitle.noResults", defaultMessage: "ui.userSubscribedGroupsWidget.subtitle.noResults" }))) : (react_1.default.createElement(react_1.default.Fragment, null,
169
+ react_1.default.createElement(List_1.default, null, state.results.slice(0, limit).map((group) => (react_1.default.createElement(material_1.ListItem, { key: group.id },
170
+ react_1.default.createElement(Group_1.default, Object.assign({ elevation: 0, group: group, groupSubscribeButtonProps: { onSubscribe: handleOnSubscribe } }, GroupProps)))))),
171
+ limit < state.count && (react_1.default.createElement(material_1.Button, { className: classes.showMore, onClick: handleToggleDialogOpen },
172
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.userSubscribedGroupsWidget.button.showAll", defaultMessage: "ui.userSubscribedGroupsWidget.button.showAll" }))),
173
+ openDialog && (react_1.default.createElement(DialogRoot, Object.assign({ className: classes.dialogRoot, title: react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.userSubscribedGroupsWidget.title", defaultMessage: "ui.userSubscribedGroupsWidget.title", values: { total: state.count } }), onClose: handleToggleDialogOpen, open: openDialog, scroll: "paper" }, DialogProps),
174
+ react_1.default.createElement(List_1.default, null,
175
+ state.results.map((g) => (react_1.default.createElement(material_1.ListItem, { key: g.id },
176
+ react_1.default.createElement(Group_1.default, Object.assign({ elevation: 0, group: g, groupSubscribeButtonProps: { onSubscribe: handleOnSubscribe } }, GroupProps))))),
177
+ state.isLoadingNext && (react_1.default.createElement(material_1.ListItem, null,
178
+ react_1.default.createElement(Group_1.GroupSkeleton, Object.assign({ elevation: 0 }, GroupProps))))),
179
+ react_1.default.createElement(material_1.Typography, { className: classes.endMessage },
180
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.userSubscribedGroupsWidget.noMoreResults", defaultMessage: "ui.userSubscribedGroupsWidget.noMoreResults" }))))))));
181
+ return (react_1.default.createElement(Root, Object.assign({ className: (0, classnames_1.default)(classes.root, className) }, rest), content));
182
+ }
183
+ exports.default = UserSubscribedGroupsWidget;
@@ -0,0 +1 @@
1
+ export declare const PREFIX = "SCUserSubscribedGroupsWidget";
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PREFIX = void 0;
4
+ exports.PREFIX = 'SCUserSubscribedGroupsWidget';
@@ -0,0 +1,4 @@
1
+ import UserSubscribedGroupsWidget, { UserSubscribedGroupsWidgetProps } from './UserSubscribedGroupsWidget';
2
+ import UserSubscribedGroupsWidgetSkeleton from './Skeleton';
3
+ export default UserSubscribedGroupsWidget;
4
+ export { UserSubscribedGroupsWidgetSkeleton, UserSubscribedGroupsWidgetProps };
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UserSubscribedGroupsWidgetSkeleton = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const UserSubscribedGroupsWidget_1 = tslib_1.__importDefault(require("./UserSubscribedGroupsWidget"));
6
+ const Skeleton_1 = tslib_1.__importDefault(require("./Skeleton"));
7
+ exports.UserSubscribedGroupsWidgetSkeleton = Skeleton_1.default;
8
+ exports.default = UserSubscribedGroupsWidget_1.default;
@@ -134,6 +134,6 @@ function VoteAudienceButton(inProps) {
134
134
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.voteAudienceButton.dialog.end", defaultMessage: "ui.voteAudienceButton.dialog.end" })) },
135
135
  react_1.default.createElement(material_1.List, null, voteList.map((vote) => (react_1.default.createElement(material_1.ListItem, { key: vote.user.id },
136
136
  react_1.default.createElement(User_1.default, { elevation: 0, user: vote.user, badgeContent: react_1.default.createElement(material_1.Avatar, { className: classes.dialogVoteBadge }, vote.reaction ? (react_1.default.createElement(Icon_1.default, null,
137
- react_1.default.createElement("img", { alt: vote.reaction.label, src: vote.reaction.image, width: "100%", height: "100%" }))) : (react_1.default.createElement(Icon_1.default, null, "thumb_up"))) })))))))))));
137
+ react_1.default.createElement("img", { alt: vote.reaction.label, src: vote.reaction.image, width: "100%", height: "100%" }))) : (react_1.default.createElement(Icon_1.default, null, "thumb_up"))), onClick: handleClose })))))))))));
138
138
  }
139
139
  exports.default = VoteAudienceButton;