mirror of
https://gitlab.com/wheres-the-tp/ui-mobile.git
synced 2026-01-25 07:54:57 -06:00
Merge branch '99-ios-top-bar' into 'master'
Resolve "iOS top bar" Closes #99 See merge request aretherecookies/ui-mobile!18
This commit is contained in:
commit
92ada00274
7 changed files with 61 additions and 145 deletions
|
|
@ -1,98 +0,0 @@
|
||||||
// @flow
|
|
||||||
import React from 'react';
|
|
||||||
import { ActionButton } from 'react-native-material-ui';
|
|
||||||
import { compose, pure, withHandlers } from 'recompose';
|
|
||||||
import { withRouterContext, withViewMode, withPushRoute } from '../enhancers/routeEnhancers';
|
|
||||||
import queryString from 'query-string';
|
|
||||||
import { routeWithQuery } from '../helpers/RouteHelpers';
|
|
||||||
import { prop, head, length, map } from 'ramda';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
actions: Array<'add-food' | 'filter-modal' | 'view-mode'>,
|
|
||||||
viewMode: string,
|
|
||||||
actionPressed: Function,
|
|
||||||
toggleFilterModal: ?Function,
|
|
||||||
pushRoute: Function,
|
|
||||||
router: Object,
|
|
||||||
addFoodItem: Function,
|
|
||||||
setViewMode: (mode: string) => void,
|
|
||||||
placeId?: string,
|
|
||||||
};
|
|
||||||
|
|
||||||
const actionDefs = {
|
|
||||||
'add-food': () => ({ icon: 'add', label: 'Add New', name: 'add-food' }),
|
|
||||||
'filter-modal': () => ({ icon: 'filter-list', label: 'Filter', name: 'filter-modal' }),
|
|
||||||
'view-mode': props =>
|
|
||||||
props.viewMode === 'map'
|
|
||||||
? { icon: 'list', label: 'View list', name: 'list-view' }
|
|
||||||
: { icon: 'map', label: 'View map', name: 'map-view' },
|
|
||||||
};
|
|
||||||
|
|
||||||
const ActionsButton = (props: Props) => {
|
|
||||||
const actions = map(action => actionDefs[action](props), props.actions || []);
|
|
||||||
const transition = length(actions) > 1 ? 'speedDial' : null;
|
|
||||||
const icon = length(actions) > 1 ? 'add' : prop('icon', head(actions));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ActionButton
|
|
||||||
actions={actions}
|
|
||||||
icon={icon}
|
|
||||||
transition={transition}
|
|
||||||
onPress={props.actionPressed}
|
|
||||||
onLongPress={props.actionPressed}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default compose(
|
|
||||||
pure,
|
|
||||||
withRouterContext,
|
|
||||||
withViewMode,
|
|
||||||
withPushRoute,
|
|
||||||
withHandlers({
|
|
||||||
addFoodItem: ({ pushRoute, placeId }: Props) => () => {
|
|
||||||
pushRoute(
|
|
||||||
routeWithQuery('/createFoodItem', {
|
|
||||||
routeTitle: 'Add a Food Item',
|
|
||||||
placeId,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
setViewMode: ({ router }: Props) => (viewMode: string) => {
|
|
||||||
const history = router.history;
|
|
||||||
const search = router.route.location.search;
|
|
||||||
|
|
||||||
history.replace({
|
|
||||||
search: queryString.stringify({
|
|
||||||
search,
|
|
||||||
viewMode,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
withHandlers({
|
|
||||||
actionPressed: (props: Props) =>
|
|
||||||
function handleActionPressed(action: ?String) {
|
|
||||||
switch (action) {
|
|
||||||
case 'add-food':
|
|
||||||
props.addFoodItem();
|
|
||||||
break;
|
|
||||||
case 'filter-modal':
|
|
||||||
props.toggleFilterModal && props.toggleFilterModal();
|
|
||||||
break;
|
|
||||||
case 'map-view':
|
|
||||||
case 'list-view':
|
|
||||||
case 'view-mode':
|
|
||||||
props.setViewMode(props.viewMode === 'map' ? 'list' : 'map');
|
|
||||||
break;
|
|
||||||
case 'main-button':
|
|
||||||
if (length(props.actions) === 1) {
|
|
||||||
handleActionPressed(head(props.actions));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
)(ActionsButton);
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { View, TextInput, TouchableOpacity, SafeAreaView } from 'react-native';
|
||||||
import { Toolbar, Icon } from 'react-native-material-ui';
|
import { Toolbar, Icon } from 'react-native-material-ui';
|
||||||
import { path, pipe, not, cond, isNil, compose, always } from 'ramda';
|
import { path, pipe, not, cond, isNil, compose, always } from 'ramda';
|
||||||
import queryString from 'query-string';
|
import queryString from 'query-string';
|
||||||
import { getSearch } from '../helpers/RouteHelpers';
|
import { getSearch, getViewMode } from '../helpers/RouteHelpers';
|
||||||
import FoodItemSaveBtn from '../components/FoodItemSaveBtn';
|
import FoodItemSaveBtn from '../components/FoodItemSaveBtn';
|
||||||
import { withFilter } from '../enhancers/filterEnhancers';
|
import { withFilter } from '../enhancers/filterEnhancers';
|
||||||
import FilterRecord from '../records/FilterRecord';
|
import FilterRecord from '../records/FilterRecord';
|
||||||
|
|
@ -46,16 +46,15 @@ class TopToolbar extends Component {
|
||||||
goBackTo(router);
|
goBackTo(router);
|
||||||
};
|
};
|
||||||
|
|
||||||
onRightPress = ({ action }: { action: string }) => {
|
toggleMapList = () => {
|
||||||
const {
|
const history = path(['router', 'history'], this.props);
|
||||||
router: { history },
|
|
||||||
} = this.props;
|
|
||||||
const search = getSearch(this.props);
|
const search = getSearch(this.props);
|
||||||
|
const viewMode = getViewMode(this.props);
|
||||||
|
|
||||||
history.replace({
|
history.replace({
|
||||||
search: queryString.stringify({
|
search: queryString.stringify({
|
||||||
...search,
|
...search,
|
||||||
viewMode: action,
|
viewMode: viewMode === 'list' ? 'map' : 'list',
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -83,6 +82,7 @@ class TopToolbar extends Component {
|
||||||
const route = path(['router', 'route', 'location', 'pathname'], this.props);
|
const route = path(['router', 'route', 'location', 'pathname'], this.props);
|
||||||
const routeSearch = getSearch(this.props);
|
const routeSearch = getSearch(this.props);
|
||||||
const title = routeSearch.routeTitle || this.props.title;
|
const title = routeSearch.routeTitle || this.props.title;
|
||||||
|
const viewMode = getViewMode(this.props);
|
||||||
|
|
||||||
const showSearch = /^\/list/.test(route);
|
const showSearch = /^\/list/.test(route);
|
||||||
const showSearchClear = filter.search.length > 0;
|
const showSearchClear = filter.search.length > 0;
|
||||||
|
|
@ -97,45 +97,60 @@ class TopToolbar extends Component {
|
||||||
onLeftElementPress={this.onBackPress}
|
onLeftElementPress={this.onBackPress}
|
||||||
centerElement={title}
|
centerElement={title}
|
||||||
rightElement={this.getRightElement()}
|
rightElement={this.getRightElement()}
|
||||||
onRightElementPress={this.onRightPress}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showSearch && (
|
{showSearch && (
|
||||||
<View
|
<View style={{ flexDirection: 'row', padding: 10 }}>
|
||||||
style={{
|
<View
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
margin: 10,
|
|
||||||
backgroundColor: 'white',
|
|
||||||
borderRadius: 10,
|
|
||||||
}}>
|
|
||||||
<Icon name="search" style={{ margin: 10 }} />
|
|
||||||
<TextInput
|
|
||||||
value={filter.search}
|
|
||||||
onChangeText={this.onChangeText}
|
|
||||||
placeholder={searchPlaceholder}
|
|
||||||
underlineColorAndroid="transparent"
|
|
||||||
style={{
|
style={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
fontSize: 18,
|
flexDirection: 'row',
|
||||||
}}
|
alignItems: 'center',
|
||||||
/>
|
backgroundColor: 'white',
|
||||||
{showSearchClear ? (
|
borderRadius: 10,
|
||||||
<TouchableOpacity onPress={this.onSearchCleared}>
|
}}>
|
||||||
<Icon name="close" style={{ margin: 10 }} />
|
<Icon name="search" style={{ marginHorizontal: 10 }} />
|
||||||
</TouchableOpacity>
|
<TextInput
|
||||||
) : (
|
value={filter.search}
|
||||||
<TouchableOpacity
|
onChangeText={this.onChangeText}
|
||||||
onPress={onFilterPress}
|
placeholder={searchPlaceholder}
|
||||||
|
underlineColorAndroid="transparent"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: '#E5E5E5',
|
flex: 1,
|
||||||
borderRadius: 3,
|
fontSize: 18,
|
||||||
marginHorizontal: 10,
|
padding: 5,
|
||||||
padding: 7,
|
}}
|
||||||
}}>
|
/>
|
||||||
<FAIcon name="filter" style={{ fontSize: 22 }} />
|
{showSearchClear ? (
|
||||||
</TouchableOpacity>
|
<TouchableOpacity onPress={this.onSearchCleared}>
|
||||||
)}
|
<Icon name="close" style={{ margin: 10 }} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
) : (
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={onFilterPress}
|
||||||
|
style={{
|
||||||
|
backgroundColor: '#E5E5E5',
|
||||||
|
borderRadius: 3,
|
||||||
|
marginHorizontal: 10,
|
||||||
|
paddingVertical: 5,
|
||||||
|
paddingHorizontal: 8,
|
||||||
|
}}>
|
||||||
|
<FAIcon name="filter" style={{ fontSize: 22 }} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={this.toggleMapList}
|
||||||
|
style={{
|
||||||
|
padding: 8,
|
||||||
|
borderRadius: 10,
|
||||||
|
backgroundColor: 'rgba(255,255,255,0.2)',
|
||||||
|
marginLeft: 10,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}>
|
||||||
|
<Icon name={viewMode === 'map' ? 'view-list' : 'map'} size={22} color="white" />
|
||||||
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
import { getContext, withProps, compose } from 'recompose';
|
import { getContext, withProps, compose } from 'recompose';
|
||||||
import { shape, func, string } from 'prop-types';
|
import { shape, func, string } from 'prop-types';
|
||||||
import { path } from 'ramda';
|
import { path } from 'ramda';
|
||||||
import { getSearch } from '../helpers/RouteHelpers';
|
import { getViewMode } from '../helpers/RouteHelpers';
|
||||||
|
|
||||||
export type routeMatch = {
|
export type routeMatch = {
|
||||||
isExact: boolean,
|
isExact: boolean,
|
||||||
|
|
@ -48,7 +48,7 @@ export const withRouterContext = getContext({
|
||||||
|
|
||||||
export const withViewMode = withProps((props: Object) => {
|
export const withViewMode = withProps((props: Object) => {
|
||||||
return {
|
return {
|
||||||
viewMode: getSearch(props).viewMode || 'list',
|
viewMode: getViewMode(props),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,3 +26,8 @@ export const getSearch = pipe(
|
||||||
pathOr('', ['router', 'route', 'location', 'search']),
|
pathOr('', ['router', 'route', 'location', 'search']),
|
||||||
queryString.parse
|
queryString.parse
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getViewMode = pipe(
|
||||||
|
getSearch,
|
||||||
|
pathOr('list', ['viewMode'])
|
||||||
|
);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import { View, Text, TextInput, Button, TouchableOpacity } from 'react-native';
|
||||||
import { withHandlers, compose, withState, lifecycle } from 'recompose';
|
import { withHandlers, compose, withState, lifecycle } from 'recompose';
|
||||||
import { withRouterContext } from '../enhancers/routeEnhancers';
|
import { withRouterContext } from '../enhancers/routeEnhancers';
|
||||||
import AuthManager from '../AuthManager';
|
import AuthManager from '../AuthManager';
|
||||||
import queryString from 'query-string';
|
|
||||||
import theme from '../ui-theme';
|
import theme from '../ui-theme';
|
||||||
import { Divider, Icon } from 'react-native-material-ui';
|
import { Divider, Icon } from 'react-native-material-ui';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import { type List } from 'immutable';
|
||||||
import typeof FoodItemRecord from '../records/FoodItemRecord';
|
import typeof FoodItemRecord from '../records/FoodItemRecord';
|
||||||
import FoodItemTile from '../components/FoodItemTile';
|
import FoodItemTile from '../components/FoodItemTile';
|
||||||
import { openUrl } from '../helpers/linkHelpers';
|
import { openUrl } from '../helpers/linkHelpers';
|
||||||
import ActionsButton from '../components/ActionsButton';
|
|
||||||
import { routeWithQuery } from '../helpers/RouteHelpers';
|
import { routeWithQuery } from '../helpers/RouteHelpers';
|
||||||
import { Link } from 'react-router-native';
|
import { Link } from 'react-router-native';
|
||||||
|
|
||||||
|
|
@ -115,7 +114,6 @@ const PlaceDetail = (props: Props) => {
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
<ActionsButton actions={['add-food']} placeId={place.id} />
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import PlaceTile from '../components/PlaceTile';
|
||||||
import { withFoodItemsGroupedByPlace } from '../enhancers/foodItemEnhancers';
|
import { withFoodItemsGroupedByPlace } from '../enhancers/foodItemEnhancers';
|
||||||
import { withRegionState } from '../enhancers/mapViewEnhancers';
|
import { withRegionState } from '../enhancers/mapViewEnhancers';
|
||||||
import typeof PlaceRecord from '../records/PlaceRecord';
|
import typeof PlaceRecord from '../records/PlaceRecord';
|
||||||
import ActionsButton from '../components/ActionsButton';
|
|
||||||
|
|
||||||
type Region = {
|
type Region = {
|
||||||
latitude: number,
|
latitude: number,
|
||||||
|
|
@ -29,7 +28,6 @@ type Props = {
|
||||||
pushRoute: () => {},
|
pushRoute: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
// const PlacesMap = ({ places, region, onRegionChange, pushRoute }: Props) => {
|
|
||||||
const PlacesMap = ({
|
const PlacesMap = ({
|
||||||
places = Map(),
|
places = Map(),
|
||||||
foodItemsByPlace = Map(),
|
foodItemsByPlace = Map(),
|
||||||
|
|
@ -72,7 +70,6 @@ const PlacesMap = ({
|
||||||
})
|
})
|
||||||
.toList()}
|
.toList()}
|
||||||
</MapView>
|
</MapView>
|
||||||
<ActionsButton actions={['view-mode']} />
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue