[FIX] Storybook not able to import Avatar (#2607)

* [FIX] Storybook not able to import Avatar

* Fix lint

* Mock Date.now

* Fix RU translation

* isLegacy -> serverVersion

* Remove change avatar from room info edit for servers below 3.6

* Mock for storyshots only

* lint

Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
Djorkaeff Alexandre 2020-11-04 13:53:44 -03:00 committed by GitHub
parent 25c4637d39
commit 080b8cc3fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 103 additions and 157 deletions

View File

@ -1,3 +1,6 @@
import initStoryshots from '@storybook/addon-storyshots'; import initStoryshots from '@storybook/addon-storyshots';
jest.mock('../app/lib/database', () => jest.fn(() => null));
global.Date.now = jest.fn(() => new Date('2019-10-10').getTime());
initStoryshots(); initStoryshots();

View File

@ -25,7 +25,8 @@ const Avatar = React.memo(({
avatarETag, avatarETag,
isStatic, isStatic,
rid, rid,
blockUnauthenticatedAccess blockUnauthenticatedAccess,
serverVersion
}) => { }) => {
if ((!text && !avatar && !emoji && !rid) || !server) { if ((!text && !avatar && !emoji && !rid) || !server) {
return null; return null;
@ -60,6 +61,7 @@ const Avatar = React.memo(({
avatar, avatar,
server, server,
avatarETag, avatarETag,
serverVersion,
rid, rid,
blockUnauthenticatedAccess blockUnauthenticatedAccess
}); });
@ -114,7 +116,8 @@ Avatar.propTypes = {
avatarETag: PropTypes.string, avatarETag: PropTypes.string,
isStatic: PropTypes.bool, isStatic: PropTypes.bool,
rid: PropTypes.string, rid: PropTypes.string,
blockUnauthenticatedAccess: PropTypes.bool blockUnauthenticatedAccess: PropTypes.bool,
serverVersion: PropTypes.string
}; };
Avatar.defaultProps = { Avatar.defaultProps = {

View File

@ -13,7 +13,8 @@ class AvatarContainer extends React.Component {
rid: PropTypes.string, rid: PropTypes.string,
text: PropTypes.string, text: PropTypes.string,
type: PropTypes.string, type: PropTypes.string,
blockUnauthenticatedAccess: PropTypes.bool blockUnauthenticatedAccess: PropTypes.bool,
serverVersion: PropTypes.string
}; };
static defaultProps = { static defaultProps = {
@ -83,9 +84,11 @@ class AvatarContainer extends React.Component {
render() { render() {
const { avatarETag } = this.state; const { avatarETag } = this.state;
const { serverVersion } = this.props;
return ( return (
<Avatar <Avatar
avatarETag={avatarETag} avatarETag={avatarETag}
serverVersion={serverVersion}
{...this.props} {...this.props}
/> />
); );
@ -94,7 +97,8 @@ class AvatarContainer extends React.Component {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
user: getUserSelector(state), user: getUserSelector(state),
server: state.share.server || state.server.server, server: state.share.server.server || state.server.server,
serverVersion: state.share.server.version || state.server.version,
blockUnauthenticatedAccess: blockUnauthenticatedAccess:
state.share.settings?.Accounts_AvatarBlockUnauthenticatedAccess state.share.settings?.Accounts_AvatarBlockUnauthenticatedAccess
?? state.settings.Accounts_AvatarBlockUnauthenticatedAccess ?? state.settings.Accounts_AvatarBlockUnauthenticatedAccess

View File

@ -17,7 +17,7 @@ export default class EmojiKeyboard extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
const state = store.getState(); const state = store.getState();
this.baseUrl = state.share.server || state.server.server; this.baseUrl = state.share.server.server || state.server.server;
} }
onEmojiSelected = (emoji) => { onEmojiSelected = (emoji) => {

View File

@ -1,14 +1,14 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Avatar from '../Avatar/Avatar'; import Avatar from '../Avatar';
import styles from './styles'; import styles from './styles';
import MessageContext from './Context'; import MessageContext from './Context';
const MessageAvatar = React.memo(({ const MessageAvatar = React.memo(({
isHeader, avatar, author, small, navToRoomInfo, emoji, getCustomEmoji, theme isHeader, avatar, author, small, navToRoomInfo, emoji, getCustomEmoji, theme
}) => { }) => {
const { baseUrl, user } = useContext(MessageContext); const { user } = useContext(MessageContext);
if (isHeader && author) { if (isHeader && author) {
const navParam = { const navParam = {
t: 'd', t: 'd',
@ -22,9 +22,6 @@ const MessageAvatar = React.memo(({
borderRadius={small ? 2 : 4} borderRadius={small ? 2 : 4}
onPress={author._id === user.id ? undefined : () => navToRoomInfo(navParam)} onPress={author._id === user.id ? undefined : () => navToRoomInfo(navParam)}
getCustomEmoji={getCustomEmoji} getCustomEmoji={getCustomEmoji}
user={user}
server={baseUrl}
avatarETag={author.avatarETag}
avatar={avatar} avatar={avatar}
emoji={emoji} emoji={emoji}
theme={theme} theme={theme}

View File

@ -9,7 +9,6 @@ import { SYSTEM_MESSAGES, getMessageTranslation } from './utils';
import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/encryption/constants'; import { E2E_MESSAGE_TYPE, E2E_STATUS } from '../../lib/encryption/constants';
import messagesStatus from '../../constants/messagesStatus'; import messagesStatus from '../../constants/messagesStatus';
import { withTheme } from '../../theme'; import { withTheme } from '../../theme';
import database from '../../lib/database';
class MessageContainer extends React.Component { class MessageContainer extends React.Component {
static propTypes = { static propTypes = {
@ -74,11 +73,7 @@ class MessageContainer extends React.Component {
theme: 'light' theme: 'light'
} }
state = { componentDidMount() {
author: null
}
async componentDidMount() {
const { item } = this.props; const { item } = this.props;
if (item && item.observe) { if (item && item.observe) {
const observable = item.observe(); const observable = item.observe();
@ -86,19 +81,6 @@ class MessageContainer extends React.Component {
this.forceUpdate(); this.forceUpdate();
}); });
} }
const db = database.active;
const usersCollection = db.collections.get('users');
try {
const user = await usersCollection.find(item.u?._id);
const observable = user.observe();
this.userSubscription = observable.subscribe((author) => {
this.setState({ author });
this.forceUpdate();
});
} catch {
// Do nothing
}
} }
shouldComponentUpdate(nextProps) { shouldComponentUpdate(nextProps) {
@ -113,9 +95,6 @@ class MessageContainer extends React.Component {
if (this.subscription && this.subscription.unsubscribe) { if (this.subscription && this.subscription.unsubscribe) {
this.subscription.unsubscribe(); this.subscription.unsubscribe();
} }
if (this.userSubscription && this.userSubscription.unsubscribe) {
this.userSubscription.unsubscribe();
}
} }
onPress = debounce(() => { onPress = debounce(() => {
@ -264,7 +243,6 @@ class MessageContainer extends React.Component {
} }
render() { render() {
const { author } = this.state;
const { const {
item, user, style, archived, baseUrl, useRealName, broadcast, fetchThreadName, showAttachment, timeFormat, isReadReceiptEnabled, autoTranslateRoom, autoTranslateLanguage, navToRoomInfo, getCustomEmoji, isThreadRoom, callJitsi, blockAction, rid, theme, getBadgeColor, toggleFollowThread item, user, style, archived, baseUrl, useRealName, broadcast, fetchThreadName, showAttachment, timeFormat, isReadReceiptEnabled, autoTranslateRoom, autoTranslateLanguage, navToRoomInfo, getCustomEmoji, isThreadRoom, callJitsi, blockAction, rid, theme, getBadgeColor, toggleFollowThread
} = this.props; } = this.props;
@ -302,7 +280,7 @@ class MessageContainer extends React.Component {
id={id} id={id}
msg={message} msg={message}
rid={rid} rid={rid}
author={author || u} author={u}
ts={ts} ts={ts}
type={t} type={t}
attachments={attachments} attachments={attachments}

View File

@ -662,7 +662,7 @@ export default {
Logout_failed: 'Выход не успешен!', Logout_failed: 'Выход не успешен!',
Log_analytics_events: 'Журнал событий аналитики', Log_analytics_events: 'Журнал событий аналитики',
E2E_encryption_change_password_title: 'Изменить пароль шифрования', E2E_encryption_change_password_title: 'Изменить пароль шифрования',
E2E_encryption_change_password_description: 'Теперь вы можете создавать зашифрованные прватные чаты и личные беседы. Вы так же можете сделать существующие приватные чаты и личные беседы шифрованными. \nЭто сквозное шифрование, поэтому ключь для шифрования\дешифрования ваших сообщений не будет сохранен на сервере. Именно поэтому вам необходимо сохранить ваш пароль в надежном и безопасном месте. Вам необходимо вводить этот пароль на всех устройствах, где вы хотите использовать E2E шифрование.', E2E_encryption_change_password_description: 'Теперь вы можете создавать зашифрованные прватные чаты и личные беседы. Вы так же можете сделать существующие приватные чаты и личные беседы шифрованными. \nЭто сквозное шифрование, поэтому ключь для шифрования\nдешифрования ваших сообщений не будет сохранен на сервере. Именно поэтому вам необходимо сохранить ваш пароль в надежном и безопасном месте. Вам необходимо вводить этот пароль на всех устройствах, где вы хотите использовать E2E шифрование.',
E2E_encryption_change_password_error: 'Ошибка при смене пароля E2E ключа!', E2E_encryption_change_password_error: 'Ошибка при смене пароля E2E ключа!',
E2E_encryption_change_password_success: 'Пароль ключа E2E изменен успешно!', E2E_encryption_change_password_success: 'Пароль ключа E2E изменен успешно!',
E2E_encryption_change_password_message: 'Убедитесь, что вы сохранили пароль в надежном мпсте.', E2E_encryption_change_password_message: 'Убедитесь, что вы сохранили пароль в надежном мпсте.',

View File

@ -320,8 +320,16 @@ const RocketChat = {
this.shareSDK = new RocketchatClient({ host: server, protocol: 'ddp', useSsl: useSsl(server) }); this.shareSDK = new RocketchatClient({ host: server, protocol: 'ddp', useSsl: useSsl(server) });
// set Server // set Server
const currentServer = { server };
const serversDB = database.servers; const serversDB = database.servers;
reduxStore.dispatch(shareSelectServer(server)); const serversCollection = serversDB.collections.get('servers');
try {
const serverRecord = await serversCollection.find(server);
currentServer.version = serverRecord.version;
} catch {
// Record not found
}
reduxStore.dispatch(shareSelectServer(currentServer));
RocketChat.setCustomEmojis(); RocketChat.setCustomEmojis();
@ -368,6 +376,7 @@ const RocketChat = {
} }
database.share = null; database.share = null;
reduxStore.dispatch(shareSelectServer({}));
reduxStore.dispatch(shareSetUser({})); reduxStore.dispatch(shareSetUser({}));
reduxStore.dispatch(shareSetSettings({})); reduxStore.dispatch(shareSetSettings({}));
}, },

View File

@ -19,10 +19,7 @@ const RoomItem = ({
avatar, avatar,
width, width,
avatarSize, avatarSize,
baseUrl,
userId,
username, username,
token,
showLastMessage, showLastMessage,
status, status,
useRealName, useRealName,
@ -48,8 +45,7 @@ const RoomItem = ({
onPress, onPress,
toggleFav, toggleFav,
toggleRead, toggleRead,
hideChannel, hideChannel
avatarETag
}) => ( }) => (
<Touchable <Touchable
onPress={onPress} onPress={onPress}
@ -70,11 +66,7 @@ const RoomItem = ({
accessibilityLabel={accessibilityLabel} accessibilityLabel={accessibilityLabel}
avatar={avatar} avatar={avatar}
avatarSize={avatarSize} avatarSize={avatarSize}
avatarETag={avatarETag}
type={type} type={type}
baseUrl={baseUrl}
userId={userId}
token={token}
theme={theme} theme={theme}
rid={rid} rid={rid}
> >
@ -160,11 +152,8 @@ RoomItem.propTypes = {
prid: PropTypes.string, prid: PropTypes.string,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
avatar: PropTypes.string.isRequired, avatar: PropTypes.string.isRequired,
baseUrl: PropTypes.string.isRequired,
showLastMessage: PropTypes.bool, showLastMessage: PropTypes.bool,
userId: PropTypes.string,
username: PropTypes.string, username: PropTypes.string,
token: PropTypes.string,
avatarSize: PropTypes.number, avatarSize: PropTypes.number,
testID: PropTypes.string, testID: PropTypes.string,
width: PropTypes.number, width: PropTypes.number,
@ -191,8 +180,7 @@ RoomItem.propTypes = {
toggleFav: PropTypes.func, toggleFav: PropTypes.func,
toggleRead: PropTypes.func, toggleRead: PropTypes.func,
onPress: PropTypes.func, onPress: PropTypes.func,
hideChannel: PropTypes.func, hideChannel: PropTypes.func
avatarETag: PropTypes.string
}; };
RoomItem.defaultProps = { RoomItem.defaultProps = {

View File

@ -4,17 +4,13 @@ import PropTypes from 'prop-types';
import styles from './styles'; import styles from './styles';
import { themes } from '../../constants/colors'; import { themes } from '../../constants/colors';
import Avatar from '../../containers/Avatar/Avatar'; import Avatar from '../../containers/Avatar';
const Wrapper = ({ const Wrapper = ({
accessibilityLabel, accessibilityLabel,
avatar, avatar,
avatarSize, avatarSize,
avatarETag,
type, type,
baseUrl,
userId,
token,
theme, theme,
rid, rid,
children children
@ -28,9 +24,6 @@ const Wrapper = ({
size={avatarSize} size={avatarSize}
type={type} type={type}
style={styles.avatar} style={styles.avatar}
server={baseUrl}
user={{ id: userId, token }}
avatarETag={avatarETag}
rid={rid} rid={rid}
/> />
<View <View
@ -50,11 +43,7 @@ Wrapper.propTypes = {
accessibilityLabel: PropTypes.string, accessibilityLabel: PropTypes.string,
avatar: PropTypes.string, avatar: PropTypes.string,
avatarSize: PropTypes.number, avatarSize: PropTypes.number,
avatarETag: PropTypes.string,
type: PropTypes.string, type: PropTypes.string,
baseUrl: PropTypes.string,
userId: PropTypes.string,
token: PropTypes.string,
theme: PropTypes.string, theme: PropTypes.string,
rid: PropTypes.string, rid: PropTypes.string,
children: PropTypes.element children: PropTypes.element

View File

@ -5,7 +5,6 @@ import { connect } from 'react-redux';
import I18n from '../../i18n'; import I18n from '../../i18n';
import { ROW_HEIGHT } from './styles'; import { ROW_HEIGHT } from './styles';
import { formatDate } from '../../utils/room'; import { formatDate } from '../../utils/room';
import database from '../../lib/database';
import RoomItem from './RoomItem'; import RoomItem from './RoomItem';
export { ROW_HEIGHT }; export { ROW_HEIGHT };
@ -23,13 +22,10 @@ const attrs = [
class RoomItemContainer extends React.Component { class RoomItemContainer extends React.Component {
static propTypes = { static propTypes = {
item: PropTypes.object.isRequired, item: PropTypes.object.isRequired,
baseUrl: PropTypes.string.isRequired,
showLastMessage: PropTypes.bool, showLastMessage: PropTypes.bool,
id: PropTypes.string, id: PropTypes.string,
onPress: PropTypes.func, onPress: PropTypes.func,
userId: PropTypes.string,
username: PropTypes.string, username: PropTypes.string,
token: PropTypes.string,
avatarSize: PropTypes.number, avatarSize: PropTypes.number,
testID: PropTypes.string, testID: PropTypes.string,
width: PropTypes.number, width: PropTypes.number,
@ -63,7 +59,6 @@ class RoomItemContainer extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.mounted = false; this.mounted = false;
this.state = { avatarETag: '' };
this.init(); this.init();
} }
@ -71,11 +66,7 @@ class RoomItemContainer extends React.Component {
this.mounted = true; this.mounted = true;
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps) {
const { avatarETag } = this.state;
if (nextState.avatarETag !== avatarETag) {
return true;
}
const { props } = this; const { props } = this;
return !attrs.every(key => props[key] === nextProps[key]); return !attrs.every(key => props[key] === nextProps[key]);
} }
@ -88,9 +79,6 @@ class RoomItemContainer extends React.Component {
} }
componentWillUnmount() { componentWillUnmount() {
if (this.avatarSubscription?.unsubscribe) {
this.avatarSubscription.unsubscribe();
}
if (this.roomSubscription?.unsubscribe) { if (this.roomSubscription?.unsubscribe) {
this.roomSubscription.unsubscribe(); this.roomSubscription.unsubscribe();
} }
@ -106,7 +94,7 @@ class RoomItemContainer extends React.Component {
return t === 'd' && id && !this.isGroupChat; return t === 'd' && id && !this.isGroupChat;
} }
init = async() => { init = () => {
const { item } = this.props; const { item } = this.props;
if (item?.observe) { if (item?.observe) {
const observable = item.observe(); const observable = item.observe();
@ -114,35 +102,6 @@ class RoomItemContainer extends React.Component {
this.forceUpdate(); this.forceUpdate();
}); });
} }
const db = database.active;
const usersCollection = db.collections.get('users');
const subsCollection = db.collections.get('subscriptions');
try {
const { id } = this.props;
const { rid } = item;
let record;
if (this.isDirect) {
record = await usersCollection.find(id);
} else {
record = await subsCollection.find(rid);
}
if (record) {
const observable = record.observe();
this.avatarSubscription = observable.subscribe((u) => {
const { avatarETag } = u;
if (this.mounted) {
this.setState({ avatarETag });
} else {
this.state.avatarETag = avatarETag;
}
});
}
} catch {
// Record not found
}
} }
onPress = () => { onPress = () => {
@ -151,7 +110,6 @@ class RoomItemContainer extends React.Component {
} }
render() { render() {
const { avatarETag } = this.state;
const { const {
item, item,
getRoomTitle, getRoomTitle,
@ -165,9 +123,6 @@ class RoomItemContainer extends React.Component {
theme, theme,
isFocused, isFocused,
avatarSize, avatarSize,
baseUrl,
userId,
token,
status, status,
showLastMessage, showLastMessage,
username, username,
@ -215,9 +170,6 @@ class RoomItemContainer extends React.Component {
theme={theme} theme={theme}
isFocused={isFocused} isFocused={isFocused}
size={avatarSize} size={avatarSize}
baseUrl={baseUrl}
userId={userId}
token={token}
prid={item.prid} prid={item.prid}
status={status} status={status}
hideUnreadStatus={item.hideUnreadStatus} hideUnreadStatus={item.hideUnreadStatus}
@ -233,7 +185,6 @@ class RoomItemContainer extends React.Component {
tunread={item.tunread} tunread={item.tunread}
tunreadUser={item.tunreadUser} tunreadUser={item.tunreadUser}
tunreadGroup={item.tunreadGroup} tunreadGroup={item.tunreadGroup}
avatarETag={avatarETag || item.avatarETag}
swipeEnabled={swipeEnabled} swipeEnabled={swipeEnabled}
/> />
); );

View File

@ -2,7 +2,7 @@ import { SHARE } from '../actions/actionsTypes';
const initialState = { const initialState = {
user: {}, user: {},
server: '', server: {},
settings: {} settings: {}
}; };

View File

@ -19,7 +19,7 @@ import { showErrorAlert } from '../utils/info';
import I18n from '../i18n'; import I18n from '../i18n';
import log from '../utils/log'; import log from '../utils/log';
const getServer = state => state.share.server || state.server.server; const getServer = state => state.share.server.server || state.server.server;
const getE2eEnable = state => state.settings.E2E_Enable; const getE2eEnable = state => state.settings.E2E_Enable;
const handleEncryptionInit = function* handleEncryptionInit() { const handleEncryptionInit = function* handleEncryptionInit() {

View File

@ -1,19 +1,14 @@
import semver from 'semver'; import semver from 'semver';
import reduxStore from '../lib/createStore';
const formatUrl = (url, size, query) => `${ url }?format=png&size=${ size }${ query }`; const formatUrl = (url, size, query) => `${ url }?format=png&size=${ size }${ query }`;
export const avatarURL = ({ export const avatarURL = ({
type, text, size, user = {}, avatar, server, avatarETag, rid, blockUnauthenticatedAccess type, text, size, user = {}, avatar, server, avatarETag, rid, blockUnauthenticatedAccess, serverVersion
}) => { }) => {
const { version: serverVersion } = reduxStore.getState().server;
const isLegacy = serverVersion && semver.lt(semver.coerce(serverVersion), '3.6.0');
let room; let room;
if (type === 'd') { if (type === 'd') {
room = text; room = text;
} else if (rid && !isLegacy) { } else if (rid && !(serverVersion && semver.lt(semver.coerce(serverVersion), '3.6.0'))) {
room = `room/${ rid }`; room = `room/${ rid }`;
} else { } else {
room = `@${ text }`; room = `@${ text }`;

View File

@ -12,7 +12,7 @@ import { themes } from '../../constants/colors';
import styles from './styles'; import styles from './styles';
const SelectChannel = ({ const SelectChannel = ({
server, token, userId, onChannelSelect, initial, blockUnauthenticatedAccess, theme server, token, userId, onChannelSelect, initial, blockUnauthenticatedAccess, serverVersion, theme
}) => { }) => {
const [channels, setChannels] = useState([]); const [channels, setChannels] = useState([]);
@ -32,7 +32,8 @@ const SelectChannel = ({
server, server,
avatarETag: item.avatarETag, avatarETag: item.avatarETag,
rid: item.rid, rid: item.rid,
blockUnauthenticatedAccess blockUnauthenticatedAccess,
serverVersion
}); });
return ( return (
@ -63,6 +64,7 @@ SelectChannel.propTypes = {
initial: PropTypes.object, initial: PropTypes.object,
onChannelSelect: PropTypes.func, onChannelSelect: PropTypes.func,
blockUnauthenticatedAccess: PropTypes.bool, blockUnauthenticatedAccess: PropTypes.bool,
serverVersion: PropTypes.string,
theme: PropTypes.string theme: PropTypes.string
}; };

View File

@ -15,7 +15,7 @@ import styles from './styles';
import { themes } from '../../constants/colors'; import { themes } from '../../constants/colors';
const SelectUsers = ({ const SelectUsers = ({
server, token, userId, selected, onUserSelect, blockUnauthenticatedAccess, theme server, token, userId, selected, onUserSelect, blockUnauthenticatedAccess, serverVersion, theme
}) => { }) => {
const [users, setUsers] = useState([]); const [users, setUsers] = useState([]);
@ -53,7 +53,8 @@ const SelectUsers = ({
user: { id: userId, token }, user: { id: userId, token },
server, server,
avatarETag: item.avatarETag, avatarETag: item.avatarETag,
blockUnauthenticatedAccess blockUnauthenticatedAccess,
serverVersion
}); });
return ( return (
@ -84,6 +85,7 @@ SelectUsers.propTypes = {
selected: PropTypes.array, selected: PropTypes.array,
onUserSelect: PropTypes.func, onUserSelect: PropTypes.func,
blockUnauthenticatedAccess: PropTypes.bool, blockUnauthenticatedAccess: PropTypes.bool,
serverVersion: PropTypes.string,
theme: PropTypes.string theme: PropTypes.string
}; };

View File

@ -40,7 +40,8 @@ class CreateChannelView extends React.Component {
error: PropTypes.object, error: PropTypes.object,
theme: PropTypes.string, theme: PropTypes.string,
isMasterDetail: PropTypes.bool, isMasterDetail: PropTypes.bool,
blockUnauthenticatedAccess: PropTypes.bool blockUnauthenticatedAccess: PropTypes.bool,
serverVersion: PropTypes.string
} }
constructor(props) { constructor(props) {
@ -144,7 +145,7 @@ class CreateChannelView extends React.Component {
render() { render() {
const { name, users } = this.state; const { name, users } = this.state;
const { const {
server, user, loading, blockUnauthenticatedAccess, theme server, user, loading, blockUnauthenticatedAccess, theme, serverVersion
} = this.props; } = this.props;
return ( return (
<KeyboardView <KeyboardView
@ -163,6 +164,7 @@ class CreateChannelView extends React.Component {
initial={this.channel && { text: RocketChat.getRoomTitle(this.channel) }} initial={this.channel && { text: RocketChat.getRoomTitle(this.channel) }}
onChannelSelect={this.selectChannel} onChannelSelect={this.selectChannel}
blockUnauthenticatedAccess={blockUnauthenticatedAccess} blockUnauthenticatedAccess={blockUnauthenticatedAccess}
serverVersion={serverVersion}
theme={theme} theme={theme}
/> />
<TextInput <TextInput
@ -180,6 +182,7 @@ class CreateChannelView extends React.Component {
selected={users} selected={users}
onUserSelect={this.selectUsers} onUserSelect={this.selectUsers}
blockUnauthenticatedAccess={blockUnauthenticatedAccess} blockUnauthenticatedAccess={blockUnauthenticatedAccess}
serverVersion={serverVersion}
theme={theme} theme={theme}
/> />
<TextInput <TextInput
@ -207,6 +210,7 @@ const mapStateToProps = state => ({
loading: state.createDiscussion.isFetching, loading: state.createDiscussion.isFetching,
result: state.createDiscussion.result, result: state.createDiscussion.result,
blockUnauthenticatedAccess: state.settings.Accounts_AvatarBlockUnauthenticatedAccess ?? true, blockUnauthenticatedAccess: state.settings.Accounts_AvatarBlockUnauthenticatedAccess ?? true,
serverVersion: state.share.server.version || state.server.version,
isMasterDetail: state.app.isMasterDetail isMasterDetail: state.app.isMasterDetail
}); });

View File

@ -405,6 +405,11 @@ class RoomInfoEditView extends React.Component {
this.setState({ encrypted: value }); this.setState({ encrypted: value });
} }
isServerVersionLowerThan = (version) => {
const { serverVersion } = this.props;
return serverVersion && semver.lt(semver.coerce(serverVersion), version);
}
render() { render() {
const { const {
name, nameError, description, topic, announcement, t, ro, reactWhenReadOnly, room, joinCode, saving, permissions, archived, enableSysMes, encrypted, avatar name, nameError, description, topic, announcement, t, ro, reactWhenReadOnly, room, joinCode, saving, permissions, archived, enableSysMes, encrypted, avatar
@ -428,7 +433,11 @@ class RoomInfoEditView extends React.Component {
testID='room-info-edit-view-list' testID='room-info-edit-view-list'
{...scrollPersistTaps} {...scrollPersistTaps}
> >
<TouchableOpacity style={styles.avatarContainer} onPress={this.changeAvatar}> <TouchableOpacity
style={styles.avatarContainer}
onPress={this.changeAvatar}
disabled={this.isServerVersionLowerThan('3.6.0')}
>
<Avatar <Avatar
type={room.t} type={room.t}
text={room.name} text={room.name}
@ -437,9 +446,14 @@ class RoomInfoEditView extends React.Component {
rid={isEmpty(avatar) && room.rid} rid={isEmpty(avatar) && room.rid}
size={100} size={100}
> >
<TouchableOpacity style={[styles.resetButton, { backgroundColor: themes[theme].dangerColor }]} onPress={this.resetAvatar}> {this.isServerVersionLowerThan('3.6.0')
<CustomIcon name='delete' color={themes[theme].backgroundColor} size={24} /> ? null
</TouchableOpacity> : (
<TouchableOpacity style={[styles.resetButton, { backgroundColor: themes[theme].dangerColor }]} onPress={this.resetAvatar}>
<CustomIcon name='delete' color={themes[theme].backgroundColor} size={24} />
</TouchableOpacity>
)
}
</Avatar> </Avatar>
</TouchableOpacity> </TouchableOpacity>
<RCTextInput <RCTextInput
@ -650,7 +664,7 @@ class RoomInfoEditView extends React.Component {
} }
const mapStateToProps = state => ({ const mapStateToProps = state => ({
serverVersion: state.server.version, serverVersion: state.share.server.version || state.server.version,
e2eEnabled: state.settings.E2E_Enable || false e2eEnabled: state.settings.E2E_Enable || false
}); });

View File

@ -896,12 +896,7 @@ class RoomsListView extends React.Component {
const { item: currentItem } = this.state; const { item: currentItem } = this.state;
const { const {
user: { user: { username },
id: userId,
username,
token
},
server,
StoreLastMessage, StoreLastMessage,
useRealName, useRealName,
theme, theme,
@ -916,10 +911,7 @@ class RoomsListView extends React.Component {
theme={theme} theme={theme}
id={id} id={id}
type={item.t} type={item.t}
userId={userId}
username={username} username={username}
token={token}
baseUrl={server}
showLastMessage={StoreLastMessage} showLastMessage={StoreLastMessage}
onPress={this.onPressItem} onPress={this.onPressItem}
testID={`rooms-list-view-item-${ item.name }`} testID={`rooms-list-view-item-${ item.name }`}

View File

@ -106,7 +106,7 @@ class SelectServerView extends React.Component {
} }
const mapStateToProps = (({ share }) => ({ const mapStateToProps = (({ share }) => ({
server: share.server server: share.server.server
})); }));
export default connect(mapStateToProps)(withTheme(SelectServerView)); export default connect(mapStateToProps)(withTheme(SelectServerView));

View File

@ -473,7 +473,7 @@ class ShareListView extends React.Component {
const mapStateToProps = (({ share }) => ({ const mapStateToProps = (({ share }) => ({
userId: share.user && share.user.id, userId: share.user && share.user.id,
token: share.user && share.user.token, token: share.user && share.user.token,
server: share.server server: share.server.server
})); }));
export default connect(mapStateToProps)(withTheme(ShareListView)); export default connect(mapStateToProps)(withTheme(ShareListView));

View File

@ -345,7 +345,7 @@ ShareView.propTypes = {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
user: getUserSelector(state), user: getUserSelector(state),
server: state.share.server || state.server.server, server: state.share.server.server || state.server.server,
FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList, FileUpload_MediaTypeWhiteList: state.settings.FileUpload_MediaTypeWhiteList,
FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize FileUpload_MaxFileSize: state.settings.FileUpload_MaxFileSize
}); });

View File

@ -56,8 +56,13 @@ const reducers = combineReducers({
name: 'Rocket Cat' name: 'Rocket Cat'
} }
}), }),
server: () => ({
server: 'https://open.rocket.chat',
version: '3.7.0'
}),
share: () => ({ share: () => ({
server: 'https://open.rocket.chat' server: 'https://open.rocket.chat',
version: '3.7.0'
}), }),
settings: () => ({ settings: () => ({
blockUnauthenticatedAccess: false blockUnauthenticatedAccess: false

View File

@ -4,11 +4,6 @@ import { getStorybookUI, configure } from '@storybook/react-native'; // eslint-d
import RNBootSplash from 'react-native-bootsplash'; import RNBootSplash from 'react-native-bootsplash';
import 'react-native-gesture-handler'; import 'react-native-gesture-handler';
// eslint-disable-next-line no-undef
jest.mock('../app/lib/database', () => jest.fn(() => null)); // comment this line to make storybook work
// eslint-disable-next-line no-undef
jest.mock('../app/lib/createStore', () => ({ getState: () => ({ server: {} }) })); // comment this line to make storybook work
RNBootSplash.hide(); RNBootSplash.hide();
// import stories // import stories

View File

@ -37,7 +37,15 @@ const reducers = combineReducers({
username: 'diego.mello' username: 'diego.mello'
} }
}), }),
share: () => ({ settings: {} }), server: () => ({
server: 'https://open.rocket.chat',
version: '3.7.0'
}),
share: () => ({
server: 'https://open.rocket.chat',
version: '3.7.0',
settings: {}
}),
meteor: () => ({ connected: true }), meteor: () => ({ connected: true }),
activeUsers: () => ({ abc: { status: 'online', statusText: 'dog' } }) activeUsers: () => ({ abc: { status: 'online', statusText: 'dog' } })
}); });

View File

@ -6162,16 +6162,16 @@ entities@^2.0.0:
resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.2.tgz#ac74db0bba8d33808bbf36809c3a5c3683531436" resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.2.tgz#ac74db0bba8d33808bbf36809c3a5c3683531436"
integrity sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw== integrity sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw==
envinfo@^7.1.0:
version "7.5.1"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.5.1.tgz#93c26897225a00457c75e734d354ea9106a72236"
integrity sha512-hQBkDf2iO4Nv0CNHpCuSBeaSrveU6nThVxFGTrq/eDlV716UQk09zChaJae4mZRsos1x4YLY2TaH3LHUae3ZmQ==
envinfo@^7.5.0: envinfo@^7.5.0:
version "7.7.0" version "7.7.0"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.7.0.tgz#fbfa46d739dec0554ef40220cd91fb20f64c9698" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.7.0.tgz#fbfa46d739dec0554ef40220cd91fb20f64c9698"
integrity sha512-XX0+kACx7HcIFhar/JjsDtDIVcC8hnzQO1Asehq+abs+v9MtzpUuujFb6eBTT4lF9j2Bh6d2XFngbFRryjUAeQ== integrity sha512-XX0+kACx7HcIFhar/JjsDtDIVcC8hnzQO1Asehq+abs+v9MtzpUuujFb6eBTT4lF9j2Bh6d2XFngbFRryjUAeQ==
envinfo@^7.7.2:
version "7.7.3"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.7.3.tgz#4b2d8622e3e7366afb8091b23ed95569ea0208cc"
integrity sha512-46+j5QxbPWza0PB1i15nZx0xQ4I/EfQxg9J8Had3b408SV63nEtor2e+oiY63amTo9KTuh2a3XLObNwduxYwwA==
errno@^0.1.3, errno@~0.1.7: errno@^0.1.3, errno@~0.1.7:
version "0.1.7" version "0.1.7"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
@ -7829,6 +7829,13 @@ hermes-engine@~0.5.0:
resolved "https://registry.yarnpkg.com/hermes-engine/-/hermes-engine-0.5.0.tgz#d914acce72e9657b3c98875ad3f9094d8643f327" resolved "https://registry.yarnpkg.com/hermes-engine/-/hermes-engine-0.5.0.tgz#d914acce72e9657b3c98875ad3f9094d8643f327"
integrity sha512-jSuHiOhdh2+IF3bH2gLpQ37eMkdUrEb9GK6PoG3rLRaUDK3Zn2Y9fXM+wyDfoUTA3gz9EET0/IIWk5k21qp4kw== integrity sha512-jSuHiOhdh2+IF3bH2gLpQ37eMkdUrEb9GK6PoG3rLRaUDK3Zn2Y9fXM+wyDfoUTA3gz9EET0/IIWk5k21qp4kw==
hermes-profile-transformer@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/hermes-profile-transformer/-/hermes-profile-transformer-0.0.6.tgz#bd0f5ecceda80dd0ddaae443469ab26fb38fc27b"
integrity sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==
dependencies:
source-map "^0.7.3"
hex-lite@^1.5.0: hex-lite@^1.5.0:
version "1.5.0" version "1.5.0"
resolved "https://registry.yarnpkg.com/hex-lite/-/hex-lite-1.5.0.tgz#482db64f673dcacdb8be93c629a799ce5a76b24d" resolved "https://registry.yarnpkg.com/hex-lite/-/hex-lite-1.5.0.tgz#482db64f673dcacdb8be93c629a799ce5a76b24d"