aretherecookies-mobile/js/pages/ProductDetail.js
2020-05-31 15:43:53 -05:00

244 lines
6.6 KiB
JavaScript

import React from 'react';
import { Image, View } from 'react-native';
import theme from '../ui-theme';
import { StrongText, SubText } from '../components/ItemTile';
import typeof ProductRecord from '../records/ProductRecord';
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 { withProduct } from '../enhancers/productsEnhancers';
import { withPlaceForProduct } from '../enhancers/placeEnhancers';
import Carousel from 'react-native-looped-carousel';
import CountBadge from '../components/CountBadge';
import { routeWithTitle, loginWithBackto } from '../helpers/RouteHelpers';
import { Link } from 'react-router-native';
import { withUpdateQuantity } from '../enhancers/quantityEnhancers';
import QuantityModal from '../modals/QuantityModal';
import { identity, pathOr } from 'ramda';
import Spinner from 'react-native-loading-spinner-overlay';
import ImageRecord from '../records/ImageRecord';
import { get } from 'immutable';
import Snackbar from 'react-native-snackbar';
import { withAuthed } from '../enhancers/authEnhancers';
import { withFaves } from '../enhancers/favesEnhancer';
import debounce from '../helpers/debounce';
import { withCurrentPath, withReplaceRoute } from '../enhancers/routeEnhancers';
import QuantityTile from '../components/QuantityTile';
const { productDetails: style } = theme;
const stretchedStyle = { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 };
const ProductImages = ({
currentImage,
visibleImages,
changeCurrentImage,
}: {
currentImage: number,
visibleImages: Set<ImageRecord>,
changeCurrentImage: (img: number) => void,
}) => {
return (
<View style={{ flex: 3 }}>
{visibleImages.size === 1 && (
<View style={stretchedStyle}>
<Image
style={{ flex: 1, resizeMode: 'contain' }}
resizeMethod="scale"
source={{ uri: visibleImages.first() }}
/>
</View>
)}
{visibleImages.size > 1 && (
<Carousel
autoplay={false}
onAnimateNextPage={changeCurrentImage}
style={stretchedStyle}
currentPage={currentImage}>
{visibleImages.map(imageUrl => (
<Image
key={imageUrl}
style={{ flex: 1, resizeMode: 'cover' }}
resizeMethod="resize"
source={{ uri: imageUrl }}
/>
))}
</Carousel>
)}
{visibleImages.size > 0 && (
<CountBadge currentImage={currentImage + 1} totalCount={visibleImages.size} />
)}
</View>
);
};
const contentTileStyle = {
backgroundColor: 'white',
padding: 15,
marginBottom: 10,
};
type Props = {
product: ?ProductRecord,
productId: string,
place: PlaceRecord,
currentImage: number,
quantityModalOpen: boolean,
isAuthed: boolean,
changeCurrentImage: (index: number) => void,
updateAmount: (quantity: Quantity) => void,
updateQuantity: (arg: { productId: string, quantity: Quantity }) => void,
toggleQuantityModal: () => void,
addPhoto: () => void,
addImage: (arg: { productId: string, imageUri: string }) => Promise<void>,
addToFaves: () => void,
isFave: boolean,
deleteFromFaves: () => void,
};
export const ProductDetail = (props: Props) => {
const {
product,
place,
currentImage,
changeCurrentImage,
isAuthed,
addPhoto,
toggleQuantityModal,
quantityModalOpen,
updateAmount,
addToFaves,
isFave,
deleteFromFaves,
} = props;
if (!product || !place) {
return <Spinner />;
}
return (
<View style={{ ...theme.page.container }}>
<ProductImages
currentImage={currentImage}
visibleImages={product.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>
<QuantityTile
product={product}
isAuthed={isAuthed}
onUpdatePress={toggleQuantityModal}
style={contentTileStyle}
/>
<View style={{ flex: 1, ...contentTileStyle }}>
{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 && (
<IconButton
glyph="insert-photo"
text="Add Photo"
onPress={addPhoto}
color={style.actionIconColor}
textStyle={{ fontSize: 20, color: '#555555' }}
/>
)}
</View>
{quantityModalOpen && (
<QuantityModal product={product} onUpdate={updateAmount} onClose={toggleQuantityModal} />
)}
</View>
);
};
export default compose(
withProduct,
withPlaceForProduct,
withUpdateQuantity,
withAuthed,
withFaves,
withCurrentPath,
withReplaceRoute,
withState('currentImage', 'changeCurrentImage', 0),
withState('quantityModalOpen', 'setQuantityModalOpen', false),
withHandlers({
updateAmount: ({ updateQuantity, product }: Props) => async (quantity: Quantity) => {
if (!product) {
return;
}
await updateQuantity({ productId: product.id, quantity });
Snackbar.show({ title: 'Product updated.', backgroundColor: 'black', color: 'white' });
},
toggleQuantityModal: ({ quantityModalOpen, setQuantityModalOpen }) =>
debounce(() => {
setQuantityModalOpen(!quantityModalOpen);
}, 500),
addToFaves: ({ addFave, productId, isAuthed, replaceRoute }) =>
debounce(() => {
if (!isAuthed) {
replaceRoute(loginWithBackto(`/product/${productId}?loginAction=add-to-faves`));
} else {
addFave(productId);
}
}, 500),
deleteFromFaves: ({ deleteFave, productId }) => () => deleteFave(productId),
}),
withProps(props => ({
isFave: props.faves && !!props.faves.find(fave => get(fave, 'id') === props.productId),
loginAction: pathOr('', [1], /loginAction=(.+)(&?.*$)/.exec(props.currentPath)),
})),
onlyUpdateForKeys([
'product',
'place',
'quantityModalOpen',
// 'imagesLoading',
'isAuthed',
'faves',
]),
lifecycle({
componentDidMount() {
const { loginAction, setQuantityModalOpen, addToFaves } = this.props;
if (loginAction === 'open-quantity-modal') {
setQuantityModalOpen(true);
}
if (loginAction === 'add-to-faves') {
addToFaves();
}
},
})
)(ProductDetail);