Commit c61c955d authored by Dmytro Zavgorodniy's avatar Dmytro Zavgorodniy

[RNA-761] Update Store/WineList/DrinkList HOCs

parent dc349fce
......@@ -2,64 +2,51 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { createSelector } from 'reselect'
import { denormalize } from 'normalizr'
import { Router } from 'tipsi-router'
import { searchInventory, clearPaginationCache } from 'tipsi_api/actions'
import {
entitiesSelector,
relationsSelector,
metaSelector,
createSearchInventoryListSelector,
createStoreSelector,
createStoreCartOrderSelector,
entitiesSelector,
createStoreCartSelector,
} from 'tipsi_api/selectors'
import { searchInventory, clearPaginationCache } from 'tipsi_api/actions'
import { STORE_SEARCH_KEY } from '../../actions'
import { createStoreCartStatusSelector } from '../../selectors/storeCarts'
import { Schemas } from 'tipsi_api/middleware'
import { convertFiltersToQuery } from '../../reducers/storeFilters'
import { STORE_SEARCH_KEY } from '../../actions'
function enhanceDrinkList(ComposedComponent, drinkType, listLabel) {
class Wrapper extends Component {
static propTypes = {
// props
storeId: PropTypes.number.isRequired,
storeDrinks: PropTypes.object.isRequired,
isLoading: PropTypes.bool.isRequired,
isTabLoaded: PropTypes.bool.isRequired,
onAddToCartPress: PropTypes.func.isRequired,
onRemoveFromCartPress: PropTypes.func.isRequired,
inventoryType: PropTypes.string.isRequired,
itemsCount: PropTypes.number.isRequired,
loadStoreDrinks: PropTypes.func.isRequired,
clearSearchCache: PropTypes.func.isRequired,
// map state to props
isLoading: PropTypes.bool.isRequired,
nextPage: PropTypes.number,
isTabLoaded: PropTypes.bool.isRequired,
store: PropTypes.object,
searchQuery: PropTypes.string,
storeFilters: PropTypes.object,
store: PropTypes.object,
orderProducts: PropTypes.object,
storeCart: PropTypes.object.isRequired,
orderProductsInventory: PropTypes.object,
onAddToCartPress: PropTypes.func.isRequired,
onRemoveFromCartPress: PropTypes.func.isRequired,
itemsCount: PropTypes.number.isRequired,
storeDrinks: PropTypes.object.isRequired,
isLoadingStoreCart: PropTypes.bool.isRequired,
// map dispatch to props
searchInventory: PropTypes.func.isRequired,
clearPaginationCache: PropTypes.func.isRequired,
}
static defaultProps = {
// map state to props
nextPage: undefined,
store: {},
searchQuery: undefined,
storeFilters: undefined,
store: undefined,
orderProductsInventory: {},
orderProducts: {},
}
clearSearchCache = () => {
this.props.clearSearchCache()
}
handleOnRowPress = (inventoryId) => {
const { storeId, inventoryType } = this.props
Router.push(null, Router.routes.itemDetails, {
storeId,
inventoryId,
inventoryType,
itemType: 'drink',
title: 'Drink Details',
detailsType: 'inventory',
})
}
loadStoreDrinks = (page) => {
......@@ -85,7 +72,23 @@ function enhanceDrinkList(ComposedComponent, drinkType, listLabel) {
props.page = page
}
this.lastSearchInventory = this.props.loadStoreDrinks(props)
this.lastSearchInventory = this.props.searchInventory(props)
}
clearSearchCache = () => {
this.props.clearPaginationCache()
}
handleOnRowPress = (inventoryId) => {
const { storeId, inventoryType } = this.props
Router.push(null, Router.routes.itemDetails, {
storeId,
inventoryId,
inventoryType,
itemType: 'drink',
title: 'Drink Details',
detailsType: 'inventory',
})
}
handleEndReached = () => {
......@@ -98,6 +101,16 @@ function enhanceDrinkList(ComposedComponent, drinkType, listLabel) {
return (
<ComposedComponent
{...this.props}
isTabLoaded={this.props.isTabLoaded}
onAddToCartPress={this.props.onAddToCartPress}
onRemoveFromCartPress={this.props.onRemoveFromCartPress}
isLoading={this.props.isLoading}
store={this.props.store}
searchQuery={this.props.searchQuery}
storeFilters={this.props.storeFilters}
itemsCount={this.props.itemsCount}
storeDrinks={this.props.storeDrinks}
isLoadingStoreCart={this.props.isLoadingStoreCart}
loadStoreDrinks={this.loadStoreDrinks}
clearSearchCache={this.clearSearchCache}
handleEndReached={this.handleEndReached}
......@@ -107,41 +120,68 @@ function enhanceDrinkList(ComposedComponent, drinkType, listLabel) {
}
}
const drinkKey = `drinks/${drinkType}`
const mapPropsToKey = props => `${props.storeId}/${drinkKey}`
const getStoreId = (state, props) => props.storeId
const selectorsWithStoreId = createSelector(
createSearchInventoryListSelector((state, props) => mapPropsToKey(props)),
createStoreSelector(getStoreId),
createStoreCartOrderSelector(getStoreId),
createStoreCartStatusSelector(getStoreId),
({ store }, order = {}, storeCart) => ({ store, order, storeCart })
createStoreCartSelector(getStoreId),
({ result, isLoading, nextPage }, { store }, storeCart) => ({
result,
isLoading,
nextPage,
store,
storeCart,
})
)
const drinkKey = `drinks/${drinkType}`
const mapPropsToKey = props => `${props.storeId}/${drinkKey}`
const mapStateToProps = createSelector(
const mapStateToProps = createSelector([
(state, props) => ({ state, props }),
selectorsWithStoreId,
createSearchInventoryListSelector((state, props) => mapPropsToKey(props)),
entitiesSelector,
({ state, props }, { store, order, storeCart }, { result, ...rest }, entities) => ({
...rest,
relationsSelector,
metaSelector,
], (
{ state, props },
{ result, isLoading, nextPage, store, storeCart },
entities,
relations,
meta
) => {
const combinedResult = result.map(({ inventory }) => {
const { id: inventoryId } = inventory
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 { inventory, isUpdatingInventory, orderProduct }
})
return {
isLoading,
nextPage,
store,
storeCart,
searchQuery: state.searchQueries[STORE_SEARCH_KEY],
storeFilters: state.storeFilters[mapPropsToKey(props)],
orderProducts: entities.orderProducts,
orderProductsInventory: state.relations.orderProductsInventory[order.id],
itemsCount: result.length,
storeFilters: state.storeFilters[`${props.storeId}/wines`],
itemsCount: combinedResult.length,
inventoryType: drinkType,
storeDrinks: {
[listLabel]: result,
[listLabel]: combinedResult,
},
})
)
isLoadingStoreCart: storeCart.isLoading,
}
})
const mapDispatchToProps = (dispatch, props) => ({
loadStoreDrinks: params => dispatch(
searchInventory: params => dispatch(
searchInventory({ ...params, drinkType, key: mapPropsToKey(props) })
),
clearSearchCache: () => dispatch(
clearPaginationCache: () => dispatch(
clearPaginationCache({ searchInventory: mapPropsToKey(props) })
),
})
......
......@@ -3,18 +3,14 @@ import PropTypes from 'prop-types'
import { Router } from 'tipsi-router'
import { isEqual } from 'lodash'
import { connect } from 'react-redux'
import { createSelector } from 'reselect'
import { userSelector, createStoreCartOrderSelector } from 'tipsi_api/selectors'
import {
loadStoreCart,
addInventoryToCart,
removeInventoryFromCart,
} from '../../actions/storeCarts'
import { createStoreCartStatusSelector } from '../../selectors'
import { userSelector } from 'tipsi_api/selectors'
import { analyticsLogEvent } from '../../actions'
import tabItems from '../../constants/storeTabItems'
import enhanceStoreSearchInput from './StoreSearchInput'
import { enhanceFiltersButton } from './filters/FiltersButton'
import { enhanceFilterModal } from './filters/FiltersModal'
import CartHOC from '../CartHOC'
import NotificationManager from '../../NotificationManager'
function enhanceStore(ComposedComponent, StoreSearchInput, FiltersModal, FiltersButton) {
const StoreSearchInputHOC = enhanceStoreSearchInput(StoreSearchInput)
......@@ -29,19 +25,21 @@ function enhanceStore(ComposedComponent, StoreSearchInput, FiltersModal, Filters
tabIndex: PropTypes.number,
// map state to props
user: PropTypes.object,
order: PropTypes.object,
isLoadingCart: PropTypes.bool.isRequired,
// map dispatch to props
loadStoreCart: PropTypes.func.isRequired,
analyticsLogEvent: PropTypes.func.isRequired,
// Cart HOC
orderCount: PropTypes.number.isRequired,
addInventoryToCart: PropTypes.func.isRequired,
removeInventoryFromCart: PropTypes.func.isRequired,
openCart: PropTypes.func.isRequired,
}
static defaultProps = {
// route props
searchQuery: '',
tabIndex: 0,
// map state to props
user: undefined,
order: undefined,
}
state = {
......@@ -53,19 +51,31 @@ function enhanceStore(ComposedComponent, StoreSearchInput, FiltersModal, Filters
Router.setTitle(this.props.title)
}
shouldComponentUpdate(nextProps, nextState) {
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState)
componentDidMount() {
if (this.props.user) {
NotificationManager.getInstance().setUser(this.props.user)
}
}
loadStoreCart = () => {
if (!this.props.isLoadingCart) {
this.props.loadStoreCart({ storeId: this.props.storeId })
componentWillReceiveProps(nextProps) {
if (!this.props.user && nextProps.user) {
NotificationManager.getInstance().setUser(this.props.user)
}
}
shouldComponentUpdate(nextProps, nextState) {
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState)
}
handleChangeTab = (tabIndex) => {
// Analytics
const { key: currentValue } = tabItems[this.state.tabIndex]
const { key: nextValue } = tabItems[tabIndex]
this.props.analyticsLogEvent('ui_storeTabView_changeTab_click', { currentValue, nextValue })
// updateRouteParams(this.props.navigator, { title: tabItems[tabIndex].title })
// Router.setTitle(tabItems[tabIndex].title)
this.setState({ tabIndex })
}
......@@ -77,58 +87,31 @@ function enhanceStore(ComposedComponent, StoreSearchInput, FiltersModal, Filters
this.setState({ filtersVisible: false })
)
handleCheckoutButtonOnPress = () => {
// const { order: { id: orderId }, navigation } = this.props
// const navigatorApp = navigation.getNavigator('app')
// navigatorApp.push('Cart', { orderId })
console.log('Show cart')
}
addInventoryToCart = (inventoryId) => {
if (!this.props.user) {
Router.showModal(null, Router.routes.login, {
config: { navigationBar: { visible: false } },
})
return
}
this.props.addInventoryToCart({ storeId: this.props.storeId, inventoryId })
}
removeInventoryFromCart = inventoryId => (
this.props.removeInventoryFromCart({ storeId: this.props.storeId, inventoryId })
)
render() {
const StoreTabView = Router.routes.storeTabView.component
return (
<ComposedComponent
{...this.props}
{...this.state}
storeId={this.props.storeId}
searchQuery={this.props.searchQuery}
tabIndex={this.state.tabIndex}
StoreSearchInput={StoreSearchInputHOC}
StoreTabView={StoreTabView}
FiltersButton={FiltersButtonHOC}
FiltersModal={FiltersModalHOC}
handleCheckoutButtonOnPress={this.handleCheckoutButtonOnPress}
FiltersButton={FiltersButtonHOC}
filtersVisible={this.state.filtersVisible}
orderCount={this.props.orderCount}
handleChangeTab={this.handleChangeTab}
addInventoryToCart={this.addInventoryToCart}
removeInventoryFromCart={this.removeInventoryFromCart}
handleShowFilters={this.handleShowFilters}
handleHideFilters={this.handleHideFilters}
handleAddToCartPress={this.props.addInventoryToCart}
handleRemoveFromCartPress={this.props.removeInventoryFromCart}
handleCheckoutButtonPress={this.props.openCart}
/>
)
}
}
const mapStateToProps = createSelector(
userSelector,
createStoreCartStatusSelector((state, props) => props.storeId),
createStoreCartOrderSelector((state, props) => props.storeId),
({ user }, { isLoadingCart }, order = {}) => ({ user, order, isLoadingCart })
)
const mapDispatchToProps = { loadStoreCart, addInventoryToCart, removeInventoryFromCart }
return connect(mapStateToProps, mapDispatchToProps)(Wrapper)
return connect(userSelector, { analyticsLogEvent })(CartHOC(Wrapper))
}
export default enhanceStore
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { createSelector } from 'reselect'
import { denormalize } from 'normalizr'
import { Router } from 'tipsi-router'
import { searchInventory, clearPaginationCache } from 'tipsi_api/actions'
import { wineListSelector } from '../../selectors'
import {
entitiesSelector,
relationsSelector,
metaSelector,
createSearchInventoryListSelector,
createStoreSelector,
createStoreCartSelector,
} from 'tipsi_api/selectors'
import { Schemas } from 'tipsi_api/middleware'
import { convertFiltersToQuery } from '../../reducers/storeFilters'
import { STORE_SEARCH_KEY } from '../../actions'
const getStoreId = (state, props) => props.storeId
const selectorsWithStoreId = createSelector(
createSearchInventoryListSelector((state, props) => `${props.storeId}/wines`),
createStoreSelector(getStoreId),
createStoreCartSelector(getStoreId),
({ result, isLoading, nextPage }, { store }, storeCart) => ({
result,
isLoading,
nextPage,
store,
storeCart,
})
)
const mapStateToProps = createSelector(
[
(state, props) => ({ state, props }),
selectorsWithStoreId,
entitiesSelector,
relationsSelector,
metaSelector,
], (
{ state, props },
{ result, isLoading, nextPage, store, storeCart },
entities,
relations,
meta
) => {
const combinedResult = result.map(({ inventory }) => {
const { id: inventoryId } = inventory
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 { inventory, isUpdatingInventory, orderProduct }
})
return {
isLoading,
nextPage,
store,
searchQuery: state.searchQueries[STORE_SEARCH_KEY],
storeFilters: state.storeFilters[`${props.storeId}/wines`],
itemsCount: combinedResult.length,
storeWines: {
'Store Wines': combinedResult,
},
isLoadingStoreCart: storeCart.isLoading,
}
})
const mapDispatchToProps = { searchInventory, clearPaginationCache }
function enhanceWineList(ComposedComponent) {
class Wrapper extends Component {
static propTypes = {
// props
storeId: PropTypes.number.isRequired,
searchInventory: PropTypes.func.isRequired,
clearPaginationCache: PropTypes.func.isRequired,
isTabLoaded: PropTypes.bool.isRequired,
onAddToCartPress: PropTypes.func.isRequired,
onRemoveFromCartPress: PropTypes.func.isRequired,
// map state to props
isLoading: PropTypes.bool.isRequired,
nextPage: PropTypes.number,
store: PropTypes.object,
searchQuery: PropTypes.string,
storeFilters: PropTypes.object,
itemsCount: PropTypes.number.isRequired,
storeWines: PropTypes.object.isRequired,
isLoadingStoreCart: PropTypes.bool.isRequired,
// map dispatch to props
searchInventory: PropTypes.func.isRequired,
clearPaginationCache: PropTypes.func.isRequired,
}
static defaultProps = {
// map state to props
nextPage: undefined,
store: {},
searchQuery: undefined,
storeFilters: undefined,
store: undefined,
orderProductsInventory: {},
orderProducts: {},
}
loadStoreWines = (page) => {
......@@ -87,6 +165,16 @@ function enhanceWineList(ComposedComponent) {
return (
<ComposedComponent
{...this.props}
isTabLoaded={this.props.isTabLoaded}
onAddToCartPress={this.props.onAddToCartPress}
onRemoveFromCartPress={this.props.onRemoveFromCartPress}
isLoading={this.props.isLoading}
store={this.props.store}
searchQuery={this.props.searchQuery}
storeFilters={this.props.storeFilters}
itemsCount={this.props.itemsCount}
storeWines={this.props.storeWines}
isLoadingStoreCart={this.props.isLoadingStoreCart}
loadStoreWines={this.loadStoreWines}
clearSearchCache={this.clearSearchCache}
handleEndReached={this.handleEndReached}
......@@ -95,8 +183,8 @@ function enhanceWineList(ComposedComponent) {
)
}
}
const mapDispatchToProps = { searchInventory, clearPaginationCache }
return connect(wineListSelector, mapDispatchToProps)(Wrapper)
return connect(mapStateToProps, mapDispatchToProps)(Wrapper)
}
export default enhanceWineList
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