mirror of
https://gitlab.com/wheres-the-tp/ui-mobile.git
synced 2026-01-25 07:54:57 -06:00
Merge branch 'dedupe-name-suggestions' into 'master'
dedupe fooditem name suggestions See merge request aretherecookies/ui-mobile!1
This commit is contained in:
commit
1827b35403
4 changed files with 90 additions and 43 deletions
|
|
@ -6,13 +6,12 @@ import { withReplaceRoute } from '../enhancers/routeEnhancers';
|
||||||
import { compose, onlyUpdateForKeys, withHandlers } from 'recompose';
|
import { compose, onlyUpdateForKeys, withHandlers } from 'recompose';
|
||||||
import { routeWithTitle } from '../helpers/RouteHelpers';
|
import { routeWithTitle } from '../helpers/RouteHelpers';
|
||||||
|
|
||||||
const FoodItemSaveBtn = ({
|
type Props = {
|
||||||
saveFoodItem,
|
|
||||||
loading,
|
|
||||||
}: {
|
|
||||||
saveFoodItem?: Function,
|
|
||||||
loading: boolean,
|
loading: boolean,
|
||||||
}) => {
|
doSave: Function,
|
||||||
|
};
|
||||||
|
|
||||||
|
const FoodItemSaveBtn = ({ loading, doSave }: Props) => {
|
||||||
const textStyle = {
|
const textStyle = {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
marginRight: 20,
|
marginRight: 20,
|
||||||
|
|
@ -21,7 +20,7 @@ const FoodItemSaveBtn = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={loading ? null : saveFoodItem}>
|
<TouchableOpacity onPress={loading ? null : doSave}>
|
||||||
<Text style={textStyle}>SAVE</Text>
|
<Text style={textStyle}>SAVE</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
|
|
@ -31,7 +30,7 @@ export default compose(
|
||||||
withCreateFoodItemState,
|
withCreateFoodItemState,
|
||||||
withReplaceRoute,
|
withReplaceRoute,
|
||||||
withHandlers({
|
withHandlers({
|
||||||
saveFoodItem: ({ saveFoodItem, setLoading, setError, replaceRoute }) => async () => {
|
doSave: ({ saveFoodItem, setLoading, setError, replaceRoute }) => async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const { id, name } = await saveFoodItem();
|
const { id, name } = await saveFoodItem();
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,33 @@
|
||||||
// @flow
|
// @flow
|
||||||
import withProps from 'recompose/withProps';
|
import withProps from 'recompose/withProps';
|
||||||
import compose from 'recompose/compose';
|
import compose from 'recompose/compose';
|
||||||
import { path } from 'ramda';
|
|
||||||
import mapPropsStream from 'recompose/mapPropsStream';
|
import mapPropsStream from 'recompose/mapPropsStream';
|
||||||
import FoodItems$ from '../streams/FoodItemsStream';
|
import FoodItems$ from '../streams/FoodItemsStream';
|
||||||
import typeof FoodItemRecord from '../records/FoodItemRecord';
|
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$ =>
|
export const withFoodItems = mapPropsStream(props$ =>
|
||||||
props$.combineLatest(FoodItems$, (props, foodItems) => {
|
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),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
|
||||||
|
|
@ -6,30 +6,37 @@ import FoodItemList from '../components/FoodItemList';
|
||||||
import FoodItemRecord from '../records/FoodItemRecord';
|
import FoodItemRecord from '../records/FoodItemRecord';
|
||||||
import { StrongText } from '../components/ItemTile';
|
import { StrongText } from '../components/ItemTile';
|
||||||
import { Toolbar } from 'react-native-material-ui';
|
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 {
|
class NameModal extends Component {
|
||||||
static displayName = 'NameModal';
|
static displayName = 'NameModal';
|
||||||
|
|
||||||
props: {
|
props: Props;
|
||||||
onClose: () => void,
|
|
||||||
onUpdate: (name: string) => void,
|
|
||||||
};
|
|
||||||
|
|
||||||
state: {
|
state: {
|
||||||
text: string,
|
filter: FilterRecord,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
text: '',
|
filter: new FilterRecord(),
|
||||||
};
|
};
|
||||||
|
|
||||||
save = () => {
|
save = () => {
|
||||||
this.props.onUpdate(this.state.text);
|
this.props.onUpdate(this.state.filter.search);
|
||||||
this.props.onClose();
|
this.props.onClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
setText = (text: string) => {
|
setText = (text: string) => {
|
||||||
this.setState({ text });
|
this.setState(({ filter }) => ({ filter: filter.set('search', text) }));
|
||||||
};
|
};
|
||||||
|
|
||||||
updateAndClose = (text: string) => {
|
updateAndClose = (text: string) => {
|
||||||
|
|
@ -37,15 +44,9 @@ class NameModal extends Component {
|
||||||
this.props.onClose();
|
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() {
|
render() {
|
||||||
const { onClose } = this.props;
|
const { onClose, foodItemsSeq } = this.props;
|
||||||
const { text } = this.state;
|
const { filter } = this.state;
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -71,7 +72,7 @@ class NameModal extends Component {
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{!!text && (
|
{!!filter.search && (
|
||||||
<TextButton
|
<TextButton
|
||||||
text="Not here, it's a new product"
|
text="Not here, it's a new product"
|
||||||
onPress={this.save}
|
onPress={this.save}
|
||||||
|
|
@ -79,11 +80,24 @@ class NameModal extends Component {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ScrollView style={{ paddingLeft: 78 }}>
|
<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>
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NameModal;
|
export default compose(
|
||||||
|
pure,
|
||||||
|
withUniqueFoodItems
|
||||||
|
)(NameModal);
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,23 @@ import { withCreateFoodItemState } from '../enhancers/createFoodItemEnhancers';
|
||||||
import { withPlaceForFoodItem, withPlaceId, withPlaceActions } from '../enhancers/placeEnhancers';
|
import { withPlaceForFoodItem, withPlaceId, withPlaceActions } from '../enhancers/placeEnhancers';
|
||||||
import Spinner from 'react-native-loading-spinner-overlay';
|
import Spinner from 'react-native-loading-spinner-overlay';
|
||||||
import { openImagePicker } from '../helpers/ImagePickerHelpers';
|
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 = {
|
type GooglePlaceObject = {
|
||||||
placeID: string,
|
placeID: string,
|
||||||
|
|
@ -54,20 +71,6 @@ const openPlaceModal = (onChoosePlace: (place: GooglePlaceObject) => void) => ()
|
||||||
RNGooglePlaces.openAutocompleteModal({ type: 'establishment' }).then(onChoosePlace);
|
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 CreateFoodItem = (props: Props) => {
|
||||||
const {
|
const {
|
||||||
foodItem,
|
foodItem,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue