@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.
- package/dist/module/actions/JobActions.js +20 -0
- package/dist/module/actions/JobActions.js.map +1 -0
- package/dist/module/actions/index.js +2 -0
- package/dist/module/actions/index.js.map +1 -0
- package/dist/module/actions/types.js +5 -0
- package/dist/module/actions/types.js.map +1 -0
- package/dist/module/apis/index.js +2 -0
- package/dist/module/apis/index.js.map +1 -0
- package/dist/module/apis/maintenanceActions.js +171 -0
- package/dist/module/apis/maintenanceActions.js.map +1 -0
- package/dist/module/components/FilterPopupMenu.js +271 -0
- package/dist/module/components/FilterPopupMenu.js.map +1 -0
- package/dist/module/components/MaintenanceList.js +360 -0
- package/dist/module/components/MaintenanceList.js.map +1 -0
- package/dist/module/components/MaintenanceListItem.js +322 -0
- package/dist/module/components/MaintenanceListItem.js.map +1 -0
- package/dist/module/components/MaintenanceWidgetItem.js +149 -0
- package/dist/module/components/MaintenanceWidgetItem.js.map +1 -0
- package/dist/module/components/StatusSelectorPopup.js +89 -0
- package/dist/module/components/StatusSelectorPopup.js.map +1 -0
- package/dist/module/components/WidgetLarge.js +9 -0
- package/dist/module/components/WidgetLarge.js.map +1 -0
- package/dist/module/components/WidgetSmall.js +171 -0
- package/dist/module/components/WidgetSmall.js.map +1 -0
- package/dist/module/core.config.js +17 -0
- package/dist/module/core.config.js.map +1 -0
- package/dist/module/feature.config.js +75 -0
- package/dist/module/feature.config.js.map +1 -0
- package/dist/module/helper.js +33 -0
- package/dist/module/helper.js.map +1 -0
- package/dist/module/images/speechbubble.png +0 -0
- package/dist/module/index.js +25 -0
- package/dist/module/index.js.map +1 -0
- package/dist/module/reducers/JobsReducer.js +63 -0
- package/dist/module/reducers/JobsReducer.js.map +1 -0
- package/dist/module/screens/JobTypePicker.js +130 -0
- package/dist/module/screens/JobTypePicker.js.map +1 -0
- package/dist/module/screens/MaintenancePage.js +92 -0
- package/dist/module/screens/MaintenancePage.js.map +1 -0
- package/dist/module/screens/RequestDetail.js +980 -0
- package/dist/module/screens/RequestDetail.js.map +1 -0
- package/dist/module/screens/RequestNotes.js +390 -0
- package/dist/module/screens/RequestNotes.js.map +1 -0
- package/dist/module/screens/ServiceRequest.js +1243 -0
- package/dist/module/screens/ServiceRequest.js.map +1 -0
- 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 +53 -0
- package/src/actions/JobActions.js +22 -0
- package/src/actions/index.js +1 -0
- package/src/actions/types.js +5 -0
- package/src/apis/index.js +1 -0
- package/src/apis/maintenanceActions.js +163 -0
- package/src/components/FilterPopupMenu.js +256 -0
- package/src/components/MaintenanceList.js +335 -0
- package/src/components/MaintenanceListItem.js +289 -0
- package/src/components/MaintenanceWidgetItem.js +132 -0
- package/src/components/StatusSelectorPopup.js +87 -0
- package/src/components/WidgetLarge.js +10 -0
- package/src/components/WidgetSmall.js +152 -0
- package/src/core.config.js +5 -0
- package/src/feature.config.js +73 -0
- package/src/helper.js +39 -0
- package/src/images/speechbubble.png +0 -0
- package/src/index.js +25 -0
- package/src/reducers/JobsReducer.js +51 -0
- package/src/screens/JobTypePicker.js +107 -0
- package/src/screens/MaintenancePage.js +96 -0
- package/src/screens/RequestDetail.js +915 -0
- package/src/screens/RequestNotes.js +418 -0
- package/src/screens/ServiceRequest.js +1219 -0
- 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
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
|
|
3
|
+
import { connect } from 'react-redux';
|
|
4
|
+
import { Icon } from 'react-native-elements';
|
|
5
|
+
import moment from 'moment';
|
|
6
|
+
import _ from 'lodash';
|
|
7
|
+
import { getJobStatusProps, jobStatusOptions } from '../helper';
|
|
8
|
+
import { Services } from '../feature.config';
|
|
9
|
+
import { Colours, Helper } from '../core.config';
|
|
10
|
+
import { values } from '../values.config';
|
|
11
|
+
|
|
12
|
+
class MaintenanceWidgetItem extends Component {
|
|
13
|
+
onPressJob = () => {
|
|
14
|
+
Services.navigation.navigate(values.screenRequestDetail, { job: this.props.job });
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
render() {
|
|
18
|
+
const { job } = this.props;
|
|
19
|
+
const createdTime = moment(job.createdUnix);
|
|
20
|
+
const createdTimeText = `${createdTime.format('ddd, D MMMM')} • ${createdTime.format('h:mma')}`;
|
|
21
|
+
const { statusText, statusColor } = getJobStatusProps(job.status);
|
|
22
|
+
const seenText = (() => {
|
|
23
|
+
if (!job.status || job.status === jobStatusOptions[0].name) {
|
|
24
|
+
return job.seen ? 'Seen' : 'Unseen';
|
|
25
|
+
}
|
|
26
|
+
return '';
|
|
27
|
+
})();
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<TouchableOpacity key={job.id} onPress={this.onPressJob}>
|
|
31
|
+
<View style={styles.jobContainer}>
|
|
32
|
+
<View style={styles.jobInnerContainer}>
|
|
33
|
+
<View style={styles.jobTopSection}>
|
|
34
|
+
<Text numberOfLines={2} style={styles.jobTitleText}>
|
|
35
|
+
{job.title}
|
|
36
|
+
</Text>
|
|
37
|
+
<Text style={styles.jobCreatedTimeText}>{createdTimeText}</Text>
|
|
38
|
+
<View style={styles.jobSeenContainer}>
|
|
39
|
+
{job.seen && !_.isEmpty(seenText) && (
|
|
40
|
+
<Icon name="check" type="font-awesome" iconStyle={[styles.jobSeenIcon, { color: this.props.colourBrandingMain }]} />
|
|
41
|
+
)}
|
|
42
|
+
<Text style={[styles.jobSeenText, job.seen && { color: this.props.colourBrandingMain }]}>{seenText}</Text>
|
|
43
|
+
</View>
|
|
44
|
+
</View>
|
|
45
|
+
<View style={styles.jobBottomSection}>
|
|
46
|
+
<View style={[styles.jobStatusContainer, { backgroundColor: statusColor }]}>
|
|
47
|
+
{/* <Icon name="wrench" type="font-awesome" iconStyle={styles.jobStatusIcon} /> */}
|
|
48
|
+
<Text style={styles.jobStatusText}>{statusText}</Text>
|
|
49
|
+
</View>
|
|
50
|
+
</View>
|
|
51
|
+
</View>
|
|
52
|
+
</View>
|
|
53
|
+
</TouchableOpacity>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const styles = StyleSheet.create({
|
|
59
|
+
jobContainer: {
|
|
60
|
+
padding: 10,
|
|
61
|
+
},
|
|
62
|
+
jobInnerContainer: {
|
|
63
|
+
width: 140,
|
|
64
|
+
height: 160,
|
|
65
|
+
...Helper.getShadowStyle(),
|
|
66
|
+
},
|
|
67
|
+
jobTopSection: {
|
|
68
|
+
flex: 1,
|
|
69
|
+
padding: 10,
|
|
70
|
+
paddingTop: 20,
|
|
71
|
+
},
|
|
72
|
+
jobTitleText: {
|
|
73
|
+
flex: 1,
|
|
74
|
+
fontFamily: 'sf-semibold',
|
|
75
|
+
fontSize: 16,
|
|
76
|
+
color: Colours.TEXT_DARK,
|
|
77
|
+
},
|
|
78
|
+
jobCreatedTimeText: {
|
|
79
|
+
fontFamily: 'sf-medium',
|
|
80
|
+
fontSize: 11,
|
|
81
|
+
color: Colours.TEXT_LIGHT,
|
|
82
|
+
paddingTop: 3,
|
|
83
|
+
},
|
|
84
|
+
jobSeenContainer: {
|
|
85
|
+
flexDirection: 'row',
|
|
86
|
+
alignItems: 'center',
|
|
87
|
+
paddingTop: 5,
|
|
88
|
+
},
|
|
89
|
+
jobSeenIcon: {
|
|
90
|
+
fontSize: 12,
|
|
91
|
+
marginRight: 4,
|
|
92
|
+
},
|
|
93
|
+
jobSeenText: {
|
|
94
|
+
fontFamily: 'sf-semibold',
|
|
95
|
+
fontSize: 12,
|
|
96
|
+
color: Colours.TEXT_SUPER_LIGHT,
|
|
97
|
+
},
|
|
98
|
+
jobBottomSection: {
|
|
99
|
+
alignItems: 'center',
|
|
100
|
+
justifyContent: 'center',
|
|
101
|
+
paddingVertical: 10,
|
|
102
|
+
borderTopWidth: 1,
|
|
103
|
+
borderTopColor: Colours.LINEGREY,
|
|
104
|
+
},
|
|
105
|
+
jobStatusContainer: {
|
|
106
|
+
flexDirection: 'row',
|
|
107
|
+
alignItems: 'center',
|
|
108
|
+
justifyContent: 'space-between',
|
|
109
|
+
width: 105,
|
|
110
|
+
height: 30,
|
|
111
|
+
paddingHorizontal: 8,
|
|
112
|
+
borderRadius: 4,
|
|
113
|
+
},
|
|
114
|
+
jobStatusIcon: {
|
|
115
|
+
color: '#fff',
|
|
116
|
+
fontSize: 14,
|
|
117
|
+
},
|
|
118
|
+
jobStatusText: {
|
|
119
|
+
color: '#fff',
|
|
120
|
+
textAlign: 'center',
|
|
121
|
+
fontFamily: 'sf-semibold',
|
|
122
|
+
fontSize: 13,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const mapStateToProps = state => {
|
|
127
|
+
return {
|
|
128
|
+
colourBrandingMain: Colours.getMainBrandingColourFromState(state),
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export default connect(mapStateToProps, {})(MaintenanceWidgetItem);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React, { PureComponent } from 'react';
|
|
2
|
+
import { View, StyleSheet, TouchableOpacity, Text } from 'react-native';
|
|
3
|
+
import { connect } from 'react-redux';
|
|
4
|
+
import { jobStatusOptions, getJobStatusColour } from '../helper';
|
|
5
|
+
import { Components, Colours } from '../core.config';
|
|
6
|
+
|
|
7
|
+
class StatusSelectorPopup extends PureComponent {
|
|
8
|
+
render() {
|
|
9
|
+
const { title, filter, includeAll, allText, onClose, onSelect } = this.props;
|
|
10
|
+
let statuses = filter
|
|
11
|
+
? filter.map(status => {
|
|
12
|
+
return {
|
|
13
|
+
name: status,
|
|
14
|
+
label: getJobStatusLabel(status),
|
|
15
|
+
color: getJobStatusColour(status),
|
|
16
|
+
};
|
|
17
|
+
})
|
|
18
|
+
: jobStatusOptions;
|
|
19
|
+
if (includeAll)
|
|
20
|
+
statuses = [
|
|
21
|
+
{
|
|
22
|
+
name: allText || 'Show All',
|
|
23
|
+
color: this.props.colourBrandingMain,
|
|
24
|
+
},
|
|
25
|
+
...statuses,
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Components.MiddlePopup style={[styles.statusPopup, { height: statuses.length * 50 + 40 }]} onClose={onClose}>
|
|
30
|
+
<Text style={styles.statusPopupTitle}>{title || 'Select Status'}</Text>
|
|
31
|
+
<View style={styles.statusPopupOptionsContainer}>
|
|
32
|
+
{statuses.map(status => {
|
|
33
|
+
return (
|
|
34
|
+
<TouchableOpacity key={status.name} onPress={() => onSelect(status.name)}>
|
|
35
|
+
<View style={[styles.jobStatusContainer, { backgroundColor: status.color }]}>
|
|
36
|
+
<Text style={styles.jobStatusText}>{status.label}</Text>
|
|
37
|
+
</View>
|
|
38
|
+
</TouchableOpacity>
|
|
39
|
+
);
|
|
40
|
+
})}
|
|
41
|
+
</View>
|
|
42
|
+
</Components.MiddlePopup>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const styles = StyleSheet.create({
|
|
48
|
+
statusPopup: {
|
|
49
|
+
width: 160,
|
|
50
|
+
padding: 16,
|
|
51
|
+
borderRadius: 12,
|
|
52
|
+
},
|
|
53
|
+
statusPopupTitle: {
|
|
54
|
+
fontFamily: 'sf-bold',
|
|
55
|
+
color: Colours.TEXT_DARK,
|
|
56
|
+
fontSize: 18,
|
|
57
|
+
marginBottom: 16,
|
|
58
|
+
},
|
|
59
|
+
statusPopupOptionsContainer: {
|
|
60
|
+
flex: 1,
|
|
61
|
+
justifyContent: 'space-between',
|
|
62
|
+
},
|
|
63
|
+
jobStatusContainer: {
|
|
64
|
+
flexDirection: 'row',
|
|
65
|
+
alignItems: 'center',
|
|
66
|
+
justifyContent: 'space-between',
|
|
67
|
+
width: 105,
|
|
68
|
+
height: 30,
|
|
69
|
+
paddingHorizontal: 8,
|
|
70
|
+
borderRadius: 4,
|
|
71
|
+
},
|
|
72
|
+
jobStatusText: {
|
|
73
|
+
color: '#fff',
|
|
74
|
+
textAlign: 'center',
|
|
75
|
+
fontFamily: 'sf-semibold',
|
|
76
|
+
fontSize: 13,
|
|
77
|
+
flex: 1,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const mapStateToProps = state => {
|
|
82
|
+
return {
|
|
83
|
+
colourBrandingMain: Colours.getMainBrandingColourFromState(state),
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export default connect(mapStateToProps, {})(StatusSelectorPopup);
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import { Text, View, ScrollView, StyleSheet } from 'react-native';
|
|
3
|
+
import { connect } from 'react-redux';
|
|
4
|
+
import _ from 'lodash';
|
|
5
|
+
import { maintenanceActions } from '../apis';
|
|
6
|
+
import { jobsLoaded } from '../actions';
|
|
7
|
+
import MaintenanceWidgetItem from './MaintenanceWidgetItem';
|
|
8
|
+
import { Services } from '../feature.config';
|
|
9
|
+
import { Colours, Components, Config } from '../core.config';
|
|
10
|
+
import { values } from '../values.config';
|
|
11
|
+
|
|
12
|
+
const MAX_ITEMS = 10;
|
|
13
|
+
|
|
14
|
+
class WidgetSmall extends Component {
|
|
15
|
+
constructor(props) {
|
|
16
|
+
super(props);
|
|
17
|
+
this.state = { loading: false };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
componentDidMount() {
|
|
21
|
+
this.refresh();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
componentDidUpdate(prevProps) {
|
|
25
|
+
if (!prevProps.dataUpdated && this.props.dataUpdated) this.refresh();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getTitle = () => {
|
|
29
|
+
const { options } = this.props;
|
|
30
|
+
if (options && !_.isEmpty(options.Title)) return options.Title;
|
|
31
|
+
return this.props.strings[`${values.featureKey}_textFeatureTitle`] || values.textFeatureTitle;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
getEmptyStateText = () => {
|
|
35
|
+
const { options, userCategory } = this.props;
|
|
36
|
+
if (options && !_.isEmpty(options.EmptyText)) return options.EmptyText;
|
|
37
|
+
return userCategory === 'staff' ? values.emptyRequestsStaff : values.emptyRequestsUser;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
refresh = () => {
|
|
41
|
+
this.onLoadingChanged(true, async () => {
|
|
42
|
+
try {
|
|
43
|
+
const res = await maintenanceActions.getJobsRecursive(this.props.site);
|
|
44
|
+
// console.log('WidgetSmall - refresh', res.data);
|
|
45
|
+
this.props.jobsLoaded(res);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.log('refresh error', error);
|
|
48
|
+
} finally {
|
|
49
|
+
this.onLoadingChanged(false);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
onLoadingChanged = (loading, callback) => {
|
|
55
|
+
this.setState({ loading }, () => {
|
|
56
|
+
if (this.props.onLoadingChanged) this.props.onLoadingChanged(this.state.loading);
|
|
57
|
+
if (callback) callback();
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
onPressAll = () => {
|
|
62
|
+
Services.navigation.navigate(values.screenMaintenance, { options: this.props.options });
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
renderContent() {
|
|
66
|
+
const { jobs } = this.props;
|
|
67
|
+
if (_.isEmpty(jobs)) {
|
|
68
|
+
if (this.state.loading) {
|
|
69
|
+
return (
|
|
70
|
+
<View style={styles.loadingPadding}>
|
|
71
|
+
<Components.LoadingStateWidget height={180} />
|
|
72
|
+
</View>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return (
|
|
76
|
+
<View style={styles.loadingPadding}>
|
|
77
|
+
<Components.EmptyStateWidget title={this.getEmptyStateText()} height={180} />
|
|
78
|
+
</View>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return (
|
|
82
|
+
<ScrollView horizontal contentContainerStyle={{ paddingLeft: 6, paddingRight: 8 }} showsHorizontalScrollIndicator={false}>
|
|
83
|
+
{jobs.slice(0, MAX_ITEMS).map(job => {
|
|
84
|
+
return <MaintenanceWidgetItem key={job.id} job={job} />;
|
|
85
|
+
})}
|
|
86
|
+
</ScrollView>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
render() {
|
|
91
|
+
const { colourBrandingMain } = this.props;
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<View style={styles.sectionContainer}>
|
|
95
|
+
<View style={styles.sectionPadding}>
|
|
96
|
+
<View style={styles.sectionHeading}>
|
|
97
|
+
<Text style={styles.sectionTitle}>{this.getTitle()}</Text>
|
|
98
|
+
<Components.InlineButton
|
|
99
|
+
onPress={this.onPressAll}
|
|
100
|
+
color={colourBrandingMain}
|
|
101
|
+
touchableStyle={{ paddingTop: 6 }}
|
|
102
|
+
textStyle={{ color: '#fff' }}
|
|
103
|
+
>
|
|
104
|
+
View All
|
|
105
|
+
</Components.InlineButton>
|
|
106
|
+
</View>
|
|
107
|
+
</View>
|
|
108
|
+
{this.renderContent()}
|
|
109
|
+
</View>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const styles = StyleSheet.create({
|
|
115
|
+
sectionContainer: {
|
|
116
|
+
backgroundColor: '#fff',
|
|
117
|
+
paddingTop: 16,
|
|
118
|
+
},
|
|
119
|
+
sectionPadding: {
|
|
120
|
+
paddingHorizontal: 16,
|
|
121
|
+
paddingBottom: 6,
|
|
122
|
+
},
|
|
123
|
+
loadingPadding: {
|
|
124
|
+
paddingHorizontal: 16,
|
|
125
|
+
},
|
|
126
|
+
sectionHeading: {
|
|
127
|
+
marginBottom: 4,
|
|
128
|
+
flexDirection: 'row',
|
|
129
|
+
alignContent: 'flex-start',
|
|
130
|
+
justifyContent: 'space-between',
|
|
131
|
+
},
|
|
132
|
+
sectionTitle: {
|
|
133
|
+
fontFamily: 'sf-bold',
|
|
134
|
+
fontSize: 24,
|
|
135
|
+
color: Colours.TEXT_DARKEST,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const mapStateToProps = state => {
|
|
140
|
+
const { user, notifications } = state;
|
|
141
|
+
const jobs = state[values.reducerKey];
|
|
142
|
+
return {
|
|
143
|
+
colourBrandingMain: Colours.getMainBrandingColourFromState(state),
|
|
144
|
+
jobs: _.orderBy(jobs.jobs, ['createdUnix'], ['desc']),
|
|
145
|
+
site: user.site,
|
|
146
|
+
userCategory: user.category,
|
|
147
|
+
dataUpdated: notifications.dataUpdated[values.updateKey],
|
|
148
|
+
strings: state.strings?.config || {},
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export default connect(mapStateToProps, { jobsLoaded }, null, { forwardRef: true })(WidgetSmall);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// import * as PlussCore from '../../pluss-core/src';
|
|
2
|
+
import * as PlussCore from '@plusscommunities/pluss-core-app';
|
|
3
|
+
|
|
4
|
+
const { Apis, Fonts, Actions, ActionTypes, Config, Components, Styles, Session, Helper, Constants, Colours } = PlussCore;
|
|
5
|
+
export { Apis, Fonts, Actions, ActionTypes, Config, Components, Styles, Session, Helper, Constants, Colours };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// import * as PlussCore from '../../pluss-core/src';
|
|
2
|
+
import * as PlussCore from '@plusscommunities/pluss-core-app';
|
|
3
|
+
import { values } from './values.config';
|
|
4
|
+
|
|
5
|
+
export const Services = {
|
|
6
|
+
navigation: null,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const BaseComponents = {
|
|
10
|
+
NotificationBell: null,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const FeatureConfig = {
|
|
14
|
+
key: values.featureKey,
|
|
15
|
+
aliases: values.aliases,
|
|
16
|
+
title: values.textFeatureTitle,
|
|
17
|
+
gridMenu: {
|
|
18
|
+
icon: values.iconGridMenu,
|
|
19
|
+
viewBox: values.gridViewBox,
|
|
20
|
+
navigate: values.screenMaintenance,
|
|
21
|
+
},
|
|
22
|
+
addMenu: {
|
|
23
|
+
order: values.orderAddMenu,
|
|
24
|
+
icon: values.iconAddMenu,
|
|
25
|
+
title: values.textAddMenuTitle,
|
|
26
|
+
navigate: values.screenServiceRequest,
|
|
27
|
+
visibleExps: { type: 'feature', value: values.featureKey },
|
|
28
|
+
},
|
|
29
|
+
moreMenu: values.hasMoreOption
|
|
30
|
+
? {
|
|
31
|
+
order: values.orderMoreMenu,
|
|
32
|
+
title: values.textMoreMenuTitle,
|
|
33
|
+
navigate: values.screenMaintenance,
|
|
34
|
+
visibleExps: {
|
|
35
|
+
type: 'and',
|
|
36
|
+
exps: [
|
|
37
|
+
{ type: 'notHidden', value: 'maintenanceRequest' },
|
|
38
|
+
{ type: 'notUserType', value: 'KIOSK' },
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
: undefined,
|
|
43
|
+
kioskAction: {
|
|
44
|
+
order: values.orderKioskAction,
|
|
45
|
+
icon: values.iconKioskAction,
|
|
46
|
+
title: values.textKioskActionTitle,
|
|
47
|
+
navigate: values.screenServiceRequest,
|
|
48
|
+
},
|
|
49
|
+
hideTabBar: [],
|
|
50
|
+
env: {
|
|
51
|
+
baseStage: '',
|
|
52
|
+
baseAPIUrl: '',
|
|
53
|
+
hasGradientHeader: false,
|
|
54
|
+
defaultProfileImage: '',
|
|
55
|
+
tinyChatDefault: '',
|
|
56
|
+
baseUploadsUrl: '',
|
|
57
|
+
allowMediaDownload: false,
|
|
58
|
+
allowMediaSharing: false,
|
|
59
|
+
awsUploadsBucket: '',
|
|
60
|
+
awsStorageBucket: '',
|
|
61
|
+
preferredSite: '',
|
|
62
|
+
strings: {},
|
|
63
|
+
newEventDefaults: '',
|
|
64
|
+
defaultAllowComments: true,
|
|
65
|
+
},
|
|
66
|
+
init: (environment, navigation, notificationBell) => {
|
|
67
|
+
FeatureConfig.env = environment;
|
|
68
|
+
Services.navigation = navigation;
|
|
69
|
+
BaseComponents.NotificationBell = notificationBell;
|
|
70
|
+
PlussCore.Config.init(environment, navigation);
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
export default FeatureConfig;
|
package/src/helper.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { label } from 'aws-amplify';
|
|
2
|
+
import { Colours } from './core.config';
|
|
3
|
+
|
|
4
|
+
const jobStatusOptions = [
|
|
5
|
+
{
|
|
6
|
+
name: 'Unassigned',
|
|
7
|
+
label: 'Open',
|
|
8
|
+
color: Colours.LINEGREY,
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'In Progress',
|
|
12
|
+
label: 'In Progress',
|
|
13
|
+
color: Colours.COLOUR_TEAL,
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'Completed',
|
|
17
|
+
label: 'Completed',
|
|
18
|
+
color: Colours.COLOUR_GREEN_LIGHT,
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const getJobStatusColour = status => {
|
|
23
|
+
const option = jobStatusOptions.find(item => item.name === status);
|
|
24
|
+
return option ? option.color : jobStatusOptions[0].color;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const getJobStatusLabel = status => {
|
|
28
|
+
const option = jobStatusOptions.find(item => item.name === status);
|
|
29
|
+
return option ? option.label : jobStatusOptions[0].label;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const getJobStatusProps = status => {
|
|
33
|
+
const statusText = getJobStatusLabel(status) || jobStatusOptions[0].label;
|
|
34
|
+
const statusColor = getJobStatusColour(statusText);
|
|
35
|
+
|
|
36
|
+
return { statusText, statusColor };
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export { jobStatusOptions, getJobStatusColour, getJobStatusProps, getJobStatusLabel };
|
|
Binary file
|
package/src/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import MaintenancePage from './screens/MaintenancePage';
|
|
2
|
+
import RequestDetail from './screens/RequestDetail';
|
|
3
|
+
import ServiceRequest from './screens/ServiceRequest';
|
|
4
|
+
import JobTypePicker from './screens/JobTypePicker';
|
|
5
|
+
import RequestNotes from './screens/RequestNotes';
|
|
6
|
+
import JobsReducer from './reducers/JobsReducer';
|
|
7
|
+
import { values } from './values.config';
|
|
8
|
+
|
|
9
|
+
export const Reducers = (() => {
|
|
10
|
+
const reducers = {};
|
|
11
|
+
reducers[values.reducerKey] = JobsReducer;
|
|
12
|
+
return reducers;
|
|
13
|
+
})();
|
|
14
|
+
export const Screens = (() => {
|
|
15
|
+
const screens = {};
|
|
16
|
+
screens[values.screenMaintenance] = MaintenancePage;
|
|
17
|
+
screens[values.screenRequestDetail] = RequestDetail;
|
|
18
|
+
screens[values.screenServiceRequest] = ServiceRequest;
|
|
19
|
+
screens[values.screenJobTypePicker] = JobTypePicker;
|
|
20
|
+
screens[values.screenRequestNotes] = RequestNotes;
|
|
21
|
+
return screens;
|
|
22
|
+
})();
|
|
23
|
+
export { default as Config } from './feature.config';
|
|
24
|
+
export { default as WidgetSmall } from './components/WidgetSmall';
|
|
25
|
+
export { default as WidgetLarge } from './components/WidgetLarge';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
import { REHYDRATE } from 'redux-persist';
|
|
4
|
+
import { JOBS_LOADED, JOB_ADDED, JOBS_ADDED } from '../actions/types';
|
|
5
|
+
import { ActionTypes } from '../core.config';
|
|
6
|
+
import { values } from '../values.config';
|
|
7
|
+
|
|
8
|
+
const REDUCER_KEY = values.reducerKey;
|
|
9
|
+
|
|
10
|
+
const INITIAL_STATE = {
|
|
11
|
+
jobs: [],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default (state = INITIAL_STATE, action) => {
|
|
15
|
+
let updateJobs = [];
|
|
16
|
+
let index = 0;
|
|
17
|
+
|
|
18
|
+
switch (action.type) {
|
|
19
|
+
case ActionTypes.LOGOUT:
|
|
20
|
+
case ActionTypes.CHANGE_ROLE:
|
|
21
|
+
return INITIAL_STATE;
|
|
22
|
+
case JOBS_LOADED:
|
|
23
|
+
return { ...state, jobs: action.payload.map(job => ({ title: job.title || job.description, ...job })) };
|
|
24
|
+
case JOBS_ADDED:
|
|
25
|
+
updateJobs = action.payload.map(job => ({ title: job.title || job.description, ...job }));
|
|
26
|
+
updateJobs = _.unionWith(updateJobs, state.jobs, (j1, j2) => {
|
|
27
|
+
return j1.id === j2.id;
|
|
28
|
+
});
|
|
29
|
+
return { ...state, jobs: updateJobs };
|
|
30
|
+
case JOB_ADDED:
|
|
31
|
+
updateJobs = [...state.jobs];
|
|
32
|
+
index = updateJobs.findIndex(item => item.id === action.payload.id);
|
|
33
|
+
if (index > -1) {
|
|
34
|
+
updateJobs[index] = action.payload;
|
|
35
|
+
} else {
|
|
36
|
+
updateJobs.push(action.payload);
|
|
37
|
+
}
|
|
38
|
+
return { ...state, jobs: updateJobs };
|
|
39
|
+
case REHYDRATE:
|
|
40
|
+
if (!action.payload) return state;
|
|
41
|
+
if (action.payload[REDUCER_KEY]) {
|
|
42
|
+
if (action.payload[REDUCER_KEY].jobs == null) {
|
|
43
|
+
action.payload[REDUCER_KEY].jobs = [];
|
|
44
|
+
}
|
|
45
|
+
return action.payload[REDUCER_KEY];
|
|
46
|
+
}
|
|
47
|
+
return state;
|
|
48
|
+
default:
|
|
49
|
+
return state;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import _ from 'lodash';
|
|
3
|
+
import { TouchableOpacity, View, ScrollView, Text } from 'react-native';
|
|
4
|
+
import { connect } from 'react-redux';
|
|
5
|
+
import { Icon } from 'react-native-elements';
|
|
6
|
+
import { Services } from '../feature.config';
|
|
7
|
+
import { Components, Colours } from '../core.config';
|
|
8
|
+
|
|
9
|
+
class JobTypePicker extends Component {
|
|
10
|
+
state = {
|
|
11
|
+
currentType: null,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
UNSAFE_componentWillMount() {
|
|
15
|
+
this.setState({ currentType: this.props.currentType });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
onPressBack() {
|
|
19
|
+
Services.navigation.goBack();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onTypePress(type) {
|
|
23
|
+
this.props.onSelectType(type);
|
|
24
|
+
this.setState({ currentType: type });
|
|
25
|
+
setTimeout(() => {
|
|
26
|
+
this.onPressBack();
|
|
27
|
+
}, 200);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
renderMain() {
|
|
31
|
+
if (_.isEmpty(this.props.types)) {
|
|
32
|
+
return (
|
|
33
|
+
<View style={{ marginTop: 16 }}>
|
|
34
|
+
<Components.Spinner />
|
|
35
|
+
</View>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return <Components.FormCard style={{ marginTop: 16 }}>{this.renderOptions()}</Components.FormCard>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
renderOptions() {
|
|
43
|
+
return this.props.types.map((rep, index) => {
|
|
44
|
+
return (
|
|
45
|
+
<TouchableOpacity key={index} onPress={this.onTypePress.bind(this, rep.typeName)}>
|
|
46
|
+
<Components.FormCardSection label={rep.typeName} labelStyle={{ height: 0, margin: 0 }} hasUnderline hasContent>
|
|
47
|
+
<View style={styles.labelContainer}>
|
|
48
|
+
<Text style={styles.labelText}>{rep.typeName}</Text>
|
|
49
|
+
<Icon
|
|
50
|
+
name="check-circle"
|
|
51
|
+
//style={styles.uploadButtonInner}
|
|
52
|
+
type="font-awesome"
|
|
53
|
+
iconStyle={[{ color: '#d5d9e0', fontSize: 20 }, rep.typeName === this.state.currentType && { color: Colours.COLOUR_GREEN }]}
|
|
54
|
+
/>
|
|
55
|
+
</View>
|
|
56
|
+
{!_.isEmpty(rep.description) && <Text style={styles.description}>{rep.description}</Text>}
|
|
57
|
+
</Components.FormCardSection>
|
|
58
|
+
</TouchableOpacity>
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
render() {
|
|
64
|
+
return (
|
|
65
|
+
<View style={styles.container}>
|
|
66
|
+
<Components.Header leftIcon="angle-left" onPressLeft={this.onPressBack.bind(this)} text="Select type" />
|
|
67
|
+
<ScrollView style={{ flex: 1 }}>{this.renderMain()}</ScrollView>
|
|
68
|
+
</View>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const styles = {
|
|
74
|
+
container: {
|
|
75
|
+
flex: 1,
|
|
76
|
+
position: 'relative',
|
|
77
|
+
backgroundColor: '#f0f0f5',
|
|
78
|
+
},
|
|
79
|
+
row: {
|
|
80
|
+
flexDirection: 'row',
|
|
81
|
+
alignItems: 'center',
|
|
82
|
+
minHeight: 22,
|
|
83
|
+
},
|
|
84
|
+
text: {
|
|
85
|
+
flex: 1,
|
|
86
|
+
fontFamily: 'sf-regular',
|
|
87
|
+
fontSize: 14,
|
|
88
|
+
color: Colours.TEXT_DARK,
|
|
89
|
+
},
|
|
90
|
+
labelContainer: {
|
|
91
|
+
flexDirection: 'row',
|
|
92
|
+
justifyContent: 'space-between',
|
|
93
|
+
},
|
|
94
|
+
labelText: {
|
|
95
|
+
fontFamily: 'sf-medium',
|
|
96
|
+
fontSize: 16,
|
|
97
|
+
color: Colours.TEXT_DARK,
|
|
98
|
+
},
|
|
99
|
+
description: {
|
|
100
|
+
marginTop: 5,
|
|
101
|
+
fontSize: 14,
|
|
102
|
+
fontFamily: 'sf-regular',
|
|
103
|
+
color: Colours.TEXT_DARK,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export default connect(null, {})(JobTypePicker);
|