Added permissions, translations strings for teams, deleteTeamRoom and addTeamRooms, AddExistingChannelView, updated CreateChannelView, TeamChannelsView
This commit is contained in:
parent
37421d395a
commit
bb0632b689
File diff suppressed because it is too large
Load Diff
|
@ -719,5 +719,8 @@
|
||||||
"team-name-already-exists": "A team with that name already exists",
|
"team-name-already-exists": "A team with that name already exists",
|
||||||
"Add_Channel_to_Team": "Add Channel to Team",
|
"Add_Channel_to_Team": "Add Channel to Team",
|
||||||
"Create_New": "Create New",
|
"Create_New": "Create New",
|
||||||
"Add_Existing": "Add Existing"
|
"Add_Existing": "Add Existing",
|
||||||
|
"Add_Existing_Channel": "Add Existing Channel",
|
||||||
|
"Remove_from_Team": "Remove from Team",
|
||||||
|
"Auto-join": "Auto-join"
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ const PERMISSIONS = [
|
||||||
'add-user-to-any-c-room',
|
'add-user-to-any-c-room',
|
||||||
'add-user-to-any-p-room',
|
'add-user-to-any-p-room',
|
||||||
'add-user-to-joined-room',
|
'add-user-to-joined-room',
|
||||||
|
'add-team-channel',
|
||||||
'archive-room',
|
'archive-room',
|
||||||
'auto-translate',
|
'auto-translate',
|
||||||
'create-invite-links',
|
'create-invite-links',
|
||||||
|
@ -21,11 +22,13 @@ const PERMISSIONS = [
|
||||||
'delete-p',
|
'delete-p',
|
||||||
'edit-message',
|
'edit-message',
|
||||||
'edit-room',
|
'edit-room',
|
||||||
|
'edit-team-channel',
|
||||||
'force-delete-message',
|
'force-delete-message',
|
||||||
'mute-user',
|
'mute-user',
|
||||||
'pin-message',
|
'pin-message',
|
||||||
'post-readonly',
|
'post-readonly',
|
||||||
'remove-user',
|
'remove-user',
|
||||||
|
'remove-team-channel',
|
||||||
'set-leader',
|
'set-leader',
|
||||||
'set-moderator',
|
'set-moderator',
|
||||||
'set-owner',
|
'set-owner',
|
||||||
|
@ -38,7 +41,9 @@ const PERMISSIONS = [
|
||||||
'view-privileged-setting',
|
'view-privileged-setting',
|
||||||
'view-room-administration',
|
'view-room-administration',
|
||||||
'view-statistics',
|
'view-statistics',
|
||||||
'view-user-administration'
|
'view-user-administration',
|
||||||
|
'view-all-teams',
|
||||||
|
'view-all-team-channels'
|
||||||
];
|
];
|
||||||
|
|
||||||
export async function setPermissions() {
|
export async function setPermissions() {
|
||||||
|
|
|
@ -734,7 +734,7 @@ const RocketChat = {
|
||||||
const params = {
|
const params = {
|
||||||
name,
|
name,
|
||||||
users,
|
users,
|
||||||
type: type ? 1 : 0,
|
type,
|
||||||
room: {
|
room: {
|
||||||
readOnly,
|
readOnly,
|
||||||
extraData: {
|
extraData: {
|
||||||
|
@ -746,6 +746,22 @@ const RocketChat = {
|
||||||
// RC 3.13.0
|
// RC 3.13.0
|
||||||
return this.post('teams.create', params);
|
return this.post('teams.create', params);
|
||||||
},
|
},
|
||||||
|
addTeamRooms({ rooms, teamId }) {
|
||||||
|
const params = {
|
||||||
|
rooms: rooms.length ? [...rooms] : [rooms],
|
||||||
|
teamId
|
||||||
|
};
|
||||||
|
// RC 3.13.0
|
||||||
|
return this.post('teams.addRooms', params);
|
||||||
|
},
|
||||||
|
deleteTeamRoom({ rid, teamId }) {
|
||||||
|
const params = {
|
||||||
|
roomId: rid,
|
||||||
|
teamId
|
||||||
|
};
|
||||||
|
// RC 3.13.0
|
||||||
|
return this.post('teams.removeRoom', params);
|
||||||
|
},
|
||||||
joinRoom(roomId, joinCode, type) {
|
joinRoom(roomId, joinCode, type) {
|
||||||
// TODO: join code
|
// TODO: join code
|
||||||
// RC 0.48.0
|
// RC 0.48.0
|
||||||
|
|
|
@ -42,6 +42,7 @@ const RoomItem = ({
|
||||||
testID,
|
testID,
|
||||||
swipeEnabled,
|
swipeEnabled,
|
||||||
onPress,
|
onPress,
|
||||||
|
onLongPress,
|
||||||
toggleFav,
|
toggleFav,
|
||||||
toggleRead,
|
toggleRead,
|
||||||
hideChannel,
|
hideChannel,
|
||||||
|
@ -49,6 +50,7 @@ const RoomItem = ({
|
||||||
}) => (
|
}) => (
|
||||||
<Touchable
|
<Touchable
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
|
onLongPress={onLongPress}
|
||||||
width={width}
|
width={width}
|
||||||
favorite={favorite}
|
favorite={favorite}
|
||||||
toggleFav={toggleFav}
|
toggleFav={toggleFav}
|
||||||
|
@ -181,6 +183,7 @@ RoomItem.propTypes = {
|
||||||
toggleFav: PropTypes.func,
|
toggleFav: PropTypes.func,
|
||||||
toggleRead: PropTypes.func,
|
toggleRead: PropTypes.func,
|
||||||
onPress: PropTypes.func,
|
onPress: PropTypes.func,
|
||||||
|
onLongPress: PropTypes.func,
|
||||||
hideChannel: PropTypes.func
|
hideChannel: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Animated } from 'react-native';
|
import { Animated, Pressable } from 'react-native';
|
||||||
import { PanGestureHandler, State } from 'react-native-gesture-handler';
|
import { PanGestureHandler, State } from 'react-native-gesture-handler';
|
||||||
|
|
||||||
import Touch from '../../utils/touch';
|
|
||||||
import {
|
import {
|
||||||
ACTION_WIDTH,
|
ACTION_WIDTH,
|
||||||
SMALL_SWIPE,
|
SMALL_SWIPE,
|
||||||
|
@ -17,6 +16,7 @@ class Touchable extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
type: PropTypes.string.isRequired,
|
type: PropTypes.string.isRequired,
|
||||||
onPress: PropTypes.func,
|
onPress: PropTypes.func,
|
||||||
|
onLongPress: PropTypes.func,
|
||||||
testID: PropTypes.string,
|
testID: PropTypes.string,
|
||||||
width: PropTypes.number,
|
width: PropTypes.number,
|
||||||
favorite: PropTypes.bool,
|
favorite: PropTypes.bool,
|
||||||
|
@ -203,6 +203,18 @@ class Touchable extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onLongPress = () => {
|
||||||
|
const { rowState } = this.state;
|
||||||
|
if (rowState !== 0) {
|
||||||
|
this.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { onLongPress } = this.props;
|
||||||
|
if (onLongPress) {
|
||||||
|
onLongPress();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
testID, isRead, width, favorite, children, theme, isFocused, swipeEnabled
|
testID, isRead, width, favorite, children, theme, isFocused, swipeEnabled
|
||||||
|
@ -237,8 +249,9 @@ class Touchable extends React.Component {
|
||||||
transform: [{ translateX: this.transX }]
|
transform: [{ translateX: this.transX }]
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Touch
|
<Pressable
|
||||||
onPress={this.onPress}
|
onPress={this.onPress}
|
||||||
|
onLongPress={this.onLongPress}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
style={{
|
style={{
|
||||||
|
@ -246,7 +259,7 @@ class Touchable extends React.Component {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Touch>
|
</Pressable>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ class RoomItemContainer extends React.Component {
|
||||||
showLastMessage: PropTypes.bool,
|
showLastMessage: PropTypes.bool,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
onPress: PropTypes.func,
|
onPress: PropTypes.func,
|
||||||
|
onLongPress: PropTypes.func,
|
||||||
username: PropTypes.string,
|
username: PropTypes.string,
|
||||||
avatarSize: PropTypes.number,
|
avatarSize: PropTypes.number,
|
||||||
width: PropTypes.number,
|
width: PropTypes.number,
|
||||||
|
@ -112,6 +113,11 @@ class RoomItemContainer extends React.Component {
|
||||||
return onPress(item);
|
return onPress(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onLongPress = () => {
|
||||||
|
const { item, onLongPress } = this.props;
|
||||||
|
return onLongPress(item);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
item,
|
item,
|
||||||
|
@ -160,6 +166,7 @@ class RoomItemContainer extends React.Component {
|
||||||
isGroupChat={this.isGroupChat}
|
isGroupChat={this.isGroupChat}
|
||||||
isRead={isRead}
|
isRead={isRead}
|
||||||
onPress={this.onPress}
|
onPress={this.onPress}
|
||||||
|
onLongPress={this.onLongPress}
|
||||||
date={date}
|
date={date}
|
||||||
accessibilityLabel={accessibilityLabel}
|
accessibilityLabel={accessibilityLabel}
|
||||||
width={width}
|
width={width}
|
||||||
|
|
|
@ -25,6 +25,10 @@ const createTeam = function createTeam(data) {
|
||||||
return RocketChat.createTeam(data);
|
return RocketChat.createTeam(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addTeamRoom = function addRoomToTeam(params) {
|
||||||
|
return RocketChat.addTeamRoom(params);
|
||||||
|
};
|
||||||
|
|
||||||
const handleRequest = function* handleRequest({ data }) {
|
const handleRequest = function* handleRequest({ data }) {
|
||||||
try {
|
try {
|
||||||
const auth = yield select(state => state.login.isAuthenticated);
|
const auth = yield select(state => state.login.isAuthenticated);
|
||||||
|
@ -40,6 +44,7 @@ const handleRequest = function* handleRequest({ data }) {
|
||||||
broadcast,
|
broadcast,
|
||||||
encrypted
|
encrypted
|
||||||
} = data;
|
} = data;
|
||||||
|
// TODO: Create event CT_CREATE
|
||||||
logEvent(events.CR_CREATE, {
|
logEvent(events.CR_CREATE, {
|
||||||
type,
|
type,
|
||||||
readOnly,
|
readOnly,
|
||||||
|
@ -67,14 +72,22 @@ const handleRequest = function* handleRequest({ data }) {
|
||||||
encrypted
|
encrypted
|
||||||
});
|
});
|
||||||
sub = yield call(createChannel, data);
|
sub = yield call(createChannel, data);
|
||||||
}
|
|
||||||
|
|
||||||
|
if (data.teamId) {
|
||||||
|
// TODO: Log when adding room to team
|
||||||
|
const channels = yield call(addTeamRoom, { rooms: sub.rid, teamId: data.teamId });
|
||||||
|
if (channels.success) {
|
||||||
|
sub.teamId = channels.teamId;
|
||||||
|
sub.isTeamChannel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
const subCollection = db.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
yield db.action(async() => {
|
yield db.action(async() => {
|
||||||
await subCollection.create((s) => {
|
await subCollection.create((s) => {
|
||||||
s._raw = sanitizedRaw({ id: sub.team ? sub.team.roomId : sub.rid }, subCollection.schema);
|
s._raw = sanitizedRaw({ id: sub.team ? sub.team.roomId : sub.rid, team_id: sub.teamId }, subCollection.schema);
|
||||||
Object.assign(s, sub);
|
Object.assign(s, sub);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -72,6 +72,7 @@ import CreateDiscussionView from '../views/CreateDiscussionView';
|
||||||
|
|
||||||
import QueueListView from '../ee/omnichannel/views/QueueListView';
|
import QueueListView from '../ee/omnichannel/views/QueueListView';
|
||||||
import AddChannelTeamView from '../views/AddChannelTeamView';
|
import AddChannelTeamView from '../views/AddChannelTeamView';
|
||||||
|
import AddExistingChannelView from '../views/AddExistingChannelView';
|
||||||
|
|
||||||
// ChatsStackNavigator
|
// ChatsStackNavigator
|
||||||
const ChatsStack = createStackNavigator();
|
const ChatsStack = createStackNavigator();
|
||||||
|
@ -180,6 +181,11 @@ const ChatsStackNavigator = () => {
|
||||||
component={AddChannelTeamView}
|
component={AddChannelTeamView}
|
||||||
options={AddChannelTeamView.navigationOptions}
|
options={AddChannelTeamView.navigationOptions}
|
||||||
/>
|
/>
|
||||||
|
<ChatsStack.Screen
|
||||||
|
name='AddExistingChannelView'
|
||||||
|
component={AddExistingChannelView}
|
||||||
|
options={AddExistingChannelView.navigationOptions}
|
||||||
|
/>
|
||||||
<ChatsStack.Screen
|
<ChatsStack.Screen
|
||||||
name='MarkdownTableView'
|
name='MarkdownTableView'
|
||||||
component={MarkdownTableView}
|
component={MarkdownTableView}
|
||||||
|
|
|
@ -8,17 +8,34 @@ const navigate = ({ item, isMasterDetail, ...props }) => {
|
||||||
navigationMethod = Navigation.replace;
|
navigationMethod = Navigation.replace;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigationMethod('RoomView', {
|
if (item.isTeamChannel) {
|
||||||
rid: item.roomId || item.rid,
|
// TODO: Refactor
|
||||||
name: RocketChat.getRoomTitle(item),
|
Navigation.navigate('TeamChannelsView');
|
||||||
t: item.type ? 'p' : item.t,
|
Navigation.push('RoomView', {
|
||||||
prid: item.prid,
|
rid: item.roomId || item.rid,
|
||||||
room: item,
|
name: RocketChat.getRoomTitle(item),
|
||||||
search: item.search,
|
t: item.type ? 'p' : item.t,
|
||||||
visitor: item.visitor,
|
prid: item.prid,
|
||||||
roomUserId: RocketChat.getUidDirectMessage(item),
|
room: item,
|
||||||
...props
|
search: item.search,
|
||||||
});
|
visitor: item.visitor,
|
||||||
|
roomUserId: RocketChat.getUidDirectMessage(item),
|
||||||
|
teamId: item.teamId,
|
||||||
|
...props
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
navigationMethod('RoomView', {
|
||||||
|
rid: item.roomId || item.rid,
|
||||||
|
name: RocketChat.getRoomTitle(item),
|
||||||
|
t: item.type ? 'p' : item.t,
|
||||||
|
prid: item.prid,
|
||||||
|
room: item,
|
||||||
|
search: item.search,
|
||||||
|
visitor: item.visitor,
|
||||||
|
roomUserId: RocketChat.getUidDirectMessage(item),
|
||||||
|
...props
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const goRoom = async({ item = {}, isMasterDetail = false, ...props }) => {
|
export const goRoom = async({ item = {}, isMasterDetail = false, ...props }) => {
|
||||||
|
|
|
@ -15,13 +15,14 @@ class Touch extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
children, onPress, theme, underlayColor, ...props
|
children, onPress, onLongPress, theme, underlayColor, ...props
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RectButton
|
<RectButton
|
||||||
ref={this.getRef}
|
ref={this.getRef}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
|
onLongPress={onLongPress}
|
||||||
activeOpacity={1}
|
activeOpacity={1}
|
||||||
underlayColor={underlayColor || themes[theme].bannerBackground}
|
underlayColor={underlayColor || themes[theme].bannerBackground}
|
||||||
rippleColor={themes[theme].bannerBackground}
|
rippleColor={themes[theme].bannerBackground}
|
||||||
|
@ -36,6 +37,7 @@ class Touch extends React.Component {
|
||||||
Touch.propTypes = {
|
Touch.propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
onPress: PropTypes.func,
|
onPress: PropTypes.func,
|
||||||
|
onLongPress: PropTypes.func,
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
underlayColor: PropTypes.string
|
underlayColor: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,6 @@ import sharedStyles from './Styles';
|
||||||
import { CustomIcon } from '../lib/Icons';
|
import { CustomIcon } from '../lib/Icons';
|
||||||
import Touch from '../utils/touch';
|
import Touch from '../utils/touch';
|
||||||
import StatusBar from '../containers/StatusBar';
|
import StatusBar from '../containers/StatusBar';
|
||||||
import RoomHeader from '../containers/RoomHeader';
|
|
||||||
import { withTheme } from '../theme';
|
import { withTheme } from '../theme';
|
||||||
import * as HeaderButton from '../containers/HeaderButton';
|
import * as HeaderButton from '../containers/HeaderButton';
|
||||||
import SafeAreaView from '../containers/SafeAreaView';
|
import SafeAreaView from '../containers/SafeAreaView';
|
||||||
|
@ -47,9 +46,7 @@ class AddChannelTeamView extends React.Component {
|
||||||
const options = {
|
const options = {
|
||||||
headerShown: true,
|
headerShown: true,
|
||||||
headerTitleAlign: 'center',
|
headerTitleAlign: 'center',
|
||||||
headerTitle: () => (
|
headerTitle: I18n.t('Add_Channel_to_Team')
|
||||||
<RoomHeader title={I18n.t('Add_Channel_to_Team')} />
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isMasterDetail) {
|
if (isMasterDetail) {
|
||||||
|
@ -74,7 +71,7 @@ class AddChannelTeamView extends React.Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Touch
|
<Touch
|
||||||
onPress={() => onPress()}
|
onPress={onPress}
|
||||||
style={{ backgroundColor: themes[theme].backgroundColor }}
|
style={{ backgroundColor: themes[theme].backgroundColor }}
|
||||||
testID={testID}
|
testID={testID}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
@ -88,21 +85,22 @@ class AddChannelTeamView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { navigation } = this.props;
|
const { navigation, route } = this.props;
|
||||||
|
const { teamChannels } = route?.params;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaView testID='add-channel-team-view'>
|
<SafeAreaView testID='add-channel-team-view'>
|
||||||
<StatusBar />
|
<StatusBar />
|
||||||
<View style={styles.buttonContainer}>
|
<View style={styles.buttonContainer}>
|
||||||
{this.renderButton({
|
{this.renderButton({
|
||||||
onPress: navigation.navigate('NewMessageStackNavigator', { screen: 'CreateChannelView', isTeam: false }),
|
onPress: () => navigation.navigate('NewMessageStackNavigator', { screen: 'SelectedUsersViewCreateChannel', params: { nextAction: () => navigation.navigate('CreateChannelView', { teamId: this.teamId }) } }),
|
||||||
title: I18n.t('Create_New'),
|
title: I18n.t('Create_New'),
|
||||||
icon: 'channel-public',
|
icon: 'channel-public',
|
||||||
testID: 'add-channel-team-view-create-channel',
|
testID: 'add-channel-team-view-create-channel',
|
||||||
first: true
|
first: true
|
||||||
})}
|
})}
|
||||||
{this.renderButton({
|
{this.renderButton({
|
||||||
// onPress: navigation.navigate('AddExistingChannelView'),
|
onPress: () => navigation.navigate('AddExistingChannelView', { teamId: this.teamId, teamChannels }),
|
||||||
title: I18n.t('Add_Existing'),
|
title: I18n.t('Add_Existing'),
|
||||||
icon: 'team',
|
icon: 'team',
|
||||||
testID: 'add-channel-team-view-create-channel'
|
testID: 'add-channel-team-view-create-channel'
|
||||||
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
/* eslint-disable no-mixed-spaces-and-tabs */
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {
|
||||||
|
View, StyleSheet, FlatList, Text
|
||||||
|
} from 'react-native';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { Q } from '@nozbe/watermelondb';
|
||||||
|
import { HeaderBackButton } from '@react-navigation/stack';
|
||||||
|
import * as List from '../containers/List';
|
||||||
|
|
||||||
|
import Touch from '../utils/touch';
|
||||||
|
import database from '../lib/database';
|
||||||
|
import RocketChat from '../lib/rocketchat';
|
||||||
|
import sharedStyles from './Styles';
|
||||||
|
import I18n from '../i18n';
|
||||||
|
import log from '../utils/log';
|
||||||
|
import SearchBox from '../containers/SearchBox';
|
||||||
|
import { CustomIcon } from '../lib/Icons';
|
||||||
|
import * as HeaderButton from '../containers/HeaderButton';
|
||||||
|
import StatusBar from '../containers/StatusBar';
|
||||||
|
import { themes } from '../constants/colors';
|
||||||
|
import { withTheme } from '../theme';
|
||||||
|
import SafeAreaView from '../containers/SafeAreaView';
|
||||||
|
import { animateNextTransition } from '../utils/layoutAnimation';
|
||||||
|
import { goRoom } from '../utils/goRoom';
|
||||||
|
import Loading from '../containers/Loading';
|
||||||
|
|
||||||
|
const QUERY_SIZE = 15;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
button: {
|
||||||
|
height: 46,
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center'
|
||||||
|
},
|
||||||
|
buttonIcon: {
|
||||||
|
marginLeft: 18,
|
||||||
|
marginRight: 16
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
fontSize: 17,
|
||||||
|
...sharedStyles.textRegular
|
||||||
|
},
|
||||||
|
textContainer: {
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginRight: 15
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
marginHorizontal: 15,
|
||||||
|
alignSelf: 'center'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class AddExistingChannelView extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
navigation: PropTypes.object,
|
||||||
|
route: PropTypes.object,
|
||||||
|
user: PropTypes.shape({
|
||||||
|
id: PropTypes.string,
|
||||||
|
token: PropTypes.string
|
||||||
|
}),
|
||||||
|
theme: PropTypes.string,
|
||||||
|
isMasterDetail: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.init();
|
||||||
|
this.teamId = props.route?.params?.teamId;
|
||||||
|
this.state = {
|
||||||
|
search: [],
|
||||||
|
channels: [],
|
||||||
|
selected: [],
|
||||||
|
loading: false
|
||||||
|
};
|
||||||
|
this.setHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
setHeader = () => {
|
||||||
|
const { navigation, isMasterDetail, theme } = this.props;
|
||||||
|
const { selected } = this.state;
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
headerShown: true,
|
||||||
|
headerTitleAlign: 'center',
|
||||||
|
headerTitle: I18n.t('Add_Existing_Channel')
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isMasterDetail) {
|
||||||
|
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
|
||||||
|
} else {
|
||||||
|
options.headerLeft = () => <HeaderBackButton labelVisible={false} onPress={() => navigation.pop()} tintColor={themes[theme].headerTintColor} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.headerRight = () => selected.length > 0 && (
|
||||||
|
<HeaderButton.Container>
|
||||||
|
<HeaderButton.Item title={I18n.t('Create')} onPress={this.submit} testID='add-existing-channel-view-submit' />
|
||||||
|
</HeaderButton.Container>
|
||||||
|
);
|
||||||
|
|
||||||
|
navigation.setOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line react/sort-comp
|
||||||
|
init = async() => {
|
||||||
|
try {
|
||||||
|
const db = database.active;
|
||||||
|
const channels = await db.collections
|
||||||
|
.get('subscriptions')
|
||||||
|
.query(
|
||||||
|
Q.where('t', 'p'),
|
||||||
|
Q.where('team_id', ''),
|
||||||
|
Q.experimentalTake(QUERY_SIZE),
|
||||||
|
Q.experimentalSortBy('room_updated_at', Q.desc)
|
||||||
|
)
|
||||||
|
.fetch();
|
||||||
|
this.setState({ channels });
|
||||||
|
} catch (e) {
|
||||||
|
log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearchChangeText(text) {
|
||||||
|
this.search(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss = () => {
|
||||||
|
const { navigation } = this.props;
|
||||||
|
return navigation.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
search = async(text) => {
|
||||||
|
const result = await RocketChat.search({ text, filterUsers: false });
|
||||||
|
this.setState({
|
||||||
|
search: result
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
submit = async() => {
|
||||||
|
const { selected } = this.state;
|
||||||
|
const { isMasterDetail } = this.props;
|
||||||
|
|
||||||
|
this.setState({ loading: true });
|
||||||
|
try {
|
||||||
|
// TODO: Log request
|
||||||
|
const result = await RocketChat.addTeamRooms({ rooms: selected, teamId: this.teamId });
|
||||||
|
if (result.success) {
|
||||||
|
this.setState({ loading: false });
|
||||||
|
goRoom(result, isMasterDetail);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// TODO: Log error
|
||||||
|
this.setState({ loading: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderChannel = ({
|
||||||
|
onPress, testID, title, icon, checked
|
||||||
|
}) => {
|
||||||
|
const { theme } = this.props;
|
||||||
|
return (
|
||||||
|
<Touch
|
||||||
|
onPress={onPress}
|
||||||
|
style={{ backgroundColor: themes[theme].backgroundColor }}
|
||||||
|
testID={testID}
|
||||||
|
theme={theme}
|
||||||
|
>
|
||||||
|
<View style={[styles.button, { borderColor: themes[theme].separatorColor, marginVertical: 4 }]}>
|
||||||
|
<CustomIcon style={[styles.buttonIcon, { color: themes[theme].controlText }]} size={24} name={icon} />
|
||||||
|
<View style={styles.textContainer}>
|
||||||
|
<Text style={[styles.buttonText, { color: themes[theme].bodyText }]}>{title}</Text>
|
||||||
|
</View>
|
||||||
|
{checked ? <CustomIcon name={checked} size={22} style={[styles.icon, { color: themes[theme].actionTintColor }]} /> : null}
|
||||||
|
</View>
|
||||||
|
</Touch>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderHeader = () => {
|
||||||
|
const { theme } = this.props;
|
||||||
|
return (
|
||||||
|
<View style={{ backgroundColor: themes[theme].auxiliaryBackground }}>
|
||||||
|
<SearchBox onChangeText={text => this.onSearchChangeText(text)} testID='add-existing-channel-view-search' />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
isChecked = (rid) => {
|
||||||
|
const { selected } = this.state;
|
||||||
|
return selected.includes(rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleChannel = (rid) => {
|
||||||
|
const { selected } = this.state;
|
||||||
|
|
||||||
|
animateNextTransition();
|
||||||
|
if (!this.isChecked(rid)) {
|
||||||
|
// logEvent(events.SELECTED_USERS_ADD_USER);
|
||||||
|
this.setState({ selected: [...selected, rid] }, () => this.setHeader());
|
||||||
|
} else {
|
||||||
|
// logEvent(events.SELECTED_USERS_REMOVE_USER);
|
||||||
|
const filterSelected = selected.filter(el => el !== rid);
|
||||||
|
this.setState({ selected: filterSelected }, () => this.setHeader());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderItem = ({ item }) => (
|
||||||
|
<>
|
||||||
|
{this.renderChannel({
|
||||||
|
onPress: () => this.toggleChannel(item.rid),
|
||||||
|
title: item.name,
|
||||||
|
icon: item.t === 'p' && !item.teamId ? 'channel-private' : 'channel-public',
|
||||||
|
checked: this.isChecked(item.rid) ? 'check' : null,
|
||||||
|
testID: 'add-existing-channel-view-item'
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
renderList = () => {
|
||||||
|
const { search, channels } = this.state;
|
||||||
|
const { theme } = this.props;
|
||||||
|
return (
|
||||||
|
<FlatList
|
||||||
|
data={search.length > 0 ? search : channels}
|
||||||
|
extraData={this.state}
|
||||||
|
keyExtractor={item => item._id}
|
||||||
|
ListHeaderComponent={this.renderHeader}
|
||||||
|
renderItem={this.renderItem}
|
||||||
|
ItemSeparatorComponent={List.Separator}
|
||||||
|
contentContainerStyle={{ backgroundColor: themes[theme].backgroundColor }}
|
||||||
|
keyboardShouldPersistTaps='always'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { loading } = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SafeAreaView testID='new-message-view'>
|
||||||
|
<StatusBar />
|
||||||
|
{this.renderList()}
|
||||||
|
<Loading visible={loading} />
|
||||||
|
</SafeAreaView>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
isMasterDetail: state.app.isMasterDetail
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(withTheme(AddExistingChannelView));
|
|
@ -87,13 +87,15 @@ class CreateChannelView extends React.Component {
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
token: PropTypes.string
|
token: PropTypes.string
|
||||||
}),
|
}),
|
||||||
theme: PropTypes.string
|
theme: PropTypes.string,
|
||||||
|
teamId: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
const { route } = this.props;
|
const { route } = this.props;
|
||||||
this.isTeam = route?.params?.isTeam || false;
|
this.isTeam = route?.params?.isTeam || false;
|
||||||
|
this.teamId = route?.params?.teamId;
|
||||||
this.state = {
|
this.state = {
|
||||||
channelName: '',
|
channelName: '',
|
||||||
type: true,
|
type: true,
|
||||||
|
@ -173,7 +175,7 @@ class CreateChannelView extends React.Component {
|
||||||
|
|
||||||
// create channel or team
|
// create channel or team
|
||||||
create({
|
create({
|
||||||
name: channelName, users, type, readOnly, broadcast, encrypted, isTeam: this.isTeam
|
name: channelName, users, type, readOnly, broadcast, encrypted, isTeam: this.isTeam, teamId: this.teamId
|
||||||
});
|
});
|
||||||
|
|
||||||
Review.pushPositiveEvent();
|
Review.pushPositiveEvent();
|
||||||
|
|
|
@ -114,7 +114,7 @@ class RightButtonsContainer extends Component {
|
||||||
goTeamChannels = () => {
|
goTeamChannels = () => {
|
||||||
logEvent(events.ROOM_GO_TEAM_CHANNELS);
|
logEvent(events.ROOM_GO_TEAM_CHANNELS);
|
||||||
const {
|
const {
|
||||||
navigation, isMasterDetail, teamId
|
navigation, isMasterDetail, teamId, rid
|
||||||
} = this.props;
|
} = this.props;
|
||||||
if (isMasterDetail) {
|
if (isMasterDetail) {
|
||||||
navigation.navigate('ModalStackNavigator', {
|
navigation.navigate('ModalStackNavigator', {
|
||||||
|
@ -122,7 +122,7 @@ class RightButtonsContainer extends Component {
|
||||||
params: { teamId }
|
params: { teamId }
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
navigation.navigate('TeamChannelsView', { teamId });
|
navigation.navigate('TeamChannelsView', { teamId, rid });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Keyboard } from 'react-native';
|
import { Keyboard, Alert } from 'react-native';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Q } from '@nozbe/watermelondb';
|
import { Q } from '@nozbe/watermelondb';
|
||||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
|
@ -28,6 +28,8 @@ import debounce from '../utils/debounce';
|
||||||
import { showErrorAlert } from '../utils/info';
|
import { showErrorAlert } from '../utils/info';
|
||||||
import { goRoom } from '../utils/goRoom';
|
import { goRoom } from '../utils/goRoom';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
|
import { withActionSheet } from '../containers/ActionSheet';
|
||||||
|
import { deleteRoom as deleteRoomAction } from '../actions/room';
|
||||||
|
|
||||||
const API_FETCH_COUNT = 25;
|
const API_FETCH_COUNT = 25;
|
||||||
|
|
||||||
|
@ -47,12 +49,16 @@ class TeamChannelsView extends React.Component {
|
||||||
theme: PropTypes.string,
|
theme: PropTypes.string,
|
||||||
useRealName: PropTypes.bool,
|
useRealName: PropTypes.bool,
|
||||||
width: PropTypes.number,
|
width: PropTypes.number,
|
||||||
StoreLastMessage: PropTypes.bool
|
StoreLastMessage: PropTypes.bool,
|
||||||
|
addTeamChannelPermission: PropTypes.array,
|
||||||
|
showActionSheet: PropTypes.func,
|
||||||
|
deleteRoom: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.teamId = props.route.params?.teamId;
|
this.teamId = props.route.params?.teamId;
|
||||||
|
this.rid = props.route.params?.rid;
|
||||||
this.state = {
|
this.state = {
|
||||||
loading: true,
|
loading: true,
|
||||||
loadingMore: false,
|
loadingMore: false,
|
||||||
|
@ -60,9 +66,11 @@ class TeamChannelsView extends React.Component {
|
||||||
isSearching: false,
|
isSearching: false,
|
||||||
searchText: '',
|
searchText: '',
|
||||||
search: [],
|
search: [],
|
||||||
end: false
|
end: false,
|
||||||
|
showCreate: false
|
||||||
};
|
};
|
||||||
this.loadTeam();
|
this.loadTeam();
|
||||||
|
this.setHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -70,6 +78,7 @@ class TeamChannelsView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTeam = async() => {
|
loadTeam = async() => {
|
||||||
|
const { addTeamChannelPermission } = this.props;
|
||||||
const db = database.active;
|
const db = database.active;
|
||||||
try {
|
try {
|
||||||
const subCollection = db.get('subscriptions');
|
const subCollection = db.get('subscriptions');
|
||||||
|
@ -82,6 +91,11 @@ class TeamChannelsView extends React.Component {
|
||||||
if (!this.team) {
|
if (!this.team) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const permissions = await RocketChat.hasPermission([addTeamChannelPermission], this.team.rid);
|
||||||
|
if (permissions[0]) {
|
||||||
|
this.setState({ showCreate: true }, () => this.setHeader());
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
const { navigation } = this.props;
|
const { navigation } = this.props;
|
||||||
navigation.pop();
|
navigation.pop();
|
||||||
|
@ -135,8 +149,8 @@ class TeamChannelsView extends React.Component {
|
||||||
}
|
}
|
||||||
}, 300)
|
}, 300)
|
||||||
|
|
||||||
getHeader = () => {
|
setHeader = () => {
|
||||||
const { isSearching } = this.state;
|
const { isSearching, showCreate, data } = this.state;
|
||||||
const {
|
const {
|
||||||
navigation, isMasterDetail, insets, theme
|
navigation, isMasterDetail, insets, theme
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
@ -201,15 +215,11 @@ class TeamChannelsView extends React.Component {
|
||||||
options.headerRight = () => (
|
options.headerRight = () => (
|
||||||
<HeaderButton.Container>
|
<HeaderButton.Container>
|
||||||
<HeaderButton.Item iconName='search' onPress={this.onSearchPress} />
|
<HeaderButton.Item iconName='search' onPress={this.onSearchPress} />
|
||||||
<HeaderButton.Item iconName='create' onPress={() => navigation.navigate('AddChannelTeamView')} />
|
{ showCreate
|
||||||
|
? <HeaderButton.Item iconName='create' onPress={() => navigation.navigate('AddChannelTeamView', { teamId: this.teamId, teamChannels: data })} />
|
||||||
|
: null}
|
||||||
</HeaderButton.Container>
|
</HeaderButton.Container>
|
||||||
);
|
);
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
setHeader = () => {
|
|
||||||
const { navigation } = this.props;
|
|
||||||
const options = this.getHeader();
|
|
||||||
navigation.setOptions(options);
|
navigation.setOptions(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,6 +298,54 @@ class TeamChannelsView extends React.Component {
|
||||||
}
|
}
|
||||||
}, 1000, true);
|
}, 1000, true);
|
||||||
|
|
||||||
|
options = item => ([
|
||||||
|
{
|
||||||
|
title: I18n.t('Auto-join'),
|
||||||
|
icon: item.t === 'p' ? 'channel-private' : 'channel-public'
|
||||||
|
// onPress: this.autoJoin
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: I18n.t('Remove_from_Team'),
|
||||||
|
icon: 'close',
|
||||||
|
danger: true,
|
||||||
|
onPress: this.removeFromTeam(item.id, this.teamId)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: I18n.t('Delete'),
|
||||||
|
icon: 'delete',
|
||||||
|
danger: true,
|
||||||
|
onPress: this.delete
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
delete = () => {
|
||||||
|
const { room } = this.state;
|
||||||
|
const { deleteRoom } = this.props;
|
||||||
|
|
||||||
|
Alert.alert(
|
||||||
|
I18n.t('Are_you_sure_question_mark'),
|
||||||
|
I18n.t('Delete_Room_Warning'),
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: I18n.t('Cancel'),
|
||||||
|
style: 'cancel'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: I18n.t('Yes_action_it', { action: I18n.t('delete') }),
|
||||||
|
style: 'destructive',
|
||||||
|
onPress: () => deleteRoom(room.rid, room.t)
|
||||||
|
}
|
||||||
|
],
|
||||||
|
{ cancelable: false }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
showChannelActions = (item) => {
|
||||||
|
logEvent(events.ROOM_SHOW_BOX_ACTIONS);
|
||||||
|
const { showActionSheet } = this.props;
|
||||||
|
showActionSheet({ options: this.options(item) });
|
||||||
|
}
|
||||||
|
|
||||||
renderItem = ({ item }) => {
|
renderItem = ({ item }) => {
|
||||||
const {
|
const {
|
||||||
StoreLastMessage,
|
StoreLastMessage,
|
||||||
|
@ -303,6 +361,7 @@ class TeamChannelsView extends React.Component {
|
||||||
showLastMessage={StoreLastMessage}
|
showLastMessage={StoreLastMessage}
|
||||||
onPress={this.onPressItem}
|
onPress={this.onPressItem}
|
||||||
width={width}
|
width={width}
|
||||||
|
onLongPress={this.showChannelActions}
|
||||||
useRealName={useRealName}
|
useRealName={useRealName}
|
||||||
getRoomTitle={this.getRoomTitle}
|
getRoomTitle={this.getRoomTitle}
|
||||||
getRoomAvatar={this.getRoomAvatar}
|
getRoomAvatar={this.getRoomAvatar}
|
||||||
|
@ -366,7 +425,12 @@ const mapStateToProps = state => ({
|
||||||
user: getUserSelector(state),
|
user: getUserSelector(state),
|
||||||
useRealName: state.settings.UI_Use_Real_Name,
|
useRealName: state.settings.UI_Use_Real_Name,
|
||||||
isMasterDetail: state.app.isMasterDetail,
|
isMasterDetail: state.app.isMasterDetail,
|
||||||
StoreLastMessage: state.settings.Store_Last_Message
|
StoreLastMessage: state.settings.Store_Last_Message,
|
||||||
|
addTeamChannelPermission: state.permissions['add-team-channel']
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps)(withDimensions(withSafeAreaInsets(withTheme(TeamChannelsView))));
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
deleteRoom: (rid, t) => dispatch(deleteRoomAction(rid, t))
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(withDimensions(withSafeAreaInsets(withTheme(withActionSheet(TeamChannelsView)))));
|
||||||
|
|
Loading…
Reference in New Issue