add food item name modal

This commit is contained in:
Bart Akeley 2017-05-13 22:33:56 -05:00
parent 27ad3d5769
commit 38035c6f5c
5 changed files with 214 additions and 19 deletions

View file

@ -12,6 +12,7 @@ import List from './pages/List';
import FoodItemDetail from './pages/FoodItemDetail';
import PlaceDetail from './pages/PlaceDetail';
import Drawer from 'react-native-drawer';
import CreateFoodItem from './pages/CreateFoodItem';
setObservableConfig(rxjsconfig);
@ -56,6 +57,7 @@ export default class App extends Component {
<Route path="/list/:type" component={List} />
<Route path="/foodItem/:id" component={FoodItemDetail} />
<Route path="/place/:id" component={PlaceDetail} />
<Route path="/createFoodItem" component={CreateFoodItem} />
</View>
</Drawer>
</ThemeProvider>

View file

@ -0,0 +1,39 @@
// @flow
import React, { Component } from 'react';
import { View } from 'react-native';
import { Seq } from 'immutable';
import FoodItemRecord, { type FoodItem } from '../records/FoodItemRecord';
import { pure, compose } from 'recompose';
import { memoize } from 'ramda';
import { withFoodItemsAsSeq } from '../enhancers/foodItemEnhancers';
const matchString = memoize((match = '', str = '') => str.toLowerCase().includes(match.toLowerCase()));
const textFilter = (filter?: string = '', foodItemsSeq: Seq<FoodItem>) => {
return foodItemsSeq.filter((foodItem: typeof FoodItemRecord) => {
return matchString(filter, foodItem.name);
});
};
class FoodItemList extends Component {
static displayName = 'FoodItemList';
props: {
filter: string,
foodItemsSeq: Seq<FoodItem>,
renderFoodItem: (foodItem: typeof FoodItemRecord) => Component,
};
render() {
const { filter, foodItemsSeq, renderFoodItem } = this.props;
return (
<View>
{textFilter(filter, foodItemsSeq).map(renderFoodItem)}
</View>
);
}
}
const enhance = compose(pure, withFoodItemsAsSeq);
export default enhance(FoodItemList);

View file

@ -0,0 +1,70 @@
// @flow
import React, { Component } from 'react';
import { View, TextInput, TouchableOpacity } from 'react-native';
import Modal from '../components/Modal';
import { Divider, Icon } from 'react-native-material-ui';
import FoodItemList from '../components/FoodItemList';
import FoodItemRecord from '../records/FoodItemRecord';
import { withPlaceForFoodItem } from '../enhancers/placeEnhancers';
import { NameAndPlace } from '../components/ItemTile';
import { type Place } from '../records/PlaceRecord';
const FoodItemWithPlace = withPlaceForFoodItem(
({ foodItem, place }: { foodItem: typeof FoodItemRecord, place: Place }) => {
return <NameAndPlace name={foodItem.name} place={place.name} />;
}
);
class NameModal extends Component {
static displayName = 'NameModal';
props: {
isVisible: boolean,
onClose: () => void,
};
state: {
text: string,
};
state = {
text: '',
};
setText = (text: string) => {
this.setState({ text });
};
renderFoodItem = (foodItem: typeof FoodItemRecord) => {
return (
<TouchableOpacity key={foodItem.id} onPress={() => this.setText(foodItem.name)}>
<FoodItemWithPlace foodItem={foodItem} />
<Divider />
</TouchableOpacity>
);
};
render() {
const { isVisible, onClose } = this.props;
return (
<Modal isVisible={isVisible}>
<View style={{ flexDirection: 'row' }}>
<Icon name="search" style={{ marginTop: 10 }} />
<TextInput
style={{ flex: 1, height: 40 }}
onChangeText={this.setText}
value={this.state.text}
placeholder="search"
/>
<TouchableOpacity onPress={onClose}>
<Icon name="close" style={{ marginTop: 10 }} />
</TouchableOpacity>
</View>
<Divider />
<FoodItemList filter={this.state.text} renderFoodItem={this.renderFoodItem} />
</Modal>
);
}
}
export default NameModal;

View file

@ -0,0 +1,67 @@
// @flow
import React, { Component } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import theme from '../ui-theme';
import { Divider } from 'react-native-material-ui';
import FoodItemRecord from '../records/FoodItemRecord';
import NameModal from '../modals/FoodItemNameModal';
const fieldStyle = {
paddingTop: 10,
paddingBottom: 10,
};
const fieldNameStyle = {
fontSize: 18,
};
class CreateFoodItem extends Component {
static displayName = 'CreateFoodItem';
state: {
foodItem: typeof FoodItemRecord,
modals: {
name: boolean,
},
};
state = {
foodItem: new FoodItemRecord(),
modalsVisible: {
name: false,
},
};
setName = (name: string) => {
this.setState(({ foodItem }) => foodItem.set('name', name));
};
toggleModal = (modalName: string) => () => {
this.setState(state => {
return {
...state,
modalsVisible: {
...state.modalsVisible,
[modalName]: !state.modalsVisible[modalName],
},
};
});
};
render() {
const { foodItem, modalsVisible } = this.state;
return (
<View style={{ ...theme.page.container, backgroundColor: 'white', padding: 10 }}>
<TouchableOpacity style={fieldStyle} onPress={this.toggleModal('name')}>
<Text style={fieldNameStyle}>
{foodItem.name || 'Name'}
</Text>
<Divider />
</TouchableOpacity>
<NameModal isVisible={modalsVisible.name} onClose={this.toggleModal('name')} />
</View>
);
}
}
export default CreateFoodItem;

View file

@ -1,5 +1,5 @@
// @flow
import React, { Component } from 'react';
import React, { Component, PropTypes } from 'react';
import { View, ScrollView } from 'react-native';
import theme from '../ui-theme';
import { withFoodItemsAsSeq } from '../enhancers/foodItemEnhancers';
@ -7,30 +7,47 @@ import { pure, compose } from 'recompose';
import { FoodItemTile } from '../components/ItemTile';
import { type FoodItem } from '../records/FoodItemRecord';
import { type Seq } from 'immutable';
import { ActionButton } from 'react-native-material-ui';
import { routeWithTitle } from '../helpers/RouteHelpers';
const { shape, func } = PropTypes;
const enhance = compose(pure, withFoodItemsAsSeq);
const FoodItemList = enhance(({ foodItemsSeq }: { foodItemsSeq: Seq<FoodItem> }) => {
return (
<View>
{foodItemsSeq.map((foodItem: FoodItem, index: number) => {
return <FoodItemTile key={index} foodItem={foodItem} />;
})}
</View>
);
export const FoodItemList = enhance(({ foodItemsSeq }: { foodItemsSeq: Seq<FoodItem> }) => {
return (
<View>
{foodItemsSeq.map((foodItem: FoodItem, index: number) => {
return <FoodItemTile key={index} foodItem={foodItem} />;
})}
</View>
);
});
class Food extends Component {
static displayName = 'Food';
static displayName = 'Food';
static contextTypes = {
router: shape({
history: shape({
push: func.isRequired,
}).isRequired,
}).isRequired,
};
render() {
return (
<View style={theme.page.container}>
<ScrollView>
<FoodItemList />
</ScrollView>
</View>
);
}
addFoodItem = () => {
const newRoute = routeWithTitle('/createFoodItem', 'Add a Food Item');
this.context.router.history.push(newRoute);
};
render() {
return (
<View style={theme.page.container}>
<ScrollView>
<FoodItemList />
</ScrollView>
<ActionButton icon="add" onPress={this.addFoodItem} />
</View>
);
}
}
export default Food;