Various UI Fixes (#384)

* Various UI Fixes

* ability to scroll through teams

* Fix drawer when not logged in

* fix channel info DM status

* channel drawer spacing of icons made equal

* address feedback
This commit is contained in:
enahum 2017-03-23 10:36:35 -03:00 committed by GitHub
parent 56a27ce7ad
commit c049cb0f9d
17 changed files with 239 additions and 308 deletions

View file

@ -232,7 +232,13 @@ export function requestCloseModal() {
export function renderDrawer() {
return async (dispatch, getState) => {
dispatch({type: NavigationTypes.NAVIGATION_RENDER_LEFT_DRAWER}, getState);
dispatch({type: NavigationTypes.NAVIGATION_RENDER_LEFT_DRAWER, data: true}, getState);
};
}
export function unrenderDrawer() {
return async (dispatch, getState) => {
dispatch({type: NavigationTypes.NAVIGATION_RENDER_LEFT_DRAWER, data: false}, getState);
};
}

View file

@ -23,6 +23,12 @@ export default class ChannelDrawerItem extends PureComponent {
theme: PropTypes.object.isRequired
};
handleLongPress = (channel) => {
if (this.props.onLongPress) {
this.props.onLongPress(channel);
}
};
render() {
const {
channel,
@ -81,7 +87,7 @@ export default class ChannelDrawerItem extends PureComponent {
onPress={() => this.props.onSelectChannel(channel)}
delayLongPress={1000}
onLongPress={() => {
this.props.onLongPress(channel);
this.handleLongPress(channel);
}}
>
<View style={style.container}>
@ -142,10 +148,11 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
badgeContainer: {
alignItems: 'center',
backgroundColor: theme.mentionBj,
borderRadius: 7,
height: 15,
justifyContent: 'center',
marginRight: 16,
width: 15
width: 16
},
badge: {
color: theme.mentionColor,

View file

@ -154,133 +154,6 @@ class ChannelDrawerList extends Component {
);
};
onShowModal = (channel) => {
const {formatMessage} = this.props.intl;
let open;
let close;
let favorite;
let term;
let title;
switch (channel.type) {
case Constants.DM_CHANNEL:
title = formatMessage({
id: 'mobile.channel_list.modalTitle',
defaultMessage: 'Select an action for the {term} {name}'},
{
name: channel.display_name,
term: formatMessage({id: 'mobile.channel_list.dm', defaultMessage: 'Direct Message'}).toLowerCase()
});
open = {
action: () => {
this.props.actions.closeOptionsModal();
this.onSelectChannel(channel);
},
text: formatMessage({id: 'mobile.channel_list.openDM', defaultMessage: 'Open Direct Message'})
};
close = {
action: () => {
this.handleClose(channel);
},
text: formatMessage({id: 'mobile.channel_list.closeDM', defaultMessage: 'Close Direct Message'}),
textStyle: {
color: '#CC3239'
}
};
break;
case Constants.GM_CHANNEL:
title = formatMessage({
id: 'mobile.channel_list.modalTitle',
defaultMessage: 'Select an action for the {term} {name}'},
{
name: channel.display_name,
term: formatMessage({id: 'mobile.channel_list.gm', defaultMessage: 'Group Message'}).toLowerCase()
});
open = {
action: () => {
this.props.actions.closeOptionsModal();
this.onSelectChannel(channel);
},
text: formatMessage({id: 'mobile.channel_list.openGM', defaultMessage: 'Open Group Message'})
};
close = {
action: () => {
this.handleClose(channel);
},
text: formatMessage({id: 'mobile.channel_list.closeGM', defaultMessage: 'Close Group Message'}),
textStyle: {
color: '#CC3239'
}
};
break;
default:
term = channel.type === Constants.OPEN_CHANNEL ?
formatMessage({id: 'mobile.channel_list.publicChannel', defaultMessage: 'Public Channel'}) :
formatMessage({id: 'mobile.channel_list.privateChannel', defaultMessage: 'Private Channel'});
title = formatMessage({
id: 'mobile.channel_list.modalTitle',
defaultMessage: 'Select an action for the {term} {name}'},
{
name: channel.display_name,
term: term.toLowerCase()
});
open = {
action: () => {
this.props.actions.closeOptionsModal();
this.onSelectChannel(channel);
},
text: formatMessage({id: 'mobile.channel_list.openChannel', defaultMessage: 'Open {term}'}, {
term
})
};
if (channel.name !== Constants.DEFAULT_CHANNEL) {
close = {
action: () => {
this.handleLeave(channel, term);
},
text: formatMessage({id: 'channel_header.leave', defaultMessage: 'Leave {term}'}, {
term
}),
textStyle: {
color: '#CC3239'
}
};
}
break;
}
if (channel.isFavorite) {
favorite = {
action: () => {
this.props.actions.closeOptionsModal();
this.props.actions.unmarkFavorite(channel.id);
},
text: formatMessage({id: 'channelHeader.removeFromFavorites', defaultMessage: 'Remove from Favorites'})
};
} else {
favorite = {
action: () => {
this.props.actions.closeOptionsModal();
this.props.actions.markFavorite(channel.id);
},
text: formatMessage({id: 'channelHeader.addToFavorites', defaultMessage: 'Add to Favorites'})
};
}
const options = [open, favorite];
if (close) {
options.push(close);
}
this.props.actions.showOptionsModal({title, items: options});
};
getUnreadMessages = (channel) => {
const member = this.props.channelMembers[channel.id];
let mentions = 0;
@ -328,7 +201,6 @@ class ChannelDrawerList extends Component {
hasUnread={unread}
mentions={mentions}
onSelectChannel={this.onSelectChannel}
onLongPress={this.onShowModal}
isActive={channel.isCurrent}
theme={this.props.theme}
/>
@ -557,7 +429,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
width: 50
},
settings: {
color: theme.sidebarText,
color: theme.sidebarHeaderTextColor,
fontSize: 18,
fontWeight: '300'
},
@ -578,7 +450,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
lineHeight: 18
},
divider: {
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
backgroundColor: changeOpacity(theme.sidebarText, 0.1),
height: 1
},
actionContainer: {

View file

@ -49,7 +49,7 @@ function channelIcon(props) {
return (
<Icon
name='lock'
style={[style.icon, unreadIcon, activeIcon, {fontSize: size}]}
style={[style.icon, unreadIcon, activeIcon, {fontSize: size + 1}]}
/>
);
} else if (type === Constants.GM_CHANNEL) {
@ -90,7 +90,7 @@ function channelIcon(props) {
<OfflineStatus
width={size}
height={size}
color={changeOpacity(theme.centerChannelColor, 0.4)}
color={changeOpacity(theme.sidebarText, 0.5)}
/>
</View>
);
@ -116,6 +116,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
paddingRight: 12
},
groupBox: {
alignSelf: 'flex-start',
alignItems: 'center',
borderWidth: 1,
borderColor: changeOpacity(theme.sidebarText, 0.4),

View file

@ -1,46 +1,10 @@
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {PropTypes, PureComponent} from 'react';
import {ListView, StyleSheet, Text, View} from 'react-native';
import {ListView, Platform, StyleSheet, Text, View} from 'react-native';
import FormattedText from 'app/components/formatted_text';
import {makeStyleSheetFromTheme, changeOpacity} from 'app/utils/theme';
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
return StyleSheet.create({
listView: {
flex: 1,
backgroundColor: theme.centerChannelBg
},
loadingText: {
color: changeOpacity(theme.centerChannelColor, 0.6)
},
sectionContainer: {
backgroundColor: theme.sidebarHeaderBg,
paddingLeft: 10,
paddingVertical: 2
},
sectionText: {
fontWeight: '600',
color: theme.sidebarHeaderTextColor
},
separator: {
height: 1,
flex: 1,
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1)
},
noResultContainer: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
noResultText: {
fontSize: 26,
color: changeOpacity(theme.centerChannelColor, 0.5)
}
});
});
export default class CustomList extends PureComponent {
static propTypes = {
data: PropTypes.array.isRequired,
@ -225,3 +189,44 @@ export default class CustomList extends PureComponent {
);
}
}
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
return StyleSheet.create({
listView: {
flex: 1,
backgroundColor: theme.centerChannelBg,
...Platform.select({
android: {
marginBottom: 20
}
})
},
loadingText: {
color: changeOpacity(theme.centerChannelColor, 0.6)
},
sectionContainer: {
backgroundColor: theme.sidebarHeaderBg,
paddingLeft: 10,
paddingVertical: 2
},
sectionText: {
fontWeight: '600',
color: theme.sidebarHeaderTextColor
},
separator: {
height: 1,
flex: 1,
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1)
},
noResultContainer: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
noResultText: {
fontSize: 26,
color: changeOpacity(theme.centerChannelColor, 0.5)
}
});
});

View file

@ -1,8 +1,8 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import React, {PropTypes, PureComponent} from 'react';
import {AppState, View} from 'react-native';
import React, {Component, PropTypes} from 'react';
import {AppState, StatusBar, View} from 'react-native';
import {IntlProvider} from 'react-intl';
import DeviceInfo from 'react-native-device-info';
@ -13,7 +13,7 @@ import {Constants} from 'mattermost-redux/constants';
import {getTranslations} from 'app/i18n';
import EventEmitter from 'mattermost-redux/utils/event_emitter';
export default class Root extends PureComponent {
export default class Root extends Component {
static propTypes = {
children: PropTypes.node,
currentTeamId: PropTypes.string,
@ -66,6 +66,7 @@ export default class Root extends PureComponent {
messages={getTranslations(locale)}
>
<View style={{flex: 1}}>
<StatusBar barStyle='light-content'/>
{this.props.children}
<PushNotification/>
</View>

View file

@ -26,7 +26,7 @@ export default class SearchBarIos extends PureComponent {
static defaultProps = {
barStyle: 'default',
searchBarStyle: 'default',
searchBarStyle: 'minimal',
placeholder: 'Search',
showCancelButton: true,
hideBackground: true,
@ -77,7 +77,7 @@ export default class SearchBarIos extends PureComponent {
text={this.props.text}
placeholder={this.props.placeholder}
showsCancelButton={this.state.displayCancelButton}
hideBackground={this.props.hideBackground}
hideBackground={false}
textFieldBackgroundColor={this.props.textFieldBackgroundColor}
placeholderTextColor={this.props.placeholderTextColor}
textColor={this.props.textColor}

View file

@ -2,6 +2,7 @@
// See License.txt for license information.
import React from 'react';
import {View} from 'react-native';
import Svg, {
Ellipse,
G,
@ -16,30 +17,33 @@ export default class AwayStatus extends React.Component {
};
render() {
const {color, height, width} = this.props;
return (
<Svg
width={this.props.width}
height={this.props.height}
viewBox='-299 391 12 12'
>
<G>
<Ellipse
cx='-294.6'
cy='394'
rx='2.5'
ry='2.5'
fill={this.props.color}
/>
<View style={{height, width, alignItems: 'flex-start'}}>
<Svg
width={width}
height={height}
viewBox='-299 391 12 12'
>
<G>
<Ellipse
cx='-294.6'
cy='394'
rx='2.5'
ry='2.5'
fill={color}
/>
<Path
d='M-293.8,399.4c0-0.4,0.1-0.7,0.2-1c-0.3,0.1-0.6,0.2-1,0.2c-2.5,0-2.5-2-2.5-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5 c0,0.1-0.1,0.5,0,0.6c0.2,1.3,2.2,2.3,4.4,2.4c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0c0.7,0,1.4-0.1,2-0.3 C-293.3,401.5-293.8,400.5-293.8,399.4z'
fill={color}
/>
</G>
<Path
d='M-293.8,399.4c0-0.4,0.1-0.7,0.2-1c-0.3,0.1-0.6,0.2-1,0.2c-2.5,0-2.5-2-2.5-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5 c0,0.1-0.1,0.5,0,0.6c0.2,1.3,2.2,2.3,4.4,2.4c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0c0.7,0,1.4-0.1,2-0.3 C-293.3,401.5-293.8,400.5-293.8,399.4z'
fill={this.props.color}
d='M-287,400c0,0.1-0.1,0.1-0.1,0.1l-4.9,0c-0.1,0-0.1-0.1-0.1-0.1v-1.6c0-0.1,0.1-0.1,0.1-0.1l4.9,0c0.1,0,0.1,0.1,0.1,0.1 V400z'
fill={color}
/>
</G>
<Path
d='M-287,400c0,0.1-0.1,0.1-0.1,0.1l-4.9,0c-0.1,0-0.1-0.1-0.1-0.1v-1.6c0-0.1,0.1-0.1,0.1-0.1l4.9,0c0.1,0,0.1,0.1,0.1,0.1 V400z'
fill={this.props.color}
/>
</Svg>
</Svg>
</View>
);
}
}

View file

@ -2,6 +2,7 @@
// See License.txt for license information.
import React from 'react';
import {View} from 'react-native';
import Svg, {
Ellipse,
G,
@ -16,34 +17,37 @@ export default class OfflineStatus extends React.Component {
};
render() {
const {color, height, width} = this.props;
return (
<Svg
width={this.props.width}
height={this.props.height}
viewBox='-299 391 12 12'
>
<G>
<View style={{height, width, alignItems: 'flex-start'}}>
<Svg
width={width}
height={height}
viewBox='-299 391 12 12'
>
<G>
<G>
<Ellipse
cx='-294.5'
cy='394'
rx='2.5'
ry='2.5'
fill={color}
/>
<Path
d='M-294.3,399.7c0-0.4,0.1-0.8,0.2-1.2c-0.1,0-0.2,0-0.4,0c-2.5,0-2.5-2-2.5-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5 c0,0.1-0.1,0.5,0,0.6c0.2,1.3,2.2,2.3,4.4,2.4h0.1h0.1c0.3,0,0.7,0,1-0.1C-293.9,401.6-294.3,400.7-294.3,399.7z'
fill={color}
/>
</G>
</G>
<G>
<Ellipse
cx='-294.5'
cy='394'
rx='2.5'
ry='2.5'
fill={this.props.color}
/>
<Path
d='M-294.3,399.7c0-0.4,0.1-0.8,0.2-1.2c-0.1,0-0.2,0-0.4,0c-2.5,0-2.5-2-2.5-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5 c0,0.1-0.1,0.5,0,0.6c0.2,1.3,2.2,2.3,4.4,2.4h0.1h0.1c0.3,0,0.7,0,1-0.1C-293.9,401.6-294.3,400.7-294.3,399.7z'
fill={this.props.color}
d='M-288.9,399.4l1.8-1.8c0.1-0.1,0.1-0.3,0-0.3l-0.7-0.7c-0.1-0.1-0.3-0.1-0.3,0l-1.8,1.8l-1.8-1.8c-0.1-0.1-0.3-0.1-0.3,0 l-0.7,0.7c-0.1,0.1-0.1,0.3,0,0.3l1.8,1.8l-1.8,1.8c-0.1,0.1-0.1,0.3,0,0.3l0.7,0.7c0.1,0.1,0.3,0.1,0.3,0l1.8-1.8l1.8,1.8 c0.1,0.1,0.3,0.1,0.3,0l0.7-0.7c0.1-0.1,0.1-0.3,0-0.3L-288.9,399.4z'
fill={color}
/>
</G>
</G>
<G>
<Path
d='M-288.9,399.4l1.8-1.8c0.1-0.1,0.1-0.3,0-0.3l-0.7-0.7c-0.1-0.1-0.3-0.1-0.3,0l-1.8,1.8l-1.8-1.8c-0.1-0.1-0.3-0.1-0.3,0 l-0.7,0.7c-0.1,0.1-0.1,0.3,0,0.3l1.8,1.8l-1.8,1.8c-0.1,0.1-0.1,0.3,0,0.3l0.7,0.7c0.1,0.1,0.3,0.1,0.3,0l1.8-1.8l1.8,1.8 c0.1,0.1,0.3,0.1,0.3,0l0.7-0.7c0.1-0.1,0.1-0.3,0-0.3L-288.9,399.4z'
fill={this.props.color}
/>
</G>
</Svg>
</Svg>
</View>
);
}
}

View file

@ -2,6 +2,7 @@
// See License.txt for license information.
import React from 'react';
import {View} from 'react-native';
import Svg, {
Ellipse,
G,
@ -16,38 +17,41 @@ export default class OnlineStatus extends React.Component {
};
render() {
const {color, height, width} = this.props;
return (
<Svg
width={this.props.width}
height={this.props.height}
viewBox='-243 245 12 12'
>
<G>
<Path
d='M-236,250.5C-236,250.5-236,250.5-236,250.5C-236,250.5-236,250.5-236,250.5C-236,250.5-236,250.5-236,250.5z'
fill={this.props.color}
/>
<Ellipse
cx='-238.5'
cy='248'
rx='2.5'
ry='2.5'
fill={this.props.color}
/>
</G>
<Path
d='M-238.9,253.8c0-0.4,0.1-0.9,0.2-1.3c-2.2-0.2-2.2-2-2.2-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5c0,0.1-0.1,0.5,0,0.6 c0.2,1.3,2.2,2.3,4.4,2.4c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0C-238.7,255.7-238.9,254.8-238.9,253.8z'
fill={this.props.color}
/>
<G>
<View style={{height, width, alignItems: 'flex-start'}}>
<Svg
width={width}
height={height}
viewBox='-243 245 12 12'
>
<G>
<Path
d='M-232.3,250.1l1.3,1.3c0,0,0,0.1,0,0.1l-4.1,4.1c0,0,0,0-0.1,0c0,0,0,0,0,0l-2.7-2.7c0,0,0-0.1,0-0.1l1.2-1.2 c0,0,0.1,0,0.1,0l1.4,1.4l2.9-2.9C-232.4,250.1-232.3,250.1-232.3,250.1z'
fill={this.props.color}
d='M-236,250.5C-236,250.5-236,250.5-236,250.5C-236,250.5-236,250.5-236,250.5C-236,250.5-236,250.5-236,250.5z'
fill={color}
/>
<Ellipse
cx='-238.5'
cy='248'
rx='2.5'
ry='2.5'
fill={color}
/>
</G>
</G>
</Svg>
<Path
d='M-238.9,253.8c0-0.4,0.1-0.9,0.2-1.3c-2.2-0.2-2.2-2-2.2-2s-1,0.1-1.2,0.5c-0.4,0.6-0.6,1.7-0.7,2.5c0,0.1-0.1,0.5,0,0.6 c0.2,1.3,2.2,2.3,4.4,2.4c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0C-238.7,255.7-238.9,254.8-238.9,253.8z'
fill={color}
/>
<G>
<G>
<Path
d='M-232.3,250.1l1.3,1.3c0,0,0,0.1,0,0.1l-4.1,4.1c0,0,0,0-0.1,0c0,0,0,0,0,0l-2.7-2.7c0,0,0-0.1,0-0.1l1.2-1.2 c0,0,0.1,0,0.1,0l1.4,1.4l2.9-2.9C-232.4,250.1-232.3,250.1-232.3,250.1z'
fill={color}
/>
</G>
</G>
</Svg>
</View>
);
}
}

View file

@ -203,7 +203,7 @@ class Router extends Component {
deviceWidth: event.nativeEvent.layout.width
});
}
}
};
handleDrawerTween = (ratio) => {
const opacity = (ratio / 2);
@ -216,8 +216,8 @@ class Router extends Component {
opacity
},
drawerOverlay: {
backgroundColor: '#000',
opacity: (1 - ratio) / 2
backgroundColor: ratio ? '#000' : '#FFF',
opacity: ratio ? (1 - ratio) / 2 : 1
}
};
};

View file

@ -213,7 +213,7 @@ export default function(state = initialState, action) {
case NavigationTypes.NAVIGATION_RENDER_LEFT_DRAWER: {
return {
...state,
shouldRenderDrawer: true
shouldRenderDrawer: action.data
};
}

View file

@ -156,6 +156,7 @@ class ChannelInfo extends PureComponent {
currentChannelCreatorName,
currentChannelMemberCount,
canManageUsers,
status,
theme
} = this.props;
@ -186,6 +187,7 @@ class ChannelInfo extends PureComponent {
displayName={currentChannel.display_name}
header={currentChannel.header}
purpose={currentChannel.purpose}
status={status}
theme={theme}
type={currentChannel.type}
/>
@ -200,14 +202,19 @@ class ChannelInfo extends PureComponent {
theme={theme}
/>
<View style={style.separator}/>
<ChannelInfoRow
action={() => true}
defaultMessage='Notification Preferences'
icon='bell-o'
textId='channel_header.notificationPreferences'
theme={theme}
/>
<View style={style.separator}/>
{
/**
<ChannelInfoRow
action={() => true}
defaultMessage='Notification Preferences'
icon='bell-o'
textId='channel_header.notificationPreferences'
theme={theme}
/>
<View style={style.separator}/>
**/
}
<ChannelInfoRow
action={this.props.actions.goToChannelMembers}
defaultMessage={canManageUsers ? 'Manage Members' : 'View Members'}

View file

@ -5,6 +5,7 @@ import React, {PropTypes, PureComponent} from 'react';
import {
Image,
Keyboard,
StatusBar,
TouchableWithoutFeedback,
View
} from 'react-native';
@ -34,7 +35,8 @@ export default class SelectServer extends PureComponent {
getPing: PropTypes.func.isRequired,
resetPing: PropTypes.func.isRequired,
handleLoginOptions: PropTypes.func.isRequired,
handleServerUrlChanged: PropTypes.func.isRequired
handleServerUrlChanged: PropTypes.func.isRequired,
unrenderDrawer: PropTypes.func.isRequired
}).isRequired
};
@ -46,6 +48,10 @@ export default class SelectServer extends PureComponent {
};
}
componentDidMount() {
this.props.actions.unrenderDrawer();
}
componentWillReceiveProps(nextProps) {
if (!this.props.transition && nextProps.transition) {
this.props.actions.resetPing().then(() => {
@ -101,6 +107,7 @@ export default class SelectServer extends PureComponent {
style={{flex: 1}}
keyboardVerticalOffset={0}
>
<StatusBar barStyle='light-content'/>
<TouchableWithoutFeedback onPress={this.blur}>
<View style={[GlobalStyles.container, GlobalStyles.signupContainer]}>
<Image

View file

@ -7,6 +7,7 @@ import navigationSceneConnect from '../navigationSceneConnect';
import {getPing, resetPing} from 'mattermost-redux/actions/general';
import {RequestStatus} from 'mattermost-redux/constants';
import {unrenderDrawer} from 'app/actions/navigation';
import * as SelectServerActions from 'app/actions/views/select_server';
import SelectServer from './select_server';
@ -31,7 +32,8 @@ function mapDispatchToProps(dispatch) {
actions: bindActionCreators({
...SelectServerActions,
getPing,
resetPing
resetPing,
unrenderDrawer
}, dispatch)
};
}

View file

@ -5,6 +5,7 @@ import React, {PropTypes, PureComponent} from 'react';
import {
Image,
InteractionManager,
ScrollView,
Text,
TouchableOpacity,
View
@ -12,16 +13,15 @@ import {
import Button from 'react-native-button';
import Icon from 'react-native-vector-icons/MaterialIcons';
import FormattedText from 'app/components/formatted_text';
import {GlobalStyles} from 'app/styles';
import FormattedText from 'app/components/formatted_text';
import logo from 'assets/images/logo.png';
export default class SelectTeam extends PureComponent {
static propTypes = {
config: PropTypes.object.isRequired,
teams: PropTypes.object.isRequired,
myMembers: PropTypes.object.isRequired,
teams: PropTypes.array.isRequired,
subscribeToHeaderEvent: PropTypes.func.isRequired,
unsubscribeFromHeaderEvent: PropTypes.func.isRequired,
actions: PropTypes.shape({
@ -70,48 +70,50 @@ export default class SelectTeam extends PureComponent {
};
render() {
const content = [];
const teams = Object.values(this.props.teams);
for (const team of teams) {
if (this.props.myMembers.hasOwnProperty(team.id)) {
content.push(
<Button
key={team.id}
onPress={() => this.onSelectTeam(team)}
style={GlobalStyles.buttonListItemText}
containerStyle={GlobalStyles.buttonListItem}
>
{team.display_name}
<Icon
name='keyboard-arrow-right'
size={24}
color='#777'
/>
</Button>
);
}
}
const content = this.props.teams.map((team) => {
return (
<Button
key={team.id}
onPress={() => this.onSelectTeam(team)}
style={GlobalStyles.buttonListItemText}
containerStyle={GlobalStyles.buttonListItem}
>
{team.display_name}
<Icon
name='keyboard-arrow-right'
size={24}
color='#777'
/>
</Button>
);
});
return (
<View style={GlobalStyles.container}>
<Image
style={GlobalStyles.logo}
source={logo}
/>
<Text style={GlobalStyles.header}>
{this.props.config.SiteName}
</Text>
<FormattedText
style={GlobalStyles.subheader}
id='web.root.signup_info'
defaultMessage='All team communication in one place, searchable and accessible anywhere'
/>
<FormattedText
style={GlobalStyles.subheader}
id='signup_team.choose'
defaultMessage='Your teams:'
/>
{content}
<ScrollView
style={{flex: 1}}
contentContainerStyle={{alignItems: 'center', paddingVertical: 64}}
showsVerticalScrollIndicator={false}
>
<Image
style={GlobalStyles.logo}
source={logo}
/>
<Text style={GlobalStyles.header}>
{this.props.config.SiteName}
</Text>
<FormattedText
style={GlobalStyles.subheader}
id='web.root.signup_info'
defaultMessage='All team communication in one place, searchable and accessible anywhere'
/>
<FormattedText
style={GlobalStyles.subheader}
id='signup_team.choose'
defaultMessage='Your teams:'
/>
{content}
</ScrollView>
</View>
);
}

View file

@ -8,17 +8,26 @@ import navigationSceneConnect from '../navigationSceneConnect';
import {closeDrawers, closeModal, goBack} from 'app/actions/navigation';
import {handleTeamChange} from 'app/actions/views/select_team';
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentTeam, getTeams, getTeamMemberships} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import SelectTeam from './select_team.js';
function mapStateToProps(state) {
const allTeams = Object.values(getTeams(state));
const myMembers = getTeamMemberships(state);
const user = getCurrentUser(state);
const myTeams = allTeams.filter((team) => myMembers.hasOwnProperty(team.id));
function sortTeams(a, b) {
return a.display_name.localeCompare(b.display_name, user.locale, {numeric: true});
}
return {
config: state.entities.general.config,
teamsRequest: state.requests.teams.allTeams,
teams: state.entities.teams.teams,
currentTeam: getCurrentTeam(state),
myMembers: state.entities.teams.myMembers
teams: myTeams.sort(sortTeams),
currentTeam: getCurrentTeam(state)
};
}