@plusscommunities/pluss-maintenance-app 6.1.2-beta.0 → 7.0.0-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 (69) hide show
  1. package/dist/module/apis/index.js +1 -1
  2. package/dist/module/apis/index.js.map +1 -1
  3. package/dist/module/apis/{generalActions.js → maintenanceActions.js} +25 -41
  4. package/dist/module/apis/maintenanceActions.js.map +1 -0
  5. package/dist/module/components/FilterPopupMenu.js +48 -12
  6. package/dist/module/components/FilterPopupMenu.js.map +1 -1
  7. package/dist/module/components/MaintenanceList.js +52 -18
  8. package/dist/module/components/MaintenanceList.js.map +1 -1
  9. package/dist/module/components/MaintenanceListItem.js +16 -17
  10. package/dist/module/components/MaintenanceListItem.js.map +1 -1
  11. package/dist/module/components/MaintenanceWidgetItem.js +4 -8
  12. package/dist/module/components/MaintenanceWidgetItem.js.map +1 -1
  13. package/dist/module/components/StatusSelectorPopup.js +2 -1
  14. package/dist/module/components/StatusSelectorPopup.js.map +1 -1
  15. package/dist/module/components/WidgetSmall.js +6 -6
  16. package/dist/module/components/WidgetSmall.js.map +1 -1
  17. package/dist/module/feature.config.js +3 -3
  18. package/dist/module/feature.config.js.map +1 -1
  19. package/dist/module/helper.js +10 -2
  20. package/dist/module/helper.js.map +1 -1
  21. package/dist/module/reducers/JobsReducer.js +2 -1
  22. package/dist/module/reducers/JobsReducer.js.map +1 -1
  23. package/dist/module/screens/JobTypePicker.js +3 -3
  24. package/dist/module/screens/JobTypePicker.js.map +1 -1
  25. package/dist/module/screens/MaintenancePage.js +2 -2
  26. package/dist/module/screens/RequestDetail.js +252 -72
  27. package/dist/module/screens/RequestDetail.js.map +1 -1
  28. package/dist/module/screens/RequestNotes.js +10 -8
  29. package/dist/module/screens/RequestNotes.js.map +1 -1
  30. package/dist/module/screens/ServiceRequest.js +596 -93
  31. package/dist/module/screens/ServiceRequest.js.map +1 -1
  32. package/dist/module/values.config.a.js +4 -1
  33. package/dist/module/values.config.a.js.map +1 -1
  34. package/dist/module/values.config.default.js +10 -1
  35. package/dist/module/values.config.default.js.map +1 -1
  36. package/dist/module/values.config.forms.js +37 -0
  37. package/dist/module/values.config.forms.js.map +1 -0
  38. package/dist/module/values.config.js +10 -1
  39. package/dist/module/values.config.js.map +1 -1
  40. package/package.json +12 -12
  41. package/src/apis/index.js +1 -1
  42. package/src/apis/{generalActions.js → maintenanceActions.js} +35 -39
  43. package/src/components/FilterPopupMenu.js +39 -7
  44. package/src/components/MaintenanceList.js +59 -19
  45. package/src/components/MaintenanceListItem.js +18 -10
  46. package/src/components/MaintenanceWidgetItem.js +2 -2
  47. package/src/components/StatusSelectorPopup.js +2 -1
  48. package/src/components/WidgetSmall.js +4 -4
  49. package/src/feature.config.js +15 -13
  50. package/src/helper.js +11 -2
  51. package/src/reducers/JobsReducer.js +2 -1
  52. package/src/screens/JobTypePicker.js +1 -1
  53. package/src/screens/RequestDetail.js +237 -51
  54. package/src/screens/RequestNotes.js +27 -25
  55. package/src/screens/ServiceRequest.js +642 -157
  56. package/src/values.config.a.js +3 -0
  57. package/src/values.config.default.js +9 -0
  58. package/src/values.config.forms.js +37 -0
  59. package/src/values.config.js +9 -0
  60. package/dist/module/apis/generalActions.js.map +0 -1
  61. package/dist/module/values.config.b.js +0 -28
  62. package/dist/module/values.config.b.js.map +0 -1
  63. package/dist/module/values.config.c.js +0 -28
  64. package/dist/module/values.config.c.js.map +0 -1
  65. package/dist/module/values.config.d.js +0 -28
  66. package/dist/module/values.config.d.js.map +0 -1
  67. package/src/values.config.b.js +0 -28
  68. package/src/values.config.c.js +0 -28
  69. package/src/values.config.d.js +0 -28
