Created
April 4, 2017 20:12
-
-
Save betiol/02279121f72c5b2a62e0f7541ca28ab1 to your computer and use it in GitHub Desktop.
Dashboard
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Sample React Native App | |
* https://github.com/facebook/react-native | |
* @flow | |
*/ | |
import React, { Component } from 'react'; | |
import Login from './Login'; | |
import { API, ApiException, dateFormat } from '../Utils/API'; | |
import MapView from 'react-native-maps'; | |
import ActionButton from 'react-native-action-button'; | |
import Modal from 'react-native-simple-modal'; | |
import moment from 'moment'; | |
import { Button, Section, Status, Card } from './Helpers'; | |
import Spinner from 'react-native-spinkit'; | |
import Icon from 'react-native-vector-icons/Ionicons'; | |
import CookieManager from 'react-native-cookies'; | |
import Positions from './Positions'; | |
import { | |
Alert, | |
StyleSheet, | |
View, | |
Text, | |
Image, | |
TouchableHighlight, | |
AsyncStorage, | |
TouchableOpacity, | |
LayoutAnimation, | |
StatusBar, | |
InteractionManager, | |
} from 'react-native'; | |
import DatePickerTime from 'react-native-datepicker'; | |
import { Container, Navbar } from 'navbar-native'; | |
const dateTimeComponentFormat = 'DD/MM/YYYY HH:mm'; | |
const IMG_NORMAL = require('../images/normal.png'); | |
const IMG_ONLINE = require('../images/seta-online.png'); | |
class Dashboard extends Component { | |
constructor() { | |
super(); | |
this.animationInterval = undefined; | |
this.tries = 0; | |
this.state = { | |
isLoading: true, | |
positions: [], | |
coordinates: [], | |
isVisible: false, | |
modalDate: false, | |
loading: true, | |
dtInicio: moment().subtract(8, 'hours').format(dateTimeComponentFormat), | |
dtFim: moment().format(dateTimeComponentFormat) | |
}; | |
} | |
_renderIgnicao(speed, mode) { | |
if (mode == 2 || speed > 0) { | |
return 'Ligado'; | |
} | |
return 'Desligado'; | |
} | |
loadPositions(last) { | |
if (this.animationInterval) clearInterval(this.animationInterval); | |
last = last || false; | |
var dtInicio = this.state.dtInicio; | |
var dtFim = this.state.dtFim; | |
var imei = this.props.imei; | |
var api = undefined; | |
if (!last) { | |
dtInicio = moment(dtInicio, dateTimeComponentFormat).seconds(0); | |
dtFim = moment(dtFim, dateTimeComponentFormat).seconds(59); | |
if (dtInicio.isAfter(dtFim)) { | |
Alert.alert('Atenção', 'A Data Início deve ser inferior a Data Final.'); | |
return; | |
} | |
api = API.getPositions(imei, dtInicio.utc().format(dateFormat), dtFim.utc().format(dateFormat)); | |
} else { | |
api = API.ffLastPositions(imei); | |
} | |
if (api) { | |
this.setState({ | |
isLoading: true, | |
isVisible: true, | |
}); | |
api | |
.then(res => res.json()) | |
.then(res => { | |
var coordinates = []; | |
var positions = []; | |
res = res.filter(position => position && position.latitude && position.longitude); | |
res = res | |
.sort((a, b) => { | |
if (a.time < b.time) | |
return 1; | |
if (a.time > b.time) | |
return -1; | |
return 0; | |
}) | |
.map(position => { | |
coordinates.push({ | |
latitude: position.latitude, | |
longitude: position.longitude, | |
}); | |
return position; | |
}); | |
return { | |
positions: res, | |
coordinates: coordinates, | |
}; | |
}) | |
.then(res => { | |
if (res.positions.length) { | |
this.refs.map.fitToCoordinates(res.coordinates, { | |
edgePadding: { top: 40, right: 40, bottom: 40, left: 40 }, | |
animated: true | |
}); | |
} else { | |
Alert.alert('Atenção', 'Nenhuma posição encontrada.'); | |
} | |
this.setState({ | |
positions: res.positions || [], | |
coordinates: res.coordinates || [], | |
isLoading: false, | |
}); | |
}) | |
.catch(err => { | |
if (err instanceof ApiException) { | |
Alert.alert('Ocorreu um erro', 'Não foi possível completar a solicitação.'); | |
} | |
}).finally(() => { | |
this.setState({ isVisible: false, modalDate: false }); | |
}); | |
} | |
} | |
_renderPositions() { | |
InteractionManager.runAfterInteractions(() => { | |
this.props.navigator.push({ | |
component: Positions, | |
passProps: { position: this.state.positions } | |
}) | |
this.setState({ | |
loading: false | |
}); | |
}) | |
} | |
loadMap() { | |
this.setState({ | |
isVisible: true | |
}); | |
} | |
componentWillUnmount() { | |
if (this.animationInterval) clearInterval(this.animationInterval); | |
} | |
componentWillMount() { | |
InteractionManager.runAfterInteractions(() => { | |
this.loadPositions(true); | |
}); | |
} | |
renderButton() { | |
if (this.state.isVisible) { | |
return <View style={styles.viewSpinner}> | |
<Spinner | |
isVisible | |
size={50} | |
type={'Wave'} | |
color={'#FF9800'} | |
style={styles.spinnerStyle} | |
/> | |
</View>; | |
} | |
return ( | |
<View style={{ paddingTop: 10 }}> | |
<Button onPress={this.loadPositions.bind(this, false)}>Buscar</Button> | |
</View> | |
) | |
} | |
_loadMarkers(positions, coordinates) { | |
positions = positions.map((position, index) => { | |
const coordinate = { | |
latitude: position.latitude, | |
longitude: position.longitude, | |
}; | |
var iconStyle = { zIndex: (positions.length - index) } | |
var imgMarker = undefined; | |
if (!index) { | |
imgMarker = IMG_NORMAL | |
} else { | |
imgMarker = IMG_ONLINE | |
iconStyle.transform = [{ rotate: (position.course) + 'deg' }]; | |
} | |
return <MapView.Marker | |
style={iconStyle} | |
key={"marker-" + index} | |
coordinate={coordinate} | |
image={imgMarker} | |
onPress={e => this._showCallout.bind(this, e, coordinate)}> | |
<MapView.Callout style={styles.customView}> | |
<View> | |
<Text style={{ fontSize: 20, marginBottom: 10 }}>{moment(position.time, 'x').format('DD/MM/YYYY HH:mm:ss')}</Text> | |
<Text>Endereço: {position.address}</Text> | |
<Text>Velocidade: {Math.round(position.speed)} km/h</Text> | |
<Text>Ignição: {this._renderIgnicao(position.speed, position.mode)}</Text> | |
<Text>Odometro: {position.distance}</Text> | |
</View> | |
</MapView.Callout> | |
</MapView.Marker>; | |
}); | |
return positions; | |
} | |
_followPositions() { | |
const currentPositions = Object.assign([], this.state.positions).reverse(); | |
const currentCoordinates = Object.assign([], this.state.coordinates).reverse(); | |
var current = 0; | |
this.animationInterval = setInterval(() => { | |
var coordinates = currentCoordinates.slice(0, current); | |
if (currentCoordinates.length == coordinates.length && this.animationInterval) { | |
clearInterval(this.animationInterval); | |
} | |
this.setState({ | |
coordinates: coordinates.reverse(), | |
positions: currentPositions.slice(0, current++).reverse(), | |
}); | |
if (coordinates && coordinates.length) | |
this.refs.map.animateToCoordinate(coordinates[0], 200); | |
}, 1000); | |
} | |
_showCallout(e, coordinate) { | |
this.refs.map.animateToCoordinate(coordinate, 200); | |
e.showCallout(); | |
} | |
_logout() { | |
CookieManager.clearAll(() => { | |
AsyncStorage.clear().then(() => { | |
this.props.navigator.resetTo(Login); | |
}); | |
}); | |
} | |
render() { | |
const dateInputStyles = { | |
dateIcon: { | |
position: 'absolute', | |
left: 0, | |
top: 4, | |
marginLeft: 0, | |
}, | |
dateInput: { | |
marginLeft: 36, | |
borderColor: '#ff9800' | |
} | |
}; | |
return ( | |
<Container> | |
<Navbar | |
bgColor={"#FF9800"} | |
title={this.props.placa} | |
titleColor={'#fff'} | |
statusBar={{ | |
bgColor: "#FF9800", | |
style: "light-content", | |
hideAnimation: Navbar.FADE, | |
showAnimation: Navbar.SLIDE, | |
}} | |
left={{ | |
icon: "ios-arrow-back", | |
iconColor: "white", | |
style: { color: 'white' }, | |
label: "Voltar", | |
onPress: () => { this.props.navigator.pop() } | |
}} | |
right={{ | |
iconFamily: 'MaterialIcons', | |
icon: "exit-to-app", | |
iconColor: "white", | |
style: { color: 'white' }, | |
onPress: () => { this._logout() } | |
}} | |
/> | |
<MapView | |
loadingEnabled={this.state.isLoading} | |
loadingIndicatorColor={'#FF9800'} | |
showsUserLocation={true} | |
followUserLocation={true} | |
showsCompass={true} | |
showsPointsOfInterest={true} | |
rotateEnabled={true} | |
toolbarEnabled={true} | |
style={styles.container} | |
ref="map"> | |
{this._loadMarkers(this.state.positions, this.state.coordinates)} | |
<MapView.Polyline | |
coordinates={this.state.coordinates} | |
strokeColor={'#00FFFF'} | |
strokeWidth={3} /> | |
</MapView> | |
<ActionButton buttonColor="#d35400" position="center"> | |
<ActionButton.Item buttonColor='#4CAF50' onPress={() => this._followPositions()} title="Acompanhar" > | |
<Icon name="md-play" style={styles.actionButtonIcon} /> | |
</ActionButton.Item> | |
<ActionButton.Item buttonColor='#d35400' onPress={() => this.setState({ modalDate: true })} title="Pesquisar" > | |
<Icon name="md-calendar" style={styles.actionButtonIcon} /> | |
</ActionButton.Item> | |
<ActionButton.Item buttonColor='#2196F3' onPress={() => this._renderPositions()} title="Listagem" > | |
<Icon name="md-pin" style={styles.actionButtonIcon} /> | |
</ActionButton.Item> | |
</ActionButton> | |
<Modal | |
offset={this.state.offset} | |
open={this.state.modalDate} | |
modalDidClose={() => this.state.isVisible ? Alert.alert('Um momento', 'Aguarde o término da solicitação') : this.setState({ modalDate: false })} | |
style={{ alignItems: 'center', width: 100 }}> | |
<View key="modal-details" style={{ justifyContent: 'center' }}> | |
<Text style={{ fontSize: 20, marginBottom: 10, color: '#000', alignSelf: 'center' }}>Pesquisar por Período:</Text> | |
<DatePickerTime | |
onDateChange={(date) => { this.setState({ dtInicio: date }) }} | |
style={styles.dateTimePicker} | |
customStyles={dateInputStyles} | |
date={this.state.dtInicio} | |
mode="datetime" | |
minDate={this.state.minDate} | |
placeholder="Selecione um Período" | |
format={dateTimeComponentFormat} | |
confirmBtnText="Confirmar" | |
cancelBtnText="Cancelar" | |
onPressCancel={() => { this.state.isVisible ? Alert.alert('Um momento', 'Aguarde o termino da solicitação') : this.setState({ modalDate: false }) }} | |
/> | |
<DatePickerTime | |
onDateChange={(date) => { this.setState({ dtFim: date }) }} | |
style={styles.dateTimePicker} | |
customStyles={dateInputStyles} | |
date={this.state.dtFim} | |
mode="datetime" | |
placeholder="Selecione um Período" | |
format={dateTimeComponentFormat} | |
confirmBtnText="Confirmar" | |
cancelBtnText="Cancelar" | |
onPressCancel={() => { this.setState({ modalDate: false }) }} | |
/> | |
{this.renderButton()} | |
</View> | |
</Modal> | |
</Container> | |
) | |
} | |
} | |
const styles = StyleSheet.create({ | |
container: { | |
flex: 1, | |
}, | |
customView: { | |
width: 250, | |
height: null, | |
}, | |
spinnerStyle: { | |
marginBottom: 0, | |
}, | |
viewSpinner: { | |
justifyContent: 'center', | |
alignItems: 'center' | |
}, | |
actionButtonIcon: { | |
color: '#fff', | |
fontSize: 23, | |
height: 22, | |
}, | |
dateTimePicker: { | |
width: undefined, | |
marginBottom: 10, | |
}, | |
}); | |
module.exports = Dashboard; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment