@plusscommunities/pluss-maintenance-app 6.1.2-beta.0 → 7.0.0-beta.1

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 (78) hide show
  1. package/dist/module/actions/JobActions.js +44 -1
  2. package/dist/module/actions/JobActions.js.map +1 -1
  3. package/dist/module/actions/types.js +3 -0
  4. package/dist/module/actions/types.js.map +1 -1
  5. package/dist/module/apis/index.js +3 -1
  6. package/dist/module/apis/index.js.map +1 -1
  7. package/dist/module/apis/{generalActions.js → maintenanceActions.js} +44 -45
  8. package/dist/module/apis/maintenanceActions.js.map +1 -0
  9. package/dist/module/components/FilterPopupMenu.js +78 -26
  10. package/dist/module/components/FilterPopupMenu.js.map +1 -1
  11. package/dist/module/components/MaintenanceList.js +70 -45
  12. package/dist/module/components/MaintenanceList.js.map +1 -1
  13. package/dist/module/components/MaintenanceListItem.js +54 -42
  14. package/dist/module/components/MaintenanceListItem.js.map +1 -1
  15. package/dist/module/components/MaintenanceWidgetItem.js +16 -20
  16. package/dist/module/components/MaintenanceWidgetItem.js.map +1 -1
  17. package/dist/module/components/PrioritySelectorPopup.js +82 -0
  18. package/dist/module/components/PrioritySelectorPopup.js.map +1 -0
  19. package/dist/module/components/StatusSelectorPopup.js +9 -13
  20. package/dist/module/components/StatusSelectorPopup.js.map +1 -1
  21. package/dist/module/components/WidgetSmall.js +13 -9
  22. package/dist/module/components/WidgetSmall.js.map +1 -1
  23. package/dist/module/feature.config.js +3 -3
  24. package/dist/module/feature.config.js.map +1 -1
  25. package/dist/module/helper.js +39 -17
  26. package/dist/module/helper.js.map +1 -1
  27. package/dist/module/reducers/JobsReducer.js +33 -3
  28. package/dist/module/reducers/JobsReducer.js.map +1 -1
  29. package/dist/module/screens/JobTypePicker.js +3 -3
  30. package/dist/module/screens/JobTypePicker.js.map +1 -1
  31. package/dist/module/screens/MaintenancePage.js +2 -2
  32. package/dist/module/screens/RequestDetail.js +340 -88
  33. package/dist/module/screens/RequestDetail.js.map +1 -1
  34. package/dist/module/screens/RequestNotes.js +437 -26
  35. package/dist/module/screens/RequestNotes.js.map +1 -1
  36. package/dist/module/screens/ServiceRequest.js +596 -93
  37. package/dist/module/screens/ServiceRequest.js.map +1 -1
  38. package/dist/module/values.config.a.js +9 -1
  39. package/dist/module/values.config.a.js.map +1 -1
  40. package/dist/module/values.config.default.js +15 -1
  41. package/dist/module/values.config.default.js.map +1 -1
  42. package/dist/module/values.config.forms.js +42 -0
  43. package/dist/module/values.config.forms.js.map +1 -0
  44. package/dist/module/values.config.js +34 -20
  45. package/dist/module/values.config.js.map +1 -1
  46. package/package.json +11 -11
  47. package/src/actions/JobActions.js +53 -1
  48. package/src/actions/types.js +4 -0
  49. package/src/apis/index.js +5 -1
  50. package/src/apis/{generalActions.js → maintenanceActions.js} +51 -43
  51. package/src/components/FilterPopupMenu.js +75 -24
  52. package/src/components/MaintenanceList.js +64 -33
  53. package/src/components/MaintenanceListItem.js +53 -31
  54. package/src/components/MaintenanceWidgetItem.js +18 -14
  55. package/src/components/PrioritySelectorPopup.js +79 -0
  56. package/src/components/StatusSelectorPopup.js +8 -13
  57. package/src/components/WidgetSmall.js +9 -7
  58. package/src/feature.config.js +15 -13
  59. package/src/helper.js +51 -13
  60. package/src/reducers/JobsReducer.js +27 -2
  61. package/src/screens/JobTypePicker.js +1 -1
  62. package/src/screens/RequestDetail.js +324 -75
  63. package/src/screens/RequestNotes.js +434 -33
  64. package/src/screens/ServiceRequest.js +642 -157
  65. package/src/values.config.a.js +8 -0
  66. package/src/values.config.default.js +14 -0
  67. package/src/values.config.forms.js +42 -0
  68. package/src/values.config.js +34 -20
  69. package/dist/module/apis/generalActions.js.map +0 -1
  70. package/dist/module/values.config.b.js +0 -28
  71. package/dist/module/values.config.b.js.map +0 -1
  72. package/dist/module/values.config.c.js +0 -28
  73. package/dist/module/values.config.c.js.map +0 -1
  74. package/dist/module/values.config.d.js +0 -28
  75. package/dist/module/values.config.d.js.map +0 -1
  76. package/src/values.config.b.js +0 -28
  77. package/src/values.config.c.js +0 -28
  78. package/src/values.config.d.js +0 -28
@@ -1,18 +1,20 @@
1
- function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2
- function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
1
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
2
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
3
3
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
4
4
  import React, { Component } from 'react';
5
- import { ScrollView, View, Text, TouchableOpacity, Modal, KeyboardAvoidingView } from 'react-native';
5
+ import { ScrollView, View, Text, TouchableOpacity, Modal, KeyboardAvoidingView, Platform, FlatList, Dimensions, ImageBackground, Keyboard } from 'react-native';
6
6
  import { connect } from 'react-redux';
7
- import { Icon } from 'react-native-elements';
7
+ import { Icon } from '@rneui/themed';
8
8
  import _ from 'lodash';
9
9
  import moment from 'moment';
10
10
  import { jobAdded } from '../actions';
11
- import { generalActions } from '../apis';
11
+ import { maintenanceActions } from '../apis';
12
12
  import { getBottomSpace } from 'react-native-iphone-x-helper';
13
13
  import { Services } from '../feature.config';
14
14
  import { Components, Colours, Helper } from '../core.config';
15
15
  import { values } from '../values.config';
16
+ const SCREEN_WIDTH = Dimensions.get('window').width;
17
+ const PHOTO_SIZE = (SCREEN_WIDTH - 64) / 3;
16
18
  class RequestNotes extends Component {
17
19
  constructor(props) {
18
20
  super(props);
@@ -35,7 +37,7 @@ class RequestNotes extends Component {
35
37
  });
36
38
  });
37
39
  _defineProperty(this, "onPressConfirmDelete", () => {
38
- generalActions.deleteNote(this.props.job.id, this.state.noteToDelete.Id);
40
+ maintenanceActions.deleteNote(this.props.job.id, this.state.noteToDelete.Id);
39
41
  const newNotes = _.filter(this.state.job.Notes, note => {
40
42
  return note.Id !== this.state.noteToDelete.Id;
41
43
  });
@@ -44,6 +46,7 @@ class RequestNotes extends Component {
44
46
  };
45
47
  newJob.Notes = newNotes;
46
48
  this.props.jobAdded(newJob);
49
+ this.props.onChange && this.props.onChange();
47
50
  this.setState({
48
51
  job: newJob,
49
52
  noteToDelete: null
@@ -55,12 +58,10 @@ class RequestNotes extends Component {
55
58
  });
56
59
  });
57
60
  _defineProperty(this, "isReadyToSaveNote", () => {
58
- if (_.some(this.state.noteAttachments, n => {
59
- return n.Uploading;
60
- })) {
61
- return false;
62
- }
63
- return !_.isEmpty(this.state.noteInput) || !_.isEmpty(this.state.noteAttachments);
61
+ const uploadingAttachments = _.some(this.state.noteAttachments, n => n.Uploading);
62
+ const uploadingImages = _.some(this.state.noteImages, n => n.uploading);
63
+ if (uploadingAttachments || uploadingImages) return false;
64
+ return !_.isEmpty(this.state.noteInput) || !_.isEmpty(this.state.noteAttachments) || !_.isEmpty(this.state.noteImages.filter(img => !img.add));
64
65
  });
65
66
  _defineProperty(this, "openAddNote", () => {
66
67
  this.setState({
@@ -76,12 +77,20 @@ class RequestNotes extends Component {
76
77
  if (!!this.state.editingNote) {
77
78
  newState.noteInput = '';
78
79
  newState.noteAttachments = [];
80
+ newState.noteImages = [];
79
81
  }
80
82
  this.setState(newState);
81
83
  });
82
84
  _defineProperty(this, "openEditNote", n => {
85
+ const noteImages = [...(n.Images || []).map(i => ({
86
+ url: i,
87
+ thumbNailUrl: Helper.getThumb300(i)
88
+ })), {
89
+ add: true
90
+ }];
83
91
  this.setState({
84
92
  noteAttachments: n.Attachments || [],
93
+ noteImages,
85
94
  noteInput: n.Note || '',
86
95
  addNoteOpen: true,
87
96
  editingNote: n.Id,
@@ -96,42 +105,184 @@ class RequestNotes extends Component {
96
105
  this.setState({
97
106
  submittingNote: true
98
107
  });
99
- const res = await (this.state.editingNote ? generalActions.editNote(this.props.job.id, this.state.editingNote, this.state.noteInput, this.state.noteAttachments.map(a => {
100
- return {
101
- Title: a.Title,
102
- Source: a.Source
103
- };
104
- })) : generalActions.addNote(this.props.job.id, this.state.noteInput, this.state.noteAttachments.map(a => {
108
+ const attachments = this.state.noteAttachments.filter(a => !a.add).map(a => {
105
109
  return {
106
110
  Title: a.Title,
107
111
  Source: a.Source
108
112
  };
109
- })));
113
+ });
114
+ const images = this.state.noteImages.filter(img => !img.add).map(img => img.url);
115
+ const res = await (this.state.editingNote ? maintenanceActions.editNote(this.props.job.id, this.state.editingNote, this.state.noteInput, attachments, images) : maintenanceActions.addNote(this.props.job.id, this.state.noteInput, attachments, images));
110
116
  this.setState({
111
117
  job: res.data.job,
112
118
  submittingNote: false,
113
119
  addNoteOpen: false,
114
120
  noteInput: '',
115
121
  noteAttachments: [],
122
+ noteImages: [{
123
+ add: true
124
+ }],
125
+ uploadingImage: false,
116
126
  editingNote: null
117
127
  }, () => {
118
128
  this.props.jobAdded(res.data.job);
129
+ this.props.onChange && this.props.onChange();
119
130
  });
120
131
  } catch (err) {
121
132
  console.log('error');
122
133
  console.log(err);
123
134
  this.setState({
124
- submittingNote: false
135
+ submittingNote: false,
136
+ uploadingImage: false
125
137
  });
126
138
  }
127
139
  });
140
+ _defineProperty(this, "setImages", (noteImages, uploadingImage = false, callback = null) => {
141
+ this.setState({
142
+ noteImages,
143
+ uploadingImage
144
+ }, callback);
145
+ });
146
+ _defineProperty(this, "getImages", () => {
147
+ const {
148
+ noteImages
149
+ } = this.state;
150
+ const imagesList = _.cloneDeep(noteImages);
151
+ if (!imagesList || !Array.isArray(imagesList) || imagesList.length === 0) {
152
+ return [{
153
+ add: true
154
+ }];
155
+ }
156
+ return imagesList;
157
+ });
158
+ _defineProperty(this, "getImageUrls", () => {
159
+ const imagesList = this.getImages();
160
+ return _.filter(imagesList, img => {
161
+ return !img.uploading && !img.add;
162
+ }).map(img => {
163
+ return img.url;
164
+ });
165
+ });
166
+ _defineProperty(this, "waitForThumbnails", () => {
167
+ if (this.checkThumb) return;
168
+ this.checkThumb = setInterval(async () => {
169
+ const imagesList = this.getImages();
170
+ const imagesUpdate = [];
171
+ await Promise.all(imagesList.map(image => {
172
+ return new Promise(async resolve => {
173
+ const newImage = {
174
+ ...image
175
+ };
176
+ imagesUpdate.push(newImage);
177
+ if (newImage.url && !newImage.thumbNailExists) {
178
+ newImage.uploading = false;
179
+ newImage.allowRetry = false;
180
+ newImage.thumbNailExists = await Helper.imageExists(newImage.thumbNailUrl);
181
+ resolve(newImage.thumbNailExists);
182
+ }
183
+ resolve(true);
184
+ });
185
+ }));
186
+ const thumbnailsExist = imagesUpdate.every(image => !image.url || image.thumbNailExists);
187
+ if (thumbnailsExist) {
188
+ clearInterval(this.checkThumb);
189
+ this.checkThumb = null;
190
+ this.setImages(imagesUpdate);
191
+ }
192
+ }, 2000);
193
+ });
194
+ _defineProperty(this, "removeImage", index => {
195
+ const imagesUpdate = this.getImages();
196
+ imagesUpdate.splice(index, 1);
197
+ this.setImages(imagesUpdate);
198
+ });
199
+ _defineProperty(this, "showUploadMenu", () => {
200
+ Keyboard.dismiss();
201
+ const {
202
+ uploadingImage,
203
+ submittingNote
204
+ } = this.state;
205
+ if (uploadingImage || submittingNote) return;
206
+ this.imageUploader.showUploadMenu();
207
+ });
208
+ _defineProperty(this, "toggleFullscreenVideo", url => {
209
+ if (typeof url !== 'string') url = '';
210
+ this.setState({
211
+ showFullscreenVideo: url.length > 0,
212
+ currentVideoUrl: url
213
+ });
214
+ });
215
+ _defineProperty(this, "onUploadStarted", (uploadUri, imageUri) => {
216
+ const imagesUpdate = this.getImages();
217
+ imagesUpdate.splice(imagesUpdate.length - 1, 0, {
218
+ uploading: true,
219
+ uploadProgress: '0%',
220
+ uploadUri,
221
+ imageUri,
222
+ allowRetry: true
223
+ });
224
+ this.setImages(imagesUpdate, true);
225
+ });
226
+ _defineProperty(this, "onUploadProgress", progress => {
227
+ const imagesUpdate = this.getImages();
228
+ imagesUpdate.map(img => {
229
+ if (img.uploadUri === progress.uri) {
230
+ img.uploadProgress = progress.percentage;
231
+ img.uploading = true;
232
+ img.allowRetry = true;
233
+ }
234
+ });
235
+ this.setImages(imagesUpdate, true);
236
+ });
237
+ _defineProperty(this, "onUploadSuccess", async (uri, uploadUri) => {
238
+ const imagesUpdate = this.getImages();
239
+ imagesUpdate.map(img => {
240
+ if (img.uploadUri === uploadUri && img.uploading) {
241
+ img.url = uri.replace('/general/', '/general1400/');
242
+ img.thumbNailExists = false;
243
+ img.thumbNailUrl = Helper.getThumb300(img.url);
244
+ img.allowRetry = true;
245
+ }
246
+ });
247
+ this.setImages(imagesUpdate, false, () => this.waitForThumbnails());
248
+ });
249
+ _defineProperty(this, "onUploadFailed", uploadUri => {
250
+ const imagesUpdate = this.getImages();
251
+ imagesUpdate.map(img => {
252
+ if (img.uploadUri === uploadUri) {
253
+ img.uploading = true; // Requried for retry
254
+ img.uploadProgress = '';
255
+ img.allowRetry = true;
256
+ }
257
+ });
258
+ this.setImages(imagesUpdate);
259
+ });
260
+ _defineProperty(this, "onLibrarySelected", uri => {
261
+ const imagesUpdate = this.getImages();
262
+ imagesUpdate.splice(imagesUpdate.length - 1, 0, {
263
+ uploading: false,
264
+ allowRetry: false,
265
+ url: Helper.get1400(uri),
266
+ thumbNailExists: true,
267
+ thumbNailUrl: Helper.getThumb300(uri)
268
+ });
269
+ this.setImages(imagesUpdate);
270
+ });
128
271
  this.state = {
129
272
  job: {},
130
273
  selectedPDF: null,
131
274
  noteAttachments: [],
132
275
  noteInput: '',
133
- addNoteOpen: false
276
+ addNoteOpen: false,
277
+ noteImages: [{
278
+ add: true
279
+ }],
280
+ uploadingImage: false,
281
+ galleryOpen: false,
282
+ galleryImages: [],
283
+ galleryIndex: 0
134
284
  };
285
+ this.checkThumb = null;
135
286
  }
136
287
  componentDidMount() {
137
288
  this.updateJobState();
@@ -141,12 +292,29 @@ class RequestNotes extends Component {
141
292
  this.updateJobState();
142
293
  }
143
294
  }
295
+ componentWillUnmount() {
296
+ clearInterval(this.checkThumb);
297
+ }
144
298
  updateJobState() {
145
299
  const job = _.find(this.props.jobs, j => j.id === this.props.job.id) || this.props.job;
146
300
  this.setState({
147
301
  job
148
302
  });
149
303
  }
304
+ openGallery(images, index) {
305
+ this.setState({
306
+ galleryOpen: true,
307
+ galleryImages: images,
308
+ galleryIndex: index
309
+ });
310
+ }
311
+ closeGallery() {
312
+ this.setState({
313
+ galleryOpen: false,
314
+ galleryImages: [],
315
+ galleryIndex: 0
316
+ });
317
+ }
150
318
  renderAttachment(a, i) {
151
319
  return /*#__PURE__*/React.createElement(Components.Attachment, {
152
320
  onPress: () => {
@@ -156,6 +324,67 @@ class RequestNotes extends Component {
156
324
  title: a.Title
157
325
  });
158
326
  }
327
+ renderPlayableImageUrl(images, index, containerStyle) {
328
+ const url = images[index];
329
+ const thumbUrl = Helper.getThumb300(url);
330
+ if (Helper.isVideo(url)) {
331
+ return /*#__PURE__*/React.createElement(ImageBackground, {
332
+ style: [{
333
+ flex: 1
334
+ }, containerStyle],
335
+ source: {
336
+ uri: thumbUrl
337
+ }
338
+ }, /*#__PURE__*/React.createElement(View, {
339
+ style: styles.imagePlayContainer
340
+ }, /*#__PURE__*/React.createElement(TouchableOpacity, {
341
+ onPress: this.toggleFullscreenVideo.bind(this, url)
342
+ }, /*#__PURE__*/React.createElement(Icon, {
343
+ name: "play",
344
+ type: "font-awesome",
345
+ iconStyle: styles.imageControlIcon
346
+ }))));
347
+ }
348
+ const imageUrl = Helper.get1400(url);
349
+ return /*#__PURE__*/React.createElement(TouchableOpacity, {
350
+ style: containerStyle,
351
+ onPress: this.openGallery.bind(this, images, index || 0)
352
+ }, /*#__PURE__*/React.createElement(ImageBackground, {
353
+ resizeMode: "cover",
354
+ style: styles.imageContainer,
355
+ source: {
356
+ uri: imageUrl
357
+ }
358
+ }));
359
+ }
360
+ renderImages(note) {
361
+ if (!note) return null;
362
+ if (!_.isNil(note.Images) && !_.isEmpty(note.Images)) {
363
+ return /*#__PURE__*/React.createElement(ScrollView, {
364
+ horizontal: true,
365
+ style: styles.sideBySideImages
366
+ }, note.Images.map((_p, index) => this.renderPlayableImageUrl(note.Images, index, styles.sideBySideImageContainer)));
367
+ }
368
+ return null;
369
+ }
370
+ renderImagePopup() {
371
+ const {
372
+ galleryOpen,
373
+ galleryImages,
374
+ galleryIndex
375
+ } = this.state;
376
+ console.log('renderimagepopup', {
377
+ galleryOpen,
378
+ galleryImages,
379
+ galleryIndex
380
+ });
381
+ return /*#__PURE__*/React.createElement(Components.ImagePopup, {
382
+ visible: galleryOpen,
383
+ images: galleryImages,
384
+ index: galleryIndex,
385
+ onClose: this.closeGallery.bind(this)
386
+ });
387
+ }
159
388
  renderNote(n) {
160
389
  return /*#__PURE__*/React.createElement(View, {
161
390
  style: styles.noteContainer,
@@ -198,7 +427,7 @@ class RequestNotes extends Component {
198
427
  style: styles.noteContainerName
199
428
  }, n.User.displayName)))), /*#__PURE__*/React.createElement(Text, {
200
429
  style: styles.noteContainerText
201
- }, n.Note), (n.Attachments || []).map((a, i) => this.renderAttachment(a, i)), /*#__PURE__*/React.createElement(Text, {
430
+ }, n.Note), (n.Attachments || []).map((a, i) => this.renderAttachment(a, i)), this.renderImages(n), /*#__PURE__*/React.createElement(Text, {
202
431
  style: styles.noteTimestamp
203
432
  }, moment.utc(n.Timestamp).local().format(Helper.TIMESTAMP_FORMAT)));
204
433
  }
@@ -238,6 +467,108 @@ class RequestNotes extends Component {
238
467
  large: true
239
468
  }, "Save");
240
469
  }
470
+ renderUploadMenu() {
471
+ return /*#__PURE__*/React.createElement(Components.ImageUploader, {
472
+ ref: ref => this.imageUploader = ref,
473
+ onUploadStarted: this.onUploadStarted,
474
+ onUploadSuccess: this.onUploadSuccess,
475
+ onUploadFailed: this.onUploadFailed,
476
+ onUploadProgress: this.onUploadProgress,
477
+ onLibrarySelected: this.onLibrarySelected,
478
+ size: {
479
+ width: 1400
480
+ },
481
+ quality: 0.8,
482
+ fileName: 'serviceNoteImage',
483
+ popupTitle: 'Upload Image',
484
+ userId: this.props.user.uid,
485
+ allowsEditing: false,
486
+ multiple: true,
487
+ hideLibrary: true
488
+ });
489
+ }
490
+ renderImage(item, index) {
491
+ const isVideoUrl = Helper.isVideo(item.url);
492
+ const imagesList = this.getImages();
493
+ if (item.add) {
494
+ return /*#__PURE__*/React.createElement(TouchableOpacity, {
495
+ activeOpacity: 0.8,
496
+ onPress: () => this.showUploadMenu()
497
+ }, /*#__PURE__*/React.createElement(View, {
498
+ style: [styles.imageContainer, imagesList.length > 1 && styles.imageContainerNotEmpty, index % 3 === 0 && {
499
+ marginLeft: 0
500
+ }, index > 2 && {
501
+ marginTop: 8
502
+ }]
503
+ }, /*#__PURE__*/React.createElement(View, {
504
+ style: styles.imageCircle
505
+ }, /*#__PURE__*/React.createElement(Icon, {
506
+ name: "camera",
507
+ type: "font-awesome",
508
+ iconStyle: styles.addImageIcon
509
+ }))));
510
+ }
511
+ return /*#__PURE__*/React.createElement(View, {
512
+ style: [styles.imageContainer, imagesList.length > 1 && styles.imageContainerNotEmpty, index % 3 === 0 && {
513
+ marginLeft: 0
514
+ }, index > 2 && {
515
+ marginTop: 8
516
+ }]
517
+ }, item.uploading ? /*#__PURE__*/React.createElement(Components.ImageUploadProgress, {
518
+ uploader: this.imageUploader,
519
+ image: item,
520
+ color: this.props.colourBrandingMain
521
+ }) : /*#__PURE__*/React.createElement(ImageBackground, {
522
+ style: styles.imageBackground,
523
+ source: Helper.getImageSource(item.thumbNailExists ? item.thumbNailUrl : item.url || item)
524
+ }, isVideoUrl && /*#__PURE__*/React.createElement(View, {
525
+ style: styles.imagePlayContainer
526
+ }, /*#__PURE__*/React.createElement(TouchableOpacity, {
527
+ onPress: this.toggleFullscreenVideo.bind(this, item.url)
528
+ }, /*#__PURE__*/React.createElement(Icon, {
529
+ name: "play",
530
+ type: "font-awesome",
531
+ iconStyle: styles.imageControlIcon
532
+ }))), /*#__PURE__*/React.createElement(TouchableOpacity, {
533
+ style: styles.removeImage,
534
+ onPress: () => this.removeImage(index)
535
+ }, /*#__PURE__*/React.createElement(Icon, {
536
+ name: "remove",
537
+ type: "font-awesome",
538
+ iconStyle: styles.imageControlIcon,
539
+ style: styles.removeImage
540
+ }))));
541
+ }
542
+ renderImageList() {
543
+ const imagesList = this.getImages();
544
+ return /*#__PURE__*/React.createElement(View, {
545
+ style: styles.imageListContainer
546
+ }, /*#__PURE__*/React.createElement(FlatList, {
547
+ keyboardShouldPersistTaps: "always",
548
+ enableEmptySections: true,
549
+ data: imagesList,
550
+ renderItem: ({
551
+ item,
552
+ index
553
+ }) => this.renderImage(item, index),
554
+ keyExtractor: (item, index) => index,
555
+ numColumns: 3,
556
+ scrollEnabled: false
557
+ }));
558
+ }
559
+ renderVideoPlayerPopup() {
560
+ const {
561
+ showFullscreenVideo,
562
+ currentVideoUrl
563
+ } = this.state;
564
+ if (!currentVideoUrl) return;
565
+ return /*#__PURE__*/React.createElement(Components.VideoPopup, {
566
+ uri: currentVideoUrl,
567
+ visible: showFullscreenVideo,
568
+ showFullscreenButton: false,
569
+ onClose: this.toggleFullscreenVideo
570
+ });
571
+ }
241
572
  renderAdd() {
242
573
  return /*#__PURE__*/React.createElement(Modal, {
243
574
  animationType: "slide",
@@ -245,7 +576,7 @@ class RequestNotes extends Component {
245
576
  }, /*#__PURE__*/React.createElement(KeyboardAvoidingView, {
246
577
  style: styles.container,
247
578
  behavior: Platform.OS === 'ios' && 'padding'
248
- }, /*#__PURE__*/React.createElement(Components.Header, {
579
+ }, this.renderUploadMenu(), /*#__PURE__*/React.createElement(Components.Header, {
249
580
  leftText: "Cancel",
250
581
  onPressLeft: this.closeAddNote,
251
582
  text: ""
@@ -275,12 +606,12 @@ class RequestNotes extends Component {
275
606
  }), /*#__PURE__*/React.createElement(Components.GenericInputSection, {
276
607
  label: "Attachments",
277
608
  sectionStyle: styles.inputSection
278
- }, this.state.editingNote ? (this.state.noteAttachments || []).map((a, i) => this.renderAttachment(a, i)) : /*#__PURE__*/React.createElement(Components.TextStyle, {
609
+ }, this.renderImageList(), this.state.editingNote ? (this.state.noteAttachments || []).map((a, i) => this.renderAttachment(a, i)) : /*#__PURE__*/React.createElement(Components.TextStyle, {
279
610
  type: "body",
280
611
  style: styles.attachmentInfo
281
612
  }, "PDFs can only be attached to notes from the Community Manager."))), /*#__PURE__*/React.createElement(View, {
282
613
  style: styles.popupFooter
283
- }, this.renderFooterContent())));
614
+ }, this.renderFooterContent()), this.renderVideoPlayerPopup()));
284
615
  }
285
616
  render() {
286
617
  return /*#__PURE__*/React.createElement(View, {
@@ -294,7 +625,7 @@ class RequestNotes extends Component {
294
625
  contentContainerStyle: styles.innerContainer
295
626
  }, this.renderNotes()), /*#__PURE__*/React.createElement(Components.AddButton, {
296
627
  onPress: this.openAddNote
297
- }));
628
+ }), this.renderImagePopup());
298
629
  }
299
630
  }
300
631
  const styles = {
@@ -372,6 +703,86 @@ const styles = {
372
703
  },
373
704
  attachmentInfo: {
374
705
  marginTop: 8
706
+ },
707
+ imageListContainer: {
708
+ marginVertical: 8
709
+ },
710
+ imageContainer: {
711
+ width: PHOTO_SIZE,
712
+ height: PHOTO_SIZE,
713
+ borderStyle: 'dashed',
714
+ justifyContent: 'center',
715
+ alignItems: 'center',
716
+ borderWidth: 1,
717
+ borderColor: Colours.LINEGREY,
718
+ backgroundColor: Colours.BOXGREY,
719
+ borderRadius: 4,
720
+ marginLeft: 8
721
+ },
722
+ imageContainerNotEmpty: {
723
+ borderWidth: 1,
724
+ borderColor: Colours.LINEGREY,
725
+ backgroundColor: '#fff',
726
+ borderStyle: 'dashed'
727
+ },
728
+ imageBackground: {
729
+ flex: 1,
730
+ height: '100%',
731
+ width: '100%',
732
+ borderRadius: 4
733
+ },
734
+ imageCircle: {
735
+ width: 90,
736
+ height: 90,
737
+ borderRadius: 45,
738
+ backgroundColor: Colours.PINKISH_GREY,
739
+ justifyContent: 'center'
740
+ },
741
+ addImageIcon: {
742
+ color: '#fff',
743
+ fontSize: 32
744
+ },
745
+ imagePlayContainer: {
746
+ position: 'absolute',
747
+ top: 0,
748
+ left: 0,
749
+ right: 0,
750
+ bottom: 0,
751
+ alignItems: 'center',
752
+ justifyContent: 'center'
753
+ },
754
+ imageControlIcon: {
755
+ color: '#fff',
756
+ fontSize: 20,
757
+ textShadowColor: 'rgba(0,0,0,0.3)',
758
+ textShadowOffset: {
759
+ width: 2,
760
+ height: 2
761
+ }
762
+ },
763
+ removeImage: {
764
+ position: 'absolute',
765
+ top: 0,
766
+ right: 0,
767
+ padding: 4,
768
+ width: 40,
769
+ height: 40,
770
+ alignItems: 'center',
771
+ justifyContent: 'center'
772
+ },
773
+ sideBySideImages: {
774
+ flex: 1,
775
+ flexDirection: 'row',
776
+ marginTop: 12,
777
+ marginHorizontal: -8
778
+ },
779
+ sideBySideImageContainer: {
780
+ backgroundColor: '#fff',
781
+ width: 60,
782
+ height: 50,
783
+ borderRadius: 2,
784
+ overflow: 'hidden',
785
+ marginRight: 2
375
786
  }
376
787
  };
377
788
  const mapStateToProps = state => {