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