diff --git a/js/apis/PlaceDetailsApi.js b/js/apis/PlaceDetailsApi.js
index 3bce083..9a1cef2 100644
--- a/js/apis/PlaceDetailsApi.js
+++ b/js/apis/PlaceDetailsApi.js
@@ -1,8 +1,9 @@
// @flow
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) => {
+export const getPlaceDetails = async (placeid: ?string) => {
if (!placeid || typeof placeid !== 'string') {
throw new Error('placeid looks wrong');
}
@@ -16,3 +17,19 @@ export const getPlaceDetails = async (placeid: string) => {
}
return result;
};
+
+export const getURLForPhotoReference = (opts?: { maxheight?: number, maxwidth?: number } = {}) => (
+ photoReference: string
+) => {
+ if (!photoReference) {
+ return '';
+ }
+
+ const { maxheight, maxwidth } = opts;
+
+ const maxHeight = `&maxheight=${maxheight || 600}`;
+ const maxWidth = maxwidth ? `&maxwidth=${maxwidth}` : '';
+ const photoref = `&photoreference=${photoReference}`;
+
+ return `${photosUrl}${photoref}${maxHeight}${maxWidth}`;
+};
diff --git a/js/components/FoodItemTile.js b/js/components/FoodItemTile.js
new file mode 100644
index 0000000..4f2853d
--- /dev/null
+++ b/js/components/FoodItemTile.js
@@ -0,0 +1,37 @@
+// @flow
+import React from 'react';
+import { View } from 'react-native';
+import { pure } from 'recompose';
+import FoodItemRecord from '../records/FoodItemRecord';
+import typeof PlaceRecord from '../records/PlaceRecord';
+import theme from '../ui-theme';
+import { Link } from 'react-router-native';
+import { routeWithTitle } from '../helpers/RouteHelpers';
+import { TileBox, StrongText, SubText, Thumbnail } from './ItemTile';
+
+export default pure(({ foodItem, place = {} }: { foodItem: FoodItemRecord, place: PlaceRecord }) => {
+ if (!foodItem) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+
+ {foodItem.name || ''}
+
+
+ {`${place.name || ''} - ${foodItem.distance} mi`}
+
+
+
+
+
+ );
+});
diff --git a/js/components/IconButton.js b/js/components/IconButton.js
index 48b8f85..dc9ee73 100644
--- a/js/components/IconButton.js
+++ b/js/components/IconButton.js
@@ -4,13 +4,15 @@ import { Text, View, TouchableOpacity } from 'react-native';
import { pure } from 'recompose';
import { Icon } from 'react-native-material-ui';
-type Props = { glyph: string, text: string, route: string, onPress: Function, underlayColor?: string };
+type Props = { glyph: string, text: string, route: string, onPress: Function, color?: string };
-export default pure(({ glyph, text, underlayColor = 'grey', ...others }: Props) => (
+export default pure(({ glyph, text, color = 'grey', ...others }: Props) =>
-
- {text}
+
+
+ {text}
+
-));
+);
diff --git a/js/components/ItemTile.js b/js/components/ItemTile.js
index d9d1d7d..c31530c 100644
--- a/js/components/ItemTile.js
+++ b/js/components/ItemTile.js
@@ -1,12 +1,7 @@
//@flow
import React from 'react';
import { Text, View, Image } from 'react-native';
-import { pure } from 'recompose';
-import FoodItemRecord from '../records/FoodItemRecord';
-import typeof PlaceRecord from '../records/PlaceRecord';
import theme from '../ui-theme';
-import { Link } from 'react-router-native';
-import { routeWithTitle } from '../helpers/RouteHelpers';
export const Thumbnail = ({ thumb }: { thumb: ?string }) =>
{children}
;
-
-export const FoodItemTile = pure(({ foodItem = {}, place = {} }: { foodItem: FoodItemRecord, place: PlaceRecord }) =>
-
-
-
-
-
-
- {foodItem.name || ''}
-
-
- {`${place.name || ''} - ${foodItem.distance} mi`}
-
-
-
-
-
-);
diff --git a/js/components/PlaceTile.js b/js/components/PlaceTile.js
index cb0a347..923962a 100644
--- a/js/components/PlaceTile.js
+++ b/js/components/PlaceTile.js
@@ -8,10 +8,23 @@ import { Link } from 'react-router-native';
import { Thumbnail, StrongText, SubText } from './ItemTile';
import { routeWithTitle } from '../helpers/RouteHelpers';
+const getHoursText = (hours: List) => {
+ if (!hours) {
+ return 'not listed';
+ }
+ // Note: js Date return 0-Sun/6-Sat where google return 0-Mon/6-Sun
+ // Immutable.List is smart enough to know that a negative index is counted from the last index
+ return hours.get(new Date().getDay() - 1);
+};
+
import theme from '../ui-theme';
type PlaceTileProps = { place: PlaceRecord, distance: number, categories: List };
-export default pure(({ place = {}, distance = 999, categories = new List() }: PlaceTileProps) => {
+export default pure(({ place, distance = 999, categories = new List() }: PlaceTileProps) => {
+ if (!place) {
+ return ;
+ }
+
return (
-
+
{`${place.name} - ${distance} mi`}
@@ -27,7 +40,7 @@ export default pure(({ place = {}, distance = 999, categories = new List() }: Pl
{`${categories.interpose(', ').reduce((str, token) => str + token, '')}`}
- {'hours'}
+ {getHoursText(place.hours)}
diff --git a/js/enhancers/placeEnhancers.js b/js/enhancers/placeEnhancers.js
index d4eb3c6..b3b16bc 100644
--- a/js/enhancers/placeEnhancers.js
+++ b/js/enhancers/placeEnhancers.js
@@ -3,6 +3,7 @@ import withProps from 'recompose/withProps';
import mapPropsStream from 'recompose/mapPropsStream';
import compose from 'recompose/compose';
import Places$ from '../streams/PlacesStream';
+import FoodItems$ from '../streams/FoodItemsStream';
import { path } from 'ramda';
export const withPlaces = mapPropsStream(props$ =>
@@ -40,3 +41,13 @@ export const withPlaceForFoodItem = mapPropsStream(props$ =>
};
})
);
+
+export const withFoodItemsForPlace = mapPropsStream(props$ =>
+ props$.combineLatest(FoodItems$, (props, foodItems) => {
+ const placeId = props.placeId;
+ return {
+ ...props,
+ foodItems: foodItems.toList().filter(foodItem => placeId === foodItem.placeId),
+ };
+ })
+);
diff --git a/js/pages/Food.js b/js/pages/Food.js
index 211e1c7..4f24a6d 100644
--- a/js/pages/Food.js
+++ b/js/pages/Food.js
@@ -2,7 +2,7 @@
import React, { Component, PropTypes } from 'react';
import { View, ScrollView } from 'react-native';
import theme from '../ui-theme';
-import { FoodItemTile } from '../components/ItemTile';
+import FoodItemTile from '../components/FoodItemTile';
import { ActionButton } from 'react-native-material-ui';
import { routeWithTitle } from '../helpers/RouteHelpers';
import FoodItemList from '../components/FoodItemList';
diff --git a/js/pages/FoodItemDetail.js b/js/pages/FoodItemDetail.js
index d70b0e9..c2f0c46 100644
--- a/js/pages/FoodItemDetail.js
+++ b/js/pages/FoodItemDetail.js
@@ -57,6 +57,11 @@ export class FoodItemDetail extends Component {
render() {
const { foodItem, place } = this.props;
+
+ if (!foodItem || !place) {
+ return ;
+ }
+
const { images, quantity } = foodItem;
const viewableImages = images.filter(image => !!image);
diff --git a/js/pages/PlaceDetail.js b/js/pages/PlaceDetail.js
index b750a3b..9992bfe 100644
--- a/js/pages/PlaceDetail.js
+++ b/js/pages/PlaceDetail.js
@@ -1,31 +1,112 @@
// @flow
import React, { Component } from 'react';
-import { Text, View } from 'react-native';
+import { View, Image, ScrollView } from 'react-native';
import theme from '../ui-theme';
import { compose, pure } from 'recompose';
+import typeof PlaceRecord from '../records/PlaceRecord';
+import { withPlace, withPlaceIdFromRoute, withFoodItemsForPlace } from '../enhancers/placeEnhancers';
+import Carousel from 'react-native-looped-carousel';
+import CountBadge from '../components/CountBadge';
+import { StrongText } from '../components/ItemTile';
+import IconButton from '../components/IconButton';
+import { type List } from 'immutable';
+import typeof FoodItemRecord from '../records/FoodItemRecord';
+import FoodItemTile from '../components/FoodItemTile';
+
+const { placeDetails: style } = theme;
+
+const stretchedStyle = { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 };
+
+const contentTileStyle = {
+ backgroundColor: 'white',
+ paddingLeft: 20,
+ paddingRight: 20,
+};
export class PlaceDetail extends Component {
static displayName = 'PlaceDetail';
props: {
- match: {
- params: {
- id: string,
- },
- },
+ place: ?PlaceRecord,
+ foodItems: ?List,
};
+ state: {
+ currentImage: number,
+ };
+
+ state = {
+ currentImage: 0,
+ };
+
+ changeCurrentImage = (currentImage: number) => this.setState({ currentImage });
+
+ // TODO placeholder implementation until we get a backend
+ addToFaves = () =>
+ this.setState(prevState => ({
+ isFavorite: !prevState.isFavorite,
+ }));
+
+ // todo - build a map view and open it here
+ viewOnMap = () => {};
+
// todo: need to get the item from the stream by this id
render() {
- const { match: { params: { id } } } = this.props;
+ const { place, foodItems } = this.props;
+
+ if (!place) {
+ return ;
+ }
+
+ const { photos } = place;
+ const { currentImage } = this.state;
+
return (
-
- {id}
-
+
+
+ {photos.size === 1 && }
+ {photos.size > 1 &&
+
+ {photos.map(uri =>
+
+ )}
+ }
+
+
+
+
+
+ {place.address}
+
+
+
+
+
+
+
+
+ Products
+ {!!foodItems &&
+ foodItems.size &&
+ foodItems.map(foodItem => )}
+
+
);
}
}
-const enhance = compose(pure);
+const enhance = compose(pure, withPlaceIdFromRoute, withPlace, withFoodItemsForPlace);
export default enhance(PlaceDetail);
diff --git a/js/pages/Places.js b/js/pages/Places.js
index 94c78fa..05fc9ba 100644
--- a/js/pages/Places.js
+++ b/js/pages/Places.js
@@ -17,8 +17,8 @@ const PlacesList = withFoodItemsGroupedByPlace(
{foodItemsByPlace
.map((foodItems: Map, placeId: string) => {
- const Comp = withPlaceProps(PlaceTile);
- return ;
+ const EnhancedPlaceTile = withPlaceProps(PlaceTile);
+ return ;
})
.toList()}
diff --git a/js/records/PlaceRecord.js b/js/records/PlaceRecord.js
index db8034f..c0064b0 100644
--- a/js/records/PlaceRecord.js
+++ b/js/records/PlaceRecord.js
@@ -1,5 +1,7 @@
// @flow
-import { List, Record, fromJS } from 'immutable';
+import { List, Map, Record, fromJS } from 'immutable';
+import { pipe, pathOr, map, head, memoizeWith } from 'ramda';
+import { getURLForPhotoReference } from '../apis/PlaceDetailsApi';
export type GooglePlaceObj = {
place_id: string,
@@ -24,7 +26,6 @@ export type GooglePlaceObj = {
formatted_phone_number: string,
url: string,
photos: Array,
- icon: string,
opening_hours: {
open_now: boolean,
periods: Array<{
@@ -41,6 +42,8 @@ export type GooglePlaceObj = {
},
};
+export type Period = Map;
+
export type Place = {
id: string,
name: string,
@@ -50,8 +53,9 @@ export type Place = {
phoneNumber: string,
googleMapsUrl: string,
photos: List,
- icon: string,
+ thumb: string,
hours: List,
+ periods: List