@selfcommunity/react-ui 0.7.9-alpha.39 → 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.
@@ -59,6 +59,7 @@ const Root = (0, styles_1.styled)(BaseItemButton_1.default, {
59
59
  * @param inProps
60
60
  */
61
61
  function Group(inProps) {
62
+ var _a;
62
63
  // PROPS
63
64
  const props = (0, system_1.useThemeProps)({
64
65
  props: inProps,
@@ -69,6 +70,9 @@ function Group(inProps) {
69
70
  const { scGroup } = (0, react_core_1.useSCFetchGroup)({ id: groupId, group });
70
71
  // CONTEXT
71
72
  const scRoutingContext = (0, react_core_1.useSCRouting)();
73
+ const scUserContext = (0, react_core_1.useSCUser)();
74
+ // CONST
75
+ const isGroupAdmin = (0, react_1.useMemo)(() => { var _a; return scUserContext.user && ((_a = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _a === void 0 ? void 0 : _a.id) === scUserContext.user.id; }, [scUserContext.user, (_a = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _a === void 0 ? void 0 : _a.id]);
72
76
  const [openAlert, setOpenAlert] = (0, react_1.useState)(false);
73
77
  // INTL
74
78
  const intl = (0, react_intl_1.useIntl)();
@@ -79,6 +83,7 @@ function Group(inProps) {
79
83
  function renderAuthenticatedActions() {
80
84
  return (react_1.default.createElement(material_1.Stack, { className: classes.actions, direction: "row", alignItems: "center", justifyContent: "center", spacing: 2 },
81
85
  react_1.default.createElement(material_1.Icon, null, (group === null || group === void 0 ? void 0 : group.privacy) === types_1.SCGroupPrivacyType.PRIVATE ? 'private' : 'public'),
86
+ isGroupAdmin && react_1.default.createElement(material_1.Icon, null, "face"),
82
87
  react_1.default.createElement(GroupSubscribeButton_1.default, Object.assign({ group: group, groupId: groupId }, groupSubscribeButtonProps))));
83
88
  }
84
89
  /**
@@ -173,8 +173,10 @@ function GroupForm(inProps) {
173
173
  if (field.emotionalImageOriginalFile) {
174
174
  formData.append('emotional_image_original', field.emotionalImageOriginalFile);
175
175
  }
176
- for (const key in field.invitedUsers) {
177
- formData.append(key, field.invitedUsers[key]);
176
+ if (!group) {
177
+ for (const key in field.invitedUsers) {
178
+ formData.append(key, field.invitedUsers[key]);
179
+ }
178
180
  }
179
181
  let groupService;
180
182
  if (group) {
@@ -251,8 +253,9 @@ function GroupForm(inProps) {
251
253
  react_1.default.createElement(material_1.Icon, null, "visibility"),
252
254
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupForm.visibility.visible", defaultMessage: "ui.groupForm.visibility.visible" }))),
253
255
  react_1.default.createElement(material_1.Typography, { variant: "body2", className: classes.visibilitySectionInfo }, !field.isVisible ? (react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupForm.visibility.hidden.info", defaultMessage: "ui.groupForm.visibility.hidden.info", values: { b: (chunks) => react_1.default.createElement("strong", null, chunks) } })) : (react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupForm.visibility.visible.info", defaultMessage: "ui.groupForm.visibility.visible.info", values: { b: (chunks) => react_1.default.createElement("strong", null, chunks) } }))))))),
254
- react_1.default.createElement(material_1.Divider, null),
255
- react_1.default.createElement(material_1.Box, { className: classes.inviteSection },
256
- react_1.default.createElement(GroupInviteButton_1.default, { handleInvitations: handleInviteSection })))));
256
+ !group && (react_1.default.createElement(react_1.default.Fragment, null,
257
+ react_1.default.createElement(material_1.Divider, null),
258
+ react_1.default.createElement(material_1.Box, { className: classes.inviteSection },
259
+ react_1.default.createElement(GroupInviteButton_1.default, { handleInvitations: handleInviteSection })))))));
257
260
  }
258
261
  exports.default = GroupForm;
@@ -22,6 +22,7 @@ const classes = {
22
22
  privacyTitle: `${constants_1.PREFIX}-privacy-title`,
23
23
  visibility: `${constants_1.PREFIX}-visibility`,
24
24
  visibilityTitle: `${constants_1.PREFIX}-visibility-title`,
25
+ admin: `${constants_1.PREFIX}-admin`,
25
26
  date: `${constants_1.PREFIX}-date`
26
27
  };
27
28
  const Root = (0, styles_1.styled)(Widget_1.default, {
@@ -125,6 +126,8 @@ function GroupInfoWidget(inProps) {
125
126
  react_1.default.createElement(material_1.Typography, { variant: "body2" },
126
127
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupForm.visibility.hidden.info", defaultMessage: "ui.groupForm.visibility.hidden.info", values: { b: (chunks) => react_1.default.createElement("strong", null, chunks) } })))))),
127
128
  react_1.default.createElement(material_1.Typography, { variant: "body2", className: classes.date },
128
- react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupInfoWidget.date", defaultMessage: "ui.groupInfoWidget.date", values: { date: intl.formatDate(scGroup.created_at, { day: 'numeric', year: 'numeric', month: 'long' }) } })))));
129
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupInfoWidget.date", defaultMessage: "ui.groupInfoWidget.date", values: { date: intl.formatDate(scGroup.created_at, { day: 'numeric', year: 'numeric', month: 'long' }) } })),
130
+ react_1.default.createElement(material_1.Typography, { variant: "body2", className: classes.admin },
131
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupInfoWidget.admin", defaultMessage: "ui.groupInfoWidget.admin", values: { b: (chunks) => react_1.default.createElement("strong", null, chunks), admin: scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by.username } })))));
129
132
  }
130
133
  exports.default = GroupInfoWidget;
@@ -91,11 +91,11 @@ function GroupInviteButton(inProps) {
91
91
  const [loading, setLoading] = (0, react_1.useState)(false);
92
92
  const [invited, setInvited] = (0, react_1.useState)([]);
93
93
  function convertToInvitedUsersObject(data) {
94
- const invited_users = {};
94
+ const invite_users = {};
95
95
  data.forEach((user, index) => {
96
- invited_users[`invited_users[${index}]`] = user.id;
96
+ invite_users[`invite_users[${index}]`] = user.id;
97
97
  });
98
- return invited_users;
98
+ return invite_users;
99
99
  }
100
100
  /**
101
101
  * Memoized users invited ids
@@ -22,10 +22,12 @@ const constants_1 = require("./constants");
22
22
  const User_1 = tslib_1.__importStar(require("../User"));
23
23
  const GroupInviteButton_1 = tslib_1.__importDefault(require("../GroupInviteButton"));
24
24
  const GroupSettingsIconButton_1 = tslib_1.__importDefault(require("../GroupSettingsIconButton"));
25
+ const Icon_1 = tslib_1.__importDefault(require("@mui/material/Icon"));
25
26
  const classes = {
26
27
  root: `${constants_1.PREFIX}-root`,
27
28
  title: `${constants_1.PREFIX}-title`,
28
29
  actions: `${constants_1.PREFIX}-actions`,
30
+ badge: `${constants_1.PREFIX}-badge`,
29
31
  noResults: `${constants_1.PREFIX}-no-results`,
30
32
  showMore: `${constants_1.PREFIX}-show-more`,
31
33
  dialogRoot: `${constants_1.PREFIX}-dialog-root`,
@@ -197,10 +199,11 @@ function GroupMembersWidget(inProps) {
197
199
  !state.count ? (react_1.default.createElement(material_1.Typography, { className: classes.noResults, variant: "body2" },
198
200
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupMembersWidget.subtitle.noResults", defaultMessage: "" }))) : (react_1.default.createElement(react_1.default.Fragment, null,
199
201
  react_1.default.createElement(List_1.default, null, state.results.slice(0, state.visibleItems).map((user) => {
200
- var _a;
202
+ var _a, _b;
201
203
  return (react_1.default.createElement(material_1.ListItem, { key: user.id },
202
204
  react_1.default.createElement(User_1.default, { elevation: 0, actions: isGroupAdmin ? (react_1.default.createElement(GroupSettingsIconButton_1.default, { group: scGroup, user: user, onRemoveSuccess: () => handleRefresh(user.id) })) : ((_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.id) !== user.id ? (react_1.default.createElement(material_1.Button, { size: "small", variant: "outlined", component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.USER_PRIVATE_MESSAGES_ROUTE_NAME, user) },
203
- react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupSettingsIconButton.item.message", defaultMessage: "ui.groupSettingsIconButton.item.message" }))) : null, user: user, userId: user.id })));
205
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupSettingsIconButton.item.message", defaultMessage: "ui.groupSettingsIconButton.item.message" }))) : null, badgeContent: ((_b = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _b === void 0 ? void 0 : _b.id) === user.id ? (react_1.default.createElement(material_1.Avatar, { className: classes.badge },
206
+ react_1.default.createElement(Icon_1.default, null, "face"))) : null, user: user, userId: user.id })));
204
207
  })),
205
208
  state.count > state.visibleItems && (react_1.default.createElement(material_1.Button, { className: classes.showMore, onClick: handleToggleDialogOpen },
206
209
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupMembersWidget.button.showMore", defaultMessage: "ui.groupMembersWidget.button.showMore" }))))),
@@ -208,10 +211,11 @@ function GroupMembersWidget(inProps) {
208
211
  react_1.default.createElement(InfiniteScroll_1.default, { dataLength: state.results.length, next: handleNext, hasMoreNext: Boolean(state.next), loaderNext: react_1.default.createElement(User_1.UserSkeleton, Object.assign({ elevation: 0 }, UserProps)), height: isMobile ? '100%' : 400, endMessage: react_1.default.createElement(material_1.Typography, { className: classes.endMessage },
209
212
  react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupMembersWidget.noMoreResults", defaultMessage: "ui.groupMembersWidget.noMoreResults" })) },
210
213
  react_1.default.createElement(List_1.default, null, state.results.map((user) => {
211
- var _a;
214
+ var _a, _b;
212
215
  return (react_1.default.createElement(material_1.ListItem, { key: user.id },
213
216
  react_1.default.createElement(User_1.default, { elevation: 0, actions: isGroupAdmin ? (react_1.default.createElement(GroupSettingsIconButton_1.default, { group: scGroup, user: user, onRemoveSuccess: () => handleRefresh(user.id) })) : ((_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.id) !== user.id ? (react_1.default.createElement(material_1.Button, { size: "small", variant: "outlined", component: react_core_1.Link, to: scRoutingContext.url(react_core_1.SCRoutes.USER_PRIVATE_MESSAGES_ROUTE_NAME, user) },
214
- react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupSettingsIconButton.item.message", defaultMessage: "ui.groupSettingsIconButton.item.message" }))) : null, user: user, userId: user.id })));
217
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groupSettingsIconButton.item.message", defaultMessage: "ui.groupSettingsIconButton.item.message" }))) : null, badgeContent: ((_b = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _b === void 0 ? void 0 : _b.id) === user.id ? (react_1.default.createElement(material_1.Avatar, { className: classes.badge },
218
+ react_1.default.createElement(Icon_1.default, null, "face"))) : null, user: user, userId: user.id })));
215
219
  })))))),
216
220
  react_1.default.createElement(material_1.CardActions, { className: classes.actions },
217
221
  react_1.default.createElement(GroupInviteButton_1.default, { groupId: scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, group: scGroup }))));
@@ -26,6 +26,21 @@ export interface GroupsProps {
26
26
  * @default null
27
27
  */
28
28
  general?: boolean;
29
+ /**
30
+ * Show/Hide filters
31
+ * @default false
32
+ */
33
+ showFilters?: boolean;
34
+ /**
35
+ * Override filter func
36
+ * @default null
37
+ */
38
+ handleFilterGroups?: (groups: SCGroupType[]) => SCGroupType[];
39
+ /**
40
+ * Filters component
41
+ * @param props
42
+ */
43
+ filters?: JSX.Element;
29
44
  /**
30
45
  * Other props
31
46
  */
@@ -17,6 +17,7 @@ const constants_1 = require("./constants");
17
17
  const Group_1 = tslib_1.__importDefault(require("../Group"));
18
18
  const classes = {
19
19
  root: `${constants_1.PREFIX}-root`,
20
+ filters: `${constants_1.PREFIX}-filter`,
20
21
  groups: `${constants_1.PREFIX}-groups`,
21
22
  item: `${constants_1.PREFIX}-item`,
22
23
  noResults: `${constants_1.PREFIX}-no-results`,
@@ -64,10 +65,11 @@ function Groups(inProps) {
64
65
  props: inProps,
65
66
  name: constants_1.PREFIX
66
67
  });
67
- const { endpoint, className, GroupComponentProps = { variant: 'outlined', ButtonBaseProps: { disableRipple: true, component: material_1.Box } }, prefetchedGroups = [], general } = props, rest = tslib_1.__rest(props, ["endpoint", "className", "GroupComponentProps", "prefetchedGroups", "general"]);
68
+ const { endpoint, className, GroupComponentProps = { variant: 'outlined', ButtonBaseProps: { disableRipple: true, component: material_1.Box } }, prefetchedGroups = [], showFilters = false, filters, handleFilterGroups, general } = props, rest = tslib_1.__rest(props, ["endpoint", "className", "GroupComponentProps", "prefetchedGroups", "showFilters", "filters", "handleFilterGroups", "general"]);
68
69
  // STATE
69
70
  const [groups, setGroups] = (0, react_1.useState)([]);
70
71
  const [loading, setLoading] = (0, react_1.useState)(true);
72
+ const [filterName, setFilterName] = (0, react_1.useState)('');
71
73
  // CONTEXT
72
74
  const scUserContext = (0, react_core_1.useSCUser)();
73
75
  const scPreferencesContext = (0, react_core_1.useSCPreferences)();
@@ -120,16 +122,42 @@ function Groups(inProps) {
120
122
  setGroups(_updated);
121
123
  }
122
124
  };
125
+ /**
126
+ * Get groups filtered
127
+ */
128
+ const getFilteredGroups = () => {
129
+ if (handleFilterGroups) {
130
+ return handleFilterGroups(groups);
131
+ }
132
+ if (filterName) {
133
+ return groups.filter((g) => g.name.toLowerCase().includes(filterName.toLowerCase()));
134
+ }
135
+ return groups;
136
+ };
137
+ /**
138
+ * Handle change filter name
139
+ * @param event
140
+ */
141
+ const handleOnChangeFilterName = (event) => {
142
+ setFilterName(event.target.value);
143
+ };
144
+ /**
145
+ * Renders groups list
146
+ */
147
+ const filteredGroups = (0, utils_1.sortByAttr)(getFilteredGroups(), 'order');
148
+ const content = (react_1.default.createElement(react_1.default.Fragment, null,
149
+ showFilters && (react_1.default.createElement(material_1.Grid, { container: true, direction: "row", justifyContent: "center", alignItems: "center", className: classes.filters }, filters ? (filters) : (react_1.default.createElement(material_1.Grid, { item: true, xs: 12, md: 6 },
150
+ react_1.default.createElement(material_1.TextField, { fullWidth: true, value: filterName, label: react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.filterByName", defaultMessage: "ui.groups.filterByName" }), variant: "outlined", onChange: handleOnChangeFilterName, disabled: loading }))))),
151
+ loading ? (react_1.default.createElement(Skeleton_1.default, null)) : (react_1.default.createElement(react_1.default.Fragment, null, !groups.length ? (react_1.default.createElement(material_1.Box, { className: classes.noResults },
152
+ react_1.default.createElement(material_1.Typography, { variant: "h4" },
153
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.noGroups.title", defaultMessage: "ui.groups.noGroups.title" })),
154
+ react_1.default.createElement(material_1.Typography, { variant: "body1" },
155
+ react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.noGroups.subtitle", defaultMessage: "ui.groups.noGroups.subtitle" })))) : (react_1.default.createElement(material_1.Grid, { container: true, spacing: { xs: 3 }, className: classes.groups }, filteredGroups.map((group) => (react_1.default.createElement(material_1.Grid, { item: true, xs: 12, sm: 8, md: 6, key: group.id, className: classes.item },
156
+ react_1.default.createElement(Group_1.default, Object.assign({ group: group, groupId: group.id, groupSubscribeButtonProps: { onSubscribe: handleSubscribe } }, GroupComponentProps)))))))))));
123
157
  // RENDER
124
158
  if (!contentAvailability && !scUserContext.user) {
125
159
  return react_1.default.createElement(HiddenPlaceholder_1.default, null);
126
160
  }
127
- const content = (react_1.default.createElement(react_1.default.Fragment, null, loading ? (react_1.default.createElement(Skeleton_1.default, null)) : (react_1.default.createElement(react_1.default.Fragment, null, !groups.length ? (react_1.default.createElement(material_1.Box, { className: classes.noResults },
128
- react_1.default.createElement(material_1.Typography, { variant: "h4" },
129
- react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.noGroups.title", defaultMessage: "ui.groups.noGroups.title" })),
130
- react_1.default.createElement(material_1.Typography, { variant: "body1" },
131
- react_1.default.createElement(react_intl_1.FormattedMessage, { id: "ui.groups.noGroups.subtitle", defaultMessage: "ui.groups.noGroups.subtitle" })))) : (react_1.default.createElement(material_1.Grid, { container: true, spacing: { xs: 3 }, className: classes.groups }, groups.map((group) => (react_1.default.createElement(material_1.Grid, { item: true, xs: 12, sm: 8, md: 6, key: group.id, className: classes.item },
132
- react_1.default.createElement(Group_1.default, Object.assign({ group: group, groupId: group.id, groupSubscribeButtonProps: { onSubscribe: handleSubscribe } }, GroupComponentProps)))))))))));
133
161
  return (react_1.default.createElement(Root, Object.assign({ className: (0, classnames_1.default)(classes.root, className) }, rest), content));
134
162
  }
135
163
  exports.default = Groups;
@@ -1,9 +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
5
  import { SCGroupPrivacyType } from '@selfcommunity/types';
6
- import { Link, SCRoutes, useSCFetchGroup, useSCRouting } from '@selfcommunity/react-core';
6
+ import { Link, SCRoutes, useSCFetchGroup, useSCRouting, useSCUser } from '@selfcommunity/react-core';
7
7
  import { defineMessages, useIntl } from 'react-intl';
8
8
  import classNames from 'classnames';
9
9
  import { useThemeProps } from '@mui/system';
@@ -57,6 +57,7 @@ const Root = styled(BaseItemButton, {
57
57
  * @param inProps
58
58
  */
59
59
  export default function Group(inProps) {
60
+ var _a;
60
61
  // PROPS
61
62
  const props = useThemeProps({
62
63
  props: inProps,
@@ -67,6 +68,9 @@ export default function Group(inProps) {
67
68
  const { scGroup } = useSCFetchGroup({ id: groupId, group });
68
69
  // CONTEXT
69
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]);
70
74
  const [openAlert, setOpenAlert] = useState(false);
71
75
  // INTL
72
76
  const intl = useIntl();
@@ -77,6 +81,7 @@ export default function Group(inProps) {
77
81
  function renderAuthenticatedActions() {
78
82
  return (React.createElement(Stack, { className: classes.actions, direction: "row", alignItems: "center", justifyContent: "center", spacing: 2 },
79
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"),
80
85
  React.createElement(GroupSubscribeButton, Object.assign({ group: group, groupId: groupId }, groupSubscribeButtonProps))));
81
86
  }
82
87
  /**
@@ -171,8 +171,10 @@ export default function GroupForm(inProps) {
171
171
  if (field.emotionalImageOriginalFile) {
172
172
  formData.append('emotional_image_original', field.emotionalImageOriginalFile);
173
173
  }
174
- for (const key in field.invitedUsers) {
175
- formData.append(key, field.invitedUsers[key]);
174
+ if (!group) {
175
+ for (const key in field.invitedUsers) {
176
+ formData.append(key, field.invitedUsers[key]);
177
+ }
176
178
  }
177
179
  let groupService;
178
180
  if (group) {
@@ -249,7 +251,8 @@ export default function GroupForm(inProps) {
249
251
  React.createElement(Icon, null, "visibility"),
250
252
  React.createElement(FormattedMessage, { id: "ui.groupForm.visibility.visible", defaultMessage: "ui.groupForm.visibility.visible" }))),
251
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) } }))))))),
252
- React.createElement(Divider, null),
253
- React.createElement(Box, { className: classes.inviteSection },
254
- React.createElement(GroupInviteButton, { handleInvitations: handleInviteSection })))));
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 })))))));
255
258
  }
@@ -20,6 +20,7 @@ const classes = {
20
20
  privacyTitle: `${PREFIX}-privacy-title`,
21
21
  visibility: `${PREFIX}-visibility`,
22
22
  visibilityTitle: `${PREFIX}-visibility-title`,
23
+ admin: `${PREFIX}-admin`,
23
24
  date: `${PREFIX}-date`
24
25
  };
25
26
  const Root = styled(Widget, {
@@ -123,5 +124,7 @@ export default function GroupInfoWidget(inProps) {
123
124
  React.createElement(Typography, { variant: "body2" },
124
125
  React.createElement(FormattedMessage, { id: "ui.groupForm.visibility.hidden.info", defaultMessage: "ui.groupForm.visibility.hidden.info", values: { b: (chunks) => React.createElement("strong", null, chunks) } })))))),
125
126
  React.createElement(Typography, { variant: "body2", className: classes.date },
126
- 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 } })))));
127
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 invited_users = {};
92
+ const invite_users = {};
93
93
  data.forEach((user, index) => {
94
- invited_users[`invited_users[${index}]`] = user.id;
94
+ invite_users[`invite_users[${index}]`] = user.id;
95
95
  });
96
- return invited_users;
96
+ return invite_users;
97
97
  }
98
98
  /**
99
99
  * Memoized users invited ids
@@ -2,7 +2,7 @@ import { __rest } from "tslib";
2
2
  import React, { useEffect, useMemo, useReducer, useState } from 'react';
3
3
  import { styled } from '@mui/material/styles';
4
4
  import List from '@mui/material/List';
5
- import { Button, CardActions, CardContent, ListItem, Typography, useMediaQuery, useTheme } from '@mui/material';
5
+ import { Avatar, Button, CardActions, CardContent, ListItem, Typography, useMediaQuery, useTheme } from '@mui/material';
6
6
  import Widget from '../Widget';
7
7
  import { http, Endpoints, GroupService } from '@selfcommunity/api-services';
8
8
  import { CacheStrategies, isInteger, Logger } from '@selfcommunity/utils';
@@ -20,10 +20,12 @@ import { PREFIX } from './constants';
20
20
  import User, { UserSkeleton } from '../User';
21
21
  import GroupInviteButton from '../GroupInviteButton';
22
22
  import GroupSettingsIconButton from '../GroupSettingsIconButton';
23
+ import Icon from '@mui/material/Icon';
23
24
  const classes = {
24
25
  root: `${PREFIX}-root`,
25
26
  title: `${PREFIX}-title`,
26
27
  actions: `${PREFIX}-actions`,
28
+ badge: `${PREFIX}-badge`,
27
29
  noResults: `${PREFIX}-no-results`,
28
30
  showMore: `${PREFIX}-show-more`,
29
31
  dialogRoot: `${PREFIX}-dialog-root`,
@@ -195,10 +197,11 @@ export default function GroupMembersWidget(inProps) {
195
197
  !state.count ? (React.createElement(Typography, { className: classes.noResults, variant: "body2" },
196
198
  React.createElement(FormattedMessage, { id: "ui.groupMembersWidget.subtitle.noResults", defaultMessage: "" }))) : (React.createElement(React.Fragment, null,
197
199
  React.createElement(List, null, state.results.slice(0, state.visibleItems).map((user) => {
198
- var _a;
200
+ var _a, _b;
199
201
  return (React.createElement(ListItem, { key: user.id },
200
202
  React.createElement(User, { elevation: 0, actions: isGroupAdmin ? (React.createElement(GroupSettingsIconButton, { group: scGroup, user: user, onRemoveSuccess: () => handleRefresh(user.id) })) : ((_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.id) !== user.id ? (React.createElement(Button, { size: "small", variant: "outlined", component: Link, to: scRoutingContext.url(SCRoutes.USER_PRIVATE_MESSAGES_ROUTE_NAME, user) },
201
- React.createElement(FormattedMessage, { id: "ui.groupSettingsIconButton.item.message", defaultMessage: "ui.groupSettingsIconButton.item.message" }))) : null, user: user, userId: user.id })));
203
+ React.createElement(FormattedMessage, { id: "ui.groupSettingsIconButton.item.message", defaultMessage: "ui.groupSettingsIconButton.item.message" }))) : null, badgeContent: ((_b = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _b === void 0 ? void 0 : _b.id) === user.id ? (React.createElement(Avatar, { className: classes.badge },
204
+ React.createElement(Icon, null, "face"))) : null, user: user, userId: user.id })));
202
205
  })),
203
206
  state.count > state.visibleItems && (React.createElement(Button, { className: classes.showMore, onClick: handleToggleDialogOpen },
204
207
  React.createElement(FormattedMessage, { id: "ui.groupMembersWidget.button.showMore", defaultMessage: "ui.groupMembersWidget.button.showMore" }))))),
@@ -206,10 +209,11 @@ export default function GroupMembersWidget(inProps) {
206
209
  React.createElement(InfiniteScroll, { dataLength: state.results.length, next: handleNext, hasMoreNext: Boolean(state.next), loaderNext: React.createElement(UserSkeleton, Object.assign({ elevation: 0 }, UserProps)), height: isMobile ? '100%' : 400, endMessage: React.createElement(Typography, { className: classes.endMessage },
207
210
  React.createElement(FormattedMessage, { id: "ui.groupMembersWidget.noMoreResults", defaultMessage: "ui.groupMembersWidget.noMoreResults" })) },
208
211
  React.createElement(List, null, state.results.map((user) => {
209
- var _a;
212
+ var _a, _b;
210
213
  return (React.createElement(ListItem, { key: user.id },
211
214
  React.createElement(User, { elevation: 0, actions: isGroupAdmin ? (React.createElement(GroupSettingsIconButton, { group: scGroup, user: user, onRemoveSuccess: () => handleRefresh(user.id) })) : ((_a = scUserContext === null || scUserContext === void 0 ? void 0 : scUserContext.user) === null || _a === void 0 ? void 0 : _a.id) !== user.id ? (React.createElement(Button, { size: "small", variant: "outlined", component: Link, to: scRoutingContext.url(SCRoutes.USER_PRIVATE_MESSAGES_ROUTE_NAME, user) },
212
- React.createElement(FormattedMessage, { id: "ui.groupSettingsIconButton.item.message", defaultMessage: "ui.groupSettingsIconButton.item.message" }))) : null, user: user, userId: user.id })));
215
+ React.createElement(FormattedMessage, { id: "ui.groupSettingsIconButton.item.message", defaultMessage: "ui.groupSettingsIconButton.item.message" }))) : null, badgeContent: ((_b = scGroup === null || scGroup === void 0 ? void 0 : scGroup.managed_by) === null || _b === void 0 ? void 0 : _b.id) === user.id ? (React.createElement(Avatar, { className: classes.badge },
216
+ React.createElement(Icon, null, "face"))) : null, user: user, userId: user.id })));
213
217
  })))))),
214
218
  React.createElement(CardActions, { className: classes.actions },
215
219
  React.createElement(GroupInviteButton, { groupId: scGroup === null || scGroup === void 0 ? void 0 : scGroup.id, group: scGroup }))));
@@ -26,6 +26,21 @@ export interface GroupsProps {
26
26
  * @default null
27
27
  */
28
28
  general?: boolean;
29
+ /**
30
+ * Show/Hide filters
31
+ * @default false
32
+ */
33
+ showFilters?: boolean;
34
+ /**
35
+ * Override filter func
36
+ * @default null
37
+ */
38
+ handleFilterGroups?: (groups: SCGroupType[]) => SCGroupType[];
39
+ /**
40
+ * Filters component
41
+ * @param props
42
+ */
43
+ filters?: JSX.Element;
29
44
  /**
30
45
  * Other props
31
46
  */
@@ -1,9 +1,9 @@
1
1
  import { __awaiter, __rest } from "tslib";
2
2
  import React, { useEffect, useMemo, useState } from 'react';
3
3
  import { styled } from '@mui/material/styles';
4
- import { Box, Grid, Typography } from '@mui/material';
4
+ import { Box, Grid, TextField, Typography } from '@mui/material';
5
5
  import { http } from '@selfcommunity/api-services';
6
- import { Logger } from '@selfcommunity/utils';
6
+ import { Logger, sortByAttr } from '@selfcommunity/utils';
7
7
  import { SCPreferences, useIsComponentMountedRef, useSCPreferences, useSCUser } from '@selfcommunity/react-core';
8
8
  import Skeleton from './Skeleton';
9
9
  import { FormattedMessage } from 'react-intl';
@@ -15,6 +15,7 @@ import { PREFIX } from './constants';
15
15
  import Group from '../Group';
16
16
  const classes = {
17
17
  root: `${PREFIX}-root`,
18
+ filters: `${PREFIX}-filter`,
18
19
  groups: `${PREFIX}-groups`,
19
20
  item: `${PREFIX}-item`,
20
21
  noResults: `${PREFIX}-no-results`,
@@ -62,10 +63,11 @@ export default function Groups(inProps) {
62
63
  props: inProps,
63
64
  name: PREFIX
64
65
  });
65
- const { endpoint, className, GroupComponentProps = { variant: 'outlined', ButtonBaseProps: { disableRipple: true, component: Box } }, prefetchedGroups = [], general } = props, rest = __rest(props, ["endpoint", "className", "GroupComponentProps", "prefetchedGroups", "general"]);
66
+ const { endpoint, className, GroupComponentProps = { variant: 'outlined', ButtonBaseProps: { disableRipple: true, component: Box } }, prefetchedGroups = [], showFilters = false, filters, handleFilterGroups, general } = props, rest = __rest(props, ["endpoint", "className", "GroupComponentProps", "prefetchedGroups", "showFilters", "filters", "handleFilterGroups", "general"]);
66
67
  // STATE
67
68
  const [groups, setGroups] = useState([]);
68
69
  const [loading, setLoading] = useState(true);
70
+ const [filterName, setFilterName] = useState('');
69
71
  // CONTEXT
70
72
  const scUserContext = useSCUser();
71
73
  const scPreferencesContext = useSCPreferences();
@@ -118,15 +120,41 @@ export default function Groups(inProps) {
118
120
  setGroups(_updated);
119
121
  }
120
122
  };
123
+ /**
124
+ * Get groups filtered
125
+ */
126
+ const getFilteredGroups = () => {
127
+ if (handleFilterGroups) {
128
+ return handleFilterGroups(groups);
129
+ }
130
+ if (filterName) {
131
+ return groups.filter((g) => g.name.toLowerCase().includes(filterName.toLowerCase()));
132
+ }
133
+ return groups;
134
+ };
135
+ /**
136
+ * Handle change filter name
137
+ * @param event
138
+ */
139
+ const handleOnChangeFilterName = (event) => {
140
+ setFilterName(event.target.value);
141
+ };
142
+ /**
143
+ * Renders groups list
144
+ */
145
+ const filteredGroups = sortByAttr(getFilteredGroups(), 'order');
146
+ const content = (React.createElement(React.Fragment, null,
147
+ showFilters && (React.createElement(Grid, { container: true, direction: "row", justifyContent: "center", alignItems: "center", className: classes.filters }, filters ? (filters) : (React.createElement(Grid, { item: true, xs: 12, md: 6 },
148
+ React.createElement(TextField, { fullWidth: true, value: filterName, label: React.createElement(FormattedMessage, { id: "ui.groups.filterByName", defaultMessage: "ui.groups.filterByName" }), variant: "outlined", onChange: handleOnChangeFilterName, disabled: loading }))))),
149
+ loading ? (React.createElement(Skeleton, null)) : (React.createElement(React.Fragment, null, !groups.length ? (React.createElement(Box, { className: classes.noResults },
150
+ React.createElement(Typography, { variant: "h4" },
151
+ React.createElement(FormattedMessage, { id: "ui.groups.noGroups.title", defaultMessage: "ui.groups.noGroups.title" })),
152
+ React.createElement(Typography, { variant: "body1" },
153
+ React.createElement(FormattedMessage, { id: "ui.groups.noGroups.subtitle", defaultMessage: "ui.groups.noGroups.subtitle" })))) : (React.createElement(Grid, { container: true, spacing: { xs: 3 }, className: classes.groups }, filteredGroups.map((group) => (React.createElement(Grid, { item: true, xs: 12, sm: 8, md: 6, key: group.id, className: classes.item },
154
+ React.createElement(Group, Object.assign({ group: group, groupId: group.id, groupSubscribeButtonProps: { onSubscribe: handleSubscribe } }, GroupComponentProps)))))))))));
121
155
  // RENDER
122
156
  if (!contentAvailability && !scUserContext.user) {
123
157
  return React.createElement(HiddenPlaceholder, null);
124
158
  }
125
- const content = (React.createElement(React.Fragment, null, loading ? (React.createElement(Skeleton, null)) : (React.createElement(React.Fragment, null, !groups.length ? (React.createElement(Box, { className: classes.noResults },
126
- React.createElement(Typography, { variant: "h4" },
127
- React.createElement(FormattedMessage, { id: "ui.groups.noGroups.title", defaultMessage: "ui.groups.noGroups.title" })),
128
- React.createElement(Typography, { variant: "body1" },
129
- React.createElement(FormattedMessage, { id: "ui.groups.noGroups.subtitle", defaultMessage: "ui.groups.noGroups.subtitle" })))) : (React.createElement(Grid, { container: true, spacing: { xs: 3 }, className: classes.groups }, groups.map((group) => (React.createElement(Grid, { item: true, xs: 12, sm: 8, md: 6, key: group.id, className: classes.item },
130
- React.createElement(Group, Object.assign({ group: group, groupId: group.id, groupSubscribeButtonProps: { onSubscribe: handleSubscribe } }, GroupComponentProps)))))))))));
131
159
  return (React.createElement(Root, Object.assign({ className: classNames(classes.root, className) }, rest), content));
132
160
  }