Reorganized navigation (#181)
* Moved ChannelDrawer into its own scene * Moved RightSideMenu to a separate route * Moved title back above scenes * Moved right side menu into a separate scene * Reorganized navigation so that it centers around ChannelView when logged in * Stopped using NavigationExperimental to manage drawers * Fixed copyright date * Added unit tests for navigation drawers * Renamed RightSideMenu to RightMenuDrawer * Removed unnecessary ChannelDrawer style
This commit is contained in:
parent
d180f324c5
commit
cea81f6497
36 changed files with 780 additions and 515 deletions
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
14
app/actions/views/load_team.js
Normal file
14
app/actions/views/load_team.js
Normal file
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
50
app/actions/views/right_menu_drawer.js
Normal file
50
app/actions/views/right_menu_drawer.js
Normal file
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
|
@ -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 (
|
||||
<Drawer
|
||||
ref={(ref) => {
|
||||
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={
|
||||
<ChannelList
|
||||
currentTeam={currentTeam}
|
||||
currentChannel={currentChannel}
|
||||
channels={channels}
|
||||
channelMembers={channelMembers}
|
||||
theme={theme}
|
||||
onSelectChannel={this.selectChannel}
|
||||
onViewChannel={this.props.actions.viewChannel}
|
||||
handleCloseDM={this.props.actions.closeDMChannel}
|
||||
closeChannelDrawer={this.props.actions.closeChannelDrawer}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{this.props.children}
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<NavigationExperimental.Card
|
||||
{...cardProps}
|
||||
style={NavigationExperimental.Card.PagerStyleInterpolator.forHorizontal({
|
||||
...cardProps
|
||||
})}
|
||||
style={style}
|
||||
renderScene={this.renderScene}
|
||||
key={scene.key}
|
||||
/>
|
||||
|
|
@ -52,11 +63,9 @@ class Router extends React.Component {
|
|||
});
|
||||
|
||||
return (
|
||||
<View style={{flex: 1, flexDirection: 'column-reverse'}}>
|
||||
<View style={{flex: 1}}>
|
||||
{renderedScenes}
|
||||
</View>
|
||||
<View style={{flex: 1}}>
|
||||
{title}
|
||||
{renderedScenes}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
@ -79,11 +88,15 @@ class Router extends React.Component {
|
|||
};
|
||||
|
||||
renderScene = ({scene}) => {
|
||||
const SceneComponent = getComponentForScene(scene.route.key);
|
||||
|
||||
return <SceneComponent {...scene.route.props}/>;
|
||||
return this.renderRoute(scene.route);
|
||||
};
|
||||
|
||||
renderRoute = (route) => {
|
||||
const SceneComponent = getComponentForScene(route.key);
|
||||
|
||||
return <SceneComponent {...route.props}/>;
|
||||
}
|
||||
|
||||
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 (
|
||||
<NavigationExperimental.Transitioner
|
||||
style={{flex: 1}}
|
||||
navigationState={this.props.navigation}
|
||||
render={this.renderTransition}
|
||||
configureTransition={this.configureTransition}
|
||||
/>
|
||||
<Drawer
|
||||
open={leftDrawerOpen}
|
||||
type='displace'
|
||||
content={leftDrawerContent}
|
||||
tapToClose={true}
|
||||
openDrawerOffset={0.2}
|
||||
onRequestClose={this.props.actions.closeDrawers}
|
||||
>
|
||||
<Drawer
|
||||
open={rightDrawerOpen}
|
||||
type='displace'
|
||||
side='right'
|
||||
content={rightDrawerContent}
|
||||
tapToClose={true}
|
||||
openDrawerOffset={0.2}
|
||||
onRequestClose={this.props.actions.closeDrawers}
|
||||
>
|
||||
<NavigationExperimental.Transitioner
|
||||
style={{flex: 1}}
|
||||
navigationState={this.props.navigation}
|
||||
render={this.renderTransition}
|
||||
configureTransition={this.configureTransition}
|
||||
/>
|
||||
</Drawer>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
@ -112,6 +161,7 @@ function mapStateToProps(state) {
|
|||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
closeDrawers,
|
||||
goBack
|
||||
}, dispatch)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
>
|
||||
<StatusBar barStyle='default'/>
|
||||
<ChannelDrawer
|
||||
currentTeam={currentTeam}
|
||||
<ChannelHeader
|
||||
currentChannel={currentChannel}
|
||||
theme={theme}
|
||||
>
|
||||
<Drawer
|
||||
open={this.state.rightSidebarOpen}
|
||||
type='displace'
|
||||
content={<RightSidebarMenu onClose={this.closeRightSidebar}/>}
|
||||
side='right'
|
||||
tapToClose={true}
|
||||
onCloseStart={this.closeRightSidebar}
|
||||
openDrawerOffset={0.2}
|
||||
>
|
||||
<ChannelHeader
|
||||
currentChannel={currentChannel}
|
||||
openLeftDrawer={this.openChannelDrawer}
|
||||
openRightDrawer={this.openRightSidebar}
|
||||
goToChannelInfo={this.props.actions.goToChannelInfo}
|
||||
/>
|
||||
<ChannelPostList channel={currentChannel}/>
|
||||
<PostTextbox
|
||||
ref='postTextbox'
|
||||
value={this.props.postDraft}
|
||||
teamId={currentChannel.team_id}
|
||||
channelId={currentChannel.id}
|
||||
onChangeText={this.props.actions.handlePostDraftChanged}
|
||||
/>
|
||||
</Drawer>
|
||||
</ChannelDrawer>
|
||||
openLeftDrawer={this.openChannelDrawer}
|
||||
openRightDrawer={this.openRightMenuDrawer}
|
||||
goToChannelInfo={this.props.actions.goToChannelInfo}
|
||||
/>
|
||||
<ChannelPostList channel={currentChannel}/>
|
||||
<PostTextbox
|
||||
ref='postTextbox'
|
||||
value={this.props.postDraft}
|
||||
teamId={currentChannel.team_id}
|
||||
channelId={currentChannel.id}
|
||||
onChangeText={this.props.actions.handlePostDraftChanged}
|
||||
/>
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
50
app/scenes/channel_drawer/channel_drawer.js
Normal file
50
app/scenes/channel_drawer/channel_drawer.js
Normal file
|
|
@ -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 (
|
||||
<ChannelList
|
||||
currentTeam={currentTeam}
|
||||
currentChannel={currentChannel}
|
||||
channels={channels}
|
||||
channelMembers={channelMembers}
|
||||
theme={theme}
|
||||
onSelectChannel={this.selectChannel}
|
||||
onViewChannel={this.props.actions.viewChannel}
|
||||
handleCloseDM={this.props.actions.closeDMChannel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
38
app/scenes/channel_drawer/channel_drawer_container.js
Normal file
38
app/scenes/channel_drawer/channel_drawer_container.js
Normal file
|
|
@ -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);
|
||||
|
|
@ -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';
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
6
app/scenes/load_team/index.js
Normal file
6
app/scenes/load_team/index.js
Normal file
|
|
@ -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;
|
||||
60
app/scenes/load_team/load_team.js
Normal file
60
app/scenes/load_team/load_team.js
Normal file
|
|
@ -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 <Loading/>;
|
||||
}
|
||||
}
|
||||
35
app/scenes/load_team/load_team_container.js
Normal file
35
app/scenes/load_team/load_team_container.js
Normal file
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
6
app/scenes/right_menu_drawer/index.js
Normal file
6
app/scenes/right_menu_drawer/index.js
Normal file
|
|
@ -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;
|
||||
|
|
@ -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 (
|
||||
<ScrollView style={Styles.container}>
|
||||
<Item onPress={this.goToRecentMentions}>
|
||||
<RightMenuDrawerItem onPress={this.props.actions.goToRecentMentions}>
|
||||
<Text style={[Styles.icon, Styles.mentionIcon]}>{'@'}</Text>
|
||||
<FormattedText
|
||||
style={Styles.itemText}
|
||||
id='sidebar_right_menu.recentMentions'
|
||||
defaultMessage='Recent Mentions'
|
||||
/>
|
||||
</Item>
|
||||
<Item onPress={this.goToFlaggedPosts}>
|
||||
</RightMenuDrawerItem>
|
||||
<RightMenuDrawerItem onPress={this.props.actions.goToFlaggedPosts}>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='flag'
|
||||
|
|
@ -82,9 +68,9 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='sidebar_right_menu.flagged'
|
||||
defaultMessage='Flagged Posts'
|
||||
/>
|
||||
</Item>
|
||||
</RightMenuDrawerItem>
|
||||
<Divider/>
|
||||
<Item>
|
||||
<RightMenuDrawerItem>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='cog'
|
||||
|
|
@ -94,8 +80,8 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='sidebar_right_menu.accountSettings'
|
||||
defaultMessage='Account Settings'
|
||||
/>
|
||||
</Item>
|
||||
<Item>
|
||||
</RightMenuDrawerItem>
|
||||
<RightMenuDrawerItem>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='user-plus'
|
||||
|
|
@ -105,8 +91,8 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='sidebar_right_menu.inviteNew'
|
||||
defaultMessage='Invite New Member'
|
||||
/>
|
||||
</Item>
|
||||
<Item>
|
||||
</RightMenuDrawerItem>
|
||||
<RightMenuDrawerItem>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='link'
|
||||
|
|
@ -116,9 +102,9 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='sidebar_right_menu.teamLink'
|
||||
defaultMessage='Get Team Invite Link'
|
||||
/>
|
||||
</Item>
|
||||
</RightMenuDrawerItem>
|
||||
<Divider/>
|
||||
<Item>
|
||||
<RightMenuDrawerItem>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='globe'
|
||||
|
|
@ -128,8 +114,8 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='sidebar_right_menu.teamSettings'
|
||||
defaultMessage='Team Settings'
|
||||
/>
|
||||
</Item>
|
||||
<Item>
|
||||
</RightMenuDrawerItem>
|
||||
<RightMenuDrawerItem>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='users'
|
||||
|
|
@ -139,8 +125,8 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='sidebar_right_menu.manageMembers'
|
||||
defaultMessage='Manage Members'
|
||||
/>
|
||||
</Item>
|
||||
<Item onPress={this.goToTeamSelection}>
|
||||
</RightMenuDrawerItem>
|
||||
<RightMenuDrawerItem onPress={this.props.actions.goToSelectTeam}>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='exchange'
|
||||
|
|
@ -150,9 +136,9 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='sidebar_right_menu.switch_team'
|
||||
defaultMessage='Team Selection'
|
||||
/>
|
||||
</Item>
|
||||
</RightMenuDrawerItem>
|
||||
<Divider/>
|
||||
<Item>
|
||||
<RightMenuDrawerItem>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='question'
|
||||
|
|
@ -162,8 +148,8 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='sidebar_right_menu.help'
|
||||
defaultMessage='Help'
|
||||
/>
|
||||
</Item>
|
||||
<Item>
|
||||
</RightMenuDrawerItem>
|
||||
<RightMenuDrawerItem>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='phone'
|
||||
|
|
@ -173,8 +159,8 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='sidebar_right_menu.report'
|
||||
defaultMessage='Report a Problem'
|
||||
/>
|
||||
</Item>
|
||||
<Item>
|
||||
</RightMenuDrawerItem>
|
||||
<RightMenuDrawerItem>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='info'
|
||||
|
|
@ -184,9 +170,9 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='navbar_dropdown.about'
|
||||
defaultMessage='About Mattermost'
|
||||
/>
|
||||
</Item>
|
||||
</RightMenuDrawerItem>
|
||||
<Divider/>
|
||||
<Item onPress={this.props.actions.logout}>
|
||||
<RightMenuDrawerItem onPress={this.props.actions.logout}>
|
||||
<Icon
|
||||
style={Styles.icon}
|
||||
name='sign-out'
|
||||
|
|
@ -196,7 +182,7 @@ export default class RightSidebarMenu extends React.Component {
|
|||
id='sidebar_right_menu.logout'
|
||||
defaultMessage='Logout'
|
||||
/>
|
||||
</Item>
|
||||
</RightMenuDrawerItem>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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,
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 <Loading/>;
|
||||
}
|
||||
|
||||
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}
|
||||
<ErrorText error={this.props.teamsRequest.error}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue