Commit 124b653c authored by Denis Sedura's avatar Denis Sedura

[RNA-761] Fix after rebase

parent 16869631
...@@ -3,202 +3,239 @@ import PropTypes from 'prop-types' ...@@ -3,202 +3,239 @@ import PropTypes from 'prop-types'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { denormalize } from 'normalizr' import { denormalize } from 'normalizr'
import { createSelector } from 'reselect' import { createSelector } from 'reselect'
import { isEqual } from 'lodash' import { debounce } from 'lodash'
import { Router } from 'tipsi-router' import { Router } from 'tipsi-router'
import { updateStoreCartProductCount } from 'tipsi_api/actions'
import { import {
entitiesSelector, entitiesSelector,
paginationsSelector, relationsSelector,
metaSelector,
createStoreSelector, createStoreSelector,
createStoreCartOrderSelector,
createInventorySelector, createInventorySelector,
userSelector, userSelector,
createStoreCartSelector,
} from 'tipsi_api/selectors' } from 'tipsi_api/selectors'
import { Schemas } from 'tipsi_api/middleware' import { Schemas } from 'tipsi_api/middleware'
import { import { loadStoreCart } from '../../actions'
loadStoreCart,
addInventoryToCart,
increaseInventoryCount,
decreaseInventoryCount,
} from '../../actions/storeCarts'
import { createCartStatusSelector } from '../../selectors'
export function enhanceAddToCartView(ComposedComponent) { export function enhanceAddToCartView(ComposedComponent) {
class Wrapper extends Component { class Wrapper extends Component {
static propTypes = { static propTypes = {
user: PropTypes.object, // props
inventoryType: PropTypes.string,
storeId: PropTypes.number.isRequired, storeId: PropTypes.number.isRequired,
inventoryId: PropTypes.number.isRequired, inventoryId: PropTypes.number.isRequired,
store: PropTypes.object, 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
inventory: PropTypes.object, inventory: PropTypes.object,
user: PropTypes.object,
order: PropTypes.object, order: PropTypes.object,
isLoadingStoreCart: PropTypes.bool.isRequired,
orderProduct: PropTypes.object, orderProduct: PropTypes.object,
isUpdatingInventory: PropTypes.bool.isRequired,
// map dispatch to props
loadStoreCart: PropTypes.func.isRequired, loadStoreCart: PropTypes.func.isRequired,
addInventoryToCart: PropTypes.func.isRequired, updateStoreCartProductCount: PropTypes.func.isRequired,
increaseInventoryCount: PropTypes.func.isRequired,
decreaseInventoryCount: PropTypes.func.isRequired,
isLoadingCart: PropTypes.bool,
isAddingToCart: PropTypes.bool,
isIncreasingCount: PropTypes.bool,
isDecreasingCount: PropTypes.bool,
isRemovingFromCart: PropTypes.bool,
} }
static defaultProps = { static defaultProps = {
user: undefined, // props
inventoryType: 'other', inventoryType: 'other',
// map state to props
store: undefined, store: undefined,
inventory: undefined, inventory: undefined,
user: undefined,
order: undefined, order: undefined,
orderProduct: undefined, orderProduct: undefined,
isLoadingCart: false,
isAddingToCart: false,
isIncreasingCount: false,
isDecreasingCount: false,
isRemovingFromCart: false,
} }
shouldComponentUpdate(nextProps) { state = this.getCurrentState()
return !isEqual(this.props, nextProps)
}
loadStoreCart = () => { shouldComponentUpdate(nextProps, nextState) {
const { storeId, inventoryId, isLoadingCart } = this.props const { orderProduct, user } = this.props
if (!isLoadingCart) { const userHasLoggedIn = !user && nextProps.user
this.props.loadStoreCart({ storeId, inventoryId }) 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
} }
addToCart = () => { getTotalCount(nextProps) {
const { storeId, inventoryId, isAddingToCart, user } = this.props const { order = {} } = nextProps || this.props
return order.total_count || 0
}
if (!user) { getCount(nextProps) {
Router.showModal(null, Router.routes.login, { const { orderProduct = {} } = nextProps || this.props
config: { navigationBar: { visible: false } }, return orderProduct.count || 0
}) }
return
}
if (!isAddingToCart) { getCurrentState(nextProps) {
this.props.addInventoryToCart({ storeId, inventoryId }) const props = nextProps || this.props
return {
totalCount: this.getTotalCount(props),
count: this.getCount(props),
} }
} }
increaseCount = () => { loadStoreCart = () => {
const { storeId, inventoryId, isIncreasingCount } = this.props if (!this.props.isLoadingStoreCart && !this.props.order && this.props.user) {
if (!isIncreasingCount) { this.props.loadStoreCart(this.props.storeId)
this.props.increaseInventoryCount({ storeId, inventoryId })
} }
} }
decreaseCount = () => { isLoading = (nextProps) => {
const { storeId, inventoryId, isDecreasingCount, isRemovingFromCart } = this.props const props = nextProps || this.props
const loading = isDecreasingCount || isRemovingFromCart return (props.isLoadingStoreCart || props.isUpdatingInventory)
if (!loading) {
this.props.decreaseInventoryCount({ storeId, inventoryId })
}
} }
countForOrder = (order) => { updateStoreCartProduct = (totalCount, count) => {
let count = 0 this.setState({ totalCount, count })
if (order && order.total_count) {
count = order.total_count if (this.props.orderProduct) {
return this.debounceUpdateStoreCartProduct(count)
} }
return count
return this.props.updateStoreCartProductCount(
this.props.storeId,
[{ inventory_id: this.props.inventoryId, count }]
)
} }
countForOrderProduct = (orderProduct) => { debounceUpdateStoreCartProduct = debounce((count) => {
let count = 0 // No need send update if count does not change
if (orderProduct && orderProduct.count) { if (count === this.getCount()) {
count = orderProduct.count return
} }
return count
} this.props.updateStoreCartProductCount(
this.props.storeId,
[{ inventory_id: this.props.inventoryId, count }]
)
}, 1000)
handleAddToCartButtonOnPress = () => { handleAddToCartButtonOnPress = () => {
const { isLoadingCart, isAddingToCart } = this.props // Should not update inventory if is in loading state
const loading = isLoadingCart || isAddingToCart if (this.isLoading()) {
if (!loading) { return
this.addToCart() }
// 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 = () => { handleCartButtonOnPress = () => {
// const { order: { id: orderId }, navigation } = this.props // this.props.navigation.getNavigator('app').push('Cart', { storeId: this.props.storeId })
// const navigatorApp = navigation.getNavigator('app') console.log('Go to Cart')
// navigatorApp.push('Cart', { orderId })
console.log('Show Cart')
} }
handleRemoveButtonOnPress = () => { handleRemoveButtonOnPress = () => {
this.decreaseCount() 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 = () => { handleAddButtonOnPress = () => {
this.increaseCount() 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() { render() {
return ( return (
<ComposedComponent <ComposedComponent
{...this.props} {...this.props}
addToCart={this.addToCart} {...this.state}
loadStoreCart={this.loadStoreCart} loadStoreCart={this.loadStoreCart}
countForOrder={this.countForOrder} isLoading={this.isLoading}
countForOrderProduct={this.countForOrderProduct} handleAddToCartButtonOnPress={this.handleAddToCartButtonOnPress}
handleCartButtonOnPress={this.handleCartButtonOnPress} handleCartButtonOnPress={this.handleCartButtonOnPress}
handleAddButtonOnPress={this.handleAddButtonOnPress}
handleRemoveButtonOnPress={this.handleRemoveButtonOnPress} handleRemoveButtonOnPress={this.handleRemoveButtonOnPress}
handleAddToCartButtonOnPress={this.handleAddToCartButtonOnPress} handleAddButtonOnPress={this.handleAddButtonOnPress}
/> />
) )
} }
} }
const getStoreId = (state, props) => props.storeId const mapStateToProps = createSelector(
const inventoryIdSelector = (state, props) => props.inventoryId (state, props) => ({ props }),
createStoreSelector((state, props) => props.storeId),
const createStoreCartSelector = createSelector( createInventorySelector((state, props) => props.inventoryId),
createStoreCartOrderSelector(getStoreId), userSelector,
paginationsSelector, createStoreCartSelector((state, props) => props.storeId),
entitiesSelector, entitiesSelector,
(order = {}, paginations, entities) => { relationsSelector,
const { ids = [] } = paginations.orderProducts[order.id] || {} metaSelector,
const orderProducts = denormalize(ids, Schemas.ORDER_PRODUCT_ARRAY, entities) ({ props }, { store }, { inventory }, { user }, storeCart, entities, relations, meta) => {
return { order, orderProducts } 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 createStoreInventoryCartSelector = createSelector( const isUpdatingInventory = meta.storeCartInventory.fetchStatus[inventoryId] || false
createStoreCartSelector,
createInventorySelector(inventoryIdSelector),
inventoryIdSelector,
({ order, orderProducts }, { inventory }, inventoryId) => ({
order,
inventory,
orderProduct: orderProducts.find(product => product.inventory.id === inventoryId),
})
)
const mapStateToProps = createSelector( return {
createStoreSelector(getStoreId), store,
createCartStatusSelector(getStoreId, inventoryIdSelector), inventory,
createStoreInventoryCartSelector, user,
userSelector, order: storeCart.order,
({ store }, status, { order, inventory, orderProduct }, { user }) => ({ isLoadingStoreCart: storeCart.isLoading,
store, orderProduct,
order, isUpdatingInventory,
orderProduct, }
inventory, }
user,
...status,
})
) )
return connect(mapStateToProps, { return connect(mapStateToProps, { loadStoreCart, updateStoreCartProductCount })(Wrapper)
loadStoreCart,
addInventoryToCart,
increaseInventoryCount,
decreaseInventoryCount,
})(Wrapper)
} }
import React, { Component } from 'react' import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { createSelector } from 'reselect'
import { Router } from 'tipsi-router' import { Router } from 'tipsi-router'
import {
loginEmail,
loginTwitter,
loginFacebook,
loadUserProfile,
register,
linkSocialAccount,
} from 'tipsi_api/actions'
import { authSelector, userSelector } from 'tipsi_api/selectors'
function enhanceLogin(ComposedComponent) { export default function enhanceLogin(ComposedComponent) {
class Wrapper extends Component { return class Wrapper extends Component {
static propTypes = { dismissModal = () => (
loginEmail: PropTypes.func.isRequired,
loginTwitter: PropTypes.func.isRequired,
loginFacebook: PropTypes.func.isRequired,
loadUserProfile: PropTypes.func.isRequired,
navigation: PropTypes.object.isRequired,
isLoading: PropTypes.bool.isRequired,
isTwitterLoading: PropTypes.bool.isRequired,
isFacebookLoading: PropTypes.bool.isRequired,
route: PropTypes.object.isRequired,
user: PropTypes.object,
}
static defaultProps = {
user: null,
}
state = {
username: '',
password: '',
}
componentWillReceiveProps(nextProps) {
const { route, user } = nextProps
if (!this.props.user && user && user.username) {
Router.dismissModal()
if (route.params.redirect) {
// navigation.getNavigator('app').push(route.params.redirect, { user })
console.log('Redirect to');
}
}
}
handleDismissLogin = () => {
Router.dismissModal() Router.dismissModal()
} )
handleChangeUsername = (username) => {
this.setState({ username })
}
handleChangePassword = (password) => {
this.setState({ password: password.replace(/\s+/g, '') })
}
render() { render() {
return ( return (
<ComposedComponent <ComposedComponent {...this.props} dismissModal={this.dismissModal} />
{...this.props}
{...this.state}
handleDismissLogin={this.handleDismissLogin}
handleChangeUsername={this.handleChangeUsername}
handleChangePassword={this.handleChangePassword}
/>
) )
} }
} }
const mapStateToProps = createSelector(
[authSelector, userSelector],
({ isLoading, isTwitterLoading, isFacebookLoading }, user) => ({
...user,
isLoading,
isTwitterLoading,
isFacebookLoading,
})
)
const mapDispatchToProps = {
loginEmail,
loginTwitter,
loginFacebook,
loadUserProfile,
register,
linkSocialAccount,
}
return connect(mapStateToProps, mapDispatchToProps)(Wrapper)
} }
export default enhanceLogin
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
"tipsi-stripe": "4.0.0" "tipsi-stripe": "4.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"redux-form": "^7.1.2",
"normalizr": "^3.2.2", "normalizr": "^3.2.2",
"@expo/ex-navigation": "3.1.0", "@expo/ex-navigation": "3.1.0",
"react-native-firebase-analytics": "3.0.2", "react-native-firebase-analytics": "3.0.2",
......
import { createStore, applyMiddleware, combineReducers, compose } from 'redux' import { createStore, applyMiddleware, combineReducers, compose } from 'redux'
import { AsyncStorage, Platform } from 'react-native' import { AsyncStorage, Platform } from 'react-native'
import { persistStore, autoRehydrate } from 'redux-persist' import { persistStore, autoRehydrate } from 'redux-persist'
import { reducer as form } from 'redux-form'
import createFilter from 'redux-persist-transform-filter' import createFilter from 'redux-persist-transform-filter'
import thunk from 'redux-thunk' import thunk from 'redux-thunk'
import uuidv4 from 'uuid/v4' import uuidv4 from 'uuid/v4'
...@@ -27,7 +28,7 @@ const tipsiMiddleware = createApiMiddleware({ ...@@ -27,7 +28,7 @@ const tipsiMiddleware = createApiMiddleware({
}), }),
}) })
const middleware = [tipsiMiddleware, thunk, analyticsMiddleware]//, logger] const middleware = [tipsiMiddleware, thunk, analyticsMiddleware] // ,logger]
// if (__DEV__) { // if (__DEV__) {
// middleware.push(require('redux-logger')()) // middleware.push(require('redux-logger')())
...@@ -47,6 +48,7 @@ const combinedReducers = combineReducers({ ...@@ -47,6 +48,7 @@ const combinedReducers = combineReducers({
meta, meta,
paginations, paginations,
navigation, navigation,
form,
...reducers, ...reducers,
}) })
......
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