Merge remote-tracking branch 'origin/master'

This commit is contained in:
Erick Clark 2017-10-22 21:35:55 -05:00
commit 9c40c27811
8 changed files with 116 additions and 157 deletions

2
.prettierrc Normal file
View file

@ -0,0 +1,2 @@
printWidth: 100;
parser: flow;

View file

@ -1,111 +1,60 @@
// @flow
import { memoize } from 'ramda';
// 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);
export type FoodItemsFilter = {
radius?: number,
};
/* eslint-enable no-unused-vars */
export type RawFoodItem = {
id: string,
name: string,
place_id: string,
category: string,
images: string,
thumbimage: string,
latitude: number,
longitude: number,
distance: number,
};
export type FoodItemsForLocation = {
orderby: string,
filter: FoodItemsFilter,
fooditems: Array<RawFoodItem>,
};
export const getFoodItemsForLocation = memoize(
async ({ pos: { coords: { latitude, longitude } } }: { pos: Position }): Promise<FoodItemsForLocation> => {
try {
return fetch('http://192.168.122.1:3000/fooditems', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
lat: latitude,
lng: longitude,
orderby: 'distance',
filter: {
radius: 10,
},
}),
})
.then(res => res.json())
.then(json => ({
...json,
loading: false,
error: null,
}));
} catch (error) {
console.error(error); // eslint-disable-line no-console
return {
orderby: 'distance',
filter: {},
fooditems: [],
loading: false,
error: error,
};
}
}
);

View file

