Reference Source

src/components/views/reportfound-view.js

import React, {Component} from 'react';
import {AppRegistry, StyleSheet, Text, View, TouchableOpacity, TouchableHighlight, ScrollView, Alert, Button} from 'react-native';
import ModalDropdown from 'react-native-modal-dropdown';
import MapView from 'react-native-maps';
import {Marker} from 'react-native-maps';
import { TextInput } from 'react-native-paper';
import { HeaderBackButton } from 'react-navigation';

import { styles, colours, reportfound_styles } from './stylesheets/reportfound-styles';

import ReportFoundPresenter from '../presenters/reportfound-presenter';
import BaseView from './view';

/**
 * Class for the reportfound view
 * @extends BaseView
 */
class ReportFoundView extends BaseView {
	/**
	 * Creates an instance of the report found view
	 *
	 * @constructor
	 * @param {Object} props - Component properties
	 */
	constructor(props) {
  		super(props);
		this.reportfoundP = new ReportFoundPresenter(this);
		this.state = {
			text:'',
			bikeMenu:[],
			region:{
				latitude:44.237424,
				longitude:-76.5131,
				latitudeDelta:0.0922,
				longitudeDelta:0.0421,
	  		},
		  thisMarker: [],
		};
	}

	/**
	 * Set the navigation options, change the header to handle a back button.
	 *
	 * @return {Object} Navigation option
	 */
	static navigationOptions = ({navigation, transitioning}) => {
		const { params = {} } = navigation.state;
		const back = params._onBack ? params._onBack : () => 'default';
		return {
			headerLeft: (<HeaderBackButton disabled={transitioning} onPress={()=>{back()}}/>),
		};
	}

	/**
	 * The back function to go to the previous page.
	 */
	_onBack = () => {
		this.props.navigation.navigate(this.state.from);
	}
	
	/**
	 * Sets a marker in the state. Only one marker is stored at a time.
	 *
	 * @param {Object} e - A place marker event
	 */
	setMarker(e){
		let coor = e.nativeEvent.coordinate;
		this.setState({
			thisMarker:[{key: 0, coordinate:coor}],
		});
	}

	/**
	 * Component is about to mount, initialize the data before rendering.
	 */
	componentWillMount = () => {
		this.props.navigation.setParams({
			_onBack: this._onBack,
		});
		
		const { navigation } = this.props;
		const data = navigation.getParam('rawData', 'NO-DATA');

		const fromPage = navigation.getParam('from', 'Home');
		this.setState({
			editeddata: data,
			from: fromPage
		});
	};

	/**
	 * Component mounted
	 */
	componentDidMount = () => {
		this._setUserLocation();
	};

	/**
	 * Component is about to unmount.
	 */
	componentWillUnmount = () => {
		this.viewUnmounting(this.reportfoundP);
	}
	
	/**
	 * Region has changed so set the state to the new region.
	 *
	 * @param {Object} region - A new region. Properties: latitude, longitude, latitudeDelta, longitudeDelta
	 */
	onRegionChange = (region) =>{
		this.setState({region:region});
	}

	/**
	 * Set the location of user.
 	 */
	_setUserLocation = () => {
		this._getCurrentLocation().then(position => {
			if (position) {
				const location = {
					latitude: position.coords.latitude,
					longitude: position.coords.longitude,
					latitudeDelta: 0.0922,
					longitudeDelta: 0.0421,
				};
				this.setState({
					region: location
				});
			}
		});
	}

	/**
	 * Get user's current location.
	 */
	_getCurrentLocation = () => {
		return new Promise((resolve, reject) => {
			navigator.geolocation.getCurrentPosition(position => resolve(position), e => reject(e));
		});
	};

	/**
	 * Handle the events after clicking submit button.
	 */
	_handleClick() {
		if (typeof(this.state.thisMarker[0])==='undefined') {
			Alert.alert("Please pin a location")
		} else {
			this.sendUpdate();
		}
	}

	/**
	 * Refreshes the state of the component so new data is fetched.
	 */
	refreshState = () => {
		this.setState({
			refresh: !this.state.refresh
		});
	}

	/**
	 * Get needed data from the view and send it to presenter.
	 */
	sendUpdate = () => {
		// console.log('latitude in reportfound: '+this.state.thisMarker[0].coordinate.latitude)
		// Extract data from components
		let new_data = {
			data:	{
				coordinate:this.state.thisMarker[0].coordinate,
				editeddata:this.state.editeddata,
				text:this.state.text,
			}
		}
		const data = new_data;
		this.reportfoundP.update(data, this.alertCallback);
	}

	/**
	 * Sets a callback on what to do if there is a success or error when a bike is uploaded.
	 *
	 * @param {Boolean} success - true: Uploading successful; false: Uploading failed
	 */
	alertCallback = (success) => {
		this.refreshState();
		if (success) {
			Alert.alert(
				"Report successfully uploaded!",
				"",
				[
					{ text: "Ok", onPress: () => this.props.navigation.navigate('Home'), style: "ok" },
				],
				{ cancelable: false },
			);
		} else {
			Alert.alert(
				"Fail to report.",
				"Please try again.",
				[
					{ text: "Ok", onPress: () => {}, style: "ok" },
				],
				{ cancelable: false },
			);
		}
	}

	/**
	 * Render the text of button.
	 * @param {Object} rowData - the row data of the bike menu
	 * @return {string} Returns the name of the component
	 */
	_dropdown_2_renderButtonText(rowData) {
		const {name} = rowData;
		return `${name}`;
	}

	/**
	 * Events after selecting the item from the dropdown menu
	 * @param {Number} idx - the id of the selected item in menu.
	 * @param {Object} value - the value of the selected item.
	 */
	_dropdown_2_onSelect = (idx,value) => {
		this.setState({bikeid: `${value.id}`});
	}

	/**
	 * Render each row in the menu. Highlights the selected item.
	 * @param {Object} rowData - each data in bikemenu
	 * @param {Number} rowID - the id of item in the menu
	 * @param {Boolean} highlighted - If the component should be highlighted or not
	 */
	 _dropdown_2_renderRow(rowData, rowID, highlighted) {
		let evenRow = rowID % 2;

		return (
			<TouchableHighlight underlayColor='cornflowerblue'>
				<View style={[reportfound_styles.dropdown_2_row, {backgroundColor: evenRow ? 'lemonchiffon' : 'white'}]}>
					<Text style={[reportfound_styles.dropdown_2_row_text, highlighted && {color: 'mediumaquamarine'}]}>
						{`${rowData.name} `}
					</Text>
				</View>
		  </TouchableHighlight>
		);
	}

	/**
	 * Renders the react native component.
	 */
	render() {
		return (
			<View style={styles.container}>
				<Text style={reportfound_styles.serial_number}>
					{"Serial Number: " + this.state.editeddata.serial_number}
				</Text>
				<TextInput style={reportfound_styles.row1}
					label="Add a Description"
					multiline={true}
					blurOnSubmit
					onChangeText={(text) => this.setState({text})}>
			   	</TextInput>

				<View style = {reportfound_styles.cell}>
					<MapView style = {reportfound_styles.cell}
						region= {this.state.region}
						onPress = {e => this.setMarker(e)}
						onRegionChangeComplete={this.onRegionChange.bind(this)}>
						{this.state.thisMarker.map(marker=> (<Marker draggable {...marker}/>))}
					</MapView>
				</View>
				<View>
					<TouchableHighlight style={reportfound_styles.submitButton} onPress={this._handleClick.bind(this)}>
						<Button color={'#000'} title="SUBMIT"/>
					</TouchableHighlight>
				</View>
		  </View>
		);
	}
}

export default ReportFoundView;