Search (#415)
* Align post_textbox paper plane * add search to manage | view | add channel members
This commit is contained in:
parent
bc18d60883
commit
442d6b0bc5
8 changed files with 396 additions and 188 deletions
|
|
@ -368,7 +368,8 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
}
|
||||
}),
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
justifyContent: 'center',
|
||||
paddingLeft: 2
|
||||
},
|
||||
typing: {
|
||||
paddingLeft: 10,
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React, {PropTypes} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
|
||||
import {getTheme} from 'app/selectors/preferences';
|
||||
|
||||
function AddMemberButton(props) {
|
||||
return (
|
||||
<View style={{flexDirection: 'column', justifyContent: 'center', alignItems: 'center', flex: 1}}>
|
||||
<TouchableOpacity
|
||||
onPress={() => props.emitter('add_members')}
|
||||
style={{paddingHorizontal: 15}}
|
||||
>
|
||||
<FormattedText
|
||||
id='integrations.add'
|
||||
defaultMessage='Add'
|
||||
style={{color: props.theme.sidebarHeaderTextColor}}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
AddMemberButton.propTypes = {
|
||||
emitter: PropTypes.func.isRequired,
|
||||
theme: PropTypes.object
|
||||
};
|
||||
|
||||
AddMemberButton.defaultProps = {
|
||||
theme: {}
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
theme: getTheme(state)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(AddMemberButton);
|
||||
|
|
@ -2,30 +2,28 @@
|
|||
// See License.txt for license information.
|
||||
|
||||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import {injectIntl, intlShape} from 'react-intl';
|
||||
import {
|
||||
Alert,
|
||||
Keyboard,
|
||||
Platform,
|
||||
InteractionManager,
|
||||
StyleSheet,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
import ActionButton from 'app/components/action_button';
|
||||
import MemberList from 'app/components/custom_list';
|
||||
import SearchBar from 'app/components/search_bar';
|
||||
import {createMembersSections, loadingText, renderMemberRow} from 'app/utils/member_list';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
import AddMemberButton from './add_member_button';
|
||||
import {makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import {Constants, RequestStatus} from 'mattermost-redux/constants';
|
||||
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
||||
|
||||
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default class ChannelAddMembers extends PureComponent {
|
||||
class ChannelAddMembers extends PureComponent {
|
||||
static propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
theme: PropTypes.object.isRequired,
|
||||
currentChannel: PropTypes.object,
|
||||
currentChannelMemberCount: PropTypes.number,
|
||||
|
|
@ -34,23 +32,37 @@ export default class ChannelAddMembers extends PureComponent {
|
|||
currentTeamMemberCount: PropTypes.number,
|
||||
preferences: PropTypes.object,
|
||||
loadMoreRequestStatus: PropTypes.string,
|
||||
searchRequestStatus: PropTypes.string,
|
||||
addChannelMemberStatus: PropTypes.string,
|
||||
subscribeToHeaderEvent: React.PropTypes.func,
|
||||
unsubscribeFromHeaderEvent: React.PropTypes.func,
|
||||
actions: PropTypes.shape({
|
||||
getTeamStats: PropTypes.func.isRequired,
|
||||
getProfilesNotInChannel: PropTypes.func.isRequired,
|
||||
goBack: PropTypes.func.isRequired,
|
||||
handleAddChannelMembers: PropTypes.func.isRequired
|
||||
handleAddChannelMembers: PropTypes.func.isRequired,
|
||||
searchProfiles: PropTypes.func.isRequired
|
||||
})
|
||||
};
|
||||
|
||||
static navigationProps = {
|
||||
renderRightComponent: (props, emitter) => {
|
||||
return <AddMemberButton emitter={emitter}/>;
|
||||
return (
|
||||
<ActionButton
|
||||
actionEventName='add_members'
|
||||
emitter={emitter}
|
||||
enabled={false}
|
||||
enableEventName='can_add_members'
|
||||
labelDefaultMessage='Add'
|
||||
labelId='integrations.add'
|
||||
loadingEventName='adding_members'
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
state = {
|
||||
profiles: [],
|
||||
selectedMembers: {}
|
||||
};
|
||||
|
||||
|
|
@ -59,14 +71,59 @@ export default class ChannelAddMembers extends PureComponent {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (Platform.OS === 'android') {
|
||||
Keyboard.addListener('keyboardDidHide', this.handleAndroidKeyboard);
|
||||
}
|
||||
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
this.props.actions.getProfilesNotInChannel(this.props.currentTeam.id, this.props.currentChannel.id, 0);
|
||||
this.props.actions.getTeamStats(this.props.currentTeam.id);
|
||||
});
|
||||
|
||||
this.emitCanAddMembers(false);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.unsubscribeFromHeaderEvent('add_members');
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
Keyboard.removeListener('keyboardDidHide', this.handleAndroidKeyboard);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const {loadMoreRequestStatus} = this.props;
|
||||
if (loadMoreRequestStatus === RequestStatus.STARTED &&
|
||||
nextProps.loadMoreRequestStatus === RequestStatus.SUCCESS) {
|
||||
this.setState({profiles: nextProps.membersNotInChannel});
|
||||
} else if (this.state.searching &&
|
||||
nextProps.searchRequestStatus === RequestStatus.SUCCESS) {
|
||||
const results = nextProps.membersNotInChannel.filter((p) => {
|
||||
const {term} = this.state;
|
||||
return p.username.toLowerCase().includes(term) || p.email.toLowerCase().includes(term) ||
|
||||
p.first_name.toLowerCase().includes(term) || p.last_name.toLowerCase().includes(term);
|
||||
});
|
||||
this.setState({profiles: results});
|
||||
}
|
||||
|
||||
const {addChannelMemberStatus} = nextProps;
|
||||
|
||||
if (this.props.addChannelMemberStatus !== addChannelMemberStatus) {
|
||||
switch (addChannelMemberStatus) {
|
||||
case RequestStatus.STARTED:
|
||||
this.emitAdding(true);
|
||||
this.setState({error: null});
|
||||
break;
|
||||
case RequestStatus.SUCCESS:
|
||||
this.emitAdding(false);
|
||||
this.setState({error: null});
|
||||
this.props.actions.goBack();
|
||||
break;
|
||||
case RequestStatus.FAILURE:
|
||||
this.emitAdding(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleAddMembersPress = () => {
|
||||
|
|
@ -79,36 +136,107 @@ export default class ChannelAddMembers extends PureComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
actions.handleAddChannelMembers(currentTeam.id, currentChannel.id, membersToAdd).then(() => {
|
||||
actions.goBack();
|
||||
});
|
||||
}
|
||||
actions.handleAddChannelMembers(currentTeam.id, currentChannel.id, membersToAdd);
|
||||
};
|
||||
|
||||
handleAndroidKeyboard = () => {
|
||||
this.onSearchButtonPress();
|
||||
};
|
||||
|
||||
loadMoreMembers = () => {
|
||||
const {currentChannelMemberCount, currentTeamMemberCount, membersNotInChannel, loadMoreRequestStatus} = this.props;
|
||||
if (loadMoreRequestStatus !== 'started' && membersNotInChannel.length < (currentTeamMemberCount - currentChannelMemberCount - 1)) {
|
||||
if (loadMoreRequestStatus !== RequestStatus.STARTED && membersNotInChannel.length < (currentTeamMemberCount - currentChannelMemberCount - 1)) {
|
||||
this.props.actions.getProfilesNotInChannel(this.props.currentTeam.id, this.props.currentChannel.id, this.props.membersNotInChannel.length);
|
||||
}
|
||||
};
|
||||
|
||||
handleRowSelect = (id) => {
|
||||
const selectedMembers = Object.assign({}, this.state.selectedMembers, {[id]: !this.state.selectedMembers[id]});
|
||||
if (Object.keys(selectedMembers).length) {
|
||||
this.emitCanAddMembers(true);
|
||||
} else {
|
||||
this.emitCanAddMembers(false);
|
||||
}
|
||||
this.setState({
|
||||
selectedMembers
|
||||
});
|
||||
};
|
||||
|
||||
emitCanAddMembers = (enabled) => {
|
||||
EventEmitter.emit('can_add_members', enabled);
|
||||
};
|
||||
|
||||
emitAdding = (loading) => {
|
||||
EventEmitter.emit('adding_members', loading);
|
||||
};
|
||||
|
||||
searchBarRef = (ref) => {
|
||||
this.searchBar = ref;
|
||||
};
|
||||
|
||||
onSearchButtonPress = () => {
|
||||
this.searchBar.blur();
|
||||
};
|
||||
|
||||
searchProfiles = (event) => {
|
||||
const term = event.nativeEvent.text.toLowerCase();
|
||||
|
||||
if (term) {
|
||||
this.setState({searching: true, term});
|
||||
clearTimeout(this.searchTimeoutId);
|
||||
|
||||
this.searchTimeoutId = setTimeout(() => {
|
||||
this.props.actions.searchProfiles(term, {not_in_channel_id: this.props.currentChannel.id});
|
||||
}, Constants.SEARCH_TIMEOUT_MILLISECONDS);
|
||||
} else {
|
||||
this.cancelSearch();
|
||||
}
|
||||
};
|
||||
|
||||
cancelSearch = () => {
|
||||
this.setState({
|
||||
searching: false,
|
||||
term: null,
|
||||
page: 0,
|
||||
profiles: this.props.membersNotInChannel
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const style = getStyleFromTheme(this.props.theme);
|
||||
const {intl, loadMoreRequestStatus, searchRequestStatus, preferences, theme} = this.props;
|
||||
const {profiles, searching} = this.state;
|
||||
const {formatMessage} = intl;
|
||||
const isLoading = (loadMoreRequestStatus === RequestStatus.STARTED) ||
|
||||
(searchRequestStatus === RequestStatus.STARTED);
|
||||
const style = getStyleFromTheme(theme);
|
||||
const more = searching ? () => true : this.loadMoreMembers;
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<View
|
||||
style={{marginVertical: 5}}
|
||||
>
|
||||
<SearchBar
|
||||
ref={this.searchBarRef}
|
||||
placeholder={formatMessage({id: 'search_bar.search', defaultMesage: 'Search'})}
|
||||
height={27}
|
||||
fontSize={14}
|
||||
textColor={theme.centerChannelColor}
|
||||
hideBackground={true}
|
||||
textFieldBackgroundColor={changeOpacity(theme.centerChannelColor, 0.07)}
|
||||
onChange={this.searchProfiles}
|
||||
onSearchButtonPress={this.onSearchButtonPress}
|
||||
onCancelButtonPress={this.cancelSearch}
|
||||
/>
|
||||
</View>
|
||||
<MemberList
|
||||
data={this.props.membersNotInChannel}
|
||||
theme={this.props.theme}
|
||||
onListEndReached={this.loadMoreMembers}
|
||||
preferences={this.props.preferences}
|
||||
loading={this.props.loadMoreRequestStatus === 'started'}
|
||||
data={profiles}
|
||||
theme={theme}
|
||||
searching={searching}
|
||||
onListEndReached={more}
|
||||
preferences={preferences}
|
||||
listScrollRenderAheadDistance={50}
|
||||
loading={isLoading}
|
||||
loadingText={loadingText}
|
||||
selectable={true}
|
||||
onRowSelect={this.handleRowSelect}
|
||||
|
|
@ -119,3 +247,14 @@ export default class ChannelAddMembers extends PureComponent {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default injectIntl(ChannelAddMembers);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences'
|
|||
import {getCurrentTeam, getCurrentTeamStats} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {getProfilesNotInCurrentChannel} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getTeamStats} from 'mattermost-redux/actions/teams';
|
||||
import {getProfilesNotInChannel} from 'mattermost-redux/actions/users';
|
||||
import {getProfilesNotInChannel, searchProfiles} from 'mattermost-redux/actions/users';
|
||||
|
||||
import ChannelAddMembers from './channel_add_members';
|
||||
|
||||
|
|
@ -30,7 +30,9 @@ function mapStateToProps(state) {
|
|||
currentChannelMemberCount,
|
||||
preferences: getMyPreferences(state),
|
||||
loadMoreRequestStatus: state.requests.users.getProfilesNotInChannel.status,
|
||||
addChannelMemberRequestStatus: state.requests.channels.addChannelMember
|
||||
addChannelMemberRequestStatus: state.requests.channels.addChannelMember,
|
||||
searchRequestStatus: state.requests.users.searchProfiles.status,
|
||||
addChannelMemberStatus: state.requests.channels.addChannelMember.status
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +42,8 @@ function mapDispatchToProps(dispatch) {
|
|||
getTeamStats,
|
||||
getProfilesNotInChannel,
|
||||
goBack,
|
||||
handleAddChannelMembers
|
||||
handleAddChannelMembers,
|
||||
searchProfiles
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
import React, {PropTypes, PureComponent} from 'react';
|
||||
import {
|
||||
Alert,
|
||||
Keyboard,
|
||||
Platform,
|
||||
InteractionManager,
|
||||
StyleSheet,
|
||||
View
|
||||
|
|
@ -11,23 +13,18 @@ import {
|
|||
import {injectIntl, intlShape} from 'react-intl';
|
||||
|
||||
import MemberList from 'app/components/custom_list';
|
||||
import SearchBar from 'app/components/search_bar';
|
||||
import {createMembersSections, loadingText} from 'app/utils/member_list';
|
||||
import MemberListRow from 'app/components/custom_list/member_list_row';
|
||||
import {displayUsername} from 'mattermost-redux/utils/user_utils';
|
||||
import {makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
import {Constants, RequestStatus} from 'mattermost-redux/constants';
|
||||
import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
||||
|
||||
import ChannelMembersTitle from './channel_members_title';
|
||||
import RemoveMemberButton from './remove_member_button';
|
||||
|
||||
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
class ChannelMembers extends PureComponent {
|
||||
static propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
|
|
@ -39,13 +36,16 @@ class ChannelMembers extends PureComponent {
|
|||
currentTeam: PropTypes.object,
|
||||
preferences: PropTypes.object,
|
||||
requestStatus: PropTypes.string,
|
||||
searchRequestStatus: PropTypes.string,
|
||||
removeMembersStatus: PropTypes.string,
|
||||
canManageUsers: PropTypes.bool.isRequired,
|
||||
subscribeToHeaderEvent: React.PropTypes.func,
|
||||
unsubscribeFromHeaderEvent: React.PropTypes.func,
|
||||
actions: PropTypes.shape({
|
||||
getProfilesInChannel: PropTypes.func.isRequired,
|
||||
goBack: PropTypes.func.isRequired,
|
||||
handleRemoveChannelMembers: PropTypes.func.isRequired
|
||||
handleRemoveChannelMembers: PropTypes.func.isRequired,
|
||||
searchProfiles: PropTypes.func.isRequired
|
||||
})
|
||||
};
|
||||
|
||||
|
|
@ -59,6 +59,7 @@ class ChannelMembers extends PureComponent {
|
|||
};
|
||||
|
||||
state = {
|
||||
profiles: [],
|
||||
selectedMembers: {}
|
||||
};
|
||||
|
||||
|
|
@ -67,13 +68,58 @@ class ChannelMembers extends PureComponent {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (Platform.OS === 'android') {
|
||||
Keyboard.addListener('keyboardDidHide', this.handleAndroidKeyboard);
|
||||
}
|
||||
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
this.props.actions.getProfilesInChannel(this.props.currentTeam.id, this.props.currentChannel.id, 0);
|
||||
});
|
||||
|
||||
this.emitCanRemoveMembers(false);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.unsubscribeFromHeaderEvent('remove_members');
|
||||
|
||||
if (Platform.OS === 'android') {
|
||||
Keyboard.removeListener('keyboardDidHide', this.handleAndroidKeyboard);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const {requestStatus} = this.props;
|
||||
if (requestStatus === RequestStatus.STARTED &&
|
||||
nextProps.requestStatus === RequestStatus.SUCCESS) {
|
||||
this.setState({profiles: nextProps.currentChannelMembers});
|
||||
} else if (this.state.searching &&
|
||||
nextProps.searchRequestStatus === RequestStatus.SUCCESS) {
|
||||
const results = nextProps.currentChannelMembers.filter((p) => {
|
||||
const {term} = this.state;
|
||||
return p.username.toLowerCase().includes(term) || p.email.toLowerCase().includes(term) ||
|
||||
p.first_name.toLowerCase().includes(term) || p.last_name.toLowerCase().includes(term);
|
||||
});
|
||||
this.setState({profiles: results});
|
||||
}
|
||||
|
||||
const {removeMembersStatus} = nextProps;
|
||||
|
||||
if (this.props.removeMembersStatus !== removeMembersStatus) {
|
||||
switch (removeMembersStatus) {
|
||||
case RequestStatus.STARTED:
|
||||
this.emitRemoving(true);
|
||||
this.setState({error: null});
|
||||
break;
|
||||
case RequestStatus.SUCCESS:
|
||||
this.emitRemoving(false);
|
||||
this.setState({error: null});
|
||||
this.props.actions.goBack();
|
||||
break;
|
||||
case RequestStatus.FAILURE:
|
||||
this.emitRemoving(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleRemoveMembersPress = () => {
|
||||
|
|
@ -113,11 +159,13 @@ class ChannelMembers extends PureComponent {
|
|||
);
|
||||
};
|
||||
|
||||
handleAndroidKeyboard = () => {
|
||||
this.onSearchButtonPress();
|
||||
};
|
||||
|
||||
removeMembers = (membersToRemove) => {
|
||||
const {actions, currentTeam, currentChannel} = this.props;
|
||||
actions.handleRemoveChannelMembers(currentTeam.id, currentChannel.id, membersToRemove).then(() => {
|
||||
actions.goBack();
|
||||
});
|
||||
actions.handleRemoveChannelMembers(currentTeam.id, currentChannel.id, membersToRemove);
|
||||
};
|
||||
|
||||
loadMoreMembers = () => {
|
||||
|
|
@ -128,11 +176,56 @@ class ChannelMembers extends PureComponent {
|
|||
|
||||
handleRowSelect = (id) => {
|
||||
const selectedMembers = Object.assign({}, this.state.selectedMembers, {[id]: !this.state.selectedMembers[id]});
|
||||
if (Object.keys(selectedMembers).length) {
|
||||
this.emitCanRemoveMembers(true);
|
||||
} else {
|
||||
this.emitCanRemoveMembers(false);
|
||||
}
|
||||
this.setState({
|
||||
selectedMembers
|
||||
});
|
||||
};
|
||||
|
||||
emitCanRemoveMembers = (enabled) => {
|
||||
EventEmitter.emit('can_remove_members', enabled);
|
||||
};
|
||||
|
||||
emitRemoving = (loading) => {
|
||||
EventEmitter.emit('removing_members', loading);
|
||||
};
|
||||
|
||||
searchBarRef = (ref) => {
|
||||
this.searchBar = ref;
|
||||
};
|
||||
|
||||
onSearchButtonPress = () => {
|
||||
this.searchBar.blur();
|
||||
};
|
||||
|
||||
searchProfiles = (event) => {
|
||||
const term = event.nativeEvent.text.toLowerCase();
|
||||
|
||||
if (term) {
|
||||
this.setState({searching: true, term});
|
||||
clearTimeout(this.searchTimeoutId);
|
||||
|
||||
this.searchTimeoutId = setTimeout(() => {
|
||||
this.props.actions.searchProfiles(term, {in_channel_id: this.props.currentChannel.id});
|
||||
}, Constants.SEARCH_TIMEOUT_MILLISECONDS);
|
||||
} else {
|
||||
this.cancelSearch();
|
||||
}
|
||||
};
|
||||
|
||||
cancelSearch = () => {
|
||||
this.setState({
|
||||
searching: false,
|
||||
term: null,
|
||||
page: 0,
|
||||
profiles: this.props.currentChannelMembers
|
||||
});
|
||||
};
|
||||
|
||||
renderMemberRow = (user, sectionId, rowId, preferences, theme, selectable, onPress, onSelect) => {
|
||||
const {id, username} = user;
|
||||
const displayName = displayUsername(user, preferences);
|
||||
|
|
@ -157,20 +250,43 @@ class ChannelMembers extends PureComponent {
|
|||
disableSelect={disableSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {canManageUsers, theme} = this.props;
|
||||
const {canManageUsers, intl, preferences, requestStatus, searchRequestStatus, theme} = this.props;
|
||||
const {formatMessage} = intl;
|
||||
const {profiles, searching} = this.state;
|
||||
const isLoading = (requestStatus === RequestStatus.STARTED) ||
|
||||
(searchRequestStatus === RequestStatus.STARTED);
|
||||
const more = searching ? () => true : this.loadMoreMembers;
|
||||
const style = getStyleFromTheme(theme);
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<View
|
||||
style={{marginVertical: 5}}
|
||||
>
|
||||
<SearchBar
|
||||
ref={this.searchBarRef}
|
||||
placeholder={formatMessage({id: 'search_bar.search', defaultMesage: 'Search'})}
|
||||
height={27}
|
||||
fontSize={14}
|
||||
textColor={theme.centerChannelColor}
|
||||
hideBackground={true}
|
||||
textFieldBackgroundColor={changeOpacity(theme.centerChannelColor, 0.07)}
|
||||
onChange={this.searchProfiles}
|
||||
onSearchButtonPress={this.onSearchButtonPress}
|
||||
onCancelButtonPress={this.cancelSearch}
|
||||
/>
|
||||
</View>
|
||||
<MemberList
|
||||
data={this.props.currentChannelMembers}
|
||||
theme={this.props.theme}
|
||||
onListEndReached={this.loadMoreMembers}
|
||||
preferences={this.props.preferences}
|
||||
loading={this.props.requestStatus === 'started'}
|
||||
data={profiles}
|
||||
theme={theme}
|
||||
searching={searching}
|
||||
onListEndReached={more}
|
||||
preferences={preferences}
|
||||
listScrollRenderAheadDistance={50}
|
||||
loading={isLoading}
|
||||
loadingText={loadingText}
|
||||
selectable={canManageUsers}
|
||||
onRowSelect={this.handleRowSelect}
|
||||
|
|
@ -182,4 +298,13 @@ class ChannelMembers extends PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default injectIntl(ChannelMembers);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import {getCurrentChannel, getCurrentChannelStats, canManageChannelMembers} from
|
|||
import {getMyPreferences} from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
|
||||
import {getProfilesInCurrentChannel} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getProfilesInChannel} from 'mattermost-redux/actions/users';
|
||||
import {getProfilesInChannel, searchProfiles} from 'mattermost-redux/actions/users';
|
||||
|
||||
import ChannelMembers from './channel_members';
|
||||
|
||||
|
|
@ -28,6 +28,8 @@ function mapStateToProps(state) {
|
|||
currentTeam: getCurrentTeam(state),
|
||||
preferences: getMyPreferences(state),
|
||||
requestStatus: state.requests.users.getProfilesInChannel.status,
|
||||
searchRequestStatus: state.requests.users.searchProfiles.status,
|
||||
removeMembersStatus: state.requests.channels.removeChannelMember.status,
|
||||
canManageUsers: canManageChannelMembers(state)
|
||||
};
|
||||
}
|
||||
|
|
@ -37,7 +39,8 @@ function mapDispatchToProps(dispatch) {
|
|||
actions: bindActionCreators({
|
||||
getProfilesInChannel,
|
||||
goBack,
|
||||
handleRemoveChannelMembers
|
||||
handleRemoveChannelMembers,
|
||||
searchProfiles
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,10 @@
|
|||
|
||||
import React, {PropTypes} from 'react';
|
||||
import {connect} from 'react-redux';
|
||||
import {
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
import ActionButton from 'app/components/action_button';
|
||||
|
||||
import {getCurrentChannel, canManageChannelMembers} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getTheme} from 'app/selectors/preferences';
|
||||
import {canManageChannelMembers} from 'mattermost-redux/selectors/entities/channels';
|
||||
|
||||
function RemoveMemberButton(props) {
|
||||
const {canManageUsers} = props;
|
||||
|
|
@ -20,37 +15,26 @@ function RemoveMemberButton(props) {
|
|||
}
|
||||
|
||||
return (
|
||||
<View style={{flexDirection: 'column', justifyContent: 'center', alignItems: 'center', flex: 1}}>
|
||||
<TouchableOpacity
|
||||
onPress={() => props.emitter('remove_members')}
|
||||
style={{paddingHorizontal: 15}}
|
||||
>
|
||||
<FormattedText
|
||||
id='channel_members_modal.remove'
|
||||
defaultMessage='Remove'
|
||||
style={{color: props.theme.sidebarHeaderTextColor}}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<ActionButton
|
||||
actionEventName='remove_members'
|
||||
emitter={props.emitter}
|
||||
enabled={false}
|
||||
enableEventName='can_remove_members'
|
||||
labelDefaultMessage='Remove'
|
||||
labelId='channel_members_modal.remove'
|
||||
loadingEventName='removing_members'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
RemoveMemberButton.propTypes = {
|
||||
emitter: PropTypes.func.isRequired,
|
||||
canManageUsers: PropTypes.bool.isRequired,
|
||||
currentChannel: PropTypes.object.isRequired,
|
||||
theme: PropTypes.object
|
||||
};
|
||||
|
||||
RemoveMemberButton.defaultProps = {
|
||||
theme: {}
|
||||
canManageUsers: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
canManageUsers: canManageChannelMembers(state),
|
||||
currentChannel: getCurrentChannel(state),
|
||||
theme: getTheme(state)
|
||||
canManageUsers: canManageChannelMembers(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,66 +25,6 @@ import EventEmitter from 'mattermost-redux/utils/event_emitter';
|
|||
|
||||
import ActionButton from 'app/components/action_button';
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
|
||||
paddingTop: 30
|
||||
},
|
||||
errorContainer: {
|
||||
position: 'absolute'
|
||||
},
|
||||
errorWrapper: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: 10
|
||||
},
|
||||
inputContainer: {
|
||||
marginTop: 10,
|
||||
borderTopWidth: 1,
|
||||
borderBottomWidth: 1,
|
||||
borderTopColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
borderBottomColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
backgroundColor: theme.centerChannelBg
|
||||
},
|
||||
input: {
|
||||
color: theme.centerChannelColor,
|
||||
fontSize: 14,
|
||||
height: 40,
|
||||
paddingHorizontal: 15
|
||||
},
|
||||
titleContainer30: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 30
|
||||
},
|
||||
titleContainer15: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 15
|
||||
},
|
||||
title: {
|
||||
fontSize: 14,
|
||||
color: theme.centerChannelColor,
|
||||
marginLeft: 15
|
||||
},
|
||||
optional: {
|
||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
||||
fontSize: 14,
|
||||
marginLeft: 5
|
||||
},
|
||||
helpText: {
|
||||
fontSize: 14,
|
||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
||||
marginTop: 10,
|
||||
marginHorizontal: 15
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
class CreateChannel extends PureComponent {
|
||||
static propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
|
|
@ -372,4 +312,64 @@ class CreateChannel extends PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.03),
|
||||
paddingTop: 30
|
||||
},
|
||||
errorContainer: {
|
||||
position: 'absolute'
|
||||
},
|
||||
errorWrapper: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: 10
|
||||
},
|
||||
inputContainer: {
|
||||
marginTop: 10,
|
||||
borderTopWidth: 1,
|
||||
borderBottomWidth: 1,
|
||||
borderTopColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
borderBottomColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
backgroundColor: theme.centerChannelBg
|
||||
},
|
||||
input: {
|
||||
color: theme.centerChannelColor,
|
||||
fontSize: 14,
|
||||
height: 40,
|
||||
paddingHorizontal: 15
|
||||
},
|
||||
titleContainer30: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 30
|
||||
},
|
||||
titleContainer15: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 15
|
||||
},
|
||||
title: {
|
||||
fontSize: 14,
|
||||
color: theme.centerChannelColor,
|
||||
marginLeft: 15
|
||||
},
|
||||
optional: {
|
||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
||||
fontSize: 14,
|
||||
marginLeft: 5
|
||||
},
|
||||
helpText: {
|
||||
fontSize: 14,
|
||||
color: changeOpacity(theme.centerChannelColor, 0.5),
|
||||
marginTop: 10,
|
||||
marginHorizontal: 15
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export default injectIntl(CreateChannel);
|
||||
|
|
|
|||
Loading…
Reference in a new issue