@selfcommunity/react-ui 0.7.9-alpha.53 → 0.7.9-alpha.55
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/BottomNavigation/BottomNavigation.js +1 -1
- package/lib/cjs/components/GroupForm/GroupForm.js +2 -1
- package/lib/cjs/components/GroupInviteButton/GroupInviteButton.js +48 -13
- package/lib/cjs/components/Groups/Groups.js +4 -2
- package/lib/cjs/components/Groups/Skeleton.d.ts +1 -1
- package/lib/cjs/components/Groups/Skeleton.js +1 -1
- package/lib/cjs/components/NavigationToolbarMobile/NavigationToolbarMobile.d.ts +1 -0
- package/lib/cjs/components/NavigationToolbarMobile/NavigationToolbarMobile.js +9 -1
- package/lib/esm/components/BottomNavigation/BottomNavigation.js +1 -1
- package/lib/esm/components/GroupForm/GroupForm.js +2 -1
- package/lib/esm/components/GroupInviteButton/GroupInviteButton.js +48 -13
- package/lib/esm/components/Groups/Groups.js +5 -3
- package/lib/esm/components/Groups/Skeleton.d.ts +1 -1
- package/lib/esm/components/Groups/Skeleton.js +1 -1
- package/lib/esm/components/NavigationToolbarMobile/NavigationToolbarMobile.d.ts +1 -0
- package/lib/esm/components/NavigationToolbarMobile/NavigationToolbarMobile.js +11 -3
- package/lib/umd/react-ui.js +1 -1
- package/package.json +2 -2
|
@@ -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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
148
|
-
|
|
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 &&
|
|
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:
|
|
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" },
|
|
@@ -14,7 +14,7 @@ const Errors_1 = require("../../constants/Errors");
|
|
|
14
14
|
const system_1 = require("@mui/system");
|
|
15
15
|
const HiddenPlaceholder_1 = tslib_1.__importDefault(require("../../shared/HiddenPlaceholder"));
|
|
16
16
|
const constants_1 = require("./constants");
|
|
17
|
-
const Group_1 = tslib_1.
|
|
17
|
+
const Group_1 = tslib_1.__importStar(require("../Group"));
|
|
18
18
|
const Pagination_1 = require("../../constants/Pagination");
|
|
19
19
|
const InfiniteScroll_1 = tslib_1.__importDefault(require("../../shared/InfiniteScroll"));
|
|
20
20
|
const classes = {
|
|
@@ -73,6 +73,8 @@ function Groups(inProps) {
|
|
|
73
73
|
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
74
74
|
const [next, setNext] = (0, react_1.useState)(null);
|
|
75
75
|
const [search, setSearch] = (0, react_1.useState)('');
|
|
76
|
+
const theme = (0, material_1.useTheme)();
|
|
77
|
+
const isMobile = (0, material_1.useMediaQuery)(theme.breakpoints.down('md'));
|
|
76
78
|
// CONTEXT
|
|
77
79
|
const scUserContext = (0, react_core_1.useSCUser)();
|
|
78
80
|
const scPreferencesContext = (0, react_core_1.useSCPreferences)();
|
|
@@ -167,7 +169,7 @@ function Groups(inProps) {
|
|
|
167
169
|
react_1.default.createElement(material_1.Typography, { variant: "h4" },
|
|
168
170
|
react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.noGroups.title", defaultMessage: "ui.groups.noGroups.title" })),
|
|
169
171
|
react_1.default.createElement(material_1.Typography, { variant: "body1" },
|
|
170
|
-
react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.noGroups.subtitle", defaultMessage: "ui.groups.noGroups.subtitle" })))) : (react_1.default.createElement(InfiniteScroll_1.default, { dataLength: groups.length, next: handleNext, hasMoreNext: Boolean(next), loaderNext: react_1.default.createElement(Skeleton_1.default, { groupsNumber: 2 }), endMessage: react_1.default.createElement(material_1.Typography, { component: "div", className: classes.endMessage },
|
|
172
|
+
react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.noGroups.subtitle", defaultMessage: "ui.groups.noGroups.subtitle" })))) : (react_1.default.createElement(InfiniteScroll_1.default, { dataLength: groups.length, next: handleNext, hasMoreNext: Boolean(next), loaderNext: isMobile ? react_1.default.createElement(Group_1.GroupSkeleton, null) : react_1.default.createElement(Skeleton_1.default, { groupsNumber: 2 }), endMessage: react_1.default.createElement(material_1.Typography, { component: "div", className: classes.endMessage },
|
|
171
173
|
react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.endMessage", defaultMessage: "ui.groups.endMessage", values: {
|
|
172
174
|
button: (chunk) => (react_1.default.createElement(material_1.Button, { color: "secondary", variant: "text", onClick: handleScrollUp }, chunk))
|
|
173
175
|
} })) },
|
|
@@ -37,7 +37,7 @@ const Root = (0, styles_1.styled)(material_1.Box, {
|
|
|
37
37
|
*
|
|
38
38
|
*/
|
|
39
39
|
function GroupsSkeleton(inProps) {
|
|
40
|
-
const { className, GroupSkeletonProps = {}, groupsNumber =
|
|
40
|
+
const { className, GroupSkeletonProps = {}, groupsNumber = 20 } = inProps, rest = tslib_1.__rest(inProps, ["className", "GroupSkeletonProps", "groupsNumber"]);
|
|
41
41
|
return (react_1.default.createElement(Root, Object.assign({ className: (0, classnames_1.default)(classes.root, className) }, rest),
|
|
42
42
|
react_1.default.createElement(material_1.Grid, { container: true, spacing: { xs: 3 }, className: classes.groups }, [...Array(groupsNumber)].map((category, index) => (react_1.default.createElement(material_1.Grid, { item: true, xs: 12, sm: 8, md: 6, key: index },
|
|
43
43
|
react_1.default.createElement(Group_1.GroupSkeleton, Object.assign({ elevation: 0, variant: 'outlined' }, GroupSkeletonProps))))))));
|
|
@@ -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
|
}
|
|
@@ -71,7 +71,7 @@ export default function BottomNavigation(inProps) {
|
|
|
71
71
|
preferences[SCPreferences.CONFIGURATIONS_EXPLORE_STREAM_ENABLED].value ? (React.createElement(BottomNavigationAction, { key: "explore", className: classes.action, component: Link, to: scRoutingContext.url(SCRoutes.EXPLORE_ROUTE_NAME, {}), value: scRoutingContext.url(SCRoutes.EXPLORE_ROUTE_NAME, {}), icon: React.createElement(Icon, null, "explore") })) : null,
|
|
72
72
|
React.createElement(BottomNavigationAction, { key: "composer", className: classNames(classes.composer, classes.action), component: ComposerIconButton, disableRipple: true }),
|
|
73
73
|
groupsEnabled && scUserContext.user ? (React.createElement(BottomNavigationAction, { key: "groups", className: classes.action, component: Link, to: scRoutingContext.url(SCRoutes.GROUPS_ROUTE_NAME, {}), value: scRoutingContext.url(SCRoutes.GROUPS_ROUTE_NAME, {}), icon: React.createElement(Icon, null, "groups") })) : null,
|
|
74
|
-
scUserContext.user ? (React.createElement(BottomNavigationAction, { key: "notifications", className: classes.action, component: Link, to: scRoutingContext.url(SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}), value: scRoutingContext.url(SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}), icon: React.createElement(Badge, { badgeContent: scUserContext.user.unseen_notification_banners_counter + scUserContext.user.unseen_interactions_counter, color: "secondary" },
|
|
74
|
+
scUserContext.user && !groupsEnabled ? (React.createElement(BottomNavigationAction, { key: "notifications", className: classes.action, component: Link, to: scRoutingContext.url(SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}), value: scRoutingContext.url(SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}), icon: React.createElement(Badge, { badgeContent: scUserContext.user.unseen_notification_banners_counter + scUserContext.user.unseen_interactions_counter, color: "secondary" },
|
|
75
75
|
React.createElement(Icon, null, "notifications_active")) })) : null,
|
|
76
76
|
privateMessagingEnabled && scUserContext.user ? (React.createElement(BottomNavigationAction, { key: "messages", className: classes.action, component: Link, to: scRoutingContext.url(SCRoutes.USER_PRIVATE_MESSAGES_ROUTE_NAME, {}), value: scRoutingContext.url(SCRoutes.USER_PRIVATE_MESSAGES_ROUTE_NAME, {}), icon: React.createElement(Badge, { badgeContent: 0, color: "secondary" },
|
|
77
77
|
React.createElement(Icon, null, "email")) })) : null
|
|
@@ -90,6 +90,7 @@ const Root = styled(BaseDialog, {
|
|
|
90
90
|
* @param inProps
|
|
91
91
|
*/
|
|
92
92
|
export default function GroupForm(inProps) {
|
|
93
|
+
var _a;
|
|
93
94
|
//PROPS
|
|
94
95
|
const props = useThemeProps({
|
|
95
96
|
props: inProps,
|
|
@@ -225,7 +226,7 @@ export default function GroupForm(inProps) {
|
|
|
225
226
|
endAdornment: React.createElement(Typography, { variant: "body2" }, GROUP_TITLE_MAX_LENGTH - field.name.length)
|
|
226
227
|
} }),
|
|
227
228
|
React.createElement(TextField, { multiline: true, className: classes.description, placeholder: `${intl.formatMessage(messages.description)}`, margin: "normal", value: field.description, name: "description", onChange: handleChange, InputProps: {
|
|
228
|
-
endAdornment: React.createElement(Typography, { variant: "body2" }, GROUP_DESCRIPTION_MAX_LENGTH - field.description.length)
|
|
229
|
+
endAdornment: (React.createElement(Typography, { variant: "body2" }, ((_a = field.description) === null || _a === void 0 ? void 0 : _a.length) ? GROUP_DESCRIPTION_MAX_LENGTH - field.description.length : GROUP_DESCRIPTION_MAX_LENGTH))
|
|
229
230
|
} }),
|
|
230
231
|
React.createElement(Box, { className: classes.privacySection },
|
|
231
232
|
React.createElement(Typography, { variant: "h4" },
|
|
@@ -86,6 +86,7 @@ export default function GroupInviteButton(inProps) {
|
|
|
86
86
|
const [open, setOpen] = useState(false);
|
|
87
87
|
const [isSending, setIsSending] = useState(false);
|
|
88
88
|
const [value, setValue] = useState('');
|
|
89
|
+
const [suggested, setSuggested] = useState([]);
|
|
89
90
|
const [list, setList] = useState([]);
|
|
90
91
|
const [loading, setLoading] = useState(false);
|
|
91
92
|
const [invited, setInvited] = useState([]);
|
|
@@ -124,17 +125,22 @@ export default function GroupInviteButton(inProps) {
|
|
|
124
125
|
const intl = useIntl();
|
|
125
126
|
function fetchResults() {
|
|
126
127
|
setLoading(true);
|
|
127
|
-
|
|
128
|
-
if (scGroup) {
|
|
129
|
-
service = GroupService.getGroupSuggestedUsers(scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, value);
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
service = GroupService.getGroupsSuggestedUsers(value);
|
|
133
|
-
}
|
|
134
|
-
service
|
|
128
|
+
GroupService.getGroupSuggestedUsers(scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, value)
|
|
135
129
|
.then((data) => {
|
|
136
130
|
setLoading(false);
|
|
137
|
-
|
|
131
|
+
setSuggested(data.results);
|
|
132
|
+
})
|
|
133
|
+
.catch((error) => {
|
|
134
|
+
setLoading(false);
|
|
135
|
+
Logger.error(SCOPE_SC_UI, error);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
function fetchGeneralResults() {
|
|
139
|
+
setLoading(true);
|
|
140
|
+
GroupService.getGroupsSuggestedUsers(value)
|
|
141
|
+
.then((data) => {
|
|
142
|
+
setLoading(false);
|
|
143
|
+
setSuggested(data.results);
|
|
138
144
|
})
|
|
139
145
|
.catch((error) => {
|
|
140
146
|
setLoading(false);
|
|
@@ -142,8 +148,30 @@ export default function GroupInviteButton(inProps) {
|
|
|
142
148
|
});
|
|
143
149
|
}
|
|
144
150
|
useEffect(() => {
|
|
145
|
-
|
|
146
|
-
|
|
151
|
+
if (scGroup === null || scGroup === void 0 ? void 0 : scGroup.id) {
|
|
152
|
+
GroupService.getGroupSuggestedUsers(scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, value).then((data) => {
|
|
153
|
+
setLoading(false);
|
|
154
|
+
setList(data.results);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
GroupService.getGroupsSuggestedUsers(value).then((data) => {
|
|
159
|
+
setLoading(false);
|
|
160
|
+
setList(data.results);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}, [scGroup === null || scGroup === void 0 ? void 0 : scGroup.id]);
|
|
164
|
+
/**
|
|
165
|
+
* If a value is entered in new message field, it fetches user suggested
|
|
166
|
+
*/
|
|
167
|
+
useEffect(() => {
|
|
168
|
+
if (scGroup) {
|
|
169
|
+
fetchResults();
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
fetchGeneralResults();
|
|
173
|
+
}
|
|
174
|
+
}, [value, scGroup]);
|
|
147
175
|
/**
|
|
148
176
|
* Handles dialog close
|
|
149
177
|
*/
|
|
@@ -180,7 +208,7 @@ export default function GroupInviteButton(inProps) {
|
|
|
180
208
|
switch (reason) {
|
|
181
209
|
case 'input':
|
|
182
210
|
setValue(value);
|
|
183
|
-
!value &&
|
|
211
|
+
!value && setSuggested([]);
|
|
184
212
|
break;
|
|
185
213
|
case 'reset':
|
|
186
214
|
setValue(value);
|
|
@@ -210,6 +238,13 @@ export default function GroupInviteButton(inProps) {
|
|
|
210
238
|
setInvited(invited.filter((v) => v !== option));
|
|
211
239
|
setList((prev) => [...prev, option]);
|
|
212
240
|
};
|
|
241
|
+
const filterOptions = (options, { inputValue }) => {
|
|
242
|
+
return options.filter((option) => {
|
|
243
|
+
const usernameMatch = option.username.toLowerCase().includes(inputValue.toLowerCase());
|
|
244
|
+
const nameMatch = option.real_name.toLowerCase().includes(inputValue.toLowerCase());
|
|
245
|
+
return usernameMatch || nameMatch;
|
|
246
|
+
});
|
|
247
|
+
};
|
|
213
248
|
/**
|
|
214
249
|
* If in group edit mode and logged-in user is not also the group manager, the component is hidden.
|
|
215
250
|
// */
|
|
@@ -230,7 +265,7 @@ export default function GroupInviteButton(inProps) {
|
|
|
230
265
|
React.createElement(LoadingButton, { size: "small", color: "secondary", variant: "contained", onClick: handleSendInvitations, loading: isSending, disabled: !invited.length },
|
|
231
266
|
React.createElement(FormattedMessage, { id: "ui.groupInviteButton.dialog.button.end", defaultMessage: "ui.groupInviteButton.dialog.button.end" }))) },
|
|
232
267
|
React.createElement(Box, { className: classes.dialogContent },
|
|
233
|
-
React.createElement(Autocomplete, { className: classes.autocomplete, loading: loading, size: "small", multiple: true, freeSolo: true, disableClearable: true, options:
|
|
268
|
+
React.createElement(Autocomplete, { 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.createElement(Box, Object.assign({ component: "li" }, props),
|
|
234
269
|
React.createElement(Avatar, { alt: option.username, src: option.avatar }),
|
|
235
270
|
React.createElement(Typography, { ml: 1 }, option.username))), renderInput: (params) => (React.createElement(TextField, Object.assign({}, params, { variant: "outlined", placeholder: `${intl.formatMessage(messages.placeholder)}`, InputProps: Object.assign(Object.assign({}, params.InputProps), { className: classes.input, startAdornment: (React.createElement(React.Fragment, null,
|
|
236
271
|
React.createElement(InputAdornment, { position: "start" },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __rest } from "tslib";
|
|
2
2
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import { styled } from '@mui/material/styles';
|
|
4
|
-
import { Box, Button, Grid, TextField, Typography } from '@mui/material';
|
|
4
|
+
import { Box, Button, Grid, TextField, Typography, useMediaQuery, useTheme } from '@mui/material';
|
|
5
5
|
import { Endpoints, GroupService, http } from '@selfcommunity/api-services';
|
|
6
6
|
import { Logger, sortByAttr } from '@selfcommunity/utils';
|
|
7
7
|
import { SCPreferences, useSCPreferences, useSCUser } from '@selfcommunity/react-core';
|
|
@@ -12,7 +12,7 @@ import { SCOPE_SC_UI } from '../../constants/Errors';
|
|
|
12
12
|
import { useThemeProps } from '@mui/system';
|
|
13
13
|
import HiddenPlaceholder from '../../shared/HiddenPlaceholder';
|
|
14
14
|
import { PREFIX } from './constants';
|
|
15
|
-
import Group from '../Group';
|
|
15
|
+
import Group, { GroupSkeleton } from '../Group';
|
|
16
16
|
import { DEFAULT_PAGINATION_OFFSET } from '../../constants/Pagination';
|
|
17
17
|
import InfiniteScroll from '../../shared/InfiniteScroll';
|
|
18
18
|
const classes = {
|
|
@@ -71,6 +71,8 @@ export default function Groups(inProps) {
|
|
|
71
71
|
const [loading, setLoading] = useState(true);
|
|
72
72
|
const [next, setNext] = useState(null);
|
|
73
73
|
const [search, setSearch] = useState('');
|
|
74
|
+
const theme = useTheme();
|
|
75
|
+
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
|
74
76
|
// CONTEXT
|
|
75
77
|
const scUserContext = useSCUser();
|
|
76
78
|
const scPreferencesContext = useSCPreferences();
|
|
@@ -165,7 +167,7 @@ export default function Groups(inProps) {
|
|
|
165
167
|
React.createElement(Typography, { variant: "h4" },
|
|
166
168
|
React.createElement(FormattedMessage, { id: "ui.groups.noGroups.title", defaultMessage: "ui.groups.noGroups.title" })),
|
|
167
169
|
React.createElement(Typography, { variant: "body1" },
|
|
168
|
-
React.createElement(FormattedMessage, { id: "ui.groups.noGroups.subtitle", defaultMessage: "ui.groups.noGroups.subtitle" })))) : (React.createElement(InfiniteScroll, { dataLength: groups.length, next: handleNext, hasMoreNext: Boolean(next), loaderNext: React.createElement(Skeleton, { groupsNumber: 2 }), endMessage: React.createElement(Typography, { component: "div", className: classes.endMessage },
|
|
170
|
+
React.createElement(FormattedMessage, { id: "ui.groups.noGroups.subtitle", defaultMessage: "ui.groups.noGroups.subtitle" })))) : (React.createElement(InfiniteScroll, { dataLength: groups.length, next: handleNext, hasMoreNext: Boolean(next), loaderNext: isMobile ? React.createElement(GroupSkeleton, null) : React.createElement(Skeleton, { groupsNumber: 2 }), endMessage: React.createElement(Typography, { component: "div", className: classes.endMessage },
|
|
169
171
|
React.createElement(FormattedMessage, { id: "ui.groups.endMessage", defaultMessage: "ui.groups.endMessage", values: {
|
|
170
172
|
button: (chunk) => (React.createElement(Button, { color: "secondary", variant: "text", onClick: handleScrollUp }, chunk))
|
|
171
173
|
} })) },
|
|
@@ -35,7 +35,7 @@ const Root = styled(Box, {
|
|
|
35
35
|
*
|
|
36
36
|
*/
|
|
37
37
|
export default function GroupsSkeleton(inProps) {
|
|
38
|
-
const { className, GroupSkeletonProps = {}, groupsNumber =
|
|
38
|
+
const { className, GroupSkeletonProps = {}, groupsNumber = 20 } = inProps, rest = __rest(inProps, ["className", "GroupSkeletonProps", "groupsNumber"]);
|
|
39
39
|
return (React.createElement(Root, Object.assign({ className: classNames(classes.root, className) }, rest),
|
|
40
40
|
React.createElement(Grid, { container: true, spacing: { xs: 3 }, className: classes.groups }, [...Array(groupsNumber)].map((category, index) => (React.createElement(Grid, { item: true, xs: 12, sm: 8, md: 6, key: index },
|
|
41
41
|
React.createElement(GroupSkeleton, Object.assign({ elevation: 0, variant: 'outlined' }, GroupSkeletonProps))))))));
|
|
@@ -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.|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __rest } from "tslib";
|
|
2
|
-
import { Button, IconButton, styled, Toolbar } from '@mui/material';
|
|
3
|
-
import React, { useCallback, useState } from 'react';
|
|
2
|
+
import { Badge, Button, IconButton, styled, Toolbar } from '@mui/material';
|
|
3
|
+
import React, { useCallback, useMemo, useState } from 'react';
|
|
4
4
|
import { Link, SCPreferences, SCRoutes, useSCPreferences, useSCRouting, useSCUser } from '@selfcommunity/react-core';
|
|
5
5
|
import Icon from '@mui/material/Icon';
|
|
6
6
|
import { useThemeProps } from '@mui/system';
|
|
@@ -11,11 +11,13 @@ import SearchDialog from '../SearchDialog';
|
|
|
11
11
|
import NavigationSettingsIconButton from '../NavigationSettingsIconButton';
|
|
12
12
|
import NavigationMenuIconButton from '../NavigationMenuIconButton';
|
|
13
13
|
import { PREFIX } from './constants';
|
|
14
|
+
import { SCFeatureName } from '@selfcommunity/types';
|
|
14
15
|
const classes = {
|
|
15
16
|
root: `${PREFIX}-root`,
|
|
16
17
|
logo: `${PREFIX}-logo`,
|
|
17
18
|
search: `${PREFIX}-search`,
|
|
18
19
|
searchDialog: `${PREFIX}-search-dialog`,
|
|
20
|
+
notifications: `${PREFIX}-notifications`,
|
|
19
21
|
settings: `${PREFIX}-settings`,
|
|
20
22
|
settingsDialog: `${PREFIX}-settings-dialog`,
|
|
21
23
|
login: `${PREFIX}-login`
|
|
@@ -50,6 +52,7 @@ const Root = styled(Toolbar, {
|
|
|
50
52
|
|logo|.SCNavigationToolbarMobile-logo|Styles applied to the logo element.|
|
|
51
53
|
|search|.SCNavigationToolbarMobile-search|Styles applied to the search button element|
|
|
52
54
|
|searchDialog|.SCNavigationToolbarMobile-search-dialog|Styles applied to the search dialog element|
|
|
55
|
+
|notifications|.SCNavigationToolbarMobile-notifications|Styles applied to the notifications button element|
|
|
53
56
|
|settings|.SCNavigationToolbarMobile-settings|Styles applied to the settings button element|
|
|
54
57
|
|settingsDialog|.SCNavigationToolbarMobile-settingsDialog|Styles applied to the settings dialog elements|
|
|
55
58
|
|login|.SCNavigationToolbarMobile-login|Styles applied to the login element.|
|
|
@@ -67,9 +70,11 @@ export default function NavigationToolbarMobile(inProps) {
|
|
|
67
70
|
const scUserContext = useSCUser();
|
|
68
71
|
const scRoutingContext = useSCRouting();
|
|
69
72
|
// PREFERENCES
|
|
70
|
-
const { preferences } = useSCPreferences();
|
|
73
|
+
const { preferences, features } = useSCPreferences();
|
|
71
74
|
// STATE
|
|
72
75
|
const [searchOpen, setSearchOpen] = useState(false);
|
|
76
|
+
// MEMO
|
|
77
|
+
const groupsEnabled = useMemo(() => features.includes(SCFeatureName.GROUPING), [features]);
|
|
73
78
|
// HANDLERS
|
|
74
79
|
const handleOpenSearch = useCallback(() => {
|
|
75
80
|
setSearchOpen(true);
|
|
@@ -92,6 +97,9 @@ export default function NavigationToolbarMobile(inProps) {
|
|
|
92
97
|
React.createElement(Icon, null, "search")),
|
|
93
98
|
React.createElement(SearchDialog, { className: classes.searchDialog, fullScreen: true, open: searchOpen, SearchAutocompleteProps: Object.assign(Object.assign({}, SearchAutocompleteProps), { onClear: handleCloseSearch }) }))),
|
|
94
99
|
endActions,
|
|
100
|
+
scUserContext.user && groupsEnabled && (React.createElement(IconButton, { className: classes.notifications, component: Link, to: scRoutingContext.url(SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}) },
|
|
101
|
+
React.createElement(Badge, { badgeContent: scUserContext.user.unseen_notification_banners_counter + scUserContext.user.unseen_interactions_counter, color: "secondary" },
|
|
102
|
+
React.createElement(Icon, null, "notifications_active")))),
|
|
95
103
|
scUserContext.user ? (React.createElement(NavigationSettingsIconButtonComponent, { className: classes.settings })) : (React.createElement(Button, { className: classes.login, color: "inherit", component: Link, to: scRoutingContext.url(SCRoutes.SIGNIN_ROUTE_NAME, {}) },
|
|
96
104
|
React.createElement(FormattedMessage, { id: "ui.appBar.navigation.login", defaultMessage: "ui.appBar.navigation.login" })))));
|
|
97
105
|
}
|