diff --git a/app/actions/navigation/index.js b/app/actions/navigation/index.js
index 1e5acb990..8f55f3713 100644
--- a/app/actions/navigation/index.js
+++ b/app/actions/navigation/index.js
@@ -12,6 +12,14 @@ export function goBack() {
};
}
+export function closeDrawers() {
+ return async (dispatch, getState) => {
+ dispatch({
+ type: NavigationTypes.NAVIGATION_CLOSE_DRAWERS
+ }, getState);
+ };
+}
+
export function goToLogin() {
return async (dispatch, getState) => {
dispatch({
@@ -21,6 +29,15 @@ export function goToLogin() {
};
}
+export function goToLoadTeam() {
+ return async (dispatch, getState) => {
+ dispatch({
+ type: NavigationTypes.NAVIGATION_PUSH,
+ route: Routes.LoadTeam
+ }, getState);
+ };
+}
+
export function goToSelectTeam() {
return async (dispatch, getState) => {
dispatch({
@@ -30,43 +47,6 @@ export function goToSelectTeam() {
};
}
-export function goToChannelView() {
- return async (dispatch, getState) => {
- dispatch({
- type: NavigationTypes.NAVIGATION_PUSH,
- route: Routes.ChannelView
- }, getState);
- };
-}
-
-export function goToRecentMentions() {
- return async (dispatch, getState) => {
- dispatch({
- type: NavigationTypes.NAVIGATION_PUSH,
- route: {
- ...Routes.Search,
- props: {
- searchType: 'recent_mentions'
- }
- }
- }, getState);
- };
-}
-
-export function goToFlaggedPosts() {
- return async (dispatch, getState) => {
- dispatch({
- type: NavigationTypes.NAVIGATION_PUSH,
- route: {
- ...Routes.Search,
- props: {
- searchType: 'flagged_posts'
- }
- }
- }, getState);
- };
-}
-
export function goToChannelInfo() {
return async (dispatch, getState) => {
dispatch({
@@ -75,3 +55,21 @@ export function goToChannelInfo() {
}, getState);
};
}
+
+export function openChannelDrawer() {
+ return async (dispatch, getState) => {
+ dispatch({
+ type: NavigationTypes.NAVIGATION_OPEN_LEFT_DRAWER,
+ route: Routes.ChannelDrawer
+ }, getState);
+ };
+}
+
+export function openRightMenuDrawer() {
+ return async (dispatch, getState) => {
+ dispatch({
+ type: NavigationTypes.NAVIGATION_OPEN_RIGHT_DRAWER,
+ route: Routes.RightMenuDrawer
+ }, getState);
+ };
+}
diff --git a/app/actions/views/drawer.js b/app/actions/views/drawer.js
deleted file mode 100644
index 7f7f8f336..000000000
--- a/app/actions/views/drawer.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {ViewTypes} from 'app/constants';
-
-export function openChannelDrawer() {
- return async (dispatch, getState) => {
- dispatch({type: ViewTypes.TOGGLE_CHANNEL_DRAWER, data: true}, getState);
- };
-}
-
-export function closeChannelDrawer() {
- return async (dispatch, getState) => {
- dispatch({type: ViewTypes.TOGGLE_CHANNEL_DRAWER, data: false}, getState);
- };
-}
diff --git a/app/actions/views/load_team.js b/app/actions/views/load_team.js
new file mode 100644
index 000000000..f22034118
--- /dev/null
+++ b/app/actions/views/load_team.js
@@ -0,0 +1,14 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {NavigationTypes} from 'app/constants';
+import Routes from 'app/navigation/routes';
+
+export function goToChannelView() {
+ return async (dispatch, getState) => {
+ dispatch({
+ type: NavigationTypes.NAVIGATION_RESET,
+ routes: [Routes.ChannelView]
+ }, getState);
+ };
+}
diff --git a/app/actions/views/right_menu_drawer.js b/app/actions/views/right_menu_drawer.js
new file mode 100644
index 000000000..d9e60e868
--- /dev/null
+++ b/app/actions/views/right_menu_drawer.js
@@ -0,0 +1,50 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {batchActions} from 'redux-batched-actions';
+
+import {NavigationTypes} from 'app/constants';
+import Routes from 'app/navigation/routes';
+
+export function goToSelectTeam() {
+ return async (dispatch, getState) => {
+ dispatch(batchActions([{
+ type: NavigationTypes.NAVIGATION_CLOSE_DRAWERS
+ }, {
+ type: NavigationTypes.NAVIGATION_PUSH,
+ route: Routes.SelectTeam
+ }]), getState);
+ };
+}
+
+export function goToRecentMentions() {
+ return async (dispatch, getState) => {
+ dispatch(batchActions([{
+ type: NavigationTypes.NAVIGATION_CLOSE_DRAWERS
+ }, {
+ type: NavigationTypes.NAVIGATION_PUSH,
+ route: {
+ ...Routes.Search,
+ props: {
+ searchType: 'recent_mentions'
+ }
+ }
+ }]), getState);
+ };
+}
+
+export function goToFlaggedPosts() {
+ return async (dispatch, getState) => {
+ dispatch(batchActions([{
+ type: NavigationTypes.NAVIGATION_CLOSE_DRAWERS
+ }, {
+ type: NavigationTypes.NAVIGATION_PUSH,
+ route: {
+ ...Routes.Search,
+ props: {
+ searchType: 'flagged_posts'
+ }
+ }
+ }]), getState);
+ };
+}
diff --git a/app/components/channel_drawer/channel_drawer.js b/app/components/channel_drawer/channel_drawer.js
deleted file mode 100644
index c467d8864..000000000
--- a/app/components/channel_drawer/channel_drawer.js
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import React from 'react';
-import {Platform, BackAndroid} from 'react-native';
-import deepEqual from 'deep-equal';
-
-import Drawer from 'react-native-drawer';
-import ChannelList from './channel_list';
-
-export default class ChannelDrawer extends React.Component {
- static propTypes = {
- children: React.PropTypes.element.isRequired,
- actions: React.PropTypes.shape({
- updateStorage: React.PropTypes.func.isRequired,
- handleSelectChannel: React.PropTypes.func.isRequired,
- viewChannel: React.PropTypes.func.isRequired,
- closeDMChannel: React.PropTypes.func.isRequired,
- closeChannelDrawer: React.PropTypes.func.isRequired
- }).isRequired,
- currentTeam: React.PropTypes.object,
- currentChannel: React.PropTypes.object,
- channels: React.PropTypes.object,
- channelMembers: React.PropTypes.object,
- theme: React.PropTypes.object.isRequired,
- isOpen: React.PropTypes.bool.isRequired
- };
-
- constructor(props) {
- super(props);
-
- this.handleBackButton = this.handleBackButton.bind(this);
- this.selectChannel = this.selectChannel.bind(this);
- }
-
- componentDidMount() {
- if (Platform.OS === 'android') {
- BackAndroid.addEventListener('hardwareBackPress', this.handleBackButton);
- }
- }
-
- componentWillUnmount() {
- if (Platform.OS === 'android') {
- BackAndroid.removeEventListener('hardwareBackPress', this.handleBackButton);
- }
- }
- shouldComponentUpdate(nextProps) {
- return !deepEqual(this.props, nextProps, {strict: true});
- }
-
- componentWillReceiveProps(nextProps) {
- if (!this.props.isOpen && nextProps.isOpen) {
- this.drawer.open();
- } else if (this.props.isOpen && !nextProps.isOpen) {
- this.drawer.close();
- }
- }
-
- handleBackButton() {
- if (this.props.isOpen) {
- this.props.actions.closeChannelDrawer();
- return true;
- }
- return false;
- }
-
- selectChannel(channelId) {
- this.props.actions.handleSelectChannel(channelId);
- }
-
- render() {
- const {
- currentChannel,
- currentTeam,
- channels,
- channelMembers,
- theme
- } = this.props;
-
- return (
- {
- this.drawer = ref;
- }}
- onClose={this.props.actions.closeChannelDrawer}
- type='displace'
- openDrawerOffset={0.2}
- closedDrawerOffset={0}
- panOpenMask={0.1}
- panCloseMask={0.2}
- panThreshold={0.2}
- acceptPan={true}
- tapToClose={true}
- content={
-
- }
- >
- {this.props.children}
-
- );
- }
-}
diff --git a/app/components/channel_drawer/channel_drawer_container.js b/app/components/channel_drawer/channel_drawer_container.js
deleted file mode 100644
index 42c3ccf54..000000000
--- a/app/components/channel_drawer/channel_drawer_container.js
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {bindActionCreators} from 'redux';
-import {connect} from 'react-redux';
-
-import {viewChannel} from 'service/actions/channels';
-import {getChannelsByCategory} from 'service/selectors/entities/channels';
-import {closeDMChannel, handleSelectChannel} from 'app/actions/views/channel';
-import {closeChannelDrawer} from 'app/actions/views/drawer';
-import {updateStorage} from 'app/actions/storage';
-import ChannelDrawer from './channel_drawer';
-
-function mapStateToProps(state, ownProps) {
- const isOpen = state.views.drawer.channel;
- const channelMembers = state.entities.channels.myMembers;
- return {
- ...ownProps,
- channels: getChannelsByCategory(state),
- channelMembers,
- isOpen
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- actions: bindActionCreators({
- updateStorage,
- handleSelectChannel,
- viewChannel,
- closeDMChannel,
- closeChannelDrawer
- }, dispatch)
- };
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(ChannelDrawer);
diff --git a/app/components/channel_drawer/channel_list.js b/app/components/channel_drawer/channel_list.js
index 78458aa10..c020ed97b 100644
--- a/app/components/channel_drawer/channel_list.js
+++ b/app/components/channel_drawer/channel_list.js
@@ -60,8 +60,7 @@ class ChannelList extends React.Component {
theme: React.PropTypes.object.isRequired,
onSelectChannel: React.PropTypes.func.isRequired,
onViewChannel: React.PropTypes.func.isRequired,
- handleCloseDM: React.PropTypes.func.isRequired,
- closeChannelDrawer: React.PropTypes.func.isRequired
+ handleCloseDM: React.PropTypes.func.isRequired
};
constructor(props) {
@@ -141,7 +140,6 @@ class ChannelList extends React.Component {
this.props.onSelectChannel(channel.id);
this.props.onViewChannel(currentTeam.id, channel.id, currentChannel.id);
- this.props.closeChannelDrawer();
};
handleClose = (channel) => {
diff --git a/app/components/drawer.js b/app/components/drawer.js
index d3e53b316..96894c9cd 100644
--- a/app/components/drawer.js
+++ b/app/components/drawer.js
@@ -11,14 +11,19 @@ export default class Drawer extends BaseDrawer {
onRequestClose: React.PropTypes.func.isRequired
};
- close = (type, callback) => {
- this.props.onRequestClose();
+ processTapGestures = () => {
+ // Note that we explicitly don't support tap to open or double tap because I didn't copy them over
- if (typeof type === 'function') {
- // This function can be called with only a callback as its only argument
- type();
- } else if (callback) {
- callback();
+ if (this._activeTween) { // eslint-disable-line no-underscore-dangle
+ return false;
}
- }
+
+ if (this.props.tapToClose && this._open) { // eslint-disable-line no-underscore-dangle
+ this.props.onRequestClose();
+
+ return true;
+ }
+
+ return false;
+ };
}
diff --git a/app/components/right_sidebar_menu/index.js b/app/components/right_sidebar_menu/index.js
deleted file mode 100644
index be9b8dd2f..000000000
--- a/app/components/right_sidebar_menu/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import RightSidebarMenuContainer from './right_sidebar_menu_container';
-
-export default RightSidebarMenuContainer;
diff --git a/app/constants/navigation.js b/app/constants/navigation.js
index 0bbc7ec31..90d3ee7e1 100644
--- a/app/constants/navigation.js
+++ b/app/constants/navigation.js
@@ -6,8 +6,12 @@ import keyMirror from 'service/utils/key_mirror';
const NavigationTypes = keyMirror({
NAVIGATION_PUSH: null,
NAVIGATION_POP: null,
+ NAVIGATION_OPEN_LEFT_DRAWER: null,
+ NAVIGATION_OPEN_RIGHT_DRAWER: null,
+ NAVIGATION_CLOSE_DRAWERS: null,
NAVIGATION_JUMP: null,
NAVIGATION_JUMP_TO_INDEX: null,
+ NAVIGATION_REPLACE: null,
NAVIGATION_RESET: null
});
diff --git a/app/initial_state.js b/app/initial_state.js
index 6c7ceba5c..bcfde8ba6 100644
--- a/app/initial_state.js
+++ b/app/initial_state.js
@@ -257,7 +257,11 @@ const state = {
{
key: 'Root'
}
- ]
+ ],
+ leftDrawerOpen: false,
+ leftDrawerRoute: null,
+ rightDrawerOpen: false,
+ rightDrawerRoute: null
},
views: {
i18n: {
@@ -269,9 +273,6 @@ const state = {
},
selectServer: {
serverUrl: Config.DefaultServerUrl
- },
- drawer: {
- channel: false
}
}
};
diff --git a/app/navigation/router.js b/app/navigation/router.js
index 52f89029f..bace732c9 100644
--- a/app/navigation/router.js
+++ b/app/navigation/router.js
@@ -2,22 +2,26 @@
// See License.txt for license information.
import React from 'react';
-
-import {bindActionCreators} from 'redux';
+import {
+ Easing,
+ NavigationExperimental,
+ View
+} from 'react-native';
import {connect} from 'react-redux';
+import {bindActionCreators} from 'redux';
-import {goBack} from 'app/actions/navigation';
-
-import {getComponentForScene} from 'app/scenes';
-
-import {Easing, NavigationExperimental, View} from 'react-native';
+import {closeDrawers, goBack} from 'app/actions/navigation';
+import Drawer from 'app/components/drawer';
import FormattedText from 'app/components/formatted_text';
+import {RouteTransitions} from 'app/navigation/routes';
+import {getComponentForScene} from 'app/scenes';
class Router extends React.Component {
static propTypes = {
navigation: React.PropTypes.object,
actions: React.PropTypes.shape({
- goBack: React.PropTypes.func
+ closeDrawers: React.PropTypes.func.isRequired,
+ goBack: React.PropTypes.func.isRequired
}).isRequired
};
@@ -39,12 +43,19 @@ class Router extends React.Component {
scene
};
+ let style;
+ if (scene.route.transition === RouteTransitions.Horizontal) {
+ style = NavigationExperimental.Card.PagerStyleInterpolator.forHorizontal({
+ ...cardProps
+ });
+ } else {
+ style = {};
+ }
+
return (
@@ -52,11 +63,9 @@ class Router extends React.Component {
});
return (
-
-
- {renderedScenes}
-
+
{title}
+ {renderedScenes}
);
};
@@ -79,11 +88,15 @@ class Router extends React.Component {
};
renderScene = ({scene}) => {
- const SceneComponent = getComponentForScene(scene.route.key);
-
- return ;
+ return this.renderRoute(scene.route);
};
+ renderRoute = (route) => {
+ const SceneComponent = getComponentForScene(route.key);
+
+ return ;
+ }
+
configureTransition = () => {
return {
duration: 500,
@@ -92,13 +105,49 @@ class Router extends React.Component {
};
render = () => {
+ const {
+ leftDrawerOpen,
+ leftDrawerRoute,
+ rightDrawerOpen,
+ rightDrawerRoute
+ } = this.props.navigation;
+
+ let leftDrawerContent;
+ if (leftDrawerRoute) {
+ leftDrawerContent = this.renderRoute(leftDrawerRoute);
+ }
+
+ let rightDrawerContent;
+ if (rightDrawerRoute) {
+ rightDrawerContent = this.renderRoute(rightDrawerRoute);
+ }
+
return (
-
+
+
+
+
+
);
};
}
@@ -112,6 +161,7 @@ function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
+ closeDrawers,
goBack
}, dispatch)
};
diff --git a/app/navigation/routes.js b/app/navigation/routes.js
index 6372e92e8..d55d717c6 100644
--- a/app/navigation/routes.js
+++ b/app/navigation/routes.js
@@ -1,30 +1,52 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-export default {
+import keyMirror from 'service/utils/key_mirror';
+
+export const RouteTransitions = keyMirror({
+ Horizontal: null
+});
+
+export const Routes = {
+ ChannelInfo: {
+ key: 'ChannelInfo',
+ title: {id: 'mobile.routes.channelInfo', defaultMessage: 'Info'},
+ transition: RouteTransitions.Horizontal
+ },
+ ChannelDrawer: {
+ key: 'ChannelDrawer'
+ },
+ ChannelView: {
+ key: 'ChannelView',
+ transition: RouteTransitions.Horizontal
+ },
+ LoadTeam: {
+ key: 'LoadTeam'
+ },
+ Login: {
+ key: 'Login',
+ title: {id: 'mobile.routes.login', defaultMessage: 'Login'},
+ transition: RouteTransitions.Horizontal
+ },
+ RightMenuDrawer: {
+ key: 'RightMenuDrawer'
+ },
Root: {
key: 'Root'
},
+ Search: {
+ key: 'Search',
+ transition: RouteTransitions.Horizontal
+ },
SelectServer: {
key: 'SelectServer',
title: {id: 'mobile.routes.enterServerUrl', defaultMessage: 'Enter Server URL'}
},
- Login: {
- key: 'Login',
- title: {id: 'mobile.routes.login', defaultMessage: 'Login'}
- },
SelectTeam: {
key: 'SelectTeam',
- title: {id: 'mobile.routes.selectTeam', defaultMessage: 'Select Team'}
- },
- ChannelView: {
- key: 'ChannelView'
- },
- Search: {
- key: 'Search'
- },
- ChannelInfo: {
- key: 'ChannelInfo',
- title: {id: 'mobile.routes.channelInfo', defaultMessage: 'Info'}
+ title: {id: 'mobile.routes.selectTeam', defaultMessage: 'Select Team'},
+ transition: RouteTransitions.Horizontal
}
};
+
+export default Routes;
diff --git a/app/reducers/navigation/index.js b/app/reducers/navigation/index.js
index 9ed8e2a11..7b14bd20d 100644
--- a/app/reducers/navigation/index.js
+++ b/app/reducers/navigation/index.js
@@ -12,7 +12,11 @@ const initialState = {
index: 0,
routes: [
Routes.Root
- ]
+ ],
+ leftDrawerOpen: false,
+ leftDrawerRoute: null,
+ rightDrawerOpen: false,
+ rightDrawerRoute: null
};
export default function(state = initialState, action) {
@@ -21,8 +25,37 @@ export default function(state = initialState, action) {
return NavigationExperimental.StateUtils.push(state, action.route);
case NavigationTypes.NAVIGATION_POP:
+ if (state.leftDrawerOpen || state.rightDrawerOpen) {
+ return {
+ ...state,
+ leftDrawerOpen: false,
+ rightDrawerOpen: false
+ };
+ }
+
return NavigationExperimental.StateUtils.pop(state);
+ case NavigationTypes.NAVIGATION_OPEN_LEFT_DRAWER:
+ return {
+ ...state,
+ leftDrawerOpen: true,
+ leftDrawerRoute: action.route
+ };
+
+ case NavigationTypes.NAVIGATION_OPEN_RIGHT_DRAWER:
+ return {
+ ...state,
+ rightDrawerOpen: true,
+ rightDrawerRoute: action.route
+ };
+
+ case NavigationTypes.NAVIGATION_CLOSE_DRAWERS:
+ return {
+ ...state,
+ leftDrawerOpen: false,
+ rightDrawerOpen: false
+ };
+
case NavigationTypes.NAVIGATION_JUMP:
return NavigationExperimental.StateUtils.jumpTo(state, action.key);
@@ -30,7 +63,15 @@ export default function(state = initialState, action) {
return NavigationExperimental.StateUtils.jumpToIndex(state, action.index);
case NavigationTypes.NAVIGATION_RESET:
- return NavigationExperimental.StateUtils.reset(state, action.routes, action.index);
+ return {
+ ...state,
+ ...NavigationExperimental.StateUtils.reset(state, action.routes, action.index),
+ leftDrawerOpen: false,
+ rightDrawerOpen: false
+ };
+
+ case NavigationTypes.NAVIGATION_REPLACE:
+ return NavigationExperimental.StateUtils.replaceAtIndex(state, state.index, action.route);
case UsersTypes.LOGOUT_SUCCESS:
return NavigationExperimental.StateUtils.reset(state, initialState.routes, initialState.index);
diff --git a/app/reducers/views/drawer.js b/app/reducers/views/drawer.js
deleted file mode 100644
index c4f1e1c1b..000000000
--- a/app/reducers/views/drawer.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {combineReducers} from 'redux';
-import {ViewTypes} from 'app/constants';
-
-function channel(state = false, action) {
- switch (action.type) {
- case ViewTypes.TOGGLE_CHANNEL_DRAWER:
- return action.data;
-
- default:
- return state;
- }
-}
-
-export default combineReducers({
- channel
-});
-
diff --git a/app/reducers/views/index.js b/app/reducers/views/index.js
index 29acc036e..bb9fd29c2 100644
--- a/app/reducers/views/index.js
+++ b/app/reducers/views/index.js
@@ -4,14 +4,12 @@
import {combineReducers} from 'redux';
import channel from './channel';
-import drawer from './drawer';
import i18n from './i18n';
import login from './login';
import selectServer from './select_server';
export default combineReducers({
channel,
- drawer,
i18n,
login,
selectServer
diff --git a/app/scenes/channel/channel.js b/app/scenes/channel/channel.js
index 4f51f6602..dfac84d13 100644
--- a/app/scenes/channel/channel.js
+++ b/app/scenes/channel/channel.js
@@ -7,11 +7,8 @@ import {
StatusBar,
Text
} from 'react-native';
-import Drawer from 'react-native-drawer';
-import ChannelDrawer from 'app/components/channel_drawer';
import PostTextbox from 'app/components/post_textbox';
-import RightSidebarMenu from 'app/components/right_sidebar_menu';
import ChannelHeader from './channel_header';
import ChannelPostList from './channel_post_list';
@@ -23,6 +20,7 @@ export default class Channel extends React.PureComponent {
loadProfilesAndTeamMembersForDMSidebar: React.PropTypes.func.isRequired,
selectInitialChannel: React.PropTypes.func.isRequired,
openChannelDrawer: React.PropTypes.func.isRequired,
+ openRightMenuDrawer: React.PropTypes.func.isRequired,
handlePostDraftChanged: React.PropTypes.func.isRequired,
goToChannelInfo: React.PropTypes.func.isRequired
}).isRequired,
@@ -60,20 +58,16 @@ export default class Channel extends React.PureComponent {
});
};
- openRightSidebar = () => {
- this.refs.postTextbox.getWrappedInstance().blur();
- this.setState({rightSidebarOpen: true});
- };
-
- closeRightSidebar = () => {
- this.setState({rightSidebarOpen: false});
- };
-
openChannelDrawer = () => {
this.refs.postTextbox.getWrappedInstance().blur();
this.props.actions.openChannelDrawer();
}
+ openRightMenuDrawer = () => {
+ this.refs.postTextbox.getWrappedInstance().blur();
+ this.props.actions.openRightMenuDrawer();
+ }
+
render() {
const {
currentTeam,
@@ -93,36 +87,20 @@ export default class Channel extends React.PureComponent {
style={{flex: 1, backgroundColor: theme.centerChannelBg}}
>
-
- }
- side='right'
- tapToClose={true}
- onCloseStart={this.closeRightSidebar}
- openDrawerOffset={0.2}
- >
-
-
-
-
-
+ openLeftDrawer={this.openChannelDrawer}
+ openRightDrawer={this.openRightMenuDrawer}
+ goToChannelInfo={this.props.actions.goToChannelInfo}
+ />
+
+
);
}
diff --git a/app/scenes/channel/channel_container.js b/app/scenes/channel/channel_container.js
index 2b14d299e..d2a1fd243 100644
--- a/app/scenes/channel/channel_container.js
+++ b/app/scenes/channel/channel_container.js
@@ -4,18 +4,21 @@
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
+import {
+ goToChannelInfo,
+ openChannelDrawer,
+ openRightMenuDrawer
+} from 'app/actions/navigation';
import {
loadChannelsIfNecessary,
loadProfilesAndTeamMembersForDMSidebar,
selectInitialChannel,
handlePostDraftChanged
} from 'app/actions/views/channel';
-import {openChannelDrawer} from 'app/actions/views/drawer';
import {getCurrentChannel} from 'service/selectors/entities/channels';
import {getTheme} from 'service/selectors/entities/preferences';
import {getCurrentTeam} from 'service/selectors/entities/teams';
-import {goToChannelInfo} from 'app/actions/navigation';
import Channel from './channel';
@@ -36,6 +39,7 @@ function mapDispatchToProps(dispatch) {
loadProfilesAndTeamMembersForDMSidebar,
selectInitialChannel,
openChannelDrawer,
+ openRightMenuDrawer,
handlePostDraftChanged,
goToChannelInfo
}, dispatch)
diff --git a/app/scenes/channel_drawer/channel_drawer.js b/app/scenes/channel_drawer/channel_drawer.js
new file mode 100644
index 000000000..3bbbdbcb8
--- /dev/null
+++ b/app/scenes/channel_drawer/channel_drawer.js
@@ -0,0 +1,50 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React from 'react';
+
+import ChannelList from 'app/components/channel_drawer/channel_list';
+
+export default class ChannelDrawer extends React.PureComponent {
+ static propTypes = {
+ actions: React.PropTypes.shape({
+ selectChannel: React.PropTypes.func.isRequired,
+ viewChannel: React.PropTypes.func.isRequired,
+ closeDMChannel: React.PropTypes.func.isRequired,
+ closeDrawers: React.PropTypes.func.isRequired
+ }).isRequired,
+ currentTeam: React.PropTypes.object,
+ currentChannel: React.PropTypes.object,
+ channels: React.PropTypes.object,
+ channelMembers: React.PropTypes.object,
+ theme: React.PropTypes.object.isRequired
+ };
+
+ selectChannel = (id) => {
+ this.props.actions.selectChannel(id);
+ this.props.actions.closeDrawers();
+ }
+
+ render() {
+ const {
+ currentChannel,
+ currentTeam,
+ channels,
+ channelMembers,
+ theme
+ } = this.props;
+
+ return (
+
+ );
+ }
+}
diff --git a/app/scenes/channel_drawer/channel_drawer_container.js b/app/scenes/channel_drawer/channel_drawer_container.js
new file mode 100644
index 000000000..cd60ec371
--- /dev/null
+++ b/app/scenes/channel_drawer/channel_drawer_container.js
@@ -0,0 +1,38 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {bindActionCreators} from 'redux';
+import {connect} from 'react-redux';
+
+import {closeDrawers} from 'app/actions/navigation';
+import {closeDMChannel} from 'app/actions/views/channel';
+
+import {selectChannel, viewChannel} from 'service/actions/channels';
+import {getChannelsByCategory, getCurrentChannel} from 'service/selectors/entities/channels';
+import {getTheme} from 'service/selectors/entities/preferences';
+import {getCurrentTeam} from 'service/selectors/entities/teams';
+
+import ChannelDrawer from './channel_drawer.js';
+
+function mapStateToProps(state) {
+ return {
+ currentTeam: getCurrentTeam(state),
+ currentChannel: getCurrentChannel(state),
+ channels: getChannelsByCategory(state),
+ channelMembers: state.entities.channels.myMembers,
+ theme: getTheme(state)
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({
+ selectChannel,
+ viewChannel,
+ closeDMChannel,
+ closeDrawers
+ }, dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(ChannelDrawer);
diff --git a/app/components/channel_drawer/index.js b/app/scenes/channel_drawer/index.js
similarity index 71%
rename from app/components/channel_drawer/index.js
rename to app/scenes/channel_drawer/index.js
index 859043ad5..79e9d4d33 100644
--- a/app/components/channel_drawer/index.js
+++ b/app/scenes/channel_drawer/index.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import ChannelDrawerContainer from './channel_drawer_container';
diff --git a/app/scenes/index.js b/app/scenes/index.js
index 96fb53b6d..472ecd989 100644
--- a/app/scenes/index.js
+++ b/app/scenes/index.js
@@ -2,21 +2,27 @@
// See License.txt for license information.
import Channel from './channel';
+import ChannelDrawer from './channel_drawer';
+import ChannelInfo from './channel_info';
+import LoadTeam from './load_team';
import Login from './login/login_container.js';
+import RightMenuDrawer from './right_menu_drawer';
import Root from './root/root_container.js';
import Search from './search/search_container.js';
import SelectServer from './select_server/select_server_container.js';
import SelectTeam from './select_team/select_team_container.js';
-import ChannelInfo from './channel_info';
const scenes = {
- Root,
- SelectServer,
- Login,
- SelectTeam,
ChannelView: Channel, // Special case the name for this one to avoid ambiguity
+ ChannelDrawer,
+ ChannelInfo,
+ LoadTeam,
+ Login,
+ RightMenuDrawer,
+ Root,
Search,
- ChannelInfo
+ SelectServer,
+ SelectTeam
};
export function getComponentForScene(key) {
diff --git a/app/scenes/load_team/index.js b/app/scenes/load_team/index.js
new file mode 100644
index 000000000..e1315349f
--- /dev/null
+++ b/app/scenes/load_team/index.js
@@ -0,0 +1,6 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import LoadTeamContainer from './load_team_container';
+
+export default LoadTeamContainer;
diff --git a/app/scenes/load_team/load_team.js b/app/scenes/load_team/load_team.js
new file mode 100644
index 000000000..ff4f3da98
--- /dev/null
+++ b/app/scenes/load_team/load_team.js
@@ -0,0 +1,60 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import React from 'react';
+
+import Loading from 'app/components/loading';
+
+import {RequestStatus} from 'service/constants';
+
+export default class LoadTeam extends React.Component {
+ static propTypes = {
+ teams: React.PropTypes.object.isRequired,
+ myMembers: React.PropTypes.object.isRequired,
+ teamsRequest: React.PropTypes.object.isRequired,
+ currentTeam: React.PropTypes.object,
+ actions: React.PropTypes.shape({
+ goToChannelView: React.PropTypes.func.isRequired,
+ handleTeamChange: React.PropTypes.func.isRequired,
+ initWebsocket: React.PropTypes.func.isRequired
+ }).isRequired
+ };
+
+ componentWillMount() {
+ this.props.actions.initWebsocket();
+ }
+
+ componentDidMount() {
+ const {currentTeam, myMembers, teams} = this.props;
+
+ if (currentTeam) {
+ this.onSelectTeam(currentTeam);
+ } else if (!currentTeam) {
+ this.selectFirstTeam(teams, myMembers);
+ }
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (this.props.teamsRequest.status === RequestStatus.STARTED &&
+ nextProps.teamsRequest.status === RequestStatus.SUCCESS) {
+ this.selectFirstTeam(nextProps.teams, nextProps.myMembers);
+ }
+ }
+
+ selectFirstTeam(allTeams, myMembers) {
+ const teams = Object.keys(myMembers).map((key) => allTeams[key]);
+ const firstTeam = Object.values(teams).sort((a, b) => a.display_name.localeCompare(b.display_name))[0];
+
+ if (firstTeam) {
+ this.onSelectTeam(firstTeam);
+ }
+ }
+
+ onSelectTeam(team) {
+ this.props.actions.handleTeamChange(team).then(this.props.actions.goToChannelView);
+ }
+
+ render() {
+ return ;
+ }
+}
diff --git a/app/scenes/load_team/load_team_container.js b/app/scenes/load_team/load_team_container.js
new file mode 100644
index 000000000..6c5ac5bb6
--- /dev/null
+++ b/app/scenes/load_team/load_team_container.js
@@ -0,0 +1,35 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import {bindActionCreators} from 'redux';
+import {connect} from 'react-redux';
+
+import {goToChannelView} from 'app/actions/views/load_team';
+import {handleTeamChange} from 'app/actions/views/select_team';
+
+import {init} from 'service/actions/websocket';
+import {getCurrentTeam} from 'service/selectors/entities/teams';
+
+import LoadTeam from './load_team.js';
+
+function mapStateToProps(state) {
+ return {
+ config: state.entities.general.config,
+ teamsRequest: state.requests.teams.allTeams,
+ teams: state.entities.teams.teams,
+ currentTeam: getCurrentTeam(state),
+ myMembers: state.entities.teams.myMembers
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({
+ goToChannelView,
+ handleTeamChange,
+ initWebsocket: init
+ }, dispatch)
+ };
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(LoadTeam);
diff --git a/app/scenes/login/login.js b/app/scenes/login/login.js
index 1dab9dcba..91abd37fb 100644
--- a/app/scenes/login/login.js
+++ b/app/scenes/login/login.js
@@ -35,7 +35,7 @@ class Login extends Component {
componentWillReceiveProps(nextProps) {
if (this.props.loginRequest.status === RequestStatus.STARTED && nextProps.loginRequest.status === RequestStatus.SUCCESS) {
- this.props.actions.handleSuccessfulLogin().then(this.props.actions.goToSelectTeam);
+ this.props.actions.handleSuccessfulLogin().then(this.props.actions.goToLoadTeam);
}
}
diff --git a/app/scenes/login/login_container.js b/app/scenes/login/login_container.js
index 823b5006b..bc348dd02 100644
--- a/app/scenes/login/login_container.js
+++ b/app/scenes/login/login_container.js
@@ -6,8 +6,7 @@ import {connect} from 'react-redux';
import {getClientConfig, getLicenseConfig} from 'service/actions/general';
import LoginActions from 'app/actions/views/login';
-import {updateRootStorage} from 'app/actions/storage';
-import {goToSelectTeam} from 'app/actions/navigation';
+import {goToLoadTeam} from 'app/actions/navigation';
import {login} from 'service/actions/users';
import Login from './login.js';
@@ -27,11 +26,10 @@ function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
...LoginActions,
- updateRootStorage,
login,
getClientConfig,
getLicenseConfig,
- goToSelectTeam
+ goToLoadTeam
}, dispatch)
};
}
diff --git a/app/scenes/right_menu_drawer/index.js b/app/scenes/right_menu_drawer/index.js
new file mode 100644
index 000000000..ef150b1e5
--- /dev/null
+++ b/app/scenes/right_menu_drawer/index.js
@@ -0,0 +1,6 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import RightMenuDrawerContainer from './right_menu_drawer_container';
+
+export default RightMenuDrawerContainer;
diff --git a/app/components/right_sidebar_menu/right_sidebar_menu.js b/app/scenes/right_menu_drawer/right_menu_drawer.js
similarity index 80%
rename from app/components/right_sidebar_menu/right_sidebar_menu.js
rename to app/scenes/right_menu_drawer/right_menu_drawer.js
index 6d94777c0..fad51b302 100644
--- a/app/components/right_sidebar_menu/right_sidebar_menu.js
+++ b/app/scenes/right_menu_drawer/right_menu_drawer.js
@@ -2,16 +2,17 @@
// See License.txt for license information.
import React from 'react';
-
-import FormattedText from 'app/components/formatted_text';
-import Icon from 'react-native-vector-icons/FontAwesome';
-import Item from './components/item';
import {
ScrollView,
StyleSheet,
Text,
View
} from 'react-native';
+import Icon from 'react-native-vector-icons/FontAwesome';
+
+import FormattedText from 'app/components/formatted_text';
+
+import RightMenuDrawerItem from './right_menu_drawer_item';
const Styles = StyleSheet.create({
container: {
@@ -36,43 +37,28 @@ const Styles = StyleSheet.create({
}
});
-export default class RightSidebarMenu extends React.Component {
+export default class RightMenuDrawer extends React.Component {
static propTypes = {
actions: React.PropTypes.shape({
- goBack: React.PropTypes.func.isRequired,
goToFlaggedPosts: React.PropTypes.func.isRequired,
goToRecentMentions: React.PropTypes.func.isRequired,
+ goToSelectTeam: React.PropTypes.func.isRequired,
logout: React.PropTypes.func.isRequired
- }).isRequired,
- onClose: React.PropTypes.func.isRequired
- }
-
- goToRecentMentions = () => {
- this.props.onClose();
- this.props.actions.goToRecentMentions();
- }
-
- goToFlaggedPosts = () => {
- this.props.onClose();
- this.props.actions.goToFlaggedPosts();
- }
-
- goToTeamSelection = () => {
- this.props.actions.goBack();
+ }).isRequired
}
render() {
return (
- -
+
{'@'}
-
- -
+
+
-
+
- -
+
-
- -
+
+
-
- -
+
+
-
+
- -
+
-
- -
+
+
-
- -
+
+
-
+
- -
+
-
- -
+
+
-
- -
+
+
-
+
- -
+
-
+
);
}
diff --git a/app/components/right_sidebar_menu/right_sidebar_menu_container.js b/app/scenes/right_menu_drawer/right_menu_drawer_container.js
similarity index 70%
rename from app/components/right_sidebar_menu/right_sidebar_menu_container.js
rename to app/scenes/right_menu_drawer/right_menu_drawer_container.js
index 0620c7cf3..28c5dd489 100644
--- a/app/components/right_sidebar_menu/right_sidebar_menu_container.js
+++ b/app/scenes/right_menu_drawer/right_menu_drawer_container.js
@@ -4,10 +4,12 @@
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
-import {goBack, goToFlaggedPosts, goToRecentMentions} from 'app/actions/navigation';
+import {goBack} from 'app/actions/navigation';
+import {goToFlaggedPosts, goToRecentMentions, goToSelectTeam} from 'app/actions/views/right_menu_drawer';
+
import {logout} from 'service/actions/users';
-import RightSidebarMenu from './right_sidebar_menu';
+import RightMenuDrawer from './right_menu_drawer';
function mapStateToProps(state, ownProps) {
return ownProps;
@@ -19,9 +21,10 @@ function mapDispatchToProps(dispatch) {
goBack,
goToFlaggedPosts,
goToRecentMentions,
+ goToSelectTeam,
logout
}, dispatch)
};
}
-export default connect(mapStateToProps, mapDispatchToProps)(RightSidebarMenu);
+export default connect(mapStateToProps, mapDispatchToProps)(RightMenuDrawer);
diff --git a/app/components/right_sidebar_menu/components/item.js b/app/scenes/right_menu_drawer/right_menu_drawer_item.js
similarity index 94%
rename from app/components/right_sidebar_menu/components/item.js
rename to app/scenes/right_menu_drawer/right_menu_drawer_item.js
index 0942bb603..3a73e829f 100644
--- a/app/components/right_sidebar_menu/components/item.js
+++ b/app/scenes/right_menu_drawer/right_menu_drawer_item.js
@@ -16,7 +16,7 @@ const Styles = StyleSheet.create({
}
});
-export default class Item extends React.Component {
+export default class MainMenuItem extends React.Component {
static propTypes = {
children: React.PropTypes.node,
onPress: React.PropTypes.func,
diff --git a/app/scenes/root/root.js b/app/scenes/root/root.js
index b77d9fd09..c1b8a6232 100644
--- a/app/scenes/root/root.js
+++ b/app/scenes/root/root.js
@@ -12,9 +12,8 @@ export default class Root extends React.Component {
logoutRequest: React.PropTypes.object,
loginRequest: React.PropTypes.object,
actions: React.PropTypes.shape({
- goToChannelView: React.PropTypes.func,
+ goToLoadTeam: React.PropTypes.func,
goToSelectServer: React.PropTypes.func,
- goToSelectTeam: React.PropTypes.func,
loadStorage: React.PropTypes.func,
removeStorage: React.PropTypes.func,
setStoreFromLocalData: React.PropTypes.func,
@@ -24,7 +23,6 @@ export default class Root extends React.Component {
componentDidMount() {
// Any initialization logic for navigation, setting up the client, etc should go here
-
this.init();
}
@@ -53,7 +51,7 @@ export default class Root extends React.Component {
if (this.props.credentials.token && this.props.credentials.url) {
this.props.actions.setStoreFromLocalData(this.props.credentials).then(() => {
if (this.props.loginRequest.status === RequestStatus.SUCCESS) {
- this.props.actions.goToSelectTeam();
+ this.props.actions.goToLoadTeam();
} else {
this.props.actions.goToSelectServer();
}
diff --git a/app/scenes/root/root_container.js b/app/scenes/root/root_container.js
index 53fe0d11e..bcbf4bb1a 100644
--- a/app/scenes/root/root_container.js
+++ b/app/scenes/root/root_container.js
@@ -6,7 +6,7 @@ import {connect} from 'react-redux';
import {loadStorage, removeStorage} from 'app/actions/storage';
import {goToSelectServer, setStoreFromLocalData} from 'app/actions/views/root';
-import {goToSelectTeam, goToChannelView} from 'app/actions/navigation';
+import {goToLoadTeam} from 'app/actions/navigation';
import {resetLogout} from 'service/actions/users';
import Root from './root';
@@ -23,9 +23,8 @@ function mapStateToProps(state, ownProps) {
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
- goToChannelView,
+ goToLoadTeam,
goToSelectServer,
- goToSelectTeam,
loadStorage,
removeStorage,
setStoreFromLocalData,
diff --git a/app/scenes/select_team/select_team.js b/app/scenes/select_team/select_team.js
index 5a8807b35..5eb6ab50c 100644
--- a/app/scenes/select_team/select_team.js
+++ b/app/scenes/select_team/select_team.js
@@ -1,68 +1,32 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import React, {Component, PropTypes} from 'react';
+import React from 'react';
import {View, Image, Text} from 'react-native';
import Button from 'react-native-button';
import Icon from 'react-native-vector-icons/MaterialIcons';
-import ErrorText from 'app/components/error_text';
import FormattedText from 'app/components/formatted_text';
-import Loading from 'app/components/loading';
import {GlobalStyles} from 'app/styles';
import logo from 'assets/images/logo.png';
-import {RequestStatus} from 'service/constants';
-
-export default class SelectTeam extends Component {
+export default class SelectTeam extends React.Component {
static propTypes = {
- config: PropTypes.object.isRequired,
- teams: PropTypes.object.isRequired,
- myMembers: PropTypes.object.isRequired,
- teamsRequest: PropTypes.object.isRequired,
- currentTeam: PropTypes.object,
- actions: PropTypes.object.isRequired
+ config: React.PropTypes.object.isRequired,
+ teams: React.PropTypes.object.isRequired,
+ myMembers: React.PropTypes.object.isRequired,
+ actions: React.PropTypes.shape({
+ goBackToChannelView: React.PropTypes.func.isRequired,
+ handleTeamChange: React.PropTypes.func.isRequired
+ }).isRequired
};
- componentWillMount() {
- this.props.actions.websocket();
- }
-
- componentDidMount() {
- const {currentTeam, myMembers, teams} = this.props;
-
- if (currentTeam) {
- this.onSelectTeam(currentTeam);
- } else if (!currentTeam) {
- this.selectFirstTeam(teams, myMembers);
- }
- }
-
- componentWillReceiveProps(nextProps) {
- if (this.props.teamsRequest.status === RequestStatus.STARTED &&
- nextProps.teamsRequest.status === RequestStatus.SUCCESS) {
- this.selectFirstTeam(nextProps.teams, nextProps.myMembers);
- }
- }
-
- selectFirstTeam(allTeams, myMembers) {
- const teams = Object.keys(myMembers).map((key) => allTeams[key]);
- const firstTeam = Object.values(teams).sort((a, b) => a.display_name.localeCompare(b.display_name))[0];
- if (firstTeam) {
- this.onSelectTeam(firstTeam);
- }
- }
-
onSelectTeam(team) {
- this.props.actions.handleTeamChange(team).then(this.props.actions.goToChannelView);
+ this.props.actions.handleTeamChange(team).then(this.props.actions.goBackToChannelView);
}
render() {
- if (this.props.teamsRequest.status === RequestStatus.STARTED) {
- return ;
- }
-
const teams = [];
for (const id of Object.keys(this.props.teams)) {
const team = this.props.teams[id];
@@ -106,7 +70,6 @@ export default class SelectTeam extends Component {
defaultMessage='Your teams:'
/>
{teams}
-
);
}
diff --git a/app/scenes/select_team/select_team_container.js b/app/scenes/select_team/select_team_container.js
index fbacab8e2..17323e12e 100644
--- a/app/scenes/select_team/select_team_container.js
+++ b/app/scenes/select_team/select_team_container.js
@@ -4,13 +4,12 @@
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
+import {goBack} from 'app/actions/navigation';
import {handleTeamChange} from 'app/actions/views/select_team';
-import {init as websocket} from 'service/actions/websocket';
-import {updateRootStorage, loadTeamStorage} from 'app/actions/storage';
-import {goToChannelView} from 'app/actions/navigation';
+
import {getCurrentTeam} from 'service/selectors/entities/teams';
-import SelectTeamView from './select_team.js';
+import SelectTeam from './select_team.js';
function mapStateToProps(state) {
return {
@@ -25,13 +24,10 @@ function mapStateToProps(state) {
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
- goToChannelView,
- updateRootStorage,
- loadTeamStorage,
- handleTeamChange,
- websocket
+ goBackToChannelView: goBack,
+ handleTeamChange
}, dispatch)
};
}
-export default connect(mapStateToProps, mapDispatchToProps)(SelectTeamView);
+export default connect(mapStateToProps, mapDispatchToProps)(SelectTeam);
diff --git a/test/app/reducers/navigation.test.js b/test/app/reducers/navigation.test.js
index 836d4377d..ab5395fc0 100644
--- a/test/app/reducers/navigation.test.js
+++ b/test/app/reducers/navigation.test.js
@@ -22,7 +22,11 @@ describe('Reducers.Navigation', () => {
assert.deepEqual(state, {
index: 0,
- routes: [Routes.Root]
+ routes: [Routes.Root],
+ leftDrawerOpen: false,
+ leftDrawerRoute: null,
+ rightDrawerOpen: false,
+ rightDrawerRoute: null
}, 'initial state');
});
@@ -31,44 +35,38 @@ describe('Reducers.Navigation', () => {
it('first push', () => {
state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake'}
});
- assert.deepEqual(state, {
- index: 1,
- routes: [Routes.Root, {key: 'fake'}]
- });
+ assert.equal(state.index, 1);
+ assert.deepEqual(state.routes, [Routes.Root, {key: 'fake'}]);
});
it('second push', () => {
state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake2'}
});
- assert.deepEqual(state, {
- index: 1,
- routes: [Routes.Root, {key: 'fake'}, {key: 'fake2'}]
- });
+ assert.equal(state.index, 2);
+ assert.deepEqual(state.routes, [Routes.Root, {key: 'fake2'}]);
+ });
+
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_JUMP,
+ key: Routes.Root.key
});
it('push when not at head of stack', () => {
state = reduceAndFreeze(state, {
- type: NavigationTypes.JUMP,
- key: Routes.key.root
- });
-
- state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake3'}
});
// The next route on the stack is replaced, but anything past that is left unchanged
- assert.deepEqual(state, {
- index: 1,
- routes: [Routes.Root, {key: 'fake3'}, {key: 'fake2'}]
- });
+ assert.equal(state.index, 1);
+ assert.deepEqual(state.routes, [Routes.Root, {key: 'fake3'}, {key: 'fake2'}]);
});
});
@@ -76,45 +74,146 @@ describe('Reducers.Navigation', () => {
let state = initialState();
state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake'}
});
state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake2'}
});
it('first pop', () => {
state = reduceAndFreeze(state, {
- type: NavigationTypes.POP
+ type: NavigationTypes.NAVIGATION_POP
});
- assert.deepEqual(state, {
- index: 1,
- routes: [Routes.Root, {key: 'fake'}]
- });
+ assert.equal(state.index, 1);
+ assert.deepEqual(state.routes, [Routes.Root, {key: 'fake'}]);
});
it('second pop', () => {
state = reduceAndFreeze(state, {
- type: NavigationTypes.POP
+ type: NavigationTypes.NAVIGATION_POP
});
- assert.deepEqual(state, {
- index: 0,
- routes: [Routes.Root]
- });
+ assert.equal(state.index, 0);
+ assert.deepEqual(state.routes, [Routes.Root]);
});
it('pop last entry on stack', () => {
state = reduceAndFreeze(state, {
- type: NavigationTypes.POP
+ type: NavigationTypes.NAVIGATION_POP
});
- assert.deepEqual(state, {
- index: 0,
- routes: [Routes.Root]
+ // Nothing happens
+ assert.equal(state.index, 0);
+ assert.deepEqual(state.routes, [Routes.Root]);
+ });
+
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_PUSH,
+ route: {key: 'fake3'}
+ });
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_OPEN_LEFT_DRAWER,
+ route: {key: 'fake'}
+ });
+
+ it('popping to close left drawer', () => {
+ state.reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_POP
});
+
+ // Routes not popped, but drawer closed
+ assert.equal(state.index, 1);
+ assert.deepEqual(state.routes, [Routes.Root, {key: 'fake3'}]);
+ assert.equal(state.leftDrawerOpen, false);
+ assert.equal(state.rightDrawerOpen, false);
+ });
+
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_OPEN_RIGHT_DRAWER,
+ route: {key: 'fake'}
+ });
+
+ it('popping to close right drawer', () => {
+ state.reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_POP
+ });
+
+ // Routes not popped, but drawer closed
+ assert.equal(state.index, 1);
+ assert.deepEqual(state.routes, [Routes.Root, {key: 'fake'}]);
+ assert.equal(state.leftDrawerOpen, false);
+ assert.equal(state.rightDrawerOpen, false);
+ });
+ });
+
+ it('NAVIGATION_OPEN_LEFT_DRAWER', () => {
+ let state = initialState();
+
+ it('open left drawer', () => {
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_OPEN_LEFT_DRAWER,
+ route: {key: 'fake'}
+ });
+
+ assert.equal(state.index, 0);
+ assert.deepEqual(state.routes, [Routes.Root]);
+ assert.equal(state.leftDrawerOpen, true);
+ assert.deepEqual(state.leftDrawerRoute, {key: 'fake'});
+ assert.equal(state.rightDrawerOpen, false);
+ });
+ });
+
+ it('NAVIGATION_OPEN_RIGHT_DRAWER', () => {
+ let state = initialState();
+
+ it('open right drawer', () => {
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_OPEN_RIGHT_DRAWER,
+ route: {key: 'fake'}
+ });
+
+ assert.equal(state.index, 0);
+ assert.deepEqual(state.routes, [Routes.Root]);
+ assert.equal(state.leftDrawerOpen, false);
+ assert.equal(state.rightDrawerOpen, true);
+ assert.deepEqual(state.rightDrawerRoute, {key: 'fake'});
+ });
+ });
+
+ it('NAVIGATION_CLOSE_DRAWERS', () => {
+ let state = initialState();
+
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_OPEN_LEFT_DRAWER,
+ route: {key: 'fake'}
+ });
+
+ it('close left drawer', () => {
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_CLOSE_DRAWERS
+ });
+
+ assert.equal(state.index, 0);
+ assert.deepEqual(state.routes, [Routes.Root]);
+ assert.equal(state.leftDrawerOpen, false);
+ });
+
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_OPEN_RIGHT_DRAWER,
+ route: {key: 'fake'}
+ });
+
+ it('close right drawer', () => {
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_CLOSE_DRAWERS
+ });
+
+ assert.equal(state.index, 0);
+ assert.deepEqual(state.routes, [Routes.Root]);
+ assert.equal(state.rightDrawerOpen, false);
});
});
@@ -122,11 +221,11 @@ describe('Reducers.Navigation', () => {
let state = initialState();
state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake'}
});
state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake2'}
});
@@ -137,10 +236,8 @@ describe('Reducers.Navigation', () => {
});
// The rest of the stack is preserved
- assert.deepEqual(state, {
- index: 0,
- routes: [Routes.Root, {key: 'fake'}, {key: 'fake2'}]
- });
+ assert.equal(state.index, 0);
+ assert.deepEqual(state.routes, [Routes.Root, {key: 'fake'}, {key: 'fake2'}]);
});
it('jump forward', () => {
@@ -149,10 +246,8 @@ describe('Reducers.Navigation', () => {
key: 'fake'
});
- assert.deepEqual(state, {
- index: 2,
- routes: [Routes.Root, {key: 'fake'}, {key: 'fake2'}]
- });
+ assert.equal(state.index, 2);
+ assert.deepEqual(state.routes, [Routes.Root, {key: 'fake'}, {key: 'fake2'}]);
});
});
@@ -160,11 +255,11 @@ describe('Reducers.Navigation', () => {
let state = initialState();
state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake'}
});
state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake2'}
});
@@ -175,10 +270,8 @@ describe('Reducers.Navigation', () => {
});
// The rest of the stack is preserved
- assert.deepEqual(state, {
- index: 0,
- routes: [Routes.Root, {key: 'fake'}, {key: 'fake2'}]
- });
+ assert.equal(state.index, 0);
+ assert.deepEqual(state.routes, [Routes.Root, {key: 'fake'}, {key: 'fake2'}]);
});
it('jump forward', () => {
@@ -187,10 +280,8 @@ describe('Reducers.Navigation', () => {
index: 2
});
- assert.deepEqual(state, {
- index: 2,
- routes: [Routes.Root, {key: 'fake'}, {key: 'fake2'}]
- });
+ assert.equal(state.index, 2);
+ assert.deepEqual(state.routes, [Routes.Root, {key: 'fake'}, {key: 'fake2'}]);
});
});
@@ -198,11 +289,11 @@ describe('Reducers.Navigation', () => {
let state = initialState();
state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake'}
});
state = reduceAndFreeze(state, {
- type: NavigationTypes.PUSH,
+ type: NavigationTypes.NAVIGATION_PUSH,
route: {key: 'fake2'}
});
@@ -215,9 +306,67 @@ describe('Reducers.Navigation', () => {
// The navigation state is wiped out and replaced with the new state
assert.deepEqual(state, {
+ index: 1,
+ routes: [{key: 'fake3'}, {key: 'fake4'}],
+ leftDrawerOpen: false,
+ leftDrawerRoute: null,
+ rightDrawerOpen: false,
+ rightDrawerRoute: null
+ });
+ });
+
+ state = initialState();
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_PUSH,
+ route: {key: 'fake'}
+ });
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_OPEN_LEFT_DRAWER,
+ route: {key: 'fake2'}
+ });
+
+ it('reset with left drawer open', () => {
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_RESET,
index: 1,
routes: [{key: 'fake3'}, {key: 'fake4'}]
});
+
+ assert.deepEqual(state, {
+ index: 1,
+ routes: [{key: 'fake3'}, {key: 'fake4'}],
+ leftDrawerOpen: false,
+ leftDrawerRoute: {key: 'fake2'}, // Leave drawer routes in tact so that the close animation still works
+ rightDrawerOpen: false,
+ rightDrawerRoute: null
+ });
+ });
+
+ state = initialState();
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_PUSH,
+ route: {key: 'fake'}
+ });
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_OPEN_RIGHT_DRAWER,
+ route: {key: 'fake2'}
+ });
+
+ it('reset with left drawer open', () => {
+ state = reduceAndFreeze(state, {
+ type: NavigationTypes.NAVIGATION_RESET,
+ index: 1,
+ routes: [{key: 'fake3'}, {key: 'fake4'}]
+ });
+
+ assert.deepEqual(state, {
+ index: 1,
+ routes: [{key: 'fake3'}, {key: 'fake4'}],
+ leftDrawerOpen: false,
+ leftDrawerRoute: null,
+ rightDrawerOpen: false,
+ rightDrawerRoute: {key: 'fake2'} // Leave drawer routes in tact so that the close animation still works
+ });
});
});
});