@plusscommunities/pluss-circles-web-groups 1.0.11-beta.0

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.
@@ -0,0 +1,388 @@
1
+ import React, { Component } from 'react';
2
+ import { connect } from 'react-redux';
3
+ import _ from 'lodash';
4
+ import moment from 'moment';
5
+ import { Link } from 'react-router-dom';
6
+ import { PlussCore } from '../feature.config';
7
+ import { circlesLoaded, circleRemoved } from '../actions';
8
+ import { circleActions } from '../apis';
9
+ import { Table } from 'react-bootstrap';
10
+ import FontAwesome from 'react-fontawesome';
11
+ import { values } from '../values.config';
12
+
13
+ const { Components, Session, Helper } = PlussCore;
14
+
15
+ class Circles extends Component {
16
+ constructor(props) {
17
+ super(props);
18
+ this.state = {
19
+ userSearch: '',
20
+ };
21
+ }
22
+
23
+ componentDidMount() {
24
+ this.getData();
25
+ }
26
+
27
+ getData = () => {
28
+ const { auth } = this.props;
29
+ this.setState({ loadingAll: true }, async () => {
30
+ try {
31
+ const res = await circleActions.getAll(auth.site);
32
+ console.log('getData', res.data);
33
+ this.props.circlesLoaded(res.data);
34
+ this.setState({ loadingAll: false });
35
+ } catch (error) {
36
+ console.error('getData', error);
37
+ this.setState({ loadingAll: false });
38
+ }
39
+ });
40
+ };
41
+
42
+ getCircles() {
43
+ let result = this.props.circles;
44
+ if (this.state.selectedTypeFilter) {
45
+ result = _.filter(result, (circle) => {
46
+ return this.state.selectedTypeFilter === 'circle' ? !circle.IsPrivate : circle.IsPrivate;
47
+ });
48
+ }
49
+ if (this.state.selectedUserFilter) {
50
+ result = _.filter(result, (circle) => {
51
+ return _.some(circle.Audience, (user) => {
52
+ return user.userId === this.state.selectedUserFilter.userId;
53
+ });
54
+ });
55
+ }
56
+ return result;
57
+ }
58
+
59
+ getUsers() {
60
+ let users = [];
61
+ this.props.circles.forEach((circle) => {
62
+ circle.Audience.forEach((user) => {
63
+ users.push(user);
64
+ });
65
+ });
66
+ users = _.sortBy(
67
+ _.uniqBy(users, (user) => {
68
+ return user.userId;
69
+ }),
70
+ 'displayName',
71
+ );
72
+ return _.filter(users, (u) => {
73
+ if (!_.isEmpty(this.state.userSearch)) {
74
+ return (u.displayName || '').toLowerCase().indexOf(this.state.userSearch.toLowerCase()) > -1;
75
+ }
76
+ return true;
77
+ });
78
+ }
79
+
80
+ validateCircleAdmin(circle, onlyCreator) {
81
+ if (Session.validateAccess(this.props.auth.site, values.permission, this.props.auth)) {
82
+ return true;
83
+ }
84
+ if (onlyCreator) {
85
+ return (circle.Creator && circle.Creator.userId === this.props.user.Id) || circle.CreatorId === this.props.user.Id;
86
+ }
87
+ return _.some(circle.Audience, (user) => {
88
+ return user.userId === this.props.user.Id && user.isAdmin;
89
+ });
90
+ }
91
+
92
+ canAddNew = () => {
93
+ const { auth } = this.props;
94
+ return Session.validateAccess(auth.site, values.permission, auth);
95
+ };
96
+
97
+ onAddNew = () => {
98
+ const { auth } = this.props;
99
+ if (Session.validateAccess(auth.site, values.permission, auth)) {
100
+ this.props.history.push(`/${values.featureKey}/add`);
101
+ }
102
+ };
103
+
104
+ openUserFilter = () => {
105
+ this.setState({
106
+ userFilterOpen: true,
107
+ });
108
+ };
109
+
110
+ closeUserFilter = () => {
111
+ this.setState({
112
+ userFilterOpen: false,
113
+ });
114
+ };
115
+
116
+ selectUserFilter = (user) => {
117
+ this.setState({
118
+ selectedUserFilter: user,
119
+ userFilterOpen: false,
120
+ });
121
+ };
122
+
123
+ removeUserFilter = (event) => {
124
+ event.stopPropagation();
125
+ this.setState({
126
+ selectedUserFilter: null,
127
+ });
128
+ };
129
+
130
+ openTypeFilter = () => {
131
+ this.setState({
132
+ typeFilterOpen: true,
133
+ });
134
+ };
135
+
136
+ closeTypeFilter = () => {
137
+ this.setState({
138
+ typeFilterOpen: false,
139
+ });
140
+ };
141
+
142
+ selectTypeFilter = (type) => {
143
+ this.setState({
144
+ selectedTypeFilter: type,
145
+ typeFilterOpen: false,
146
+ });
147
+ };
148
+
149
+ removeTypeFilter = (event) => {
150
+ event.stopPropagation();
151
+ this.setState({
152
+ selectedTypeFilter: null,
153
+ });
154
+ };
155
+
156
+ onHandleChange = (event) => {
157
+ var stateChange = {};
158
+ stateChange[event.target.getAttribute('id')] = event.target.value;
159
+ this.setState(stateChange);
160
+ };
161
+
162
+ removeCircle = (circle) => {
163
+ if (
164
+ window.confirm(
165
+ `Are you sure you want to delete that ${values.entityName}? You will no longer be able to access the messages in the ${values.entityName}.`,
166
+ )
167
+ ) {
168
+ this.props.circleRemoved(circle.Id);
169
+ circleActions
170
+ .delete(circle.Id)
171
+ .then((res) => {
172
+ this.getData();
173
+ })
174
+ .catch((res) => {
175
+ alert('Something went wrong with the request. Please try again.');
176
+ });
177
+ }
178
+ };
179
+
180
+ getTypeFilterText = (type) => {
181
+ if (type === 'private') {
182
+ return 'Private Message';
183
+ }
184
+ return _.capitalize(values.entityName);
185
+ };
186
+
187
+ getTitle = (circle) => {
188
+ if (circle.IsPrivate) {
189
+ return `PM: ${circle.Audience.map((user) => {
190
+ return user.displayName;
191
+ }).join(', ')}`;
192
+ }
193
+ return circle.Title;
194
+ };
195
+
196
+ renderRow(circle) {
197
+ return (
198
+ <tr key={circle.Id}>
199
+ <td className="table-TitleColumn">
200
+ <Link to={`/${values.featureKey}/${values.entityKey}/${circle.Id}`}>{this.getTitle(circle)}</Link>
201
+ </td>
202
+ <td>{moment(circle.Changed).local().format('D MMM YYYY')}</td>
203
+ <td>
204
+ {circle.Audience.map((user) => {
205
+ return (
206
+ <Components.ProfilePic
207
+ size={30}
208
+ image={user.profilePic}
209
+ hoverText={user.displayName}
210
+ containerClass="circleTableProfilePic"
211
+ />
212
+ );
213
+ })}
214
+ </td>
215
+ <td className="table-options">
216
+ <div style={{ display: 'flex', alignItems: 'center' }}>
217
+ {this.validateCircleAdmin(circle) && !circle.IsPrivate && (
218
+ <Link to={`/${values.featureKey}/edit/${circle.Id}`}>
219
+ <FontAwesome
220
+ style={{
221
+ fontSize: 20,
222
+ padding: 5,
223
+ marginLeft: 12,
224
+ cursor: 'pointer',
225
+ }}
226
+ name="pencil"
227
+ />
228
+ </Link>
229
+ )}
230
+ {this.validateCircleAdmin(circle, true) && !circle.IsPrivate && (
231
+ <a
232
+ onClick={() => {
233
+ this.removeCircle(circle);
234
+ }}
235
+ >
236
+ <FontAwesome
237
+ style={{
238
+ fontSize: 20,
239
+ padding: 5,
240
+ marginLeft: 12,
241
+ cursor: 'pointer',
242
+ }}
243
+ name="minus-circle"
244
+ />
245
+ </a>
246
+ )}
247
+ </div>
248
+ </td>
249
+ </tr>
250
+ );
251
+ }
252
+
253
+ renderFilters() {
254
+ let userFilter = <Components.Tag className="marginRight-10" onClick={this.openUserFilter} text="User" />;
255
+ let typeFilter = <Components.Tag className="marginRight-10" onClick={this.openTypeFilter} text="Type" />;
256
+
257
+ if (this.state.selectedUserFilter) {
258
+ userFilter = (
259
+ <Components.Tag className="marginRight-10" onClick={this.openUserFilter} rightIcon="close" rightClick={this.removeUserFilter}>
260
+ <Components.UserListing size={15} user={this.state.selectedUserFilter} textClass="tag_text" />
261
+ </Components.Tag>
262
+ );
263
+ }
264
+ if (this.state.selectedTypeFilter) {
265
+ typeFilter = (
266
+ <Components.Tag
267
+ className="marginRight-10"
268
+ onClick={this.openTypeFilter}
269
+ rightIcon="close"
270
+ rightClick={this.removeTypeFilter}
271
+ text={this.getTypeFilterText(this.state.selectedTypeFilter)}
272
+ />
273
+ );
274
+ }
275
+ return (
276
+ <div className="flex flex-center marginTop-20">
277
+ <Components.Text type="h5" className="marginRight-20">
278
+ Filter by
279
+ </Components.Text>
280
+ {userFilter}
281
+ {typeFilter}
282
+ </div>
283
+ );
284
+ }
285
+
286
+ renderUserFilterPopup() {
287
+ if (!this.state.userFilterOpen) {
288
+ return null;
289
+ }
290
+ return (
291
+ <Components.Popup title="Select User" maxWidth={600} minWidth={400} minHeight={400} hasPadding onClose={this.closeUserFilter}>
292
+ <Components.GenericInput
293
+ id="userSearch"
294
+ type="text"
295
+ label="Search"
296
+ placeholder="Enter name"
297
+ value={this.state.userSearch}
298
+ onChange={(e) => this.onHandleChange(e)}
299
+ alwaysShowLabel
300
+ />
301
+ {this.getUsers().map((user) => {
302
+ return (
303
+ <Components.UserListing
304
+ key={user.userId}
305
+ user={user}
306
+ onClick={() => {
307
+ this.selectUserFilter(user);
308
+ }}
309
+ />
310
+ );
311
+ })}
312
+ </Components.Popup>
313
+ );
314
+ }
315
+
316
+ renderTypeFilterPopup() {
317
+ if (!this.state.typeFilterOpen) {
318
+ return null;
319
+ }
320
+ return (
321
+ <Components.Popup title="Select Type" maxWidth={600} minWidth={400} hasPadding onClose={this.closeTypeFilter}>
322
+ <Components.Tag
323
+ onClick={() => {
324
+ this.selectTypeFilter('circle');
325
+ }}
326
+ text={_.capitalize(values.entityName)}
327
+ className="marginRight-10"
328
+ />
329
+ <Components.Tag
330
+ onClick={() => {
331
+ this.selectTypeFilter('private');
332
+ }}
333
+ text="Private Message"
334
+ />
335
+ </Components.Popup>
336
+ );
337
+ }
338
+
339
+ render() {
340
+ return (
341
+ <div>
342
+ {this.renderTypeFilterPopup()}
343
+ {this.renderUserFilterPopup()}
344
+ <Components.Header>
345
+ {this.canAddNew() && <Components.AddButton onClick={this.onAddNew} text={`NEW ${_.upperCase(values.entityName)}`} />}
346
+ </Components.Header>
347
+ <div className="pageContainer paddingVertical-20 paddingHorizontal-40">
348
+ <Components.Text type="h1" className="">
349
+ {values.textFeatureTitle}
350
+ </Components.Text>
351
+ {this.renderFilters()}
352
+
353
+ <Table className="plussTable" striped bordered condensed hover style={{ minWidth: '100%' }}>
354
+ <thead>
355
+ <tr>
356
+ <th>Title</th>
357
+ <th>Last updated</th>
358
+ <th>Members</th>
359
+ <th style={{ width: 50 }} />
360
+ </tr>
361
+ </thead>
362
+ <tbody>
363
+ {this.getCircles().map((circle) => {
364
+ return this.renderRow(circle);
365
+ })}
366
+ </tbody>
367
+ </Table>
368
+ <div className="hub_tidioPadding"></div>
369
+ </div>
370
+ </div>
371
+ );
372
+ }
373
+ }
374
+
375
+ const styles = {};
376
+
377
+ const mapStateToProps = (state) => {
378
+ const { circles } = state[values.reducerKey];
379
+ const { auth } = state;
380
+
381
+ return {
382
+ circles,
383
+ auth,
384
+ user: Helper.getUserFromState(state),
385
+ };
386
+ };
387
+
388
+ export default connect(mapStateToProps, { circlesLoaded, circleRemoved })(Circles);
@@ -0,0 +1,35 @@
1
+ const values = {
2
+ featureKey: 'circles',
3
+ entityKey: 'circle',
4
+ entityName: 'circle',
5
+ serviceKey: 'circles',
6
+ permission: 'circles',
7
+ menuIcon: 'circle-o',
8
+ isFontAwesome: true,
9
+
10
+ reducerKey: 'circles',
11
+
12
+ actionCircleKey: 'CIRCLE',
13
+
14
+ textFeatureTitle: 'Circles',
15
+ textAddMenuTitle: 'Circle',
16
+ textEmptyGroups: "You aren't in any Circles",
17
+ textEmptyPeople: 'Contacts will show here',
18
+
19
+ componentCircles: 'Circles',
20
+ componentAddCircle: 'AddCircle',
21
+ componentCircle: 'Circle',
22
+
23
+ inviteKey: 'circleInvite',
24
+ messageKey: 'circleMessage',
25
+ chatRoute: 'circleChat',
26
+ updateKeyUserCircles: 'userCircles',
27
+ allowPublicKey: 'circleAllowPublicCircles',
28
+ allowPublicKeyDefault: false,
29
+
30
+ settings: {
31
+ allowAnyCreate: false,
32
+ },
33
+ };
34
+
35
+ export { values };
@@ -0,0 +1,35 @@
1
+ const values = {
2
+ featureKey: 'groups',
3
+ entityKey: 'group',
4
+ entityName: 'group',
5
+ serviceKey: 'groups',
6
+ permission: 'groups',
7
+ menuIcon: 'comments',
8
+ isFontAwesome: true,
9
+
10
+ reducerKey: 'groups',
11
+
12
+ actionCircleKey: 'GROUP',
13
+
14
+ textFeatureTitle: 'Groups',
15
+ textAddMenuTitle: 'Group',
16
+ textEmptyGroups: "You aren't in any Groups",
17
+ textEmptyPeople: 'Contacts will show here',
18
+
19
+ componentCircles: 'Groups',
20
+ componentAddCircle: 'AddGroup',
21
+ componentCircle: 'Group',
22
+
23
+ inviteKey: 'groupInvite',
24
+ messageKey: 'groupMessage',
25
+ chatRoute: 'groupChat',
26
+ updateKeyUserCircles: 'userGroups',
27
+ allowPublicKey: 'groupAllowPublicGroups',
28
+ allowPublicKeyDefault: true,
29
+
30
+ settings: {
31
+ allowAnyCreate: true,
32
+ },
33
+ };
34
+
35
+ export { values };
@@ -0,0 +1,35 @@
1
+ const values = {
2
+ featureKey: 'groups',
3
+ entityKey: 'group',
4
+ entityName: 'group',
5
+ serviceKey: 'groups',
6
+ permission: 'groups',
7
+ menuIcon: 'comments',
8
+ isFontAwesome: true,
9
+
10
+ reducerKey: 'groups',
11
+
12
+ actionCircleKey: 'GROUP',
13
+
14
+ textFeatureTitle: 'Groups',
15
+ textAddMenuTitle: 'Group',
16
+ textEmptyGroups: "You aren't in any Groups",
17
+ textEmptyPeople: 'Contacts will show here',
18
+
19
+ componentCircles: 'Groups',
20
+ componentAddCircle: 'AddGroup',
21
+ componentCircle: 'Group',
22
+
23
+ inviteKey: 'groupInvite',
24
+ messageKey: 'groupMessage',
25
+ chatRoute: 'groupChat',
26
+ updateKeyUserCircles: 'userGroups',
27
+ allowPublicKey: 'groupAllowPublicGroups',
28
+ allowPublicKeyDefault: true,
29
+
30
+ settings: {
31
+ allowAnyCreate: true,
32
+ },
33
+ };
34
+
35
+ export { values };