mirror of
https://gitlab.com/wheres-the-tp/ui-mobile.git
synced 2026-01-25 09:34:56 -06:00
location stream
This commit is contained in:
parent
56cc8a715e
commit
3e1249b6e8
8 changed files with 158 additions and 125 deletions
|
|
@ -12,6 +12,10 @@
|
|||
"eslint:recommended",
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
"globals": {
|
||||
"Position": false,
|
||||
"navigator": false
|
||||
},
|
||||
"rules": {
|
||||
// overrides
|
||||
"react/display-name": 1
|
||||
|
|
|
|||
111
js/apis/FoodItemsApi.js
Normal file
111
js/apis/FoodItemsApi.js
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
// @flow
|
||||
|
||||
// TODO open a websoket and create observable from it
|
||||
const DUMMY_DATA = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Big John Cookies',
|
||||
placeId: 'ChIJf5QJFBK1RIYRjjfxZz9Z0O0',
|
||||
latitude: 30.270667599999996,
|
||||
longitude: -97.7532464,
|
||||
distance: 0.5,
|
||||
quantity: 'alot',
|
||||
category: 'desserts',
|
||||
images: [
|
||||
'https://s-media-cache-ak0.pinimg.com/564x/e7/5f/08/e75f08b00c0bc7f2b01b3d1a636389f6.jpg',
|
||||
'http://images.media-allrecipes.com/userphotos/560x315/1107530.jpg',
|
||||
],
|
||||
thumbImage: 'http://images.media-allrecipes.com/userphotos/560x315/1107530.jpg',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Jelly Filled Donuts',
|
||||
placeId: 'ChIJ72if-Qe1RIYRCzMucGEEdBA',
|
||||
latitude: 30.263963300000004,
|
||||
longitude: -97.742308,
|
||||
distance: 1.0,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: ['https://timenewsfeed.files.wordpress.com/2013/06/jellydonut.jpg'],
|
||||
thumbImage: 'https://timenewsfeed.files.wordpress.com/2013/06/jellydonut.jpg',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Spelt Brownies',
|
||||
placeId: 'ChIJG44vBQi1RIYRvWGHdYUolZY',
|
||||
latitude: 30.265019100000004,
|
||||
longitude: -97.7419085,
|
||||
distance: 1.7,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: ['http://www.momshealthyeats.com/wp-content/uploads/2011/11/spelt-fudge-brownie.jpg'],
|
||||
thumbImage: 'http://www.momshealthyeats.com/wp-content/uploads/2011/11/spelt-fudge-brownie.jpg',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Oatmeal Raisin Cookies',
|
||||
placeId: 'ChIJf5QJFBK1RIYRjjfxZz9Z0O0',
|
||||
latitude: 30.270667599999996,
|
||||
longitude: -97.7532464,
|
||||
distance: 0.5,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: ['http://cookingontheside.com/wp-content/uploads/2009/04/oatmeal_raisin_cookies_stack-400.jpg'],
|
||||
thumbImage: 'http://cookingontheside.com/wp-content/uploads/2009/04/oatmeal_raisin_cookies_stack-400.jpg',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Donuts with Sprinkles',
|
||||
placeId: 'ChIJ72if-Qe1RIYRCzMucGEEdBA',
|
||||
latitude: 30.263963300000004,
|
||||
longitude: -97.742308,
|
||||
distance: 1.0,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: ['https://dannivee.files.wordpress.com/2013/10/img_1950.jpg'],
|
||||
thumbImage: 'https://dannivee.files.wordpress.com/2013/10/img_1950.jpg',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Powdered Donuts',
|
||||
placeId: 'ChIJ72if-Qe1RIYRCzMucGEEdBA',
|
||||
latitude: 30.263963300000004,
|
||||
longitude: -97.742308,
|
||||
distance: 1.0,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: [
|
||||
'http://3.bp.blogspot.com/-NUKSXr1qLHs/UQmsaEFgbTI/AAAAAAAAA_Y/l4psfVl4a5A/s1600/white-powdered-sugar-doughnuts-tracie-kaska.jpg',
|
||||
],
|
||||
thumbImage:
|
||||
'http://3.bp.blogspot.com/-NUKSXr1qLHs/UQmsaEFgbTI/AAAAAAAAA_Y/l4psfVl4a5A/s1600/white-powdered-sugar-doughnuts-tracie-kaska.jpg',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'Snickerdoodles',
|
||||
placeId: 'ChIJr3szW6a1RIYRkM7LRpnBIO0',
|
||||
latitude: 30.266898599999998,
|
||||
longitude: -97.73798459999999,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: ['http://josephcphillips.com/wp-content/uploads/2015/02/snickerdoodles2.jpg'],
|
||||
thumbImage: 'http://josephcphillips.com/wp-content/uploads/2015/02/snickerdoodles2.jpg',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'Pizza',
|
||||
placeId: 'ChIJr3szW6a1RIYRkM7LRpnBIO0',
|
||||
latitude: 30.266898599999998,
|
||||
longitude: -97.73798459999999,
|
||||
quantity: 'few',
|
||||
category: 'entrees',
|
||||
images: ['http://www.foodandhealth.co.uk/wp-content/uploads/2016/05/Hot-stone-Vegan-Pizza.jpg'],
|
||||
thumbImage: 'http://www.foodandhealth.co.uk/wp-content/uploads/2016/05/Hot-stone-Vegan-Pizza.jpg',
|
||||
},
|
||||
];
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
export const getFoodItemsForLocation = (location: Location) => {
|
||||
return Promise.resolve(DUMMY_DATA);
|
||||
};
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
|
@ -1,16 +1,20 @@
|
|||
// @flow
|
||||
import { type GooglePlaceObj } from '../records/PlaceRecord';
|
||||
|
||||
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}`;
|
||||
|
||||
export const getPlaceDetails = async (placeid: ?string) => {
|
||||
type GooglePlaceDetailsResponse = { error_message: ?string, result: GooglePlaceObj };
|
||||
|
||||
export const getPlaceDetails = async (placeid: ?string): Promise<GooglePlaceObj> => {
|
||||
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();
|
||||
const { error_message, result }: GooglePlaceDetailsResponse = await res.json();
|
||||
|
||||
if (error_message) {
|
||||
throw new Error(error_message);
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import { type List, type Map } from 'immutable';
|
|||
|
||||
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> => {
|
||||
if (!item.id) {
|
||||
export const setById = (map: Map<string, any>, item: ?{ id?: string }): Map<string, any> => {
|
||||
if (!item || !item.id) {
|
||||
return map;
|
||||
}
|
||||
return map.set(item.id, item);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ const FoodRecordDefaults: Place = {
|
|||
|
||||
const PlaceRecord = Record(FoodRecordDefaults, 'PlaceRecord');
|
||||
|
||||
const getPhotos = pathOr([], ['photos']);
|
||||
const getPhotos = pathOr([{}], ['photos']);
|
||||
|
||||
const getPhotoRef = photo => photo.photo_reference || '';
|
||||
|
||||
|
|
@ -85,8 +85,12 @@ const getThumb = pipe(getPhotos, head, getPhotoRef, getURLForPhotoReference({ ma
|
|||
const getPhotoUrls = pipe(getPhotos, map(getPhotoRef), map(getURLForPhotoReference({ maxheight: 600 })));
|
||||
|
||||
export const buildPlaceRecord = memoizeWith(
|
||||
(place: GooglePlaceObj) => place.place_id,
|
||||
(place: GooglePlaceObj) => {
|
||||
(place: ?GooglePlaceObj) => place && place.place_id,
|
||||
(place: ?GooglePlaceObj) => {
|
||||
if (!place) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
place_id,
|
||||
name,
|
||||
|
|
|
|||
|
|
@ -1,113 +1,10 @@
|
|||
//@flow
|
||||
import { createFoodItem } from '../records/FoodItemRecord';
|
||||
import { Observable } from 'rxjs';
|
||||
import { setById } from '../helpers/ImmutableHelpers';
|
||||
import { Map } from 'immutable';
|
||||
import location$ from './LocationStream';
|
||||
import { getFoodItemsForLocation } from '../apis/FoodItemsApi';
|
||||
|
||||
// TODO open a websoket and create observable from it
|
||||
const DUMMY_DATA = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Big John Cookies',
|
||||
placeId: 'ChIJf5QJFBK1RIYRjjfxZz9Z0O0',
|
||||
latitude: 30.270667599999996,
|
||||
longitude: -97.7532464,
|
||||
distance: 0.5,
|
||||
quantity: 'alot',
|
||||
category: 'desserts',
|
||||
images: [
|
||||
'https://s-media-cache-ak0.pinimg.com/564x/e7/5f/08/e75f08b00c0bc7f2b01b3d1a636389f6.jpg',
|
||||
'http://images.media-allrecipes.com/userphotos/560x315/1107530.jpg',
|
||||
],
|
||||
thumbImage: 'http://images.media-allrecipes.com/userphotos/560x315/1107530.jpg',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Jelly Filled Donuts',
|
||||
placeId: 'ChIJ72if-Qe1RIYRCzMucGEEdBA',
|
||||
latitude: 30.263963300000004,
|
||||
longitude: -97.742308,
|
||||
distance: 1.0,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: ['https://timenewsfeed.files.wordpress.com/2013/06/jellydonut.jpg'],
|
||||
thumbImage: 'https://timenewsfeed.files.wordpress.com/2013/06/jellydonut.jpg',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Spelt Brownies',
|
||||
placeId: 'ChIJG44vBQi1RIYRvWGHdYUolZY',
|
||||
latitude: 30.265019100000004,
|
||||
longitude: -97.7419085,
|
||||
distance: 1.7,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: ['http://www.momshealthyeats.com/wp-content/uploads/2011/11/spelt-fudge-brownie.jpg'],
|
||||
thumbImage: 'http://www.momshealthyeats.com/wp-content/uploads/2011/11/spelt-fudge-brownie.jpg',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Oatmeal Raisin Cookies',
|
||||
placeId: 'ChIJf5QJFBK1RIYRjjfxZz9Z0O0',
|
||||
latitude: 30.270667599999996,
|
||||
longitude: -97.7532464,
|
||||
distance: 0.5,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: ['http://cookingontheside.com/wp-content/uploads/2009/04/oatmeal_raisin_cookies_stack-400.jpg'],
|
||||
thumbImage: 'http://cookingontheside.com/wp-content/uploads/2009/04/oatmeal_raisin_cookies_stack-400.jpg',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Donuts with Sprinkles',
|
||||
placeId: 'ChIJ72if-Qe1RIYRCzMucGEEdBA',
|
||||
latitude: 30.263963300000004,
|
||||
longitude: -97.742308,
|
||||
distance: 1.0,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: ['https://dannivee.files.wordpress.com/2013/10/img_1950.jpg'],
|
||||
thumbImage: 'https://dannivee.files.wordpress.com/2013/10/img_1950.jpg',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Powdered Donuts',
|
||||
placeId: 'ChIJ72if-Qe1RIYRCzMucGEEdBA',
|
||||
latitude: 30.263963300000004,
|
||||
longitude: -97.742308,
|
||||
distance: 1.0,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: [
|
||||
'http://3.bp.blogspot.com/-NUKSXr1qLHs/UQmsaEFgbTI/AAAAAAAAA_Y/l4psfVl4a5A/s1600/white-powdered-sugar-doughnuts-tracie-kaska.jpg',
|
||||
],
|
||||
thumbImage:
|
||||
'http://3.bp.blogspot.com/-NUKSXr1qLHs/UQmsaEFgbTI/AAAAAAAAA_Y/l4psfVl4a5A/s1600/white-powdered-sugar-doughnuts-tracie-kaska.jpg',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'Snickerdoodles',
|
||||
placeId: 'ChIJr3szW6a1RIYRkM7LRpnBIO0',
|
||||
latitude: 30.266898599999998,
|
||||
longitude: -97.73798459999999,
|
||||
quantity: 'few',
|
||||
category: 'desserts',
|
||||
images: ['http://josephcphillips.com/wp-content/uploads/2015/02/snickerdoodles2.jpg'],
|
||||
thumbImage: 'http://josephcphillips.com/wp-content/uploads/2015/02/snickerdoodles2.jpg',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'Pizza',
|
||||
placeId: 'ChIJr3szW6a1RIYRkM7LRpnBIO0',
|
||||
latitude: 30.266898599999998,
|
||||
longitude: -97.73798459999999,
|
||||
quantity: 'few',
|
||||
category: 'entrees',
|
||||
images: ['http://www.foodandhealth.co.uk/wp-content/uploads/2016/05/Hot-stone-Vegan-Pizza.jpg'],
|
||||
thumbImage: 'http://www.foodandhealth.co.uk/wp-content/uploads/2016/05/Hot-stone-Vegan-Pizza.jpg',
|
||||
},
|
||||
];
|
||||
|
||||
export const foodItemsRaw$ = Observable.from(DUMMY_DATA);
|
||||
|
||||
export default foodItemsRaw$.map(createFoodItem).scan(setById, Map());
|
||||
export default location$.mergeMap(getFoodItemsForLocation).map(foodItems => {
|
||||
return foodItems.map(createFoodItem).reduce(setById, new Map());
|
||||
});
|
||||
|
|
|
|||
6
js/streams/LocationStream.js
Normal file
6
js/streams/LocationStream.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// @flow
|
||||
import { Observable, type Observer } from 'rxjs';
|
||||
|
||||
export default Observable.create((obs: Observer<Position>): Observable<Position> => {
|
||||
navigator.geolocation.getCurrentPosition((pos: Position) => obs.next(pos));
|
||||
});
|
||||
|
|
@ -1,26 +1,33 @@
|
|||
// @flow
|
||||
import { buildPlaceRecord } from '../records/PlaceRecord';
|
||||
import { Map } from 'immutable';
|
||||
import { foodItemsRaw$ } from './FoodItemsStream';
|
||||
import foodItems$ from './FoodItemsStream';
|
||||
import { getPlaceDetails } from '../apis/PlaceDetailsApi';
|
||||
import { memoize } from 'ramda';
|
||||
import { Observable } from 'rxjs';
|
||||
import typeof FoodItemRecord from '../records/FoodItemRecord';
|
||||
import PlaceRecord, { type GooglePlaceObj } from '../records/PlaceRecord';
|
||||
import { setById } from '../helpers/ImmutableHelpers';
|
||||
|
||||
/**
|
||||
* return a promise of a place details object
|
||||
* if already requested return existing promise
|
||||
* swallow exceptions so as not to break the stream
|
||||
*/
|
||||
const safeGetPlaceDetails = memoize(placeId => {
|
||||
const safeGetPlaceDetails = memoize((placeId: string): Promise<?GooglePlaceObj> => {
|
||||
return getPlaceDetails(placeId).catch(error => {
|
||||
console.log(error); // eslint-disable-line no-console
|
||||
return {};
|
||||
return null;
|
||||
});
|
||||
});
|
||||
|
||||
const uniquePlaceIds$ = foodItemsRaw$.map(foodItem => foodItem.placeId).distinct();
|
||||
|
||||
const placeRecords$ = uniquePlaceIds$.mergeMap(safeGetPlaceDetails).map(buildPlaceRecord).distinct();
|
||||
|
||||
export default placeRecords$.scan((accMap, place) => {
|
||||
return accMap.set(place.id, place);
|
||||
}, new Map());
|
||||
export default foodItems$
|
||||
.map((foodItems: Map<string, FoodItemRecord>): Array<string> => {
|
||||
return foodItems.map(foodItem => foodItem.placeId).toArray();
|
||||
})
|
||||
.mergeMap((placeIds: Array<string>): Observable<Array<Promise<?GooglePlaceObj>>> => {
|
||||
return Observable.forkJoin(placeIds.map(safeGetPlaceDetails));
|
||||
})
|
||||
.map((places: Array<GooglePlaceObj>): Map<string, PlaceRecord> => {
|
||||
return places.map(buildPlaceRecord).reduce(setById, new Map());
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue