aretherecookies-mobile/js/pages/FoodItemDetail.js
2019-11-17 15:47:24 -06:00

255 lines
6.7 KiB
JavaScript

// @flow
import React from 'react';
import { Button, Image, Text, View } from 'react-native';
import theme from '../ui-theme';
import { StrongText, SubText } from '../components/ItemTile';
import typeof FoodItemRecord from '../records/FoodItemRecord';
import { type Quantity } from '../constants/QuantityConstants';
import typeof PlaceRecord from '../records/PlaceRecord';
import {
compose,
withState,
withHandlers,
onlyUpdateForKeys,
withProps,
lifecycle,
} from 'recompose';
import IconButton from '../components/IconButton';
import { withFoodItem } from '../enhancers/foodItemEnhancers';
import { withPlaceForFoodItem } from '../enhancers/placeEnhancers';
import Carousel from 'react-native-looped-carousel';
import CountBadge from '../components/CountBadge';
import { routeWithTitle } from '../helpers/RouteHelpers';
import { Link } from 'react-router-native';
import moment from 'moment';
import { withUpdateQuantity } from '../enhancers/quantityEnhancers';
import { getQuantityLabelText } from '../helpers/QuantityHelpers';
import AuthManager from '../AuthManager';
import RouterButton from 'react-router-native-button';
import QuantityModal from '../modals/QuantityModal';
import { withImages } from '../enhancers/imagesEnhancers';
import { openImagePicker } from '../helpers/ImagePickerHelpers';
import { identity } from 'ramda';
import Spinner from 'react-native-loading-spinner-overlay';
import ImageRecord from '../records/ImageRecord';
import { List } from 'immutable';
import Snackbar from 'react-native-snackbar';
const { foodItemDetails: style } = theme;
const stretchedStyle = { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 };
const FoodItemImages = ({
currentImage,
visibleImages,
changeCurrentImage,
}: {
currentImage: number,
visibleImages: List<ImageRecord>,
changeCurrentImage: (img: number) => void,
}) => {
return (
<View style={{ flex: 3 }}>
{visibleImages.size === 1 && (
<View style={stretchedStyle}>
<Image
style={{ flex: 1, resizeMode: 'cover' }}
resizeMethod="resize"
source={{ uri: visibleImages.first().get('url', '') }}
/>
</View>
)}
{visibleImages.size > 1 && (
<Carousel autoplay={false} onAnimateNextPage={changeCurrentImage} style={stretchedStyle}>
{visibleImages.map(image => (
<Image
key={image.get('url', '')}
style={{ flex: 1, resizeMode: 'cover' }}
resizeMethod="resize"
source={{ uri: image.get('url', '') }}
/>
))}
</Carousel>
)}
{visibleImages.size > 0 && (
<CountBadge currentImage={currentImage + 1} totalCount={visibleImages.size} />
)}
</View>
);
};
const contentTileStyle = {
backgroundColor: 'white',
padding: 15,
marginBottom: 10,
};
type Props = {
foodItem: ?FoodItemRecord,
foodItemId: string,
place: PlaceRecord,
currentImage: number,
quantityModalOpen: boolean,
isLoggedIn: boolean,
changeCurrentImage: (index: number) => void,
updateAmount: (quantity: Quantity) => void,
updateQuantity: (arg: { foodItemId: string, quantity: Quantity }) => void,
toggleQuantityModal: () => void,
addPhoto: () => void,
addImage: (arg: { foodItemId: string, imageUri: string }) => Promise<void>,
imagesLoading: boolean,
setImagesLoading: (loading: boolean) => void,
};
export const FoodItemDetail = (props: Props) => {
const {
foodItem,
place,
currentImage,
changeCurrentImage,
isLoggedIn,
addPhoto,
toggleQuantityModal,
quantityModalOpen,
updateAmount,
imagesLoading,
} = props;
if (!foodItem || !place) {
return <View />;
}
if (quantityModalOpen) {
return (
<QuantityModal foodItem={foodItem} onUpdate={updateAmount} onClose={toggleQuantityModal} />
);
}
return (
<View style={{ ...theme.page.container }}>
<Spinner visible={imagesLoading} />
<FoodItemImages
currentImage={currentImage}
visibleImages={foodItem.images.filter(identity)}
changeCurrentImage={changeCurrentImage}
/>
<View style={{ ...contentTileStyle }}>
<Link
to={routeWithTitle(`/place/${place.id || ''}`, place.name)}
underlayColor={theme.itemTile.pressHighlightColor}>
<View>
<StrongText>{place.name}</StrongText>
<SubText>{place.address}</SubText>
</View>
</Link>
</View>
<View
style={{
flexBasis: 100,
flexGrow: 1,
...contentTileStyle,
flexDirection: 'column',
justifyContent: 'space-between',
}}>
<Text style={{ fontSize: 42, color: 'black' }}>
{getQuantityLabelText(foodItem.quantity)}
</Text>
<SubText>
Last updated at {moment(foodItem.lastupdated).format('h:mm A on MMM D, YYYY')}
</SubText>
{isLoggedIn && (
<Button
title="Update quantity"
onPress={toggleQuantityModal}
color={theme.palette.primaryColor}
/>
)}
{!isLoggedIn && (
<RouterButton
title="Log in to update quantity"
to={'/login'}
color={theme.palette.primaryColor}
/>
)}
</View>
<View style={{ flex: 1, ...contentTileStyle }}>
{/* <IconButton
glyph="stars"
text="Add to Faves"
onPress={this.addToFaves}
color={style.actionIconColor}
/> */}
{isLoggedIn && (
<IconButton
glyph="insert-photo"
text="Add Photo"
onPress={addPhoto}
color={style.actionIconColor}
/>
)}
</View>
</View>
);
};
export default compose(
withFoodItem,
withPlaceForFoodItem,
withUpdateQuantity,
withImages,
withProps(() => ({
isLoggedIn: AuthManager.isLoggedIn(),
})),
withState('currentImage', 'changeCurrentImage', 0),
withState('quantityModalOpen', 'setQuantityModalOpen', false),
withState('imagesLoading', 'setImagesLoading', true),
withHandlers({
addPhoto: ({ addImage, foodItem, setImagesLoading }: Props) => async () => {
if (!foodItem) {
return;
}
const { path: imageUri } = await openImagePicker();
setImagesLoading(true);
await addImage({ foodItemId: foodItem.id, imageUri });
setImagesLoading(false);
setTimeout(
() =>
Snackbar.show({
title: 'Food updated.',
backgroundColor: 'black',
color: 'white',
}),
700
);
},
updateAmount: ({ updateQuantity, foodItem }: Props) => async (quantity: Quantity) => {
if (!foodItem) {
return;
}
await updateQuantity({ foodItemId: foodItem.id, quantity });
Snackbar.show({ title: 'Food updated.', backgroundColor: 'black', color: 'white' });
},
toggleQuantityModal: ({ quantityModalOpen, setQuantityModalOpen }) => () => {
setQuantityModalOpen(!quantityModalOpen);
},
}),
onlyUpdateForKeys([
'foodItem',
'place',
'currentImage',
'quantityModalOpen',
'imagesLoading',
'isLoggedIn',
]),
lifecycle({
componentDidMount() {
const { getImages, foodItemId, setImagesLoading } = this.props;
getImages({
foodItemId,
}).then(() => {
setImagesLoading(false);
});
},
})
)(FoodItemDetail);