@plusscommunities/pluss-maintenance-app 6.0.7-auth.0 → 6.0.8-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/actions/types.js +4 -3
- package/dist/module/actions/types.js.map +1 -1
- package/dist/module/apis/maintenanceActions.js +17 -15
- package/dist/module/apis/maintenanceActions.js.map +1 -1
- package/dist/module/components/MaintenanceList.js +5 -4
- package/dist/module/components/MaintenanceList.js.map +1 -1
- package/dist/module/components/MaintenanceListItem.js +3 -2
- package/dist/module/components/MaintenanceListItem.js.map +1 -1
- package/dist/module/components/MaintenanceWidgetItem.js +2 -1
- package/dist/module/components/MaintenanceWidgetItem.js.map +1 -1
- package/dist/module/components/WidgetSmall.js +8 -5
- package/dist/module/components/WidgetSmall.js.map +1 -1
- package/dist/module/feature.config.js +21 -36
- package/dist/module/feature.config.js.map +1 -1
- package/dist/module/index.js +15 -10
- package/dist/module/index.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/MaintenancePage.js +7 -3
- package/dist/module/screens/MaintenancePage.js.map +1 -1
- package/dist/module/screens/RequestDetail.js +106 -31
- package/dist/module/screens/RequestDetail.js.map +1 -1
- package/dist/module/screens/RequestNotes.js +2 -1
- package/dist/module/screens/RequestNotes.js.map +1 -1
- package/dist/module/screens/ServiceRequest.js +581 -86
- package/dist/module/screens/ServiceRequest.js.map +1 -1
- package/dist/module/values.config.a.js +30 -0
- package/dist/module/values.config.a.js.map +1 -0
- package/dist/module/values.config.b.js +30 -0
- package/dist/module/values.config.b.js.map +1 -0
- package/dist/module/values.config.c.js +30 -0
- package/dist/module/values.config.c.js.map +1 -0
- package/dist/module/values.config.d.js +30 -0
- package/dist/module/values.config.d.js.map +1 -0
- package/dist/module/values.config.default.js +35 -0
- package/dist/module/values.config.default.js.map +1 -0
- package/dist/module/values.config.forms.js +35 -0
- package/dist/module/values.config.forms.js.map +1 -0
- package/dist/module/values.config.js +35 -0
- package/dist/module/values.config.js.map +1 -0
- package/package.json +9 -6
- package/src/actions/types.js +5 -3
- package/src/apis/maintenanceActions.js +30 -14
- package/src/components/MaintenanceList.js +6 -4
- package/src/components/MaintenanceListItem.js +7 -2
- package/src/components/MaintenanceWidgetItem.js +2 -1
- package/src/components/WidgetSmall.js +8 -5
- package/src/feature.config.js +30 -40
- package/src/index.js +15 -8
- package/src/reducers/JobsReducer.js +2 -1
- package/src/screens/MaintenancePage.js +5 -4
- package/src/screens/RequestDetail.js +101 -33
- package/src/screens/RequestNotes.js +2 -1
- package/src/screens/ServiceRequest.js +625 -152
- package/src/values.config.a.js +30 -0
- package/src/values.config.b.js +30 -0
- package/src/values.config.c.js +30 -0
- package/src/values.config.d.js +30 -0
- package/src/values.config.default.js +35 -0
- package/src/values.config.forms.js +35 -0
- package/src/values.config.js +35 -0
@@ -3,46 +3,120 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
|
|
3
3
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
4
4
|
import React, { Component } from 'react';
|
5
5
|
import { Dimensions, Platform, KeyboardAvoidingView, ScrollView, Text, TouchableOpacity, View, Switch, FlatList, ImageBackground, Keyboard } from 'react-native';
|
6
|
-
import
|
6
|
+
import DateTimePicker from 'react-native-modal-datetime-picker';
|
7
7
|
import { Icon } from 'react-native-elements';
|
8
|
+
import _ from 'lodash';
|
9
|
+
import moment from 'moment';
|
8
10
|
import { connect } from 'react-redux';
|
9
11
|
import { jobAdded } from '../actions';
|
10
12
|
import { maintenanceActions } from '../apis';
|
11
13
|
import { Services } from '../feature.config';
|
12
14
|
import { Components, Colours, Helper, Config } from '../core.config';
|
15
|
+
import { values } from '../values.config';
|
13
16
|
const PHOTO_SIZE = (Dimensions.get('window').width - 64) / 3;
|
14
17
|
class MaintenanceRequest extends Component {
|
15
18
|
constructor(props) {
|
16
19
|
super(props);
|
20
|
+
_defineProperty(this, "onChangeAnswer", (fieldId, answer) => {
|
21
|
+
const update = {
|
22
|
+
customFields: _.cloneDeep(this.state.customFields)
|
23
|
+
};
|
24
|
+
const field = update.customFields[fieldId];
|
25
|
+
field.answer = answer;
|
26
|
+
if (field.isTitle) update.title = field.answer;
|
27
|
+
this.setState(update);
|
28
|
+
});
|
29
|
+
_defineProperty(this, "onChangeToggleAnswer", (fieldId, answer) => {
|
30
|
+
const update = {
|
31
|
+
customFields: _.cloneDeep(this.state.customFields)
|
32
|
+
};
|
33
|
+
const field = update.customFields[fieldId];
|
34
|
+
field.answer = field.answer === answer ? undefined : answer;
|
35
|
+
if (field.isTitle) update.title = field.answer;
|
36
|
+
this.setState(update);
|
37
|
+
});
|
38
|
+
_defineProperty(this, "onChangeCheckboxAnswer", (fieldId, answer) => {
|
39
|
+
const update = {
|
40
|
+
customFields: _.cloneDeep(this.state.customFields)
|
41
|
+
};
|
42
|
+
const field = update.customFields[fieldId];
|
43
|
+
field.answer = _.xor(field.answer || [], [answer]);
|
44
|
+
if (field.isTitle) update.title = field.answer.join(', ');
|
45
|
+
this.setState(update);
|
46
|
+
});
|
47
|
+
_defineProperty(this, "onOpenDatePicker", (field, fieldId) => {
|
48
|
+
Keyboard.dismiss();
|
49
|
+
this.setState({
|
50
|
+
dateFieldId: fieldId,
|
51
|
+
popUpType: field.type,
|
52
|
+
isDateTimePickerVisible: true
|
53
|
+
});
|
54
|
+
});
|
55
|
+
_defineProperty(this, "onClearDate", fieldId => {
|
56
|
+
const update = {
|
57
|
+
customFields: _.cloneDeep(this.state.customFields)
|
58
|
+
};
|
59
|
+
const field = update.customFields[fieldId];
|
60
|
+
field.answer = undefined;
|
61
|
+
if (field.isTitle) update.title = field.answer;
|
62
|
+
this.setState(update);
|
63
|
+
});
|
64
|
+
_defineProperty(this, "onDateSelected", date => {
|
65
|
+
const {
|
66
|
+
customFields,
|
67
|
+
dateFieldId,
|
68
|
+
popUpType
|
69
|
+
} = this.state;
|
70
|
+
const update = {
|
71
|
+
customFields: _.cloneDeep(customFields),
|
72
|
+
isDateTimePickerVisible: false,
|
73
|
+
fieldId: null
|
74
|
+
};
|
75
|
+
const field = update.customFields[dateFieldId];
|
76
|
+
const dateObj = moment(date);
|
77
|
+
if (popUpType === 'date') {
|
78
|
+
field.answer = dateObj.format('YYYY-MM-DD');
|
79
|
+
if (field.isTitle) update.title = dateObj.format('DD MMM YYYY');
|
80
|
+
} else {
|
81
|
+
field.answer = dateObj.format('HH:mm');
|
82
|
+
if (field.isTitle) update.title = dateObj.format('h:mm a');
|
83
|
+
}
|
84
|
+
this.setState(update);
|
85
|
+
});
|
17
86
|
_defineProperty(this, "onUploadStarted", (uploadUri, imageUri) => {
|
18
|
-
const
|
19
|
-
|
87
|
+
const {
|
88
|
+
imageFieldId
|
89
|
+
} = this.state;
|
90
|
+
const imagesUpdate = this.getImages(imageFieldId);
|
91
|
+
imagesUpdate.splice(imagesUpdate.length - 1, 0, {
|
20
92
|
uploading: true,
|
21
93
|
uploadProgress: '0%',
|
22
94
|
uploadUri,
|
23
95
|
imageUri,
|
24
96
|
allowRetry: true
|
25
97
|
});
|
26
|
-
this.
|
27
|
-
images
|
28
|
-
});
|
98
|
+
this.setImages(imagesUpdate, imageFieldId);
|
29
99
|
});
|
30
100
|
_defineProperty(this, "onUploadProgress", progress => {
|
31
|
-
const
|
32
|
-
|
101
|
+
const {
|
102
|
+
imageFieldId
|
103
|
+
} = this.state;
|
104
|
+
const imagesUpdate = this.getImages(imageFieldId);
|
105
|
+
imagesUpdate.map(img => {
|
33
106
|
if (img.uploadUri === progress.uri) {
|
34
107
|
img.uploadProgress = progress.percentage;
|
35
108
|
img.uploading = true;
|
36
109
|
img.allowRetry = true;
|
37
110
|
}
|
38
111
|
});
|
39
|
-
this.
|
40
|
-
images
|
41
|
-
});
|
112
|
+
this.setImages(imagesUpdate, imageFieldId);
|
42
113
|
});
|
43
114
|
_defineProperty(this, "onUploadSuccess", async (uri, uploadUri) => {
|
44
|
-
const
|
45
|
-
|
115
|
+
const {
|
116
|
+
imageFieldId
|
117
|
+
} = this.state;
|
118
|
+
const imagesUpdate = this.getImages(imageFieldId);
|
119
|
+
imagesUpdate.map(img => {
|
46
120
|
if (img.uploadUri === uploadUri && img.uploading) {
|
47
121
|
img.url = uri.replace('/general/', '/general1400/');
|
48
122
|
img.thumbNailExists = false;
|
@@ -50,41 +124,81 @@ class MaintenanceRequest extends Component {
|
|
50
124
|
img.allowRetry = true;
|
51
125
|
}
|
52
126
|
});
|
53
|
-
this.
|
54
|
-
images
|
55
|
-
}, () => this.waitForThumbnails());
|
127
|
+
this.setImages(imagesUpdate, imageFieldId, () => this.waitForThumbnails());
|
56
128
|
});
|
57
129
|
_defineProperty(this, "onUploadFailed", uploadUri => {
|
58
|
-
const
|
59
|
-
|
130
|
+
const {
|
131
|
+
imageFieldId
|
132
|
+
} = this.state;
|
133
|
+
const imagesUpdate = this.getImages(imageFieldId);
|
134
|
+
imagesUpdate.map(img => {
|
60
135
|
if (img.uploadUri === uploadUri) {
|
61
136
|
img.uploading = true; // Requried for retry
|
62
137
|
img.uploadProgress = '';
|
63
138
|
img.allowRetry = true;
|
64
139
|
}
|
65
140
|
});
|
66
|
-
this.
|
67
|
-
images
|
68
|
-
});
|
141
|
+
this.setImages(imagesUpdate, imageFieldId);
|
69
142
|
});
|
70
143
|
_defineProperty(this, "onLibrarySelected", uri => {
|
71
|
-
const
|
72
|
-
|
144
|
+
const {
|
145
|
+
imageFieldId
|
146
|
+
} = this.state;
|
147
|
+
const imagesUpdate = this.getImages(imageFieldId);
|
148
|
+
imagesUpdate.splice(imagesUpdate.length - 1, 0, {
|
73
149
|
uploading: false,
|
74
150
|
allowRetry: false,
|
75
151
|
url: Helper.get1400(uri),
|
76
152
|
thumbNailExists: true,
|
77
153
|
thumbNailUrl: Helper.getThumb300(uri)
|
78
154
|
});
|
79
|
-
this.
|
80
|
-
images
|
81
|
-
});
|
155
|
+
this.setImages(imagesUpdate, imageFieldId);
|
82
156
|
});
|
83
|
-
_defineProperty(this, "
|
157
|
+
_defineProperty(this, "isFieldValid", (field, fieldId) => {
|
158
|
+
const {
|
159
|
+
mandatory,
|
160
|
+
type,
|
161
|
+
answer
|
162
|
+
} = field;
|
163
|
+
if (['staticTitle', 'staticText'].includes(type)) return true;
|
164
|
+
const imagesList = type === 'image' ? this.getImageUrls(fieldId) : [];
|
165
|
+
const checkMandatory = () => {
|
166
|
+
if (!mandatory) return true;
|
167
|
+
switch (type) {
|
168
|
+
case 'yn':
|
169
|
+
return _.isBoolean(answer);
|
170
|
+
case 'image':
|
171
|
+
return imagesList.length > 0;
|
172
|
+
case 'checkbox':
|
173
|
+
return _.isArray(answer) && answer.length > 0;
|
174
|
+
default:
|
175
|
+
return !_.isNil(answer) && !_.isEmpty(answer);
|
176
|
+
}
|
177
|
+
};
|
178
|
+
const checkFormat = () => {
|
179
|
+
if (_.isNil(answer) || _.isEmpty(answer)) return true;
|
180
|
+
switch (type) {
|
181
|
+
case 'email':
|
182
|
+
return Helper.isEmail(answer);
|
183
|
+
case 'date':
|
184
|
+
return moment(answer, 'YYYY-MM-DD', true).isValid();
|
185
|
+
case 'time':
|
186
|
+
return moment(answer, 'HH:mm', true).isValid();
|
187
|
+
default:
|
188
|
+
return true;
|
189
|
+
}
|
190
|
+
};
|
191
|
+
const valid = checkMandatory() && checkFormat();
|
192
|
+
return valid;
|
193
|
+
});
|
194
|
+
_defineProperty(this, "showUploadMenu", fieldId => {
|
84
195
|
Keyboard.dismiss();
|
85
196
|
if (this.state.uploadingImage || this.state.submitting) {
|
86
197
|
return;
|
87
198
|
}
|
199
|
+
if (fieldId) this.setState({
|
200
|
+
imageFieldId: fieldId
|
201
|
+
});
|
88
202
|
this.imageUploader.showUploadMenu();
|
89
203
|
});
|
90
204
|
_defineProperty(this, "submit", async () => {
|
@@ -100,12 +214,15 @@ class MaintenanceRequest extends Component {
|
|
100
214
|
y: 0
|
101
215
|
});
|
102
216
|
}, 100);
|
103
|
-
const images =
|
104
|
-
|
105
|
-
|
106
|
-
|
217
|
+
const images = this.getImageUrls();
|
218
|
+
|
219
|
+
// Fix custom images field answers
|
220
|
+
const customFields = _.cloneDeep(this.state.customFields);
|
221
|
+
const updatedCustomFields = customFields.map((field, fieldId) => {
|
222
|
+
if (field.type === 'image') field.answer = this.getImageUrls(fieldId);
|
223
|
+
return field;
|
107
224
|
});
|
108
|
-
maintenanceActions.sendMaintenanceRequest(this.props.uid, this.state.userName, this.state.phone, this.state.roomNumber, this.state.title, description, null, this.state.type, images, Helper.getSite(this.props.site), this.state.isHome, this.state.times).then(res => {
|
225
|
+
maintenanceActions.sendMaintenanceRequest(this.props.uid, this.state.userName, this.state.phone, this.state.roomNumber, this.state.title, description, null, this.state.type, images, Helper.getSite(this.props.site), this.state.isHome, this.state.times, updatedCustomFields).then(res => {
|
109
226
|
if (res.data.success) {
|
110
227
|
this.refreshRequest(res.data.searchResult);
|
111
228
|
if (this.props.onSubmissionSuccess) this.props.onSubmissionSuccess(res.data);
|
@@ -130,22 +247,71 @@ class MaintenanceRequest extends Component {
|
|
130
247
|
_defineProperty(this, "refreshRequest", async id => {
|
131
248
|
try {
|
132
249
|
const job = await maintenanceActions.getJob(Helper.getSite(this.props.site), id);
|
133
|
-
// console.log('refreshRequest', job?.data);
|
134
250
|
this.props.jobAdded(job.data);
|
135
251
|
} catch (error) {
|
136
252
|
console.log('refreshRequest error', error);
|
137
253
|
}
|
138
254
|
});
|
255
|
+
_defineProperty(this, "validateCustomFields", () => {
|
256
|
+
const {
|
257
|
+
customFields
|
258
|
+
} = this.state;
|
259
|
+
if (!customFields || customFields.length === 0) return true;
|
260
|
+
return customFields.every((field, index) => {
|
261
|
+
const isValid = this.isFieldValid(field, index);
|
262
|
+
return isValid;
|
263
|
+
});
|
264
|
+
});
|
265
|
+
_defineProperty(this, "getImages", (fieldId = null) => {
|
266
|
+
const {
|
267
|
+
images,
|
268
|
+
customFieldImages
|
269
|
+
} = this.state;
|
270
|
+
const imagesList = _.cloneDeep(fieldId ? customFieldImages[fieldId] : images);
|
271
|
+
if (!imagesList || !Array.isArray(imagesList) || imagesList.length === 0) {
|
272
|
+
return [{
|
273
|
+
add: true
|
274
|
+
}];
|
275
|
+
}
|
276
|
+
return imagesList;
|
277
|
+
});
|
278
|
+
_defineProperty(this, "setImages", (imagesList, fieldId = null, callback = null) => {
|
279
|
+
let update = {};
|
280
|
+
if (fieldId) {
|
281
|
+
const customFieldImages = _.cloneDeep(this.state.customFieldImages);
|
282
|
+
customFieldImages[fieldId] = imagesList;
|
283
|
+
update = {
|
284
|
+
customFieldImages
|
285
|
+
};
|
286
|
+
} else {
|
287
|
+
update = {
|
288
|
+
images: imagesList
|
289
|
+
};
|
290
|
+
}
|
291
|
+
this.setState(update, callback);
|
292
|
+
});
|
293
|
+
_defineProperty(this, "getImageUrls", (fieldId = null) => {
|
294
|
+
const imagesList = this.getImages(fieldId);
|
295
|
+
return _.filter(imagesList, img => {
|
296
|
+
return !img.uploading && !img.add;
|
297
|
+
}).map(img => {
|
298
|
+
return img.url;
|
299
|
+
});
|
300
|
+
});
|
139
301
|
_defineProperty(this, "waitForThumbnails", () => {
|
140
302
|
if (this.checkThumb) return;
|
141
303
|
this.checkThumb = setInterval(async () => {
|
142
|
-
const
|
143
|
-
|
304
|
+
const {
|
305
|
+
imageFieldId
|
306
|
+
} = this.state;
|
307
|
+
const imagesList = this.getImages(imageFieldId);
|
308
|
+
const imagesUpdate = [];
|
309
|
+
await Promise.all(imagesList.map(image => {
|
144
310
|
return new Promise(async resolve => {
|
145
311
|
const newImage = {
|
146
312
|
...image
|
147
313
|
};
|
148
|
-
|
314
|
+
imagesUpdate.push(newImage);
|
149
315
|
if (newImage.url && !newImage.thumbNailExists) {
|
150
316
|
newImage.uploading = false;
|
151
317
|
newImage.allowRetry = false;
|
@@ -155,22 +321,18 @@ class MaintenanceRequest extends Component {
|
|
155
321
|
resolve(true);
|
156
322
|
});
|
157
323
|
}));
|
158
|
-
const thumbnailsExist =
|
324
|
+
const thumbnailsExist = imagesUpdate.every(image => !image.url || image.thumbNailExists);
|
159
325
|
if (thumbnailsExist) {
|
160
326
|
clearInterval(this.checkThumb);
|
161
327
|
this.checkThumb = null;
|
162
|
-
this.
|
163
|
-
images
|
164
|
-
});
|
328
|
+
this.setImages(imagesUpdate, imageFieldId);
|
165
329
|
}
|
166
330
|
}, 2000);
|
167
331
|
});
|
168
|
-
_defineProperty(this, "removeImage", index => {
|
169
|
-
const
|
170
|
-
|
171
|
-
this.
|
172
|
-
images
|
173
|
-
});
|
332
|
+
_defineProperty(this, "removeImage", (index, fieldId) => {
|
333
|
+
const imagesUpdate = this.getImages(fieldId);
|
334
|
+
imagesUpdate.splice(index, 1);
|
335
|
+
this.setImages(imagesUpdate, fieldId);
|
174
336
|
});
|
175
337
|
_defineProperty(this, "toggleFullscreenVideo", url => {
|
176
338
|
if (typeof url !== 'string') url = '';
|
@@ -185,6 +347,7 @@ class MaintenanceRequest extends Component {
|
|
185
347
|
fail: false,
|
186
348
|
error: null,
|
187
349
|
showError: false,
|
350
|
+
loadingTypes: values.forceCustomFields,
|
188
351
|
userName: '',
|
189
352
|
roomNumber: '',
|
190
353
|
phone: '',
|
@@ -200,9 +363,20 @@ class MaintenanceRequest extends Component {
|
|
200
363
|
currentVideoUrl: '',
|
201
364
|
isHome: false,
|
202
365
|
types: [],
|
203
|
-
confirmationToShow: false
|
366
|
+
confirmationToShow: false,
|
367
|
+
customFields: [],
|
368
|
+
customFieldImages: {},
|
369
|
+
isDateTimePickerVisible: false,
|
370
|
+
popUpType: 'date',
|
371
|
+
dateFieldId: null,
|
372
|
+
imageFieldId: null
|
204
373
|
};
|
205
374
|
this.checkThumb = null;
|
375
|
+
this.keyboardTypes = {
|
376
|
+
phone: 'phone-pad',
|
377
|
+
email: 'email-address',
|
378
|
+
text: 'default'
|
379
|
+
};
|
206
380
|
}
|
207
381
|
componentDidMount() {
|
208
382
|
if (this.props.userType !== 'KIOSK') {
|
@@ -221,7 +395,7 @@ class MaintenanceRequest extends Component {
|
|
221
395
|
Services.navigation.goBack();
|
222
396
|
}
|
223
397
|
onPressType() {
|
224
|
-
Services.navigation.navigate(
|
398
|
+
Services.navigation.navigate(values.screenJobTypePicker, {
|
225
399
|
currentType: this.state.type,
|
226
400
|
types: this.state.types,
|
227
401
|
onSelectType: this.pickType.bind(this)
|
@@ -247,32 +421,66 @@ class MaintenanceRequest extends Component {
|
|
247
421
|
}],
|
248
422
|
submitting: false,
|
249
423
|
success: false,
|
250
|
-
fail: false
|
251
|
-
|
424
|
+
fail: false,
|
425
|
+
customFields: [],
|
426
|
+
customFieldImages: {},
|
427
|
+
isDateTimePickerVisible: false,
|
428
|
+
popUpType: 'date',
|
429
|
+
dateFieldId: null,
|
430
|
+
imageFieldId: null
|
431
|
+
}, () => this.pickType(this.state.type));
|
252
432
|
}
|
253
433
|
getJobTypes() {
|
254
|
-
const self = this;
|
255
434
|
maintenanceActions.getJobTypes(Helper.getSite(this.props.site)).then(res => {
|
256
|
-
|
435
|
+
this.setState({
|
257
436
|
types: res.data
|
258
437
|
});
|
259
|
-
|
438
|
+
console.log(res.data);
|
439
|
+
this.getDefaultJob();
|
260
440
|
}).catch(() => {});
|
261
441
|
}
|
262
|
-
|
263
|
-
|
442
|
+
pickType(type) {
|
443
|
+
const {
|
444
|
+
types
|
445
|
+
} = this.state;
|
446
|
+
const selected = types.find(t => t.typeName === type) || {};
|
447
|
+
if (values.forceCustomFields && !selected.hasCustomFields) {
|
448
|
+
console.log(selected);
|
264
449
|
this.setState({
|
265
|
-
type
|
450
|
+
type,
|
451
|
+
customFields: [],
|
452
|
+
noType: true
|
266
453
|
});
|
454
|
+
return;
|
267
455
|
}
|
268
|
-
}
|
269
|
-
pickType(type) {
|
270
456
|
this.setState({
|
271
|
-
type
|
457
|
+
type,
|
458
|
+
customFields: selected.hasCustomFields && selected.customFields.length > 0 ? _.cloneDeep(selected.customFields) : [],
|
459
|
+
loadingTypes: false
|
272
460
|
});
|
273
461
|
}
|
462
|
+
getDefaultJob() {
|
463
|
+
const {
|
464
|
+
types,
|
465
|
+
jobId
|
466
|
+
} = this.state;
|
467
|
+
if (types.length !== 0 && jobId == null) {
|
468
|
+
const defaultType = types[0];
|
469
|
+
this.pickType(defaultType.typeName);
|
470
|
+
}
|
471
|
+
}
|
274
472
|
submitRequest() {
|
275
|
-
|
473
|
+
const {
|
474
|
+
customFields,
|
475
|
+
submitting,
|
476
|
+
uploadingImage,
|
477
|
+
title,
|
478
|
+
roomNumber,
|
479
|
+
isHome,
|
480
|
+
times
|
481
|
+
} = this.state;
|
482
|
+
const hasCustomFields = customFields && customFields.length > 0;
|
483
|
+
if (submitting || !this.props.connected) {
|
276
484
|
if (!this.props.connected) {
|
277
485
|
this.setState({
|
278
486
|
error: {
|
@@ -282,25 +490,41 @@ class MaintenanceRequest extends Component {
|
|
282
490
|
}
|
283
491
|
return;
|
284
492
|
}
|
285
|
-
if (
|
286
|
-
return;
|
287
|
-
}
|
493
|
+
if (uploadingImage) return;
|
288
494
|
this.setState({
|
289
495
|
error: null,
|
290
496
|
showError: false
|
291
497
|
});
|
292
|
-
if (
|
293
|
-
|
294
|
-
|
498
|
+
if (title.length === 0 || !roomNumber || roomNumber.length === 0) {
|
499
|
+
console.log('submitRequest - error', {
|
500
|
+
title,
|
501
|
+
roomNumber
|
295
502
|
});
|
296
|
-
return;
|
297
|
-
}
|
298
|
-
if (this.state.isHome && this.state.times.length < 2) {
|
299
503
|
this.setState({
|
300
504
|
showError: true
|
301
505
|
});
|
302
506
|
return;
|
303
507
|
}
|
508
|
+
if (hasCustomFields) {
|
509
|
+
if (!this.validateCustomFields()) {
|
510
|
+
console.log('submitRequest - custom fields error');
|
511
|
+
this.setState({
|
512
|
+
showError: true
|
513
|
+
});
|
514
|
+
return;
|
515
|
+
}
|
516
|
+
} else {
|
517
|
+
if (isHome && times.length < 2) {
|
518
|
+
console.log('submitRequest - error', {
|
519
|
+
isHome,
|
520
|
+
times
|
521
|
+
});
|
522
|
+
this.setState({
|
523
|
+
showError: true
|
524
|
+
});
|
525
|
+
return;
|
526
|
+
}
|
527
|
+
}
|
304
528
|
this.submit();
|
305
529
|
}
|
306
530
|
renderUploadMenu() {
|
@@ -323,14 +547,15 @@ class MaintenanceRequest extends Component {
|
|
323
547
|
hideLibrary: true
|
324
548
|
});
|
325
549
|
}
|
326
|
-
renderImage(item, index) {
|
550
|
+
renderImage(item, index, fieldId = null) {
|
327
551
|
const isVideoUrl = Helper.isVideo(item.url);
|
552
|
+
const imagesList = this.getImages(fieldId);
|
328
553
|
if (item.add) {
|
329
554
|
return /*#__PURE__*/React.createElement(TouchableOpacity, {
|
330
555
|
activeOpacity: 0.8,
|
331
|
-
onPress: this.showUploadMenu
|
556
|
+
onPress: () => this.showUploadMenu(fieldId)
|
332
557
|
}, /*#__PURE__*/React.createElement(View, {
|
333
|
-
style: [styles.imageContainer,
|
558
|
+
style: [styles.imageContainer, imagesList.length > 1 && styles.imageContainerNotEmpty, index % 3 === 0 && {
|
334
559
|
marginLeft: 0
|
335
560
|
}, index > 2 && {
|
336
561
|
marginTop: 8
|
@@ -344,7 +569,7 @@ class MaintenanceRequest extends Component {
|
|
344
569
|
}))));
|
345
570
|
}
|
346
571
|
return /*#__PURE__*/React.createElement(View, {
|
347
|
-
style: [styles.imageContainer,
|
572
|
+
style: [styles.imageContainer, imagesList.length > 1 && styles.imageContainerNotEmpty, index % 3 === 0 && {
|
348
573
|
marginLeft: 0
|
349
574
|
}, index > 2 && {
|
350
575
|
marginTop: 8
|
@@ -366,7 +591,7 @@ class MaintenanceRequest extends Component {
|
|
366
591
|
iconStyle: styles.imageControlIcon
|
367
592
|
}))), /*#__PURE__*/React.createElement(TouchableOpacity, {
|
368
593
|
style: styles.removeImage,
|
369
|
-
onPress: this.removeImage
|
594
|
+
onPress: () => this.removeImage(index, fieldId)
|
370
595
|
}, /*#__PURE__*/React.createElement(Icon, {
|
371
596
|
name: "remove",
|
372
597
|
type: "font-awesome",
|
@@ -385,24 +610,200 @@ class MaintenanceRequest extends Component {
|
|
385
610
|
style: styles.requestSuccess
|
386
611
|
}, "Your request has been submitted. Thank you."));
|
387
612
|
}
|
388
|
-
renderImageList() {
|
613
|
+
renderImageList(fieldId = null) {
|
614
|
+
const imagesList = this.getImages(fieldId);
|
389
615
|
return /*#__PURE__*/React.createElement(View, {
|
390
616
|
style: styles.imageSection
|
391
617
|
}, /*#__PURE__*/React.createElement(View, {
|
392
|
-
style: [styles.imageListContainer,
|
618
|
+
style: [styles.imageListContainer, imagesList.length < 2 && styles.imageListContainerEmpty]
|
393
619
|
}, /*#__PURE__*/React.createElement(FlatList, {
|
394
620
|
keyboardShouldPersistTaps: "always",
|
395
621
|
enableEmptySections: true,
|
396
|
-
data:
|
622
|
+
data: imagesList,
|
397
623
|
renderItem: ({
|
398
624
|
item,
|
399
625
|
index
|
400
|
-
}) => this.renderImage(item, index),
|
626
|
+
}) => this.renderImage(item, index, fieldId),
|
401
627
|
keyExtractor: (item, index) => index,
|
402
628
|
numColumns: 3
|
403
629
|
})));
|
404
630
|
}
|
631
|
+
renderDateField(field, fieldId, sectionStyle) {
|
632
|
+
let displayText, placeHolder, icon, errorText;
|
633
|
+
if (field.type === 'date') {
|
634
|
+
displayText = field.answer ? moment(field.answer, 'YYYY-MM-DD').format('DD MMM YYYY') : '';
|
635
|
+
placeHolder = 'dd mmm yyyy';
|
636
|
+
icon = 'calendar';
|
637
|
+
errorText = 'Not a valid date';
|
638
|
+
} else {
|
639
|
+
displayText = field.answer ? moment(field.answer, 'HH:mm').format('h:mm a') : '';
|
640
|
+
placeHolder = '--:-- --';
|
641
|
+
icon = 'clock-o';
|
642
|
+
errorText = 'Not a valid time';
|
643
|
+
}
|
644
|
+
return /*#__PURE__*/React.createElement(Components.GenericInputSection, {
|
645
|
+
key: fieldId,
|
646
|
+
label: field.label,
|
647
|
+
sectionStyle: sectionStyle,
|
648
|
+
isValid: () => this.isFieldValid(field, fieldId),
|
649
|
+
required: field.mandatory,
|
650
|
+
showError: this.state.showError,
|
651
|
+
errorText: errorText
|
652
|
+
}, /*#__PURE__*/React.createElement(View, {
|
653
|
+
style: styles.dateContainer
|
654
|
+
}, /*#__PURE__*/React.createElement(TouchableOpacity, {
|
655
|
+
style: styles.dateFieldButton,
|
656
|
+
onPress: () => this.onOpenDatePicker(field, fieldId)
|
657
|
+
}, /*#__PURE__*/React.createElement(View, {
|
658
|
+
style: styles.dateFieldContainer
|
659
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
660
|
+
style: styles.dateText
|
661
|
+
}, displayText || placeHolder), /*#__PURE__*/React.createElement(Icon, {
|
662
|
+
type: "font-awesome",
|
663
|
+
name: icon,
|
664
|
+
iconStyle: styles.dateIcon
|
665
|
+
}))), displayText ? /*#__PURE__*/React.createElement(TouchableOpacity, {
|
666
|
+
style: styles.dateClearButton,
|
667
|
+
onPress: () => this.onClearDate(fieldId)
|
668
|
+
}, /*#__PURE__*/React.createElement(Icon, {
|
669
|
+
type: "font-awesome",
|
670
|
+
name: "times",
|
671
|
+
iconStyle: styles.removeIcon
|
672
|
+
})) : null));
|
673
|
+
}
|
674
|
+
renderField(field, fieldId) {
|
675
|
+
const sectionStyle = {
|
676
|
+
marginTop: fieldId === 0 ? 24 : 0,
|
677
|
+
marginBottom: 24
|
678
|
+
};
|
679
|
+
switch (field.type) {
|
680
|
+
case 'yn':
|
681
|
+
return /*#__PURE__*/React.createElement(Components.GenericInputSection, {
|
682
|
+
key: fieldId,
|
683
|
+
label: field.label,
|
684
|
+
sectionStyle: sectionStyle,
|
685
|
+
inputType: "toggle",
|
686
|
+
value: field.answer,
|
687
|
+
onChange: answer => this.onChangeToggleAnswer(fieldId, answer),
|
688
|
+
isValid: () => this.isFieldValid(field, fieldId),
|
689
|
+
showError: this.state.showError,
|
690
|
+
required: field.mandatory
|
691
|
+
});
|
692
|
+
case 'multichoice':
|
693
|
+
return /*#__PURE__*/React.createElement(Components.GenericInputSection, {
|
694
|
+
key: fieldId,
|
695
|
+
label: field.label,
|
696
|
+
sectionStyle: sectionStyle,
|
697
|
+
inputType: "radio",
|
698
|
+
value: field.answer,
|
699
|
+
onChange: answer => this.onChangeToggleAnswer(fieldId, answer),
|
700
|
+
options: field.values.map(o => {
|
701
|
+
return {
|
702
|
+
Label: o,
|
703
|
+
Value: o
|
704
|
+
};
|
705
|
+
}),
|
706
|
+
isValid: () => this.isFieldValid(field, fieldId),
|
707
|
+
showError: this.state.showError,
|
708
|
+
required: field.mandatory
|
709
|
+
});
|
710
|
+
case 'checkbox':
|
711
|
+
return /*#__PURE__*/React.createElement(Components.GenericInputSection, {
|
712
|
+
key: fieldId,
|
713
|
+
label: field.label,
|
714
|
+
sectionStyle: sectionStyle,
|
715
|
+
isValid: () => this.isFieldValid(field, fieldId),
|
716
|
+
showError: this.state.showError,
|
717
|
+
required: field.mandatory
|
718
|
+
}, field.values.map((o, i) => {
|
719
|
+
const isActive = field.answer && _.includes(field.answer, o);
|
720
|
+
return /*#__PURE__*/React.createElement(TouchableOpacity, {
|
721
|
+
onPress: () => this.onChangeCheckboxAnswer(fieldId, o),
|
722
|
+
key: i,
|
723
|
+
style: styles.multiChoiceOption,
|
724
|
+
hitSlop: {
|
725
|
+
top: 8,
|
726
|
+
left: 8,
|
727
|
+
bottom: 8,
|
728
|
+
right: 8
|
729
|
+
}
|
730
|
+
}, isActive ? /*#__PURE__*/React.createElement(Components.TickIcon, {
|
731
|
+
style: styles.tick,
|
732
|
+
size: 20,
|
733
|
+
color: this.props.colourBrandingMain
|
734
|
+
}) : /*#__PURE__*/React.createElement(View, {
|
735
|
+
style: styles.unticked
|
736
|
+
}), /*#__PURE__*/React.createElement(Text, {
|
737
|
+
style: styles.multiChoiceText
|
738
|
+
}, o));
|
739
|
+
}));
|
740
|
+
case 'text':
|
741
|
+
case 'email':
|
742
|
+
case 'phone':
|
743
|
+
return /*#__PURE__*/React.createElement(Components.GenericInputSection, {
|
744
|
+
key: fieldId,
|
745
|
+
label: field.label,
|
746
|
+
placeholder: field.placeHolder,
|
747
|
+
value: field.answer,
|
748
|
+
onChangeText: val => this.onChangeAnswer(fieldId, val),
|
749
|
+
editable: true,
|
750
|
+
squaredCorners: true,
|
751
|
+
isValid: () => this.isFieldValid(field, fieldId),
|
752
|
+
showError: this.state.showError,
|
753
|
+
errorText: field.type === 'email' ? 'Not a valid email' : undefined,
|
754
|
+
required: field.mandatory,
|
755
|
+
sectionStyle: sectionStyle,
|
756
|
+
autoCapitalize: "sentences",
|
757
|
+
keyboardType: this.keyboardTypes[field.type]
|
758
|
+
});
|
759
|
+
case 'staticTitle':
|
760
|
+
return /*#__PURE__*/React.createElement(Text, {
|
761
|
+
key: fieldId,
|
762
|
+
style: [styles.staticTitle, {
|
763
|
+
color: this.props.colourBrandingMain
|
764
|
+
}, sectionStyle]
|
765
|
+
}, field.label);
|
766
|
+
case 'staticText':
|
767
|
+
return /*#__PURE__*/React.createElement(View, {
|
768
|
+
key: fieldId,
|
769
|
+
style: [styles.staticText, sectionStyle]
|
770
|
+
}, Helper.toParagraphed(field.label, styles.staticText));
|
771
|
+
case 'date':
|
772
|
+
case 'time':
|
773
|
+
return this.renderDateField(field, fieldId, sectionStyle);
|
774
|
+
case 'image':
|
775
|
+
return /*#__PURE__*/React.createElement(Components.GenericInputSection, {
|
776
|
+
key: fieldId,
|
777
|
+
label: field.label,
|
778
|
+
sectionStyle: sectionStyle,
|
779
|
+
isValid: () => this.isFieldValid(field, fieldId),
|
780
|
+
required: field.mandatory,
|
781
|
+
showError: this.state.showError
|
782
|
+
}, this.renderImageList(fieldId));
|
783
|
+
default:
|
784
|
+
return null;
|
785
|
+
}
|
786
|
+
}
|
787
|
+
renderCustomFields() {
|
788
|
+
const {
|
789
|
+
customFields
|
790
|
+
} = this.state;
|
791
|
+
if (!customFields || customFields.length === 0) return null;
|
792
|
+
return /*#__PURE__*/React.createElement(Components.FormCard, {
|
793
|
+
style: {
|
794
|
+
marginTop: 16
|
795
|
+
}
|
796
|
+
}, customFields.map((field, i) => this.renderField(field, i)));
|
797
|
+
}
|
405
798
|
renderForm() {
|
799
|
+
const {
|
800
|
+
customFields,
|
801
|
+
loadingTypes
|
802
|
+
} = this.state;
|
803
|
+
const hasCustomFields = customFields && customFields.length > 0;
|
804
|
+
if (loadingTypes) {
|
805
|
+
return /*#__PURE__*/React.createElement(Components.Spinner, null);
|
806
|
+
}
|
406
807
|
return /*#__PURE__*/React.createElement(View, {
|
407
808
|
style: {
|
408
809
|
flex: 1
|
@@ -464,7 +865,7 @@ class MaintenanceRequest extends Component {
|
|
464
865
|
},
|
465
866
|
required: true,
|
466
867
|
errorText: "Please provide your address.",
|
467
|
-
showError: this.state.showError && this.state.roomNumber
|
868
|
+
showError: this.state.showError && (!this.state.roomNumber || this.state.roomNumber.length < 2)
|
468
869
|
})), /*#__PURE__*/React.createElement(Components.FormCard, {
|
469
870
|
style: {
|
470
871
|
marginTop: 16,
|
@@ -493,7 +894,7 @@ class MaintenanceRequest extends Component {
|
|
493
894
|
fontSize: 20,
|
494
895
|
color: this.props.colourBrandingMain
|
495
896
|
}]
|
496
|
-
})))), /*#__PURE__*/React.createElement(Components.FormCard, {
|
897
|
+
})))), hasCustomFields ? this.renderCustomFields() : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Components.FormCard, {
|
497
898
|
style: {
|
498
899
|
marginTop: 16
|
499
900
|
}
|
@@ -576,11 +977,11 @@ class MaintenanceRequest extends Component {
|
|
576
977
|
autoCorrect: true,
|
577
978
|
multiline: true,
|
578
979
|
autoGrow: true
|
579
|
-
})), this.renderImageList())));
|
980
|
+
})), this.renderImageList()))));
|
580
981
|
}
|
581
982
|
renderRegisterConfirmation() {
|
582
983
|
return /*#__PURE__*/React.createElement(Components.ConfirmationPopup, {
|
583
|
-
confirmText:
|
984
|
+
confirmText: `${values.textEntityName} submitted`,
|
584
985
|
repeatText: 'Submit another',
|
585
986
|
visible: this.state.confirmationToShow,
|
586
987
|
onClose: this.onCloseConfirmationPopup.bind(this),
|
@@ -600,7 +1001,25 @@ class MaintenanceRequest extends Component {
|
|
600
1001
|
onClose: this.toggleFullscreenVideo
|
601
1002
|
});
|
602
1003
|
}
|
1004
|
+
renderNoType() {
|
1005
|
+
if (!this.state.noType) {
|
1006
|
+
return null;
|
1007
|
+
}
|
1008
|
+
return /*#__PURE__*/React.createElement(Components.WarningPopup, {
|
1009
|
+
confirmText: 'No forms are available',
|
1010
|
+
infoText: 'Check back later for forms.',
|
1011
|
+
visible: this.state.noType,
|
1012
|
+
onClose: this.onPressBack.bind(this),
|
1013
|
+
padHorizontal: true
|
1014
|
+
});
|
1015
|
+
}
|
603
1016
|
render() {
|
1017
|
+
const {
|
1018
|
+
submitting,
|
1019
|
+
success,
|
1020
|
+
isDateTimePickerVisible,
|
1021
|
+
popUpType
|
1022
|
+
} = this.state;
|
604
1023
|
return /*#__PURE__*/React.createElement(KeyboardAvoidingView, {
|
605
1024
|
behavior: Platform.OS === 'ios' && 'padding',
|
606
1025
|
style: styles.viewContainer
|
@@ -609,11 +1028,19 @@ class MaintenanceRequest extends Component {
|
|
609
1028
|
}, /*#__PURE__*/React.createElement(Components.Header, {
|
610
1029
|
leftIcon: "angle-left",
|
611
1030
|
onPressLeft: this.onPressBack.bind(this),
|
612
|
-
text:
|
613
|
-
rightText:
|
1031
|
+
text: this.props.strings[`${values.featureKey}_textFeatureTitle`] || values.textFeatureTitle,
|
1032
|
+
rightText: submitting || success ? null : 'Done',
|
614
1033
|
onPressRight: this.submitRequest.bind(this),
|
615
1034
|
absoluteRight: true
|
616
|
-
}), this.renderForm()), this.renderRegisterConfirmation(), this.renderVideoPlayerPopup())
|
1035
|
+
}), this.renderForm()), this.renderRegisterConfirmation(), this.renderVideoPlayerPopup(), this.renderNoType(), /*#__PURE__*/React.createElement(DateTimePicker, {
|
1036
|
+
isVisible: isDateTimePickerVisible,
|
1037
|
+
onConfirm: this.onDateSelected,
|
1038
|
+
onCancel: () => this.setState({
|
1039
|
+
isDateTimePickerVisible: false
|
1040
|
+
}),
|
1041
|
+
mode: popUpType,
|
1042
|
+
headerTextIOS: `Pick a ${popUpType}`
|
1043
|
+
}));
|
617
1044
|
}
|
618
1045
|
}
|
619
1046
|
const styles = {
|
@@ -715,9 +1142,76 @@ const styles = {
|
|
715
1142
|
height: 40,
|
716
1143
|
alignItems: 'center',
|
717
1144
|
justifyContent: 'center'
|
1145
|
+
},
|
1146
|
+
staticTitle: {
|
1147
|
+
fontSize: 20,
|
1148
|
+
fontFamily: 'sf-semibold',
|
1149
|
+
color: Colours.TEXT_DARKEST
|
1150
|
+
},
|
1151
|
+
staticText: {
|
1152
|
+
fontSize: 17,
|
1153
|
+
fontFamily: 'sf-regular',
|
1154
|
+
color: Colours.TEXT_DARKEST,
|
1155
|
+
lineHeight: 24
|
1156
|
+
},
|
1157
|
+
multiChoiceOption: {
|
1158
|
+
marginTop: 16,
|
1159
|
+
flexDirection: 'row',
|
1160
|
+
alignItems: 'center',
|
1161
|
+
minHeight: 20
|
1162
|
+
},
|
1163
|
+
multiChoiceText: {
|
1164
|
+
flex: 1,
|
1165
|
+
fontFamily: 'sf-medium',
|
1166
|
+
fontSize: 14,
|
1167
|
+
color: Colours.TEXT_DARK
|
1168
|
+
},
|
1169
|
+
tick: {
|
1170
|
+
marginRight: 10,
|
1171
|
+
borderRadius: 4
|
1172
|
+
},
|
1173
|
+
unticked: {
|
1174
|
+
marginRight: 10,
|
1175
|
+
width: 20,
|
1176
|
+
height: 20,
|
1177
|
+
borderColor: Colours.LINEGREY,
|
1178
|
+
borderWidth: 1,
|
1179
|
+
borderRadius: 4
|
1180
|
+
},
|
1181
|
+
dateContainer: {
|
1182
|
+
flexDirection: 'row',
|
1183
|
+
alignItems: 'center'
|
1184
|
+
},
|
1185
|
+
dateFieldButton: {
|
1186
|
+
flex: 1
|
1187
|
+
},
|
1188
|
+
dateFieldContainer: {
|
1189
|
+
flexDirection: 'row',
|
1190
|
+
borderRadius: 2,
|
1191
|
+
backgroundColor: '#ebeff2',
|
1192
|
+
padding: 8,
|
1193
|
+
marginTop: 8
|
1194
|
+
},
|
1195
|
+
dateText: {
|
1196
|
+
flex: 1,
|
1197
|
+
fontFamily: 'sf-regular',
|
1198
|
+
fontSize: 16,
|
1199
|
+
color: '#65686D'
|
1200
|
+
},
|
1201
|
+
dateIcon: {
|
1202
|
+
fontSize: 18,
|
1203
|
+
color: Colours.TEXT_BLUEGREY
|
1204
|
+
},
|
1205
|
+
dateClearButton: {
|
1206
|
+
paddingLeft: 12
|
1207
|
+
},
|
1208
|
+
removeIcon: {
|
1209
|
+
fontSize: 26,
|
1210
|
+
color: Colours.TEXT_BLUEGREY
|
718
1211
|
}
|
719
1212
|
};
|
720
1213
|
const mapStateToProps = state => {
|
1214
|
+
var _state$strings;
|
721
1215
|
const {
|
722
1216
|
user,
|
723
1217
|
connection
|
@@ -739,7 +1233,8 @@ const mapStateToProps = state => {
|
|
739
1233
|
site,
|
740
1234
|
unit,
|
741
1235
|
phoneNumber,
|
742
|
-
colourBrandingMain: Colours.getMainBrandingColourFromState(state)
|
1236
|
+
colourBrandingMain: Colours.getMainBrandingColourFromState(state),
|
1237
|
+
strings: ((_state$strings = state.strings) === null || _state$strings === void 0 ? void 0 : _state$strings.config) || {}
|
743
1238
|
};
|
744
1239
|
};
|
745
1240
|
export default connect(mapStateToProps, {
|