mirror of
https://gitlab.com/wheres-the-tp/ui-mobile.git
synced 2026-01-25 11:44:55 -06:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
d30e3fe122
11 changed files with 191 additions and 43 deletions
|
|
@ -91,7 +91,7 @@ android {
|
|||
applicationId "com.aretherecookies"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 22
|
||||
versionCode 9
|
||||
versionCode 12
|
||||
versionName "1.0"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"web":{"client_id":"648700523612-jbif6e356rc13pbcmrmc7gk212eelgcp.apps.googleusercontent.com","project_id":"august-copilot-171122","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"U44sJzIyL0yCreGpJ1v1saNZ"}}
|
||||
{"web":{"client_id":"648700523612-lm35m5d7m7k0sdutqmatbfhq2qsnd5if.apps.googleusercontent.com","project_id":"august-copilot-171122","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"U44sJzIyL0yCreGpJ1v1saNZ"}}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
//@flow
|
||||
import React, { Component } from 'react';
|
||||
import { View, StatusBar } from 'react-native';
|
||||
import { View, StatusBar, AsyncStorage } from 'react-native'; // eslint-disable-line
|
||||
import { ThemeProvider } from 'react-native-material-ui';
|
||||
import theme from './ui-theme';
|
||||
import DrawerMenu from './pages/DrawerMenu';
|
||||
|
|
@ -16,6 +16,7 @@ import CreateFoodItem from './pages/CreateFoodItem';
|
|||
import AuthManager from './AuthManager';
|
||||
import LoginPage from './pages/LoginPage';
|
||||
import LandingPage from './pages/LandingPage';
|
||||
import ZipcodePage from './pages/ZipcodePage';
|
||||
|
||||
setObservableConfig(rxjsconfig);
|
||||
|
||||
|
|
@ -32,6 +33,11 @@ export default class App extends Component {
|
|||
this._drawer.open();
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
// uncomment this to force show the landing/zipcode screens
|
||||
// AsyncStorage.removeItem('zipcode');
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<NativeRouter>
|
||||
|
|
@ -53,6 +59,7 @@ export default class App extends Component {
|
|||
<Route path="/foodItem/:id" component={FoodItemDetail} />
|
||||
<Route path="/place/:id" component={PlaceDetail} />
|
||||
<Route path="/login" component={LoginPage} />
|
||||
<Route path="/zipcode" component={ZipcodePage} />
|
||||
<Route
|
||||
path="/createFoodItem"
|
||||
render={() => {
|
||||
|
|
|
|||
35
js/apis/GoogleMapsApi.js
Normal file
35
js/apis/GoogleMapsApi.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// @flow
|
||||
import { GoogleAPIKey } from '../constants/AppConstants';
|
||||
import { path } from 'ramda';
|
||||
|
||||
const url = 'https://maps.googleapis.com/maps/api/geocode/json';
|
||||
|
||||
type Location = {
|
||||
lat: number,
|
||||
lng: number,
|
||||
};
|
||||
|
||||
type AddressComponent = {
|
||||
long_name: string,
|
||||
short_name: string,
|
||||
types: Array<string>,
|
||||
};
|
||||
|
||||
type GeocodeResult = {
|
||||
results: Array<{
|
||||
address_components: Array<AddressComponent>,
|
||||
formatted_address: string,
|
||||
geometry: {
|
||||
location: Location,
|
||||
},
|
||||
place_id: string,
|
||||
types: Array<string>,
|
||||
}>,
|
||||
};
|
||||
|
||||
export const getCoordsFromZip = async (zip: string): Promise<Location> => {
|
||||
const res: GeocodeResult = await (await fetch(
|
||||
`${url}?key=${GoogleAPIKey}&address=${zip}`
|
||||
)).json();
|
||||
return path(['results', 0, 'geometry', 'location'], res) || { lat: 0, lng: 0 };
|
||||
};
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
// @flow
|
||||
import { type GooglePlaceObj } from '../records/PlaceRecord';
|
||||
import { GoogleAPIKey } from '../constants/AppConstants';
|
||||
|
||||
const apiKey = 'AIzaSyBfMm1y6JayCbXrQmgAG1R3ka4ZOJno_5E';
|
||||
const placesUrl = `https://maps.googleapis.com/maps/api/place/details/json?key=${apiKey}`;
|
||||
const photosUrl = `https://maps.googleapis.com/maps/api/place/photo?key=${apiKey}`;
|
||||
const placesUrl = `https://maps.googleapis.com/maps/api/place/details/json?key=${GoogleAPIKey}`;
|
||||
const photosUrl = `https://maps.googleapis.com/maps/api/place/photo?key=${GoogleAPIKey}`;
|
||||
|
||||
type GooglePlaceDetailsResponse = { error_message: ?string, result: GooglePlaceObj };
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
// @flow
|
||||
import { emitter } from '../streams/LocationStream';
|
||||
import { getCoordsFromZip } from './GoogleMapsApi';
|
||||
import { AsyncStorage } from 'react-native';
|
||||
|
||||
export const getCurrentPosition = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
@ -20,15 +22,32 @@ export const getCurrentPosition = () => {
|
|||
};
|
||||
|
||||
// TODO actually implement geolocation for zipcode into lat/lng
|
||||
export const getPositionFromZip = () => {
|
||||
const dummyPos: any = {
|
||||
export const getPositionFromZip = async (zip: string) => {
|
||||
const { lat: latitude, lng: longitude } = await getCoordsFromZip(zip);
|
||||
|
||||
const pos: any = {
|
||||
coords: {
|
||||
latitude: 30.267,
|
||||
longitude: -97.7485,
|
||||
latitude,
|
||||
longitude,
|
||||
},
|
||||
};
|
||||
return new Promise(resolve => {
|
||||
emitter(dummyPos);
|
||||
resolve(dummyPos);
|
||||
});
|
||||
|
||||
emitter(pos);
|
||||
|
||||
return pos;
|
||||
};
|
||||
|
||||
export const getLocation = async (zipcode: string) => {
|
||||
if (zipcode) {
|
||||
AsyncStorage.setItem('zipcode', zipcode);
|
||||
}
|
||||
|
||||
const currentZip = zipcode || (await AsyncStorage.getItem('zipcode'));
|
||||
|
||||
if (currentZip && currentZip !== 'usegps') {
|
||||
getPositionFromZip(currentZip);
|
||||
} else {
|
||||
AsyncStorage.setItem('zipcode', 'usegps');
|
||||
getCurrentPosition();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,3 +8,5 @@ export const BASE_URL = 'aretherecookies.herokuapp.com';
|
|||
|
||||
// @stouthaus
|
||||
// export const BASE_URL = '192.168.1.169:3000';
|
||||
|
||||
export const GoogleAPIKey = 'AIzaSyBfMm1y6JayCbXrQmgAG1R3ka4ZOJno_5E';
|
||||
|
|
|
|||
|
|
@ -1,13 +1,31 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { View, Text, Image } from 'react-native';
|
||||
import { View, Text, Image, AsyncStorage } from 'react-native';
|
||||
import atcCookieImage from '../../static/atc-cookie-logo.png';
|
||||
import { Link } from 'react-router-native';
|
||||
import RouterButton from 'react-router-native-button';
|
||||
import { compose, withHandlers, withState } from 'recompose';
|
||||
import { withRouterContext } from '../enhancers/routeEnhancers';
|
||||
|
||||
import theme from '../ui-theme';
|
||||
|
||||
const LandingPage = () => {
|
||||
type Props = {
|
||||
skipIfAlreadyChosen: () => void,
|
||||
setLoading: (val: boolean) => void,
|
||||
loading: boolean,
|
||||
router: {
|
||||
history: {
|
||||
replace: (route: string) => void,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const LandingPage = ({ skipIfAlreadyChosen, loading }: Props) => {
|
||||
if (loading) {
|
||||
skipIfAlreadyChosen();
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
|
|
@ -17,11 +35,15 @@ const LandingPage = () => {
|
|||
flex: 1,
|
||||
height: '100%',
|
||||
}}>
|
||||
<Image source={atcCookieImage} style={{ height: 320, marginBottom: 10, }} resizeMode="contain" />
|
||||
<Text style={{ fontSize: 24, marginBottom: 30, textAlign: 'center', width: 330, }}>
|
||||
<Image
|
||||
source={atcCookieImage}
|
||||
style={{ height: 320, marginBottom: 10 }}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
<Text style={{ fontSize: 24, marginBottom: 30, textAlign: 'center', width: 330 }}>
|
||||
We need to use your location to bring you the best experience possible.
|
||||
</Text>
|
||||
<View style={{ width: 275, marginBottom: 30, }}>
|
||||
<View style={{ width: 275, marginBottom: 30 }}>
|
||||
<RouterButton
|
||||
to="/list/food?positionBy=location"
|
||||
replace
|
||||
|
|
@ -29,11 +51,26 @@ const LandingPage = () => {
|
|||
color={theme.palette.primaryColor}
|
||||
/>
|
||||
</View>
|
||||
<Link to="/list/food?positionBy=zip" replace>
|
||||
<Text style={{ color: theme.palette.primaryColor, marginBottom: 20, fontSize: 16, }}>I'd rather not.</Text>
|
||||
<Link to="/zipcode" replace>
|
||||
<Text style={{ color: theme.palette.primaryColor, marginBottom: 20, fontSize: 16 }}>
|
||||
I'd rather not.
|
||||
</Text>
|
||||
</Link>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default LandingPage;
|
||||
export default compose(
|
||||
withRouterContext,
|
||||
withState('loading', 'setLoading', true),
|
||||
withHandlers({
|
||||
skipIfAlreadyChosen: (props: Props) => async () => {
|
||||
const zipcode = await AsyncStorage.getItem('zipcode');
|
||||
if (zipcode) {
|
||||
props.router.history.replace('/list/food');
|
||||
} else {
|
||||
props.setLoading(false);
|
||||
}
|
||||
},
|
||||
})
|
||||
)(LandingPage);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import ScrollableTabView from 'react-native-scrollable-tab-view';
|
|||
import theme from '../ui-theme.js';
|
||||
import { type RoutingContextFlowTypes, routingContextPropTypes } from '../routes';
|
||||
import { getSearch } from '../helpers/RouteHelpers';
|
||||
import { getCurrentPosition, getPositionFromZip } from '../apis/PositionApi';
|
||||
import { getLocation } from '../apis/PositionApi';
|
||||
|
||||
const tabs = ['food', 'places'];
|
||||
|
||||
|
|
@ -37,22 +37,10 @@ class List extends Component {
|
|||
// TODO convert this component to SFC using recompose
|
||||
// also, figure out a less lifecyle-y way to do this request
|
||||
componentDidMount() {
|
||||
this.getLocation();
|
||||
const { zipcode } = getSearch(this.context);
|
||||
getLocation(zipcode);
|
||||
}
|
||||
|
||||
getLocation = () => {
|
||||
const { positionBy = 'zip' } = getSearch(this.context);
|
||||
try {
|
||||
if (positionBy === 'location') {
|
||||
return getCurrentPosition();
|
||||
} else {
|
||||
return getPositionFromZip();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error); // eslint-disable-line
|
||||
}
|
||||
};
|
||||
|
||||
updateTabRoute = ({ i }: { i: number }) => {
|
||||
const currentTab = getTabIndex(this.props);
|
||||
|
||||
|
|
@ -94,8 +82,8 @@ class List extends Component {
|
|||
prerenderingSiblingsNumber={Infinity}
|
||||
onChangeTab={this.updateTabRoute}
|
||||
initialPage={getTabIndex(this.props)}>
|
||||
<Food tabLabel="FOOD" onRefresh={this.getLocation} />
|
||||
<Places tabLabel="PLACES" onRefresh={this.getLocation} />
|
||||
<Food tabLabel="FOOD" onRefresh={getLocation} />
|
||||
<Places tabLabel="PLACES" onRefresh={getLocation} />
|
||||
</ScrollableTabView>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//@flow
|
||||
import React from 'react';
|
||||
import { View, Text, Button } from 'react-native';
|
||||
import { withHandlers, compose } from 'recompose';
|
||||
import { withHandlers, compose, withState } from 'recompose';
|
||||
import { withRouterContext } from '../enhancers/routeEnhancers';
|
||||
import AuthManager, { type AUTH_PROVIDER } from '../AuthManager';
|
||||
import queryString from 'query-string';
|
||||
|
|
@ -10,8 +10,18 @@ import theme from '../ui-theme';
|
|||
|
||||
type Props = {
|
||||
authUser: (provider: string) => () => Promise<void>,
|
||||
error: string,
|
||||
setError: (err: string) => void,
|
||||
router: {
|
||||
history: {
|
||||
replace: (url: string) => void,
|
||||
location: {
|
||||
search: string,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const LoginPageComponent = ({ authUser }: Props) => {
|
||||
const LoginPageComponent = ({ authUser, error }: Props) => {
|
||||
return (
|
||||
<View style={{ flexDirection: 'column', alignItems: 'center' }}>
|
||||
<Text style={theme.loginPage.titleStyle}>Sign In</Text>
|
||||
|
|
@ -29,14 +39,18 @@ const LoginPageComponent = ({ authUser }: Props) => {
|
|||
color={theme.palette.google}
|
||||
/>
|
||||
</View>
|
||||
{error && <Text>Login Failed! {error}</Text>}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const LoginPage = compose(
|
||||
withRouterContext,
|
||||
withState('error', 'setError', null),
|
||||
withHandlers({
|
||||
authUser: ({ router: { history } }) => (provider: AUTH_PROVIDER) => async () => {
|
||||
authUser: ({ router: { history }, setError }: Props) => (
|
||||
provider: AUTH_PROVIDER
|
||||
) => async () => {
|
||||
const { returnto = '/' } = queryString.parse(history.location.search);
|
||||
try {
|
||||
if (!AuthManager.isLoggedIn()) {
|
||||
|
|
@ -44,7 +58,11 @@ const LoginPage = compose(
|
|||
}
|
||||
history.replace(returnto);
|
||||
} catch (error) {
|
||||
console.log(error); //eslint-disable-line
|
||||
if (error && error.message) {
|
||||
setError(error.message);
|
||||
} else if (typeof error === 'string') {
|
||||
setError(error);
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
|
|
|||
42
js/pages/ZipcodePage.js
Normal file
42
js/pages/ZipcodePage.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { View, Text, TextInput } from 'react-native';
|
||||
import { compose, withState } from 'recompose';
|
||||
import RouterButton from 'react-router-native-button';
|
||||
|
||||
import theme from '../ui-theme';
|
||||
|
||||
type Props = {
|
||||
zipcode: string,
|
||||
setZipcode: (zip: string) => void,
|
||||
};
|
||||
|
||||
const ZipcodePage = ({ zipcode, setZipcode }: Props) => {
|
||||
return (
|
||||
<View style={{ flex: 1, justifyContent: 'center', padding: 30 }}>
|
||||
<Text style={{ fontSize: 18 }}>
|
||||
OK, we won't detect your location. Instead, please enter a zipcode for us to use as your
|
||||
default location.
|
||||
</Text>
|
||||
<TextInput
|
||||
onChangeText={setZipcode}
|
||||
value={zipcode}
|
||||
placeholder="Zipcode"
|
||||
keyboardType="numeric"
|
||||
style={{ marginBottom: 20 }}
|
||||
maxLength={5}
|
||||
autoFocus
|
||||
/>
|
||||
<RouterButton
|
||||
to={`/list/food?zipcode=${zipcode}`}
|
||||
title="Save"
|
||||
color={theme.palette.primaryColor}
|
||||
disabled={!(zipcode && zipcode.length === 5)}
|
||||
replace
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default compose(withState('zipcode', 'setZipcode', ''))(ZipcodePage);
|
||||
Loading…
Add table
Reference in a new issue