Commit dfba7072 authored by Dmytro Zavgorodniy's avatar Dmytro Zavgorodniy

[RNA-761] Update AddToCartView HOC

parent c61c955d
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { denormalize } from 'normalizr'
import { createSelector } from 'reselect'
import { debounce } from 'lodash'
import { Router } from 'tipsi-router'
import { updateStoreCartProductCount } from 'tipsi_api/actions'
import {
entitiesSelector,
relationsSelector,
metaSelector,
createStoreSelector,
createInventorySelector,
userSelector,
createStoreCartSelector,
} from 'tipsi_api/selectors'
import { Schemas } from 'tipsi_api/middleware'
import { loadStoreCart } from '../../actions'
import CartHOC from '../CartHOC'
export function enhanceAddToCartView(ComposedComponent) {
export default function enhanceAddToCartView(ComposedComponent) {
class Wrapper extends Component {
static propTypes = {
// props
storeId: PropTypes.number.isRequired,
storeId: PropTypes.number.isRequired, // eslint-disable-line react/no-unused-prop-types
inventoryId: PropTypes.number.isRequired,
inventoryType: PropTypes.string, // eslint-disable-line react/no-unused-prop-types
// map state to props
store: PropTypes.object, // eslint-disable-line react/no-unused-prop-types
inventoryType: PropTypes.string,
// Cart HOC
store: PropTypes.object,
inventory: PropTypes.object,
user: PropTypes.object,
order: PropTypes.object,
orderProducts: PropTypes.array.isRequired,
modifiedOrderCount: PropTypes.number.isRequired,
modifiedStoreCart: PropTypes.object.isRequired,
isLoadingStoreCart: PropTypes.bool.isRequired,
orderProduct: PropTypes.object,
isUpdatingInventory: PropTypes.bool.isRequired,
// map dispatch to props
loadStoreCart: PropTypes.func.isRequired,
updateStoreCartProductCount: PropTypes.func.isRequired,
storeCartStatuses: PropTypes.object.isRequired,
addInventoryToCart: PropTypes.func.isRequired,
updateInventoryInCart: PropTypes.func.isRequired,
removeInventoryFromCart: PropTypes.func.isRequired,
openCart: PropTypes.func.isRequired,
}
static defaultProps = {
// props
inventoryType: 'other',
// map state to props
// Cart HOC
store: undefined,
inventory: undefined,
user: undefined,
order: undefined,
orderProduct: undefined,
}
state = this.getCurrentState()
shouldComponentUpdate(nextProps, nextState) {
const { orderProduct, user } = this.props
const userHasLoggedIn = !user && nextProps.user
const totalCountHasChanged = this.getTotalCount() !== this.getTotalCount(nextProps)
const orderProductHasBeenAdded = !orderProduct && nextProps.orderProduct
const orderProductHasBeenRemoved = orderProduct && !nextProps.orderProduct
const orderProductCountHasChanged = orderProduct && nextProps.orderProduct && (
this.getCount() !== this.getCount(nextProps)
)
const localOrderProductCountHasChanged = (
this.state.count !== nextState.count
)
const shouldUpdate = (
userHasLoggedIn ||
totalCountHasChanged ||
orderProductHasBeenAdded ||
orderProductHasBeenRemoved ||
orderProductCountHasChanged ||
localOrderProductCountHasChanged ||
this.props.isUpdatingInventory !== nextProps.isUpdatingInventory
)
return !!shouldUpdate
}
getTotalCount(nextProps) {
const { order = {} } = nextProps || this.props
return order.total_count || 0
}
getCount(nextProps) {
const { orderProduct = {} } = nextProps || this.props
return orderProduct.count || 0
}
getCurrentState(nextProps) {
const props = nextProps || this.props
return {
totalCount: this.getTotalCount(props),
count: this.getCount(props),
}
}
loadStoreCart = () => {
if (!this.props.isLoadingStoreCart && !this.props.order && this.props.user) {
this.props.loadStoreCart(this.props.storeId)
}
}
isLoading = (nextProps) => {
const props = nextProps || this.props
return (props.isLoadingStoreCart || props.isUpdatingInventory)
}
updateStoreCartProduct = (totalCount, count) => {
this.setState({ totalCount, count })
if (this.props.orderProduct) {
return this.debounceUpdateStoreCartProduct(count)
}
return this.props.updateStoreCartProductCount(
this.props.storeId,
[{ inventory_id: this.props.inventoryId, count }]
)
}
debounceUpdateStoreCartProduct = debounce((count) => {
// No need send update if count does not change
if (count === this.getCount()) {
return
}
this.props.updateStoreCartProductCount(
this.props.storeId,
[{ inventory_id: this.props.inventoryId, count }]
)
}, 1000)
handleAddToCartButtonOnPress = () => {
// Should not update inventory if is in loading state
if (this.isLoading()) {
return
}
// Should not update inventory for guest access
if (!this.props.user) {
Router.showModal(null, Router.routes.login, {
config: { navigationBar: { visible: false } },
})
return
}
this.updateStoreCartProduct(this.state.totalCount + 1, this.state.count + 1)
}
handleCartButtonOnPress = () => {
// this.props.navigation.getNavigator('app').push('Cart', { storeId: this.props.storeId })
console.log('Go to Cart')
}
handleRemoveButtonOnPress = () => {
const { count } = this.state
// Should not update inventory if is in loading state
if (this.isLoading()) {
return
}
// Should not update inventory if current count is zero
if (count === 0) {
return
}
this.updateStoreCartProduct(this.state.totalCount - 1, count - 1)
}
handleAddButtonOnPress = () => {
const { inventory = { in_stock: 0 } } = this.props
const { count } = this.state
// Should not update inventory if is in loading state
if (this.isLoading()) {
return
}
// Should not update inventory if is no more items available
if (count >= inventory.in_stock) {
throw new Error('Sorry, there are no more items in stock')
}
this.updateStoreCartProduct(this.state.totalCount + 1, count + 1)
}
render() {
return (
<ComposedComponent
{...this.props}
{...this.state}
loadStoreCart={this.loadStoreCart}
isLoading={this.isLoading}
handleAddToCartButtonOnPress={this.handleAddToCartButtonOnPress}
handleCartButtonOnPress={this.handleCartButtonOnPress}
handleRemoveButtonOnPress={this.handleRemoveButtonOnPress}
handleAddButtonOnPress={this.handleAddButtonOnPress}
inventoryId={this.props.inventoryId}
inventoryType={this.props.inventoryType}
store={this.props.store}
inventory={this.props.inventory}
orderProducts={this.props.orderProducts}
modifiedOrderCount={this.props.modifiedOrderCount}
modifiedStoreCart={this.props.modifiedStoreCart}
isLoadingStoreCart={this.props.isLoadingStoreCart}
storeCartStatuses={this.props.storeCartStatuses}
addInventoryToCart={this.props.addInventoryToCart}
updateInventoryInCart={this.props.updateInventoryInCart}
removeInventoryFromCart={this.props.removeInventoryFromCart}
openCart={this.props.openCart}
/>
)
}
}
const mapStateToProps = createSelector(
(state, props) => ({ props }),
createStoreSelector((state, props) => props.storeId),
createInventorySelector((state, props) => props.inventoryId),
userSelector,
createStoreCartSelector((state, props) => props.storeId),
entitiesSelector,
relationsSelector,
metaSelector,
({ props }, { store }, { inventory }, { user }, storeCart, entities, relations, meta) => {
const { inventoryId } = props
let orderProduct
const orderProductId = relations.storeCartItems.inventory[inventoryId]
if (orderProductId && storeCart.orderProductIds.includes(orderProductId)) {
orderProduct = denormalize(orderProductId, Schemas.ORDER_PRODUCT, entities)
}
const isUpdatingInventory = meta.storeCartInventory.fetchStatus[inventoryId] || false
return {
store,
inventory,
user,
order: storeCart.order,
isLoadingStoreCart: storeCart.isLoading,
orderProduct,
isUpdatingInventory,
}
}
)
return connect(mapStateToProps, { loadStoreCart, updateStoreCartProductCount })(Wrapper)
return CartHOC(Wrapper)
}
......@@ -20,7 +20,7 @@ import {
metaSelector,
} from 'tipsi_api/selectors'
import { itemFormatter } from '../../utils/formatters'
import { enhanceAddToCartView } from './AddToCartView'
import enhanceAddToCartView from './AddToCartView'
function enhanceItemDetails(Wine, Drink, AddToCartView) {
const AddToCartViewHOC = enhanceAddToCartView(AddToCartView)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment