@plusscommunities/pluss-maintenance-app-forms 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.
Files changed (90) hide show
  1. package/dist/module/actions/JobActions.js +20 -0
  2. package/dist/module/actions/JobActions.js.map +1 -0
  3. package/dist/module/actions/index.js +2 -0
  4. package/dist/module/actions/index.js.map +1 -0
  5. package/dist/module/actions/types.js +5 -0
  6. package/dist/module/actions/types.js.map +1 -0
  7. package/dist/module/apis/index.js +2 -0
  8. package/dist/module/apis/index.js.map +1 -0
  9. package/dist/module/apis/maintenanceActions.js +171 -0
  10. package/dist/module/apis/maintenanceActions.js.map +1 -0
  11. package/dist/module/components/FilterPopupMenu.js +271 -0
  12. package/dist/module/components/FilterPopupMenu.js.map +1 -0
  13. package/dist/module/components/MaintenanceList.js +360 -0
  14. package/dist/module/components/MaintenanceList.js.map +1 -0
  15. package/dist/module/components/MaintenanceListItem.js +322 -0
  16. package/dist/module/components/MaintenanceListItem.js.map +1 -0
  17. package/dist/module/components/MaintenanceWidgetItem.js +149 -0
  18. package/dist/module/components/MaintenanceWidgetItem.js.map +1 -0
  19. package/dist/module/components/StatusSelectorPopup.js +89 -0
  20. package/dist/module/components/StatusSelectorPopup.js.map +1 -0
  21. package/dist/module/components/WidgetLarge.js +9 -0
  22. package/dist/module/components/WidgetLarge.js.map +1 -0
  23. package/dist/module/components/WidgetSmall.js +171 -0
  24. package/dist/module/components/WidgetSmall.js.map +1 -0
  25. package/dist/module/core.config.js +17 -0
  26. package/dist/module/core.config.js.map +1 -0
  27. package/dist/module/feature.config.js +75 -0
  28. package/dist/module/feature.config.js.map +1 -0
  29. package/dist/module/helper.js +33 -0
  30. package/dist/module/helper.js.map +1 -0
  31. package/dist/module/images/speechbubble.png +0 -0
  32. package/dist/module/index.js +25 -0
  33. package/dist/module/index.js.map +1 -0
  34. package/dist/module/reducers/JobsReducer.js +63 -0
  35. package/dist/module/reducers/JobsReducer.js.map +1 -0
  36. package/dist/module/screens/JobTypePicker.js +130 -0
  37. package/dist/module/screens/JobTypePicker.js.map +1 -0
  38. package/dist/module/screens/MaintenancePage.js +92 -0
  39. package/dist/module/screens/MaintenancePage.js.map +1 -0
  40. package/dist/module/screens/RequestDetail.js +980 -0
  41. package/dist/module/screens/RequestDetail.js.map +1 -0
  42. package/dist/module/screens/RequestNotes.js +390 -0
  43. package/dist/module/screens/RequestNotes.js.map +1 -0
  44. package/dist/module/screens/ServiceRequest.js +1243 -0
  45. package/dist/module/screens/ServiceRequest.js.map +1 -0
  46. package/dist/module/values.config.a.js +30 -0
  47. package/dist/module/values.config.a.js.map +1 -0
  48. package/dist/module/values.config.b.js +30 -0
  49. package/dist/module/values.config.b.js.map +1 -0
  50. package/dist/module/values.config.c.js +30 -0
  51. package/dist/module/values.config.c.js.map +1 -0
  52. package/dist/module/values.config.d.js +30 -0
  53. package/dist/module/values.config.d.js.map +1 -0
  54. package/dist/module/values.config.default.js +35 -0
  55. package/dist/module/values.config.default.js.map +1 -0
  56. package/dist/module/values.config.forms.js +35 -0
  57. package/dist/module/values.config.forms.js.map +1 -0
  58. package/dist/module/values.config.js +35 -0
  59. package/dist/module/values.config.js.map +1 -0
  60. package/package.json +53 -0
  61. package/src/actions/JobActions.js +22 -0
  62. package/src/actions/index.js +1 -0
  63. package/src/actions/types.js +5 -0
  64. package/src/apis/index.js +1 -0
  65. package/src/apis/maintenanceActions.js +163 -0
  66. package/src/components/FilterPopupMenu.js +256 -0
  67. package/src/components/MaintenanceList.js +335 -0
  68. package/src/components/MaintenanceListItem.js +289 -0
  69. package/src/components/MaintenanceWidgetItem.js +132 -0
  70. package/src/components/StatusSelectorPopup.js +87 -0
  71. package/src/components/WidgetLarge.js +10 -0
  72. package/src/components/WidgetSmall.js +152 -0
  73. package/src/core.config.js +5 -0
  74. package/src/feature.config.js +73 -0
  75. package/src/helper.js +39 -0
  76. package/src/images/speechbubble.png +0 -0
  77. package/src/index.js +25 -0
  78. package/src/reducers/JobsReducer.js +51 -0
  79. package/src/screens/JobTypePicker.js +107 -0
  80. package/src/screens/MaintenancePage.js +96 -0
  81. package/src/screens/RequestDetail.js +915 -0
  82. package/src/screens/RequestNotes.js +418 -0
  83. package/src/screens/ServiceRequest.js +1219 -0
  84. package/src/values.config.a.js +30 -0
  85. package/src/values.config.b.js +30 -0
  86. package/src/values.config.c.js +30 -0
  87. package/src/values.config.d.js +30 -0
  88. package/src/values.config.default.js +35 -0
  89. package/src/values.config.forms.js +35 -0
  90. package/src/values.config.js +35 -0
@@ -0,0 +1,335 @@
1
+ import React, { Component } from 'react';
2
+ import { View, StyleSheet, FlatList, TouchableOpacity, Text } from 'react-native';
3
+ import _ from 'lodash';
4
+ import { connect } from 'react-redux';
5
+ import { maintenanceActions } from '../apis';
6
+ import { jobsLoaded, jobAdded, jobsAdded } from '../actions';
7
+ import MaintenanceListItem from '../components/MaintenanceListItem';
8
+ import FilterPopupMenu from './FilterPopupMenu';
9
+ import { Components, Colours, Config, Helper } from '../core.config';
10
+ import { values } from '../values.config';
11
+
12
+ class MaintenanceList extends Component {
13
+ constructor(props) {
14
+ super(props);
15
+
16
+ this.initialStatus = props.hasPermission ? 'Unassigned|In Progress' : '';
17
+ this.initialStatusText = props.hasPermission ? 'Incomplete' : '';
18
+
19
+ this.state = {
20
+ types: [],
21
+ filteredList: props.jobs,
22
+ loading: false,
23
+ searchText: '',
24
+ showFilterPopup: false,
25
+ selectedStatus: this.initialStatus,
26
+ selectedStatusText: this.initialStatusText,
27
+ selectedType: '',
28
+ selectedAssignee: '',
29
+ selectedAssigneeName: '',
30
+ };
31
+ }
32
+
33
+ componentDidMount() {
34
+ this.refresh();
35
+ this.refreshTypes();
36
+
37
+ this.resetDataSource();
38
+ }
39
+
40
+ componentDidUpdate(prevProps) {
41
+ if (!prevProps.dataUpdated && this.props.dataUpdated) this.refresh();
42
+ if (!_.isEqual(prevProps.jobs, this.props.jobs)) this.resetDataSource();
43
+ }
44
+
45
+ refresh = () => {
46
+ this.onLoadingChanged(true, async () => {
47
+ try {
48
+ const { selectedStatus, selectedType } = this.state;
49
+ // console.log('filters', { selectedStatus, selectedType });
50
+ const res = await maintenanceActions.getJobsRecursive(this.props.site, selectedStatus, selectedType);
51
+ // console.log('refresh', res?.data);
52
+ if (selectedStatus !== this.initialStatus || !_.isEmpty(selectedType)) {
53
+ this.props.jobsAdded(res);
54
+ } else {
55
+ this.props.jobsLoaded(res);
56
+ }
57
+ } catch (error) {
58
+ console.log('refresh error', error);
59
+ } finally {
60
+ this.onLoadingChanged(false);
61
+ }
62
+ });
63
+ };
64
+
65
+ refreshTypes = async () => {
66
+ const { data } = await maintenanceActions.getJobTypes(Helper.getSite(this.props.site));
67
+ const types = data.map(t => {
68
+ return { label: t.typeName, value: t.typeName };
69
+ });
70
+ types.splice(0, 0, { label: 'All', value: '' });
71
+ // console.log('refreshTypes', types);
72
+ this.setState({ types });
73
+ };
74
+
75
+ fetchJob = jobId => {
76
+ if (this.state.loading) return;
77
+
78
+ this.onLoadingChanged(true, async () => {
79
+ try {
80
+ const job = await maintenanceActions.getJobByJobId(this.props.site, jobId);
81
+ // console.log('fetchJob', job?.data);
82
+ this.props.jobAdded(job.data);
83
+ } catch (error) {
84
+ console.log('fetchJob error', error);
85
+ } finally {
86
+ this.onLoadingChanged(false);
87
+ }
88
+ });
89
+ };
90
+
91
+ getEmptyStateText() {
92
+ if (this.props.options && !_.isEmpty(this.props.options.EmptyText)) {
93
+ return this.props.options.EmptyText;
94
+ }
95
+ return this.props.userCategory === 'staff' ? values.emptyRequestsStaff : values.emptyRequestsUser;
96
+ }
97
+
98
+ resetDataSource = (source = '') => {
99
+ const { searchText, selectedStatus, selectedType, selectedAssignee } = this.state;
100
+ const { jobs } = this.props;
101
+
102
+ let filteredList = jobs;
103
+ let jobIdMatch = null;
104
+ if (searchText) {
105
+ jobIdMatch = _.find(jobs, j => j.jobId === searchText);
106
+ filteredList = jobs.filter(j => {
107
+ if (j.room && j.room.toLowerCase().indexOf(searchText.toLowerCase()) > -1) {
108
+ return true;
109
+ }
110
+ return false;
111
+ });
112
+ if (!jobIdMatch) this.fetchJob(searchText);
113
+ }
114
+ if (selectedStatus) filteredList = filteredList.filter(j => selectedStatus.includes(j.status));
115
+ if (selectedType) filteredList = filteredList.filter(j => selectedType.includes(j.type));
116
+ if (selectedAssignee) filteredList = filteredList.filter(j => selectedAssignee.includes(j.AssigneeId));
117
+ if (jobIdMatch) {
118
+ const jobIndex = filteredList.indexOf(jobIdMatch);
119
+ if (jobIndex > -1) {
120
+ filteredList.splice(jobIndex, 1);
121
+ }
122
+ filteredList.unshift(jobIdMatch);
123
+ }
124
+ if (source !== 'search') this.refresh();
125
+
126
+ this.setState({ filteredList });
127
+ };
128
+
129
+ onLoadingChanged = (loading, callback) => {
130
+ this.setState({ loading }, () => {
131
+ if (this.props.onLoadingChanged) this.props.onLoadingChanged(this.state.loading);
132
+ if (callback) callback();
133
+ });
134
+ };
135
+
136
+ onSearchText = value => {
137
+ this.setState({ searchText: value }, () => {
138
+ if (_.isEmpty(this.state.searchText)) this.resetDataSource('search');
139
+ });
140
+ };
141
+
142
+ onSearchSubmit = () => {
143
+ this.resetDataSource('search');
144
+ };
145
+
146
+ onToggleFilter = () => {
147
+ this.setState({ showFilterPopup: !this.state.showFilterPopup });
148
+ };
149
+
150
+ onSelectFilter = selected => {
151
+ this.setState(
152
+ {
153
+ selectedStatus: selected.status,
154
+ selectedStatusText: selected.statusText,
155
+ selectedType: selected.type,
156
+ selectedAssignee: selected.assignee,
157
+ selectedAssigneeName: selected.assigneeName,
158
+ },
159
+ () => {
160
+ this.resetDataSource();
161
+ this.onToggleFilter();
162
+ },
163
+ );
164
+ };
165
+
166
+ getFilterButtonText = () => {
167
+ const { selectedStatus, selectedStatusText, selectedType, selectedAssignee, selectedAssigneeName } = this.state;
168
+ const filterTexts = [];
169
+ if (!_.isEmpty(selectedStatus)) {
170
+ filterTexts.push(selectedStatusText);
171
+ }
172
+
173
+ if (!_.isEmpty(selectedType)) {
174
+ filterTexts.push(selectedType);
175
+ }
176
+ if (!_.isEmpty(selectedAssignee)) {
177
+ filterTexts.push(selectedAssigneeName);
178
+ }
179
+ if (_.isEmpty(filterTexts)) {
180
+ return 'Filter';
181
+ }
182
+ return `Filtering by ${filterTexts.join(', ')}`;
183
+ };
184
+
185
+ renderEmptyList() {
186
+ return this.state.loading ? null : <Components.EmptyStateMain title={this.getEmptyStateText()} style={{ marginHorizontal: 16 }} />;
187
+ }
188
+
189
+ renderFilterButton() {
190
+ return (
191
+ <TouchableOpacity onPress={this.onToggleFilter}>
192
+ <View style={styles.filterButton}>
193
+ <Text style={[styles.filterButtonText, { color: this.props.colourBrandingMain }]}>{this.getFilterButtonText()}</Text>
194
+ </View>
195
+ </TouchableOpacity>
196
+ );
197
+ }
198
+
199
+ renderSearch() {
200
+ if (!this.props.hasPermission) return null;
201
+
202
+ return (
203
+ <View style={styles.searchContainer}>
204
+ <Components.GenericInput
205
+ placeholder={`Search by ${values.textEntityName} ID or Address`}
206
+ value={this.state.searchText}
207
+ onChangeText={this.onSearchText}
208
+ onSubmitEditing={this.onSearchSubmit}
209
+ squaredCorners
210
+ hasClear
211
+ // keyboardType={'numeric'}
212
+ returnKeyType={'done'}
213
+ />
214
+ </View>
215
+ );
216
+ }
217
+
218
+ renderListHeader() {
219
+ const { ListHeaderComponent } = this.props;
220
+ return (
221
+ <View>
222
+ {ListHeaderComponent ? ListHeaderComponent : <View style={{ height: 8 }} />}
223
+ {this.renderFilterButton()}
224
+ {this.renderSearch()}
225
+ </View>
226
+ );
227
+ }
228
+
229
+ renderList() {
230
+ const { filteredList } = this.state;
231
+
232
+ return (
233
+ <FlatList
234
+ keyboardShouldPersistTaps="always"
235
+ style={{ flex: 1 }}
236
+ contentContainerStyle={{ paddingBottom: 16 }}
237
+ data={filteredList}
238
+ keyExtractor={item => item.id}
239
+ renderItem={({ item }) => <MaintenanceListItem style={this.props.itemStyle} job={item} />}
240
+ ListEmptyComponent={this.renderEmptyList()}
241
+ ListHeaderComponent={this.renderListHeader()}
242
+ />
243
+ );
244
+ }
245
+
246
+ renderFilterPopup() {
247
+ const { showFilterPopup, types, selectedStatus, selectedType, selectedAssignee } = this.state;
248
+ if (!showFilterPopup) return null;
249
+
250
+ return (
251
+ <FilterPopupMenu
252
+ site={this.props.site}
253
+ types={types}
254
+ status={selectedStatus}
255
+ assignee={selectedAssignee}
256
+ type={selectedType}
257
+ onClose={this.onSelectFilter}
258
+ />
259
+ );
260
+ }
261
+
262
+ render() {
263
+ return (
264
+ <View style={[styles.container, this.props.style]}>
265
+ {this.renderList()}
266
+ {this.renderFilterPopup()}
267
+ </View>
268
+ );
269
+ }
270
+ }
271
+
272
+ const styles = StyleSheet.create({
273
+ container: {
274
+ flex: 1,
275
+ backgroundColor: '#fff',
276
+ },
277
+ filterContainerOuter: {
278
+ flexDirection: 'row',
279
+ justifyContent: 'space-between',
280
+ alignItems: 'center',
281
+ paddingHorizontal: 16,
282
+ paddingVertical: 16,
283
+ },
284
+ filterTitle: {
285
+ fontFamily: 'sf-bold',
286
+ fontSize: 11,
287
+ letterSpacing: 0.8,
288
+ color: '#4d4d4d',
289
+ },
290
+ filterContainer: {
291
+ flexDirection: 'row',
292
+ alignItems: 'center',
293
+ },
294
+ filterText: {
295
+ fontFamily: 'sf-semibold',
296
+ fontSize: 16,
297
+ marginRight: 6,
298
+ },
299
+ filterIcon: {
300
+ fontSize: 20,
301
+ },
302
+ searchContainer: {
303
+ flexDirection: 'row',
304
+ alignItems: 'center',
305
+ paddingBottom: 8,
306
+ paddingHorizontal: 16,
307
+ },
308
+ filterButton: {
309
+ paddingBottom: 8,
310
+ paddingHorizontal: 16,
311
+ flexDirection: 'row-reverse',
312
+ },
313
+ filterButtonText: {
314
+ fontFamily: 'sf-semibold',
315
+ fontSize: 16,
316
+ },
317
+ });
318
+
319
+ const mapStateToProps = state => {
320
+ const { user, notifications } = state;
321
+ const jobs = state[values.reducerKey];
322
+ const jobsOrdered = _.orderBy(jobs.jobs, ['createdUnix'], ['desc']);
323
+ const hasPermission = _.includes(user.permissions, 'maintenanceTracking');
324
+
325
+ return {
326
+ hasPermission,
327
+ jobs: jobsOrdered,
328
+ site: user.site,
329
+ userCategory: user.category,
330
+ colourBrandingMain: Colours.getMainBrandingColourFromState(state),
331
+ dataUpdated: notifications.dataUpdated[values.updateKey],
332
+ };
333
+ };
334
+
335
+ export default connect(mapStateToProps, { jobsLoaded, jobAdded, jobsAdded }, null, { forwardRef: true })(MaintenanceList);
@@ -0,0 +1,289 @@
1
+ import React, { Component } from 'react';
2
+ import { Image, Text, TouchableOpacity, View, StyleSheet } from 'react-native';
3
+ import _ from 'lodash';
4
+ import { Icon } from 'react-native-elements';
5
+ import { connect } from 'react-redux';
6
+ import moment from 'moment';
7
+ // import {
8
+ // getShadowStyle,
9
+ // LINEGREY,
10
+ // TEXT_DARK,
11
+ // TEXT_LIGHT,
12
+ // COLOUR_GREEN,
13
+ // getMainBrandingColourFromState,
14
+ // hexToRGBAstring,
15
+ // getJobStatusProps,
16
+ // jobStatusOptions,
17
+ // } from '../../js';
18
+ // import NavigationService from '../../js/NavigationService';
19
+ import { getJobStatusProps, jobStatusOptions } from '../helper';
20
+ import { Services } from '../feature.config';
21
+ import { Helper, Colours } from '../core.config';
22
+ import { values } from '../values.config';
23
+
24
+ class MaintenanceListItem extends Component {
25
+ onPressJob = () => {
26
+ Services.navigation.navigate(values.screenRequestDetail, { job: this.props.job });
27
+ };
28
+
29
+ renderCommentCount() {
30
+ const { job } = this.props;
31
+ if (!job.commentCount) {
32
+ return null;
33
+ }
34
+ return (
35
+ <View style={styles.commentCountContainer}>
36
+ <Text style={styles.commentCountText}>{job.commentCount > 99 ? '99' : job.commentCount}</Text>
37
+ </View>
38
+ );
39
+ }
40
+
41
+ renderDescription() {
42
+ const { job } = this.props;
43
+ if (_.isEmpty(job.description)) {
44
+ return null;
45
+ }
46
+ return <Text style={styles.jobDescriptionText}>{job.description}</Text>;
47
+ }
48
+
49
+ renderSeen() {
50
+ const { job } = this.props;
51
+ const showSeen = !job.status || job.status === jobStatusOptions[0].name;
52
+ if (!showSeen || !job.seen) {
53
+ return null;
54
+ }
55
+ return (
56
+ <View style={styles.jobSeenContainer}>
57
+ <Icon name="check" type="font-awesome" iconStyle={[styles.jobSeenIcon, { color: this.props.colourBrandingMain }]} />
58
+ <Text style={[styles.jobSeenText, { color: this.props.colourBrandingMain }]}>Seen</Text>
59
+ </View>
60
+ );
61
+ }
62
+
63
+ render() {
64
+ const { job } = this.props;
65
+ const createdTime = moment(job.createdUnix);
66
+ const createdTimeText = `${createdTime.format('ddd, D MMMM')} • ${createdTime.format('h:mma')}`;
67
+ const assigneeText = job.Assignee ? `Assigned to\n${job.Assignee.displayName}` : '';
68
+ const { statusText, statusColor } = getJobStatusProps(job.status);
69
+
70
+ return (
71
+ <TouchableOpacity onPress={this.onPressJob}>
72
+ <View style={[styles.jobContainer, this.props.style]}>
73
+ <View style={styles.jobInnerContainer}>
74
+ <View style={styles.jobTopSection}>
75
+ <View style={styles.jobTopLeft}>
76
+ {job.jobId ? (
77
+ <Text
78
+ style={[styles.jobIdText, { color: this.props.colourBrandingMain }]}
79
+ >{`${values.textEntityName} #${job.jobId}`}</Text>
80
+ ) : null}
81
+ <Text style={styles.jobTitleText}>{job.title}</Text>
82
+ {job.room ? <Text style={styles.jobLocationText}>{job.room}</Text> : null}
83
+ <View style={styles.jobTypeSeenContainer}>
84
+ <View style={[styles.jobTypeContainer, { backgroundColor: Colours.hexToRGBAstring(this.props.colourBrandingMain, 0.2) }]}>
85
+ <Text style={[styles.jobTypeText, { color: this.props.colourBrandingMain }]} numberOfLines={2}>
86
+ {job.type}
87
+ </Text>
88
+ </View>
89
+ {this.renderSeen()}
90
+ </View>
91
+ </View>
92
+ <View style={styles.jobTopRight}>
93
+ <Image style={styles.jobCommentImage} source={require('../images/speechbubble.png')} />
94
+ {this.renderCommentCount()}
95
+ </View>
96
+ </View>
97
+ <View style={styles.jobBottomSection}>
98
+ {/* {this.renderDescription()} */}
99
+ <Text style={styles.jobCreatedText}>{createdTimeText}</Text>
100
+ <View style={styles.jobActivityContainer}>
101
+ <View style={[styles.jobStatusContainer, { backgroundColor: statusColor }]}>
102
+ {/* <Icon name="wrench" type="font-awesome" iconStyle={styles.jobStatusIcon} /> */}
103
+ <Text style={styles.jobStatusText}>{statusText}</Text>
104
+ </View>
105
+ <View style={[styles.jobStatusLine, { borderColor: statusColor }]}>
106
+ <View style={styles.jobStatusLineMask} />
107
+ </View>
108
+ <View style={[styles.jobStatusCircle, { backgroundColor: statusColor }]} />
109
+ <Text style={styles.jobStatusDateText}>{assigneeText}</Text>
110
+ </View>
111
+ </View>
112
+ </View>
113
+ </View>
114
+ </TouchableOpacity>
115
+ );
116
+ }
117
+ }
118
+
119
+ const styles = StyleSheet.create({
120
+ jobContainer: {
121
+ marginVertical: 8,
122
+ paddingHorizontal: 16,
123
+ },
124
+ jobInnerContainer: {
125
+ ...Helper.getShadowStyle(),
126
+ },
127
+ jobTopSection: {
128
+ flexDirection: 'row',
129
+ alignItems: 'flex-end',
130
+ paddingHorizontal: 10,
131
+ paddingVertical: 10,
132
+ borderBottomWidth: 1,
133
+ borderBottomColor: Colours.LINEGREY,
134
+ },
135
+ jobTopLeft: {
136
+ flex: 1,
137
+ },
138
+ jobIdText: {
139
+ fontFamily: 'sf-medium',
140
+ fontSize: 12,
141
+ marginBottom: 4,
142
+ },
143
+ jobTitleText: {
144
+ fontFamily: 'sf-semibold',
145
+ fontSize: 18,
146
+ color: Colours.TEXT_DARK,
147
+ marginBottom: 4,
148
+ },
149
+ jobLocationText: {
150
+ fontFamily: 'sf-medium',
151
+ fontSize: 12,
152
+ color: Colours.TEXT_LIGHT,
153
+ marginBottom: 4,
154
+ },
155
+ jobTypeSeenContainer: {
156
+ marginTop: 4,
157
+ flexDirection: 'row',
158
+ alignItems: 'center',
159
+ },
160
+ jobTypeContainer: {
161
+ padding: 4,
162
+ minWidth: 80,
163
+ maxWidth: 140,
164
+ borderRadius: 4,
165
+ justifyContent: 'center',
166
+ },
167
+ jobTypeText: {
168
+ fontFamily: 'sf-semibold',
169
+ fontSize: 12,
170
+ textAlign: 'center',
171
+ maxWidth: '100%',
172
+ },
173
+ jobSeenContainer: {
174
+ flexDirection: 'row',
175
+ alignItems: 'center',
176
+ marginLeft: 10,
177
+ },
178
+ jobSeenIcon: {
179
+ fontSize: 12,
180
+ },
181
+ jobSeenText: {
182
+ fontFamily: 'sf-semibold',
183
+ fontSize: 12,
184
+ marginLeft: 4,
185
+ },
186
+ jobTopRight: {
187
+ alignItems: 'center',
188
+ justifyContent: 'center',
189
+ paddingHorizontal: 10,
190
+ paddingTop: 10,
191
+ },
192
+ jobCommentImage: {
193
+ width: 34,
194
+ height: 34,
195
+ resizeMode: 'contain',
196
+ },
197
+ commentCountContainer: {
198
+ position: 'absolute',
199
+ top: 0,
200
+ right: 0,
201
+ borderRadius: 10,
202
+ borderWidth: 2,
203
+ borderColor: '#fff',
204
+ width: 20,
205
+ height: 20,
206
+ backgroundColor: Colours.COLOUR_GREEN,
207
+ justifyContent: 'center',
208
+ alignItems: 'center',
209
+ },
210
+ commentCountText: {
211
+ textAlign: 'center',
212
+ fontFamily: 'sf-bold',
213
+ fontSize: 10,
214
+ color: '#fff',
215
+ },
216
+ jobBottomSection: {
217
+ paddingHorizontal: 10,
218
+ paddingVertical: 16,
219
+ },
220
+ jobDescriptionText: {
221
+ fontFamily: 'sf-medium',
222
+ fontSize: 14,
223
+ color: Colours.TEXT_DARK,
224
+ marginBottom: 8,
225
+ },
226
+ jobCreatedText: {
227
+ fontFamily: 'sf-medium',
228
+ fontSize: 12,
229
+ color: Colours.TEXT_LIGHT,
230
+ marginBottom: 10,
231
+ },
232
+ jobActivityContainer: {
233
+ flexDirection: 'row',
234
+ alignItems: 'center',
235
+ },
236
+ jobStatusContainer: {
237
+ flexDirection: 'row',
238
+ alignItems: 'center',
239
+ justifyContent: 'center',
240
+ width: 105,
241
+ height: 30,
242
+ paddingHorizontal: 8,
243
+ borderRadius: 4,
244
+ },
245
+ jobStatusIcon: {
246
+ color: '#fff',
247
+ fontSize: 14,
248
+ },
249
+ jobStatusText: {
250
+ color: '#fff',
251
+ textAlign: 'center',
252
+ fontFamily: 'sf-semibold',
253
+ fontSize: 13,
254
+ },
255
+ jobStatusLine: {
256
+ borderWidth: 1,
257
+ borderStyle: 'dashed',
258
+ width: 30,
259
+ },
260
+ jobStatusLineMask: {
261
+ position: 'absolute',
262
+ left: -1,
263
+ top: -1,
264
+ width: '100%',
265
+ height: 1,
266
+ backgroundColor: '#fff',
267
+ zIndex: 1,
268
+ },
269
+ jobStatusCircle: {
270
+ width: 18,
271
+ height: 18,
272
+ borderRadius: 9,
273
+ },
274
+ jobStatusDateText: {
275
+ flex: 1,
276
+ textAlign: 'right',
277
+ fontFamily: 'sf-medium',
278
+ fontSize: 14,
279
+ color: Colours.TEXT_DARK,
280
+ },
281
+ });
282
+
283
+ const mapStateToProps = state => {
284
+ return {
285
+ colourBrandingMain: Colours.getMainBrandingColourFromState(state),
286
+ };
287
+ };
288
+
289
+ export default connect(mapStateToProps, {})(MaintenanceListItem);