mirror of
https://gitlab.com/wheres-the-tp/ui-mobile.git
synced 2026-01-25 07:24:56 -06:00
create food item save button wired up to backend
This commit is contained in:
parent
4e934d9b6b
commit
54f5bf2893
9 changed files with 87 additions and 52 deletions
|
|
@ -17,6 +17,7 @@ export const fetchRequest = async ({
|
|||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...AuthManager.getAuthHeader(),
|
||||
...headers,
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// @flow
|
||||
import { memoize } from 'ramda';
|
||||
import FilterRecord from '../records/FilterRecord';
|
||||
import { BASE_URL } from '../constants/AppConstants';
|
||||
import FoodItemRecord from '../records/FoodItemRecord';
|
||||
import { fetchRequest } from './FetchApi';
|
||||
|
||||
export type FoodItemsFilter = {
|
||||
radius?: number,
|
||||
|
|
@ -39,12 +39,10 @@ export const getFoodItems = memoize(
|
|||
const { orderby, categories, radius } = filter;
|
||||
|
||||
try {
|
||||
return fetch(`http://${BASE_URL}/fooditems`, {
|
||||
return fetchRequest({
|
||||
endpoint: '/fooditems',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
body: {
|
||||
lat,
|
||||
lng,
|
||||
orderby,
|
||||
|
|
@ -52,14 +50,12 @@ export const getFoodItems = memoize(
|
|||
...(categories ? { categories } : {}),
|
||||
radius,
|
||||
},
|
||||
}),
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(json => ({
|
||||
...json,
|
||||
loading: false,
|
||||
error: null,
|
||||
}));
|
||||
},
|
||||
}).then(json => ({
|
||||
...json,
|
||||
loading: false,
|
||||
error: null,
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
return {
|
||||
|
|
@ -73,10 +69,11 @@ export const getFoodItems = memoize(
|
|||
}
|
||||
);
|
||||
|
||||
export const createFoodItem = (foodItem: FoodItemRecord) => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve(foodItem);
|
||||
}, 1000);
|
||||
export const createFoodItem = async (foodItem: FoodItemRecord) => {
|
||||
const res = await fetchRequest({
|
||||
endpoint: '/addfooditem',
|
||||
method: 'POST',
|
||||
body: foodItem,
|
||||
});
|
||||
return res;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// @flow
|
||||
import type { Quantity } from '../constants/QuantityConstants';
|
||||
import type { QuantityResponse } from '../constants/QuantityConstants';
|
||||
import AuthManager from '../AuthManager';
|
||||
import { fetchRequest } from './FetchApi';
|
||||
|
||||
export const setQuantity = ({
|
||||
|
|
@ -14,7 +13,6 @@ export const setQuantity = ({
|
|||
return fetchRequest({
|
||||
method: 'POST',
|
||||
endpoint: '/quantity',
|
||||
headers: { ...AuthManager.getAuthHeader() },
|
||||
body: {
|
||||
foodItemId,
|
||||
quantity,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { Text, TouchableOpacity } from 'react-native';
|
||||
import { withCreateFoodItem } from '../enhancers/createFoodItemEnhancers';
|
||||
import compose from 'recompose/compose';
|
||||
import mapProps from 'recompose/mapProps';
|
||||
import { withCreateFoodItemState } from '../enhancers/createFoodItemEnhancers';
|
||||
import { withReplaceRoute } from '../enhancers/routeEnhancers';
|
||||
import { compose, onlyUpdateForKeys, withHandlers } from 'recompose';
|
||||
import { routeWithTitle } from '../helpers/RouteHelpers';
|
||||
|
||||
const FoodItemSaveBtn = ({
|
||||
saveFoodItem,
|
||||
|
|
@ -27,9 +28,20 @@ const FoodItemSaveBtn = ({
|
|||
};
|
||||
|
||||
export default compose(
|
||||
withCreateFoodItem,
|
||||
mapProps(({ saveFoodItem, loading }) => ({
|
||||
saveFoodItem,
|
||||
loading,
|
||||
}))
|
||||
withCreateFoodItemState,
|
||||
withReplaceRoute,
|
||||
withHandlers({
|
||||
saveFoodItem: ({ saveFoodItem, setLoading, setError, replaceRoute }) => async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const { id, name } = await saveFoodItem();
|
||||
replaceRoute(routeWithTitle(`/foodItem/${id || ''}`, name));
|
||||
} catch (error) {
|
||||
setError(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
}),
|
||||
onlyUpdateForKeys(['loading'])
|
||||
)(FoodItemSaveBtn);
|
||||
|
|
|
|||
|
|
@ -1,31 +1,27 @@
|
|||
// @flow
|
||||
import mapPropsStream from 'recompose/mapPropsStream';
|
||||
import CreateFoodItem$, { emitter } from '../streams/CreateFoodItemStream';
|
||||
import FoodItemRecord from '../records/FoodItemRecord';
|
||||
import CreateFoodItem$, { emitter as emitCreateItemState } from '../streams/CreateFoodItemStream';
|
||||
import { emitter as emitFoodItemsState } from '../streams/FoodItemsStream';
|
||||
import { createFoodItem } from '../apis/FoodItemsApi';
|
||||
import FoodItemRecord, { createFoodItem as buildFoodItem } from '../records/FoodItemRecord';
|
||||
|
||||
// todo real implementation somewhere
|
||||
const isFoodItemValid = () => true;
|
||||
|
||||
export const withCreateFoodItem = mapPropsStream(props$ => {
|
||||
export const withCreateFoodItemState = mapPropsStream(props$ => {
|
||||
return props$.combineLatest(CreateFoodItem$, (props, state) => {
|
||||
const { foodItem, loading, error } = state;
|
||||
|
||||
const setFoodItem = (foodItem: FoodItemRecord) => emitter({ ...state, foodItem });
|
||||
const setLoading = (loading: boolean) => emitter({ ...state, loading });
|
||||
const setError = (error: Error) => emitter({ ...state, error });
|
||||
const setFoodItem = (foodItem: FoodItemRecord) => emitCreateItemState({ ...state, foodItem });
|
||||
const setLoading = (loading: boolean) => emitCreateItemState({ ...state, loading });
|
||||
const setError = (error: Error) => emitCreateItemState({ ...state, error });
|
||||
|
||||
const saveFoodItem = async () => {
|
||||
if (isFoodItemValid(foodItem)) {
|
||||
try {
|
||||
setLoading(true);
|
||||
await createFoodItem(foodItem);
|
||||
} catch (error) {
|
||||
// todo else surface a toast notification
|
||||
setError(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
const res = await createFoodItem(foodItem);
|
||||
const createdFoodItem = buildFoodItem(res[0]);
|
||||
emitFoodItemsState(createdFoodItem);
|
||||
return createdFoodItem;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -36,6 +32,8 @@ export const withCreateFoodItem = mapPropsStream(props$ => {
|
|||
error,
|
||||
setFoodItem,
|
||||
saveFoodItem,
|
||||
setLoading,
|
||||
setError,
|
||||
};
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// @flow
|
||||
import { getContext, mapProps } from 'recompose';
|
||||
import { getContext, withProps, compose } from 'recompose';
|
||||
import { shape, func, string } from 'prop-types';
|
||||
import { path } from 'ramda';
|
||||
import { getSearch } from '../helpers/RouteHelpers';
|
||||
|
|
@ -21,16 +21,23 @@ export const withRouterContext = getContext({
|
|||
}).isRequired,
|
||||
});
|
||||
|
||||
export const withViewMode = mapProps((props: Object) => {
|
||||
export const withViewMode = withProps((props: Object) => {
|
||||
return {
|
||||
...props,
|
||||
viewMode: getSearch(props).viewMode,
|
||||
};
|
||||
});
|
||||
|
||||
export const withPushRoute = mapProps((props: Object) => {
|
||||
export const withPushRoute = withProps((props: Object) => {
|
||||
return {
|
||||
...props,
|
||||
pushRoute: path(['router', 'history', 'push'], props),
|
||||
};
|
||||
});
|
||||
|
||||
export const withReplaceRoute = compose(
|
||||
withRouterContext,
|
||||
withProps((props: Object) => {
|
||||
return {
|
||||
replaceRoute: path(['router', 'history', 'replace'], props),
|
||||
};
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { compose, branch, withState, withHandlers, renderComponent, mapProps } f
|
|||
import RNGooglePlaces from 'react-native-google-places';
|
||||
import CategoryPicker from '../components/CategoryPicker';
|
||||
import { ImageThumb, ImagePicker } from '../components/ImagePicker';
|
||||
import { withCreateFoodItem } from '../enhancers/createFoodItemEnhancers';
|
||||
import { withCreateFoodItemState } from '../enhancers/createFoodItemEnhancers';
|
||||
import Spinner from 'react-native-loading-spinner-overlay';
|
||||
|
||||
type GooglePlaceObject = {
|
||||
|
|
@ -165,7 +165,7 @@ const toggleNameModal = ({ nameModalOpen, setNameModalOpen }) => () =>
|
|||
setNameModalOpen(!nameModalOpen);
|
||||
|
||||
export default compose(
|
||||
withCreateFoodItem,
|
||||
withCreateFoodItemState,
|
||||
withState('place', 'setPlace', new PlaceRecord()),
|
||||
withState('nameModalOpen', 'setNameModalOpen', false),
|
||||
withState('imagePreview', 'setImagePreview', -1),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
//@flow
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import FoodItemRecord, { createFoodItem } from '../records/FoodItemRecord';
|
||||
import { setById } from '../helpers/ImmutableHelpers';
|
||||
import { Map } from 'immutable';
|
||||
|
|
@ -9,11 +10,31 @@ import FilterRecord from '../records/FilterRecord';
|
|||
import Quantity$ from './QuantityStream';
|
||||
import type { QuantityFragment } from '../constants/QuantityConstants';
|
||||
|
||||
export default location$
|
||||
const foodItemSubject: ReplaySubject<FoodItemRecord> = new ReplaySubject();
|
||||
|
||||
export function emitter(val?: ?FoodItemRecord) {
|
||||
foodItemSubject.next(val);
|
||||
}
|
||||
|
||||
emitter(null);
|
||||
|
||||
const manualUpdate$ = foodItemSubject.scan(
|
||||
(foodItemMap: Map<string, FoodItemRecord>, foodItem: FoodItemRecord) => {
|
||||
return foodItem ? foodItemMap.set(foodItem.id, foodItem) : foodItemMap;
|
||||
},
|
||||
Map()
|
||||
);
|
||||
|
||||
const fetchedFoodItems$ = location$
|
||||
.combineLatest(Filter$)
|
||||
.mergeMap(([loc, filter]: [Position, FilterRecord]) => getFoodItems({ loc, filter }))
|
||||
.map(({ fooditems = [] }: FoodItemsForLocation) => {
|
||||
return fooditems.map(createFoodItem).reduce(setById, new Map());
|
||||
});
|
||||
|
||||
export default fetchedFoodItems$
|
||||
.combineLatest(manualUpdate$, (foodItemMap: Map<string, FoodItemRecord>, manualUpdates) => {
|
||||
return foodItemMap.mergeDeep(manualUpdates);
|
||||
})
|
||||
.combineLatest(
|
||||
Quantity$,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export default Observable.create((obs: Observer<Position>): Observable<Position>
|
|||
},
|
||||
{
|
||||
enableHighAccuracy: false,
|
||||
maximumAge: 10000,
|
||||
timeout: 1000,
|
||||
}
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue