Skip to content

Instantly share code, notes, and snippets.

@betiol
Created April 4, 2017 20:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save betiol/02279121f72c5b2a62e0f7541ca28ab1 to your computer and use it in GitHub Desktop.
Save betiol/02279121f72c5b2a62e0f7541ca28ab1 to your computer and use it in GitHub Desktop.
Dashboard
/**
* 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