@plusscommunities/pluss-circles-app 8.0.4 → 8.0.6-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.
Files changed (133) hide show
  1. package/dist/module/actions/ChatActions.js +3 -3
  2. package/dist/module/actions/ChatActions.js.map +1 -1
  3. package/dist/module/actions/GroupActions.js +18 -18
  4. package/dist/module/actions/GroupActions.js.map +1 -1
  5. package/dist/module/actions/index.js +3 -3
  6. package/dist/module/actions/index.js.map +1 -1
  7. package/dist/module/actions/types.js +2 -2
  8. package/dist/module/actions/types.js.map +1 -1
  9. package/dist/module/assets/fonts.js +1 -1
  10. package/dist/module/assets/fonts.js.map +1 -1
  11. package/dist/module/components/chat/Chat.js +83 -101
  12. package/dist/module/components/chat/Chat.js.map +1 -1
  13. package/dist/module/components/chat/ChatList.js +49 -49
  14. package/dist/module/components/chat/ChatList.js.map +1 -1
  15. package/dist/module/components/chat/ContactsList.js +21 -21
  16. package/dist/module/components/chat/ContactsList.js.map +1 -1
  17. package/dist/module/components/chat/KioskPeoplePage.js +38 -37
  18. package/dist/module/components/chat/KioskPeoplePage.js.map +1 -1
  19. package/dist/module/components/chat/PeopleContainer.js +5 -5
  20. package/dist/module/components/chat/PeopleContainer.js.map +1 -1
  21. package/dist/module/components/chat/PeoplePage.js +41 -41
  22. package/dist/module/components/chat/PeoplePage.js.map +1 -1
  23. package/dist/module/components/common/SwipeableUserListing.js +22 -22
  24. package/dist/module/components/common/SwipeableUserListing.js.map +1 -1
  25. package/dist/module/components/common/index.js +2 -2
  26. package/dist/module/components/common/index.js.map +1 -1
  27. package/dist/module/components/events/EventInvitePopup.js +40 -40
  28. package/dist/module/components/events/EventInvitePopup.js.map +1 -1
  29. package/dist/module/components/groups/EditGroup.js +62 -62
  30. package/dist/module/components/groups/EditGroup.js.map +1 -1
  31. package/dist/module/components/groups/GroupDetails.js +32 -32
  32. package/dist/module/components/groups/GroupDetails.js.map +1 -1
  33. package/dist/module/components/groups/GroupsList.js +10 -10
  34. package/dist/module/components/groups/GroupsList.js.map +1 -1
  35. package/dist/module/components/groups/GroupsWidget.js +18 -18
  36. package/dist/module/components/groups/GroupsWidget.js.map +1 -1
  37. package/dist/module/components/groups/NewGroup.js +101 -101
  38. package/dist/module/components/groups/NewGroup.js.map +1 -1
  39. package/dist/module/components/groups/PublicGroup.js +17 -17
  40. package/dist/module/components/groups/PublicGroup.js.map +1 -1
  41. package/dist/module/components/groups/PublicGroupAction.js +39 -39
  42. package/dist/module/components/groups/PublicGroupAction.js.map +1 -1
  43. package/dist/module/components/notifications/GroupInvite.js +25 -25
  44. package/dist/module/components/notifications/GroupInvite.js.map +1 -1
  45. package/dist/module/components/notifications/GroupInviteAction.js +44 -44
  46. package/dist/module/components/notifications/GroupInviteAction.js.map +1 -1
  47. package/dist/module/components/notifications/GroupMessage.js +17 -17
  48. package/dist/module/components/notifications/GroupMessage.js.map +1 -1
  49. package/dist/module/components/takeover/TakeoverBackground.js +5 -5
  50. package/dist/module/components/takeover/TakeoverBackground.js.map +1 -1
  51. package/dist/module/config/index.js +2 -2
  52. package/dist/module/config/index.js.map +1 -1
  53. package/dist/module/core.config.js +1 -1
  54. package/dist/module/core.config.js.map +1 -1
  55. package/dist/module/feature.config.js +27 -27
  56. package/dist/module/feature.config.js.map +1 -1
  57. package/dist/module/index.js +14 -14
  58. package/dist/module/index.js.map +1 -1
  59. package/dist/module/js/Colors.js +1 -1
  60. package/dist/module/js/Colors.js.map +1 -1
  61. package/dist/module/js/NavigationService.js +1 -1
  62. package/dist/module/js/NavigationService.js.map +1 -1
  63. package/dist/module/js/Styles.js +1 -1
  64. package/dist/module/js/Styles.js.map +1 -1
  65. package/dist/module/js/circles/MapStateToDirectMessages.js +2 -2
  66. package/dist/module/js/circles/MapStateToDirectMessages.js.map +1 -1
  67. package/dist/module/js/index.js +3 -3
  68. package/dist/module/js/index.js.map +1 -1
  69. package/dist/module/reducers/ChatsReducer.js +4 -4
  70. package/dist/module/reducers/ChatsReducer.js.map +1 -1
  71. package/dist/module/reducers/GroupsReducer.js +5 -5
  72. package/dist/module/reducers/GroupsReducer.js.map +1 -1
  73. package/dist/module/reducers/reducerKeys.js +1 -1
  74. package/dist/module/reducers/reducerKeys.js.map +1 -1
  75. package/dist/module/values.config.default.js +25 -25
  76. package/dist/module/values.config.default.js.map +1 -1
  77. package/dist/module/values.config.groups.js +25 -25
  78. package/dist/module/values.config.groups.js.map +1 -1
  79. package/dist/module/values.config.js +25 -25
  80. package/dist/module/values.config.js.map +1 -1
  81. package/dist/module/webapi/circleActions.js +31 -31
  82. package/dist/module/webapi/circleActions.js.map +1 -1
  83. package/dist/module/webapi/helper.js +1 -1
  84. package/dist/module/webapi/helper.js.map +1 -1
  85. package/dist/module/webapi/index.js +3 -3
  86. package/dist/module/webapi/index.js.map +1 -1
  87. package/dist/module/webapi/messageActions.js +10 -10
  88. package/dist/module/webapi/messageActions.js.map +1 -1
  89. package/package.json +54 -54
  90. package/src/actions/ChatActions.js +55 -55
  91. package/src/actions/GroupActions.js +245 -237
  92. package/src/actions/index.js +3 -3
  93. package/src/actions/types.js +2 -2
  94. package/src/assets/fonts.js +1 -1
  95. package/src/components/chat/Chat.js +730 -669
  96. package/src/components/chat/ChatList.js +603 -512
  97. package/src/components/chat/ContactsList.js +186 -169
  98. package/src/components/chat/KioskPeoplePage.js +315 -291
  99. package/src/components/chat/PeopleContainer.js +14 -14
  100. package/src/components/chat/PeoplePage.js +450 -383
  101. package/src/components/common/SwipeableUserListing.js +118 -106
  102. package/src/components/common/index.js +2 -2
  103. package/src/components/events/EventInvitePopup.js +587 -505
  104. package/src/components/groups/EditGroup.js +607 -538
  105. package/src/components/groups/GroupDetails.js +385 -305
  106. package/src/components/groups/GroupsList.js +91 -79
  107. package/src/components/groups/GroupsWidget.js +122 -116
  108. package/src/components/groups/NewGroup.js +758 -639
  109. package/src/components/groups/PublicGroup.js +129 -101
  110. package/src/components/groups/PublicGroupAction.js +312 -244
  111. package/src/components/notifications/GroupInvite.js +167 -139
  112. package/src/components/notifications/GroupInviteAction.js +371 -273
  113. package/src/components/notifications/GroupMessage.js +110 -102
  114. package/src/components/takeover/TakeoverBackground.js +24 -18
  115. package/src/config/index.js +4 -4
  116. package/src/core.config.js +27 -3
  117. package/src/feature.config.js +257 -245
  118. package/src/index.js +24 -21
  119. package/src/js/Colors.js +5 -3
  120. package/src/js/NavigationService.js +5 -4
  121. package/src/js/Styles.js +1 -1
  122. package/src/js/circles/MapStateToDirectMessages.js +6 -6
  123. package/src/js/index.js +3 -3
  124. package/src/reducers/ChatsReducer.js +66 -53
  125. package/src/reducers/GroupsReducer.js +203 -190
  126. package/src/reducers/reducerKeys.js +1 -1
  127. package/src/values.config.default.js +29 -29
  128. package/src/values.config.groups.js +29 -29
  129. package/src/values.config.js +29 -29
  130. package/src/webapi/circleActions.js +109 -109
  131. package/src/webapi/helper.js +1 -1
  132. package/src/webapi/index.js +3 -3
  133. package/src/webapi/messageActions.js +47 -47
@@ -1,548 +1,617 @@
1
- import React, { Component } from 'react';
2
- import _ from 'lodash';
3
- import { connect } from 'react-redux';
4
- import { Platform, Dimensions, ImageBackground, Text, ScrollView, TouchableOpacity, View, KeyboardAvoidingView } from 'react-native';
5
- import { Icon } from '@rneui/themed';
1
+ import React, { Component } from "react";
2
+ import _ from "lodash";
3
+ import { connect } from "react-redux";
6
4
  import {
7
- ProfilePic,
8
- FormCard,
9
- FormCardSection,
10
- Header,
11
- Spinner,
12
- ImageUploader,
13
- InlineButton,
14
- StickyFooter,
15
- TextStyle,
16
- UserListing,
17
- } from '../common';
18
- import { LINEGREY, BG_GREY, getMainBrandingColourFromState } from '../../js/Colors';
19
- import NavigationService from '../../js/NavigationService';
20
- import { TEXT_LIGHT } from '../../js/index';
21
- import { createGroup, loadGroups, editGroup } from '../../actions';
22
- import EventInvitePopup from '../events/EventInvitePopup';
23
- import { values } from '../../values.config';
24
- import { Colours } from '@plusscommunities/pluss-core-app';
25
-
26
- const PHOTO_WIDTH = Dimensions.get('window').width - 48;
5
+ Platform,
6
+ Dimensions,
7
+ ImageBackground,
8
+ Text,
9
+ ScrollView,
10
+ TouchableOpacity,
11
+ View,
12
+ KeyboardAvoidingView,
13
+ } from "react-native";
14
+ import { Icon } from "@rneui/themed";
15
+ import {
16
+ ProfilePic,
17
+ FormCard,
18
+ FormCardSection,
19
+ Header,
20
+ Spinner,
21
+ ImageUploader,
22
+ InlineButton,
23
+ StickyFooter,
24
+ TextStyle,
25
+ UserListing,
26
+ } from "../common";
27
+ import {
28
+ LINEGREY,
29
+ BG_GREY,
30
+ getMainBrandingColourFromState,
31
+ } from "../../js/Colors";
32
+ import NavigationService from "../../js/NavigationService";
33
+ import { TEXT_LIGHT } from "../../js/index";
34
+ import { createGroup, loadGroups, editGroup } from "../../actions";
35
+ import EventInvitePopup from "../events/EventInvitePopup";
36
+ import { values } from "../../values.config";
37
+ import { Colours } from "@plusscommunities/pluss-core-app";
38
+
39
+ const PHOTO_WIDTH = Dimensions.get("window").width - 48;
27
40
 
28
41
  class EditGroup extends Component {
29
- state = {
30
- group: null,
31
- message: '',
32
- title: '',
33
- error: null,
34
-
35
- submittingGroup: false,
36
- groupImage: null,
37
-
38
- showUserSelect: false,
39
- allUsers: [],
40
- audience: [],
41
- invites: [],
42
- contacts: [],
43
- selected: [],
44
- pending: [],
45
- usersToAdd: [],
46
- usersToRemove: [],
47
- searchText: '',
48
- showErrors: false,
49
-
50
- inviteOpen: false,
51
- };
52
-
53
- componentDidMount() {
54
- this.parseGroup(this.props.groups);
55
- }
56
-
57
- onPressBack() {
58
- NavigationService.goBack();
59
- }
60
-
61
- onSubmitSend() {
62
- this.setState({ error: null });
63
- if (!this.props.connected) {
64
- this.setState({ error: 'No internet connection detected.' });
65
- return;
66
- }
67
- if (this.state.submittingGroup || this.state.uploadingImage) {
68
- return;
69
- }
70
-
71
- this.setState({ submittingGroup: true });
72
-
73
- const group = {
74
- ...this.state.group,
75
- Title: this.state.title,
76
- CreatorId: this.state.group.CreatorId,
77
- };
78
-
79
- if (this.state.groupImage != null && !_.isEmpty(this.state.groupImage)) {
80
- group.Image = this.state.groupImage;
81
- }
82
-
83
- this.props.editGroup(group, this.state.usersToAdd, this.state.usersToRemove);
84
- this.onPressBack();
85
- }
86
-
87
- onChangeTitle(value) {
88
- this.setState({ title: value });
89
- }
90
-
91
- onUploadStarted = () => {
92
- this.setState({
93
- uploadingImage: true,
94
- });
95
- };
96
-
97
- onUploadSuccess = uri => {
98
- this.setState({
99
- uploadingImage: false,
100
- groupImage: uri.replace('/general/', '/general1400/'),
101
- });
102
- };
103
-
104
- onUploadFailed = () => {
105
- this.setState({
106
- uploadingImage: false,
107
- groupImage: null,
108
- });
109
- };
110
-
111
- getInvited() {
112
- return [
113
- ..._.filter(this.state.group.Invites || [], u => {
114
- return this.state.usersToRemove.indexOf(u.userId) === -1;
115
- }),
116
- ...this.state.usersToAdd,
117
- ];
118
- }
119
-
120
- getPendingChanges() {
121
- return [...this.state.usersToRemove, ...this.state.usersToAdd];
122
- }
123
-
124
- getAttendees() {
125
- return [
126
- ..._.filter(this.state.group.Audience || [], u => {
127
- return this.state.usersToRemove.indexOf(u.userId) === -1;
128
- }),
129
- ...this.state.usersToAdd,
130
- ];
131
- }
132
-
133
- parseGroup(groupz) {
134
- const newStates = {};
135
- let newGrop = {};
136
- _.forEach(groupz, group => {
137
- if (!_.isUndefined(this.props.chat.key) && group.Id === this.props.chat.key) {
138
- newGrop = { ...group };
139
- } else if (group.Id === this.props.chat.Id) {
140
- newGrop = { ...group };
141
- }
142
- });
143
-
144
- newStates.group = { ...newGrop };
145
- newStates.title = newGrop.Title;
146
- if (!_.isEmpty(newGrop.Image)) {
147
- newStates.groupImage = newGrop.Image;
148
- }
149
- newStates.audience = [...newGrop.Audience];
150
- if (!_.isUndefined(newGrop.Invites)) {
151
- newStates.invites = [...newGrop.Invites];
152
- newStates.allUsers = [...newGrop.Invites, ...newGrop.Audience];
153
- } else {
154
- newStates.allUsers = [...newGrop.Audience];
155
- }
156
-
157
- this.setState(newStates);
158
- }
159
-
160
- addToAudience(user) {
161
- const indexToRemove = this.state.usersToRemove.indexOf(user.userId);
162
- if (indexToRemove > -1) {
163
- const newUsersToRemove = [...this.state.usersToRemove];
164
- newUsersToRemove.splice(indexToRemove, 1);
165
- this.setState({
166
- usersToRemove: newUsersToRemove,
167
- });
168
- } else {
169
- const newUsersToAdd = [...this.state.usersToAdd];
170
- newUsersToAdd.push(user);
171
- this.setState({ usersToAdd: newUsersToAdd });
172
- }
173
- }
174
-
175
- removeFromAudience(user) {
176
- const indexToAdd = _.findIndex(this.state.usersToAdd, u => {
177
- return u.userId === user.userId;
178
- });
179
- if (indexToAdd > -1) {
180
- const newUsersToAdd = [...this.state.usersToAdd];
181
- newUsersToAdd.splice(indexToAdd, 1);
182
- this.setState({
183
- usersToAdd: newUsersToAdd,
184
- });
185
- } else {
186
- const newUsersToRemove = [...this.state.usersToRemove];
187
- newUsersToRemove.push(user.userId);
188
- this.setState({ usersToRemove: newUsersToRemove });
189
- }
190
- }
191
-
192
- toggleAdmin = user => {
193
- const index = this.state.group.Audience.indexOf(user);
194
- if (index > -1) {
195
- const newUsers = [...this.state.group.Audience];
196
- newUsers[index].isAdmin = !newUsers[index].isAdmin;
197
- this.setState({ group: { ...this.state.group, Audience: newUsers } });
198
- }
199
- };
200
-
201
- closeInvitePopup() {
202
- this.setState({
203
- inviteOpen: false,
204
- inviteAttendeeList: null,
205
- inviteRepToShow: null,
206
- inviteRepIdToShow: null,
207
- });
208
- }
209
-
210
- openInvite() {
211
- this.setState({ inviteOpen: true });
212
- }
213
-
214
- nextPage() {
215
- this.setState({ page: 2, title: this.state.title });
216
- }
217
-
218
- clickCreate() {
219
- if (this.state.title.length < 1) {
220
- this.setState({ showErrors: true });
221
- return;
222
- }
223
- if (this.state.uploadingImage) {
224
- return;
225
- }
226
- this.onSubmitSend();
227
- }
228
-
229
- showUploadMenu() {
230
- if (this.state.uploadingImage || this.state.submittingGroup) {
231
- return;
232
- }
233
- this.imageUploader.showUploadMenu();
234
- }
235
-
236
- renderInvitePopup() {
237
- return (
238
- <EventInvitePopup
239
- isNewEvent
240
- onNewEventInvite={this.addToAudience.bind(this)}
241
- onNewEventRemove={this.removeFromAudience.bind(this)}
242
- isSearchable
243
- source="residents"
244
- attendees={this.getAttendees()}
245
- attendingStatusText="Member"
246
- invited={this.getInvited()}
247
- invitedText="Added"
248
- visible={this.state.inviteOpen}
249
- onClose={this.closeInvitePopup.bind(this)}
250
- showStatusText
251
- editButtons
252
- />
253
- );
254
- }
255
-
256
- renderUploadMenu() {
257
- return (
258
- <ImageUploader
259
- ref={ref => (this.imageUploader = ref)}
260
- onUploadStarted={this.onUploadStarted}
261
- onUploadSuccess={this.onUploadSuccess}
262
- onUploadFailed={this.onUploadFailed}
263
- onLibrarySelected={this.onUploadSuccess}
264
- size={{ width: 700 }}
265
- quality={0.8}
266
- fileName={'groupImage'}
267
- popupTitle={`Add ${values.entityName} Cover Image`}
268
- />
269
- );
270
- }
271
-
272
- renderInnerImage() {
273
- if (!this.state.uploadingImage && this.state.groupImage === null) {
274
- return (
275
- <View>
276
- <Icon
277
- name="camera"
278
- //style={styles.uploadButtonInner}
279
- type="font-awesome"
280
- iconStyle={{ color: TEXT_LIGHT, fontSize: 20, marginBottom: 13 }}
281
- />
282
- <Text style={{ fontSize: 13, fontFamily: 'sf-regular', color: TEXT_LIGHT }}>Upload group image</Text>
283
- </View>
284
- );
285
- }
286
- return this.renderImage();
287
- }
288
-
289
- renderImage() {
290
- if (this.state.uploadingImage) {
291
- return <Spinner />;
292
- }
293
- if (this.state.groupImage) {
294
- return (
295
- <ImageBackground
296
- style={{ flex: 1, height: '100%', width: '100%', borderRadius: 4, justifyContent: 'center', alignContent: 'center' }}
297
- imageStyle={{ borderRadius: 4 }}
298
- source={{ uri: this.state.groupImage }}
299
- >
300
- <View>
301
- <Icon
302
- name="camera"
303
- //style={styles.uploadButtonInner}
304
- type="font-awesome"
305
- iconStyle={{ color: '#fff', fontSize: 20, marginBottom: 13 }}
306
- />
307
- <Text style={{ fontSize: 13, fontFamily: 'sf-regular', color: '#fff', textAlign: 'center' }}>
308
- Upload {values.entityName} image
309
- </Text>
310
- </View>
311
- </ImageBackground>
312
- );
313
- }
314
- }
315
-
316
- renderPage() {
317
- return (
318
- <View>
319
- <FormCard style={{ marginTop: 16 }}>
320
- <FormCardSection
321
- label={`${_.capitalize(values.entityName)} name`}
322
- placeholder={`${_.capitalize(values.entityName)} name`}
323
- textValue={this.state.title}
324
- onChangeText={value => {
325
- this.onChangeTitle(value);
326
- }}
327
- editable={this.state.submittingGroup === false}
328
- isValid={() => {
329
- return this.state.title.length > 1;
330
- }}
331
- required
332
- />
333
- </FormCard>
334
- <View style={{ padding: 24 }}>
335
- <TouchableOpacity activeOpacity={0.8} onPress={this.showUploadMenu.bind(this)}>
336
- <View style={styles.imageContainer}>{this.renderInnerImage()}</View>
337
- </TouchableOpacity>
338
- </View>
339
- <View style={{ paddingVertical: 24, paddingHorizontal: 8 }}>
340
- <View style={{ paddingHorizontal: 16 }}>
341
- <TextStyle type="detailLabel">Members</TextStyle>
342
- </View>
343
- {this.getAttendees().map(user => {
344
- return (
345
- <UserListing
346
- key={user.userId}
347
- user={user}
348
- rightContent={(() => {
349
- if (this.state.usersToAdd.indexOf(user) > -1) {
350
- return null;
351
- }
352
- return (
353
- <InlineButton
354
- onPress={() => {
355
- this.toggleAdmin(user);
356
- }}
357
- style={{ borderColor: this.props.colourBrandingMain, borderWidth: 1 }}
358
- textStyle={{ color: this.props.colourBrandingMain }}
359
- >
360
- {user.isAdmin ? 'Remove admin' : 'Make admin'}
361
- </InlineButton>
362
- );
363
- })()}
364
- statusText={(() => {
365
- if (this.state.usersToAdd.indexOf(user) > -1) {
366
- return 'Added';
367
- }
368
- if (user.isAdmin) {
369
- return 'Admin';
370
- }
371
- return 'Member';
372
- })()}
373
- />
374
- );
375
- })}
376
- </View>
377
- </View>
378
- );
379
- }
380
-
381
- renderPreviewAtts() {
382
- return (
383
- <View style={styles.attendeePreviews}>
384
- {this.state.allUsers.map((user, index) => {
385
- if (index < 3) {
386
- return (
387
- <ProfilePic ProfilePic={user.profilePic} Diameter={36} style={[styles.profilePic, { left: index * -20 }]} key={user.userId} />
388
- );
389
- }
390
- return null;
391
- })}
392
- </View>
393
- );
394
- }
395
-
396
- renderInviteButton() {
397
- const changes = this.getPendingChanges();
398
- return (
399
- <View style={{ flexDirection: 'row' }}>
400
- {this.renderPreviewAtts()}
401
- <View style={styles.fill}>
402
- <InlineButton
403
- onPress={this.openInvite.bind(this)}
404
- style={[styles.inviteButton, { borderColor: this.props.colourBrandingMain }]}
405
- color="#fff"
406
- textStyle={{ color: this.props.colourBrandingMain }}
407
- >
408
- Manage members
409
- </InlineButton>
410
- <View style={styles.attendingContainer}>
411
- <Text style={styles.tix} numberOfLines={1}>
412
- <Text>{this.state.group.Audience.length}</Text>
413
- {' members'}
414
- </Text>
415
- <Text style={[styles.tix, changes.length > 0 && { color: Colours.COLOUR_RED }]} numberOfLines={1}>
416
- <Text>{changes.length}</Text>
417
- {' changes made'}
418
- </Text>
419
- </View>
420
- </View>
421
- </View>
422
- );
423
- }
424
-
425
- render() {
426
- if (!this.state.group) {
427
- return null;
428
- }
429
- return (
430
- <KeyboardAvoidingView behavior={'padding'} style={{ position: 'relative', flex: 1, backgroundColor: '#fff' }}>
431
- <View style={styles.greyContainer}>
432
- {this.renderUploadMenu()}
433
- <Header
434
- leftIcon="close"
435
- leftIconType="pluss"
436
- leftText="Cancel"
437
- leftIconStyle={{ color: this.props.colourBrandingMain }}
438
- onPressLeft={this.onPressBack.bind(this)}
439
- rightText="Done"
440
- onPressRight={this.clickCreate.bind(this)}
441
- optionalRightStyle={this.state.submittingGroup && { opacity: 0.2 }}
442
- text={this.state.title.length > 1 ? this.state.title : ' '}
443
- />
444
- <ScrollView style={{ flex: 1 }} keyboardShouldPersistTaps={'handled'}>
445
- {this.state.submittingGroup && (
446
- <View style={{ marginTop: 16 }}>
447
- <Spinner size={'small'} />
448
- </View>
449
- )}
450
- {this.renderPage()}
451
- </ScrollView>
452
-
453
- <StickyFooter style={styles.footer}>{this.renderInviteButton()}</StickyFooter>
454
- </View>
455
-
456
- {this.renderInvitePopup()}
457
- </KeyboardAvoidingView>
458
- );
459
- }
42
+ state = {
43
+ group: null,
44
+ message: "",
45
+ title: "",
46
+ error: null,
47
+
48
+ submittingGroup: false,
49
+ groupImage: null,
50
+
51
+ showUserSelect: false,
52
+ allUsers: [],
53
+ audience: [],
54
+ invites: [],
55
+ contacts: [],
56
+ selected: [],
57
+ pending: [],
58
+ usersToAdd: [],
59
+ usersToRemove: [],
60
+ searchText: "",
61
+ showErrors: false,
62
+
63
+ inviteOpen: false,
64
+ };
65
+
66
+ componentDidMount() {
67
+ this.parseGroup(this.props.groups);
68
+ }
69
+
70
+ onPressBack() {
71
+ NavigationService.goBack();
72
+ }
73
+
74
+ onSubmitSend() {
75
+ this.setState({ error: null });
76
+ if (!this.props.connected) {
77
+ this.setState({ error: "No internet connection detected." });
78
+ return;
79
+ }
80
+ if (this.state.submittingGroup || this.state.uploadingImage) {
81
+ return;
82
+ }
83
+
84
+ this.setState({ submittingGroup: true });
85
+
86
+ const group = {
87
+ ...this.state.group,
88
+ Title: this.state.title,
89
+ CreatorId: this.state.group.CreatorId,
90
+ };
91
+
92
+ if (this.state.groupImage != null && !_.isEmpty(this.state.groupImage)) {
93
+ group.Image = this.state.groupImage;
94
+ }
95
+
96
+ this.props.editGroup(
97
+ group,
98
+ this.state.usersToAdd,
99
+ this.state.usersToRemove,
100
+ );
101
+ this.onPressBack();
102
+ }
103
+
104
+ onChangeTitle(value) {
105
+ this.setState({ title: value });
106
+ }
107
+
108
+ onUploadStarted = () => {
109
+ this.setState({
110
+ uploadingImage: true,
111
+ });
112
+ };
113
+
114
+ onUploadSuccess = (uri) => {
115
+ this.setState({
116
+ uploadingImage: false,
117
+ groupImage: uri.replace("/general/", "/general1400/"),
118
+ });
119
+ };
120
+
121
+ onUploadFailed = () => {
122
+ this.setState({
123
+ uploadingImage: false,
124
+ groupImage: null,
125
+ });
126
+ };
127
+
128
+ getInvited() {
129
+ return [
130
+ ..._.filter(this.state.group.Invites || [], (u) => {
131
+ return this.state.usersToRemove.indexOf(u.userId) === -1;
132
+ }),
133
+ ...this.state.usersToAdd,
134
+ ];
135
+ }
136
+
137
+ getPendingChanges() {
138
+ return [...this.state.usersToRemove, ...this.state.usersToAdd];
139
+ }
140
+
141
+ getAttendees() {
142
+ return [
143
+ ..._.filter(this.state.group.Audience || [], (u) => {
144
+ return this.state.usersToRemove.indexOf(u.userId) === -1;
145
+ }),
146
+ ...this.state.usersToAdd,
147
+ ];
148
+ }
149
+
150
+ parseGroup(groupz) {
151
+ const newStates = {};
152
+ let newGrop = {};
153
+ _.forEach(groupz, (group) => {
154
+ if (
155
+ !_.isUndefined(this.props.chat.key) &&
156
+ group.Id === this.props.chat.key
157
+ ) {
158
+ newGrop = { ...group };
159
+ } else if (group.Id === this.props.chat.Id) {
160
+ newGrop = { ...group };
161
+ }
162
+ });
163
+
164
+ newStates.group = { ...newGrop };
165
+ newStates.title = newGrop.Title;
166
+ if (!_.isEmpty(newGrop.Image)) {
167
+ newStates.groupImage = newGrop.Image;
168
+ }
169
+ newStates.audience = [...newGrop.Audience];
170
+ if (!_.isUndefined(newGrop.Invites)) {
171
+ newStates.invites = [...newGrop.Invites];
172
+ newStates.allUsers = [...newGrop.Invites, ...newGrop.Audience];
173
+ } else {
174
+ newStates.allUsers = [...newGrop.Audience];
175
+ }
176
+
177
+ this.setState(newStates);
178
+ }
179
+
180
+ addToAudience(user) {
181
+ const indexToRemove = this.state.usersToRemove.indexOf(user.userId);
182
+ if (indexToRemove > -1) {
183
+ const newUsersToRemove = [...this.state.usersToRemove];
184
+ newUsersToRemove.splice(indexToRemove, 1);
185
+ this.setState({
186
+ usersToRemove: newUsersToRemove,
187
+ });
188
+ } else {
189
+ const newUsersToAdd = [...this.state.usersToAdd];
190
+ newUsersToAdd.push(user);
191
+ this.setState({ usersToAdd: newUsersToAdd });
192
+ }
193
+ }
194
+
195
+ removeFromAudience(user) {
196
+ const indexToAdd = _.findIndex(this.state.usersToAdd, (u) => {
197
+ return u.userId === user.userId;
198
+ });
199
+ if (indexToAdd > -1) {
200
+ const newUsersToAdd = [...this.state.usersToAdd];
201
+ newUsersToAdd.splice(indexToAdd, 1);
202
+ this.setState({
203
+ usersToAdd: newUsersToAdd,
204
+ });
205
+ } else {
206
+ const newUsersToRemove = [...this.state.usersToRemove];
207
+ newUsersToRemove.push(user.userId);
208
+ this.setState({ usersToRemove: newUsersToRemove });
209
+ }
210
+ }
211
+
212
+ toggleAdmin = (user) => {
213
+ const index = this.state.group.Audience.indexOf(user);
214
+ if (index > -1) {
215
+ const newUsers = [...this.state.group.Audience];
216
+ newUsers[index].isAdmin = !newUsers[index].isAdmin;
217
+ this.setState({ group: { ...this.state.group, Audience: newUsers } });
218
+ }
219
+ };
220
+
221
+ closeInvitePopup() {
222
+ this.setState({
223
+ inviteOpen: false,
224
+ inviteAttendeeList: null,
225
+ inviteRepToShow: null,
226
+ inviteRepIdToShow: null,
227
+ });
228
+ }
229
+
230
+ openInvite() {
231
+ this.setState({ inviteOpen: true });
232
+ }
233
+
234
+ nextPage() {
235
+ this.setState({ page: 2, title: this.state.title });
236
+ }
237
+
238
+ clickCreate() {
239
+ if (this.state.title.length < 1) {
240
+ this.setState({ showErrors: true });
241
+ return;
242
+ }
243
+ if (this.state.uploadingImage) {
244
+ return;
245
+ }
246
+ this.onSubmitSend();
247
+ }
248
+
249
+ showUploadMenu() {
250
+ if (this.state.uploadingImage || this.state.submittingGroup) {
251
+ return;
252
+ }
253
+ this.imageUploader.showUploadMenu();
254
+ }
255
+
256
+ renderInvitePopup() {
257
+ return (
258
+ <EventInvitePopup
259
+ isNewEvent
260
+ onNewEventInvite={this.addToAudience.bind(this)}
261
+ onNewEventRemove={this.removeFromAudience.bind(this)}
262
+ isSearchable
263
+ source="residents"
264
+ attendees={this.getAttendees()}
265
+ attendingStatusText="Member"
266
+ invited={this.getInvited()}
267
+ invitedText="Added"
268
+ visible={this.state.inviteOpen}
269
+ onClose={this.closeInvitePopup.bind(this)}
270
+ showStatusText
271
+ editButtons
272
+ />
273
+ );
274
+ }
275
+
276
+ renderUploadMenu() {
277
+ return (
278
+ <ImageUploader
279
+ ref={(ref) => (this.imageUploader = ref)}
280
+ onUploadStarted={this.onUploadStarted}
281
+ onUploadSuccess={this.onUploadSuccess}
282
+ onUploadFailed={this.onUploadFailed}
283
+ onLibrarySelected={this.onUploadSuccess}
284
+ size={{ width: 700 }}
285
+ quality={0.8}
286
+ fileName={"groupImage"}
287
+ popupTitle={`Add ${values.entityName} Cover Image`}
288
+ />
289
+ );
290
+ }
291
+
292
+ renderInnerImage() {
293
+ if (!this.state.uploadingImage && this.state.groupImage === null) {
294
+ return (
295
+ <View>
296
+ <Icon
297
+ name="camera"
298
+ //style={styles.uploadButtonInner}
299
+ type="font-awesome"
300
+ iconStyle={{ color: TEXT_LIGHT, fontSize: 20, marginBottom: 13 }}
301
+ />
302
+ <Text
303
+ style={{
304
+ fontSize: 13,
305
+ fontFamily: "sf-regular",
306
+ color: TEXT_LIGHT,
307
+ }}
308
+ >
309
+ Upload group image
310
+ </Text>
311
+ </View>
312
+ );
313
+ }
314
+ return this.renderImage();
315
+ }
316
+
317
+ renderImage() {
318
+ if (this.state.uploadingImage) {
319
+ return <Spinner />;
320
+ }
321
+ if (this.state.groupImage) {
322
+ return (
323
+ <ImageBackground
324
+ style={{
325
+ flex: 1,
326
+ height: "100%",
327
+ width: "100%",
328
+ borderRadius: 4,
329
+ justifyContent: "center",
330
+ alignContent: "center",
331
+ }}
332
+ imageStyle={{ borderRadius: 4 }}
333
+ source={{ uri: this.state.groupImage }}
334
+ >
335
+ <View>
336
+ <Icon
337
+ name="camera"
338
+ //style={styles.uploadButtonInner}
339
+ type="font-awesome"
340
+ iconStyle={{ color: "#fff", fontSize: 20, marginBottom: 13 }}
341
+ />
342
+ <Text
343
+ style={{
344
+ fontSize: 13,
345
+ fontFamily: "sf-regular",
346
+ color: "#fff",
347
+ textAlign: "center",
348
+ }}
349
+ >
350
+ Upload {values.entityName} image
351
+ </Text>
352
+ </View>
353
+ </ImageBackground>
354
+ );
355
+ }
356
+ }
357
+
358
+ renderPage() {
359
+ return (
360
+ <View>
361
+ <FormCard style={{ marginTop: 16 }}>
362
+ <FormCardSection
363
+ label={`${_.capitalize(values.entityName)} name`}
364
+ placeholder={`${_.capitalize(values.entityName)} name`}
365
+ textValue={this.state.title}
366
+ onChangeText={(value) => {
367
+ this.onChangeTitle(value);
368
+ }}
369
+ editable={this.state.submittingGroup === false}
370
+ isValid={() => {
371
+ return this.state.title.length > 1;
372
+ }}
373
+ required
374
+ />
375
+ </FormCard>
376
+ <View style={{ padding: 24 }}>
377
+ <TouchableOpacity
378
+ activeOpacity={0.8}
379
+ onPress={this.showUploadMenu.bind(this)}
380
+ >
381
+ <View style={styles.imageContainer}>{this.renderInnerImage()}</View>
382
+ </TouchableOpacity>
383
+ </View>
384
+ <View style={{ paddingVertical: 24, paddingHorizontal: 8 }}>
385
+ <View style={{ paddingHorizontal: 16 }}>
386
+ <TextStyle type="detailLabel">Members</TextStyle>
387
+ </View>
388
+ {this.getAttendees().map((user) => {
389
+ return (
390
+ <UserListing
391
+ key={user.userId}
392
+ user={user}
393
+ rightContent={(() => {
394
+ if (this.state.usersToAdd.indexOf(user) > -1) {
395
+ return null;
396
+ }
397
+ return (
398
+ <InlineButton
399
+ onPress={() => {
400
+ this.toggleAdmin(user);
401
+ }}
402
+ style={{
403
+ borderColor: this.props.colourBrandingMain,
404
+ borderWidth: 1,
405
+ }}
406
+ textStyle={{ color: this.props.colourBrandingMain }}
407
+ >
408
+ {user.isAdmin ? "Remove admin" : "Make admin"}
409
+ </InlineButton>
410
+ );
411
+ })()}
412
+ statusText={(() => {
413
+ if (this.state.usersToAdd.indexOf(user) > -1) {
414
+ return "Added";
415
+ }
416
+ if (user.isAdmin) {
417
+ return "Admin";
418
+ }
419
+ return "Member";
420
+ })()}
421
+ />
422
+ );
423
+ })}
424
+ </View>
425
+ </View>
426
+ );
427
+ }
428
+
429
+ renderPreviewAtts() {
430
+ return (
431
+ <View style={styles.attendeePreviews}>
432
+ {this.state.allUsers.map((user, index) => {
433
+ if (index < 3) {
434
+ return (
435
+ <ProfilePic
436
+ ProfilePic={user.profilePic}
437
+ Diameter={36}
438
+ style={[styles.profilePic, { left: index * -20 }]}
439
+ key={user.userId}
440
+ />
441
+ );
442
+ }
443
+ return null;
444
+ })}
445
+ </View>
446
+ );
447
+ }
448
+
449
+ renderInviteButton() {
450
+ const changes = this.getPendingChanges();
451
+ return (
452
+ <View style={{ flexDirection: "row" }}>
453
+ {this.renderPreviewAtts()}
454
+ <View style={styles.fill}>
455
+ <InlineButton
456
+ onPress={this.openInvite.bind(this)}
457
+ style={[
458
+ styles.inviteButton,
459
+ { borderColor: this.props.colourBrandingMain },
460
+ ]}
461
+ color="#fff"
462
+ textStyle={{ color: this.props.colourBrandingMain }}
463
+ >
464
+ Manage members
465
+ </InlineButton>
466
+ <View style={styles.attendingContainer}>
467
+ <Text style={styles.tix} numberOfLines={1}>
468
+ <Text>{this.state.group.Audience.length}</Text>
469
+ {" members"}
470
+ </Text>
471
+ <Text
472
+ style={[
473
+ styles.tix,
474
+ changes.length > 0 && { color: Colours.COLOUR_RED },
475
+ ]}
476
+ numberOfLines={1}
477
+ >
478
+ <Text>{changes.length}</Text>
479
+ {" changes made"}
480
+ </Text>
481
+ </View>
482
+ </View>
483
+ </View>
484
+ );
485
+ }
486
+
487
+ render() {
488
+ if (!this.state.group) {
489
+ return null;
490
+ }
491
+ return (
492
+ <KeyboardAvoidingView
493
+ behavior={"padding"}
494
+ style={{ position: "relative", flex: 1, backgroundColor: "#fff" }}
495
+ >
496
+ <View style={styles.greyContainer}>
497
+ {this.renderUploadMenu()}
498
+ <Header
499
+ leftIcon="close"
500
+ leftIconType="pluss"
501
+ leftText="Cancel"
502
+ leftIconStyle={{ color: this.props.colourBrandingMain }}
503
+ onPressLeft={this.onPressBack.bind(this)}
504
+ rightText="Done"
505
+ onPressRight={this.clickCreate.bind(this)}
506
+ optionalRightStyle={this.state.submittingGroup && { opacity: 0.2 }}
507
+ text={this.state.title.length > 1 ? this.state.title : " "}
508
+ />
509
+ <ScrollView style={{ flex: 1 }} keyboardShouldPersistTaps={"handled"}>
510
+ {this.state.submittingGroup && (
511
+ <View style={{ marginTop: 16 }}>
512
+ <Spinner size={"small"} />
513
+ </View>
514
+ )}
515
+ {this.renderPage()}
516
+ </ScrollView>
517
+
518
+ <StickyFooter style={styles.footer}>
519
+ {this.renderInviteButton()}
520
+ </StickyFooter>
521
+ </View>
522
+
523
+ {this.renderInvitePopup()}
524
+ </KeyboardAvoidingView>
525
+ );
526
+ }
460
527
  }
