show message when no food items found

This commit is contained in:
Bart Akeley 2018-08-25 10:12:52 -05:00
parent a2206a00bf
commit a7f9a5bae9
5 changed files with 80 additions and 47 deletions

View file

@ -15,7 +15,7 @@ type homomorph<T> = T => T;
type Props = {
filter: FilterRecord,
foodItemsSeq: SetSeq<FoodItemRecord>,
renderFoodItem: (foodItem: typeof FoodItemRecord) => Component<*, *, *>,
children: (foodItem: FoodItemRecord) => Component<*, *, *>,
};
const sortByDistance = (foodItemsSeq: SetSeq<FoodItemRecord>): SetSeq<FoodItemRecord> => {
@ -48,7 +48,7 @@ const intoArray = (foodItemsSeq: SetSeq<FoodItemRecord>): Array<FoodItemRecord>
foodItemsSeq ? foodItemsSeq.toArray() : [];
const FoodItemList = (props: Props) => {
const { filter, foodItemsSeq, renderFoodItem } = props;
const { filter, foodItemsSeq, children } = props;
if (!foodItemsSeq) {
return null;
@ -59,7 +59,7 @@ const FoodItemList = (props: Props) => {
intoArray
)(foodItemsSeq);
return <View style={{ flexShrink: 2 }}>{items.map(renderFoodItem)}</View>;
return <View style={{ flexShrink: 2 }}>{items.map(children)}</View>;
};
export default compose(

View file

@ -0,0 +1,23 @@
import React from 'react';
import { View } from 'react-native';
const FullScreenMessage = ({ children }: { children?: any }) => {
return (
<View
style={{
flexDirection: 'column',
flex: 1,
}}>
<View
style={{
height: '50%',
alignItems: 'center',
justifyContent: 'center',
}}>
{children}
</View>
</View>
);
};
export default FullScreenMessage;

View file

@ -1,6 +1,6 @@
// @flow
import mapPropsStream from 'recompose/mapPropsStream';
import Filter$, { emitter } from '../streams/FilterStream';
import Filter$, { emitter, initialFilter } from '../streams/FilterStream';
export const withFilter = mapPropsStream(props$ => {
return props$.combineLatest(Filter$, (props, filter) => {
@ -8,6 +8,7 @@ export const withFilter = mapPropsStream(props$ => {
...props,
filter,
setFilter: emitter,
isFilterDirty: initialFilter !== filter,
};
});
});

View file

@ -1,6 +1,6 @@
// @flow
import React, { Component } from 'react';
import { View, ScrollView, RefreshControl } from 'react-native';
import React from 'react';
import { View, Text, ScrollView, RefreshControl } from 'react-native';
import FoodItemTile from '../components/FoodItemTile';
import FoodItemList from '../components/FoodItemList';
import typeof FoodItemRecord from '../records/FoodItemRecord';
@ -8,59 +8,66 @@ import FilterModal from '../modals/FilterModal';
import { withFoodItemsAsSeq } from '../enhancers/foodItemEnhancers';
import { type SetSeq } from 'immutable';
import { compose, pure, withState, withHandlers } from 'recompose';
import { type RoutingContextFlowTypes } from '../routes';
import ActionsButton from '../components/ActionsButton';
import { withFilter } from '../enhancers/filterEnhancers';
import { withRouterContext } from '../enhancers/routeEnhancers';
import FullScreenMessage from '../components/FullScreenMessage';
const renderFoodItem = (foodItem: FoodItemRecord) => (
<FoodItemTile key={foodItem.id} foodItem={foodItem} />
);
type Props = {
isFilterModalOpen: boolean,
toggleFilterModal: () => void,
foodItemsSeq: SetSeq<FoodItemRecord>,
isRefreshing: boolean,
onRefresh: () => Promise<any>,
onPulldown: () => {},
isFilterDirty: boolean,
};
class FoodList extends Component {
static displayName = 'FoodList';
const FoodList = (props: Props) => {
const {
isFilterModalOpen,
foodItemsSeq,
isRefreshing,
onPulldown,
toggleFilterModal,
isFilterDirty,
} = props;
context: RoutingContextFlowTypes;
const refreshing = isRefreshing || !foodItemsSeq;
const showNoResults = !isRefreshing && isFilterDirty && foodItemsSeq && !foodItemsSeq.size;
props: {
isFilterModalOpen: boolean,
toggleFilterModal: () => void,
foodItemsSeq: SetSeq<FoodItemRecord>,
isRefreshing: boolean,
onRefresh: () => Promise<any>,
onPulldown: () => {},
};
render() {
const {
isFilterModalOpen,
foodItemsSeq,
isRefreshing,
onPulldown,
toggleFilterModal,
} = this.props;
const refreshing = isRefreshing || !foodItemsSeq;
return (
<View style={{ flex: 1 }}>
return (
<View style={{ flex: 1 }}>
{showNoResults && (
<FullScreenMessage>
<Text style={{ fontSize: 16 }}>No food matched your search.</Text>
<Text style={{ fontSize: 16 }}>Check your filters and try again</Text>
</FullScreenMessage>
)}
{!showNoResults && (
<ScrollView
style={{ flex: 1 }}
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={onPulldown} />}>
<FoodItemList foodItemsSeq={foodItemsSeq} renderFoodItem={renderFoodItem} />
<FoodItemList foodItemsSeq={foodItemsSeq}>
{(foodItem: FoodItemRecord) => <FoodItemTile key={foodItem.id} foodItem={foodItem} />}
</FoodItemList>
</ScrollView>
<FilterModal isVisible={isFilterModalOpen} onClose={toggleFilterModal} />
<ActionsButton
toggleFilterModal={toggleFilterModal}
actions={['add-food', 'filter-modal', 'view-mode']}
icon="add"
/>
</View>
);
}
}
)}
<FilterModal isVisible={isFilterModalOpen} onClose={toggleFilterModal} />
<ActionsButton
toggleFilterModal={toggleFilterModal}
actions={['add-food', 'filter-modal', 'view-mode']}
icon="add"
/>
</View>
);
};
export default compose(
pure,
withRouterContext,
withFoodItemsAsSeq,
withFilter,
withState('isRefreshing', 'setRefreshing', false),
withHandlers({
onPulldown: ({ setRefreshing, onRefresh }) => async () => {

View file

@ -8,6 +8,8 @@ export function emitter(val: typeof FilterRecord) {
multicaster.next(val);
}
emitter(new FilterRecord());
export const initialFilter = new FilterRecord();
emitter(initialFilter);
export default multicaster;