@plusscommunities/pluss-maintenance-app 6.1.1-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.
- package/dist/module/apis/index.js +1 -1
- package/dist/module/apis/index.js.map +1 -1
- package/dist/module/apis/{generalActions.js → maintenanceActions.js} +25 -41
- package/dist/module/apis/maintenanceActions.js.map +1 -0
- package/dist/module/components/FilterPopupMenu.js +48 -12
- package/dist/module/components/FilterPopupMenu.js.map +1 -1
- package/dist/module/components/MaintenanceList.js +52 -18
- package/dist/module/components/MaintenanceList.js.map +1 -1
- package/dist/module/components/MaintenanceListItem.js +16 -17
- package/dist/module/components/MaintenanceListItem.js.map +1 -1
- package/dist/module/components/MaintenanceWidgetItem.js +4 -8
- package/dist/module/components/MaintenanceWidgetItem.js.map +1 -1
- package/dist/module/components/StatusSelectorPopup.js +2 -1
- package/dist/module/components/StatusSelectorPopup.js.map +1 -1
- package/dist/module/components/WidgetSmall.js +7 -7
- 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 +10 -2
- package/dist/module/helper.js.map +1 -1
- package/dist/module/reducers/JobsReducer.js +2 -1
- 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 +252 -72
- package/dist/module/screens/RequestDetail.js.map +1 -1
- package/dist/module/screens/RequestNotes.js +10 -8
- 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 +4 -1
- package/dist/module/values.config.a.js.map +1 -1
- package/dist/module/values.config.default.js +10 -1
- package/dist/module/values.config.default.js.map +1 -1
- package/dist/module/values.config.forms.js +37 -0
- package/dist/module/values.config.forms.js.map +1 -0
- package/dist/module/values.config.js +10 -1
- package/dist/module/values.config.js.map +1 -1
- package/package.json +12 -12
- package/src/apis/index.js +1 -1
- package/src/apis/{generalActions.js → maintenanceActions.js} +35 -39
- package/src/components/FilterPopupMenu.js +39 -7
- package/src/components/MaintenanceList.js +59 -19
- package/src/components/MaintenanceListItem.js +18 -10
- package/src/components/MaintenanceWidgetItem.js +2 -2
- package/src/components/StatusSelectorPopup.js +2 -1
- package/src/components/WidgetSmall.js +5 -5
- package/src/feature.config.js +15 -13
- package/src/helper.js +11 -2
- package/src/reducers/JobsReducer.js +2 -1
- package/src/screens/JobTypePicker.js +1 -1
- package/src/screens/RequestDetail.js +237 -51
- package/src/screens/RequestNotes.js +27 -25
- package/src/screens/ServiceRequest.js +642 -157
- package/src/values.config.a.js +3 -0
- package/src/values.config.default.js +9 -0
- package/src/values.config.forms.js +37 -0
- package/src/values.config.js +9 -0
- 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
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
|
2
2
|
import _ from 'lodash';
|
3
3
|
import { TouchableOpacity, View, ScrollView, Text } from 'react-native';
|
4
4
|
import { connect } from 'react-redux';
|
5
|
-
import { Icon } from '
|
5
|
+
import { Icon } from '@rneui/themed';
|
6
6
|
import { Services } from '../feature.config';
|
7
7
|
import { Components, Colours } from '../core.config';
|
8
8
|
|
@@ -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 '
|
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 {
|
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:
|
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.
|
45
|
+
this.getJob();
|
46
|
+
this.updateJobState(this.props.job);
|
47
|
+
this.getAssignees();
|
44
48
|
}
|
45
49
|
|
46
|
-
|
47
|
-
|
48
|
-
|
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) ||
|
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
|
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
|
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
|
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
|
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
|
-
|
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 }]}
|
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(
|
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
|
-
|
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
|
-
|
325
|
-
|
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,
|
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(
|
337
|
-
return <View style={styles.singleImageContainer}>{this.renderPlayableImageUrl(
|
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.
|
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.
|
368
|
-
{!
|
369
|
-
|
370
|
-
{job.
|
371
|
-
|
372
|
-
|
373
|
-
|
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}>
|
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.
|
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.
|
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
|
-
|
445
|
-
|
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
|
-
|
507
|
-
|
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 '
|
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 {
|
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
|
-
|
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
|
-
?
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
:
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
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) {
|