From c30a5f8707dcefb6a7ea82f2627dbfef4fd213e0 Mon Sep 17 00:00:00 2001 From: Ananta Pandey Date: Wed, 5 Sep 2018 18:21:34 -0400 Subject: [PATCH] Onboarding Part 1 (#41) * create a privacy and terms screen * add an auth stack, save user token for future sessions * always show saved markers * add sign out button --- expo_project/components/MapWithMarkers.js | 4 +- expo_project/constants/Theme.js | 11 +++ expo_project/navigation/AppNavigator.js | 55 +++++++++--- expo_project/screens/AuthLoadingScreen.js | 37 ++++++++ expo_project/screens/AuthScreen.js | 101 ++++++++++++++++++++++ expo_project/screens/PrivacyScreen.js | 43 +++++++++ expo_project/screens/StudyIndexScreen.js | 20 ++++- expo_project/screens/SurveyScreen.js | 57 +++++++++--- 8 files changed, 297 insertions(+), 31 deletions(-) create mode 100644 expo_project/constants/Theme.js create mode 100644 expo_project/screens/AuthLoadingScreen.js create mode 100644 expo_project/screens/AuthScreen.js create mode 100644 expo_project/screens/PrivacyScreen.js diff --git a/expo_project/components/MapWithMarkers.js b/expo_project/components/MapWithMarkers.js index 485e87d..97eb431 100644 --- a/expo_project/components/MapWithMarkers.js +++ b/expo_project/components/MapWithMarkers.js @@ -92,7 +92,7 @@ class MapWithMarkers extends React.Component { const key = marker.id + (selected ? "-selected" : ""); //trigger a re render when switching states, so it recenters itself return ( { + const userToken = await AsyncStorage.getItem("userToken"); + this.props.navigation.navigate(userToken ? "App" : "Auth"); + }; + + render() { + return ( + + + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#fff", + justifyContent: "center", + alignItems: "center" + } +}); diff --git a/expo_project/screens/AuthScreen.js b/expo_project/screens/AuthScreen.js new file mode 100644 index 0000000..1864bfe --- /dev/null +++ b/expo_project/screens/AuthScreen.js @@ -0,0 +1,101 @@ +import React from "react"; +import { AsyncStorage, StyleSheet, View } from "react-native"; +import { withNavigation } from "react-navigation"; +import { Button, Subheading, Title } from "react-native-paper"; +import Theme from "../constants/Theme"; +import { Icon } from "expo"; +import firebase from "../lib/firebaseSingleton"; + +class AuthScreen extends React.Component { + static navigationOptions = { + header: null + }; + + constructor(props) { + super(props); + } + + _signIn = async () => { + try { + console.log("start the log ing"); + const { type, idToken } = await Expo.Google.logInAsync({ + iosClientId: + "8677857213-j9dn9ebe425td60q8c9tc20gomjbojip.apps.googleusercontent.com", + iosStandaloneAppClientId: + "8677857213-s1rosh2e597b3nccpqv67dbfpmc3q53o.apps.googleusercontent.com", + scopes: ["profile", "email"] + }); + + if (type === "success") { + // Build Firebase credential with the access token. + const credential = firebase.auth.GoogleAuthProvider.credential(idToken); + console.log(`credential: ${credential}`); + + // Sign in with credential from the Facebook user. + const firebaseSignInResult = await firebase + .auth() + .signInAndRetrieveDataWithCredential(credential); + console.log(`sign in result: ${firebaseSignInResult}`); + + // TODO: Check whether user has access to surveys, and if not add to a waiting list + + // set token for next session, then navigate to the internal app + await AsyncStorage.setItem("userToken", idToken); + this.props.navigation.navigate("App"); + } else { + console.log("cancelled"); + } + } catch (e) { + console.log("error", e); + } + }; + + render() { + return ( + + Create an account + + Once your study is complete, you can use graphs and text to explain + your findings + + + + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "white", + justifyContent: "center", + alignItems: "center" + }, + title: { + fontSize: 25, + marginHorizontal: 50 + }, + subheading: { + marginHorizontal: 50, + marginVertical: 30 + } +}); + +export default withNavigation(AuthScreen); diff --git a/expo_project/screens/PrivacyScreen.js b/expo_project/screens/PrivacyScreen.js new file mode 100644 index 0000000..510c317 --- /dev/null +++ b/expo_project/screens/PrivacyScreen.js @@ -0,0 +1,43 @@ +import React, { Component } from "react"; +import { StyleSheet, View, WebView } from "react-native"; +import { withNavigation } from "react-navigation"; + +import { Button, Divider, withTheme } from "react-native-paper"; + +class PrivacyScreen extends Component { + static navigationOptions = { + title: "Privacy & Terms" + }; + + render() { + return ( + + + + + + + + ); + } +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#fff" + }, + footer: { + padding: 20 + } +}); + +export default withNavigation(withTheme(PrivacyScreen)); diff --git a/expo_project/screens/StudyIndexScreen.js b/expo_project/screens/StudyIndexScreen.js index 1cdc341..e9157a3 100644 --- a/expo_project/screens/StudyIndexScreen.js +++ b/expo_project/screens/StudyIndexScreen.js @@ -1,8 +1,8 @@ import React from "react"; -import { ScrollView, StyleSheet, Text, View } from "react-native"; +import { AsyncStorage, ScrollView, StyleSheet, Text, View } from "react-native"; import { withNavigation } from "react-navigation"; - import studies from "../config/studies"; +import Theme from "../constants/Theme"; import { Button, Caption, @@ -18,10 +18,15 @@ class SurveyIndexScreen extends React.Component { title: "Studies" }; + _signOut = async () => { + await AsyncStorage.clear(); + this.props.navigation.navigate("Auth"); + }; + render() { return ( - + Your studies {studies.map(study => ( @@ -59,6 +64,15 @@ class SurveyIndexScreen extends React.Component { ))} + ); } diff --git a/expo_project/screens/SurveyScreen.js b/expo_project/screens/SurveyScreen.js index 38503e6..8074f40 100644 --- a/expo_project/screens/SurveyScreen.js +++ b/expo_project/screens/SurveyScreen.js @@ -8,15 +8,16 @@ import { View, TouchableOpacity } from "react-native"; +import { Button } from "react-native-paper"; import { withNavigation } from "react-navigation"; import * as _ from "lodash"; import moment from "moment"; import MapWithMarkers from "../components/MapWithMarkers"; import MarkerCarousel from "../components/MarkerCarousel"; import Survey from "../components/Survey"; +import { iconColors } from "../constants/Colors"; import Layout from "../constants/Layout"; - -import { Button } from "react-native-paper"; +import firebase from "../lib/firebaseSingleton"; // TODO (Ananta): shouold be dynamically set const INITIAL_DRAWER_TRANSLATE_Y = Layout.drawer.height; @@ -26,16 +27,21 @@ const MAX_DRAWER_TRANSLATE_Y = Layout.drawer.height - 95; // mostly collapsed, w function _markerToDataPoint(marker) { const dataPoint = {}; - fields = ["gender", "groupSize", "mode", "object", "posture", "timestamp"]; + fields = [ + "gender", + "groupSize", + "mode", + "object", + "posture", + "timestamp", + "location" + ]; fields.forEach(field => { if (marker[field]) { dataPoint[field] = marker[field]; } }); - if (marker.coordinate) { - dataPoint.location = marker.coordinate; - } return dataPoint; } @@ -58,7 +64,7 @@ class SurveyScreen extends React.Component { super(props); // firestore has its own timestamp type - this.firestore = this.props.screenProps.firebase.firestore(); + this.firestore = firebase.firestore(); this.firestore.settings({ timestampsInSnapshots: true }); this.state = { @@ -78,6 +84,33 @@ class SurveyScreen extends React.Component { this.setFormResponse = this.setFormResponse.bind(this); } + componentDidMount() { + // Query for saved data + const studyId = this.props.navigation.getParam("studyId"); + const surveyId = this.props.navigation.getParam("surveyId"); + + this.firestore + .collection("study") + .doc(studyId) + .collection("survey") + .doc(surveyId) + .collection("dataPoints") + .get() + .then(querySnapshot => { + const markers = []; + + querySnapshot.forEach(function(doc) { + const marker = { + id: doc.id, + ...doc.data(), + color: _.sample(_.values(iconColors)) + }; + markers.push(marker); + }); + this.setState({ markers }); + }); + } + componentWillMount() { this._panResponder = PanResponder.create({ onStartShouldSetPanResponder: (evt, gestureState) => false, @@ -232,7 +265,7 @@ class SurveyScreen extends React.Component { } } - createNewMarker(coordinate, color) { + createNewMarker(location, color) { const studyId = this.props.navigation.getParam("studyId"); const surveyId = this.props.navigation.getParam("surveyId"); const markersCopy = [...this.state.markers]; @@ -241,7 +274,7 @@ class SurveyScreen extends React.Component { const title = "Person " + (markersCopy.length + 1); const marker = { - coordinate: coordinate, + location, color, title, dateLabel @@ -268,7 +301,7 @@ class SurveyScreen extends React.Component { }); } - setMarkerLocation(id, coordinate) { + setMarkerLocation(id, location) { // TODO: add logic for updating in db const studyId = this.props.navigation.getParam("studyId"); const surveyId = this.props.navigation.getParam("surveyId"); @@ -276,7 +309,7 @@ class SurveyScreen extends React.Component { const marker = _.find(markersCopy, { id }); if (marker) { - marker.coordinate = coordinate; + marker.location = location; this.setState({ markers: markersCopy }); @@ -288,7 +321,7 @@ class SurveyScreen extends React.Component { .doc(surveyId) .collection("dataPoints") .doc(marker.firestoreId) - .update({ location: marker.coordinate }); + .update({ location: marker.location }); } }