Skip to content

Commit d3c6541

Browse files
committed
rework lots of the menus
1 parent 236fc08 commit d3c6541

File tree

3 files changed

+243
-222
lines changed

3 files changed

+243
-222
lines changed
Lines changed: 109 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// @flow
22

33
import React from 'react'
4-
import {View, StyleSheet, SectionList} from 'react-native'
4+
import {StyleSheet, SectionList} from 'react-native'
55
import * as c from '../../components/colors'
66
import {connect} from 'react-redux'
77
import {updateMenuFilters} from '../../../flux'
@@ -12,34 +12,34 @@ import type {
1212
MasterCorIconMapType,
1313
ProcessedMealType,
1414
MenuItemContainerType,
15+
StationMenuType,
1516
} from '../types'
1617
import size from 'lodash/size'
1718
import values from 'lodash/values'
1819
import {ListSeparator, ListSectionHeader} from '../../components/list'
1920
import type {FilterType} from '../../components/filter'
2021
import {applyFiltersToItem} from '../../components/filter'
2122
import {NoticeView} from '../../components/notice'
22-
import {FilterMenuToolbar} from './filter-menu-toolbar'
23+
import {FilterMenuToolbar as FilterToolbar} from './filter-menu-toolbar'
2324
import {FoodItemRow} from './food-item-row'
2425
import {chooseMeal} from '../lib/choose-meal'
2526
import {buildFilters} from '../lib/build-filters'
2627

27-
type FancyMenuPropsType = TopLevelViewPropsType & {
28+
type Props = TopLevelViewPropsType & {
2829
applyFilters: (filters: FilterType[], item: MenuItemType) => boolean,
29-
now: momentT,
30-
name: string,
30+
cafeMessage?: ?string,
3131
filters: FilterType[],
3232
foodItems: MenuItemContainerType,
3333
meals: ProcessedMealType[],
3434
menuCorIcons: MasterCorIconMapType,
35+
name: string,
36+
now: momentT,
3537
onFiltersChange: (f: FilterType[]) => any,
38+
onRefresh?: ?() => any,
39+
refreshing?: ?boolean,
3640
}
3741

38-
const leftSideSpacing = 28
3942
const styles = StyleSheet.create({
40-
container: {
41-
flex: 1,
42-
},
4343
inner: {
4444
backgroundColor: c.white,
4545
},
@@ -48,31 +48,40 @@ const styles = StyleSheet.create({
4848
},
4949
})
5050

51-
const CustomSeparator = () => (
52-
<ListSeparator spacing={{left: leftSideSpacing}} />
53-
)
51+
class FancyMenu extends React.PureComponent<any, Props, void> {
52+
static leftSideSpacing = 28
53+
static separator = () => (
54+
<ListSeparator spacing={{left: FancyMenu.leftSideSpacing}} />
55+
)
5456

55-
class FancyMenuView extends React.PureComponent {
5657
static defaultProps = {
5758
applyFilters: applyFiltersToItem,
5859
}
5960

60-
props: FancyMenuPropsType
61-
6261
componentWillMount() {
63-
let {foodItems, menuCorIcons, filters, meals, now} = this.props
62+
this.updateFilters(this.props)
63+
}
64+
65+
componentWillReceiveProps(nextProps: Props) {
66+
this.updateFilters(nextProps)
67+
}
68+
69+
updateFilters = (props: Props) => {
70+
const {foodItems, menuCorIcons, filters, meals, now} = props
6471

6572
// prevent ourselves from overwriting the filters from redux on mount
6673
if (filters.length) {
6774
return
6875
}
6976

70-
const foodItemsArray = values(foodItems)
71-
this.props.onFiltersChange(
72-
buildFilters(foodItemsArray, menuCorIcons, meals, now),
73-
)
77+
const newFilters = buildFilters(values(foodItems), menuCorIcons, meals, now)
78+
props.onFiltersChange(newFilters)
7479
}
7580

81+
areSpecialsFiltered = filters => Boolean(filters.find(this.isSpecialsFilter))
82+
isSpecialsFilter = f =>
83+
f.enabled && f.type === 'toggle' && f.spec.label === 'Only Show Specials'
84+
7685
openFilterView = () => {
7786
this.props.navigation.navigate('FilterView', {
7887
title: `Filter ${this.props.name} Menu`,
@@ -81,120 +90,110 @@ class FancyMenuView extends React.PureComponent {
8190
})
8291
}
8392

93+
groupMenuData = (props: Props, stations: Array<StationMenuType>) => {
94+
const {applyFilters, filters, foodItems} = props
95+
96+
const derefrenceMenuItems = menu =>
97+
menu.items
98+
// Dereference each menu item
99+
.map(id => foodItems[id])
100+
// Ensure that the referenced menu items exist,
101+
// and apply the selected filters to the items in the menu
102+
.filter(item => item && applyFilters(filters, item))
103+
104+
const menusWithItems = stations
105+
// We're grouping the menu items in a [label, Array<items>] tuple.
106+
.map(menu => [menu.label, derefrenceMenuItems(menu)])
107+
// We only want to show stations with at least one item in them
108+
.filter(([_, items]) => items.length)
109+
// We need to map the tuples into objects for SectionList
110+
.map(([title, data]) => ({title, data}))
111+
112+
return menusWithItems
113+
}
114+
84115
renderSectionHeader = ({section: {title}}: any) => {
85116
const {filters, now, meals} = this.props
86117
const {stations} = chooseMeal(meals, filters, now)
87118
const menu = stations.find(m => m.label === title)
88-
const note = menu ? menu.note : ''
89119

90120
return (
91121
<ListSectionHeader
92122
title={title}
93-
subtitle={note}
94-
spacing={{left: leftSideSpacing}}
123+
subtitle={menu ? menu.note : ''}
124+
spacing={{left: FancyMenu.leftSideSpacing}}
95125
/>
96126
)
97127
}
98128

99-
keyExtractor = (item, index) => index.toString()
100-
101-
render() {
102-
const {applyFilters, filters, foodItems, now, meals} = this.props
103-
104-
const {label: mealName, stations: stationMenus} = chooseMeal(
105-
meals,
106-
filters,
107-
now,
129+
renderItem = ({item}: {item: MenuItemType}) => {
130+
const specialsFilterEnabled = this.areSpecialsFiltered(this.props.filters)
131+
return (
132+
<FoodItemRow
133+
data={item}
134+
corIcons={this.props.menuCorIcons}
135+
badgeSpecials={!specialsFilterEnabled}
136+
spacing={{left: FancyMenu.leftSideSpacing}}
137+
/>
108138
)
139+
}
109140

110-
const filteredByMenu = stationMenus
111-
.map(menu => [
112-
// we're grouping the menu items in a [label, Array<items>] tuple.
113-
menu.label,
114-
// dereference each menu item
115-
menu.items
116-
.map(id => foodItems[id])
117-
// ensure that the referenced menu items exist
118-
// and apply the selected filters to the items in the menu
119-
.filter(item => item && applyFilters(filters, item)),
120-
])
121-
// we only want to show stations with at least one item in them
122-
.filter(([_, items]) => items.length)
141+
keyExtractor = (item, index) => index.toString()
123142

124-
// map the tuples into objects for SectionList
125-
const grouped = filteredByMenu.map(([title, data]) => ({title, data}))
143+
render() {
144+
const {filters, now, meals, cafeMessage} = this.props
126145

146+
const {label: mealName, stations} = chooseMeal(meals, filters, now)
127147
const anyFiltersEnabled = filters.some(f => f.enabled)
128-
const specialsFilterEnabled = Boolean(
129-
filters.find(
130-
f =>
131-
f.enabled &&
132-
f.type === 'toggle' &&
133-
f.spec.label === 'Only Show Specials',
134-
),
135-
)
148+
const specialsFilterEnabled = this.areSpecialsFiltered(filters)
149+
const groupedMenuData = this.groupMenuData(this.props, stations)
150+
151+
let message = 'No items to show.'
152+
if (cafeMessage) {
153+
message = cafeMessage
154+
} else if (specialsFilterEnabled && stations.length === 0) {
155+
message =
156+
'No items to show. There may be no specials today. Try changing the filters.'
157+
} else if (anyFiltersEnabled && !size(groupedMenuData)) {
158+
message = 'No items to show. Try changing the filters.'
159+
}
160+
161+
const messageView = <NoticeView style={styles.message} text={message} />
136162

137-
let messageView = (
138-
<NoticeView style={styles.message} text="No items to show." />
163+
const header = (
164+
<FilterToolbar
165+
date={now}
166+
title={mealName}
167+
filters={filters}
168+
onPress={this.openFilterView}
169+
/>
139170
)
140-
if (specialsFilterEnabled && stationMenus.length === 0) {
141-
messageView = (
142-
<NoticeView
143-
style={styles.message}
144-
text="No items to show. There may be no specials today. Try changing the filters."
145-
/>
146-
)
147-
} else if (anyFiltersEnabled && !size(grouped)) {
148-
messageView = (
149-
<NoticeView
150-
style={styles.message}
151-
text="No items to show. Try changing the filters."
152-
/>
153-
)
154-
}
155171

156172
return (
157-
<View style={styles.container}>
158-
<FilterMenuToolbar
159-
date={now}
160-
title={mealName}
161-
filters={filters}
162-
onPress={this.openFilterView}
163-
/>
164-
<SectionList
165-
ItemSeparatorComponent={CustomSeparator}
166-
ListEmptyComponent={messageView}
167-
keyExtractor={this.keyExtractor}
168-
style={styles.inner}
169-
sections={grouped}
170-
renderSectionHeader={this.renderSectionHeader}
171-
renderItem={({item}: {item: MenuItemType}) => (
172-
<FoodItemRow
173-
data={item}
174-
corIcons={this.props.menuCorIcons}
175-
badgeSpecials={!specialsFilterEnabled}
176-
spacing={{left: leftSideSpacing}}
177-
/>
178-
)}
179-
/>
180-
</View>
173+
<SectionList
174+
ItemSeparatorComponent={FancyMenu.separator}
175+
ListEmptyComponent={messageView}
176+
ListHeaderComponent={header}
177+
data={filters}
178+
keyExtractor={this.keyExtractor}
179+
onRefresh={this.props.onRefresh}
180+
refreshing={this.props.refreshing}
181+
renderItem={this.renderItem}
182+
renderSectionHeader={this.renderSectionHeader}
183+
sections={(groupedMenuData: any)}
184+
style={styles.inner}
185+
/>
181186
)
182187
}
183188
}
184189

185-
function mapStateToProps(state, actualProps: FancyMenuPropsType) {
186-
return {
187-
filters: state.menus[actualProps.name] || [],
188-
}
189-
}
190+
const mapState = (state, actualProps: Props) => ({
191+
filters: state.menus[actualProps.name] || [],
192+
})
190193

191-
function mapDispatchToProps(dispatch, actualProps: FancyMenuPropsType) {
192-
return {
193-
onFiltersChange: (filters: FilterType[]) =>
194-
dispatch(updateMenuFilters(actualProps.name, filters)),
195-
}
196-
}
194+
const mapDispatch = (dispatch, actualProps: Props) => ({
195+
onFiltersChange: (filters: FilterType[]) =>
196+
dispatch(updateMenuFilters(actualProps.name, filters)),
197+
})
197198

198-
export const FancyMenu = connect(mapStateToProps, mapDispatchToProps)(
199-
FancyMenuView,
200-
)
199+
export const ConnectedFancyMenu = connect(mapState, mapDispatch)(FancyMenu)

0 commit comments

Comments
 (0)