[NEW] Add/Create/Remove channel on a team (#3090)
* Added Create Team * Added actionTypes, actions, ENG strings for Teams and updated NewMessageView * Added createTeam sagas, createTeam reducer, new Team string and update CreateChannelView * Remove unnecessary actionTypes, reducers and sagas, e2e tests and navigation to team view * Minor tweaks * Show TeamChannelsView only if joined the team * Minor tweak * Added AddChannelTeamView * Added permissions, translations strings for teams, deleteTeamRoom and addTeamRooms, AddExistingChannelView, updated CreateChannelView, TeamChannelsView * Refactor touch component and update removeRoom and deleteRoom methods * Minor tweaks * Minor tweaks for removing channels and addExistingChannelView * Added missing events and fixed channels list * Minor tweaks for refactored touch component * Minor tweaks * Remove unnecesary changes, update TeamChannelsView, AddExistingChannelView, AddChannelTeamView, createChannel, goRoom and Touchable * Add screens to ModalStack, events, autoJoin, update createChannel, addRoomsToTeam and Touchable * Minor tweak * Update loadMessagesForRoom.js * Updated schema, tag component, touch, AddChannelTeamView, AddExistingChannelView, ActionSheet Item * Fix unnecessary changes * Add i18n, update createChannel, AddExistingChannelTeamView, AddChannelTeamView, RightButton and TeamChannelsView * Updated styles, added tag story * Minor tweak * Minor tweaks * Auto-join tweak * Minor tweaks * Minor tweak on search * One way to refactor :P * Next level refactor :) * Fix create group dm * Refactor renderItem * Minor bug fixes * Fix stories Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
b701913478
commit
9670fa623a
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Text } from 'react-native';
|
||||
import { Text, View } from 'react-native';
|
||||
|
||||
import { themes } from '../../constants/colors';
|
||||
import { CustomIcon } from '../../lib/Icons';
|
||||
|
@ -20,12 +20,19 @@ export const Item = React.memo(({ item, hide, theme }) => {
|
|||
theme={theme}
|
||||
>
|
||||
<CustomIcon name={item.icon} size={20} color={item.danger ? themes[theme].dangerColor : themes[theme].bodyText} />
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[styles.title, { color: item.danger ? themes[theme].dangerColor : themes[theme].bodyText }]}
|
||||
>
|
||||
{item.title}
|
||||
</Text>
|
||||
<View style={styles.titleContainer}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[styles.title, { color: item.danger ? themes[theme].dangerColor : themes[theme].bodyText }]}
|
||||
>
|
||||
{item.title}
|
||||
</Text>
|
||||
</View>
|
||||
{ item.right ? (
|
||||
<View style={styles.rightContainer}>
|
||||
{item.right ? item.right() : null}
|
||||
</View>
|
||||
) : null }
|
||||
</Button>
|
||||
);
|
||||
});
|
||||
|
@ -34,7 +41,8 @@ Item.propTypes = {
|
|||
title: PropTypes.string,
|
||||
icon: PropTypes.string,
|
||||
danger: PropTypes.bool,
|
||||
onPress: PropTypes.func
|
||||
onPress: PropTypes.func,
|
||||
right: PropTypes.func
|
||||
}),
|
||||
hide: PropTypes.func,
|
||||
theme: PropTypes.string
|
||||
|
|
|
@ -22,6 +22,9 @@ export default StyleSheet.create({
|
|||
content: {
|
||||
paddingTop: 16
|
||||
},
|
||||
titleContainer: {
|
||||
flex: 1
|
||||
},
|
||||
title: {
|
||||
fontSize: 16,
|
||||
marginLeft: 16,
|
||||
|
@ -58,5 +61,8 @@ export default StyleSheet.create({
|
|||
fontSize: 16,
|
||||
...sharedStyles.textMedium,
|
||||
...sharedStyles.textAlignCenter
|
||||
},
|
||||
rightContainer: {
|
||||
paddingLeft: 12
|
||||
}
|
||||
});
|
||||
|
|
|
@ -30,6 +30,7 @@ const RoomTypeIcon = React.memo(({
|
|||
return <Status style={[iconStyle, { color: STATUS_COLORS[status] ?? STATUS_COLORS.offline }]} size={size} status={status} />;
|
||||
}
|
||||
|
||||
// TODO: move this to a separate function
|
||||
let icon = 'channel-private';
|
||||
if (teamMain) {
|
||||
icon = `teams${ type === 'p' ? '-private' : '' }`;
|
||||
|
|
|
@ -435,6 +435,7 @@
|
|||
"Review_app_unable_store": "Unable to open {{store}}",
|
||||
"Review_this_app": "Review this app",
|
||||
"Remove": "Remove",
|
||||
"remove": "remove",
|
||||
"Roles": "Roles",
|
||||
"Room_actions": "Room actions",
|
||||
"Room_changed_announcement": "Room announcement changed to: {{announcement}} by {{userBy}}",
|
||||
|
@ -716,5 +717,14 @@
|
|||
"Read_Only_Team": "Read Only Team",
|
||||
"Broadcast_Team": "Broadcast Team",
|
||||
"creating_team": "creating team",
|
||||
"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",
|
||||
"Create_New": "Create New",
|
||||
"Add_Existing": "Add Existing",
|
||||
"Add_Existing_Channel": "Add Existing Channel",
|
||||
"Remove_from_Team": "Remove from Team",
|
||||
"Auto-join": "Auto-join",
|
||||
"Delete_Team_Room_Warning": "Woud you like to remove this channel from the team? The channel will be moved back to the workspace",
|
||||
"Confirmation": "Confirmation",
|
||||
"invalid-room": "Invalid room"
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ const PERMISSIONS = [
|
|||
'add-user-to-any-c-room',
|
||||
'add-user-to-any-p-room',
|
||||
'add-user-to-joined-room',
|
||||
'add-team-channel',
|
||||
'archive-room',
|
||||
'auto-translate',
|
||||
'create-invite-links',
|
||||
|
@ -21,11 +22,13 @@ const PERMISSIONS = [
|
|||
'delete-p',
|
||||
'edit-message',
|
||||
'edit-room',
|
||||
'edit-team-channel',
|
||||
'force-delete-message',
|
||||
'mute-user',
|
||||
'pin-message',
|
||||
'post-readonly',
|
||||
'remove-user',
|
||||
'remove-team-channel',
|
||||
'set-leader',
|
||||
'set-moderator',
|
||||
'set-owner',
|
||||
|
@ -38,7 +41,9 @@ const PERMISSIONS = [
|
|||
'view-privileged-setting',
|
||||
'view-room-administration',
|
||||
'view-statistics',
|
||||
'view-user-administration'
|
||||
'view-user-administration',
|
||||
'view-all-teams',
|
||||
'view-all-team-channels'
|
||||
];
|
||||
|
||||
export async function setPermissions() {
|
||||
|
|
|
@ -95,10 +95,19 @@ const RocketChat = {
|
|||
},
|
||||
canOpenRoom,
|
||||
createChannel({
|
||||
name, users, type, readOnly, broadcast, encrypted
|
||||
name, users, type, readOnly, broadcast, encrypted, teamId
|
||||
}) {
|
||||
// RC 0.51.0
|
||||
return this.methodCallWrapper(type ? 'createPrivateGroup' : 'createChannel', name, users, readOnly, {}, { broadcast, encrypted });
|
||||
const params = {
|
||||
name,
|
||||
members: users,
|
||||
readOnly,
|
||||
extraData: {
|
||||
broadcast,
|
||||
encrypted,
|
||||
...(teamId && { teamId })
|
||||
}
|
||||
};
|
||||
return this.post(type ? 'groups.create' : 'channels.create', params);
|
||||
},
|
||||
async getWebsocketInfo({ server }) {
|
||||
const sdk = new RocketchatClient({ host: server, protocol: 'ddp', useSsl: useSsl(server) });
|
||||
|
@ -648,7 +657,8 @@ const RocketChat = {
|
|||
avatarETag: sub.avatarETag,
|
||||
t: sub.t,
|
||||
encrypted: sub.encrypted,
|
||||
lastMessage: sub.lastMessage
|
||||
lastMessage: sub.lastMessage,
|
||||
...(sub.teamId && { teamId: sub.teamId })
|
||||
}));
|
||||
|
||||
return data;
|
||||
|
@ -751,6 +761,18 @@ const RocketChat = {
|
|||
// RC 3.13.0
|
||||
return this.post('teams.create', params);
|
||||
},
|
||||
addRoomsToTeam({ teamId, rooms }) {
|
||||
// RC 3.13.0
|
||||
return this.post('teams.addRooms', { teamId, rooms });
|
||||
},
|
||||
removeTeamRoom({ roomId, teamId }) {
|
||||
// RC 3.13.0
|
||||
return this.post('teams.removeRoom', { roomId, teamId });
|
||||
},
|
||||
updateTeamRoom({ roomId, isDefault }) {
|
||||
// RC 3.13.0
|
||||
return this.post('teams.updateRoom', { roomId, isDefault });
|
||||
},
|
||||
joinRoom(roomId, joinCode, type) {
|
||||
// TODO: join code
|
||||
// RC 0.48.0
|
||||
|
|
|
@ -10,6 +10,8 @@ import LastMessage from './LastMessage';
|
|||
import Title from './Title';
|
||||
import UpdatedAt from './UpdatedAt';
|
||||
import Touchable from './Touchable';
|
||||
import Tag from './Tag';
|
||||
import I18n from '../../i18n';
|
||||
|
||||
const RoomItem = ({
|
||||
rid,
|
||||
|
@ -42,13 +44,16 @@ const RoomItem = ({
|
|||
testID,
|
||||
swipeEnabled,
|
||||
onPress,
|
||||
onLongPress,
|
||||
toggleFav,
|
||||
toggleRead,
|
||||
hideChannel,
|
||||
teamMain
|
||||
teamMain,
|
||||
autoJoin
|
||||
}) => (
|
||||
<Touchable
|
||||
onPress={onPress}
|
||||
onLongPress={onLongPress}
|
||||
width={width}
|
||||
favorite={favorite}
|
||||
toggleFav={toggleFav}
|
||||
|
@ -88,6 +93,9 @@ const RoomItem = ({
|
|||
hideUnreadStatus={hideUnreadStatus}
|
||||
alert={alert}
|
||||
/>
|
||||
{
|
||||
autoJoin ? <Tag name={I18n.t('Auto-join')} /> : null
|
||||
}
|
||||
<UpdatedAt
|
||||
date={date}
|
||||
theme={theme}
|
||||
|
@ -132,6 +140,9 @@ const RoomItem = ({
|
|||
hideUnreadStatus={hideUnreadStatus}
|
||||
alert={alert}
|
||||
/>
|
||||
{
|
||||
autoJoin ? <Tag name={I18n.t('Auto-join')} /> : null
|
||||
}
|
||||
<UnreadBadge
|
||||
unread={unread}
|
||||
userMentions={userMentions}
|
||||
|
@ -181,7 +192,9 @@ RoomItem.propTypes = {
|
|||
toggleFav: PropTypes.func,
|
||||
toggleRead: PropTypes.func,
|
||||
onPress: PropTypes.func,
|
||||
hideChannel: PropTypes.func
|
||||
onLongPress: PropTypes.func,
|
||||
hideChannel: PropTypes.func,
|
||||
autoJoin: PropTypes.bool
|
||||
};
|
||||
|
||||
RoomItem.defaultProps = {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { themes } from '../../constants/colors';
|
||||
import { useTheme } from '../../theme';
|
||||
import styles from './styles';
|
||||
|
||||
const Tag = React.memo(({ name }) => {
|
||||
const { theme } = useTheme();
|
||||
|
||||
return (
|
||||
<View style={[styles.tagContainer, { backgroundColor: themes[theme].borderColor }]}>
|
||||
<Text
|
||||
style={[
|
||||
styles.tagText, { color: themes[theme].infoText }
|
||||
]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{name}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
Tag.propTypes = {
|
||||
name: PropTypes.string
|
||||
};
|
||||
|
||||
export default Tag;
|
|
@ -1,7 +1,9 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Animated } from 'react-native';
|
||||
import { PanGestureHandler, State } from 'react-native-gesture-handler';
|
||||
import {
|
||||
LongPressGestureHandler, PanGestureHandler, State
|
||||
} from 'react-native-gesture-handler';
|
||||
|
||||
import Touch from '../../utils/touch';
|
||||
import {
|
||||
|
@ -17,6 +19,7 @@ class Touchable extends React.Component {
|
|||
static propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
onPress: PropTypes.func,
|
||||
onLongPress: PropTypes.func,
|
||||
testID: PropTypes.string,
|
||||
width: PropTypes.number,
|
||||
favorite: PropTypes.bool,
|
||||
|
@ -59,6 +62,12 @@ class Touchable extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
onLongPressHandlerStateChange = ({ nativeEvent }) => {
|
||||
if (nativeEvent.state === State.ACTIVE) {
|
||||
this.onLongPress();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_handleRelease = (nativeEvent) => {
|
||||
const { translationX } = nativeEvent;
|
||||
|
@ -203,54 +212,70 @@ class Touchable extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
onLongPress = () => {
|
||||
const { rowState } = this.state;
|
||||
const { onLongPress } = this.props;
|
||||
if (rowState !== 0) {
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (onLongPress) {
|
||||
onLongPress();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
testID, isRead, width, favorite, children, theme, isFocused, swipeEnabled
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
||||
<PanGestureHandler
|
||||
minDeltaX={20}
|
||||
onGestureEvent={this._onGestureEvent}
|
||||
onHandlerStateChange={this._onHandlerStateChange}
|
||||
enabled={swipeEnabled}
|
||||
>
|
||||
<LongPressGestureHandler onHandlerStateChange={this.onLongPressHandlerStateChange}>
|
||||
<Animated.View>
|
||||
<LeftActions
|
||||
transX={this.transXReverse}
|
||||
isRead={isRead}
|
||||
width={width}
|
||||
onToggleReadPress={this.onToggleReadPress}
|
||||
theme={theme}
|
||||
/>
|
||||
<RightActions
|
||||
transX={this.transXReverse}
|
||||
favorite={favorite}
|
||||
width={width}
|
||||
toggleFav={this.toggleFav}
|
||||
onHidePress={this.onHidePress}
|
||||
theme={theme}
|
||||
/>
|
||||
<Animated.View
|
||||
style={{
|
||||
transform: [{ translateX: this.transX }]
|
||||
}}
|
||||
<PanGestureHandler
|
||||
minDeltaX={20}
|
||||
onGestureEvent={this._onGestureEvent}
|
||||
onHandlerStateChange={this._onHandlerStateChange}
|
||||
enabled={swipeEnabled}
|
||||
>
|
||||
<Touch
|
||||
onPress={this.onPress}
|
||||
theme={theme}
|
||||
testID={testID}
|
||||
style={{
|
||||
backgroundColor: isFocused ? themes[theme].chatComponentBackground : themes[theme].backgroundColor
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Touch>
|
||||
</Animated.View>
|
||||
</Animated.View>
|
||||
<Animated.View>
|
||||
<LeftActions
|
||||
transX={this.transXReverse}
|
||||
isRead={isRead}
|
||||
width={width}
|
||||
onToggleReadPress={this.onToggleReadPress}
|
||||
theme={theme}
|
||||
/>
|
||||
<RightActions
|
||||
transX={this.transXReverse}
|
||||
favorite={favorite}
|
||||
width={width}
|
||||
toggleFav={this.toggleFav}
|
||||
onHidePress={this.onHidePress}
|
||||
theme={theme}
|
||||
/>
|
||||
<Animated.View
|
||||
style={{
|
||||
transform: [{ translateX: this.transX }]
|
||||
}}
|
||||
>
|
||||
<Touch
|
||||
onPress={this.onPress}
|
||||
theme={theme}
|
||||
testID={testID}
|
||||
style={{
|
||||
backgroundColor: isFocused ? themes[theme].chatComponentBackground : themes[theme].backgroundColor
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Touch>
|
||||
</Animated.View>
|
||||
</Animated.View>
|
||||
|
||||
</PanGestureHandler>
|
||||
</PanGestureHandler>
|
||||
</Animated.View>
|
||||
</LongPressGestureHandler>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ const attrs = [
|
|||
'theme',
|
||||
'isFocused',
|
||||
'forceUpdate',
|
||||
'showLastMessage'
|
||||
'showLastMessage',
|
||||
'autoJoin'
|
||||
];
|
||||
|
||||
class RoomItemContainer extends React.Component {
|
||||
|
@ -25,6 +26,7 @@ class RoomItemContainer extends React.Component {
|
|||
showLastMessage: PropTypes.bool,
|
||||
id: PropTypes.string,
|
||||
onPress: PropTypes.func,
|
||||
onLongPress: PropTypes.func,
|
||||
username: PropTypes.string,
|
||||
avatarSize: PropTypes.number,
|
||||
width: PropTypes.number,
|
||||
|
@ -41,7 +43,8 @@ class RoomItemContainer extends React.Component {
|
|||
getRoomAvatar: PropTypes.func,
|
||||
getIsGroupChat: PropTypes.func,
|
||||
getIsRead: PropTypes.func,
|
||||
swipeEnabled: PropTypes.bool
|
||||
swipeEnabled: PropTypes.bool,
|
||||
autoJoin: PropTypes.bool
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -112,6 +115,11 @@ class RoomItemContainer extends React.Component {
|
|||
return onPress(item);
|
||||
}
|
||||
|
||||
onLongPress = () => {
|
||||
const { item, onLongPress } = this.props;
|
||||
return onLongPress(item);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
item,
|
||||
|
@ -129,7 +137,8 @@ class RoomItemContainer extends React.Component {
|
|||
showLastMessage,
|
||||
username,
|
||||
useRealName,
|
||||
swipeEnabled
|
||||
swipeEnabled,
|
||||
autoJoin
|
||||
} = this.props;
|
||||
const name = getRoomTitle(item);
|
||||
const testID = `rooms-list-view-item-${ name }`;
|
||||
|
@ -160,6 +169,7 @@ class RoomItemContainer extends React.Component {
|
|||
isGroupChat={this.isGroupChat}
|
||||
isRead={isRead}
|
||||
onPress={this.onPress}
|
||||
onLongPress={this.onLongPress}
|
||||
date={date}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
width={width}
|
||||
|
@ -189,6 +199,7 @@ class RoomItemContainer extends React.Component {
|
|||
tunreadGroup={item.tunreadGroup}
|
||||
swipeEnabled={swipeEnabled}
|
||||
teamMain={item.teamMain}
|
||||
autoJoin={autoJoin}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -96,5 +96,16 @@ export default StyleSheet.create({
|
|||
height: '100%',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
tagContainer: {
|
||||
alignSelf: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: 4,
|
||||
marginHorizontal: 4
|
||||
},
|
||||
tagText: {
|
||||
fontSize: 13,
|
||||
paddingHorizontal: 4,
|
||||
...sharedStyles.textSemibold
|
||||
}
|
||||
});
|
||||
|
|
|
@ -40,18 +40,26 @@ const handleRequest = function* handleRequest({ data }) {
|
|||
broadcast,
|
||||
encrypted
|
||||
} = data;
|
||||
logEvent(events.CR_CREATE, {
|
||||
logEvent(events.CT_CREATE, {
|
||||
type,
|
||||
readOnly,
|
||||
broadcast,
|
||||
encrypted
|
||||
});
|
||||
sub = yield call(createTeam, data);
|
||||
const result = yield call(createTeam, data);
|
||||
sub = {
|
||||
rid: result?.team?.roomId,
|
||||
...result.team,
|
||||
t: result.team.type ? 'p' : 'c'
|
||||
};
|
||||
} else if (data.group) {
|
||||
logEvent(events.SELECTED_USERS_CREATE_GROUP);
|
||||
const result = yield call(createGroupChat);
|
||||
if (result.success) {
|
||||
({ room: sub } = result);
|
||||
sub = {
|
||||
rid: result.room?._id,
|
||||
...result.room
|
||||
};
|
||||
}
|
||||
} else {
|
||||
const {
|
||||
|
@ -66,33 +74,26 @@ const handleRequest = function* handleRequest({ data }) {
|
|||
broadcast,
|
||||
encrypted
|
||||
});
|
||||
sub = yield call(createChannel, data);
|
||||
const result = yield call(createChannel, data);
|
||||
sub = {
|
||||
rid: result?.channel?._id || result?.group?._id,
|
||||
...result?.channel,
|
||||
...result?.group
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const db = database.active;
|
||||
const subCollection = db.get('subscriptions');
|
||||
yield db.action(async() => {
|
||||
await subCollection.create((s) => {
|
||||
s._raw = sanitizedRaw({ id: sub.team ? sub.team.roomId : sub.rid }, subCollection.schema);
|
||||
s._raw = sanitizedRaw({ id: sub.rid }, subCollection.schema);
|
||||
Object.assign(s, sub);
|
||||
});
|
||||
});
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
let successParams = {};
|
||||
if (data.isTeam) {
|
||||
successParams = {
|
||||
...sub.team,
|
||||
rid: sub.team.roomId,
|
||||
t: sub.team.type ? 'p' : 'c'
|
||||
};
|
||||
} else {
|
||||
successParams = data;
|
||||
}
|
||||
yield put(createChannelSuccess(successParams));
|
||||
yield put(createChannelSuccess(sub));
|
||||
} catch (err) {
|
||||
logEvent(events[data.group ? 'SELECTED_USERS_CREATE_GROUP_F' : 'CR_CREATE_F']);
|
||||
yield put(createChannelFailure(err));
|
||||
|
|
|
@ -71,6 +71,8 @@ import ShareView from '../views/ShareView';
|
|||
import CreateDiscussionView from '../views/CreateDiscussionView';
|
||||
|
||||
import QueueListView from '../ee/omnichannel/views/QueueListView';
|
||||
import AddChannelTeamView from '../views/AddChannelTeamView';
|
||||
import AddExistingChannelView from '../views/AddExistingChannelView';
|
||||
|
||||
// ChatsStackNavigator
|
||||
const ChatsStack = createStackNavigator();
|
||||
|
@ -174,6 +176,16 @@ const ChatsStackNavigator = () => {
|
|||
component={TeamChannelsView}
|
||||
options={TeamChannelsView.navigationOptions}
|
||||
/>
|
||||
<ChatsStack.Screen
|
||||
name='AddChannelTeamView'
|
||||
component={AddChannelTeamView}
|
||||
options={AddChannelTeamView.navigationOptions}
|
||||
/>
|
||||
<ChatsStack.Screen
|
||||
name='AddExistingChannelView'
|
||||
component={AddExistingChannelView}
|
||||
options={AddExistingChannelView.navigationOptions}
|
||||
/>
|
||||
<ChatsStack.Screen
|
||||
name='MarkdownTableView'
|
||||
component={MarkdownTableView}
|
||||
|
|
|
@ -61,6 +61,8 @@ import { setKeyCommands, deleteKeyCommands } from '../../commands';
|
|||
import ShareView from '../../views/ShareView';
|
||||
|
||||
import QueueListView from '../../ee/omnichannel/views/QueueListView';
|
||||
import AddChannelTeamView from '../../views/AddChannelTeamView';
|
||||
import AddExistingChannelView from '../../views/AddExistingChannelView';
|
||||
|
||||
// ChatsStackNavigator
|
||||
const ChatsStack = createStackNavigator();
|
||||
|
@ -141,6 +143,16 @@ const ModalStackNavigator = React.memo(({ navigation }) => {
|
|||
component={InviteUsersView}
|
||||
options={InviteUsersView.navigationOptions}
|
||||
/>
|
||||
<ModalStack.Screen
|
||||
name='AddChannelTeamView'
|
||||
component={AddChannelTeamView}
|
||||
options={AddChannelTeamView.navigationOptions}
|
||||
/>
|
||||
<ModalStack.Screen
|
||||
name='AddExistingChannelView'
|
||||
component={AddExistingChannelView}
|
||||
options={AddExistingChannelView.navigationOptions}
|
||||
/>
|
||||
<ModalStack.Screen
|
||||
name='InviteUsersEditView'
|
||||
component={InviteUsersEditView}
|
||||
|
|
|
@ -99,14 +99,22 @@ export default {
|
|||
SELECTED_USERS_CREATE_GROUP: 'selected_users_create_group',
|
||||
SELECTED_USERS_CREATE_GROUP_F: 'selected_users_create_group_f',
|
||||
|
||||
// ADD EXISTING CHANNEL VIEW
|
||||
EXISTING_CHANNEL_ADD_CHANNEL: 'existing_channel_add_channel',
|
||||
EXISTING_CHANNEL_REMOVE_CHANNEL: 'existing_channel_remove_channel',
|
||||
|
||||
// CREATE CHANNEL VIEW
|
||||
CR_CREATE: 'cr_create',
|
||||
CT_CREATE: 'ct_create',
|
||||
CR_CREATE_F: 'cr_create_f',
|
||||
CT_CREATE_F: 'ct_create_f',
|
||||
CR_TOGGLE_TYPE: 'cr_toggle_type',
|
||||
CR_TOGGLE_READ_ONLY: 'cr_toggle_read_only',
|
||||
CR_TOGGLE_BROADCAST: 'cr_toggle_broadcast',
|
||||
CR_TOGGLE_ENCRYPTED: 'cr_toggle_encrypted',
|
||||
CR_REMOVE_USER: 'cr_remove_user',
|
||||
CT_ADD_ROOM_TO_TEAM: 'ct_add_room_to_team',
|
||||
CT_ADD_ROOM_TO_TEAM_F: 'ct_add_room_to_team_f',
|
||||
|
||||
// CREATE DISCUSSION VIEW
|
||||
CD_CREATE: 'cd_create',
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import * as List from '../containers/List';
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import { useTheme } from '../theme';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import I18n from '../i18n';
|
||||
|
||||
const setHeader = (navigation, isMasterDetail) => {
|
||||
const options = {
|
||||
headerTitle: I18n.t('Add_Channel_to_Team')
|
||||
};
|
||||
|
||||
if (isMasterDetail) {
|
||||
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
|
||||
}
|
||||
|
||||
navigation.setOptions(options);
|
||||
};
|
||||
|
||||
const AddChannelTeamView = ({
|
||||
navigation, route, isMasterDetail
|
||||
}) => {
|
||||
const { teamId, teamChannels } = route.params;
|
||||
const { theme } = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
setHeader(navigation, isMasterDetail);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SafeAreaView testID='add-channel-team-view'>
|
||||
<StatusBar />
|
||||
<List.Container>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
title='Create_New'
|
||||
onPress={() => navigation.navigate('NewMessageStackNavigator', { screen: 'SelectedUsersViewCreateChannel', params: { nextAction: () => navigation.navigate('CreateChannelView', { teamId }) } })}
|
||||
testID='add-channel-team-view-create-channel'
|
||||
left={() => <List.Icon name='team' />}
|
||||
right={() => <List.Icon name='chevron-right' />}
|
||||
theme={theme}
|
||||
/>
|
||||
<List.Separator />
|
||||
<List.Item
|
||||
title='Add_Existing'
|
||||
onPress={() => navigation.navigate('AddExistingChannelView', { teamId, teamChannels })}
|
||||
testID='add-channel-team-view-create-channel'
|
||||
left={() => <List.Icon name='channel-public' />}
|
||||
right={() => <List.Icon name='chevron-right' />}
|
||||
theme={theme}
|
||||
/>
|
||||
<List.Separator />
|
||||
</List.Container>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
AddChannelTeamView.propTypes = {
|
||||
route: PropTypes.object,
|
||||
navigation: PropTypes.object,
|
||||
isMasterDetail: PropTypes.bool
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
isMasterDetail: state.app.isMasterDetail
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(AddChannelTeamView);
|
|
@ -0,0 +1,209 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
View, FlatList
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
|
||||
import * as List from '../containers/List';
|
||||
import database from '../lib/database';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import I18n from '../i18n';
|
||||
import log, { events, logEvent } from '../utils/log';
|
||||
import SearchBox from '../containers/SearchBox';
|
||||
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 = 50;
|
||||
|
||||
class AddExistingChannelView extends React.Component {
|
||||
static propTypes = {
|
||||
navigation: PropTypes.object,
|
||||
route: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
addTeamChannelPermission: PropTypes.array
|
||||
};
|
||||
|
||||
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 } = this.props;
|
||||
const { selected } = this.state;
|
||||
|
||||
const options = {
|
||||
headerTitle: I18n.t('Add_Existing_Channel')
|
||||
};
|
||||
|
||||
if (isMasterDetail) {
|
||||
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
init = async() => {
|
||||
try {
|
||||
const { addTeamChannelPermission } = this.props;
|
||||
const db = database.active;
|
||||
const channels = await db.collections
|
||||
.get('subscriptions')
|
||||
.query(
|
||||
Q.where('team_id', ''),
|
||||
Q.where('t', Q.oneOf(['c', 'p'])),
|
||||
Q.experimentalTake(QUERY_SIZE),
|
||||
Q.experimentalSortBy('room_updated_at', Q.desc)
|
||||
)
|
||||
.fetch();
|
||||
const filteredChannels = channels.filter(async(channel) => {
|
||||
const permissions = await RocketChat.hasPermission([addTeamChannelPermission], channel.rid);
|
||||
if (!permissions[0]) {
|
||||
return;
|
||||
}
|
||||
return channel;
|
||||
});
|
||||
this.setState({ channels: filteredChannels });
|
||||
} 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 {
|
||||
logEvent(events.CT_ADD_ROOM_TO_TEAM);
|
||||
const result = await RocketChat.addRoomsToTeam({ rooms: selected, teamId: this.teamId });
|
||||
if (result.success) {
|
||||
this.setState({ loading: false });
|
||||
goRoom({ item: result, isMasterDetail });
|
||||
}
|
||||
} catch (e) {
|
||||
logEvent(events.CT_ADD_ROOM_TO_TEAM_F);
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
}
|
||||
|
||||
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.EXISTING_CHANNEL_ADD_CHANNEL);
|
||||
this.setState({ selected: [...selected, rid] }, () => this.setHeader());
|
||||
} else {
|
||||
logEvent(events.EXISTING_CHANNEL_REMOVE_CHANNEL);
|
||||
const filterSelected = selected.filter(el => el !== rid);
|
||||
this.setState({ selected: filterSelected }, () => this.setHeader());
|
||||
}
|
||||
}
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
const isChecked = this.isChecked(item.rid);
|
||||
// TODO: reuse logic inside RoomTypeIcon
|
||||
const icon = item.t === 'p' && !item.teamId ? 'channel-private' : 'channel-public';
|
||||
return (
|
||||
<List.Item
|
||||
title={RocketChat.getRoomTitle(item)}
|
||||
translateTitle={false}
|
||||
onPress={() => this.toggleChannel(item.rid)}
|
||||
testID='add-existing-channel-view-item'
|
||||
left={() => <List.Icon name={icon} />}
|
||||
right={() => (isChecked ? <List.Icon name='check' /> : null)}
|
||||
/>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
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='add-existing-channel-view'>
|
||||
<StatusBar />
|
||||
{this.renderList()}
|
||||
<Loading visible={loading} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
addTeamChannelPermission: state.permissions['add-team-channel']
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withTheme(AddExistingChannelView));
|
|
@ -83,13 +83,15 @@ class CreateChannelView extends React.Component {
|
|||
id: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
}),
|
||||
theme: PropTypes.string
|
||||
theme: PropTypes.string,
|
||||
teamId: PropTypes.string
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { route } = this.props;
|
||||
const isTeam = route?.params?.isTeam || false;
|
||||
this.teamId = route?.params?.teamId;
|
||||
this.state = {
|
||||
channelName: '',
|
||||
type: true,
|
||||
|
@ -180,7 +182,7 @@ class CreateChannelView extends React.Component {
|
|||
|
||||
// create channel or team
|
||||
create({
|
||||
name: channelName, users, type, readOnly, broadcast, encrypted, isTeam
|
||||
name: channelName, users, type, readOnly, broadcast, encrypted, isTeam, teamId: this.teamId
|
||||
});
|
||||
|
||||
Review.pushPositiveEvent();
|
||||
|
|
|
@ -60,7 +60,7 @@ class NewMessageView extends React.Component {
|
|||
id: PropTypes.string,
|
||||
token: PropTypes.string
|
||||
}),
|
||||
createChannel: PropTypes.func,
|
||||
create: PropTypes.func,
|
||||
maxUsers: PropTypes.number,
|
||||
theme: PropTypes.string,
|
||||
isMasterDetail: PropTypes.bool
|
||||
|
@ -124,9 +124,9 @@ class NewMessageView extends React.Component {
|
|||
|
||||
createGroupChat = () => {
|
||||
logEvent(events.NEW_MSG_CREATE_GROUP_CHAT);
|
||||
const { createChannel, maxUsers, navigation } = this.props;
|
||||
const { create, maxUsers, navigation } = this.props;
|
||||
navigation.navigate('SelectedUsersViewCreateChannel', {
|
||||
nextAction: () => createChannel({ group: true }),
|
||||
nextAction: () => create({ group: true }),
|
||||
buttonText: I18n.t('Create'),
|
||||
maxUsers
|
||||
});
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import React from 'react';
|
||||
import { Keyboard } from 'react-native';
|
||||
import { Keyboard, Alert } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { connect } from 'react-redux';
|
||||
import { FlatList } from 'react-native-gesture-handler';
|
||||
import { HeaderBackButton } from '@react-navigation/stack';
|
||||
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import RoomHeader from '../containers/RoomHeader';
|
||||
|
@ -23,11 +22,14 @@ import RoomItem, { ROW_HEIGHT } from '../presentation/RoomItem';
|
|||
import RocketChat from '../lib/rocketchat';
|
||||
import { withDimensions } from '../dimensions';
|
||||
import { isIOS } from '../utils/deviceInfo';
|
||||
import { themes } from '../constants/colors';
|
||||
import debounce from '../utils/debounce';
|
||||
import { showErrorAlert } from '../utils/info';
|
||||
import { goRoom } from '../utils/goRoom';
|
||||
import I18n from '../i18n';
|
||||
import { withActionSheet } from '../containers/ActionSheet';
|
||||
import { deleteRoom as deleteRoomAction } from '../actions/room';
|
||||
import { CustomIcon } from '../lib/Icons';
|
||||
import { themes } from '../constants/colors';
|
||||
|
||||
const API_FETCH_COUNT = 25;
|
||||
|
||||
|
@ -47,7 +49,11 @@ class TeamChannelsView extends React.Component {
|
|||
theme: PropTypes.string,
|
||||
useRealName: PropTypes.bool,
|
||||
width: PropTypes.number,
|
||||
StoreLastMessage: PropTypes.bool
|
||||
StoreLastMessage: PropTypes.bool,
|
||||
addTeamChannelPermission: PropTypes.array,
|
||||
removeTeamChannelPermission: PropTypes.array,
|
||||
showActionSheet: PropTypes.func,
|
||||
deleteRoom: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -60,9 +66,11 @@ class TeamChannelsView extends React.Component {
|
|||
isSearching: false,
|
||||
searchText: '',
|
||||
search: [],
|
||||
end: false
|
||||
end: false,
|
||||
showCreate: false
|
||||
};
|
||||
this.loadTeam();
|
||||
this.setHeader();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -70,6 +78,9 @@ class TeamChannelsView extends React.Component {
|
|||
}
|
||||
|
||||
loadTeam = async() => {
|
||||
const { addTeamChannelPermission } = this.props;
|
||||
const { loading, data } = this.state;
|
||||
|
||||
const db = database.active;
|
||||
try {
|
||||
const subCollection = db.get('subscriptions');
|
||||
|
@ -82,6 +93,15 @@ class TeamChannelsView extends React.Component {
|
|||
if (!this.team) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
const permissions = await RocketChat.hasPermission([addTeamChannelPermission], this.team.rid);
|
||||
if (permissions[0]) {
|
||||
this.setState({ showCreate: true }, () => this.setHeader());
|
||||
}
|
||||
|
||||
if (loading && data.length) {
|
||||
this.setState({ loading: false });
|
||||
}
|
||||
} catch {
|
||||
const { navigation } = this.props;
|
||||
navigation.pop();
|
||||
|
@ -115,14 +135,11 @@ class TeamChannelsView extends React.Component {
|
|||
loadingMore: false,
|
||||
end: result.rooms.length < API_FETCH_COUNT
|
||||
};
|
||||
const rooms = result.rooms.map((room) => {
|
||||
const record = this.teamChannels?.find(c => c.rid === room._id);
|
||||
return record ?? room;
|
||||
});
|
||||
|
||||
if (isSearching) {
|
||||
newState.search = [...search, ...rooms];
|
||||
newState.search = [...search, ...result.rooms];
|
||||
} else {
|
||||
newState.data = [...data, ...rooms];
|
||||
newState.data = [...data, ...result.rooms];
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
|
@ -135,18 +152,16 @@ class TeamChannelsView extends React.Component {
|
|||
}
|
||||
}, 300)
|
||||
|
||||
getHeader = () => {
|
||||
const { isSearching } = this.state;
|
||||
const {
|
||||
navigation, isMasterDetail, insets, theme
|
||||
} = this.props;
|
||||
setHeader = () => {
|
||||
const { isSearching, showCreate, data } = this.state;
|
||||
const { navigation, isMasterDetail, insets } = this.props;
|
||||
|
||||
const { team } = this;
|
||||
if (!team) {
|
||||
return;
|
||||
}
|
||||
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 1 });
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 2 });
|
||||
|
||||
if (isSearching) {
|
||||
return {
|
||||
|
@ -188,27 +203,16 @@ class TeamChannelsView extends React.Component {
|
|||
|
||||
if (isMasterDetail) {
|
||||
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
|
||||
} else {
|
||||
options.headerLeft = () => (
|
||||
<HeaderBackButton
|
||||
labelVisible={false}
|
||||
onPress={() => navigation.pop()}
|
||||
tintColor={themes[theme].headerTintColor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
options.headerRight = () => (
|
||||
<HeaderButton.Container>
|
||||
{ showCreate
|
||||
? <HeaderButton.Item iconName='create' onPress={() => navigation.navigate('AddChannelTeamView', { teamId: this.teamId, teamChannels: data })} />
|
||||
: null}
|
||||
<HeaderButton.Item iconName='search' onPress={this.onSearchPress} />
|
||||
</HeaderButton.Container>
|
||||
);
|
||||
return options;
|
||||
}
|
||||
|
||||
setHeader = () => {
|
||||
const { navigation } = this.props;
|
||||
const options = this.getHeader();
|
||||
navigation.setOptions(options);
|
||||
}
|
||||
|
||||
|
@ -287,6 +291,115 @@ class TeamChannelsView extends React.Component {
|
|||
}
|
||||
}, 1000, true);
|
||||
|
||||
options = (item) => {
|
||||
const { theme } = this.props;
|
||||
const isAutoJoinChecked = item.teamDefault;
|
||||
const autoJoinIcon = isAutoJoinChecked ? 'checkbox-checked' : 'checkbox-unchecked';
|
||||
const autoJoinIconColor = isAutoJoinChecked ? themes[theme].tintActive : themes[theme].auxiliaryTintColor;
|
||||
return ([
|
||||
{
|
||||
title: I18n.t('Auto-join'),
|
||||
icon: item.t === 'p' ? 'channel-private' : 'channel-public',
|
||||
onPress: () => this.toggleAutoJoin(item),
|
||||
right: () => <CustomIcon name={autoJoinIcon} size={20} color={autoJoinIconColor} />
|
||||
},
|
||||
{
|
||||
title: I18n.t('Remove_from_Team'),
|
||||
icon: 'close',
|
||||
danger: true,
|
||||
onPress: () => this.remove(item)
|
||||
},
|
||||
{
|
||||
title: I18n.t('Delete'),
|
||||
icon: 'delete',
|
||||
danger: true,
|
||||
onPress: () => this.delete(item)
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
toggleAutoJoin = async(item) => {
|
||||
try {
|
||||
const { data } = this.state;
|
||||
const result = await RocketChat.updateTeamRoom({ roomId: item._id, isDefault: !item.teamDefault });
|
||||
if (result.success) {
|
||||
const newData = data.map((i) => {
|
||||
if (i._id === item._id) {
|
||||
i.teamDefault = !i.teamDefault;
|
||||
}
|
||||
return i;
|
||||
});
|
||||
this.setState({ data: newData });
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
}
|
||||
|
||||
remove = (item) => {
|
||||
Alert.alert(
|
||||
I18n.t('Confirmation'),
|
||||
I18n.t('Delete_Team_Room_Warning'),
|
||||
[
|
||||
{
|
||||
text: I18n.t('Cancel'),
|
||||
style: 'cancel'
|
||||
},
|
||||
{
|
||||
text: I18n.t('Yes_action_it', { action: I18n.t('remove') }),
|
||||
style: 'destructive',
|
||||
onPress: () => this.removeRoom(item)
|
||||
}
|
||||
],
|
||||
{ cancelable: false }
|
||||
);
|
||||
}
|
||||
|
||||
removeRoom = async(item) => {
|
||||
try {
|
||||
const { data } = this.state;
|
||||
const result = await RocketChat.removeTeamRoom({ roomId: item._id, teamId: this.team.teamId });
|
||||
if (result.success) {
|
||||
const newData = data.filter(room => result.room._id !== room._id);
|
||||
this.setState({ data: newData });
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
}
|
||||
}
|
||||
|
||||
delete = (item) => {
|
||||
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(item._id, item.t)
|
||||
}
|
||||
],
|
||||
{ cancelable: false }
|
||||
);
|
||||
}
|
||||
|
||||
showChannelActions = async(item) => {
|
||||
logEvent(events.ROOM_SHOW_BOX_ACTIONS);
|
||||
const { showActionSheet, removeTeamChannelPermission } = this.props;
|
||||
|
||||
const permissions = await RocketChat.hasPermission([removeTeamChannelPermission], this.team.rid);
|
||||
if (!permissions[0]) {
|
||||
return;
|
||||
}
|
||||
showActionSheet({ options: this.options(item) });
|
||||
}
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
const {
|
||||
StoreLastMessage,
|
||||
|
@ -302,10 +415,12 @@ class TeamChannelsView extends React.Component {
|
|||
showLastMessage={StoreLastMessage}
|
||||
onPress={this.onPressItem}
|
||||
width={width}
|
||||
onLongPress={this.showChannelActions}
|
||||
useRealName={useRealName}
|
||||
getRoomTitle={this.getRoomTitle}
|
||||
getRoomAvatar={this.getRoomAvatar}
|
||||
swipeEnabled={false}
|
||||
autoJoin={item.teamDefault}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -365,7 +480,13 @@ const mapStateToProps = state => ({
|
|||
user: getUserSelector(state),
|
||||
useRealName: state.settings.UI_Use_Real_Name,
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
StoreLastMessage: state.settings.Store_Last_Message
|
||||
StoreLastMessage: state.settings.Store_Last_Message,
|
||||
addTeamChannelPermission: state.permissions['add-team-channel'],
|
||||
removeTeamChannelPermission: state.permissions['remove-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)))));
|
||||
|
|
|
@ -3,7 +3,6 @@ import React from 'react';
|
|||
import { ScrollView, Dimensions } from 'react-native';
|
||||
import { storiesOf } from '@storybook/react-native';
|
||||
import { Provider } from 'react-redux';
|
||||
// import moment from 'moment';
|
||||
|
||||
import { themes } from '../../app/constants/colors';
|
||||
import RoomItemComponent from '../../app/presentation/RoomItem/RoomItem';
|
||||
|
@ -94,6 +93,15 @@ stories.add('Alerts', () => (
|
|||
</>
|
||||
));
|
||||
|
||||
stories.add('Tag', () => (
|
||||
<>
|
||||
<RoomItem autoJoin />
|
||||
<RoomItem showLastMessage autoJoin />
|
||||
<RoomItem name={longText} autoJoin />
|
||||
<RoomItem name={longText} autoJoin showLastMessage />
|
||||
</>
|
||||
));
|
||||
|
||||
stories.add('Last Message', () => (
|
||||
<>
|
||||
<RoomItem
|
||||
|
|
Loading…
Reference in New Issue