@plusscommunities/pluss-maintenance-app-forms 6.0.10 → 6.0.11-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.
Files changed (106) hide show
  1. package/dist/module/actions/JobActions.js +44 -1
  2. package/dist/module/actions/JobActions.js.map +1 -1
  3. package/dist/module/actions/index.js +1 -1
  4. package/dist/module/actions/index.js.map +1 -1
  5. package/dist/module/actions/types.js +4 -1
  6. package/dist/module/actions/types.js.map +1 -1
  7. package/dist/module/apis/index.js +4 -1
  8. package/dist/module/apis/index.js.map +1 -1
  9. package/dist/module/apis/maintenanceActions.js +61 -38
  10. package/dist/module/apis/maintenanceActions.js.map +1 -1
  11. package/dist/module/apis/userActions.js +23 -0
  12. package/dist/module/apis/userActions.js.map +1 -0
  13. package/dist/module/components/FilterPopupMenu.js +82 -58
  14. package/dist/module/components/FilterPopupMenu.js.map +1 -1
  15. package/dist/module/components/MaintenanceList.js +84 -92
  16. package/dist/module/components/MaintenanceList.js.map +1 -1
  17. package/dist/module/components/MaintenanceListItem.js +94 -80
  18. package/dist/module/components/MaintenanceListItem.js.map +1 -1
  19. package/dist/module/components/MaintenanceWidgetItem.js +39 -38
  20. package/dist/module/components/MaintenanceWidgetItem.js.map +1 -1
  21. package/dist/module/components/PrioritySelectorPopup.js +83 -0
  22. package/dist/module/components/PrioritySelectorPopup.js.map +1 -0
  23. package/dist/module/components/StatusSelectorPopup.js +23 -27
  24. package/dist/module/components/StatusSelectorPopup.js.map +1 -1
  25. package/dist/module/components/WidgetLarge.js +2 -2
  26. package/dist/module/components/WidgetLarge.js.map +1 -1
  27. package/dist/module/components/WidgetSmall.js +25 -20
  28. package/dist/module/components/WidgetSmall.js.map +1 -1
  29. package/dist/module/core.config.js +2 -3
  30. package/dist/module/core.config.js.map +1 -1
  31. package/dist/module/feature.config.js +17 -17
  32. package/dist/module/feature.config.js.map +1 -1
  33. package/dist/module/helper.js +41 -26
  34. package/dist/module/helper.js.map +1 -1
  35. package/dist/module/index.js +12 -10
  36. package/dist/module/index.js.map +1 -1
  37. package/dist/module/reducers/JobsReducer.js +36 -6
  38. package/dist/module/reducers/JobsReducer.js.map +1 -1
  39. package/dist/module/screens/JobTypePicker.js +18 -17
  40. package/dist/module/screens/JobTypePicker.js.map +1 -1
  41. package/dist/module/screens/MaintenancePage.js +10 -10
  42. package/dist/module/screens/MaintenancePage.js.map +1 -1
  43. package/dist/module/screens/MaintenanceUserPicker.js +219 -0
  44. package/dist/module/screens/MaintenanceUserPicker.js.map +1 -0
  45. package/dist/module/screens/RequestDetail.js +410 -142
  46. package/dist/module/screens/RequestDetail.js.map +1 -1
  47. package/dist/module/screens/RequestNotes.js +462 -52
  48. package/dist/module/screens/RequestNotes.js.map +1 -1
  49. package/dist/module/screens/ServiceRequest.js +519 -181
  50. package/dist/module/screens/ServiceRequest.js.map +1 -1
  51. package/dist/module/values.config.a.js +30 -23
  52. package/dist/module/values.config.a.js.map +1 -1
  53. package/dist/module/values.config.default.js +35 -28
  54. package/dist/module/values.config.default.js.map +1 -1
  55. package/dist/module/values.config.enquiry.js +43 -0
  56. package/dist/module/values.config.enquiry.js.map +1 -0
  57. package/dist/module/values.config.feedback.js +43 -0
  58. package/dist/module/values.config.feedback.js.map +1 -0
  59. package/dist/module/values.config.food.js +43 -0
  60. package/dist/module/values.config.food.js.map +1 -0
  61. package/dist/module/values.config.forms.js +35 -28
  62. package/dist/module/values.config.forms.js.map +1 -1
  63. package/dist/module/values.config.js +35 -28
  64. package/dist/module/values.config.js.map +1 -1
  65. package/package.json +55 -51
  66. package/src/actions/JobActions.js +75 -16
  67. package/src/actions/index.js +1 -1
  68. package/src/actions/types.js +4 -1
  69. package/src/apis/index.js +6 -1
  70. package/src/apis/maintenanceActions.js +189 -160
  71. package/src/apis/userActions.js +21 -0
  72. package/src/components/FilterPopupMenu.js +316 -230
  73. package/src/components/MaintenanceList.js +391 -326
  74. package/src/components/MaintenanceListItem.js +348 -274
  75. package/src/components/MaintenanceWidgetItem.js +146 -120
  76. package/src/components/PrioritySelectorPopup.js +93 -0
  77. package/src/components/StatusSelectorPopup.js +82 -76
  78. package/src/components/WidgetLarge.js +5 -5
  79. package/src/components/WidgetSmall.js +154 -131
  80. package/src/core.config.js +25 -3
  81. package/src/feature.config.js +62 -62
  82. package/src/helper.js +67 -30
  83. package/src/index.js +22 -20
  84. package/src/reducers/JobsReducer.js +85 -41
  85. package/src/screens/JobTypePicker.js +116 -92
  86. package/src/screens/MaintenancePage.js +89 -80
  87. package/src/screens/MaintenanceUserPicker.js +233 -0
  88. package/src/screens/RequestDetail.js +1354 -892
  89. package/src/screens/RequestNotes.js +946 -408
  90. package/src/screens/ServiceRequest.js +1808 -1222
  91. package/src/values.config.a.js +33 -26
  92. package/src/values.config.default.js +39 -32
  93. package/src/values.config.enquiry.js +43 -0
  94. package/src/values.config.feedback.js +43 -0
  95. package/src/values.config.food.js +43 -0
  96. package/src/values.config.forms.js +39 -32
  97. package/src/values.config.js +39 -32
  98. package/dist/module/values.config.b.js +0 -30
  99. package/dist/module/values.config.b.js.map +0 -1
  100. package/dist/module/values.config.c.js +0 -30
  101. package/dist/module/values.config.c.js.map +0 -1
  102. package/dist/module/values.config.d.js +0 -30
  103. package/dist/module/values.config.d.js.map +0 -1
  104. package/src/values.config.b.js +0 -30
  105. package/src/values.config.c.js +0 -30
  106. package/src/values.config.d.js +0 -30
@@ -1,418 +1,956 @@
1
- import React, { Component } from 'react';
2
- import { ScrollView, View, Text, TouchableOpacity, Modal, KeyboardAvoidingView, Platform } from 'react-native';
3
- import { connect } from 'react-redux';
4
- import { Icon } from 'react-native-elements';
5
- import _ from 'lodash';
6
- import moment from 'moment';
7
- import { jobAdded } from '../actions';
8
- import { maintenanceActions } from '../apis';
9
- import { getBottomSpace } from 'react-native-iphone-x-helper';
10
- import { Services } from '../feature.config';
11
- import { Components, Colours, Helper } from '../core.config';
12
- import { values } from '../values.config';
1
+ import React, { Component } from "react";
2
+ import { Text } from "@plusscommunities/pluss-core-app/components";
3
+ import {
4
+ ScrollView,
5
+ View,
6
+ TouchableOpacity,
7
+ Modal,
8
+ KeyboardAvoidingView,
9
+ Platform,
10
+ FlatList,
11
+ Dimensions,
12
+ ImageBackground,
13
+ Keyboard,
14
+ } from "react-native";
15
+ import { connect } from "react-redux";
16
+ import { Icon } from "@rneui/themed";
17
+ import _ from "lodash";
18
+ import moment from "moment";
19
+ import { jobAdded } from "../actions";
20
+ import { maintenanceActions } from "../apis";
21
+ import { getBottomSpace } from "react-native-iphone-x-helper";
22
+ import { Services } from "../feature.config";
23
+ import { Components, Colours, Helper } from "../core.config";
24
+ import { values } from "../values.config";
25
+
26
+ const SCREEN_WIDTH = Dimensions.get("window").width;
27
+ const PHOTO_SIZE = (SCREEN_WIDTH - 64) / 3;
13
28
 
14
29
  class RequestNotes extends Component {
15
- constructor(props) {
16
- super(props);
17
-
18
- this.state = {
19
- job: {},
20
- selectedPDF: null,
21
- noteAttachments: [],
22
- noteInput: '',
23
- addNoteOpen: false,
24
- };
25
- }
26
-
27
- componentDidMount() {
28
- this.updateJobState();
29
- }
30
-
31
- componentDidUpdate(prevProps) {
32
- if (prevProps.jobs !== this.props.jobs) {
33
- this.updateJobState();
34
- }
35
- }
36
-
37
- updateJobState() {
38
- const job = _.find(this.props.jobs, j => j.id === this.props.job.id) || this.props.job;
39
- this.setState({ job });
40
- }
41
-
42
- onPressBack = () => {
43
- Services.navigation.goBack();
44
- };
45
-
46
- onOpenAttachment = a => {
47
- this.setState({
48
- selectedPDF: a,
49
- });
50
- };
51
-
52
- onCloseAttachment = () => {
53
- this.setState({
54
- selectedPDF: null,
55
- });
56
- };
57
-
58
- onPressDeleteNote = n => {
59
- this.setState({
60
- noteToDelete: n,
61
- });
62
- };
63
-
64
- onPressConfirmDelete = () => {
65
- maintenanceActions.deleteNote(this.props.job.id, this.state.noteToDelete.Id);
66
- const newNotes = _.filter(this.state.job.Notes, note => {
67
- return note.Id !== this.state.noteToDelete.Id;
68
- });
69
- const newJob = { ...this.props.job };
70
- newJob.Notes = newNotes;
71
- this.props.jobAdded(newJob);
72
- this.props.onChange && this.props.onChange();
73
- this.setState({
74
- job: newJob,
75
- noteToDelete: null,
76
- });
77
- };
78
-
79
- onPressCancelDelete = () => {
80
- this.setState({ noteToDelete: null });
81
- };
82
-
83
- isReadyToSaveNote = () => {
84
- if (
85
- _.some(this.state.noteAttachments, n => {
86
- return n.Uploading;
87
- })
88
- ) {
89
- return false;
90
- }
91
- return !_.isEmpty(this.state.noteInput) || !_.isEmpty(this.state.noteAttachments);
92
- };
93
-
94
- openAddNote = () => {
95
- this.setState({
96
- addNoteOpen: true,
97
- editingNote: null,
98
- });
99
- };
100
-
101
- closeAddNote = () => {
102
- const newState = {
103
- addNoteOpen: false,
104
- editingNote: null,
105
- };
106
- if (!!this.state.editingNote) {
107
- newState.noteInput = '';
108
- newState.noteAttachments = [];
109
- }
110
- this.setState(newState);
111
- };
112
-
113
- openEditNote = n => {
114
- this.setState({
115
- noteAttachments: n.Attachments || [],
116
- noteInput: n.Note || '',
117
- addNoteOpen: true,
118
- editingNote: n.Id,
119
- noteMenuOpen: null,
120
- });
121
- };
122
-
123
- confirmAddNote = async () => {
124
- if (!this.isReadyToSaveNote()) {
125
- return;
126
- }
127
-
128
- try {
129
- this.setState({ submittingNote: true });
130
- const res = await (this.state.editingNote
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
- ));
152
- this.setState(
153
- {
154
- job: res.data.job,
155
- submittingNote: false,
156
- addNoteOpen: false,
157
- noteInput: '',
158
- noteAttachments: [],
159
- editingNote: null,
160
- },
161
- () => {
162
- this.props.jobAdded(res.data.job);
163
- this.props.onChange && this.props.onChange();
164
- },
165
- );
166
- } catch (err) {
167
- console.log('error');
168
- console.log(err);
169
- this.setState({
170
- submittingNote: false,
171
- });
172
- }
173
- };
174
-
175
- renderAttachment(a, i) {
176
- return (
177
- <Components.Attachment
178
- onPress={() => {
179
- this.onOpenAttachment(a);
180
- }}
181
- key={i}
182
- title={a.Title}
183
- />
184
- );
185
- }
186
-
187
- renderNote(n) {
188
- return (
189
- <View style={styles.noteContainer} key={n.Id}>
190
- <View style={styles.noteContainerTop}>
191
- <Components.ProfilePic Diameter={30} ProfilePic={n.User.profilePic} style={styles.profilePic} />
192
- <View style={styles.noteContainerTopRight}>
193
- {this.props.user.uid === n.User.id && (
194
- <TouchableOpacity
195
- onPress={() => {
196
- this.onPressDeleteNote(n);
197
- }}
198
- >
199
- <View style={[styles.noteContainerButtonContainer, { backgroundColor: this.props.colourBrandingMain }]}>
200
- <Icon name="trash" type="font-awesome" iconStyle={styles.noteContainerButtonIcon} />
201
- </View>
202
- </TouchableOpacity>
203
- )}
204
- {this.props.user.uid === n.User.id && (
205
- <TouchableOpacity
206
- onPress={() => {
207
- this.openEditNote(n);
208
- }}
209
- >
210
- <View style={[styles.noteContainerButtonContainer, { backgroundColor: this.props.colourBrandingMain }]}>
211
- <Icon name="pencil" type="font-awesome" iconStyle={styles.noteContainerButtonIcon} />
212
- </View>
213
- </TouchableOpacity>
214
- )}
215
- <View style={styles.noteContainerTopFill}>
216
- <Text style={styles.noteContainerName}>{n.User.displayName}</Text>
217
- </View>
218
- </View>
219
- </View>
220
- <Text style={styles.noteContainerText}>{n.Note}</Text>
221
- {(n.Attachments || []).map((a, i) => this.renderAttachment(a, i))}
222
- <Text style={styles.noteTimestamp}>
223
- {moment
224
- .utc(n.Timestamp)
225
- .local()
226
- .format(Helper.TIMESTAMP_FORMAT)}
227
- </Text>
228
- </View>
229
- );
230
- }
231
-
232
- renderNotes() {
233
- return (this.state.job.Notes || []).map((n, i) => {
234
- return this.renderNote(n, i);
235
- });
236
- }
237
-
238
- renderPDF() {
239
- if (_.isEmpty(this.state.selectedPDF)) {
240
- return null;
241
- }
242
- return (
243
- <Components.PDFPopup
244
- source={this.state.selectedPDF.Source}
245
- onClose={this.onCloseAttachment}
246
- title={this.state.selectedPDF.Title}
247
- pdfCount={1}
248
- />
249
- );
250
- }
251
-
252
- renderNoteDeleteConfirm() {
253
- return (
254
- <Components.ConfirmPopup
255
- visible={!!this.state.noteToDelete}
256
- onConfirm={this.onPressConfirmDelete}
257
- onCancel={this.onPressCancelDelete}
258
- onClose={this.onPressCancelDelete}
259
- text="Are you sure you want to delete this note?"
260
- />
261
- );
262
- }
263
-
264
- renderFooterContent() {
265
- if (this.state.submittingNote) {
266
- return <Components.Spinner />;
267
- }
268
- return (
269
- <Components.InlineButton color={this.props.colourBrandingMain} onPress={this.confirmAddNote} fillTouchable large>
270
- Save
271
- </Components.InlineButton>
272
- );
273
- }
274
-
275
- renderAdd() {
276
- return (
277
- <Modal animationType="slide" visible={this.state.addNoteOpen}>
278
- <KeyboardAvoidingView style={styles.container} behavior={Platform.OS === 'ios' && 'padding'}>
279
- <Components.Header leftText="Cancel" onPressLeft={this.closeAddNote} text="" />
280
- <ScrollView style={styles.scrollContainer} contentContainerStyle={styles.innerContainer}>
281
- <Components.TextStyle type="pageHeading">Add Staff Note</Components.TextStyle>
282
- <Components.GenericInputSection
283
- label="Content"
284
- placeholder="Insert your notes here..."
285
- value={this.state.noteInput}
286
- onChangeText={noteInput => this.setState({ noteInput })}
287
- isValid={() => {
288
- return !_.isEmpty(this.state.noteInput);
289
- }}
290
- autoCapitalize="sentences"
291
- minHeight={135}
292
- autoCorrect
293
- multiline
294
- autoGrow
295
- required
296
- squaredCorners
297
- sectionStyle={styles.inputSection}
298
- />
299
- <Components.GenericInputSection label="Attachments" sectionStyle={styles.inputSection}>
300
- {this.state.editingNote ? (
301
- (this.state.noteAttachments || []).map((a, i) => this.renderAttachment(a, i))
302
- ) : (
303
- <Components.TextStyle type="body" style={styles.attachmentInfo}>
304
- PDFs can only be attached to notes from the Community Manager.
305
- </Components.TextStyle>
306
- )}
307
- </Components.GenericInputSection>
308
- </ScrollView>
309
- <View style={styles.popupFooter}>{this.renderFooterContent()}</View>
310
- </KeyboardAvoidingView>
311
- </Modal>
312
- );
313
- }
314
-
315
- render() {
316
- return (
317
- <View style={styles.container}>
318
- {this.renderPDF()}
319
- {this.renderNoteDeleteConfirm()}
320
- {this.renderAdd()}
321
- <Components.Header leftIcon="angle-left" onPressLeft={this.onPressBack} text="Staff Notes" />
322
- <ScrollView style={styles.scrollContainer} contentContainerStyle={styles.innerContainer}>
323
- {this.renderNotes()}
324
- </ScrollView>
325
- <Components.AddButton onPress={this.openAddNote} />
326
- </View>
327
- );
328
- }
30
+ constructor(props) {
31
+ super(props);
32
+
33
+ this.state = {
34
+ job: {},
35
+ selectedPDF: null,
36
+ noteAttachments: [],
37
+ noteInput: "",
38
+ addNoteOpen: false,
39
+ noteImages: [{ add: true }],
40
+ uploadingImage: false,
41
+ galleryOpen: false,
42
+ galleryImages: [],
43
+ galleryIndex: 0,
44
+ };
45
+ this.checkThumb = null;
46
+ }
47
+
48
+ componentDidMount() {
49
+ this.updateJobState();
50
+ }
51
+
52
+ componentDidUpdate(prevProps) {
53
+ if (prevProps.jobs !== this.props.jobs) {
54
+ this.updateJobState();
55
+ }
56
+ }
57
+
58
+ componentWillUnmount() {
59
+ clearInterval(this.checkThumb);
60
+ }
61
+
62
+ updateJobState() {
63
+ const job =
64
+ _.find(this.props.jobs, (j) => j.id === this.props.job.id) ||
65
+ this.props.job;
66
+ this.setState({ job });
67
+ }
68
+
69
+ onPressBack = () => {
70
+ Services.navigation.goBack();
71
+ };
72
+
73
+ onOpenAttachment = (a) => {
74
+ this.setState({
75
+ selectedPDF: a,
76
+ });
77
+ };
78
+
79
+ onCloseAttachment = () => {
80
+ this.setState({
81
+ selectedPDF: null,
82
+ });
83
+ };
84
+
85
+ onPressDeleteNote = (n) => {
86
+ this.setState({
87
+ noteToDelete: n,
88
+ });
89
+ };
90
+
91
+ onPressConfirmDelete = () => {
92
+ maintenanceActions.deleteNote(
93
+ this.props.job.id,
94
+ this.state.noteToDelete.Id,
95
+ );
96
+ const newNotes = _.filter(this.state.job.Notes, (note) => {
97
+ return note.Id !== this.state.noteToDelete.Id;
98
+ });
99
+ const newJob = { ...this.props.job };
100
+ newJob.Notes = newNotes;
101
+ this.props.jobAdded(newJob);
102
+ this.props.onChange && this.props.onChange();
103
+ this.setState({
104
+ job: newJob,
105
+ noteToDelete: null,
106
+ });
107
+ };
108
+
109
+ onPressCancelDelete = () => {
110
+ this.setState({ noteToDelete: null });
111
+ };
112
+
113
+ isReadyToSaveNote = () => {
114
+ const uploadingAttachments = _.some(
115
+ this.state.noteAttachments,
116
+ (n) => n.Uploading,
117
+ );
118
+ const uploadingImages = _.some(this.state.noteImages, (n) => n.uploading);
119
+ if (uploadingAttachments || uploadingImages) return false;
120
+ return (
121
+ !_.isEmpty(this.state.noteInput) ||
122
+ !_.isEmpty(this.state.noteAttachments) ||
123
+ !_.isEmpty(this.state.noteImages.filter((img) => !img.add))
124
+ );
125
+ };
126
+
127
+ openAddNote = () => {
128
+ this.setState({
129
+ addNoteOpen: true,
130
+ editingNote: null,
131
+ });
132
+ };
133
+
134
+ closeAddNote = () => {
135
+ const newState = {
136
+ addNoteOpen: false,
137
+ editingNote: null,
138
+ };
139
+ if (!!this.state.editingNote) {
140
+ newState.noteInput = "";
141
+ newState.noteAttachments = [];
142
+ newState.noteImages = [];
143
+ }
144
+ this.setState(newState);
145
+ };
146
+
147
+ openEditNote = (n) => {
148
+ const noteImages = [
149
+ ...(n.Images || []).map((i) => ({
150
+ url: i,
151
+ thumbNailUrl: Helper.getThumb300(i),
152
+ })),
153
+ { add: true },
154
+ ];
155
+ this.setState({
156
+ noteAttachments: n.Attachments || [],
157
+ noteImages,
158
+ noteInput: n.Note || "",
159
+ addNoteOpen: true,
160
+ editingNote: n.Id,
161
+ noteMenuOpen: null,
162
+ });
163
+ };
164
+
165
+ confirmAddNote = async () => {
166
+ if (!this.isReadyToSaveNote()) {
167
+ return;
168
+ }
169
+
170
+ try {
171
+ this.setState({ submittingNote: true });
172
+ const attachments = this.state.noteAttachments
173
+ .filter((a) => !a.add)
174
+ .map((a) => {
175
+ return {
176
+ Title: a.Title,
177
+ Source: a.Source,
178
+ };
179
+ });
180
+ const images = this.state.noteImages
181
+ .filter((img) => !img.add)
182
+ .map((img) => img.url);
183
+ const res = await (this.state.editingNote
184
+ ? maintenanceActions.editNote(
185
+ this.props.job.id,
186
+ this.state.editingNote,
187
+ this.state.noteInput,
188
+ attachments,
189
+ images,
190
+ )
191
+ : maintenanceActions.addNote(
192
+ this.props.job.id,
193
+ this.state.noteInput,
194
+ attachments,
195
+ images,
196
+ ));
197
+ this.setState(
198
+ {
199
+ job: res.data.job,
200
+ submittingNote: false,
201
+ addNoteOpen: false,
202
+ noteInput: "",
203
+ noteAttachments: [],
204
+ noteImages: [{ add: true }],
205
+ uploadingImage: false,
206
+ editingNote: null,
207
+ },
208
+ () => {
209
+ this.props.jobAdded(res.data.job);
210
+ this.props.onChange && this.props.onChange();
211
+ },
212
+ );
213
+ } catch (err) {
214
+ console.log("error");
215
+ console.log(err);
216
+ this.setState({
217
+ submittingNote: false,
218
+ uploadingImage: false,
219
+ });
220
+ }
221
+ };
222
+
223
+ setImages = (noteImages, uploadingImage = false, callback = null) => {
224
+ this.setState({ noteImages, uploadingImage }, callback);
225
+ };
226
+
227
+ getImages = () => {
228
+ const { noteImages } = this.state;
229
+ const imagesList = _.cloneDeep(noteImages);
230
+ if (!imagesList || !Array.isArray(imagesList) || imagesList.length === 0) {
231
+ return [{ add: true }];
232
+ }
233
+ return imagesList;
234
+ };
235
+
236
+ getImageUrls = () => {
237
+ const imagesList = this.getImages();
238
+ return _.filter(imagesList, (img) => {
239
+ return !img.uploading && !img.add;
240
+ }).map((img) => {
241
+ return img.url;
242
+ });
243
+ };
244
+
245
+ waitForThumbnails = () => {
246
+ if (this.checkThumb) return;
247
+
248
+ this.checkThumb = setInterval(async () => {
249
+ const imagesList = this.getImages();
250
+ const imagesUpdate = [];
251
+ await Promise.all(
252
+ imagesList.map((image) => {
253
+ return new Promise(async (resolve) => {
254
+ const newImage = { ...image };
255
+ imagesUpdate.push(newImage);
256
+ if (newImage.url && !newImage.thumbNailExists) {
257
+ newImage.uploading = false;
258
+ newImage.allowRetry = false;
259
+ newImage.thumbNailExists = await Helper.imageExists(
260
+ newImage.thumbNailUrl,
261
+ );
262
+ resolve(newImage.thumbNailExists);
263
+ }
264
+ resolve(true);
265
+ });
266
+ }),
267
+ );
268
+ const thumbnailsExist = imagesUpdate.every(
269
+ (image) => !image.url || image.thumbNailExists,
270
+ );
271
+ if (thumbnailsExist) {
272
+ clearInterval(this.checkThumb);
273
+ this.checkThumb = null;
274
+ this.setImages(imagesUpdate);
275
+ }
276
+ }, 2000);
277
+ };
278
+
279
+ removeImage = (index) => {
280
+ const imagesUpdate = this.getImages();
281
+ imagesUpdate.splice(index, 1);
282
+
283
+ this.setImages(imagesUpdate);
284
+ };
285
+
286
+ showUploadMenu = () => {
287
+ Keyboard.dismiss();
288
+ const { uploadingImage, submittingNote } = this.state;
289
+ if (uploadingImage || submittingNote) return;
290
+ this.imageUploader.showUploadMenu();
291
+ };
292
+
293
+ toggleFullscreenVideo = (url) => {
294
+ if (typeof url !== "string") url = "";
295
+ this.setState({
296
+ showFullscreenVideo: url.length > 0,
297
+ currentVideoUrl: url,
298
+ });
299
+ };
300
+
301
+ openGallery(images, index) {
302
+ this.setState({
303
+ galleryOpen: true,
304
+ galleryImages: images,
305
+ galleryIndex: index,
306
+ });
307
+ }
308
+
309
+ closeGallery() {
310
+ this.setState({ galleryOpen: false, galleryImages: [], galleryIndex: 0 });
311
+ }
312
+
313
+ onUploadStarted = (uploadUri, imageUri) => {
314
+ const imagesUpdate = this.getImages();
315
+ imagesUpdate.splice(imagesUpdate.length - 1, 0, {
316
+ uploading: true,
317
+ uploadProgress: "0%",
318
+ uploadUri,
319
+ imageUri,
320
+ allowRetry: true,
321
+ });
322
+
323
+ this.setImages(imagesUpdate, true);
324
+ };
325
+
326
+ onUploadProgress = (progress) => {
327
+ const imagesUpdate = this.getImages();
328
+ imagesUpdate.map((img) => {
329
+ if (img.uploadUri === progress.uri) {
330
+ img.uploadProgress = progress.percentage;
331
+ img.uploading = true;
332
+ img.allowRetry = true;
333
+ }
334
+ });
335
+
336
+ this.setImages(imagesUpdate, true);
337
+ };
338
+
339
+ onUploadSuccess = async (uri, uploadUri) => {
340
+ const imagesUpdate = this.getImages();
341
+ imagesUpdate.map((img) => {
342
+ if (img.uploadUri === uploadUri && img.uploading) {
343
+ img.url = uri.replace("/general/", "/general1400/");
344
+ img.thumbNailExists = false;
345
+ img.thumbNailUrl = Helper.getThumb300(img.url);
346
+ img.allowRetry = true;
347
+ }
348
+ });
349
+
350
+ this.setImages(imagesUpdate, false, () => this.waitForThumbnails());
351
+ };
352
+
353
+ onUploadFailed = (uploadUri) => {
354
+ const imagesUpdate = this.getImages();
355
+ imagesUpdate.map((img) => {
356
+ if (img.uploadUri === uploadUri) {
357
+ img.uploading = true; // Requried for retry
358
+ img.uploadProgress = "";
359
+ img.allowRetry = true;
360
+ }
361
+ });
362
+
363
+ this.setImages(imagesUpdate);
364
+ };
365
+
366
+ onLibrarySelected = (uri) => {
367
+ const imagesUpdate = this.getImages();
368
+ imagesUpdate.splice(imagesUpdate.length - 1, 0, {
369
+ uploading: false,
370
+ allowRetry: false,
371
+ url: Helper.get1400(uri),
372
+ thumbNailExists: true,
373
+ thumbNailUrl: Helper.getThumb300(uri),
374
+ });
375
+
376
+ this.setImages(imagesUpdate);
377
+ };
378
+
379
+ renderAttachment(a, i) {
380
+ return (
381
+ <Components.Attachment
382
+ onPress={() => {
383
+ this.onOpenAttachment(a);
384
+ }}
385
+ key={i}
386
+ title={a.Title}
387
+ />
388
+ );
389
+ }
390
+
391
+ renderPlayableImageUrl(images, index, containerStyle) {
392
+ const url = images[index];
393
+ const thumbUrl = Helper.getThumb300(url);
394
+
395
+ if (Helper.isVideo(url)) {
396
+ return (
397
+ <ImageBackground
398
+ style={[{ flex: 1 }, containerStyle]}
399
+ source={{ uri: thumbUrl }}
400
+ >
401
+ <View style={styles.imagePlayContainer}>
402
+ <TouchableOpacity
403
+ onPress={this.toggleFullscreenVideo.bind(this, url)}
404
+ >
405
+ <Icon
406
+ name="play"
407
+ type="font-awesome"
408
+ iconStyle={styles.imageControlIcon}
409
+ />
410
+ </TouchableOpacity>
411
+ </View>
412
+ </ImageBackground>
413
+ );
414
+ }
415
+
416
+ const imageUrl = Helper.get1400(url);
417
+ return (
418
+ <TouchableOpacity
419
+ style={containerStyle}
420
+ onPress={this.openGallery.bind(this, images, index || 0)}
421
+ >
422
+ <ImageBackground
423
+ resizeMode="cover"
424
+ style={styles.imageContainer}
425
+ source={{ uri: imageUrl }}
426
+ />
427
+ </TouchableOpacity>
428
+ );
429
+ }
430
+
431
+ renderImages(note) {
432
+ if (!note) return null;
433
+ if (!_.isNil(note.Images) && !_.isEmpty(note.Images)) {
434
+ return (
435
+ <ScrollView horizontal style={styles.sideBySideImages}>
436
+ {note.Images.map((_p, index) =>
437
+ this.renderPlayableImageUrl(
438
+ note.Images,
439
+ index,
440
+ styles.sideBySideImageContainer,
441
+ ),
442
+ )}
443
+ </ScrollView>
444
+ );
445
+ }
446
+ return null;
447
+ }
448
+
449
+ renderImagePopup() {
450
+ const { galleryOpen, galleryImages, galleryIndex } = this.state;
451
+ console.log("renderimagepopup", {
452
+ galleryOpen,
453
+ galleryImages,
454
+ galleryIndex,
455
+ });
456
+ return (
457
+ <Components.ImagePopup
458
+ visible={galleryOpen}
459
+ images={galleryImages}
460
+ index={galleryIndex}
461
+ onClose={this.closeGallery.bind(this)}
462
+ />
463
+ );
464
+ }
465
+
466
+ renderNote(n) {
467
+ return (
468
+ <View style={styles.noteContainer} key={n.Id}>
469
+ <View style={styles.noteContainerTop}>
470
+ <Components.ProfilePic
471
+ Diameter={30}
472
+ ProfilePic={n.User.profilePic}
473
+ style={styles.profilePic}
474
+ />
475
+ <View style={styles.noteContainerTopRight}>
476
+ {this.props.user.uid === n.User.id && (
477
+ <TouchableOpacity
478
+ onPress={() => {
479
+ this.onPressDeleteNote(n);
480
+ }}
481
+ >
482
+ <View
483
+ style={[
484
+ styles.noteContainerButtonContainer,
485
+ { backgroundColor: this.props.colourBrandingMain },
486
+ ]}
487
+ >
488
+ <Icon
489
+ name="trash"
490
+ type="font-awesome"
491
+ iconStyle={styles.noteContainerButtonIcon}
492
+ />
493
+ </View>
494
+ </TouchableOpacity>
495
+ )}
496
+ {this.props.user.uid === n.User.id && (
497
+ <TouchableOpacity
498
+ onPress={() => {
499
+ this.openEditNote(n);
500
+ }}
501
+ >
502
+ <View
503
+ style={[
504
+ styles.noteContainerButtonContainer,
505
+ { backgroundColor: this.props.colourBrandingMain },
506
+ ]}
507
+ >
508
+ <Icon
509
+ name="pencil"
510
+ type="font-awesome"
511
+ iconStyle={styles.noteContainerButtonIcon}
512
+ />
513
+ </View>
514
+ </TouchableOpacity>
515
+ )}
516
+ <View style={styles.noteContainerTopFill}>
517
+ <Text style={styles.noteContainerName}>{n.User.displayName}</Text>
518
+ </View>
519
+ </View>
520
+ </View>
521
+ <Text style={styles.noteContainerText}>{n.Note}</Text>
522
+ {(n.Attachments || []).map((a, i) => this.renderAttachment(a, i))}
523
+ {this.renderImages(n)}
524
+ <Text style={styles.noteTimestamp}>
525
+ {moment.utc(n.Timestamp).local().format(Helper.TIMESTAMP_FORMAT)}
526
+ </Text>
527
+ </View>
528
+ );
529
+ }
530
+
531
+ renderNotes() {
532
+ return (this.state.job.Notes || []).map((n, i) => {
533
+ return this.renderNote(n, i);
534
+ });
535
+ }
536
+
537
+ renderPDF() {
538
+ if (_.isEmpty(this.state.selectedPDF)) {
539
+ return null;
540
+ }
541
+ return (
542
+ <Components.PDFPopup
543
+ source={this.state.selectedPDF.Source}
544
+ onClose={this.onCloseAttachment}
545
+ title={this.state.selectedPDF.Title}
546
+ pdfCount={1}
547
+ />
548
+ );
549
+ }
550
+
551
+ renderNoteDeleteConfirm() {
552
+ return (
553
+ <Components.ConfirmPopup
554
+ visible={!!this.state.noteToDelete}
555
+ onConfirm={this.onPressConfirmDelete}
556
+ onCancel={this.onPressCancelDelete}
557
+ onClose={this.onPressCancelDelete}
558
+ text="Are you sure you want to delete this note?"
559
+ />
560
+ );
561
+ }
562
+
563
+ renderFooterContent() {
564
+ if (this.state.submittingNote) {
565
+ return <Components.Spinner />;
566
+ }
567
+ return (
568
+ <Components.InlineButton
569
+ color={this.props.colourBrandingMain}
570
+ onPress={this.confirmAddNote}
571
+ fillTouchable
572
+ large
573
+ >
574
+ Save
575
+ </Components.InlineButton>
576
+ );
577
+ }
578
+
579
+ renderUploadMenu() {
580
+ return (
581
+ <Components.ImageUploader
582
+ ref={(ref) => (this.imageUploader = ref)}
583
+ onUploadStarted={this.onUploadStarted}
584
+ onUploadSuccess={this.onUploadSuccess}
585
+ onUploadFailed={this.onUploadFailed}
586
+ onUploadProgress={this.onUploadProgress}
587
+ onLibrarySelected={this.onLibrarySelected}
588
+ size={{ width: 1400 }}
589
+ quality={0.8}
590
+ fileName={"serviceNoteImage"}
591
+ popupTitle={"Upload Image"}
592
+ userId={this.props.user.uid}
593
+ allowsEditing={false}
594
+ multiple
595
+ hideLibrary
596
+ />
597
+ );
598
+ }
599
+
600
+ renderImage(item, index) {
601
+ const isVideoUrl = Helper.isVideo(item.url);
602
+ const imagesList = this.getImages();
603
+
604
+ if (item.add) {
605
+ return (
606
+ <TouchableOpacity
607
+ activeOpacity={0.8}
608
+ onPress={() => this.showUploadMenu()}
609
+ >
610
+ <View
611
+ style={[
612
+ styles.imageContainer,
613
+ imagesList.length > 1 && styles.imageContainerNotEmpty,
614
+ index % 3 === 0 && { marginLeft: 0 },
615
+ index > 2 && { marginTop: 8 },
616
+ ]}
617
+ >
618
+ <View style={styles.imageCircle}>
619
+ <Icon
620
+ name="camera"
621
+ type="font-awesome"
622
+ iconStyle={styles.addImageIcon}
623
+ />
624
+ </View>
625
+ </View>
626
+ </TouchableOpacity>
627
+ );
628
+ }
629
+ return (
630
+ <View
631
+ style={[
632
+ styles.imageContainer,
633
+ imagesList.length > 1 && styles.imageContainerNotEmpty,
634
+ index % 3 === 0 && { marginLeft: 0 },
635
+ index > 2 && { marginTop: 8 },
636
+ ]}
637
+ >
638
+ {item.uploading ? (
639
+ <Components.ImageUploadProgress
640
+ uploader={this.imageUploader}
641
+ image={item}
642
+ color={this.props.colourBrandingMain}
643
+ />
644
+ ) : (
645
+ <ImageBackground
646
+ style={styles.imageBackground}
647
+ source={Helper.getImageSource(
648
+ item.thumbNailExists ? item.thumbNailUrl : item.url || item,
649
+ )}
650
+ >
651
+ {isVideoUrl && (
652
+ <View style={styles.imagePlayContainer}>
653
+ <TouchableOpacity
654
+ onPress={this.toggleFullscreenVideo.bind(this, item.url)}
655
+ >
656
+ <Icon
657
+ name="play"
658
+ type="font-awesome"
659
+ iconStyle={styles.imageControlIcon}
660
+ />
661
+ </TouchableOpacity>
662
+ </View>
663
+ )}
664
+ <TouchableOpacity
665
+ style={styles.removeImage}
666
+ onPress={() => this.removeImage(index)}
667
+ >
668
+ <Icon
669
+ name="remove"
670
+ type="font-awesome"
671
+ iconStyle={styles.imageControlIcon}
672
+ style={styles.removeImage}
673
+ />
674
+ </TouchableOpacity>
675
+ </ImageBackground>
676
+ )}
677
+ </View>
678
+ );
679
+ }
680
+
681
+ renderImageList() {
682
+ const imagesList = this.getImages();
683
+
684
+ return (
685
+ <View style={styles.imageListContainer}>
686
+ <FlatList
687
+ keyboardShouldPersistTaps="always"
688
+ enableEmptySections
689
+ data={imagesList}
690
+ renderItem={({ item, index }) => this.renderImage(item, index)}
691
+ keyExtractor={(item, index) => index}
692
+ numColumns={3}
693
+ scrollEnabled={false}
694
+ />
695
+ </View>
696
+ );
697
+ }
698
+
699
+ renderVideoPlayerPopup() {
700
+ const { showFullscreenVideo, currentVideoUrl } = this.state;
701
+ if (!currentVideoUrl) return;
702
+
703
+ return (
704
+ <Components.VideoPopup
705
+ uri={currentVideoUrl}
706
+ visible={showFullscreenVideo}
707
+ showFullscreenButton={false}
708
+ onClose={this.toggleFullscreenVideo}
709
+ />
710
+ );
711
+ }
712
+
713
+ renderAdd() {
714
+ return (
715
+ <Modal animationType="slide" visible={this.state.addNoteOpen}>
716
+ <KeyboardAvoidingView style={styles.container} behavior={"padding"}>
717
+ {this.renderUploadMenu()}
718
+ <Components.Header
719
+ leftText="Cancel"
720
+ onPressLeft={this.closeAddNote}
721
+ text=""
722
+ />
723
+ <ScrollView
724
+ style={styles.scrollContainer}
725
+ contentContainerStyle={styles.innerContainer}
726
+ >
727
+ <Components.Text type="pageHeading">Add Staff Note</Components.Text>
728
+ <Components.GenericInputSection
729
+ label="Content"
730
+ placeholder="Insert your notes here..."
731
+ value={this.state.noteInput}
732
+ onChangeText={(noteInput) => this.setState({ noteInput })}
733
+ isValid={() => {
734
+ return !_.isEmpty(this.state.noteInput);
735
+ }}
736
+ autoCapitalize="sentences"
737
+ minHeight={135}
738
+ autoCorrect
739
+ multiline
740
+ autoGrow
741
+ required
742
+ squaredCorners
743
+ sectionStyle={styles.inputSection}
744
+ />
745
+ <Components.GenericInputSection
746
+ label="Attachments"
747
+ sectionStyle={styles.inputSection}
748
+ >
749
+ {this.renderImageList()}
750
+ {this.state.editingNote ? (
751
+ (this.state.noteAttachments || []).map((a, i) =>
752
+ this.renderAttachment(a, i),
753
+ )
754
+ ) : (
755
+ <Components.Text type="body" style={styles.attachmentInfo}>
756
+ PDFs can only be attached to notes from the Community Manager.
757
+ </Components.Text>
758
+ )}
759
+ </Components.GenericInputSection>
760
+ </ScrollView>
761
+ <View style={styles.popupFooter}>{this.renderFooterContent()}</View>
762
+ {this.renderVideoPlayerPopup()}
763
+ </KeyboardAvoidingView>
764
+ </Modal>
765
+ );
766
+ }
767
+
768
+ render() {
769
+ return (
770
+ <View style={styles.container}>
771
+ {this.renderPDF()}
772
+ {this.renderNoteDeleteConfirm()}
773
+ {this.renderAdd()}
774
+ <Components.Header
775
+ leftIcon="angle-left"
776
+ onPressLeft={this.onPressBack}
777
+ text="Staff Notes"
778
+ />
779
+ <ScrollView
780
+ style={styles.scrollContainer}
781
+ contentContainerStyle={styles.innerContainer}
782
+ >
783
+ {this.renderNotes()}
784
+ </ScrollView>
785
+ <Components.AddButton onPress={this.openAddNote} />
786
+ {this.renderImagePopup()}
787
+ </View>
788
+ );
789
+ }
329
790
  }