@ -8,30 +8,36 @@ import theme from '../ui-theme';
import { Link } from 'react-router-native';
import { routeWithTitle } from '../helpers/RouteHelpers';
import { TileBox, StrongText, SubText, Thumbnail } from './ItemTile';
import { withPlace } from '../enhancers/placeEnhancers';
export default pure(({ foodItem, place = {} }: { foodItem: FoodItemRecord, place: PlaceRecord }) => {
if (!foodItem || !place) {
return <View />;
}
return (
<Link
to={routeWithTitle(`/foodItem/${foodItem.id || ''}`, foodItem.name)}
underlayColor={theme.itemTile.pressHighlightColor}
>
<View>
<TileBox>
<Thumbnail thumb={foodItem.thumbImage} />
<View style={{ paddingTop: 15 }}>
<StrongText>
{foodItem.name || ''}
</StrongText>
<SubText>
{`${place.name || ''} - ${foodItem.distance} mi`}
</SubText>
</View>
</TileBox>
</View>
</Link>
);
const PlaceNameAndDistance = withPlace(({ place = {}, distance = 999.9 }: { place: PlaceRecord, distance: number }) => {
return <SubText>{`${place.name || 'Loading...'} - ${parseFloat(distance).toFixed(1)} mi`}</SubText>;
});
export default pure(
({ foodItem }: { foodItem: FoodItemRecord }) => {
if (!foodItem) {
return <View />;
}
return (
<Link
to={routeWithTitle(`/foodItem/${foodItem.id || ''}`, foodItem.name)}
underlayColor={theme.itemTile.pressHighlightColor}
>
<View>
<TileBox>
<Thumbnail thumb={foodItem.thumbImage} />
<View style={{ paddingTop: 15 }}>
<StrongText>{foodItem.name || ''}</StrongText>
<PlaceNameAndDistance
placeId={foodItem.placeId}
distance={foodItem.distance}
/>
</View>
</TileBox>
</View>
</Link>
);
}
);

View file

@ -26,8 +26,8 @@ export const withFoodItemsAsSeq = mapPropsStream(props$ =>
);
export const withFoodItemIdFromRoute = withProps((props: { match: { params: { id: string } } }) => {
const id = path(['match', 'params', 'id'], props) || 0;
return { foodItemId: +id };
const id: string = path(['match', 'params', 'id'], props) || '';
return { foodItemId: id };
});
export const withFoodItem = compose(

View file

@ -6,13 +6,10 @@ import { ActionButton } from 'react-native-material-ui';
import { routeWithTitle } from '../helpers/RouteHelpers';
import FoodItemList from '../components/FoodItemList';
import typeof FoodItemRecord from '../records/FoodItemRecord';
import { withPlaceForFoodItem } from '../enhancers/placeEnhancers';
import theme from '../ui-theme';
const FoodItemWithPlace = withPlaceForFoodItem(FoodItemTile);
const renderFoodItem = (foodItem: FoodItemRecord) => <FoodItemWithPlace key={foodItem.id} foodItem={foodItem} />;
const renderFoodItem = (foodItem: FoodItemRecord) => <FoodItemTile key={foodItem.id} foodItem={foodItem} />;
export default class FoodList extends Component {
static displayName = 'FoodList';

View file

@ -1,5 +1,6 @@
//@flow
import { fromJS, List, Record } from 'immutable';
import { type RawFoodItem } from '../apis/FoodItemsApi';
export const QUANTITY_NONE: 'none' = 'none';
export const QUANTITY_FEW: 'few' = 'few';
@ -20,7 +21,7 @@ export type Category =
export const CATEGORIES = [CATEGORY_BEVERAGES, CATEGORY_DESSERTS, CATEGORY_ENTREES, CATEGORY_OTHER];
export type FoodItem = {
id: ?number,
id: ?string,
name: string,
placeId: ?number,
latitude: number,
@ -34,7 +35,7 @@ export type FoodItem = {
};
const FoodRecordDefaults: FoodItem = {
id: null,
id: '',
name: '',
placeId: null,
latitude: 0,
@ -49,10 +50,12 @@ const FoodRecordDefaults: FoodItem = {
const FoodItemRecord = Record(FoodRecordDefaults, 'FoodItemRecord');
export const createFoodItem = (foodItemRaw: Object) => {
export const createFoodItem = (foodItemRaw: RawFoodItem) => {
return new FoodItemRecord({
...foodItemRaw,
images: fromJS(foodItemRaw.images),
images: fromJS((foodItemRaw.images || '').split(',')),
placeId: foodItemRaw.place_id,
thumbImage: foodItemRaw.thumbimage,
});
};

View file

@ -3,8 +3,10 @@ import { createFoodItem } from '../records/FoodItemRecord';
import { setById } from '../helpers/ImmutableHelpers';
import { Map } from 'immutable';
import location$ from './LocationStream';
import { getFoodItemsForLocation } from '../apis/FoodItemsApi';
import { getFoodItemsForLocation, type FoodItemsForLocation } from '../apis/FoodItemsApi';
export default location$.mergeMap(getFoodItemsForLocation).map(foodItems => {
return foodItems.map(createFoodItem).reduce(setById, new Map());
});
export default location$
.mergeMap(pos => getFoodItemsForLocation({ pos }))
.map(({ fooditems = [] }: FoodItemsForLocation) => {
return fooditems.map(createFoodItem).reduce(setById, new Map());
});

View file

@ -16,18 +16,18 @@ import { setById } from '../helpers/ImmutableHelpers';
*/
const safeGetPlaceDetails = memoize((placeId: string): Promise<?GooglePlaceObj> => {
return getPlaceDetails(placeId).catch(error => {
console.log(error); // eslint-disable-line no-console
console.error(error); // eslint-disable-line no-console
return null;
});
});
export default foodItems$
.map((foodItems: Map<string, FoodItemRecord>): Array<string> => {
return foodItems.map(foodItem => foodItem.placeId).toArray();
const Places$ = foodItems$
.mergeMap((foodItems: Map<string, FoodItemRecord>): Observable<string> => {
return Observable.from(foodItems.toArray().map(foodItem => foodItem.placeId));
})
.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());
});
.distinct()
.mergeMap(safeGetPlaceDetails)
.map(buildPlaceRecord)
.scan(setById, new Map());
export default Places$;