mirror of
https://gitlab.com/wheres-the-tp/ui-mobile.git
synced 2026-01-25 07:54:57 -06:00
use google places api for all places components
This commit is contained in:
parent
b6b5497a72
commit
e23f279b65
11 changed files with 152 additions and 61 deletions
18
js/apis/PlaceDetailsApi.js
Normal file
18
js/apis/PlaceDetailsApi.js
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
// @flow
|
||||||
|
const apiKey = 'AIzaSyBfMm1y6JayCbXrQmgAG1R3ka4ZOJno_5E';
|
||||||
|
const placesUrl = `https://maps.googleapis.com/maps/api/place/details/json?key=${apiKey}`;
|
||||||
|
|
||||||
|
export const getPlaceDetails = async (placeid: string) => {
|
||||||
|
if (!placeid || typeof placeid !== 'string') {
|
||||||
|
throw new Error('placeid looks wrong');
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(`${placesUrl}&placeid=${placeid}`);
|
||||||
|
|
||||||
|
const { error_message, result } = await res.json();
|
||||||
|
|
||||||
|
if (error_message) {
|
||||||
|
throw new Error(error_message);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
@ -60,10 +60,10 @@ export const FoodItemTile = pure(({ foodItem = {}, place = {} }: { foodItem: Foo
|
||||||
<Thumbnail thumb={foodItem.thumbImage} />
|
<Thumbnail thumb={foodItem.thumbImage} />
|
||||||
<View style={{ paddingTop: 15 }}>
|
<View style={{ paddingTop: 15 }}>
|
||||||
<StrongText>
|
<StrongText>
|
||||||
{foodItem.name}
|
{foodItem.name || ''}
|
||||||
</StrongText>
|
</StrongText>
|
||||||
<SubText>
|
<SubText>
|
||||||
{`${place.name} - ${foodItem.distance} mi`}
|
{`${place.name || ''} - ${foodItem.distance} mi`}
|
||||||
</SubText>
|
</SubText>
|
||||||
</View>
|
</View>
|
||||||
</TileBox>
|
</TileBox>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
import { View } from 'react-native';
|
import { View } from 'react-native';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { pure } from 'recompose';
|
import { pure } from 'recompose';
|
||||||
import { type List } from 'immutable';
|
import { List } from 'immutable';
|
||||||
import typeof PlaceRecord from '../records/PlaceRecord';
|
import typeof PlaceRecord from '../records/PlaceRecord';
|
||||||
import { Link } from 'react-router-native';
|
import { Link } from 'react-router-native';
|
||||||
import { Thumbnail, StrongText, SubText } from './ItemTile';
|
import { Thumbnail, StrongText, SubText } from './ItemTile';
|
||||||
|
|
@ -11,7 +11,7 @@ import { routeWithTitle } from '../helpers/RouteHelpers';
|
||||||
import theme from '../ui-theme';
|
import theme from '../ui-theme';
|
||||||
|
|
||||||
type PlaceTileProps = { place: PlaceRecord, distance: number, categories: List<string> };
|
type PlaceTileProps = { place: PlaceRecord, distance: number, categories: List<string> };
|
||||||
export default pure(({ place, distance, categories }: PlaceTileProps) => {
|
export default pure(({ place = {}, distance = 999, categories = new List() }: PlaceTileProps) => {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
to={routeWithTitle(`/place/${place.id || ''}`, place.name)}
|
to={routeWithTitle(`/place/${place.id || ''}`, place.name)}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { path } from 'ramda';
|
||||||
import mapPropsStream from 'recompose/mapPropsStream';
|
import mapPropsStream from 'recompose/mapPropsStream';
|
||||||
import FoodItems$ from '../streams/FoodItemsStream';
|
import FoodItems$ from '../streams/FoodItemsStream';
|
||||||
import typeof FoodItemRecord from '../records/FoodItemRecord';
|
import typeof FoodItemRecord from '../records/FoodItemRecord';
|
||||||
import { Set, Map } from 'immutable';
|
import { Map } from 'immutable';
|
||||||
import { getCategoryText } from '../helpers/CategoryHelpers';
|
import { getCategoryText } from '../helpers/CategoryHelpers';
|
||||||
|
|
||||||
export const withFoodItems = mapPropsStream(props$ =>
|
export const withFoodItems = mapPropsStream(props$ =>
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,9 @@ import { type List, type Map } from 'immutable';
|
||||||
|
|
||||||
export const pushInto = <T>(list: List<T>, item: T): List<T> => list.push(item);
|
export const pushInto = <T>(list: List<T>, item: T): List<T> => list.push(item);
|
||||||
|
|
||||||
export const setById = (map: Map<string, any>, item: { id: string }): Map<string, any> => map.set(item.id, item);
|
export const setById = (map: Map<string, any>, item: { id: string }): Map<string, any> => {
|
||||||
|
if (!item.id) {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
return map.set(item.id, item);
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,8 @@ export default compose(
|
||||||
longitude,
|
longitude,
|
||||||
name,
|
name,
|
||||||
address,
|
address,
|
||||||
|
phoneNumber,
|
||||||
|
website,
|
||||||
}) => {
|
}) => {
|
||||||
setPlace(
|
setPlace(
|
||||||
new PlaceRecord({
|
new PlaceRecord({
|
||||||
|
|
@ -127,6 +129,8 @@ export default compose(
|
||||||
address,
|
address,
|
||||||
latitude,
|
latitude,
|
||||||
longitude,
|
longitude,
|
||||||
|
phoneNumber,
|
||||||
|
website,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,102 @@
|
||||||
// @flow
|
// @flow
|
||||||
import { Record } from 'immutable';
|
import { List, Record, fromJS } from 'immutable';
|
||||||
|
|
||||||
|
export type GooglePlaceObj = {
|
||||||
|
place_id: string,
|
||||||
|
name: string,
|
||||||
|
formatted_address: string,
|
||||||
|
geometry: {
|
||||||
|
location: {
|
||||||
|
lat: number,
|
||||||
|
lng: number,
|
||||||
|
},
|
||||||
|
viewport: {
|
||||||
|
northeast: {
|
||||||
|
lat: number,
|
||||||
|
lng: number,
|
||||||
|
},
|
||||||
|
southwest: {
|
||||||
|
lat: number,
|
||||||
|
lng: number,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
formatted_phone_number: string,
|
||||||
|
url: string,
|
||||||
|
photos: Array<string>,
|
||||||
|
icon: string,
|
||||||
|
opening_hours: {
|
||||||
|
open_now: boolean,
|
||||||
|
periods: Array<{
|
||||||
|
close: {
|
||||||
|
day: number,
|
||||||
|
time: string,
|
||||||
|
},
|
||||||
|
open: {
|
||||||
|
day: number,
|
||||||
|
time: string,
|
||||||
|
},
|
||||||
|
}>,
|
||||||
|
weekday_text: Array<string>,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export type Place = {
|
export type Place = {
|
||||||
id: ?string,
|
id: string,
|
||||||
name: string,
|
name: string,
|
||||||
address: string,
|
address: string,
|
||||||
latitude: ?number,
|
latitude: number,
|
||||||
longitude: ?number,
|
longitude: number,
|
||||||
|
phoneNumber: string,
|
||||||
|
googleMapsUrl: string,
|
||||||
|
photos: List<string>,
|
||||||
|
icon: string,
|
||||||
|
hours: List<string>,
|
||||||
|
openNow: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
const FoodRecordDefaults: Place = {
|
const FoodRecordDefaults: Place = {
|
||||||
id: null,
|
id: '',
|
||||||
name: '',
|
name: '',
|
||||||
address: '',
|
address: '',
|
||||||
latitude: null,
|
latitude: 0,
|
||||||
longitude: null,
|
longitude: 0,
|
||||||
|
phoneNumber: '',
|
||||||
|
googleMapsUrl: '',
|
||||||
|
photos: new List(),
|
||||||
|
icon: '',
|
||||||
|
hours: new List(),
|
||||||
|
openNow: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Record(FoodRecordDefaults, 'PlaceRecord');
|
const PlaceRecord = Record(FoodRecordDefaults, 'PlaceRecord');
|
||||||
|
|
||||||
|
export const buildPlaceRecord = (place: GooglePlaceObj) => {
|
||||||
|
const {
|
||||||
|
place_id,
|
||||||
|
name,
|
||||||
|
formatted_address,
|
||||||
|
geometry: { location = {} } = {},
|
||||||
|
formatted_phone_number,
|
||||||
|
url,
|
||||||
|
photos,
|
||||||
|
icon,
|
||||||
|
opening_hours = {},
|
||||||
|
} = place;
|
||||||
|
|
||||||
|
return new PlaceRecord({
|
||||||
|
id: place_id,
|
||||||
|
name: name,
|
||||||
|
address: formatted_address,
|
||||||
|
latitude: location.lat,
|
||||||
|
longitude: location.lng,
|
||||||
|
phoneNumber: formatted_phone_number,
|
||||||
|
googleMapsUrl: url,
|
||||||
|
photos: fromJS(photos),
|
||||||
|
icon: icon,
|
||||||
|
hours: fromJS(opening_hours.weekday_text),
|
||||||
|
openNow: opening_hours.open_now,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PlaceRecord;
|
||||||
|
|
|
||||||
|
|
@ -108,4 +108,6 @@ const DUMMY_DATA = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default Observable.from(DUMMY_DATA).map(FoodItemRecord).scan(setById, Map());
|
export const foodItemsRaw$ = Observable.from(DUMMY_DATA);
|
||||||
|
|
||||||
|
export default foodItemsRaw$.map(FoodItemRecord).scan(setById, Map());
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,26 @@
|
||||||
// @flow
|
// @flow
|
||||||
import PlaceRecord from '../records/PlaceRecord';
|
import { buildPlaceRecord } from '../records/PlaceRecord';
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { Map } from 'immutable';
|
import { Map } from 'immutable';
|
||||||
import { setById } from '../helpers/ImmutableHelpers';
|
import { foodItemsRaw$ } from './FoodItemsStream';
|
||||||
|
import { getPlaceDetails } from '../apis/PlaceDetailsApi';
|
||||||
|
import { memoize } from 'ramda';
|
||||||
|
|
||||||
// TODO open a websoket and create observable from it
|
/**
|
||||||
const DUMMY_DATA = [
|
* return a promise of a place details object
|
||||||
{
|
* if already requested return existing promise
|
||||||
id: 'ChIJf5QJFBK1RIYRjjfxZz9Z0O0',
|
* swallow exceptions so as not to break the stream
|
||||||
name: 'Whole Foods',
|
*/
|
||||||
address: '525 N. Lamar Blvd, Austin',
|
const safeGetPlaceDetails = memoize(placeId => {
|
||||||
latitude: 30.270667599999996,
|
return getPlaceDetails(placeId).catch(error => {
|
||||||
longitude: -97.7532464,
|
console.log(error); // eslint-disable-line no-console
|
||||||
},
|
return {};
|
||||||
{
|
});
|
||||||
id: 'ChIJm4_R2BG1RIYRQcnsPEmzGQY',
|
});
|
||||||
name: "Trader Joe's",
|
|
||||||
address: '211 Walter Seaholm Dr, Ste 100, Austin',
|
|
||||||
latitude: 30.267681999999994,
|
|
||||||
longitude: -97.7527494,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ChIJG44vBQi1RIYRvWGHdYUolZY',
|
|
||||||
name: 'Royal Blue Grocery',
|
|
||||||
address: '301 Brazos St Suite 110, Austin, TX 78701, USA',
|
|
||||||
latitude: 30.265019100000004,
|
|
||||||
longitude: -97.7419085,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ChIJ72if-Qe1RIYRCzMucGEEdBA',
|
|
||||||
name: 'Second Street Market',
|
|
||||||
address: '200 San Jacinto Blvd, Austin',
|
|
||||||
latitude: 30.263963300000004,
|
|
||||||
longitude: -97.742308,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'ChIJr3szW6a1RIYRkM7LRpnBIO0',
|
|
||||||
name: 'Lonestar Souvenir and Food',
|
|
||||||
address: '502 E. 6th St, Austin',
|
|
||||||
latitude: 30.266898599999998,
|
|
||||||
longitude: -97.73798459999999,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default Observable.from(DUMMY_DATA).map(PlaceRecord).scan(setById, new Map());
|
const uniquePlaceIds$ = foodItemsRaw$.map(({ placeId }) => placeId).distinct();
|
||||||
|
|
||||||
|
const placeRecords$ = uniquePlaceIds$.mergeMap(safeGetPlaceDetails).map(buildPlaceRecord);
|
||||||
|
|
||||||
|
export default placeRecords$.scan((accMap, place) => {
|
||||||
|
return accMap.set(place.id, place);
|
||||||
|
}, new Map());
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
"react-native-vector-icons": "^4.0.0",
|
"react-native-vector-icons": "^4.0.0",
|
||||||
"react-router-native": "^4.0.0",
|
"react-router-native": "^4.0.0",
|
||||||
"recompose": "^0.23.4",
|
"recompose": "^0.23.4",
|
||||||
"rxjs": "^5.2.0"
|
"rxjs": "^5.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^7.1.1",
|
"babel-eslint": "^7.1.1",
|
||||||
|
|
|
||||||
|
|
@ -3973,9 +3973,9 @@ rx-lite@^3.1.2:
|
||||||
version "3.1.2"
|
version "3.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
|
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
|
||||||
|
|
||||||
rxjs@^5.2.0:
|
rxjs@^5.4.2:
|
||||||
version "5.4.0"
|
version "5.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.4.0.tgz#a7db14ab157f9d7aac6a56e655e7a3860d39bf26"
|
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.4.2.tgz#2a3236fcbf03df57bae06fd6972fd99e5c08fcf7"
|
||||||
dependencies:
|
dependencies:
|
||||||
symbol-observable "^1.0.1"
|
symbol-observable "^1.0.1"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue