2018-01-27 16:56:01 -06:00
|
|
|
import React from 'react';
|
2020-04-26 12:27:24 -05:00
|
|
|
import { Image, View } from 'react-native';
|
2017-04-01 20:53:37 -05:00
|
|
|
import theme from '../ui-theme';
|
2017-07-02 12:32:26 -05:00
|
|
|
import { StrongText, SubText } from '../components/ItemTile';
|
2020-04-17 22:50:23 -05:00
|
|
|
import typeof ProductRecord from '../records/ProductRecord';
|
2017-11-26 19:52:16 -06:00
|
|
|
import { type Quantity } from '../constants/QuantityConstants';
|
2017-06-03 19:43:45 -05:00
|
|
|
import typeof PlaceRecord from '../records/PlaceRecord';
|
2018-04-08 10:54:29 -05:00
|
|
|
import {
|
|
|
|
|
compose,
|
|
|
|
|
withState,
|
|
|
|
|
withHandlers,
|
|
|
|
|
onlyUpdateForKeys,
|
|
|
|
|
withProps,
|
|
|
|
|
lifecycle,
|
|
|
|
|
} from 'recompose';
|
2017-04-14 12:28:48 -05:00
|
|
|
import IconButton from '../components/IconButton';
|
2020-04-17 22:50:23 -05:00
|
|
|
import { withProduct } from '../enhancers/productsEnhancers';
|
|
|
|
|
import { withPlaceForProduct } from '../enhancers/placeEnhancers';
|
2017-04-20 16:28:13 -05:00
|
|
|
import Carousel from 'react-native-looped-carousel';
|
2017-04-23 20:15:46 -05:00
|
|
|
import CountBadge from '../components/CountBadge';
|
2020-03-29 19:47:33 +00:00
|
|
|
import { routeWithTitle, loginWithBackto } from '../helpers/RouteHelpers';
|
2017-08-06 11:33:41 -05:00
|
|
|
import { Link } from 'react-router-native';
|
2017-11-26 19:52:16 -06:00
|
|
|
import { withUpdateQuantity } from '../enhancers/quantityEnhancers';
|
2018-01-27 16:56:01 -06:00
|
|
|
import QuantityModal from '../modals/QuantityModal';
|
2020-03-29 19:47:33 +00:00
|
|
|
import { identity, pathOr } from 'ramda';
|
2018-04-08 10:54:29 -05:00
|
|
|
import Spinner from 'react-native-loading-spinner-overlay';
|
|
|
|
|
import ImageRecord from '../records/ImageRecord';
|
2020-04-04 22:07:17 -05:00
|
|
|
import { get } from 'immutable';
|
2018-11-24 11:09:55 -06:00
|
|
|
import Snackbar from 'react-native-snackbar';
|
2020-03-29 19:47:33 +00:00
|
|
|
import { withAuthed } from '../enhancers/authEnhancers';
|
|
|
|
|
import { withFaves } from '../enhancers/favesEnhancer';
|
|
|
|
|
import debounce from '../helpers/debounce';
|
|
|
|
|
import { withCurrentPath, withReplaceRoute } from '../enhancers/routeEnhancers';
|
2020-04-26 12:27:24 -05:00
|
|
|
import QuantityTile from '../components/QuantityTile';
|
2017-04-14 12:28:48 -05:00
|
|
|
|
2020-04-17 22:50:23 -05:00
|
|
|
const { productDetails: style } = theme;
|
2017-04-01 20:53:37 -05:00
|
|
|
|
2017-04-23 20:15:46 -05:00
|
|
|
const stretchedStyle = { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 };
|
|
|
|
|
|
2020-04-17 22:50:23 -05:00
|
|
|
const ProductImages = ({
|
2018-04-08 10:54:29 -05:00
|
|
|
currentImage,
|
|
|
|
|
visibleImages,
|
|
|
|
|
changeCurrentImage,
|
|
|
|
|
}: {
|
|
|
|
|
currentImage: number,
|
2020-04-04 22:07:17 -05:00
|
|
|
visibleImages: Set<ImageRecord>,
|
2018-04-08 10:54:29 -05:00
|
|
|
changeCurrentImage: (img: number) => void,
|
|
|
|
|
}) => {
|
|
|
|
|
return (
|
|
|
|
|
<View style={{ flex: 3 }}>
|
|
|
|
|
{visibleImages.size === 1 && (
|
2018-09-29 11:22:03 -05:00
|
|
|
<View style={stretchedStyle}>
|
|
|
|
|
<Image
|
2020-04-13 22:11:20 -05:00
|
|
|
style={{ flex: 1, resizeMode: 'contain' }}
|
|
|
|
|
resizeMethod="scale"
|
2020-04-04 22:07:17 -05:00
|
|
|
source={{ uri: get(visibleImages.first(), 'url', '') }}
|
2018-09-29 11:22:03 -05:00
|
|
|
/>
|
|
|
|
|
</View>
|
2018-04-08 10:54:29 -05:00
|
|
|
)}
|
|
|
|
|
{visibleImages.size > 1 && (
|
2019-12-14 09:38:07 -06:00
|
|
|
<Carousel
|
|
|
|
|
autoplay={false}
|
|
|
|
|
onAnimateNextPage={changeCurrentImage}
|
|
|
|
|
style={stretchedStyle}
|
|
|
|
|
currentPage={currentImage}>
|
2020-04-13 22:11:20 -05:00
|
|
|
{visibleImages.map(image => (
|
2018-04-08 10:54:29 -05:00
|
|
|
<Image
|
2020-04-04 22:07:17 -05:00
|
|
|
key={get(image, 'url', '')}
|
2018-09-29 11:22:03 -05:00
|
|
|
style={{ flex: 1, resizeMode: 'cover' }}
|
|
|
|
|
resizeMethod="resize"
|
2020-04-04 22:07:17 -05:00
|
|
|
source={{ uri: get(image, 'url', '') }}
|
2018-04-08 10:54:29 -05:00
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
</Carousel>
|
|
|
|
|
)}
|
|
|
|
|
{visibleImages.size > 0 && (
|
|
|
|
|
<CountBadge currentImage={currentImage + 1} totalCount={visibleImages.size} />
|
|
|
|
|
)}
|
|
|
|
|
</View>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2017-04-23 20:15:46 -05:00
|
|
|
const contentTileStyle = {
|
|
|
|
|
backgroundColor: 'white',
|
2017-11-19 12:46:39 -06:00
|
|
|
padding: 15,
|
|
|
|
|
marginBottom: 10,
|
2017-04-23 20:15:46 -05:00
|
|
|
};
|
2017-04-20 16:28:13 -05:00
|
|
|
|
2018-01-27 16:56:01 -06:00
|
|
|
type Props = {
|
2020-04-17 22:50:23 -05:00
|
|
|
product: ?ProductRecord,
|
|
|
|
|
productId: string,
|
2018-01-27 16:56:01 -06:00
|
|
|
place: PlaceRecord,
|
|
|
|
|
currentImage: number,
|
|
|
|
|
quantityModalOpen: boolean,
|
2020-03-29 19:47:33 +00:00
|
|
|
isAuthed: boolean,
|
2018-01-27 16:56:01 -06:00
|
|
|
changeCurrentImage: (index: number) => void,
|
|
|
|
|
updateAmount: (quantity: Quantity) => void,
|
2020-04-17 22:50:23 -05:00
|
|
|
updateQuantity: (arg: { productId: string, quantity: Quantity }) => void,
|
2018-01-27 16:56:01 -06:00
|
|
|
toggleQuantityModal: () => void,
|
|
|
|
|
addPhoto: () => void,
|
2020-04-17 22:50:23 -05:00
|
|
|
addImage: (arg: { productId: string, imageUri: string }) => Promise<void>,
|
2020-03-29 19:47:33 +00:00
|
|
|
addToFaves: () => void,
|
|
|
|
|
isFave: boolean,
|
|
|
|
|
deleteFromFaves: () => void,
|
2018-01-27 16:56:01 -06:00
|
|
|
};
|
2017-07-23 19:58:10 -05:00
|
|
|
|
2020-04-17 22:50:23 -05:00
|
|
|
export const ProductDetail = (props: Props) => {
|
2018-01-27 16:56:01 -06:00
|
|
|
const {
|
2020-04-17 22:50:23 -05:00
|
|
|
product,
|
2018-01-27 16:56:01 -06:00
|
|
|
place,
|
|
|
|
|
currentImage,
|
|
|
|
|
changeCurrentImage,
|
2020-03-29 19:47:33 +00:00
|
|
|
isAuthed,
|
2018-01-27 16:56:01 -06:00
|
|
|
addPhoto,
|
|
|
|
|
toggleQuantityModal,
|
|
|
|
|
quantityModalOpen,
|
|
|
|
|
updateAmount,
|
2020-03-29 19:47:33 +00:00
|
|
|
addToFaves,
|
|
|
|
|
isFave,
|
|
|
|
|
deleteFromFaves,
|
2018-01-27 16:56:01 -06:00
|
|
|
} = props;
|
|
|
|
|
|
2020-04-17 22:50:23 -05:00
|
|
|
if (!product || !place) {
|
2020-04-13 22:11:20 -05:00
|
|
|
return <Spinner />;
|
2018-01-27 16:56:01 -06:00
|
|
|
}
|
2017-04-20 16:28:13 -05:00
|
|
|
|
2018-01-27 16:56:01 -06:00
|
|
|
return (
|
|
|
|
|
<View style={{ ...theme.page.container }}>
|
2020-04-17 22:50:23 -05:00
|
|
|
<ProductImages
|
2018-04-08 10:54:29 -05:00
|
|
|
currentImage={currentImage}
|
2020-04-17 22:50:23 -05:00
|
|
|
visibleImages={product.images.filter(identity)}
|
2018-04-08 10:54:29 -05:00
|
|
|
changeCurrentImage={changeCurrentImage}
|
|
|
|
|
/>
|
2018-01-27 16:56:01 -06:00
|
|
|
<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>
|
2020-04-26 12:27:24 -05:00
|
|
|
<QuantityTile
|
|
|
|
|
product={product}
|
|
|
|
|
isAuthed={isAuthed}
|
|
|
|
|
onUpdatePress={toggleQuantityModal}
|
|
|
|
|
style={contentTileStyle}
|
|
|
|
|
/>
|
2018-01-27 16:56:01 -06:00
|
|
|
<View style={{ flex: 1, ...contentTileStyle }}>
|
2020-03-29 19:47:33 +00:00
|
|
|
{isAuthed && isFave ? (
|
|
|
|
|
<IconButton
|
|
|
|
|
glyph="favorite"
|
|
|
|
|
text="Favorited"
|
|
|
|
|
onPress={deleteFromFaves}
|
|
|
|
|
color="#990000"
|
|
|
|
|
style={{ marginBottom: 10 }}
|
|
|
|
|
textStyle={{ fontSize: 20, color: '#555555' }}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<IconButton
|
|
|
|
|
glyph="favorite"
|
|
|
|
|
text="Add to Faves"
|
|
|
|
|
onPress={addToFaves}
|
|
|
|
|
color={style.actionIconColor}
|
|
|
|
|
style={{ marginBottom: 10 }}
|
|
|
|
|
textStyle={{ fontSize: 20, color: '#555555' }}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
{isAuthed && (
|
2018-04-08 10:54:29 -05:00
|
|
|
<IconButton
|
|
|
|
|
glyph="insert-photo"
|
|
|
|
|
text="Add Photo"
|
|
|
|
|
onPress={addPhoto}
|
|
|
|
|
color={style.actionIconColor}
|
2020-03-29 19:47:33 +00:00
|
|
|
textStyle={{ fontSize: 20, color: '#555555' }}
|
2018-04-08 10:54:29 -05:00
|
|
|
/>
|
|
|
|
|
)}
|
2018-01-27 16:56:01 -06:00
|
|
|
</View>
|
2019-12-14 09:38:07 -06:00
|
|
|
{quantityModalOpen && (
|
2020-04-17 22:50:23 -05:00
|
|
|
<QuantityModal product={product} onUpdate={updateAmount} onClose={toggleQuantityModal} />
|
2019-12-14 09:38:07 -06:00
|
|
|
)}
|
2018-01-27 16:56:01 -06:00
|
|
|
</View>
|
|
|
|
|
);
|
|
|
|
|
};
|
2017-04-01 20:53:37 -05:00
|
|
|
|
2018-01-27 16:56:01 -06:00
|
|
|
export default compose(
|
2020-04-17 22:50:23 -05:00
|
|
|
withProduct,
|
|
|
|
|
withPlaceForProduct,
|
2018-01-27 16:56:01 -06:00
|
|
|
withUpdateQuantity,
|
2020-03-29 19:47:33 +00:00
|
|
|
withAuthed,
|
|
|
|
|
withFaves,
|
|
|
|
|
withCurrentPath,
|
|
|
|
|
withReplaceRoute,
|
2018-01-27 16:56:01 -06:00
|
|
|
withState('currentImage', 'changeCurrentImage', 0),
|
|
|
|
|
withState('quantityModalOpen', 'setQuantityModalOpen', false),
|
|
|
|
|
withHandlers({
|
2020-04-17 22:50:23 -05:00
|
|
|
updateAmount: ({ updateQuantity, product }: Props) => async (quantity: Quantity) => {
|
|
|
|
|
if (!product) {
|
2018-05-01 16:28:01 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2020-04-17 22:50:23 -05:00
|
|
|
await updateQuantity({ productId: product.id, quantity });
|
|
|
|
|
Snackbar.show({ title: 'Product updated.', backgroundColor: 'black', color: 'white' });
|
2018-01-27 16:56:01 -06:00
|
|
|
},
|
2020-03-29 19:47:33 +00:00
|
|
|
toggleQuantityModal: ({ quantityModalOpen, setQuantityModalOpen }) =>
|
|
|
|
|
debounce(() => {
|
|
|
|
|
setQuantityModalOpen(!quantityModalOpen);
|
|
|
|
|
}, 500),
|
2020-04-17 22:50:23 -05:00
|
|
|
addToFaves: ({ addFave, productId, isAuthed, replaceRoute }) =>
|
2020-03-29 19:47:33 +00:00
|
|
|
debounce(() => {
|
|
|
|
|
if (!isAuthed) {
|
2020-04-17 22:50:23 -05:00
|
|
|
replaceRoute(loginWithBackto(`/product/${productId}?loginAction=add-to-faves`));
|
2020-03-29 19:47:33 +00:00
|
|
|
} else {
|
2020-04-17 22:50:23 -05:00
|
|
|
addFave(productId);
|
2020-03-29 19:47:33 +00:00
|
|
|
}
|
|
|
|
|
}, 500),
|
2020-04-17 22:50:23 -05:00
|
|
|
deleteFromFaves: ({ deleteFave, productId }) => () => deleteFave(productId),
|
2018-01-27 16:56:01 -06:00
|
|
|
}),
|
2020-04-13 22:11:20 -05:00
|
|
|
withProps(props => ({
|
2020-04-17 22:50:23 -05:00
|
|
|
isFave: props.faves && !!props.faves.find(fave => get(fave, 'id') === props.productId),
|
2020-03-29 19:47:33 +00:00
|
|
|
loginAction: pathOr('', [1], /loginAction=(.+)(&?.*$)/.exec(props.currentPath)),
|
|
|
|
|
})),
|
2018-08-25 15:40:25 -05:00
|
|
|
onlyUpdateForKeys([
|
2020-04-17 22:50:23 -05:00
|
|
|
'product',
|
2018-08-25 15:40:25 -05:00
|
|
|
'place',
|
|
|
|
|
'quantityModalOpen',
|
2020-04-13 22:11:20 -05:00
|
|
|
// 'imagesLoading',
|
2020-03-29 19:47:33 +00:00
|
|
|
'isAuthed',
|
|
|
|
|
'faves',
|
2018-08-25 15:40:25 -05:00
|
|
|
]),
|
2018-04-08 10:54:29 -05:00
|
|
|
lifecycle({
|
|
|
|
|
componentDidMount() {
|
2020-04-13 22:11:20 -05:00
|
|
|
const { loginAction, setQuantityModalOpen, addToFaves } = this.props;
|
2020-03-29 19:47:33 +00:00
|
|
|
|
|
|
|
|
if (loginAction === 'open-quantity-modal') {
|
|
|
|
|
setQuantityModalOpen(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (loginAction === 'add-to-faves') {
|
|
|
|
|
addToFaves();
|
|
|
|
|
}
|
2018-04-08 10:54:29 -05:00
|
|
|
},
|
|
|
|
|
})
|
2020-04-17 22:50:23 -05:00
|
|
|
)(ProductDetail);
|