This commit is contained in:
Erick Clark 2018-09-09 12:33:53 -05:00
commit 522f74e3c5
4 changed files with 90 additions and 43 deletions

View file

@ -6,13 +6,12 @@ import { withReplaceRoute } from '../enhancers/routeEnhancers';
import { compose, onlyUpdateForKeys, withHandlers } from 'recompose';
import { routeWithTitle } from '../helpers/RouteHelpers';
const FoodItemSaveBtn = ({
saveFoodItem,
loading,
}: {
saveFoodItem?: Function,
type Props = {
loading: boolean,
}) => {
doSave: Function,
};
const FoodItemSaveBtn = ({ loading, doSave }: Props) => {
const textStyle = {
color: 'white',
marginRight: 20,
@ -21,7 +20,7 @@ const FoodItemSaveBtn = ({
};
return (
<TouchableOpacity onPress={loading ? null : saveFoodItem}>
<TouchableOpacity onPress={loading ? null : doSave}>
<Text style={textStyle}>SAVE</Text>
</TouchableOpacity>
);
@ -31,7 +30,7 @@ export default compose(
withCreateFoodItemState,
withReplaceRoute,
withHandlers({
saveFoodItem: ({ saveFoodItem, setLoading, setError, replaceRoute }) => async () => {
doSave: ({ saveFoodItem, setLoading, setError, replaceRoute }) => async () => {
try {
setLoading(true);
const { id, name } = await saveFoodItem();

View file

@ -1,11 +1,33 @@
// @flow
import withProps from 'recompose/withProps';
import compose from 'recompose/compose';
import { path } from 'ramda';
import mapPropsStream from 'recompose/mapPropsStream';
import FoodItems$ from '../streams/FoodItemsStream';
import typeof FoodItemRecord from '../records/FoodItemRecord';
import { Map } from 'immutable';
import { Map, Set } from 'immutable';
import { pipe, path, toLower, equals } from 'ramda';
type FindPredicate<A> = (left: A) => (right: A) => Boolean;
const getName: (f: FoodItemRecord) => String = pipe(
path(['name']),
toLower
);
const matchesName: FindPredicate<FoodItemRecord> = left => right => {
return equals(getName(left), getName(right));
};
const addIfNotExisting = (predicate: FindPredicate<FoodItemRecord>) => (
set: Set<FoodItemRecord>,
item: FoodItemRecord
) => {
return !set.find(predicate(item)) ? set.add(item) : set;
};
const intoSet = reducer => items => {
return items ? items.reduce(reducer, new Set()) : new Set();
};
export const withFoodItems = mapPropsStream(props$ =>
props$.combineLatest(FoodItems$, (props, foodItems) => {
@ -57,3 +79,12 @@ export const withFoodItemsGroupedByPlace = compose(
};
})
);
export const withUniqueFoodItems = compose(
withFoodItemsAsSeq,
withProps(({ foodItemsSeq }) => {
return {
foodItemsSeq: intoSet(addIfNotExisting(matchesName))(foodItemsSeq),
};
})
);

View file

@ -6,30 +6,37 @@ import FoodItemList from '../components/FoodItemList';
import FoodItemRecord from '../records/FoodItemRecord';
import { StrongText } from '../components/ItemTile';
import { Toolbar } from 'react-native-material-ui';
import FilterRecord from '../records/FilterRecord';
import { compose, pure } from 'recompose';
import { withUniqueFoodItems } from '../enhancers/foodItemEnhancers';
import { Set } from 'immutable';
type Props = {
onClose: () => void,
onUpdate: (name: string) => void,
foodItemsSeq: ?Set<FoodItemRecord>,
};
class NameModal extends Component {
static displayName = 'NameModal';
props: {
onClose: () => void,
onUpdate: (name: string) => void,
};
props: Props;
state: {
text: string,
filter: FilterRecord,
};
state = {
text: '',
filter: new FilterRecord(),
};
save = () => {
this.props.onUpdate(this.state.text);
this.props.onUpdate(this.state.filter.search);
this.props.onClose();
};
setText = (text: string) => {
this.setState({ text });
this.setState(({ filter }) => ({ filter: filter.set('search', text) }));
};
updateAndClose = (text: string) => {
@ -37,15 +44,9 @@ class NameModal extends Component {
this.props.onClose();
};
renderFoodItem = (foodItem: typeof FoodItemRecord) => (
<TouchableOpacity key={foodItem.id} onPress={() => this.updateAndClose(foodItem.name)}>
<StrongText style={{ paddingTop: 20, paddingBottom: 20 }}>{foodItem.name}</StrongText>
</TouchableOpacity>
);
render() {
const { onClose } = this.props;
const { text } = this.state;
const { onClose, foodItemsSeq } = this.props;
const { filter } = this.state;
return (
<View
style={{
@ -71,7 +72,7 @@ class NameModal extends Component {
},
}}
/>
{!!text && (
{!!filter.search && (
<TextButton
text="Not here, it's a new product"
onPress={this.save}
@ -79,11 +80,24 @@ class NameModal extends Component {
/>
)}
<ScrollView style={{ paddingLeft: 78 }}>
<FoodItemList filter={text} limit={10} renderFoodItem={this.renderFoodItem} />
<FoodItemList filter={filter} limit={10} foodItemsSeq={foodItemsSeq}>
{(foodItem: FoodItemRecord) => (
<TouchableOpacity
key={foodItem.id}
onPress={() => this.updateAndClose(foodItem.name)}>
<StrongText style={{ paddingTop: 20, paddingBottom: 20 }}>
{foodItem.name}
</StrongText>
</TouchableOpacity>
)}
</FoodItemList>
</ScrollView>
</View>
);
}
}
export default NameModal;
export default compose(
pure,
withUniqueFoodItems
)(NameModal);

View file

@ -24,6 +24,23 @@ import { withCreateFoodItemState } from '../enhancers/createFoodItemEnhancers';
import { withPlaceForFoodItem, withPlaceId, withPlaceActions } from '../enhancers/placeEnhancers';
import Spinner from 'react-native-loading-spinner-overlay';
import { openImagePicker } from '../helpers/ImagePickerHelpers';
import { IndexedSeq } from 'immutable';
type Props = {
foodItem: typeof FoodItemRecord,
setPropOfFoodItem: Function,
toggleNameModal: Function,
setFoodItem: Function,
setModalsVisible: Function,
place: ?PlaceRecord,
updatePlace: (place: GooglePlaceObject) => void,
addImage: (uri: string) => void,
setImagePreview: (index?: number) => void,
loading: boolean,
setLoading: (arg: boolean) => void,
emitPlace: (place: Object) => void,
withFoodItemsAsSeq: IndexedSeq<FoodItemRecord>,
};
type GooglePlaceObject = {
placeID: string,
@ -54,20 +71,6 @@ const openPlaceModal = (onChoosePlace: (place: GooglePlaceObject) => void) => ()
RNGooglePlaces.openAutocompleteModal({ type: 'establishment' }).then(onChoosePlace);
};
type Props = {
foodItem: typeof FoodItemRecord,
setPropOfFoodItem: Function,
toggleNameModal: Function,
setFoodItem: Function,
setModalsVisible: Function,
place: ?PlaceRecord,
updatePlace: (place: GooglePlaceObject) => void,
addImage: (uri: string) => void,
setImagePreview: (index?: number) => void,
loading: boolean,
setLoading: (arg: boolean) => void,
emitPlace: (place: Object) => void,
};
const CreateFoodItem = (props: Props) => {
const {
foodItem,