330
791
 
331
792
  const styles = {
332
- container: {
333
- flex: 1,
334
- position: 'relative',
335
- backgroundColor: '#fff',
336
- },
337
- scrollContainer: {
338
- flex: 1,
339
- },
340
- innerContainer: {
341
- padding: 16,
342
- },
343
- popupFooter: {
344
- paddingHorizontal: 16,
345
- paddingBottom: getBottomSpace() + 16,
346
- },
347
- noteContainer: {
348
- ...Helper.getShadowStyle(),
349
- padding: 8,
350
- marginBottom: 16,
351
- },
352
- noteContainerTop: {
353
- flexDirection: 'row',
354
- alignItems: 'center',
355
- },
356
- profilePic: {
357
- marginRight: 8,
358
- },
359
- noteContainerTopFill: {
360
- flex: 1,
361
- },
362
- noteContainerName: {
363
- fontFamily: 'sf-semibold',
364
- fontSize: 13,
365
- color: Colours.TEXT_DARKEST,
366
- },
367
- noteContainerText: {
368
- marginTop: 8,
369
- fontFamily: 'sf-regular',
370
- fontSize: 13,
371
- color: Colours.TEXT_DARKEST,
372
- },
373
- noteTimestamp: {
374
- marginTop: 8,
375
- fontFamily: 'sf-semibold',
376
- fontSize: 11,
377
- color: Colours.TEXT_LIGHT,
378
- },
379
- noteContainerTopRight: {
380
- flex: 1,
381
- flexDirection: 'row-reverse',
382
- alignItems: 'center',
383
- },
384
- noteContainerButtonContainer: {
385
- width: 24,
386
- height: 24,
387
- borderRadius: 12,
388
- alignItems: 'center',
389
- justifyContent: 'center',
390
- marginLeft: 8,
391
- },
392
- noteContainerButtonIcon: {
393
- fontSize: 13,
394
- color: '#fff',
395
- },
396
- inputSection: {
397
- marginTop: 24,
398
- },
399
- sectionHeading: {
400
- fontFamily: 'qs-bold',
401
- fontSize: 24,
402
- color: Colours.TEXT_DARKEST,
403
- },
404
- attachmentInfo: {
405
- marginTop: 8,
406
- },
793
+ container: {
794
+ flex: 1,
795
+ position: "relative",
796
+ backgroundColor: "#fff",
797
+ },
798
+ scrollContainer: {
799
+ flex: 1,
800
+ },
801
+ innerContainer: {
802
+ padding: 16,
803
+ },
804
+ popupFooter: {
805
+ paddingHorizontal: 16,
806
+ paddingBottom: getBottomSpace() + 16,
807
+ },
808
+ noteContainer: {
809
+ ...Helper.getShadowStyle(),
810
+ padding: 8,
811
+ marginBottom: 16,
812
+ },
813
+ noteContainerTop: {
814
+ flexDirection: "row",
815
+ alignItems: "center",
816
+ },
817
+ profilePic: {
818
+ marginRight: 8,
819
+ },
820
+ noteContainerTopFill: {
821
+ flex: 1,
822
+ },
823
+ noteContainerName: {
824
+ fontFamily: "sf-semibold",
825
+ fontSize: 13,
826
+ color: Colours.TEXT_DARKEST,
827
+ },
828
+ noteContainerText: {
829
+ marginTop: 8,
830
+ fontFamily: "sf-regular",
831
+ fontSize: 13,
832
+ color: Colours.TEXT_DARKEST,
833
+ },
834
+ noteTimestamp: {
835
+ marginTop: 8,
836
+ fontFamily: "sf-semibold",
837
+ fontSize: 11,
838
+ color: Colours.TEXT_LIGHT,
839
+ },
840
+ noteContainerTopRight: {
841
+ flex: 1,
842
+ flexDirection: "row-reverse",
843
+ alignItems: "center",
844
+ },
845
+ noteContainerButtonContainer: {
846
+ width: 24,
847
+ height: 24,
848
+ borderRadius: 12,
849
+ alignItems: "center",
850
+ justifyContent: "center",
851
+ marginLeft: 8,
852
+ },
853
+ noteContainerButtonIcon: {
854
+ fontSize: 13,
855
+ color: "#fff",
856
+ },
857
+ inputSection: {
858
+ marginTop: 24,
859
+ },
860
+ sectionHeading: {
861
+ fontFamily: "qs-bold",
862
+ fontSize: 24,
863
+ color: Colours.TEXT_DARKEST,
864
+ },
865
+ attachmentInfo: {
866
+ marginTop: 8,
867
+ },
868
+ imageListContainer: {
869
+ marginVertical: 8,
870
+ },
871
+ imageContainer: {
872
+ width: PHOTO_SIZE,
873
+ height: PHOTO_SIZE,
874
+ borderStyle: "dashed",
875
+ justifyContent: "center",
876
+ alignItems: "center",
877
+ borderWidth: 1,
878
+ borderColor: Colours.LINEGREY,
879
+ backgroundColor: Colours.BOXGREY,
880
+ borderRadius: 4,
881
+ marginLeft: 8,
882
+ },
883
+ imageContainerNotEmpty: {
884
+ borderWidth: 1,
885
+ borderColor: Colours.LINEGREY,
886
+ backgroundColor: "#fff",
887
+ borderStyle: "dashed",
888
+ },
889
+ imageBackground: {
890
+ flex: 1,
891
+ height: "100%",
892
+ width: "100%",
893
+ borderRadius: 4,
894
+ },
895
+ imageCircle: {
896
+ width: 90,
897
+ height: 90,
898
+ borderRadius: 45,
899
+ backgroundColor: Colours.PINKISH_GREY,
900
+ justifyContent: "center",
901
+ },
902
+ addImageIcon: {
903
+ color: "#fff",
904
+ fontSize: 32,
905
+ },
906
+ imagePlayContainer: {
907
+ position: "absolute",
908
+ top: 0,
909
+ left: 0,
910
+ right: 0,
911
+ bottom: 0,
912
+ alignItems: "center",
913
+ justifyContent: "center",
914
+ },
915
+ imageControlIcon: {
916
+ color: "#fff",
917
+ fontSize: 20,
918
+ textShadowColor: "rgba(0,0,0,0.3)",
919
+ textShadowOffset: { width: 2, height: 2 },
920
+ },
921
+ removeImage: {
922
+ position: "absolute",
923
+ top: 0,
924
+ right: 0,
925
+ padding: 4,
926
+ width: 40,
927
+ height: 40,
928
+ alignItems: "center",
929
+ justifyContent: "center",
930
+ },
931
+ sideBySideImages: {
932
+ flex: 1,
933
+ flexDirection: "row",
934
+ marginTop: 12,
935
+ marginHorizontal: -8,
936
+ },
937
+ sideBySideImageContainer: {
938
+ backgroundColor: "#fff",
939
+ width: 60,
940
+ height: 50,
941
+ borderRadius: 2,
942
+ overflow: "hidden",
943
+ marginRight: 2,
944
+ },
407
945
  };
408
946
 
409
- const mapStateToProps = state => {
410
- return {
411
- user: state.user,
412
- colourBrandingMain: Colours.getMainBrandingColourFromState(state),
413
- colourBrandingLight: Colours.getLightBrandingColourFromState(state),
414
- jobs: state[values.reducerKey].jobs,
415
- };
947
+ const mapStateToProps = (state) => {
948
+ return {
949
+ user: state.user,
950
+ colourBrandingMain: Colours.getMainBrandingColourFromState(state),
951
+ colourBrandingLight: Colours.getLightBrandingColourFromState(state),
952
+ jobs: state[values.reducerKey].jobs,
953
+ };
416
954
  };
417
955
 
418
956
  export default connect(mapStateToProps, { jobAdded })(RequestNotes);