461
528
 
462
529
  const styles = {
463
- footer: {
464
- paddingHorizontal: 16,
465
- flexDirection: 'row',
466
- alignItems: 'center',
467
- },
468
- footerButton: {
469
- flex: 1,
470
- },
471
- profilePic: {
472
- borderWidth: 1,
473
- borderColor: '#fff',
474
- },
475
- fill: {
476
- flex: 1,
477
- flexDirection: 'row-reverse',
478
- justifyContent: 'space-between',
479
- },
480
- attendeePreviews: {
481
- width: 90,
482
- height: 36,
483
- flexDirection: 'row',
484
- },
485
- inviteButton: {
486
- height: 36,
487
- //width: 142,
488
- justifyContent: 'center',
489
- alignItems: 'center',
490
- borderRadius: 5,
491
- marginLeft: 8,
492
- borderWidth: 1,
493
- flex: 1,
494
- },
495
- viewContainer: {
496
- flex: 1,
497
- backgroundColor: '#fff',
498
- },
499
- container: {
500
- flex: 1,
501
- position: 'relative',
502
- },
503
- greyContainer: {
504
- flex: 1,
505
- backgroundColor: BG_GREY,
506
- },
507
- uploadButton: {
508
- width: '100%',
509
- //height: 150,
510
- alignContent: 'center',
511
- position: 'absolute',
512
- flexDirection: 'row',
513
- justifyContent: 'center',
514
- top: 65,
515
- },
516
- imageContainer: {
517
- width: PHOTO_WIDTH,
518
- height: PHOTO_WIDTH * 0.8,
519
- backgroundColor: '#fff',
520
- borderStyle: 'dashed',
521
- justifyContent: 'center',
522
- alignItems: 'center',
523
- borderWidth: 1,
524
- borderColor: LINEGREY,
525
- borderRadius: 4,
526
- },
527
- attendingContainer: {
528
- paddingLeft: 8,
529
- },
530
- tix: {
531
- fontFamily: 'sf-semibold',
532
- color: TEXT_LIGHT,
533
- fontSize: 14,
534
- flex: 1,
535
- },
530
+ footer: {
531
+ paddingHorizontal: 16,
532
+ flexDirection: "row",
533
+ alignItems: "center",
534
+ },
535
+ footerButton: {
536
+ flex: 1,
537
+ },
538
+ profilePic: {
539
+ borderWidth: 1,
540
+ borderColor: "#fff",
541
+ },
542
+ fill: {
543
+ flex: 1,
544
+ flexDirection: "row-reverse",
545
+ justifyContent: "space-between",
546
+ },
547
+ attendeePreviews: {
548
+ width: 90,
549
+ height: 36,
550
+ flexDirection: "row",
551
+ },
552
+ inviteButton: {
553
+ height: 36,
554
+ //width: 142,
555
+ justifyContent: "center",
556
+ alignItems: "center",
557
+ borderRadius: 5,
558
+ marginLeft: 8,
559
+ borderWidth: 1,
560
+ flex: 1,
561
+ },
562
+ viewContainer: {
563
+ flex: 1,
564
+ backgroundColor: "#fff",
565
+ },
566
+ container: {
567
+ flex: 1,
568
+ position: "relative",
569
+ },
570
+ greyContainer: {
571
+ flex: 1,
572
+ backgroundColor: BG_GREY,
573
+ },
574
+ uploadButton: {
575
+ width: "100%",
576
+ //height: 150,
577
+ alignContent: "center",
578
+ position: "absolute",
579
+ flexDirection: "row",
580
+ justifyContent: "center",
581
+ top: 65,
582
+ },
583
+ imageContainer: {
584
+ width: PHOTO_WIDTH,
585
+ height: PHOTO_WIDTH * 0.8,
586
+ backgroundColor: "#fff",
587
+ borderStyle: "dashed",
588
+ justifyContent: "center",
589
+ alignItems: "center",
590
+ borderWidth: 1,
591
+ borderColor: LINEGREY,
592
+ borderRadius: 4,
593
+ },
594
+ attendingContainer: {
595
+ paddingLeft: 8,
596
+ },
597
+ tix: {
598
+ fontFamily: "sf-semibold",
599
+ color: TEXT_LIGHT,
600
+ fontSize: 14,
601
+ flex: 1,
602
+ },
536
603
  };
537
604
 
538
- const mapStateToProps = state => {
539
- return {
540
- connected: state.connection.connected,
541
- user: state.user,
542
- blockedUserKeys: state[values.reducerKeyChats].blockedUsers,
543
- groups: state[values.reducerKey].list,
544
- colourBrandingMain: getMainBrandingColourFromState(state),
545
- };
605
+ const mapStateToProps = (state) => {
606
+ return {
607
+ connected: state.connection.connected,
608
+ user: state.user,
609
+ blockedUserKeys: state[values.reducerKeyChats].blockedUsers,
610
+ groups: state[values.reducerKey].list,
611
+ colourBrandingMain: getMainBrandingColourFromState(state),
612
+ };
546
613
  };
547
614
 
548
- export default connect(mapStateToProps, { createGroup, loadGroups, editGroup })(EditGroup);
615
+ export default connect(mapStateToProps, { createGroup, loadGroups, editGroup })(
616
+ EditGroup,
617
+ );