@plusscommunities/pluss-maintenance-app 6.1.2-beta.0 → 7.0.0-auth.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/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 +15 -1
- package/dist/module/values.config.js.map +1 -1
- package/package.json +16 -12
- 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 +14 -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
@@ -1,14 +1,15 @@
|
|
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 {
|
9
|
-
import { jobAdded } from '../actions';
|
8
|
+
import { maintenanceActions } from '../apis';
|
9
|
+
import { jobAdded, jobStatusesUpdate, jobHideSeenUpdate } from '../actions';
|
10
10
|
import StatusSelectorPopup from '../components/StatusSelectorPopup';
|
11
|
-
import
|
11
|
+
import PrioritySelectorPopup from '../components/PrioritySelectorPopup';
|
12
|
+
import { getJobStatus, getJobPriority } from '../helper';
|
12
13
|
import { Services } from '../feature.config';
|
13
14
|
import { Colours, Helper, Components, Config } from '../core.config';
|
14
15
|
import { values } from '../values.config';
|
@@ -22,16 +23,20 @@ class RequestDetail extends Component {
|
|
22
23
|
isDateTimePickerVisible: false,
|
23
24
|
popUpType: '',
|
24
25
|
status: '',
|
26
|
+
priority: '',
|
25
27
|
expectedDate: null,
|
26
28
|
expectedDateText: '',
|
27
29
|
seen: false,
|
28
|
-
showMore:
|
30
|
+
showMore: true,
|
29
31
|
showStatusPopup: false,
|
32
|
+
showPriorityPopup: false,
|
30
33
|
loading: false,
|
31
34
|
showFullscreenVideo: false,
|
32
35
|
currentVideoUrl: '',
|
33
36
|
galleryOpen: false,
|
37
|
+
galleryImages: [],
|
34
38
|
showMessages: false,
|
39
|
+
assignees: [],
|
35
40
|
};
|
36
41
|
|
37
42
|
this.scrollView = React.createRef();
|
@@ -40,17 +45,51 @@ class RequestDetail extends Component {
|
|
40
45
|
}
|
41
46
|
|
42
47
|
componentDidMount() {
|
43
|
-
this.
|
48
|
+
this.props.jobStatusesUpdate(this.props.job.site);
|
49
|
+
this.props.jobHideSeenUpdate(this.props.job.site);
|
50
|
+
this.getJob();
|
51
|
+
this.updateJobState(this.props.job);
|
52
|
+
this.getAssignees();
|
44
53
|
}
|
45
54
|
|
46
|
-
|
47
|
-
|
48
|
-
|
55
|
+
getJob = async () => {
|
56
|
+
this.setState({ loading: true }, async () => {
|
57
|
+
try {
|
58
|
+
const res = await maintenanceActions.getJob(this.props.job.site, this.props.job.id);
|
59
|
+
// console.log('getJob', JSON.stringify(res.data, null, 2));
|
60
|
+
this.props.jobAdded(res.data);
|
61
|
+
this.updateJobState(res.data);
|
62
|
+
} catch (error) {
|
63
|
+
console.log('getJob error', error.toString());
|
64
|
+
// check for 403 or 404 error
|
65
|
+
if (error.response.status === 403 || error.response.status === 404) {
|
66
|
+
this.setState({
|
67
|
+
forbidden: true,
|
68
|
+
});
|
69
|
+
}
|
70
|
+
console.log('getJob error', error);
|
71
|
+
} finally {
|
72
|
+
this.setState({ loading: false });
|
73
|
+
}
|
74
|
+
});
|
75
|
+
};
|
76
|
+
|
77
|
+
getAssignees = async () => {
|
78
|
+
if (!this.hasPermission()) return;
|
79
|
+
try {
|
80
|
+
const res = await maintenanceActions.getAssignees(this.props.user.site);
|
81
|
+
this.setState({ assignees: res.data.Users });
|
82
|
+
} catch (error) {
|
83
|
+
console.log('getAssignees error', error);
|
49
84
|
}
|
50
|
-
}
|
85
|
+
};
|
51
86
|
|
52
|
-
updateJobState() {
|
53
|
-
const job = _.find(this.props.jobs, j => j.id === this.props.job.id) ||
|
87
|
+
updateJobState(defaultJob) {
|
88
|
+
const job = _.find(this.props.jobs, j => j.id === this.props.job.id) || defaultJob;
|
89
|
+
if (!job) {
|
90
|
+
this.getJob();
|
91
|
+
return;
|
92
|
+
}
|
54
93
|
const newState = { job, status: job.status };
|
55
94
|
if (job.expectedDate) {
|
56
95
|
newState.expectedDate = moment(job.expectedDate);
|
@@ -74,9 +113,10 @@ class RequestDetail extends Component {
|
|
74
113
|
this.setState({ loading: true }, async () => {
|
75
114
|
try {
|
76
115
|
const updated = { id: job.id, seen: true, status: job.status || 'Unassigned' };
|
77
|
-
const res = await
|
116
|
+
const res = await maintenanceActions.editJob(updated, user.site);
|
78
117
|
// console.log('markSeen updated');
|
79
118
|
this.props.jobAdded(res.data.job);
|
119
|
+
this.getJob();
|
80
120
|
this.setState({ loading: false, seen: true });
|
81
121
|
} catch (error) {
|
82
122
|
console.log('markSeen error', error);
|
@@ -96,8 +136,9 @@ class RequestDetail extends Component {
|
|
96
136
|
.utc()
|
97
137
|
.toISOString();
|
98
138
|
}
|
99
|
-
const res = await
|
139
|
+
const res = await maintenanceActions.editJob(updated, user.site);
|
100
140
|
this.props.jobAdded(res.data.job);
|
141
|
+
this.getJob();
|
101
142
|
} catch (error) {
|
102
143
|
console.log('updateJob error', error);
|
103
144
|
} finally {
|
@@ -109,8 +150,9 @@ class RequestDetail extends Component {
|
|
109
150
|
updateJobStatus = () => {
|
110
151
|
this.setState({ loading: true }, async () => {
|
111
152
|
try {
|
112
|
-
const res = await
|
153
|
+
const res = await maintenanceActions.editJobStatus(this.props.job.id, this.state.status);
|
113
154
|
this.props.jobAdded(res.data.job);
|
155
|
+
this.getJob();
|
114
156
|
} catch (error) {
|
115
157
|
console.log('updateJobStatus error', error);
|
116
158
|
} finally {
|
@@ -119,6 +161,20 @@ class RequestDetail extends Component {
|
|
119
161
|
});
|
120
162
|
};
|
121
163
|
|
164
|
+
updateJobPriority = () => {
|
165
|
+
this.setState({ loading: true }, async () => {
|
166
|
+
try {
|
167
|
+
const res = await maintenanceActions.editJobPriority(this.props.job.id, this.state.priority);
|
168
|
+
this.props.jobAdded(res.data.job);
|
169
|
+
this.getJob();
|
170
|
+
} catch (error) {
|
171
|
+
console.log('updateJobPriority error', error);
|
172
|
+
} finally {
|
173
|
+
this.setState({ loading: false });
|
174
|
+
}
|
175
|
+
});
|
176
|
+
};
|
177
|
+
|
122
178
|
onPressBack = () => {
|
123
179
|
Services.navigation.goBack();
|
124
180
|
};
|
@@ -132,13 +188,29 @@ class RequestDetail extends Component {
|
|
132
188
|
};
|
133
189
|
|
134
190
|
onSelectStatus = status => {
|
191
|
+
if (this.state.loading) return;
|
135
192
|
this.setState({ status, showStatusPopup: false }, () => {
|
136
193
|
this.updateJobStatus();
|
137
194
|
});
|
138
195
|
};
|
139
196
|
|
197
|
+
onOpenPriorityPicker = () => {
|
198
|
+
this.setState({ showPriorityPopup: true });
|
199
|
+
};
|
200
|
+
|
201
|
+
onClosePriorityPopup = () => {
|
202
|
+
this.setState({ showPriorityPopup: false });
|
203
|
+
};
|
204
|
+
|
205
|
+
onSelectPriority = priority => {
|
206
|
+
if (this.state.loading) return;
|
207
|
+
this.setState({ priority, showPriorityPopup: false }, () => {
|
208
|
+
this.updateJobPriority();
|
209
|
+
});
|
210
|
+
};
|
211
|
+
|
140
212
|
openStaffNotes = () => {
|
141
|
-
Services.navigation.navigate(values.screenRequestNotes, { job: this.state.job });
|
213
|
+
Services.navigation.navigate(values.screenRequestNotes, { job: this.state.job, onChange: this.getJob });
|
142
214
|
};
|
143
215
|
|
144
216
|
onOpenDatePicker = () => {
|
@@ -182,9 +254,10 @@ class RequestDetail extends Component {
|
|
182
254
|
onCommentAdded = () => {
|
183
255
|
this.setState({ loading: true }, async () => {
|
184
256
|
try {
|
185
|
-
const job = await
|
257
|
+
const job = await maintenanceActions.getJob(this.props.user.site, this.props.job.id);
|
186
258
|
// console.log('onCommentAdded', job?.data);
|
187
259
|
this.props.jobAdded(job.data);
|
260
|
+
this.getJob();
|
188
261
|
} catch (error) {
|
189
262
|
console.log('onCommentAdded error', error);
|
190
263
|
} finally {
|
@@ -194,8 +267,15 @@ class RequestDetail extends Component {
|
|
194
267
|
};
|
195
268
|
|
196
269
|
hasPermission = () => {
|
270
|
+
const { job } = this.state;
|
197
271
|
const { permissions } = this.props.user;
|
198
|
-
|
272
|
+
if (_.includes(permissions, values.permissionMaintenanceTracking)) {
|
273
|
+
return true;
|
274
|
+
}
|
275
|
+
if (_.includes(permissions, values.permissionMaintenanceAssignment)) {
|
276
|
+
return job.AssigneeId === this.props.user.Id;
|
277
|
+
}
|
278
|
+
return false;
|
199
279
|
};
|
200
280
|
|
201
281
|
toggleFullscreenVideo = url => {
|
@@ -203,9 +283,10 @@ class RequestDetail extends Component {
|
|
203
283
|
this.setState({ showFullscreenVideo: url.length > 0, currentVideoUrl: url });
|
204
284
|
};
|
205
285
|
|
206
|
-
openGallery(index) {
|
286
|
+
openGallery(galleryImages, index) {
|
207
287
|
this.setState({
|
208
288
|
galleryOpen: true,
|
289
|
+
galleryImages,
|
209
290
|
});
|
210
291
|
this.refs.imagePopup.scrollTo(index);
|
211
292
|
}
|
@@ -216,25 +297,59 @@ class RequestDetail extends Component {
|
|
216
297
|
});
|
217
298
|
}
|
218
299
|
|
300
|
+
onOpenAssigneePicker = () => {
|
301
|
+
const options = this.state.assignees.map(a => {
|
302
|
+
return { key: a.id, name: a.displayName };
|
303
|
+
});
|
304
|
+
Services.navigation.navigate('optionSelector', {
|
305
|
+
options,
|
306
|
+
selection: this.state.job.AssigneeId,
|
307
|
+
title: 'Assign request',
|
308
|
+
onSelect: this.onSelectAssignee,
|
309
|
+
});
|
310
|
+
};
|
311
|
+
|
312
|
+
onSelectAssignee = assignee => {
|
313
|
+
this.setState({ loading: true }, async () => {
|
314
|
+
try {
|
315
|
+
console.log('onSelectAssignee', this.props.job.id, assignee.key);
|
316
|
+
const res = await maintenanceActions.assignJob(this.props.job.id, assignee.key);
|
317
|
+
this.props.jobAdded(res.data.job);
|
318
|
+
this.getJob();
|
319
|
+
} catch (error) {
|
320
|
+
console.log('onSelectAssignee error', error);
|
321
|
+
} finally {
|
322
|
+
this.setState({ loading: false });
|
323
|
+
}
|
324
|
+
});
|
325
|
+
};
|
326
|
+
|
219
327
|
renderLoading() {
|
220
328
|
return <Components.LoadingIndicator visible={this.state.loading} />;
|
221
329
|
}
|
222
330
|
|
223
331
|
renderTop() {
|
224
332
|
const { status, job } = this.state;
|
225
|
-
const
|
333
|
+
const statusOption = getJobStatus(status, this.props);
|
334
|
+
const priority = getJobPriority(job.priority);
|
226
335
|
const canEdit = this.hasPermission();
|
227
|
-
const
|
336
|
+
const isStaff = this.props.user.category === 'staff'
|
337
|
+
const showSeen = !status || status === getJobStatus(null, this.props).text;
|
228
338
|
|
229
339
|
return (
|
230
340
|
<View style={{ ...Helper.getShadowStyle() }}>
|
231
341
|
<View style={styles.jobTitleContainer}>
|
342
|
+
{job.jobId ? (
|
343
|
+
<Text style={[styles.jobIdText, { color: this.props.colourBrandingMain }]}>{`${values.textEntityName} #${job.jobId}`}</Text>
|
344
|
+
) : null}
|
232
345
|
<Text style={styles.jobTitleText}>{job.title}</Text>
|
233
346
|
<View style={styles.jobTypeSeenContainer}>
|
234
347
|
<View style={[styles.jobTypeContainer, { backgroundColor: Colours.hexToRGBAstring(this.props.colourBrandingMain, 0.2) }]}>
|
235
|
-
<Text style={[styles.jobTypeText, { color: this.props.colourBrandingMain }]}
|
348
|
+
<Text style={[styles.jobTypeText, { color: this.props.colourBrandingMain }]} numberOfLines={2}>
|
349
|
+
{job.type}
|
350
|
+
</Text>
|
236
351
|
</View>
|
237
|
-
{showSeen && this.state.seen && (
|
352
|
+
{!this.props.hideSeen && showSeen && this.state.seen && (
|
238
353
|
<View style={styles.jobSeenContainer}>
|
239
354
|
<Icon name="check" type="font-awesome" iconStyle={[styles.jobSeenIcon, { color: this.props.colourBrandingMain }]} />
|
240
355
|
<Text style={[styles.jobSeenText, { color: this.props.colourBrandingMain }]}>Seen</Text>
|
@@ -250,7 +365,7 @@ class RequestDetail extends Component {
|
|
250
365
|
</View>
|
251
366
|
</View>
|
252
367
|
)}
|
253
|
-
<View style={styles.textSectionInner}>
|
368
|
+
{/* <View style={styles.textSectionInner}>
|
254
369
|
<Text style={styles.textSectionLabel}>Expected Date</Text>
|
255
370
|
<TouchableOpacity onPress={this.onOpenDatePicker}>
|
256
371
|
<View style={styles.textSectionTextContainer}>
|
@@ -262,25 +377,36 @@ class RequestDetail extends Component {
|
|
262
377
|
/>
|
263
378
|
</View>
|
264
379
|
</TouchableOpacity>
|
265
|
-
</View>
|
380
|
+
</View> */}
|
266
381
|
</View>
|
267
|
-
<View style={styles.
|
268
|
-
<View style={styles.
|
269
|
-
<
|
270
|
-
|
271
|
-
<
|
272
|
-
<
|
273
|
-
|
382
|
+
<View style={styles.jobInfoContainer}>
|
383
|
+
<View style={styles.jobStatusExpectedContainer}>
|
384
|
+
<View style={styles.jobStatusOuterContainer}>
|
385
|
+
<Text style={styles.jobStatusHeading}>STATUS</Text>
|
386
|
+
<TouchableOpacity onPress={canEdit ? this.onOpenStatusPicker : null}>
|
387
|
+
<View style={[styles.jobStatusContainer, { backgroundColor: statusOption.color }]}>
|
388
|
+
<Text style={styles.jobStatusText}>{statusOption?.text}</Text>
|
389
|
+
</View>
|
390
|
+
</TouchableOpacity>
|
391
|
+
</View>
|
392
|
+
{this.hasPermission() && (
|
393
|
+
<View style={styles.jobStatusOuterContainer}>
|
394
|
+
<Text style={styles.jobStatusHeading}>STAFF NOTES</Text>
|
395
|
+
<TouchableOpacity onPress={this.openStaffNotes}>
|
396
|
+
<View style={[styles.jobStatusContainer, { backgroundColor: this.props.colourBrandingMain }]}>
|
397
|
+
<Icon name="pencil-square-o" type="font-awesome" iconStyle={styles.jobStatusIcon} />
|
398
|
+
<Text style={styles.jobStatusText}>Notes ({(job.Notes || []).length})</Text>
|
399
|
+
</View>
|
400
|
+
</TouchableOpacity>
|
274
401
|
</View>
|
275
|
-
|
402
|
+
)}
|
276
403
|
</View>
|
277
|
-
{
|
278
|
-
<View style={styles.
|
279
|
-
<Text style={styles.jobStatusHeading}>
|
280
|
-
<TouchableOpacity onPress={this.
|
281
|
-
<View style={[styles.jobStatusContainer, { backgroundColor:
|
282
|
-
<
|
283
|
-
<Text style={styles.jobStatusText}>Notes ({(job.Notes || []).length})</Text>
|
404
|
+
{isStaff && (
|
405
|
+
<View style={styles.jobPriorityOuterContainer}>
|
406
|
+
<Text style={styles.jobStatusHeading}>PRIORITY</Text>
|
407
|
+
<TouchableOpacity onPress={canEdit ? this.onOpenPriorityPicker : null}>
|
408
|
+
<View style={[styles.jobStatusContainer, { backgroundColor: priority.color }]}>
|
409
|
+
<Text style={styles.jobStatusText}>{priority.label}</Text>
|
284
410
|
</View>
|
285
411
|
</TouchableOpacity>
|
286
412
|
</View>
|
@@ -290,7 +416,8 @@ class RequestDetail extends Component {
|
|
290
416
|
);
|
291
417
|
}
|
292
418
|
|
293
|
-
renderPlayableImageUrl(
|
419
|
+
renderPlayableImageUrl(images, index, containerStyle, showMore) {
|
420
|
+
const url = images[index || 0];
|
294
421
|
const thumbUrl = Helper.getThumb300(url);
|
295
422
|
|
296
423
|
if (Helper.isVideo(url)) {
|
@@ -307,7 +434,7 @@ class RequestDetail extends Component {
|
|
307
434
|
|
308
435
|
const imageUrl = Helper.get1400(url);
|
309
436
|
return (
|
310
|
-
<TouchableOpacity style={containerStyle} onPress={this.openGallery.bind(this, index || 0)}>
|
437
|
+
<TouchableOpacity style={containerStyle} onPress={this.openGallery.bind(this, images, index || 0)}>
|
311
438
|
<ImageBackground style={styles.imageContainer} source={{ uri: imageUrl }}>
|
312
439
|
{showMore && <Text style={styles.plusImages}>+{this.state.job.images.length - 2}</Text>}
|
313
440
|
</ImageBackground>
|
@@ -315,26 +442,24 @@ class RequestDetail extends Component {
|
|
315
442
|
);
|
316
443
|
}
|
317
444
|
|
318
|
-
renderPlayableImage(index, containerStyle, showMore) {
|
319
|
-
|
320
|
-
return this.renderPlayableImageUrl(url, index, containerStyle, showMore);
|
445
|
+
renderPlayableImage(images, index, containerStyle, showMore) {
|
446
|
+
return this.renderPlayableImageUrl(images, index, containerStyle, showMore);
|
321
447
|
}
|
322
448
|
|
323
|
-
renderImage() {
|
324
|
-
|
325
|
-
|
326
|
-
if (job.images.length >= 2) {
|
449
|
+
renderImage(images, image = null) {
|
450
|
+
if (!_.isNil(images) && !_.isEmpty(images)) {
|
451
|
+
if (images.length >= 2) {
|
327
452
|
return (
|
328
453
|
<View style={styles.sideBySideImages}>
|
329
|
-
{this.renderPlayableImage(0, styles.sideBySideImageContainer)}
|
330
|
-
{this.renderPlayableImage(1, styles.sideBySideImageContainer,
|
454
|
+
{this.renderPlayableImage(images, 0, styles.sideBySideImageContainer)}
|
455
|
+
{this.renderPlayableImage(images, 1, styles.sideBySideImageContainer, images.length > 2)}
|
331
456
|
</View>
|
332
457
|
);
|
333
458
|
} else {
|
334
|
-
return <View style={styles.singleImageContainer}>{this.renderPlayableImage(0)}</View>;
|
459
|
+
return <View style={styles.singleImageContainer}>{this.renderPlayableImage(images, 0)}</View>;
|
335
460
|
}
|
336
|
-
} else if (!_.isNil(
|
337
|
-
return <View style={styles.singleImageContainer}>{this.renderPlayableImageUrl(
|
461
|
+
} else if (!_.isNil(image)) {
|
462
|
+
return <View style={styles.singleImageContainer}>{this.renderPlayableImageUrl([image], 0)}</View>;
|
338
463
|
}
|
339
464
|
return null;
|
340
465
|
}
|
@@ -343,15 +468,86 @@ class RequestDetail extends Component {
|
|
343
468
|
return (
|
344
469
|
<Components.ImagePopup
|
345
470
|
visible={this.state.galleryOpen}
|
346
|
-
images={this.state.
|
471
|
+
images={this.state.galleryImages}
|
347
472
|
onClose={this.closeGallery.bind(this)}
|
348
473
|
ref="imagePopup"
|
349
474
|
/>
|
350
475
|
);
|
351
476
|
}
|
352
477
|
|
478
|
+
renderAssignee() {
|
479
|
+
const { job } = this.state;
|
480
|
+
if (!this.hasPermission() && !job.Assignee) return null;
|
481
|
+
|
482
|
+
const content = (
|
483
|
+
<View>
|
484
|
+
<Text style={styles.locationLabel}>Assigned To</Text>
|
485
|
+
<View>
|
486
|
+
{job.Assignee && (
|
487
|
+
<View style={styles.profileContainer}>
|
488
|
+
<Components.ProfilePic ProfilePic={job.Assignee.profilePic} Diameter={40} />
|
489
|
+
<View style={styles.nameContainer}>
|
490
|
+
<Text style={styles.nameText}>{job.Assignee.displayName}</Text>
|
491
|
+
</View>
|
492
|
+
</View>
|
493
|
+
)}
|
494
|
+
</View>
|
495
|
+
</View>
|
496
|
+
);
|
497
|
+
|
498
|
+
if (this.hasPermission()) {
|
499
|
+
return (
|
500
|
+
<Components.FormCardSectionOptionLauncher
|
501
|
+
onPress={this.onOpenAssigneePicker}
|
502
|
+
title="Assigned To"
|
503
|
+
value={job.Assignee ? job.Assignee.displayName : 'Unassigned'}
|
504
|
+
textStyle={styles.detailsText}
|
505
|
+
sectionStyle={styles.detailsSection}
|
506
|
+
>
|
507
|
+
{content}
|
508
|
+
</Components.FormCardSectionOptionLauncher>
|
509
|
+
);
|
510
|
+
}
|
511
|
+
return content;
|
512
|
+
}
|
513
|
+
|
514
|
+
renderCustomFields() {
|
515
|
+
const { job } = this.state;
|
516
|
+
const { customFields } = job;
|
517
|
+
|
518
|
+
const renderAnswer = field => {
|
519
|
+
switch (field.type) {
|
520
|
+
case 'date':
|
521
|
+
return <Text style={styles.customText}>{field.answer ? moment(field.answer, 'YYYY-MM-DD').format('DD MMM YYYY') : ''}</Text>;
|
522
|
+
case 'time':
|
523
|
+
return <Text style={styles.customText}>{field.answer ? moment(field.answer, 'HH:mm').format('h:mm a') : ''}</Text>;
|
524
|
+
case 'yn':
|
525
|
+
return <Text style={styles.customText}>{field.answer ? 'Yes' : 'No'}</Text>;
|
526
|
+
case 'checkbox':
|
527
|
+
return <Text style={styles.customText}>{field.answer && Array.isArray(field.answer) ? field.answer.join(', ') : ''}</Text>;
|
528
|
+
case 'image':
|
529
|
+
return <View style={{ marginTop: 8 }}>{this.renderImage(field.answer)}</View>;
|
530
|
+
default:
|
531
|
+
return <Text style={styles.customText}>{field.answer}</Text>;
|
532
|
+
}
|
533
|
+
};
|
534
|
+
|
535
|
+
return customFields.map((field, index) => {
|
536
|
+
if (['staticTitle', 'staticText'].includes(field.type)) return null;
|
537
|
+
if (_.isNil(field.answer) || field.answer === '' || (Array.isArray(field.answer) && field.answer.length === 0)) return null;
|
538
|
+
return (
|
539
|
+
<View key={index}>
|
540
|
+
<Text style={styles.customLabel}>{field.label}</Text>
|
541
|
+
{renderAnswer(field)}
|
542
|
+
</View>
|
543
|
+
);
|
544
|
+
});
|
545
|
+
}
|
546
|
+
|
353
547
|
rendeDetails() {
|
354
548
|
const { job } = this.state;
|
549
|
+
const { customFields } = job;
|
550
|
+
const hasCustomFields = customFields && customFields.length > 0;
|
355
551
|
|
356
552
|
return (
|
357
553
|
<View>
|
@@ -364,21 +560,26 @@ class RequestDetail extends Component {
|
|
364
560
|
/>
|
365
561
|
{this.state.showMore && (
|
366
562
|
<View>
|
367
|
-
{this.
|
368
|
-
{!
|
369
|
-
|
370
|
-
{job.
|
371
|
-
|
372
|
-
|
373
|
-
|
563
|
+
{hasCustomFields ? this.renderCustomFields() : null}
|
564
|
+
{!hasCustomFields ? (
|
565
|
+
<>
|
566
|
+
{this.renderImage(job.images, job.image)}
|
567
|
+
{!_.isEmpty(job.description) && (
|
568
|
+
<Text numberOfLines={10} style={styles.jobDescriptionText}>
|
569
|
+
{job.description}
|
570
|
+
</Text>
|
571
|
+
)}
|
572
|
+
</>
|
573
|
+
) : null}
|
574
|
+
<Text style={styles.locationLabel}>Address</Text>
|
374
575
|
<Text style={styles.locationText}>{job.room}</Text>
|
375
|
-
{job.isHome ? (
|
576
|
+
{!hasCustomFields && job.isHome ? (
|
376
577
|
<View style={styles.detailsSection}>
|
377
578
|
<Text style={styles.locationLabel}>Must be home</Text>
|
378
579
|
<Text style={styles.locationText}>{job.homeText}</Text>
|
379
580
|
</View>
|
380
581
|
) : null}
|
381
|
-
<Text style={styles.requesterLabel}>
|
582
|
+
<Text style={styles.requesterLabel}>Submitted By</Text>
|
382
583
|
<View style={styles.profileContainer}>
|
383
584
|
<Components.ProfilePic ProfilePic={job.userProfilePic} Diameter={40} />
|
384
585
|
<View style={styles.nameContainer}>
|
@@ -400,7 +601,7 @@ class RequestDetail extends Component {
|
|
400
601
|
commentReply={this.commentReply}
|
401
602
|
scrollView={this.scrollView}
|
402
603
|
adminPermission={values.permissionMaintenanceTracking}
|
403
|
-
entityType={values.
|
604
|
+
entityType={values.commentKey}
|
404
605
|
entityId={this.props.job.id}
|
405
606
|
entityName={this.props.job.title}
|
406
607
|
site={this.state.job.site || this.state.job.location}
|
@@ -437,12 +638,12 @@ class RequestDetail extends Component {
|
|
437
638
|
ref={this.commentReply}
|
438
639
|
commentSection={this.commentSection}
|
439
640
|
scrollView={this.scrollView}
|
440
|
-
entityType={values.
|
641
|
+
entityType={values.commentKey}
|
441
642
|
entityId={this.props.job.id}
|
442
643
|
entityName={this.props.job.title}
|
443
644
|
site={this.state.job.site || this.state.job.location}
|
444
|
-
|
445
|
-
|
645
|
+
// noScroll={true}
|
646
|
+
// style={{ position: 'absolute', bottom: 0, left: 0, right: 0 }}
|
446
647
|
/>
|
447
648
|
);
|
448
649
|
}
|
@@ -452,7 +653,15 @@ class RequestDetail extends Component {
|
|
452
653
|
return <StatusSelectorPopup onClose={this.onCloseStatusPopup} onSelect={this.onSelectStatus} />;
|
453
654
|
}
|
454
655
|
|
656
|
+
renderPriorityPopup() {
|
657
|
+
if (!this.state.showPriorityPopup) return null;
|
658
|
+
return <PrioritySelectorPopup onClose={this.onClosePriorityPopup} onSelect={this.onSelectPriority} />;
|
659
|
+
}
|
660
|
+
|
455
661
|
render() {
|
662
|
+
if (this.state.forbidden) {
|
663
|
+
return <Components.Forbidden />;
|
664
|
+
}
|
456
665
|
return (
|
457
666
|
<KeyboardAvoidingView behavior={Platform.OS === 'ios' && 'padding'} style={styles.container}>
|
458
667
|
<Components.Header leftIcon="angle-left" onPressLeft={this.onPressBack} text={Config.env.strings.MAINTENANCE_REQUEST_DETAILS} />
|
@@ -460,12 +669,14 @@ class RequestDetail extends Component {
|
|
460
669
|
<ScrollView ref={this.scrollView} contentContainerStyle={{ paddingBottom: 26 }} style={{ height: '100%' }}>
|
461
670
|
<View style={styles.innerContainer}>
|
462
671
|
{this.renderTop()}
|
672
|
+
{this.renderAssignee()}
|
463
673
|
{this.rendeDetails()}
|
464
674
|
{this.renderMessages()}
|
465
675
|
</View>
|
466
676
|
</ScrollView>
|
467
677
|
{this.renderMessagesReply()}
|
468
678
|
{this.renderStatusPopup()}
|
679
|
+
{this.renderPriorityPopup()}
|
469
680
|
{this.renderImagePopup()}
|
470
681
|
<DateTimePicker
|
471
682
|
isVisible={this.state.isDateTimePickerVisible}
|
@@ -492,6 +703,11 @@ const styles = StyleSheet.create({
|
|
492
703
|
paddingVertical: 14,
|
493
704
|
paddingHorizontal: 12,
|
494
705
|
},
|
706
|
+
jobIdText: {
|
707
|
+
fontFamily: 'sf-medium',
|
708
|
+
fontSize: 12,
|
709
|
+
marginBottom: 4,
|
710
|
+
},
|
495
711
|
jobTitleText: {
|
496
712
|
fontFamily: 'sf-semibold',
|
497
713
|
fontSize: 20,
|
@@ -503,8 +719,9 @@ const styles = StyleSheet.create({
|
|
503
719
|
alignItems: 'center',
|
504
720
|
},
|
505
721
|
jobTypeContainer: {
|
506
|
-
|
507
|
-
|
722
|
+
padding: 4,
|
723
|
+
minWidth: 80,
|
724
|
+
maxWidth: 140,
|
508
725
|
borderRadius: 4,
|
509
726
|
justifyContent: 'center',
|
510
727
|
},
|
@@ -512,6 +729,7 @@ const styles = StyleSheet.create({
|
|
512
729
|
fontFamily: 'sf-semibold',
|
513
730
|
fontSize: 12,
|
514
731
|
textAlign: 'center',
|
732
|
+
maxWidth: '100%',
|
515
733
|
},
|
516
734
|
jobSeenContainer: {
|
517
735
|
flexDirection: 'row',
|
@@ -532,15 +750,17 @@ const styles = StyleSheet.create({
|
|
532
750
|
fontSize: 13,
|
533
751
|
color: Colours.TEXT_LIGHT,
|
534
752
|
},
|
535
|
-
|
536
|
-
flexDirection: 'row',
|
537
|
-
alignItems: 'flex-start',
|
538
|
-
justifyContent: 'space-between',
|
753
|
+
jobInfoContainer: {
|
539
754
|
borderTopWidth: 1,
|
540
755
|
borderTopColor: Colours.LINEGREY,
|
541
756
|
paddingVertical: 14,
|
542
757
|
paddingHorizontal: 12,
|
543
758
|
},
|
759
|
+
jobStatusExpectedContainer: {
|
760
|
+
flexDirection: 'row',
|
761
|
+
alignItems: 'flex-start',
|
762
|
+
justifyContent: 'space-between',
|
763
|
+
},
|
544
764
|
jobStatusOuterContainer: {
|
545
765
|
// marginRight: 50,
|
546
766
|
},
|
@@ -572,6 +792,9 @@ const styles = StyleSheet.create({
|
|
572
792
|
flex: 1,
|
573
793
|
textAlign: 'center',
|
574
794
|
},
|
795
|
+
jobPriorityOuterContainer: {
|
796
|
+
marginTop: 12,
|
797
|
+
},
|
575
798
|
jobExpectedDateContainer: {
|
576
799
|
backgroundColor: Colours.BOXGREY,
|
577
800
|
flexDirection: 'row',
|
@@ -715,6 +938,30 @@ const styles = StyleSheet.create({
|
|
715
938
|
marginLeft: 10,
|
716
939
|
lineHeight: 24,
|
717
940
|
},
|
941
|
+
customLabel: {
|
942
|
+
fontFamily: 'sf-bold',
|
943
|
+
fontSize: 14,
|
944
|
+
color: Colours.TEXT_DARKEST,
|
945
|
+
},
|
946
|
+
customText: {
|
947
|
+
fontFamily: 'sf-regular',
|
948
|
+
fontSize: 16,
|
949
|
+
color: Colours.TEXT_DARKEST,
|
950
|
+
paddingVertical: 8,
|
951
|
+
},
|
952
|
+
customStaticTitle: {
|
953
|
+
fontSize: 20,
|
954
|
+
fontFamily: 'sf-semibold',
|
955
|
+
color: Colours.TEXT_DARKEST,
|
956
|
+
marginBottom: 10,
|
957
|
+
},
|
958
|
+
customStaticText: {
|
959
|
+
fontSize: 17,
|
960
|
+
fontFamily: 'sf-regular',
|
961
|
+
color: Colours.TEXT_DARKEST,
|
962
|
+
lineHeight: 24,
|
963
|
+
marginBottom: 10,
|
964
|
+
},
|
718
965
|
});
|
719
966
|
|
720
967
|
const mapStateToProps = state => {
|
@@ -722,7 +969,9 @@ const mapStateToProps = state => {
|
|
722
969
|
user: state.user,
|
723
970
|
colourBrandingMain: Colours.getMainBrandingColourFromState(state),
|
724
971
|
jobs: state[values.reducerKey].jobs,
|
972
|
+
statusTypes: state[values.reducerKey].jobstatuses,
|
973
|
+
hideSeen: state[values.reducerKey].hideSeen,
|
725
974
|
};
|
726
975
|
};
|
727
976
|
|
728
|
-
export default connect(mapStateToProps, { jobAdded })(RequestDetail);
|
977
|
+
export default connect(mapStateToProps, { jobAdded, jobStatusesUpdate, jobHideSeenUpdate })(RequestDetail);
|