@@ -1,11 +1,11 @@
1
1
  import React, { Component } from 'react';
2
2
  import { ScrollView, View, StyleSheet, Text, KeyboardAvoidingView, TouchableOpacity, ImageBackground, Platform } from 'react-native';
3
3
  import DateTimePicker from 'react-native-modal-datetime-picker';
4
- import { Icon } from 'react-native-elements';
4
+ import { Icon } from '@rneui/themed';
5
5
  import _ from 'lodash';
6
6
  import moment from 'moment';
7
7
  import { connect } from 'react-redux';
8
- import { generalActions } from '../apis';
8
+ import { maintenanceActions } from '../apis';
9
9
  import { jobAdded } from '../actions';
10
10
  import StatusSelectorPopup from '../components/StatusSelectorPopup';
11
11
  import { jobStatusOptions, getJobStatusProps } from '../helper';
@@ -25,13 +25,15 @@ class RequestDetail extends Component {
25
25
  expectedDate: null,
26
26
  expectedDateText: '',
27
27
  seen: false,
28
- showMore: false,
28
+ showMore: true,
29
29
  showStatusPopup: false,
30
30
  loading: false,
31
31
  showFullscreenVideo: false,
32
32
  currentVideoUrl: '',
33
33
  galleryOpen: false,
34
+ galleryImages: [],
34
35
  showMessages: false,
36
+ assignees: [],
35
37
  };
36
38
 
37
39
  this.scrollView = React.createRef();
@@ -40,17 +42,48 @@ class RequestDetail extends Component {
40
42
  }
41
43
 
42
44
  componentDidMount() {
43
- this.updateJobState();
45
+ this.getJob();
46
+ this.updateJobState(this.props.job);
47
+ this.getAssignees();
44
48
  }
45
49
 
46
- componentDidUpdate(prevProps) {
47
- if (prevProps.jobs !== this.props.jobs) {
48
- this.updateJobState();
50
+ getJob = async () => {
51
+ this.setState({ loading: true }, async () => {
52
+ try {
53
+ const res = await maintenanceActions.getJob(this.props.job.site, this.props.job.id);
54
+ this.props.jobAdded(res.data);
55
+ this.updateJobState(res.data);
56
+ } catch (error) {
57
+ console.log('getJob error', error.toString());
58
+ // check for 403 or 404 error
59
+ if (error.response.status === 403 || error.response.status === 404) {
60
+ this.setState({
61
+ forbidden: true,
62
+ });
63
+ }
64
+ console.log('getJob error', error);
65
+ } finally {
66
+ this.setState({ loading: false });
67
+ }
68
+ });
69
+ };
70
+
71
+ getAssignees = async () => {
72
+ if (!this.hasPermission()) return;
73
+ try {
74
+ const res = await maintenanceActions.getAssignees(this.props.user.site);
75
+ this.setState({ assignees: res.data.Users });
76
+ } catch (error) {
77
+ console.log('getAssignees error', error);
49
78
  }
50
- }
79
+ };
51
80
 
52
- updateJobState() {
53
- const job = _.find(this.props.jobs, j => j.id === this.props.job.id) || this.props.job;
81
+ updateJobState(defaultJob) {
82
+ const job = _.find(this.props.jobs, j => j.id === this.props.job.id) || defaultJob;
83
+ if (!job) {
84
+ this.getJob();
85
+ return;
86
+ }
54
87
  const newState = { job, status: job.status };
55
88
  if (job.expectedDate) {
56
89
  newState.expectedDate = moment(job.expectedDate);
@@ -74,9 +107,10 @@ class RequestDetail extends Component {
74
107
  this.setState({ loading: true }, async () => {
75
108
  try {
76
109
  const updated = { id: job.id, seen: true, status: job.status || 'Unassigned' };
77
- const res = await generalActions.editJob(updated, user.site);
110
+ const res = await maintenanceActions.editJob(updated, user.site);
78
111
  // console.log('markSeen updated');
79
112
  this.props.jobAdded(res.data.job);
113
+ this.getJob();
80
114
  this.setState({ loading: false, seen: true });
81
115
  } catch (error) {
82
116
  console.log('markSeen error', error);
@@ -96,8 +130,9 @@ class RequestDetail extends Component {
96
130
  .utc()
97
131
  .toISOString();
98
132
  }
99
- const res = await generalActions.editJob(updated, user.site);
133
+ const res = await maintenanceActions.editJob(updated, user.site);
100
134
  this.props.jobAdded(res.data.job);
135
+ this.getJob();
101
136
  } catch (error) {
102
137
  console.log('updateJob error', error);
103
138
  } finally {
@@ -109,8 +144,9 @@ class RequestDetail extends Component {
109
144
  updateJobStatus = () => {
110
145
  this.setState({ loading: true }, async () => {
111
146
  try {
112
- const res = await generalActions.editJobStatus(this.props.job.id, this.state.status);
147
+ const res = await maintenanceActions.editJobStatus(this.props.job.id, this.state.status);
113
148
  this.props.jobAdded(res.data.job);
149
+ this.getJob();
114
150
  } catch (error) {
115
151
  console.log('updateJobStatus error', error);
116
152
  } finally {
@@ -138,7 +174,7 @@ class RequestDetail extends Component {
138
174
  };
139
175
 
140
176
  openStaffNotes = () => {
141
- Services.navigation.navigate(values.screenRequestNotes, { job: this.state.job });
177
+ Services.navigation.navigate(values.screenRequestNotes, { job: this.state.job, onChange: this.getJob });
142
178
  };
143
179
 
144
180
  onOpenDatePicker = () => {
@@ -182,9 +218,10 @@ class RequestDetail extends Component {
182
218
  onCommentAdded = () => {
183
219
  this.setState({ loading: true }, async () => {
184
220
  try {
185
- const job = await generalActions.getJob(this.props.user.site, this.props.job.id);
221
+ const job = await maintenanceActions.getJob(this.props.user.site, this.props.job.id);
186
222
  // console.log('onCommentAdded', job?.data);
187
223
  this.props.jobAdded(job.data);
224
+ this.getJob();
188
225
  } catch (error) {
189
226
  console.log('onCommentAdded error', error);
190
227
  } finally {
@@ -194,8 +231,15 @@ class RequestDetail extends Component {
194
231
  };
195
232
 
196
233
  hasPermission = () => {
234
+ const { job } = this.state;
197
235
  const { permissions } = this.props.user;
198
- return _.includes(permissions, values.permissionMaintenanceTracking);
236
+ if (_.includes(permissions, values.permissionMaintenanceTracking)) {
237
+ return true;
238
+ }
239
+ if (_.includes(permissions, values.permissionMaintenanceAssignment)) {
240
+ return job.AssigneeId === this.props.user.Id;
241
+ }
242
+ return false;
199
243
  };
200
244
 
201
245
  toggleFullscreenVideo = url => {
@@ -203,9 +247,10 @@ class RequestDetail extends Component {
203
247
  this.setState({ showFullscreenVideo: url.length > 0, currentVideoUrl: url });
204
248
  };
205
249
 
206
- openGallery(index) {
250
+ openGallery(galleryImages, index) {
207
251
  this.setState({
208
252
  galleryOpen: true,
253
+ galleryImages,
209
254
  });
210
255
  this.refs.imagePopup.scrollTo(index);
211
256
  }
@@ -216,6 +261,33 @@ class RequestDetail extends Component {
216
261
  });
217
262
  }
218
263
 
264
+ onOpenAssigneePicker = () => {
265
+ const options = this.state.assignees.map(a => {
266
+ return { key: a.id, name: a.displayName };
267
+ });
268
+ Services.navigation.navigate('optionSelector', {
269
+ options,
270
+ selection: this.state.job.AssigneeId,
271
+ title: 'Assign request',
272
+ onSelect: this.onSelectAssignee,
273
+ });
274
+ };
275
+
276
+ onSelectAssignee = assignee => {
277
+ this.setState({ loading: true }, async () => {
278
+ try {
279
+ console.log('onSelectAssignee', this.props.job.id, assignee.key);
280
+ const res = await maintenanceActions.assignJob(this.props.job.id, assignee.key);
281
+ this.props.jobAdded(res.data.job);
282
+ this.getJob();
283
+ } catch (error) {
284
+ console.log('onSelectAssignee error', error);
285
+ } finally {
286
+ this.setState({ loading: false });
287
+ }
288
+ });
289
+ };
290
+
219
291
  renderLoading() {
220
292
  return <Components.LoadingIndicator visible={this.state.loading} />;
221
293
  }
@@ -229,10 +301,15 @@ class RequestDetail extends Component {
229
301
  return (
230
302
  <View style={{ ...Helper.getShadowStyle() }}>
231
303
  <View style={styles.jobTitleContainer}>
304
+ {job.jobId ? (
305
+ <Text style={[styles.jobIdText, { color: this.props.colourBrandingMain }]}>{`${values.textEntityName} #${job.jobId}`}</Text>
306
+ ) : null}
232
307
  <Text style={styles.jobTitleText}>{job.title}</Text>
233
308
  <View style={styles.jobTypeSeenContainer}>
234
309
  <View style={[styles.jobTypeContainer, { backgroundColor: Colours.hexToRGBAstring(this.props.colourBrandingMain, 0.2) }]}>
235
- <Text style={[styles.jobTypeText, { color: this.props.colourBrandingMain }]}>{job.type}</Text>
310
+ <Text style={[styles.jobTypeText, { color: this.props.colourBrandingMain }]} numberOfLines={2}>
311
+ {job.type}
312
+ </Text>
236
313
  </View>
237
314
  {showSeen && this.state.seen && (
238
315
  <View style={styles.jobSeenContainer}>
@@ -250,7 +327,7 @@ class RequestDetail extends Component {
250
327
  </View>
251
328
  </View>
252
329
  )}
253
- <View style={styles.textSectionInner}>
330
+ {/* <View style={styles.textSectionInner}>
254
331
  <Text style={styles.textSectionLabel}>Expected Date</Text>
255
332
  <TouchableOpacity onPress={this.onOpenDatePicker}>
256
333
  <View style={styles.textSectionTextContainer}>
@@ -262,14 +339,13 @@ class RequestDetail extends Component {
262
339
  />
263
340
  </View>
264
341
  </TouchableOpacity>
265
- </View>
342
+ </View> */}
266
343
  </View>
267
344
  <View style={styles.jobStatusExpectedContainer}>
268
345
  <View style={styles.jobStatusOuterContainer}>
269
346
  <Text style={styles.jobStatusHeading}>STATUS</Text>
270
347
  <TouchableOpacity onPress={canEdit ? this.onOpenStatusPicker : null}>
271
348
  <View style={[styles.jobStatusContainer, { backgroundColor: statusColor }]}>
272
- <Icon name="wrench" type="font-awesome" iconStyle={styles.jobStatusIcon} />
273
349
  <Text style={styles.jobStatusText}>{statusText}</Text>
274
350
  </View>
275
351
  </TouchableOpacity>
@@ -290,7 +366,8 @@ class RequestDetail extends Component {
290
366
  );
291
367
  }
292
368
 
293
- renderPlayableImageUrl(url, index, containerStyle, showMore) {
369
+ renderPlayableImageUrl(images, index, containerStyle, showMore) {
370
+ const url = images[index || 0];
294
371
  const thumbUrl = Helper.getThumb300(url);
295
372
 
296
373
  if (Helper.isVideo(url)) {
@@ -307,7 +384,7 @@ class RequestDetail extends Component {
307
384
 
308
385
  const imageUrl = Helper.get1400(url);
309
386
  return (
310
- <TouchableOpacity style={containerStyle} onPress={this.openGallery.bind(this, index || 0)}>
387
+ <TouchableOpacity style={containerStyle} onPress={this.openGallery.bind(this, images, index || 0)}>
311
388
  <ImageBackground style={styles.imageContainer} source={{ uri: imageUrl }}>
312
389
  {showMore && <Text style={styles.plusImages}>+{this.state.job.images.length - 2}</Text>}
313
390
  </ImageBackground>
@@ -315,26 +392,24 @@ class RequestDetail extends Component {
315
392
  );
316
393
  }
317
394
 
318
- renderPlayableImage(index, containerStyle, showMore) {
319
- const url = this.state.job.images[index];
320
- return this.renderPlayableImageUrl(url, index, containerStyle, showMore);
395
+ renderPlayableImage(images, index, containerStyle, showMore) {
396
+ return this.renderPlayableImageUrl(images, index, containerStyle, showMore);
321
397
  }
322
398
 
323
- renderImage() {
324
- const { job } = this.state;
325
- if (!_.isNil(job.images) && !_.isEmpty(job.images)) {
326
- if (job.images.length >= 2) {
399
+ renderImage(images, image = null) {
400
+ if (!_.isNil(images) && !_.isEmpty(images)) {
401
+ if (images.length >= 2) {
327
402
  return (
328
403
  <View style={styles.sideBySideImages}>
329
- {this.renderPlayableImage(0, styles.sideBySideImageContainer)}
330
- {this.renderPlayableImage(1, styles.sideBySideImageContainer, job.images.length > 2)}
404
+ {this.renderPlayableImage(images, 0, styles.sideBySideImageContainer)}
405
+ {this.renderPlayableImage(images, 1, styles.sideBySideImageContainer, images.length > 2)}
331
406
  </View>
332
407
  );
333
408
  } else {
334
- return <View style={styles.singleImageContainer}>{this.renderPlayableImage(0)}</View>;
409
+ return <View style={styles.singleImageContainer}>{this.renderPlayableImage(images, 0)}</View>;
335
410
  }
336
- } else if (!_.isNil(job.image)) {
337
- return <View style={styles.singleImageContainer}>{this.renderPlayableImageUrl(job.image)}</View>;
411
+ } else if (!_.isNil(image)) {
412
+ return <View style={styles.singleImageContainer}>{this.renderPlayableImageUrl([image], 0)}</View>;
338
413
  }
339
414
  return null;
340
415
  }
@@ -343,15 +418,86 @@ class RequestDetail extends Component {
343
418
  return (
344
419
  <Components.ImagePopup
345
420
  visible={this.state.galleryOpen}
346
- images={this.state.job.images || [this.state.job.image]}
421
+ images={this.state.galleryImages}
347
422
  onClose={this.closeGallery.bind(this)}
348
423
  ref="imagePopup"
349
424
  />
350
425
  );
351
426
  }
352
427
 
428
+ renderAssignee() {
429
+ const { job } = this.state;
430
+ if (!this.hasPermission() && !job.Assignee) return null;
431
+
432
+ const content = (
433
+ <View>
434
+ <Text style={styles.locationLabel}>Assigned To</Text>
435
+ <View>
436
+ {job.Assignee && (
437
+ <View style={styles.profileContainer}>
438
+ <Components.ProfilePic ProfilePic={job.Assignee.profilePic} Diameter={40} />
439
+ <View style={styles.nameContainer}>
440
+ <Text style={styles.nameText}>{job.Assignee.displayName}</Text>
441
+ </View>
442
+ </View>
443
+ )}
444
+ </View>
445
+ </View>
446
+ );
447
+
448
+ if (this.hasPermission()) {
449
+ return (
450
+ <Components.FormCardSectionOptionLauncher
451
+ onPress={this.onOpenAssigneePicker}
452
+ title="Assigned To"
453
+ value={job.Assignee ? job.Assignee.displayName : 'Unassigned'}
454
+ textStyle={styles.detailsText}
455
+ sectionStyle={styles.detailsSection}
456
+ >
457
+ {content}
458
+ </Components.FormCardSectionOptionLauncher>
459
+ );
460
+ }
461
+ return content;
462
+ }
463
+
464
+ renderCustomFields() {
465
+ const { job } = this.state;
466
+ const { customFields } = job;
467
+
468
+ const renderAnswer = field => {
469
+ switch (field.type) {
470
+ case 'date':
471
+ return <Text style={styles.customText}>{field.answer ? moment(field.answer, 'YYYY-MM-DD').format('DD MMM YYYY') : ''}</Text>;
472
+ case 'time':
473
+ return <Text style={styles.customText}>{field.answer ? moment(field.answer, 'HH:mm').format('h:mm a') : ''}</Text>;
474
+ case 'yn':
475
+ return <Text style={styles.customText}>{field.answer ? 'Yes' : 'No'}</Text>;
476
+ case 'checkbox':
477
+ return <Text style={styles.customText}>{field.answer && Array.isArray(field.answer) ? field.answer.join(', ') : ''}</Text>;
478
+ case 'image':
479
+ return <View style={{ marginTop: 8 }}>{this.renderImage(field.answer)}</View>;
480
+ default:
481
+ return <Text style={styles.customText}>{field.answer}</Text>;
482
+ }
483
+ };
484
+
485
+ return customFields.map((field, index) => {
486
+ if (['staticTitle', 'staticText'].includes(field.type)) return null;
487
+ if (_.isNil(field.answer) || field.answer === '' || (Array.isArray(field.answer) && field.answer.length === 0)) return null;
488
+ return (
489
+ <View key={index}>
490
+ <Text style={styles.customLabel}>{field.label}</Text>
491
+ {renderAnswer(field)}
492
+ </View>
493
+ );
494
+ });
495
+ }
496
+
353
497
  rendeDetails() {
354
498
  const { job } = this.state;
499
+ const { customFields } = job;
500
+ const hasCustomFields = customFields && customFields.length > 0;
355
501
 
356
502
  return (
357
503
  <View>
@@ -364,21 +510,26 @@ class RequestDetail extends Component {
364
510
  />
365
511
  {this.state.showMore && (
366
512
  <View>
367
- {this.renderImage()}
368
- {!_.isEmpty(job.description) && (
369
- <Text numberOfLines={10} style={styles.jobDescriptionText}>
370
- {job.description}
371
- </Text>
372
- )}
373
- <Text style={styles.locationLabel}>Location</Text>
513
+ {hasCustomFields ? this.renderCustomFields() : null}
514
+ {!hasCustomFields ? (
515
+ <>
516
+ {this.renderImage(job.images, job.image)}
517
+ {!_.isEmpty(job.description) && (
518
+ <Text numberOfLines={10} style={styles.jobDescriptionText}>
519
+ {job.description}
520
+ </Text>
521
+ )}
522
+ </>
523
+ ) : null}
524
+ <Text style={styles.locationLabel}>Address</Text>
374
525
  <Text style={styles.locationText}>{job.room}</Text>
375
- {job.isHome ? (
526
+ {!hasCustomFields && job.isHome ? (
376
527
  <View style={styles.detailsSection}>
377
528
  <Text style={styles.locationLabel}>Must be home</Text>
378
529
  <Text style={styles.locationText}>{job.homeText}</Text>
379
530
  </View>
380
531
  ) : null}
381
- <Text style={styles.requesterLabel}>Person Requesting</Text>
532
+ <Text style={styles.requesterLabel}>Submitted By</Text>
382
533
  <View style={styles.profileContainer}>
383
534
  <Components.ProfilePic ProfilePic={job.userProfilePic} Diameter={40} />
384
535
  <View style={styles.nameContainer}>
@@ -400,7 +551,7 @@ class RequestDetail extends Component {
400
551
  commentReply={this.commentReply}
401
552
  scrollView={this.scrollView}
402
553
  adminPermission={values.permissionMaintenanceTracking}
403
- entityType={values.featureKey}
554
+ entityType={values.commentKey}
404
555
  entityId={this.props.job.id}
405
556
  entityName={this.props.job.title}
406
557
  site={this.state.job.site || this.state.job.location}
@@ -437,12 +588,12 @@ class RequestDetail extends Component {
437
588
  ref={this.commentReply}
438
589
  commentSection={this.commentSection}
439
590
  scrollView={this.scrollView}
440
- entityType={values.featureKey}
591
+ entityType={values.commentKey}
441
592
  entityId={this.props.job.id}
442
593
  entityName={this.props.job.title}
443
594
  site={this.state.job.site || this.state.job.location}
444
- // noScroll={true}
445
- // style={{ position: 'absolute', bottom: 0, left: 0, right: 0 }}
595
+ // noScroll={true}
596
+ // style={{ position: 'absolute', bottom: 0, left: 0, right: 0 }}
446
597
  />
447
598
  );
448
599
  }
@@ -453,6 +604,9 @@ class RequestDetail extends Component {
453
604
  }
454
605
 
455
606
  render() {
607
+ if (this.state.forbidden) {
608
+ return <Components.Forbidden />;
609
+ }
456
610
  return (
457
611
  <KeyboardAvoidingView behavior={Platform.OS === 'ios' && 'padding'} style={styles.container}>
458
612
  <Components.Header leftIcon="angle-left" onPressLeft={this.onPressBack} text={Config.env.strings.MAINTENANCE_REQUEST_DETAILS} />
@@ -460,6 +614,7 @@ class RequestDetail extends Component {
460
614
  <ScrollView ref={this.scrollView} contentContainerStyle={{ paddingBottom: 26 }} style={{ height: '100%' }}>
461
615
  <View style={styles.innerContainer}>
462
616
  {this.renderTop()}
617
+ {this.renderAssignee()}
463
618
  {this.rendeDetails()}
464
619
  {this.renderMessages()}
465
620
  </View>
@@ -492,6 +647,11 @@ const styles = StyleSheet.create({
492
647
  paddingVertical: 14,
493
648
  paddingHorizontal: 12,
494
649
  },
650
+ jobIdText: {
651
+ fontFamily: 'sf-medium',
652
+ fontSize: 12,
653
+ marginBottom: 4,
654
+ },
495
655
  jobTitleText: {
496
656
  fontFamily: 'sf-semibold',
497
657
  fontSize: 20,
@@ -503,8 +663,9 @@ const styles = StyleSheet.create({
503
663
  alignItems: 'center',
504
664
  },
505
665
  jobTypeContainer: {
506
- height: 20,
507
- width: 80,
666
+ padding: 4,
667
+ minWidth: 80,
668
+ maxWidth: 140,
508
669
  borderRadius: 4,
509
670
  justifyContent: 'center',
510
671
  },
@@ -512,6 +673,7 @@ const styles = StyleSheet.create({
512
673
  fontFamily: 'sf-semibold',
513
674
  fontSize: 12,
514
675
  textAlign: 'center',
676
+ maxWidth: '100%',
515
677
  },
516
678
  jobSeenContainer: {
517
679
  flexDirection: 'row',
@@ -715,6 +877,30 @@ const styles = StyleSheet.create({
715
877
  marginLeft: 10,
716
878
  lineHeight: 24,
717
879
  },
880
+ customLabel: {
881
+ fontFamily: 'sf-bold',
882
+ fontSize: 14,
883
+ color: Colours.TEXT_DARKEST,
884
+ },
885
+ customText: {
886
+ fontFamily: 'sf-regular',
887
+ fontSize: 16,
888
+ color: Colours.TEXT_DARKEST,
889
+ paddingVertical: 8,
890
+ },
891
+ customStaticTitle: {
892
+ fontSize: 20,
893
+ fontFamily: 'sf-semibold',
894
+ color: Colours.TEXT_DARKEST,
895
+ marginBottom: 10,
896
+ },
897
+ customStaticText: {
898
+ fontSize: 17,
899
+ fontFamily: 'sf-regular',
900
+ color: Colours.TEXT_DARKEST,
901
+ lineHeight: 24,
902
+ marginBottom: 10,
903
+ },
718
904
  });
719
905
 
720
906
  const mapStateToProps = state => {
@@ -1,11 +1,11 @@
1
1
  import React, { Component } from 'react';
2
- import { ScrollView, View, Text, TouchableOpacity, Modal, KeyboardAvoidingView } from 'react-native';
2
+ import { ScrollView, View, Text, TouchableOpacity, Modal, KeyboardAvoidingView, Platform } from 'react-native';
3
3
  import { connect } from 'react-redux';
4
- import { Icon } from 'react-native-elements';
4
+ import { Icon } from '@rneui/themed';
5
5
  import _ from 'lodash';
6
6
  import moment from 'moment';
7
7
  import { jobAdded } from '../actions';
8
- import { generalActions } from '../apis';
8
+ import { maintenanceActions } from '../apis';
9
9
  import { getBottomSpace } from 'react-native-iphone-x-helper';
10
10
  import { Services } from '../feature.config';
11
11
  import { Components, Colours, Helper } from '../core.config';
@@ -62,13 +62,14 @@ class RequestNotes extends Component {
62
62
  };
63
63
 
64
64
  onPressConfirmDelete = () => {
65
- generalActions.deleteNote(this.props.job.id, this.state.noteToDelete.Id);
65
+ maintenanceActions.deleteNote(this.props.job.id, this.state.noteToDelete.Id);
66
66
  const newNotes = _.filter(this.state.job.Notes, note => {
67
67
  return note.Id !== this.state.noteToDelete.Id;
68
68
  });
69
69
  const newJob = { ...this.props.job };
70
70
  newJob.Notes = newNotes;
71
71
  this.props.jobAdded(newJob);
72
+ this.props.onChange && this.props.onChange();
72
73
  this.setState({
73
74
  job: newJob,
74
75
  noteToDelete: null,
@@ -127,27 +128,27 @@ class RequestNotes extends Component {
127
128
  try {
128
129
  this.setState({ submittingNote: true });
129
130
  const res = await (this.state.editingNote
130
- ? generalActions.editNote(
131
- this.props.job.id,
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
- ));
131
+ ? maintenanceActions.editNote(
132
+ this.props.job.id,
133
+ this.state.editingNote,
134
+ this.state.noteInput,
135
+ this.state.noteAttachments.map(a => {
136
+ return {
137
+ Title: a.Title,
138
+ Source: a.Source,
139
+ };
140
+ }),
141
+ )
142
+ : maintenanceActions.addNote(
143
+ this.props.job.id,
144
+ this.state.noteInput,
145
+ this.state.noteAttachments.map(a => {
146
+ return {
147
+ Title: a.Title,
148
+ Source: a.Source,
149
+ };
150
+ }),
151
+ ));
151
152
  this.setState(
152
153
  {
153
154
  job: res.data.job,
@@ -159,6 +160,7 @@ class RequestNotes extends Component {
159
160
  },
160
161
  () => {
161
162
  this.props.jobAdded(res.data.job);
163
+ this.props.onChange && this.props.onChange();
162
164
  },
163
165
  );
164
166
  } catch (err) {