From a0eecdcaf45d304bd32cedf7625a98bb07f31e9d Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 16 Jul 2021 12:43:08 -0400 Subject: [PATCH 01/64] Add Discussions to RoomActionsView --- app/views/RoomActionsView/index.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 914a42913..b2b779262 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -974,6 +974,24 @@ class RoomActionsView extends React.Component { ) : null} + {['c', 'p'].includes(t) + ? ( + <> + this.onPressTouchable({ + route: 'ThreadMessagesView', + params: { rid, t, name: 'Discussions' } + })} + testID='room-actions-discussions' + left={() => } + showActionIndicator + /> + + + ) + : null} + {['c', 'p', 'd'].includes(t) ? ( <> From 659f2c864694794dabc53bf1a8c6fe597fe82ca9 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 19 Jul 2021 11:33:09 -0400 Subject: [PATCH 02/64] Add Discussions to ThreadMessagesView --- app/i18n/locales/en.json | 1 + app/views/RoomActionsView/index.js | 12 +++++-- app/views/ThreadMessagesView/index.js | 48 ++++++++++++++++++--------- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 194031660..fd1ad7d50 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -688,6 +688,7 @@ "No_threads": "There are no threads", "No_threads_following": "You are not following any threads", "No_threads_unread": "There are no unread threads", + "No_discussions": "There are no discussions", "Messagebox_Send_to_channel": "Send to channel", "Leader": "Leader", "Moderator": "Moderator", diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index b2b779262..e44126006 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -903,7 +903,7 @@ class RoomActionsView extends React.Component { room, membersCount, canViewMembers, canAddUser, canInviteUser, joined, canAutoTranslate, canForwardGuest, canReturnQueue } = this.state; const { - rid, t + rid, t, prid } = room; const isGroupChat = RocketChat.isGroupChat(room); @@ -974,14 +974,20 @@ class RoomActionsView extends React.Component { ) : null} - {['c', 'p'].includes(t) + {['c', 'p'].includes(t) && !prid ? ( <> this.onPressTouchable({ route: 'ThreadMessagesView', - params: { rid, t, name: 'Discussions' } + params: { + rid, + t, + prid, + name: 'Discussions', + isDiscussion: true + } })} testID='room-actions-discussions' left={() => } diff --git a/app/views/ThreadMessagesView/index.js b/app/views/ThreadMessagesView/index.js index 48cab9c99..2b2003469 100644 --- a/app/views/ThreadMessagesView/index.js +++ b/app/views/ThreadMessagesView/index.js @@ -55,6 +55,9 @@ class ThreadMessagesView extends React.Component { this.mounted = false; this.rid = props.route.params?.rid; this.t = props.route.params?.t; + this.name = props.route.params?.name; + this.isDiscussion = props.route.params?.isDiscussion; + this.prid = props.route.params?.prid; this.state = { loading: false, end: false, @@ -131,7 +134,7 @@ class ThreadMessagesView extends React.Component { /> ), headerTitleAlign: 'center', - headerTitle: I18n.t('Threads'), + headerTitle: this.isDiscussion ? this.name : I18n.t('Threads'), headerTitleContainerStyle: { left: null, right: null @@ -296,20 +299,33 @@ class ThreadMessagesView extends React.Component { this.setState({ loading: true }); - try { - const result = await RocketChat.getThreadsList({ - rid: this.rid, count: API_FETCH_COUNT, offset: messages.length, text: searchText - }); - if (result.success) { - this.updateThreads({ update: result.threads, lastThreadSync }); - this.setState({ - loading: false, - end: result.count < API_FETCH_COUNT - }); + if (this.isDiscussion) { + try { + const db = database.active; + const subCollection = db.get('subscriptions'); + const discussions = await subCollection.query( + Q.where('prid', Q.eq(this.prid)) + ); + this.setState({ loading: false, displayingThreads: discussions }); + } catch (e) { + log(e); + } + } else { + try { + const result = await RocketChat.getThreadsList({ + rid: this.rid, count: API_FETCH_COUNT, offset: messages.length, text: searchText + }); + if (result.success) { + this.updateThreads({ update: result.threads, lastThreadSync }); + this.setState({ + loading: false, + end: result.count < API_FETCH_COUNT + }); + } + } catch (e) { + log(e); + this.setState({ loading: false, end: true }); } - } catch (e) { - log(e); - this.setState({ loading: false, end: true }); } }, 300) @@ -434,7 +450,7 @@ class ThreadMessagesView extends React.Component { renderHeader = () => { const { messages, currentFilter } = this.state; - if (!messages.length) { + if (!messages.length || this.isDiscussion) { return null; } @@ -458,7 +474,7 @@ class ThreadMessagesView extends React.Component { } else if (currentFilter === FILTER.UNREAD) { text = I18n.t('No_threads_unread'); } else { - text = I18n.t('No_threads'); + text = this.isDiscussion ? I18n.t('No_discussions') : I18n.t('No_threads'); } return ( <> From c066c208d3d97f2d79cac66b5dfd68e7ca3051a7 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Tue, 20 Jul 2021 15:25:50 -0400 Subject: [PATCH 03/64] Update DiscussionMessagesView and add to stacks --- app/stacks/InsideStack.js | 5 + app/stacks/MasterDetailStack/index.js | 5 + app/views/DiscussionMessagesView.js | 208 ++++++++++++++++++++++++++ app/views/RoomActionsView/index.js | 5 +- 4 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 app/views/DiscussionMessagesView.js diff --git a/app/stacks/InsideStack.js b/app/stacks/InsideStack.js index 83fc22240..9f500a52c 100644 --- a/app/stacks/InsideStack.js +++ b/app/stacks/InsideStack.js @@ -74,6 +74,7 @@ import QueueListView from '../ee/omnichannel/views/QueueListView'; import AddChannelTeamView from '../views/AddChannelTeamView'; import AddExistingChannelView from '../views/AddExistingChannelView'; import SelectListView from '../views/SelectListView'; +import DiscussionMessagesView from '../views/DiscussionMessagesView'; // ChatsStackNavigator const ChatsStack = createStackNavigator(); @@ -114,6 +115,10 @@ const ChatsStackNavigator = () => { component={RoomMembersView} options={RoomMembersView.navigationOptions} /> + { name='ThreadMessagesView' component={ThreadMessagesView} /> + { + const mounted = useRef(); + const rid = route.params?.rid; + const t = route.params?.t; + const prid = route.params?.prid; + const baseUrl = useSelector(state => state.server.server); + const user = useSelector(state => getUserSelector(state)); + const useRealName = useSelector(state => state.settings.UI_Use_Real_Name); + const isMasterDetail = useSelector(state => state.app.isMasterDetail); + const [loading, setLoading] = useState(false); + const [discussions, setDiscussions] = useState([]); + const [isSearching, setIsSearching] = useState(false); + // const [searchText, setSearchText] = useState(''); + const theme = useTheme(); + const insets = useSafeAreaInsets(); + + const load = debounce(async() => { + if (loading || !mounted) { + return; + } + + setLoading(true); + + try { + const db = database.active; + const subCollection = db.get('subscriptions'); + const discussionsMessages = await subCollection.query( + Q.where('rid', Q.eq(rid)), + Q.where('prid', Q.eq(prid)) + ); + setDiscussions(discussionsMessages); + setLoading(false); + } catch (e) { + log(e); + } + }, 300); + + // const onSearchChangeText = debounce((text) => { + // setSearchText(text); + // }, 300); + + const onSearchPress = () => { + setIsSearching(true); + }; + + const setHeader = () => { + if (isSearching) { + const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 1 }); + return { + headerTitleAlign: 'left', + headerLeft: () => ( + + + + ), + headerTitle: () => , + headerTitleContainerStyle: { + left: headerTitlePosition.left, + right: headerTitlePosition.right + }, + headerRight: () => null + }; + } + + const options = { + headerLeft: () => ( + navigation.pop()} + tintColor={themes[theme].headerTintColor} + /> + ), + headerTitleAlign: 'center', + headerTitle: I18n.t('Discussion'), + headerTitleContainerStyle: { + left: null, + right: null + } + }; + + if (isMasterDetail) { + options.headerLeft = () => ; + } + + options.headerRight = () => ( + + + + ); + return options; + }; + + // const onCancelSearchPress = () => { + // setIsSearching(false); + // setSearchText(''); + // setHeader(); + // }; + + useEffect(() => { + if (!mounted.current) { + load(); + mounted.current = true; + } else { + setHeader(); + } + }, []); + + + const onThreadPress = debounce((item) => { + if (isMasterDetail) { + navigation.pop(); + } + navigation.push('RoomView', { + rid: item.subscription.id, + name: makeThreadName(item), + t, + roomUserId: RocketChat.getUidDirectMessage(item) + }); + }, 1000, true); + + const getBadgeColor = item => getBadgeColor({ item, theme, messageId: item?.id }); + + // eslint-disable-next-line react/prop-types + const renderItem = ({ item }) => { + const badgeColor = getBadgeColor(item); + return ( + + ); + }; + + if (!discussions?.length) { + return ( + <> + + + ); + } + + return ( + + + : null} + scrollIndicatorInsets={{ right: 1 }} // https://github.com/facebook/react-native/issues/26610#issuecomment-539843444 + /> + + ); +}; + +DiscussionMessagesView.propTypes = { + navigation: PropTypes.object, + route: PropTypes.object +}; + +export default DiscussionMessagesView; diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index e44126006..29a4b1a7c 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -980,13 +980,12 @@ class RoomActionsView extends React.Component { this.onPressTouchable({ - route: 'ThreadMessagesView', + route: 'DiscussionMessagesView', params: { rid, t, prid, - name: 'Discussions', - isDiscussion: true + name: 'Discussions' } })} testID='room-actions-discussions' From daba3b44e9ae1e58f18083cadc0508c3d874543f Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 21 Jul 2021 13:29:22 -0400 Subject: [PATCH 04/64] Fix DiscussionMessagesView --- app/views/DiscussionMessagesView.js | 110 ++++++++++++---------------- app/views/RoomActionsView/index.js | 4 +- 2 files changed, 50 insertions(+), 64 deletions(-) diff --git a/app/views/DiscussionMessagesView.js b/app/views/DiscussionMessagesView.js index 3a483cb31..06820dbbd 100644 --- a/app/views/DiscussionMessagesView.js +++ b/app/views/DiscussionMessagesView.js @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { FlatList } from 'react-native'; import { useSelector } from 'react-redux'; @@ -6,44 +6,44 @@ import { Q } from '@nozbe/watermelondb'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { HeaderBackButton } from '@react-navigation/stack'; -import Item from './ThreadMessagesView/Item'; import ActivityIndicator from '../containers/ActivityIndicator'; import I18n from '../i18n'; -import RocketChat from '../lib/rocketchat'; import database from '../lib/database'; import StatusBar from '../containers/StatusBar'; import log from '../utils/log'; import debounce from '../utils/debounce'; import { themes } from '../constants/colors'; -import { getUserSelector } from '../selectors/login'; import SafeAreaView from '../containers/SafeAreaView'; import * as HeaderButton from '../containers/HeaderButton'; import * as List from '../containers/List'; import BackgroundContainer from '../containers/BackgroundContainer'; import { isIOS } from '../utils/deviceInfo'; -import { makeThreadName } from '../utils/room'; import { getHeaderTitlePosition } from '../containers/Header'; import SearchHeader from './ThreadMessagesView/SearchHeader'; import { useTheme } from '../theme'; +import Message from '../containers/message'; const DiscussionMessagesView = ({ navigation, route }) => { - const mounted = useRef(); const rid = route.params?.rid; - const t = route.params?.t; - const prid = route.params?.prid; + // const t = route.params?.t; + // const prid = route.params?.prid; + const canAutoTranslate = route.params?.canAutoTranslate; + const autoTranslate = route.params?.autoTranslate; + const autoTranslateLanguage = route.params?.autoTranslateLanguage; const baseUrl = useSelector(state => state.server.server); - const user = useSelector(state => getUserSelector(state)); + // const user = useSelector(state => getUserSelector(state)); const useRealName = useSelector(state => state.settings.UI_Use_Real_Name); + const Message_TimeFormat = useSelector(state => state.settings.Message_TimeFormat); const isMasterDetail = useSelector(state => state.app.isMasterDetail); const [loading, setLoading] = useState(false); const [discussions, setDiscussions] = useState([]); const [isSearching, setIsSearching] = useState(false); - // const [searchText, setSearchText] = useState(''); - const theme = useTheme(); + const [searchText, setSearchText] = useState(''); + const { theme } = useTheme(); const insets = useSafeAreaInsets(); - const load = debounce(async() => { - if (loading || !mounted) { + const load = async() => { + if (loading) { return; } @@ -51,21 +51,26 @@ const DiscussionMessagesView = ({ navigation, route }) => { try { const db = database.active; - const subCollection = db.get('subscriptions'); - const discussionsMessages = await subCollection.query( + const subCollection = db.get('messages'); + const subDiscussions = await subCollection.query( Q.where('rid', Q.eq(rid)), - Q.where('prid', Q.eq(prid)) + Q.where('drid', Q.notEq(null)) ); - setDiscussions(discussionsMessages); + setDiscussions(subDiscussions); setLoading(false); } catch (e) { log(e); } + }; + + const onSearchChangeText = debounce((text) => { + setSearchText(text); }, 300); - // const onSearchChangeText = debounce((text) => { - // setSearchText(text); - // }, 300); + const onCancelSearchPress = () => { + setIsSearching(false); + setSearchText(''); + }; const onSearchPress = () => { setIsSearching(true); @@ -80,11 +85,11 @@ const DiscussionMessagesView = ({ navigation, route }) => { ), - headerTitle: () => , + headerTitle: () => , headerTitleContainerStyle: { left: headerTitlePosition.left, right: headerTitlePosition.right @@ -102,7 +107,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { /> ), headerTitleAlign: 'center', - headerTitle: I18n.t('Discussion'), + headerTitle: I18n.t('Discussions'), headerTitleContainerStyle: { left: null, right: null @@ -121,54 +126,34 @@ const DiscussionMessagesView = ({ navigation, route }) => { return options; }; - // const onCancelSearchPress = () => { - // setIsSearching(false); - // setSearchText(''); - // setHeader(); - // }; - useEffect(() => { - if (!mounted.current) { - load(); - mounted.current = true; - } else { - setHeader(); - } + load(); + const options = setHeader(); + navigation.setOptions(options); }, []); - const onThreadPress = debounce((item) => { - if (isMasterDetail) { - navigation.pop(); - } + const onDiscussionPress = debounce((item) => { navigation.push('RoomView', { - rid: item.subscription.id, - name: makeThreadName(item), - t, - roomUserId: RocketChat.getUidDirectMessage(item) + rid: item.drid, prid: item.rid, name: item.msg, t: 'p' }); }, 1000, true); - const getBadgeColor = item => getBadgeColor({ item, theme, messageId: item?.id }); - // eslint-disable-next-line react/prop-types - const renderItem = ({ item }) => { - const badgeColor = getBadgeColor(item); - return ( - - ); - }; + const renderItem = ({ item }) => ( + + ); if (!discussions?.length) { return ( @@ -186,7 +171,6 @@ const DiscussionMessagesView = ({ navigation, route }) => { renderItem={renderItem} // style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]} // contentContainerStyle={styles.contentContainer} - onEndReached={load} onEndReachedThreshold={0.5} maxToRenderPerBatch={5} windowSize={10} diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 29a4b1a7c..44ffe9de6 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -985,7 +985,9 @@ class RoomActionsView extends React.Component { rid, t, prid, - name: 'Discussions' + canAutoTranslate, + autoTranslate: room.autoTranslate, + autoTranslateLanguage: room.autoTranslateLanguage } })} testID='room-actions-discussions' From da3bdd42726c493e8a3aed4b0466e2a67a8c613a Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 21 Jul 2021 16:23:34 -0400 Subject: [PATCH 05/64] Fix search --- app/views/DiscussionMessagesView.js | 32 ++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/app/views/DiscussionMessagesView.js b/app/views/DiscussionMessagesView.js index 06820dbbd..7b678922e 100644 --- a/app/views/DiscussionMessagesView.js +++ b/app/views/DiscussionMessagesView.js @@ -22,6 +22,7 @@ import { getHeaderTitlePosition } from '../containers/Header'; import SearchHeader from './ThreadMessagesView/SearchHeader'; import { useTheme } from '../theme'; import Message from '../containers/message'; +import { sanitizeLikeString } from '../lib/database/utils'; const DiscussionMessagesView = ({ navigation, route }) => { const rid = route.params?.rid; @@ -38,7 +39,6 @@ const DiscussionMessagesView = ({ navigation, route }) => { const [loading, setLoading] = useState(false); const [discussions, setDiscussions] = useState([]); const [isSearching, setIsSearching] = useState(false); - const [searchText, setSearchText] = useState(''); const { theme } = useTheme(); const insets = useSafeAreaInsets(); @@ -63,13 +63,30 @@ const DiscussionMessagesView = ({ navigation, route }) => { } }; - const onSearchChangeText = debounce((text) => { - setSearchText(text); + const onSearchChangeText = debounce(async(text) => { + try { + const db = database.active; + const whereClause = [ + Q.where('rid', Q.eq(rid)), + Q.where('drid', Q.notEq(null)) + ]; + + if (text?.trim()) { + whereClause.push(Q.where('msg', Q.like(`%${ sanitizeLikeString(text?.trim()) }%`))); + } + + const discussionsMessages = await db + .get('messages') + .query(...whereClause); + setDiscussions(discussionsMessages); + } catch (e) { + log(e); + } }, 300); const onCancelSearchPress = () => { setIsSearching(false); - setSearchText(''); + load(); }; const onSearchPress = () => { @@ -128,9 +145,12 @@ const DiscussionMessagesView = ({ navigation, route }) => { useEffect(() => { load(); + }, []); + + useEffect(() => { const options = setHeader(); navigation.setOptions(options); - }, []); + }, [navigation, isSearching]); const onDiscussionPress = debounce((item) => { @@ -169,6 +189,8 @@ const DiscussionMessagesView = ({ navigation, route }) => { item.msg} // style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]} // contentContainerStyle={styles.contentContainer} onEndReachedThreshold={0.5} From 9ad45f067cbd6e2ca77c0af9e807f2624f75f3c4 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 21 Jul 2021 17:17:48 -0400 Subject: [PATCH 06/64] Add E2E test --- e2e/tests/room/04-discussion.spec.js | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/e2e/tests/room/04-discussion.spec.js b/e2e/tests/room/04-discussion.spec.js index 29fc5a090..a3185d6c6 100644 --- a/e2e/tests/room/04-discussion.spec.js +++ b/e2e/tests/room/04-discussion.spec.js @@ -71,7 +71,7 @@ describe('Discussion', () => { }); describe('Check RoomActionsView render', () => { - it('should navigete to RoomActionsView', async() => { + it('should navigate to RoomActionsView', async() => { await waitFor(element(by.id('room-header'))).toBeVisible().withTimeout(5000); await element(by.id('room-header')).tap(); await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000); @@ -118,7 +118,7 @@ describe('Discussion', () => { await expect(element(by.id('room-actions-leave-channel'))).toBeVisible(); }); - it('should navigate to RoomActionView', async() => { + it('should navigate to RoomActionsView', async() => { await element(by.type('UIScrollView')).atIndex(1).swipe('down'); await expect(element(by.id('room-actions-info'))).toBeVisible(); await element(by.id('room-actions-info')).tap(); @@ -130,4 +130,25 @@ describe('Discussion', () => { await expect(element(by.id('room-info-view-edit-button'))).toBeVisible(); }); }); + + describe('Open Discussion from DiscussionMessagesView', () => { + const discussionName = `${ data.random }message`; + it('should go back to main room', async() => { + await tapBack(); + await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000); + await tapBack(); + await waitFor(element(by.id(`room-view-title-${ discussionName }`))).toExist().withTimeout(5000); + await tapBack(); + await navigateToRoom(); + }); + + it('should navigate to DiscussionMessagesView', async() => { + await waitFor(element(by.id(`room-view-title-${ channel }`))).toExist().withTimeout(5000); + await waitFor(element(by.id('room-header'))).toBeVisible().withTimeout(5000); + await element(by.id('room-header')).tap(); + await waitFor(element(by.id('room-actions-discussions'))).toBeVisible().withTimeout(5000); + await element(by.id('room-actions-discussions')).tap(); + await waitFor(element(by.id('discussion-messages-view'))).toBeVisible().withTimeout(5000); + }); + }); }); From fc59b7426cd9a818df36c8ef4d8bce64d83151ae Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 21 Jul 2021 17:22:03 -0400 Subject: [PATCH 07/64] Remove old changes from ThreadMessagesView --- app/views/ThreadMessagesView/index.js | 46 +++++++++------------------ 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/app/views/ThreadMessagesView/index.js b/app/views/ThreadMessagesView/index.js index 2b2003469..48cab9c99 100644 --- a/app/views/ThreadMessagesView/index.js +++ b/app/views/ThreadMessagesView/index.js @@ -55,9 +55,6 @@ class ThreadMessagesView extends React.Component { this.mounted = false; this.rid = props.route.params?.rid; this.t = props.route.params?.t; - this.name = props.route.params?.name; - this.isDiscussion = props.route.params?.isDiscussion; - this.prid = props.route.params?.prid; this.state = { loading: false, end: false, @@ -134,7 +131,7 @@ class ThreadMessagesView extends React.Component { /> ), headerTitleAlign: 'center', - headerTitle: this.isDiscussion ? this.name : I18n.t('Threads'), + headerTitle: I18n.t('Threads'), headerTitleContainerStyle: { left: null, right: null @@ -299,33 +296,20 @@ class ThreadMessagesView extends React.Component { this.setState({ loading: true }); - if (this.isDiscussion) { - try { - const db = database.active; - const subCollection = db.get('subscriptions'); - const discussions = await subCollection.query( - Q.where('prid', Q.eq(this.prid)) - ); - this.setState({ loading: false, displayingThreads: discussions }); - } catch (e) { - log(e); - } - } else { - try { - const result = await RocketChat.getThreadsList({ - rid: this.rid, count: API_FETCH_COUNT, offset: messages.length, text: searchText + try { + const result = await RocketChat.getThreadsList({ + rid: this.rid, count: API_FETCH_COUNT, offset: messages.length, text: searchText + }); + if (result.success) { + this.updateThreads({ update: result.threads, lastThreadSync }); + this.setState({ + loading: false, + end: result.count < API_FETCH_COUNT }); - if (result.success) { - this.updateThreads({ update: result.threads, lastThreadSync }); - this.setState({ - loading: false, - end: result.count < API_FETCH_COUNT - }); - } - } catch (e) { - log(e); - this.setState({ loading: false, end: true }); } + } catch (e) { + log(e); + this.setState({ loading: false, end: true }); } }, 300) @@ -450,7 +434,7 @@ class ThreadMessagesView extends React.Component { renderHeader = () => { const { messages, currentFilter } = this.state; - if (!messages.length || this.isDiscussion) { + if (!messages.length) { return null; } @@ -474,7 +458,7 @@ class ThreadMessagesView extends React.Component { } else if (currentFilter === FILTER.UNREAD) { text = I18n.t('No_threads_unread'); } else { - text = this.isDiscussion ? I18n.t('No_discussions') : I18n.t('No_threads'); + text = I18n.t('No_threads'); } return ( <> From 82b306b95a0db380413581e7910af1032f60c77e Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 22 Jul 2021 11:24:24 -0400 Subject: [PATCH 08/64] Minor tweak --- app/views/DiscussionMessagesView.js | 3 --- app/views/RoomView/index.js | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/app/views/DiscussionMessagesView.js b/app/views/DiscussionMessagesView.js index 7b678922e..87a6755f2 100644 --- a/app/views/DiscussionMessagesView.js +++ b/app/views/DiscussionMessagesView.js @@ -26,13 +26,10 @@ import { sanitizeLikeString } from '../lib/database/utils'; const DiscussionMessagesView = ({ navigation, route }) => { const rid = route.params?.rid; - // const t = route.params?.t; - // const prid = route.params?.prid; const canAutoTranslate = route.params?.canAutoTranslate; const autoTranslate = route.params?.autoTranslate; const autoTranslateLanguage = route.params?.autoTranslateLanguage; const baseUrl = useSelector(state => state.server.server); - // const user = useSelector(state => getUserSelector(state)); const useRealName = useSelector(state => state.settings.UI_Use_Real_Name); const Message_TimeFormat = useSelector(state => state.settings.Message_TimeFormat); const isMasterDetail = useSelector(state => state.app.isMasterDetail); diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 13de89c87..d6e94a9a0 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -424,7 +424,7 @@ class RoomView extends React.Component { } }); } else { - navigation.navigate('RoomActionsView', { + navigation.push('RoomActionsView', { rid: this.rid, t: this.t, room, member }); } From 7feb5094fc8ba11adf80b82ab1310a0878a280ac Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Sun, 22 Aug 2021 21:51:22 -0400 Subject: [PATCH 09/64] Add discussions for channels --- app/views/DiscussionMessagesView.js | 5 ++--- app/views/RoomActionsView/index.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/app/views/DiscussionMessagesView.js b/app/views/DiscussionMessagesView.js index 87a6755f2..6069419a2 100644 --- a/app/views/DiscussionMessagesView.js +++ b/app/views/DiscussionMessagesView.js @@ -188,8 +188,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { renderItem={renderItem} // eslint-disable-next-line react/prop-types keyExtractor={item => item.msg} - // style={[styles.list, { backgroundColor: themes[theme].backgroundColor }]} - // contentContainerStyle={styles.contentContainer} + style={{ backgroundColor: themes[theme].backgroundColor }} onEndReachedThreshold={0.5} maxToRenderPerBatch={5} windowSize={10} @@ -197,7 +196,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { removeClippedSubviews={isIOS} ItemSeparatorComponent={List.Separator} ListFooterComponent={loading ? : null} - scrollIndicatorInsets={{ right: 1 }} // https://github.com/facebook/react-native/issues/26610#issuecomment-539843444 + scrollIndicatorInsets={{ right: 1 }} /> ); diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 44ffe9de6..585f6237b 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -974,7 +974,7 @@ class RoomActionsView extends React.Component { ) : null} - {['c', 'p'].includes(t) && !prid + {['c', 'p', 'd'].includes(t) && !prid ? ( <> Date: Wed, 1 Sep 2021 13:15:15 -0400 Subject: [PATCH 10/64] Minor tweak --- app/views/DiscussionMessagesView.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/views/DiscussionMessagesView.js b/app/views/DiscussionMessagesView.js index 6069419a2..4e6750192 100644 --- a/app/views/DiscussionMessagesView.js +++ b/app/views/DiscussionMessagesView.js @@ -1,3 +1,4 @@ +/* eslint-disable react/prop-types */ import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { FlatList } from 'react-native'; @@ -29,6 +30,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { const canAutoTranslate = route.params?.canAutoTranslate; const autoTranslate = route.params?.autoTranslate; const autoTranslateLanguage = route.params?.autoTranslateLanguage; + const user = useSelector(state => state.login?.user); const baseUrl = useSelector(state => state.server.server); const useRealName = useSelector(state => state.settings.UI_Use_Real_Name); const Message_TimeFormat = useSelector(state => state.settings.Message_TimeFormat); @@ -69,7 +71,8 @@ const DiscussionMessagesView = ({ navigation, route }) => { ]; if (text?.trim()) { - whereClause.push(Q.where('msg', Q.like(`%${ sanitizeLikeString(text?.trim()) }%`))); + whereClause.push(Q.where('msg', Q.like(`%${ sanitizeLikeString(text?.trim()) }%`)), + Q.where('username', Q.like(`%${ sanitizeLikeString(text?.trim()) }%`))); } const discussionsMessages = await db @@ -156,13 +159,12 @@ const DiscussionMessagesView = ({ navigation, route }) => { }); }, 1000, true); - // eslint-disable-next-line react/prop-types const renderItem = ({ item }) => ( {}} onDiscussionPress={onDiscussionPress} baseUrl={baseUrl} timeFormat={Message_TimeFormat} @@ -186,7 +188,6 @@ const DiscussionMessagesView = ({ navigation, route }) => { item.msg} style={{ backgroundColor: themes[theme].backgroundColor }} onEndReachedThreshold={0.5} From 330ab40e16d76fa43f5c0926035ea8d1bdaf9587 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 2 Sep 2021 17:04:39 -0400 Subject: [PATCH 11/64] Fix navToRoomInfo --- app/views/DiscussionMessagesView.js | 4 ++-- app/views/RoomActionsView/index.js | 4 +++- app/views/RoomView/index.js | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/views/DiscussionMessagesView.js b/app/views/DiscussionMessagesView.js index 4e6750192..3f908177d 100644 --- a/app/views/DiscussionMessagesView.js +++ b/app/views/DiscussionMessagesView.js @@ -30,6 +30,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { const canAutoTranslate = route.params?.canAutoTranslate; const autoTranslate = route.params?.autoTranslate; const autoTranslateLanguage = route.params?.autoTranslateLanguage; + const navToRoomInfo = route.params?.navToRoomInfo; const user = useSelector(state => state.login?.user); const baseUrl = useSelector(state => state.server.server); const useRealName = useSelector(state => state.settings.UI_Use_Real_Name); @@ -164,7 +165,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { item={item} user={user} rid={rid} - navToRoomInfo={() => {}} + navToRoomInfo={navToRoomInfo} onDiscussionPress={onDiscussionPress} baseUrl={baseUrl} timeFormat={Message_TimeFormat} @@ -173,7 +174,6 @@ const DiscussionMessagesView = ({ navigation, route }) => { autoTranslateLanguage={autoTranslateLanguage} /> ); - if (!discussions?.length) { return ( <> diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 585f6237b..6614d75ae 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -78,6 +78,7 @@ class RoomActionsView extends React.Component { const member = props.route.params?.member; this.rid = props.route.params?.rid; this.t = props.route.params?.t; + this.navToRoomInfo = props.route.params?.navToRoomInfo; this.state = { room: room || { rid: this.rid, t: this.t }, membersCount: 0, @@ -987,7 +988,8 @@ class RoomActionsView extends React.Component { prid, canAutoTranslate, autoTranslate: room.autoTranslate, - autoTranslateLanguage: room.autoTranslateLanguage + autoTranslateLanguage: room.autoTranslateLanguage, + navToRoomInfo: navParam => this.navToRoomInfo(navParam) } })} testID='room-actions-discussions' diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 484e17209..9ff9438c8 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -420,12 +420,12 @@ class RoomView extends React.Component { navigation.navigate('ModalStackNavigator', { screen: screen ?? 'RoomActionsView', params: { - rid: this.rid, t: this.t, room, member, showCloseModal: !!screen + rid: this.rid, t: this.t, room, member, showCloseModal: !!screen, navToRoomInfo: navParam => this.navToRoomInfo(navParam) } }); } else { navigation.push('RoomActionsView', { - rid: this.rid, t: this.t, room, member + rid: this.rid, t: this.t, room, member, navToRoomInfo: navParam => this.navToRoomInfo(navParam) }); } } From 2b1f78f3ecb1d04879051d2a29c1bedfbd5d537a Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 3 Sep 2021 11:11:57 -0400 Subject: [PATCH 12/64] Fix search --- app/views/DiscussionMessagesView.js | 5 ++--- app/views/ThreadMessagesView/SearchHeader.js | 11 ++++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/DiscussionMessagesView.js b/app/views/DiscussionMessagesView.js index 3f908177d..595d8f18d 100644 --- a/app/views/DiscussionMessagesView.js +++ b/app/views/DiscussionMessagesView.js @@ -72,8 +72,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { ]; if (text?.trim()) { - whereClause.push(Q.where('msg', Q.like(`%${ sanitizeLikeString(text?.trim()) }%`)), - Q.where('username', Q.like(`%${ sanitizeLikeString(text?.trim()) }%`))); + whereClause.push(Q.where('msg', Q.like(`%${ sanitizeLikeString(text?.trim()) }%`))); } const discussionsMessages = await db @@ -107,7 +106,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { /> ), - headerTitle: () => , + headerTitle: () => , headerTitleContainerStyle: { left: headerTitlePosition.left, right: headerTitlePosition.right diff --git a/app/views/ThreadMessagesView/SearchHeader.js b/app/views/ThreadMessagesView/SearchHeader.js index ae8c96e84..8bb82f26e 100644 --- a/app/views/ThreadMessagesView/SearchHeader.js +++ b/app/views/ThreadMessagesView/SearchHeader.js @@ -2,7 +2,7 @@ import React from 'react'; import { StyleSheet, View } from 'react-native'; import PropTypes from 'prop-types'; -import { withTheme } from '../../theme'; +import { useTheme, withTheme } from '../../theme'; import sharedStyles from '../Styles'; import { themes } from '../../constants/colors'; import TextInput from '../../presentation/TextInput'; @@ -21,7 +21,8 @@ const styles = StyleSheet.create({ }); // TODO: it might be useful to refactor this component for reusage -const SearchHeader = ({ theme, onSearchChangeText }) => { +const SearchHeader = ({ onSearchChangeText, placeholder }) => { + const { theme } = useTheme(); const titleColorStyle = { color: themes[theme].headerTitleColor }; const isLight = theme === 'light'; const { isLandscape } = useOrientation(); @@ -33,7 +34,7 @@ const SearchHeader = ({ theme, onSearchChangeText }) => { { }; SearchHeader.propTypes = { - theme: PropTypes.string, - onSearchChangeText: PropTypes.func + onSearchChangeText: PropTypes.func, + placeholder: PropTypes.string }; export default withTheme(SearchHeader); From 7429e4be5c8399730dd6155d53e084ad502d816f Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 3 Sep 2021 15:50:18 -0400 Subject: [PATCH 13/64] Add getDiscussions endpoint --- app/lib/rocketchat.js | 12 ++++++ app/views/DiscussionMessagesView.js | 58 ++++++++++++++++------------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 59ee94fc5..92d430d69 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -798,6 +798,18 @@ const RocketChat = { prid, pmid, t_name, reply, users, encrypted }); }, + getDiscussions({ + roomId, offset, count, text = '' + }) { + const params = { + roomId, + offset, + count, + text + }; + // RC 2.4.0 + return this.sdk.get('chat.getDiscussions', params); + }, createTeam({ name, users, type, readOnly, broadcast, encrypted }) { diff --git a/app/views/DiscussionMessagesView.js b/app/views/DiscussionMessagesView.js index 595d8f18d..92b4c536b 100644 --- a/app/views/DiscussionMessagesView.js +++ b/app/views/DiscussionMessagesView.js @@ -3,13 +3,11 @@ import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { FlatList } from 'react-native'; import { useSelector } from 'react-redux'; -import { Q } from '@nozbe/watermelondb'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { HeaderBackButton } from '@react-navigation/stack'; import ActivityIndicator from '../containers/ActivityIndicator'; import I18n from '../i18n'; -import database from '../lib/database'; import StatusBar from '../containers/StatusBar'; import log from '../utils/log'; import debounce from '../utils/debounce'; @@ -23,7 +21,9 @@ import { getHeaderTitlePosition } from '../containers/Header'; import SearchHeader from './ThreadMessagesView/SearchHeader'; import { useTheme } from '../theme'; import Message from '../containers/message'; -import { sanitizeLikeString } from '../lib/database/utils'; +import RocketChat from '../lib/rocketchat'; + +const API_FETCH_COUNT = 25; const DiscussionMessagesView = ({ navigation, route }) => { const rid = route.params?.rid; @@ -38,6 +38,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { const isMasterDetail = useSelector(state => state.app.isMasterDetail); const [loading, setLoading] = useState(false); const [discussions, setDiscussions] = useState([]); + const [search, setSearch] = useState([]); const [isSearching, setIsSearching] = useState(false); const { theme } = useTheme(); const insets = useSafeAreaInsets(); @@ -48,39 +49,43 @@ const DiscussionMessagesView = ({ navigation, route }) => { } setLoading(true); - try { - const db = database.active; - const subCollection = db.get('messages'); - const subDiscussions = await subCollection.query( - Q.where('rid', Q.eq(rid)), - Q.where('drid', Q.notEq(null)) - ); - setDiscussions(subDiscussions); + const result = await RocketChat.getDiscussions({ + roomId: rid, + offset: discussions.length, + count: API_FETCH_COUNT + }); + + if (result.success) { + if (isSearching) { + setSearch(result.messages); + } else { + setDiscussions(result.messages); + } + } setLoading(false); } catch (e) { log(e); + setLoading(false); } }; const onSearchChangeText = debounce(async(text) => { + setLoading(true); try { - const db = database.active; - const whereClause = [ - Q.where('rid', Q.eq(rid)), - Q.where('drid', Q.notEq(null)) - ]; - - if (text?.trim()) { - whereClause.push(Q.where('msg', Q.like(`%${ sanitizeLikeString(text?.trim()) }%`))); + const result = await RocketChat.getDiscussions({ + roomId: rid, + offset: search.length, + count: API_FETCH_COUNT, + text + }); + if (result.success) { + setSearch(result.messages); } - - const discussionsMessages = await db - .get('messages') - .query(...whereClause); - setDiscussions(discussionsMessages); + setLoading(false); } catch (e) { log(e); + setLoading(false); } }, 300); @@ -106,7 +111,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { /> ), - headerTitle: () => , + headerTitle: () => , headerTitleContainerStyle: { left: headerTitlePosition.left, right: headerTitlePosition.right @@ -185,7 +190,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { item.msg} style={{ backgroundColor: themes[theme].backgroundColor }} @@ -194,6 +199,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { windowSize={10} initialNumToRender={7} removeClippedSubviews={isIOS} + onEndReached={() => discussions.length > 25 ?? load()} ItemSeparatorComponent={List.Separator} ListFooterComponent={loading ? : null} scrollIndicatorInsets={{ right: 1 }} From 91dedfb6205fd062d60c224282897fd7de8ec3ca Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 8 Sep 2021 19:56:35 -0400 Subject: [PATCH 14/64] Convert SearchHeader to reusable component and minor tweaks to DiscussionMessagesView --- app/containers/SearchHeader.js | 52 ++++++++++++++++++++ app/lib/rocketchat.js | 2 +- app/views/DiscussionMessagesView.js | 48 +++++++++--------- app/views/TeamChannelsView.js | 16 ++++-- app/views/ThreadMessagesView/SearchHeader.js | 50 ------------------- app/views/ThreadMessagesView/index.js | 4 +- 6 files changed, 92 insertions(+), 80 deletions(-) create mode 100644 app/containers/SearchHeader.js delete mode 100644 app/views/ThreadMessagesView/SearchHeader.js diff --git a/app/containers/SearchHeader.js b/app/containers/SearchHeader.js new file mode 100644 index 000000000..cb0fb2bee --- /dev/null +++ b/app/containers/SearchHeader.js @@ -0,0 +1,52 @@ +import React from 'react'; +import { StyleSheet, View } from 'react-native'; +import PropTypes from 'prop-types'; + +import { withDimensions } from '../dimensions'; +import { isIOS, isTablet } from '../utils/deviceInfo'; +import { themes } from '../constants/colors'; +import sharedStyles from '../views/Styles'; +import TextInput from '../presentation/TextInput'; + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + marginLeft: 0 + }, + title: { + ...sharedStyles.textSemibold + } +}); + +const SearchHeader = ({ + onSearchChangeText, placeholder, theme, testID, width, height +}) => { + const isLight = theme === 'light'; + const isLandscape = width > height; + const scale = isIOS && isLandscape && !isTablet ? 0.8 : 1; + const titleFontSize = 16 * scale; + + return ( + + + + ); +}; + +SearchHeader.propTypes = { + onSearchChangeText: PropTypes.func.isRequired, + placeholder: PropTypes.string.isRequired, + theme: PropTypes.string, + testID: PropTypes.string, + width: PropTypes.number, + height: PropTypes.number +}; +export default withDimensions(SearchHeader); diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 92d430d69..9858ff134 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -799,7 +799,7 @@ const RocketChat = { }); }, getDiscussions({ - roomId, offset, count, text = '' + roomId, offset, count, text }) { const params = { roomId, diff --git a/app/views/DiscussionMessagesView.js b/app/views/DiscussionMessagesView.js index 92b4c536b..9475e50ba 100644 --- a/app/views/DiscussionMessagesView.js +++ b/app/views/DiscussionMessagesView.js @@ -1,4 +1,3 @@ -/* eslint-disable react/prop-types */ import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { FlatList } from 'react-native'; @@ -18,10 +17,11 @@ import * as List from '../containers/List'; import BackgroundContainer from '../containers/BackgroundContainer'; import { isIOS } from '../utils/deviceInfo'; import { getHeaderTitlePosition } from '../containers/Header'; -import SearchHeader from './ThreadMessagesView/SearchHeader'; + import { useTheme } from '../theme'; import Message from '../containers/message'; import RocketChat from '../lib/rocketchat'; +import SearchHeader from '../containers/SearchHeader'; const API_FETCH_COUNT = 25; @@ -31,19 +31,22 @@ const DiscussionMessagesView = ({ navigation, route }) => { const autoTranslate = route.params?.autoTranslate; const autoTranslateLanguage = route.params?.autoTranslateLanguage; const navToRoomInfo = route.params?.navToRoomInfo; + const user = useSelector(state => state.login?.user); const baseUrl = useSelector(state => state.server.server); const useRealName = useSelector(state => state.settings.UI_Use_Real_Name); const Message_TimeFormat = useSelector(state => state.settings.Message_TimeFormat); const isMasterDetail = useSelector(state => state.app.isMasterDetail); + const [loading, setLoading] = useState(false); const [discussions, setDiscussions] = useState([]); const [search, setSearch] = useState([]); const [isSearching, setIsSearching] = useState(false); + const { theme } = useTheme(); const insets = useSafeAreaInsets(); - const load = async() => { + const load = async(text = '') => { if (loading) { return; } @@ -52,8 +55,9 @@ const DiscussionMessagesView = ({ navigation, route }) => { try { const result = await RocketChat.getDiscussions({ roomId: rid, - offset: discussions.length, - count: API_FETCH_COUNT + offset: isSearching ? search.length : discussions.length, + count: API_FETCH_COUNT, + text }); if (result.success) { @@ -71,22 +75,8 @@ const DiscussionMessagesView = ({ navigation, route }) => { }; const onSearchChangeText = debounce(async(text) => { - setLoading(true); - try { - const result = await RocketChat.getDiscussions({ - roomId: rid, - offset: search.length, - count: API_FETCH_COUNT, - text - }); - if (result.success) { - setSearch(result.messages); - } - setLoading(false); - } catch (e) { - log(e); - setLoading(false); - } + setIsSearching(true); + await load(text); }, 300); const onCancelSearchPress = () => { @@ -111,7 +101,14 @@ const DiscussionMessagesView = ({ navigation, route }) => { /> ), - headerTitle: () => , + headerTitle: () => ( + + ), headerTitleContainerStyle: { left: headerTitlePosition.left, right: headerTitlePosition.right @@ -199,7 +196,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { windowSize={10} initialNumToRender={7} removeClippedSubviews={isIOS} - onEndReached={() => discussions.length > 25 ?? load()} + onEndReached={() => discussions.length > API_FETCH_COUNT ?? load()} ItemSeparatorComponent={List.Separator} ListFooterComponent={loading ? : null} scrollIndicatorInsets={{ right: 1 }} @@ -210,7 +207,10 @@ const DiscussionMessagesView = ({ navigation, route }) => { DiscussionMessagesView.propTypes = { navigation: PropTypes.object, - route: PropTypes.object + route: PropTypes.object, + item: PropTypes.shape({ + msg: PropTypes.string + }) }; export default DiscussionMessagesView; diff --git a/app/views/TeamChannelsView.js b/app/views/TeamChannelsView.js index 64822aeae..d22b14ded 100644 --- a/app/views/TeamChannelsView.js +++ b/app/views/TeamChannelsView.js @@ -8,7 +8,7 @@ import { connect } from 'react-redux'; import StatusBar from '../containers/StatusBar'; import RoomHeader from '../containers/RoomHeader'; import { withTheme } from '../theme'; -import SearchHeader from './ThreadMessagesView/SearchHeader'; + import log, { events, logEvent } from '../utils/log'; import database from '../lib/database'; import { getUserSelector } from '../selectors/login'; @@ -29,6 +29,7 @@ import { withActionSheet } from '../containers/ActionSheet'; import { deleteRoom as deleteRoomAction } from '../actions/room'; import { CustomIcon } from '../lib/Icons'; import { themes } from '../constants/colors'; +import SearchHeader from '../containers/SearchHeader'; const API_FETCH_COUNT = 25; const PERMISSION_DELETE_C = 'delete-c'; @@ -162,7 +163,9 @@ class TeamChannelsView extends React.Component { setHeader = () => { const { isSearching, showCreate, data } = this.state; - const { navigation, isMasterDetail, insets } = this.props; + const { + navigation, isMasterDetail, insets, theme + } = this.props; const { team } = this; if (!team) { @@ -182,7 +185,14 @@ class TeamChannelsView extends React.Component { /> ), - headerTitle: () => , + headerTitle: () => ( + + ), headerTitleContainerStyle: { left: headerTitlePosition.left, right: headerTitlePosition.right diff --git a/app/views/ThreadMessagesView/SearchHeader.js b/app/views/ThreadMessagesView/SearchHeader.js deleted file mode 100644 index 8bb82f26e..000000000 --- a/app/views/ThreadMessagesView/SearchHeader.js +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; -import { StyleSheet, View } from 'react-native'; -import PropTypes from 'prop-types'; - -import { useTheme, withTheme } from '../../theme'; -import sharedStyles from '../Styles'; -import { themes } from '../../constants/colors'; -import TextInput from '../../presentation/TextInput'; -import { isTablet, isIOS } from '../../utils/deviceInfo'; -import { useOrientation } from '../../dimensions'; - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - marginLeft: 0 - }, - title: { - ...sharedStyles.textSemibold - } -}); - -// TODO: it might be useful to refactor this component for reusage -const SearchHeader = ({ onSearchChangeText, placeholder }) => { - const { theme } = useTheme(); - const titleColorStyle = { color: themes[theme].headerTitleColor }; - const isLight = theme === 'light'; - const { isLandscape } = useOrientation(); - const scale = isIOS && isLandscape && !isTablet ? 0.8 : 1; - const titleFontSize = 16 * scale; - - return ( - - - - ); -}; - -SearchHeader.propTypes = { - onSearchChangeText: PropTypes.func, - placeholder: PropTypes.string -}; -export default withTheme(SearchHeader); diff --git a/app/views/ThreadMessagesView/index.js b/app/views/ThreadMessagesView/index.js index 48cab9c99..c0570919f 100644 --- a/app/views/ThreadMessagesView/index.js +++ b/app/views/ThreadMessagesView/index.js @@ -32,9 +32,9 @@ import BackgroundContainer from '../../containers/BackgroundContainer'; import { isIOS } from '../../utils/deviceInfo'; import { getBadgeColor, makeThreadName } from '../../utils/room'; import { getHeaderTitlePosition } from '../../containers/Header'; -import SearchHeader from './SearchHeader'; import EventEmitter from '../../utils/events'; import { LISTENER } from '../../containers/Toast'; +import SearchHeader from '../../containers/SearchHeader'; const API_FETCH_COUNT = 50; @@ -113,7 +113,7 @@ class ThreadMessagesView extends React.Component { /> ), - headerTitle: () => , + headerTitle: () => , headerTitleContainerStyle: { left: headerTitlePosition.left, right: headerTitlePosition.right From f88a6fa40ba3e26709bf2586e417472ff2a8e5d4 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Wed, 15 Sep 2021 09:28:55 -0400 Subject: [PATCH 15/64] Fix lint --- app/views/RoomActionsView/index.js | 64 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 184d21327..1e67eed33 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -930,9 +930,7 @@ class RoomActionsView extends React.Component { canForwardGuest, canReturnQueue } = this.state; - const { - rid, t, prid - } = room; + const { rid, t, prid } = room; const isGroupChat = RocketChat.isGroupChat(room); return ( @@ -990,22 +988,22 @@ class RoomActionsView extends React.Component { this.onPressTouchable({ route: 'InviteUsersView', params: { rid } - })} - testID='room-actions-invite-user' - left={() => } - showActionIndicator - /> - - - ) - : null} + }) + } + testID='room-actions-invite-user' + left={() => } + showActionIndicator + /> + + + ) : null} - {['c', 'p', 'd'].includes(t) && !prid - ? ( - <> - this.onPressTouchable({ + {['c', 'p', 'd'].includes(t) && !prid ? ( + <> + + this.onPressTouchable({ route: 'DiscussionMessagesView', params: { rid, @@ -1016,22 +1014,22 @@ class RoomActionsView extends React.Component { autoTranslateLanguage: room.autoTranslateLanguage, navToRoomInfo: navParam => this.navToRoomInfo(navParam) } - })} - testID='room-actions-discussions' - left={() => } - showActionIndicator - /> - - - ) - : null} + }) + } + testID='room-actions-discussions' + left={() => } + showActionIndicator + /> + + + ) : null} - {['c', 'p', 'd'].includes(t) - ? ( - <> - this.onPressTouchable({ + {['c', 'p', 'd'].includes(t) ? ( + <> + + this.onPressTouchable({ route: 'MessagesView', params: { rid, t, name: 'Files' } }) From 8ccce58ddd9eacd7bf333d88a332aef8b305d441 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Thu, 16 Sep 2021 14:16:02 -0400 Subject: [PATCH 16/64] Minor tweaks --- app/i18n/locales/en.json | 1550 ++++++++--------- app/stacks/InsideStack.js | 7 +- app/stacks/MasterDetailStack/index.js | 36 +- ...sionMessagesView.js => DiscussionsView.js} | 52 +- app/views/RoomActionsView/index.js | 2 +- e2e/tests/room/04-discussion.spec.js | 32 +- ios/Podfile.lock | 33 +- 7 files changed, 862 insertions(+), 850 deletions(-) rename app/views/{DiscussionMessagesView.js => DiscussionsView.js} (85%) diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json index 6ebcaa88e..cdb11b3e9 100644 --- a/app/i18n/locales/en.json +++ b/app/i18n/locales/en.json @@ -1,777 +1,777 @@ { - "1_person_reacted": "1 person reacted", - "1_user": "1 user", - "error-action-not-allowed": "{{action}} is not allowed", - "error-application-not-found": "Application not found", - "error-archived-duplicate-name": "There's an archived channel with name {{room_name}}", - "error-avatar-invalid-url": "Invalid avatar URL: {{url}}", - "error-avatar-url-handling": "Error while handling avatar setting from a URL ({{url}}) for {{username}}", - "error-cant-invite-for-direct-room": "Can't invite user to direct rooms", - "error-could-not-change-email": "Could not change email", - "error-could-not-change-name": "Could not change name", - "error-could-not-change-username": "Could not change username", - "error-could-not-change-status": "Could not change status", - "error-delete-protected-role": "Cannot delete a protected role", - "error-department-not-found": "Department not found", - "error-direct-message-file-upload-not-allowed": "File sharing not allowed in direct messages", - "error-duplicate-channel-name": "A channel with name {{room_name}} exists", - "error-email-domain-blacklisted": "The email domain is blacklisted", - "error-email-send-failed": "Error trying to send email: {{message}}", - "error-save-image": "Error while saving image", - "error-save-video": "Error while saving video", - "error-field-unavailable": "{{field}} is already in use :(", - "error-file-too-large": "File is too large", - "error-importer-not-defined": "The importer was not defined correctly, it is missing the Import class.", - "error-input-is-not-a-valid-field": "{{input}} is not a valid {{field}}", - "error-invalid-actionlink": "Invalid action link", - "error-invalid-arguments": "Invalid arguments", - "error-invalid-asset": "Invalid asset", - "error-invalid-channel": "Invalid channel.", - "error-invalid-channel-start-with-chars": "Invalid channel. Start with @ or #", - "error-invalid-custom-field": "Invalid custom field", - "error-invalid-custom-field-name": "Invalid custom field name. Use only letters, numbers, hyphens and underscores.", - "error-invalid-date": "Invalid date provided.", - "error-invalid-description": "Invalid description", - "error-invalid-domain": "Invalid domain", - "error-invalid-email": "Invalid email {{email}}", - "error-invalid-email-address": "Invalid email address", - "error-invalid-file-height": "Invalid file height", - "error-invalid-file-type": "Invalid file type", - "error-invalid-file-width": "Invalid file width", - "error-invalid-from-address": "You informed an invalid FROM address.", - "error-invalid-integration": "Invalid integration", - "error-invalid-message": "Invalid message", - "error-invalid-method": "Invalid method", - "error-invalid-name": "Invalid name", - "error-invalid-password": "Invalid password", - "error-invalid-redirectUri": "Invalid redirectUri", - "error-invalid-role": "Invalid role", - "error-invalid-room": "Invalid room", - "error-invalid-room-name": "{{room_name}} is not a valid room name", - "error-invalid-room-type": "{{type}} is not a valid room type.", - "error-invalid-settings": "Invalid settings provided", - "error-invalid-subscription": "Invalid subscription", - "error-invalid-token": "Invalid token", - "error-invalid-triggerWords": "Invalid triggerWords", - "error-invalid-urls": "Invalid URLs", - "error-invalid-user": "Invalid user", - "error-invalid-username": "Invalid username", - "error-invalid-webhook-response": "The webhook URL responded with a status other than 200", - "error-message-deleting-blocked": "Message deleting is blocked", - "error-message-editing-blocked": "Message editing is blocked", - "error-message-size-exceeded": "Message size exceeds Message_MaxAllowedSize", - "error-missing-unsubscribe-link": "You must provide the [unsubscribe] link.", - "error-no-owner-channel": "You don't own the channel", - "error-no-tokens-for-this-user": "There are no tokens for this user", - "error-not-allowed": "Not allowed", - "error-not-authorized": "Not authorized", - "error-push-disabled": "Push is disabled", - "error-remove-last-owner": "This is the last owner. Please set a new owner before removing this one.", - "error-role-in-use": "Cannot delete role because it's in use", - "error-role-name-required": "Role name is required", - "error-the-field-is-required": "The field {{field}} is required.", - "error-too-many-requests": "Error, too many requests. Please slow down. You must wait {{seconds}} seconds before trying again.", - "error-user-is-not-activated": "User is not activated", - "error-user-has-no-roles": "User has no roles", - "error-user-limit-exceeded": "The number of users you are trying to invite to #channel_name exceeds the limit set by the administrator", - "error-user-not-in-room": "User is not in this room", - "error-user-registration-custom-field": "error-user-registration-custom-field", - "error-user-registration-disabled": "User registration is disabled", - "error-user-registration-secret": "User registration is only allowed via Secret URL", - "error-you-are-last-owner": "You are the last owner. Please set new owner before leaving the room.", - "error-status-not-allowed": "Invisible status is disabled", - "Actions": "Actions", - "activity": "activity", - "Activity": "Activity", - "Add_Reaction": "Add Reaction", - "Add_Server": "Add Server", - "Add_users": "Add users", - "Admin_Panel": "Admin Panel", - "Agent": "Agent", - "Alert": "Alert", - "alert": "alert", - "alerts": "alerts", - "All_users_in_the_channel_can_write_new_messages": "All users in the channel can write new messages", - "All_users_in_the_team_can_write_new_messages": "All users in the team can write new messages", - "A_meaningful_name_for_the_discussion_room": "A meaningful name for the discussion room", - "All": "All", - "All_Messages": "All Messages", - "Allow_Reactions": "Allow Reactions", - "Alphabetical": "Alphabetical", - "and_more": "and more", - "and": "and", - "announcement": "announcement", - "Announcement": "Announcement", - "Apply_Your_Certificate": "Apply Your Certificate", - "ARCHIVE": "ARCHIVE", - "archive": "archive", - "are_typing": "are typing", - "Are_you_sure_question_mark": "Are you sure?", - "Are_you_sure_you_want_to_leave_the_room": "Are you sure you want to leave the room {{room}}?", - "Audio": "Audio", - "Authenticating": "Authenticating", - "Automatic": "Automatic", - "Auto_Translate": "Auto-Translate", - "Avatar_changed_successfully": "Avatar changed successfully!", - "Avatar_Url": "Avatar URL", - "Away": "Away", - "Back": "Back", - "Black": "Black", - "Block_user": "Block user", - "Browser": "Browser", - "Broadcast_channel_Description": "Only authorized users can write new messages, but the other users will be able to reply", - "Broadcast_Channel": "Broadcast Channel", - "Busy": "Busy", - "By_proceeding_you_are_agreeing": "By proceeding you are agreeing to our", - "Cancel_editing": "Cancel editing", - "Cancel_recording": "Cancel recording", - "Cancel": "Cancel", - "changing_avatar": "changing avatar", - "creating_channel": "creating channel", - "creating_invite": "creating invite", - "Channel_Name": "Channel Name", - "Channels": "Channels", - "Chats": "Chats", - "Call_already_ended": "Call already ended!", - "Clear_cookies_alert": "Do you want to clear all cookies?", - "Clear_cookies_desc": "This action will clear all login cookies, allowing you to login into other accounts.", - "Clear_cookies_yes": "Yes, clear cookies", - "Clear_cookies_no": "No, keep cookies", - "Click_to_join": "Click to Join!", - "Close": "Close", - "Close_emoji_selector": "Close emoji selector", - "Closing_chat": "Closing chat", - "Change_language_loading": "Changing language.", - "Chat_closed_by_agent": "Chat closed by agent", - "Choose": "Choose", - "Choose_from_library": "Choose from library", - "Choose_file": "Choose file", - "Choose_where_you_want_links_be_opened": "Choose where you want links be opened", - "Code": "Code", - "Code_or_password_invalid": "Code or password invalid", - "Collaborative": "Collaborative", - "Confirm": "Confirm", - "Connect": "Connect", - "Connected": "Connected", - "connecting_server": "connecting to server", - "Connecting": "Connecting...", - "Contact_us": "Contact us", - "Contact_your_server_admin": "Contact your server admin.", - "Continue_with": "Continue with", - "Copied_to_clipboard": "Copied to clipboard!", - "Copy": "Copy", - "Conversation": "Conversation", - "Permalink": "Permalink", - "Certificate_password": "Certificate Password", - "Clear_cache": "Clear local server cache", - "Clear_cache_loading": "Clearing cache.", - "Whats_the_password_for_your_certificate": "What's the password for your certificate?", - "Create_account": "Create an account", - "Create_Channel": "Create Channel", - "Create_Direct_Messages": "Create Direct Messages", - "Create_Discussion": "Create Discussion", - "Created_snippet": "created a snippet", - "Create_a_new_workspace": "Create a new workspace", - "Create": "Create", - "Custom_Status": "Custom Status", - "Dark": "Dark", - "Dark_level": "Dark Level", - "Default": "Default", - "Default_browser": "Default browser", - "Delete_Room_Warning": "Deleting a room will delete all messages posted within the room. This cannot be undone.", - "Department": "Department", - "delete": "delete", - "Delete": "Delete", - "DELETE": "DELETE", - "move": "move", - "deleting_room": "deleting room", - "description": "description", - "Description": "Description", - "Desktop_Options": "Desktop Options", - "Desktop_Notifications": "Desktop Notifications", - "Desktop_Alert_info": "These notifications are delivered in desktop", - "Directory": "Directory", - "Direct_Messages": "Direct Messages", - "Disable_notifications": "Disable notifications", - "Discussions": "Discussions", - "Discussion_Desc": "Help keeping an overview about what's going on! By creating a discussion, a sub-channel of the one you selected is created and both are linked.", - "Discussion_name": "Discussion name", - "Done": "Done", - "Dont_Have_An_Account": "Don't you have an account?", - "Do_you_have_an_account": "Do you have an account?", - "Do_you_have_a_certificate": "Do you have a certificate?", - "Do_you_really_want_to_key_this_room_question_mark": "Do you really want to {{key}} this room?", - "E2E_Encryption": "E2E Encryption", - "E2E_How_It_Works_info1": "You can now create encrypted private groups and direct messages. You may also change existing private groups or DMs to encrypted.", - "E2E_How_It_Works_info2": "This is *end to end encryption* so the key to encode/decode your messages and they will not be saved on the server. For that reason *you need to store this password somewhere safe* which you can access later if you may need.", - "E2E_How_It_Works_info3": "If you proceed, it will be auto generated an E2E password.", - "E2E_How_It_Works_info4": "You can also setup a new password for your encryption key any time from any browser you have entered the existing E2E password.", - "edit": "edit", - "edited": "edited", - "Edit": "Edit", - "Edit_Status": "Edit Status", - "Edit_Invite": "Edit Invite", - "End_to_end_encrypted_room": "End to end encrypted room", - "end_to_end_encryption": "end to end encryption", - "Email_Notification_Mode_All": "Every Mention/DM", - "Email_Notification_Mode_Disabled": "Disabled", - "Email_or_password_field_is_empty": "Email or password field is empty", - "Email": "E-mail", - "email": "e-mail", - "Empty_title": "Empty title", - "Enable_Auto_Translate": "Enable Auto-Translate", - "Enable_notifications": "Enable notifications", - "Encrypted": "Encrypted", - "Encrypted_message": "Encrypted message", - "Enter_Your_E2E_Password": "Enter Your E2E Password", - "Enter_Your_Encryption_Password_desc1": "This will allow you to access your encrypted private groups and direct messages.", - "Enter_Your_Encryption_Password_desc2": "You need to enter the password to encode/decode messages every place you use the chat.", - "Encryption_error_title": "Your encryption password seems wrong", - "Encryption_error_desc": "It wasn't possible to decode your encryption key to be imported.", - "Everyone_can_access_this_channel": "Everyone can access this channel", - "Everyone_can_access_this_team": "Everyone can access this team", - "Error_uploading": "Error uploading", - "Expiration_Days": "Expiration (Days)", - "Favorite": "Favorite", - "Favorites": "Favorites", - "Files": "Files", - "File_description": "File description", - "File_name": "File name", - "Finish_recording": "Finish recording", - "Following_thread": "Following thread", - "For_your_security_you_must_enter_your_current_password_to_continue": "For your security, you must enter your current password to continue", - "Forgot_password_If_this_email_is_registered": "If this email is registered, we'll send instructions on how to reset your password. If you do not receive an email shortly, please come back and try again.", - "Forgot_password": "Forgot your password?", - "Forgot_Password": "Forgot Password", - "Forward": "Forward", - "Forward_Chat": "Forward Chat", - "Forward_to_department": "Forward to department", - "Forward_to_user": "Forward to user", - "Full_table": "Click to see full table", - "Generate_New_Link": "Generate New Link", - "Group_by_favorites": "Group favorites", - "Group_by_type": "Group by type", - "Hide": "Hide", - "Has_joined_the_channel": "has joined the channel", - "Has_joined_the_conversation": "has joined the conversation", - "Has_left_the_channel": "has left the channel", - "Hide_System_Messages": "Hide System Messages", - "Hide_type_messages": "Hide \"{{type}}\" messages", - "How_It_Works": "How It Works", - "Message_HideType_uj": "User Join", - "Message_HideType_ul": "User Leave", - "Message_HideType_ru": "User Removed", - "Message_HideType_au": "User Added", - "Message_HideType_mute_unmute": "User Muted / Unmuted", - "Message_HideType_r": "Room Name Changed", - "Message_HideType_ut": "User Joined Conversation", - "Message_HideType_wm": "Welcome", - "Message_HideType_rm": "Message Removed", - "Message_HideType_subscription_role_added": "Was Set Role", - "Message_HideType_subscription_role_removed": "Role No Longer Defined", - "Message_HideType_room_archived": "Room Archived", - "Message_HideType_room_unarchived": "Room Unarchived", - "I_Saved_My_E2E_Password": "I Saved My E2E Password", - "IP": "IP", - "In_app": "In-app", - "In_App_And_Desktop": "In-app and Desktop", - "In_App_and_Desktop_Alert_info": "Displays a banner at the top of the screen when app is open, and displays a notification on desktop", - "Invisible": "Invisible", - "Invite": "Invite", - "is_a_valid_RocketChat_instance": "is a valid Rocket.Chat instance", - "is_not_a_valid_RocketChat_instance": "is not a valid Rocket.Chat instance", - "is_typing": "is typing", - "Invalid_or_expired_invite_token": "Invalid or expired invite token", - "Invalid_server_version": "The server you're trying to connect is using a version that's not supported by the app anymore: {{currentVersion}}.\n\nWe require version {{minVersion}}", - "Invite_Link": "Invite Link", - "Invite_users": "Invite users", - "Join": "Join", - "Join_Code": "Join Code", - "Insert_Join_Code": "Insert Join Code", - "Join_our_open_workspace": "Join our open workspace", - "Join_your_workspace": "Join your workspace", - "Just_invited_people_can_access_this_channel": "Just invited people can access this channel", - "Just_invited_people_can_access_this_team": "Just invited people can access this team", - "Language": "Language", - "last_message": "last message", - "Leave_channel": "Leave channel", - "leaving_room": "leaving room", - "Leave": "Leave", - "leave": "leave", - "Legal": "Legal", - "Light": "Light", - "License": "License", - "Livechat": "Livechat", - "Livechat_edit": "Livechat edit", - "Login": "Login", - "Login_error": "Your credentials were rejected! Please try again.", - "Login_with": "Login with", - "Logging_out": "Logging out.", - "Logout": "Logout", - "Max_number_of_uses": "Max number of uses", - "Max_number_of_users_allowed_is_number": "Max number of users allowed is {{maxUsers}}", - "members": "members", - "Members": "Members", - "Mentioned_Messages": "Mentioned Messages", - "mentioned": "mentioned", - "Mentions": "Mentions", - "Message_accessibility": "Message from {{user}} at {{time}}: {{message}}", - "Message_actions": "Message actions", - "Message_pinned": "Message pinned", - "Message_removed": "Message removed", - "Message_starred": "Message starred", - "Message_unstarred": "Message unstarred", - "message": "message", - "messages": "messages", - "Message": "Message", - "Messages": "Messages", - "Message_Reported": "Message reported", - "Microphone_Permission_Message": "Rocket.Chat needs access to your microphone so you can send audio message.", - "Microphone_Permission": "Microphone Permission", - "Mute": "Mute", - "muted": "muted", - "My_servers": "My servers", - "N_people_reacted": "{{n}} people reacted", - "N_users": "{{n}} users", - "N_channels": "{{n}} channels", - "name": "name", - "Name": "Name", - "Navigation_history": "Navigation history", - "Never": "Never", - "New_Message": "New Message", - "New_Password": "New Password", - "New_Server": "New Server", - "Next": "Next", - "No_files": "No files", - "No_limit": "No limit", - "No_mentioned_messages": "No mentioned messages", - "No_pinned_messages": "No pinned messages", - "No_results_found": "No results found", - "No_starred_messages": "No starred messages", - "No_thread_messages": "No thread messages", - "No_label_provided": "No {{label}} provided.", - "No_Message": "No Message", - "No_messages_yet": "No messages yet", - "No_Reactions": "No Reactions", - "No_Read_Receipts": "No Read Receipts", - "Not_logged": "Not logged", - "Not_RC_Server": "This is not a Rocket.Chat server.\n{{contact}}", - "Nothing": "Nothing", - "Nothing_to_save": "Nothing to save!", - "Notify_active_in_this_room": "Notify active users in this room", - "Notify_all_in_this_room": "Notify all in this room", - "Notifications": "Notifications", - "Notification_Duration": "Notification Duration", - "Notification_Preferences": "Notification Preferences", - "No_available_agents_to_transfer": "No available agents to transfer", - "Offline": "Offline", - "Oops": "Oops!", - "Omnichannel": "Omnichannel", - "Open_Livechats": "Chats in Progress", - "Omnichannel_enable_alert": "You're not available on Omnichannel. Would you like to be available?", - "Onboarding_description": "A workspace is your team or organization’s space to collaborate. Ask the workspace admin for address to join or create one for your team.", - "Onboarding_join_workspace": "Join a workspace", - "Onboarding_subtitle": "Beyond Team Collaboration", - "Onboarding_title": "Welcome to Rocket.Chat", - "Onboarding_join_open_description": "Join our open workspace to chat with the Rocket.Chat team and community.", - "Onboarding_agree_terms": "By continuing, you agree to Rocket.Chat", - "Onboarding_less_options": "Less options", - "Onboarding_more_options": "More options", - "Online": "Online", - "Only_authorized_users_can_write_new_messages": "Only authorized users can write new messages", - "Open_emoji_selector": "Open emoji selector", - "Open_Source_Communication": "Open Source Communication", - "Open_your_authentication_app_and_enter_the_code": "Open your authentication app and enter the code.", - "OR": "OR", - "OS": "OS", - "Overwrites_the_server_configuration_and_use_room_config": "Overwrites the server configuration and use room config", - "Password": "Password", - "Parent_channel_or_group": "Parent channel or group", - "Permalink_copied_to_clipboard": "Permalink copied to clipboard!", - "Phone": "Phone", - "Pin": "Pin", - "Pinned_Messages": "Pinned Messages", - "pinned": "pinned", - "Pinned": "Pinned", - "Please_add_a_comment": "Please add a comment", - "Please_enter_your_password": "Please enter your password", - "Please_wait": "Please wait.", - "Preferences": "Preferences", - "Preferences_saved": "Preferences saved!", - "Privacy_Policy": " Privacy Policy", - "Private_Channel": "Private Channel", - "Private": "Private", - "Processing": "Processing...", - "Profile_saved_successfully": "Profile saved successfully!", - "Profile": "Profile", - "Public_Channel": "Public Channel", - "Public": "Public", - "Push_Notifications": "Push Notifications", - "Push_Notifications_Alert_Info": "These notifications are delivered to you when the app is not open", - "Quote": "Quote", - "Reactions_are_disabled": "Reactions are disabled", - "Reactions_are_enabled": "Reactions are enabled", - "Reactions": "Reactions", - "Read": "Read", - "Read_External_Permission_Message": "Rocket.Chat needs to access photos, media, and files on your device", - "Read_External_Permission": "Read Media Permission", - "Read_Only_Channel": "Read Only Channel", - "Read_Only": "Read Only", - "Read_Receipt": "Read Receipt", - "Receive_Group_Mentions": "Receive Group Mentions", - "Receive_Group_Mentions_Info": "Receive @all and @here mentions", - "Register": "Register", - "Repeat_Password": "Repeat Password", - "Replied_on": "Replied on:", - "replies": "replies", - "reply": "reply", - "Reply": "Reply", - "Report": "Report", - "Receive_Notification": "Receive Notification", - "Receive_notifications_from": "Receive notifications from {{name}}", - "Resend": "Resend", - "Reset_password": "Reset password", - "resetting_password": "resetting password", - "RESET": "RESET", - "Return": "Return", - "Review_app_title": "Are you enjoying this app?", - "Review_app_desc": "Give us 5 stars on {{store}}", - "Review_app_yes": "Sure!", - "Review_app_no": "No", - "Review_app_later": "Maybe later", - "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}}", - "Room_changed_avatar": "Room avatar changed by {{userBy}}", - "Room_changed_description": "Room description changed to: {{description}} by {{userBy}}", - "Room_changed_privacy": "Room type changed to: {{type}} by {{userBy}}", - "Room_changed_topic": "Room topic changed to: {{topic}} by {{userBy}}", - "Room_Files": "Room Files", - "Room_Info_Edit": "Room Info Edit", - "Room_Info": "Room Info", - "Room_Members": "Room Members", - "Room_name_changed": "Room name changed to: {{name}} by {{userBy}}", - "SAVE": "SAVE", - "Save_Changes": "Save Changes", - "Save": "Save", - "Saved": "Saved", - "saving_preferences": "saving preferences", - "saving_profile": "saving profile", - "saving_settings": "saving settings", - "saved_to_gallery": "Saved to gallery", - "Save_Your_E2E_Password": "Save Your E2E Password", - "Save_Your_Encryption_Password": "Save Your Encryption Password", - "Save_Your_Encryption_Password_warning": "This password is not stored anywhere so save it carefully somewhere else.", - "Save_Your_Encryption_Password_info": "Notice that you lose your password, there is no way to recover it and you will lose access to your messages.", - "Search_Messages": "Search Messages", - "Search": "Search", - "Search_by": "Search by", - "Search_global_users": "Search for global users", - "Search_global_users_description": "If you turn-on, you can search for any user from others companies or servers.", - "Seconds": "{{second}} seconds", - "Security_and_privacy": "Security and privacy", - "Select_Avatar": "Select Avatar", - "Select_Server": "Select Server", - "Select_Users": "Select Users", - "Select_a_Channel": "Select a Channel", - "Select_a_Department": "Select a Department", - "Select_an_option": "Select an option", - "Select_a_User": "Select a User", - "Send": "Send", - "Send_audio_message": "Send audio message", - "Send_crash_report": "Send crash report", - "Send_message": "Send message", - "Send_me_the_code_again": "Send me the code again", - "Send_to": "Send to...", - "Sending_to": "Sending to", - "Sent_an_attachment": "Sent an attachment", - "Server": "Server", - "Servers": "Servers", - "Server_version": "Server version: {{version}}", - "Set_username_subtitle": "The username is used to allow others to mention you in messages", - "Set_custom_status": "Set custom status", - "Set_status": "Set status", - "Status_saved_successfully": "Status saved successfully!", - "Settings": "Settings", - "Settings_succesfully_changed": "Settings succesfully changed!", - "Share": "Share", - "Share_Link": "Share Link", - "Share_this_app": "Share this app", - "Show_more": "Show more..", - "Show_Unread_Counter": "Show Unread Counter", - "Show_Unread_Counter_Info": "Unread counter is displayed as a badge on the right of the channel, in the list", - "Sign_in_your_server": "Sign in your server", - "Sign_Up": "Sign Up", - "Some_field_is_invalid_or_empty": "Some field is invalid or empty", - "Sorting_by": "Sorting by {{key}}", - "Sound": "Sound", - "Star_room": "Star room", - "Star": "Star", - "Starred_Messages": "Starred Messages", - "starred": "starred", - "Starred": "Starred", - "Start_of_conversation": "Start of conversation", - "Start_a_Discussion": "Start a Discussion", - "Started_discussion": "Started a discussion:", - "Started_call": "Call started by {{userBy}}", - "Submit": "Submit", - "Table": "Table", - "Tags": "Tags", - "Take_a_photo": "Take a photo", - "Take_a_video": "Take a video", - "Take_it": "Take it!", - "tap_to_change_status": "tap to change status", - "Tap_to_view_servers_list": "Tap to view servers list", - "Terms_of_Service": " Terms of Service ", - "Theme": "Theme", - "The_user_wont_be_able_to_type_in_roomName": "The user won't be able to type in {{roomName}}", - "The_user_will_be_able_to_type_in_roomName": "The user will be able to type in {{roomName}}", - "There_was_an_error_while_action": "There was an error while {{action}}!", - "This_room_is_blocked": "This room is blocked", - "This_room_is_read_only": "This room is read only", - "Thread": "Thread", - "Threads": "Threads", - "Timezone": "Timezone", - "To": "To", - "topic": "topic", - "Topic": "Topic", - "Translate": "Translate", - "Try_again": "Try again", - "Two_Factor_Authentication": "Two-factor Authentication", - "Type_the_channel_name_here": "Type the channel name here", - "unarchive": "unarchive", - "UNARCHIVE": "UNARCHIVE", - "Unblock_user": "Unblock user", - "Unfavorite": "Unfavorite", - "Unfollowed_thread": "Unfollowed thread", - "Unmute": "Unmute", - "unmuted": "unmuted", - "Unpin": "Unpin", - "unread_messages": "unread", - "Unread": "Unread", - "Unread_on_top": "Unread on top", - "Unstar": "Unstar", - "Updating": "Updating...", - "Uploading": "Uploading", - "Upload_file_question_mark": "Upload file?", - "User": "User", - "Users": "Users", - "User_added_by": "User {{userAdded}} added by {{userBy}}", - "User_Info": "User Info", - "User_has_been_key": "User has been {{key}}", - "User_is_no_longer_role_by_": "{{user}} is no longer {{role}} by {{userBy}}", - "User_muted_by": "User {{userMuted}} muted by {{userBy}}", - "User_removed_by": "User {{userRemoved}} removed by {{userBy}}", - "User_sent_an_attachment": "{{user}} sent an attachment", - "User_unmuted_by": "User {{userUnmuted}} unmuted by {{userBy}}", - "User_was_set_role_by_": "{{user}} was set {{role}} by {{userBy}}", - "Username_is_empty": "Username is empty", - "Username": "Username", - "Username_or_email": "Username or email", - "Uses_server_configuration": "Uses server configuration", - "Validating": "Validating", - "Registration_Succeeded": "Registration Succeeded!", - "Verify": "Verify", - "Verify_email_title": "Registration Succeeded!", - "Verify_email_desc": "We have sent you an email to confirm your registration. If you do not receive an email shortly, please come back and try again.", - "Verify_your_email_for_the_code_we_sent": "Verify your email for the code we sent", - "Video_call": "Video call", - "View_Original": "View Original", - "Voice_call": "Voice call", - "Waiting_for_network": "Waiting for network...", - "Websocket_disabled": "Websocket is disabled for this server.\n{{contact}}", - "Welcome": "Welcome", - "What_are_you_doing_right_now": "What are you doing right now?", - "Whats_your_2fa": "What's your 2FA code?", - "Without_Servers": "Without Servers", - "Workspaces": "Workspaces", - "Would_you_like_to_return_the_inquiry": "Would you like to return the inquiry?", - "Write_External_Permission_Message": "Rocket.Chat needs access to your gallery so you can save images.", - "Write_External_Permission": "Gallery Permission", - "Yes": "Yes", - "Yes_action_it": "Yes, {{action}} it!", - "Yesterday": "Yesterday", - "You_are_in_preview_mode": "You are in preview mode", - "You_are_offline": "You are offline", - "You_can_search_using_RegExp_eg": "You can use RegExp. e.g. `/^text$/i`", - "You_colon": "You: ", - "you_were_mentioned": "you were mentioned", - "You_were_removed_from_channel": "You were removed from {{channel}}", - "you": "you", - "You": "You", - "Logged_out_by_server": "You've been logged out by the server. Please log in again.", - "You_need_to_access_at_least_one_RocketChat_server_to_share_something": "You need to access at least one Rocket.Chat server to share something.", - "You_need_to_verifiy_your_email_address_to_get_notications": "You need to verify your email address to get notifications", - "Your_certificate": "Your Certificate", - "Your_invite_link_will_expire_after__usesLeft__uses": "Your invite link will expire after {{usesLeft}} uses.", - "Your_invite_link_will_expire_on__date__or_after__usesLeft__uses": "Your invite link will expire on {{date}} or after {{usesLeft}} uses.", - "Your_invite_link_will_expire_on__date__": "Your invite link will expire on {{date}}.", - "Your_invite_link_will_never_expire": "Your invite link will never expire.", - "Your_workspace": "Your workspace", - "Your_password_is": "Your password is", - "Version_no": "Version: {{version}}", - "You_will_not_be_able_to_recover_this_message": "You will not be able to recover this message!", - "You_will_unset_a_certificate_for_this_server": "You will unset a certificate for this server", - "Change_Language": "Change Language", - "Crash_report_disclaimer": "We never track the content of your chats. The crash report and analytics events only contains relevant information for us in order to identify and fix issues.", - "Type_message": "Type message", - "Room_search": "Rooms search", - "Room_selection": "Room selection 1...9", - "Next_room": "Next room", - "Previous_room": "Previous room", - "New_room": "New room", - "Upload_room": "Upload to room", - "Search_messages": "Search messages", - "Scroll_messages": "Scroll messages", - "Reply_latest": "Reply to latest", - "Reply_in_Thread": "Reply in Thread", - "Server_selection": "Server selection", - "Server_selection_numbers": "Server selection 1...9", - "Add_server": "Add server", - "New_line": "New line", - "You_will_be_logged_out_of_this_application": "You will be logged out of this application.", - "Clear": "Clear", - "This_will_clear_all_your_offline_data": "This will clear all your offline data.", - "This_will_remove_all_data_from_this_server": "This will remove all data from this server.", - "Mark_unread": "Mark Unread", - "Wait_activation_warning": "Before you can login, your account must be manually activated by an administrator.", - "Screen_lock": "Screen lock", - "Local_authentication_biometry_title": "Authenticate", - "Local_authentication_biometry_fallback": "Use passcode", - "Local_authentication_unlock_option": "Unlock with Passcode", - "Local_authentication_change_passcode": "Change Passcode", - "Local_authentication_info": "Note: if you forget the Passcode, you'll need to delete and reinstall the app.", - "Local_authentication_facial_recognition": "facial recognition", - "Local_authentication_fingerprint": "fingerprint", - "Local_authentication_unlock_with_label": "Unlock with {{label}}", - "Local_authentication_auto_lock_60": "After 1 minute", - "Local_authentication_auto_lock_300": "After 5 minutes", - "Local_authentication_auto_lock_900": "After 15 minutes", - "Local_authentication_auto_lock_1800": "After 30 minutes", - "Local_authentication_auto_lock_3600": "After 1 hour", - "Passcode_enter_title": "Enter your passcode", - "Passcode_choose_title": "Choose your new passcode", - "Passcode_choose_confirm_title": "Confirm your new passcode", - "Passcode_choose_error": "Passcodes don't match. Try again.", - "Passcode_choose_force_set": "Passcode required by admin", - "Passcode_app_locked_title": "App locked", - "Passcode_app_locked_subtitle": "Try again in {{timeLeft}} seconds", - "After_seconds_set_by_admin": "After {{seconds}} seconds (set by admin)", - "Dont_activate": "Don't activate now", - "Queued_chats": "Queued chats", - "Queue_is_empty": "Queue is empty", - "Logout_from_other_logged_in_locations": "Logout from other logged in locations", - "You_will_be_logged_out_from_other_locations": "You'll be logged out from other locations.", - "Logged_out_of_other_clients_successfully": "Logged out of other clients successfully", - "Logout_failed": "Logout failed!", - "Log_analytics_events": "Log analytics events", - "E2E_encryption_change_password_title": "Change Encryption Password", - "E2E_encryption_change_password_description": "You can now create encrypted private groups and direct messages. You may also change existing private groups or DMs to encrypted. \nThis is end to end encryption so the key to encode/decode your messages will not be saved on the server. For that reason you need to store your password somewhere safe. You will be required to enter it on other devices you wish to use e2e encryption on.", - "E2E_encryption_change_password_error": "Error while changing E2E key password!", - "E2E_encryption_change_password_success": "E2E key password changed successfully!", - "E2E_encryption_change_password_message": "Make sure you've saved it carefully somewhere else.", - "E2E_encryption_change_password_confirmation": "Yes, change it", - "E2E_encryption_reset_title": "Reset E2E Key", - "E2E_encryption_reset_description": "This option will remove your current E2E key and log you out. \nWhen you login again, Rocket.Chat will generate you a new key and restore your access to any encrypted room that has one or more members online. \nDue to the nature of the E2E encryption, Rocket.Chat will not be able to restore access to any encrypted room that has no member online.", - "E2E_encryption_reset_button": "Reset E2E Key", - "E2E_encryption_reset_error": "Error while resetting E2E key!", - "E2E_encryption_reset_message": "You're going to be logged out.", - "E2E_encryption_reset_confirmation": "Yes, reset it", - "Following": "Following", - "Threads_displaying_all": "Displaying All", - "Threads_displaying_following": "Displaying Following", - "Threads_displaying_unread": "Displaying Unread", - "No_threads": "There are no threads", - "No_threads_following": "You are not following any threads", - "No_threads_unread": "There are no unread threads", - "No_discussions": "There are no discussions", - "Messagebox_Send_to_channel": "Send to channel", - "Leader": "Leader", - "Moderator": "Moderator", - "Owner": "Owner", - "Remove_from_room": "Remove from room", - "Ignore": "Ignore", - "Unignore": "Unignore", - "User_has_been_ignored": "User has been ignored", - "User_has_been_unignored": "User is no longer ignored", - "User_has_been_removed_from_s": "User has been removed from {{s}}", - "User__username__is_now_a_leader_of__room_name_": "User {{username}} is now a leader of {{room_name}}", - "User__username__is_now_a_moderator_of__room_name_": "User {{username}} is now a moderator of {{room_name}}", - "User__username__is_now_a_owner_of__room_name_": "User {{username}} is now a owner of {{room_name}}", - "User__username__removed_from__room_name__leaders": "User {{username}} removed from {{room_name}} leaders", - "User__username__removed_from__room_name__moderators": "User {{username}} removed from {{room_name}} moderators", - "User__username__removed_from__room_name__owners": "User {{username}} removed from {{room_name}} owners", - "The_user_will_be_removed_from_s": "The user will be removed from {{s}}", - "Yes_remove_user": "Yes, remove user!", - "Direct_message": "Direct message", - "Message_Ignored": "Message ignored. Tap to display it.", - "Enter_workspace_URL": "Enter workspace URL", - "Workspace_URL_Example": "Ex. your-company.rocket.chat", - "This_room_encryption_has_been_enabled_by__username_": "This room's encryption has been enabled by {{username}}", - "This_room_encryption_has_been_disabled_by__username_": "This room's encryption has been disabled by {{username}}", - "Teams": "Teams", - "No_team_channels_found": "No channels found", - "Team_not_found": "Team not found", - "Create_Team": "Create Team", - "Team_Name": "Team Name", - "Private_Team": "Private Team", - "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", - "Add_Channel_to_Team": "Add Channel to Team", - "Left_The_Team_Successfully": "Left the team successfully", - "Create_New": "Create New", - "Add_Existing": "Add Existing", - "Add_Existing_Channel": "Add Existing Channel", - "Remove_from_Team": "Remove from Team", - "Auto-join": "Auto-join", - "Remove_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", - "You_are_leaving_the_team": "You are leaving the team '{{team}}'", - "Leave_Team": "Leave Team", - "Select_Team": "Select Team", - "Select_Team_Channels": "Select the Team's channels you would like to leave.", - "Cannot_leave": "Cannot leave", - "Cannot_remove": "Cannot remove", - "Cannot_delete": "Cannot delete", - "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", - "last-owner-can-not-be-removed": "Last owner cannot be removed", - "Remove_User_Teams": "Select channels you want the user to be removed from.", - "Delete_Team": "Delete Team", - "Select_channels_to_delete": "This can't be undone. Once you delete a team, all chat content and configuration will be deleted. \n\nSelect the channels you would like to delete. The ones you decide to keep will be available on your workspace. Notice that public channels will still be public and visible to everyone.", - "You_are_deleting_the_team": "You are deleting this team.", - "Removing_user_from_this_team": "You are removing {{user}} from this team", - "Remove_User_Team_Channels": "Select the channels you want the user to be removed from.", - "Remove_Member": "Remove Member", - "leaving_team": "leaving team", - "removing_team": "removing from team", - "moving_channel_to_team": "moving channel to team", - "deleting_team": "deleting team", - "member-does-not-exist": "Member does not exist", - "Convert": "Convert", - "Convert_to_Team": "Convert to Team", - "Convert_to_Team_Warning": "You are converting this Channel to a Team. All Members will be kept.", - "Move_to_Team": "Move to Team", - "Move_Channel_Paragraph": "Moving a channel inside a team means that this channel will be added in the team’s context, however, all channel’s members, which are not members of the respective team, will still have access to this channel, but will not be added as team’s members. \n\nAll channel’s management will still be made by the owners of this channel.\n\nTeam’s members and even team’s owners, if not a member of this channel, can not have access to the channel’s content. \n\nPlease notice that the Team’s owner will be able remove members from the Channel.", - "Move_to_Team_Warning": "After reading the previous intructions about this behavior, do you still want to move this channel to the selected team?", - "Load_More": "Load More", - "Load_Newer": "Load Newer", - "Load_Older": "Load Older", - "room-name-already-exists": "Room name already exists", - "error-team-creation": "Error team creation", - "unauthorized": "Unauthorized", - "Left_The_Room_Successfully": "Left the room successfully", - "Deleted_The_Team_Successfully": "Team deleted successfully", - "Deleted_The_Room_Successfully": "Room deleted successfully", - "Convert_to_Channel": "Convert to Channel", - "Converting_Team_To_Channel": "Converting Team to Channel", - "Select_Team_Channels_To_Delete": "Select the Team’s Channels you would like to delete, the ones you do not select will be moved to the Workspace. \n\nNotice that public Channels will be public and visible to everyone.", - "You_are_converting_the_team": "You are converting this Team to a Channel", - "creating_discussion": "creating discussion" + "1_person_reacted": "1 person reacted", + "1_user": "1 user", + "error-action-not-allowed": "{{action}} is not allowed", + "error-application-not-found": "Application not found", + "error-archived-duplicate-name": "There's an archived channel with name {{room_name}}", + "error-avatar-invalid-url": "Invalid avatar URL: {{url}}", + "error-avatar-url-handling": "Error while handling avatar setting from a URL ({{url}}) for {{username}}", + "error-cant-invite-for-direct-room": "Can't invite user to direct rooms", + "error-could-not-change-email": "Could not change email", + "error-could-not-change-name": "Could not change name", + "error-could-not-change-username": "Could not change username", + "error-could-not-change-status": "Could not change status", + "error-delete-protected-role": "Cannot delete a protected role", + "error-department-not-found": "Department not found", + "error-direct-message-file-upload-not-allowed": "File sharing not allowed in direct messages", + "error-duplicate-channel-name": "A channel with name {{room_name}} exists", + "error-email-domain-blacklisted": "The email domain is blacklisted", + "error-email-send-failed": "Error trying to send email: {{message}}", + "error-save-image": "Error while saving image", + "error-save-video": "Error while saving video", + "error-field-unavailable": "{{field}} is already in use :(", + "error-file-too-large": "File is too large", + "error-importer-not-defined": "The importer was not defined correctly, it is missing the Import class.", + "error-input-is-not-a-valid-field": "{{input}} is not a valid {{field}}", + "error-invalid-actionlink": "Invalid action link", + "error-invalid-arguments": "Invalid arguments", + "error-invalid-asset": "Invalid asset", + "error-invalid-channel": "Invalid channel.", + "error-invalid-channel-start-with-chars": "Invalid channel. Start with @ or #", + "error-invalid-custom-field": "Invalid custom field", + "error-invalid-custom-field-name": "Invalid custom field name. Use only letters, numbers, hyphens and underscores.", + "error-invalid-date": "Invalid date provided.", + "error-invalid-description": "Invalid description", + "error-invalid-domain": "Invalid domain", + "error-invalid-email": "Invalid email {{email}}", + "error-invalid-email-address": "Invalid email address", + "error-invalid-file-height": "Invalid file height", + "error-invalid-file-type": "Invalid file type", + "error-invalid-file-width": "Invalid file width", + "error-invalid-from-address": "You informed an invalid FROM address.", + "error-invalid-integration": "Invalid integration", + "error-invalid-message": "Invalid message", + "error-invalid-method": "Invalid method", + "error-invalid-name": "Invalid name", + "error-invalid-password": "Invalid password", + "error-invalid-redirectUri": "Invalid redirectUri", + "error-invalid-role": "Invalid role", + "error-invalid-room": "Invalid room", + "error-invalid-room-name": "{{room_name}} is not a valid room name", + "error-invalid-room-type": "{{type}} is not a valid room type.", + "error-invalid-settings": "Invalid settings provided", + "error-invalid-subscription": "Invalid subscription", + "error-invalid-token": "Invalid token", + "error-invalid-triggerWords": "Invalid triggerWords", + "error-invalid-urls": "Invalid URLs", + "error-invalid-user": "Invalid user", + "error-invalid-username": "Invalid username", + "error-invalid-webhook-response": "The webhook URL responded with a status other than 200", + "error-message-deleting-blocked": "Message deleting is blocked", + "error-message-editing-blocked": "Message editing is blocked", + "error-message-size-exceeded": "Message size exceeds Message_MaxAllowedSize", + "error-missing-unsubscribe-link": "You must provide the [unsubscribe] link.", + "error-no-owner-channel": "You don't own the channel", + "error-no-tokens-for-this-user": "There are no tokens for this user", + "error-not-allowed": "Not allowed", + "error-not-authorized": "Not authorized", + "error-push-disabled": "Push is disabled", + "error-remove-last-owner": "This is the last owner. Please set a new owner before removing this one.", + "error-role-in-use": "Cannot delete role because it's in use", + "error-role-name-required": "Role name is required", + "error-the-field-is-required": "The field {{field}} is required.", + "error-too-many-requests": "Error, too many requests. Please slow down. You must wait {{seconds}} seconds before trying again.", + "error-user-is-not-activated": "User is not activated", + "error-user-has-no-roles": "User has no roles", + "error-user-limit-exceeded": "The number of users you are trying to invite to #channel_name exceeds the limit set by the administrator", + "error-user-not-in-room": "User is not in this room", + "error-user-registration-custom-field": "error-user-registration-custom-field", + "error-user-registration-disabled": "User registration is disabled", + "error-user-registration-secret": "User registration is only allowed via Secret URL", + "error-you-are-last-owner": "You are the last owner. Please set new owner before leaving the room.", + "error-status-not-allowed": "Invisible status is disabled", + "Actions": "Actions", + "activity": "activity", + "Activity": "Activity", + "Add_Reaction": "Add Reaction", + "Add_Server": "Add Server", + "Add_users": "Add users", + "Admin_Panel": "Admin Panel", + "Agent": "Agent", + "Alert": "Alert", + "alert": "alert", + "alerts": "alerts", + "All_users_in_the_channel_can_write_new_messages": "All users in the channel can write new messages", + "All_users_in_the_team_can_write_new_messages": "All users in the team can write new messages", + "A_meaningful_name_for_the_discussion_room": "A meaningful name for the discussion room", + "All": "All", + "All_Messages": "All Messages", + "Allow_Reactions": "Allow Reactions", + "Alphabetical": "Alphabetical", + "and_more": "and more", + "and": "and", + "announcement": "announcement", + "Announcement": "Announcement", + "Apply_Your_Certificate": "Apply Your Certificate", + "ARCHIVE": "ARCHIVE", + "archive": "archive", + "are_typing": "are typing", + "Are_you_sure_question_mark": "Are you sure?", + "Are_you_sure_you_want_to_leave_the_room": "Are you sure you want to leave the room {{room}}?", + "Audio": "Audio", + "Authenticating": "Authenticating", + "Automatic": "Automatic", + "Auto_Translate": "Auto-Translate", + "Avatar_changed_successfully": "Avatar changed successfully!", + "Avatar_Url": "Avatar URL", + "Away": "Away", + "Back": "Back", + "Black": "Black", + "Block_user": "Block user", + "Browser": "Browser", + "Broadcast_channel_Description": "Only authorized users can write new messages, but the other users will be able to reply", + "Broadcast_Channel": "Broadcast Channel", + "Busy": "Busy", + "By_proceeding_you_are_agreeing": "By proceeding you are agreeing to our", + "Cancel_editing": "Cancel editing", + "Cancel_recording": "Cancel recording", + "Cancel": "Cancel", + "changing_avatar": "changing avatar", + "creating_channel": "creating channel", + "creating_invite": "creating invite", + "Channel_Name": "Channel Name", + "Channels": "Channels", + "Chats": "Chats", + "Call_already_ended": "Call already ended!", + "Clear_cookies_alert": "Do you want to clear all cookies?", + "Clear_cookies_desc": "This action will clear all login cookies, allowing you to login into other accounts.", + "Clear_cookies_yes": "Yes, clear cookies", + "Clear_cookies_no": "No, keep cookies", + "Click_to_join": "Click to Join!", + "Close": "Close", + "Close_emoji_selector": "Close emoji selector", + "Closing_chat": "Closing chat", + "Change_language_loading": "Changing language.", + "Chat_closed_by_agent": "Chat closed by agent", + "Choose": "Choose", + "Choose_from_library": "Choose from library", + "Choose_file": "Choose file", + "Choose_where_you_want_links_be_opened": "Choose where you want links be opened", + "Code": "Code", + "Code_or_password_invalid": "Code or password invalid", + "Collaborative": "Collaborative", + "Confirm": "Confirm", + "Connect": "Connect", + "Connected": "Connected", + "connecting_server": "connecting to server", + "Connecting": "Connecting...", + "Contact_us": "Contact us", + "Contact_your_server_admin": "Contact your server admin.", + "Continue_with": "Continue with", + "Copied_to_clipboard": "Copied to clipboard!", + "Copy": "Copy", + "Conversation": "Conversation", + "Permalink": "Permalink", + "Certificate_password": "Certificate Password", + "Clear_cache": "Clear local server cache", + "Clear_cache_loading": "Clearing cache.", + "Whats_the_password_for_your_certificate": "What's the password for your certificate?", + "Create_account": "Create an account", + "Create_Channel": "Create Channel", + "Create_Direct_Messages": "Create Direct Messages", + "Create_Discussion": "Create Discussion", + "Created_snippet": "created a snippet", + "Create_a_new_workspace": "Create a new workspace", + "Create": "Create", + "Custom_Status": "Custom Status", + "Dark": "Dark", + "Dark_level": "Dark Level", + "Default": "Default", + "Default_browser": "Default browser", + "Delete_Room_Warning": "Deleting a room will delete all messages posted within the room. This cannot be undone.", + "Department": "Department", + "delete": "delete", + "Delete": "Delete", + "DELETE": "DELETE", + "move": "move", + "deleting_room": "deleting room", + "description": "description", + "Description": "Description", + "Desktop_Options": "Desktop Options", + "Desktop_Notifications": "Desktop Notifications", + "Desktop_Alert_info": "These notifications are delivered in desktop", + "Directory": "Directory", + "Direct_Messages": "Direct Messages", + "Disable_notifications": "Disable notifications", + "Discussions": "Discussions", + "Discussion_Desc": "Help keeping an overview about what's going on! By creating a discussion, a sub-channel of the one you selected is created and both are linked.", + "Discussion_name": "Discussion name", + "Done": "Done", + "Dont_Have_An_Account": "Don't you have an account?", + "Do_you_have_an_account": "Do you have an account?", + "Do_you_have_a_certificate": "Do you have a certificate?", + "Do_you_really_want_to_key_this_room_question_mark": "Do you really want to {{key}} this room?", + "E2E_Encryption": "E2E Encryption", + "E2E_How_It_Works_info1": "You can now create encrypted private groups and direct messages. You may also change existing private groups or DMs to encrypted.", + "E2E_How_It_Works_info2": "This is *end to end encryption* so the key to encode/decode your messages and they will not be saved on the server. For that reason *you need to store this password somewhere safe* which you can access later if you may need.", + "E2E_How_It_Works_info3": "If you proceed, it will be auto generated an E2E password.", + "E2E_How_It_Works_info4": "You can also setup a new password for your encryption key any time from any browser you have entered the existing E2E password.", + "edit": "edit", + "edited": "edited", + "Edit": "Edit", + "Edit_Status": "Edit Status", + "Edit_Invite": "Edit Invite", + "End_to_end_encrypted_room": "End to end encrypted room", + "end_to_end_encryption": "end to end encryption", + "Email_Notification_Mode_All": "Every Mention/DM", + "Email_Notification_Mode_Disabled": "Disabled", + "Email_or_password_field_is_empty": "Email or password field is empty", + "Email": "E-mail", + "email": "e-mail", + "Empty_title": "Empty title", + "Enable_Auto_Translate": "Enable Auto-Translate", + "Enable_notifications": "Enable notifications", + "Encrypted": "Encrypted", + "Encrypted_message": "Encrypted message", + "Enter_Your_E2E_Password": "Enter Your E2E Password", + "Enter_Your_Encryption_Password_desc1": "This will allow you to access your encrypted private groups and direct messages.", + "Enter_Your_Encryption_Password_desc2": "You need to enter the password to encode/decode messages every place you use the chat.", + "Encryption_error_title": "Your encryption password seems wrong", + "Encryption_error_desc": "It wasn't possible to decode your encryption key to be imported.", + "Everyone_can_access_this_channel": "Everyone can access this channel", + "Everyone_can_access_this_team": "Everyone can access this team", + "Error_uploading": "Error uploading", + "Expiration_Days": "Expiration (Days)", + "Favorite": "Favorite", + "Favorites": "Favorites", + "Files": "Files", + "File_description": "File description", + "File_name": "File name", + "Finish_recording": "Finish recording", + "Following_thread": "Following thread", + "For_your_security_you_must_enter_your_current_password_to_continue": "For your security, you must enter your current password to continue", + "Forgot_password_If_this_email_is_registered": "If this email is registered, we'll send instructions on how to reset your password. If you do not receive an email shortly, please come back and try again.", + "Forgot_password": "Forgot your password?", + "Forgot_Password": "Forgot Password", + "Forward": "Forward", + "Forward_Chat": "Forward Chat", + "Forward_to_department": "Forward to department", + "Forward_to_user": "Forward to user", + "Full_table": "Click to see full table", + "Generate_New_Link": "Generate New Link", + "Group_by_favorites": "Group favorites", + "Group_by_type": "Group by type", + "Hide": "Hide", + "Has_joined_the_channel": "has joined the channel", + "Has_joined_the_conversation": "has joined the conversation", + "Has_left_the_channel": "has left the channel", + "Hide_System_Messages": "Hide System Messages", + "Hide_type_messages": "Hide \"{{type}}\" messages", + "How_It_Works": "How It Works", + "Message_HideType_uj": "User Join", + "Message_HideType_ul": "User Leave", + "Message_HideType_ru": "User Removed", + "Message_HideType_au": "User Added", + "Message_HideType_mute_unmute": "User Muted / Unmuted", + "Message_HideType_r": "Room Name Changed", + "Message_HideType_ut": "User Joined Conversation", + "Message_HideType_wm": "Welcome", + "Message_HideType_rm": "Message Removed", + "Message_HideType_subscription_role_added": "Was Set Role", + "Message_HideType_subscription_role_removed": "Role No Longer Defined", + "Message_HideType_room_archived": "Room Archived", + "Message_HideType_room_unarchived": "Room Unarchived", + "I_Saved_My_E2E_Password": "I Saved My E2E Password", + "IP": "IP", + "In_app": "In-app", + "In_App_And_Desktop": "In-app and Desktop", + "In_App_and_Desktop_Alert_info": "Displays a banner at the top of the screen when app is open, and displays a notification on desktop", + "Invisible": "Invisible", + "Invite": "Invite", + "is_a_valid_RocketChat_instance": "is a valid Rocket.Chat instance", + "is_not_a_valid_RocketChat_instance": "is not a valid Rocket.Chat instance", + "is_typing": "is typing", + "Invalid_or_expired_invite_token": "Invalid or expired invite token", + "Invalid_server_version": "The server you're trying to connect is using a version that's not supported by the app anymore: {{currentVersion}}.\n\nWe require version {{minVersion}}", + "Invite_Link": "Invite Link", + "Invite_users": "Invite users", + "Join": "Join", + "Join_Code": "Join Code", + "Insert_Join_Code": "Insert Join Code", + "Join_our_open_workspace": "Join our open workspace", + "Join_your_workspace": "Join your workspace", + "Just_invited_people_can_access_this_channel": "Just invited people can access this channel", + "Just_invited_people_can_access_this_team": "Just invited people can access this team", + "Language": "Language", + "last_message": "last message", + "Leave_channel": "Leave channel", + "leaving_room": "leaving room", + "Leave": "Leave", + "leave": "leave", + "Legal": "Legal", + "Light": "Light", + "License": "License", + "Livechat": "Livechat", + "Livechat_edit": "Livechat edit", + "Login": "Login", + "Login_error": "Your credentials were rejected! Please try again.", + "Login_with": "Login with", + "Logging_out": "Logging out.", + "Logout": "Logout", + "Max_number_of_uses": "Max number of uses", + "Max_number_of_users_allowed_is_number": "Max number of users allowed is {{maxUsers}}", + "members": "members", + "Members": "Members", + "Mentioned_Messages": "Mentioned Messages", + "mentioned": "mentioned", + "Mentions": "Mentions", + "Message_accessibility": "Message from {{user}} at {{time}}: {{message}}", + "Message_actions": "Message actions", + "Message_pinned": "Message pinned", + "Message_removed": "Message removed", + "Message_starred": "Message starred", + "Message_unstarred": "Message unstarred", + "message": "message", + "messages": "messages", + "Message": "Message", + "Messages": "Messages", + "Message_Reported": "Message reported", + "Microphone_Permission_Message": "Rocket.Chat needs access to your microphone so you can send audio message.", + "Microphone_Permission": "Microphone Permission", + "Mute": "Mute", + "muted": "muted", + "My_servers": "My servers", + "N_people_reacted": "{{n}} people reacted", + "N_users": "{{n}} users", + "N_channels": "{{n}} channels", + "name": "name", + "Name": "Name", + "Navigation_history": "Navigation history", + "Never": "Never", + "New_Message": "New Message", + "New_Password": "New Password", + "New_Server": "New Server", + "Next": "Next", + "No_files": "No files", + "No_limit": "No limit", + "No_mentioned_messages": "No mentioned messages", + "No_pinned_messages": "No pinned messages", + "No_results_found": "No results found", + "No_starred_messages": "No starred messages", + "No_thread_messages": "No thread messages", + "No_label_provided": "No {{label}} provided.", + "No_Message": "No Message", + "No_messages_yet": "No messages yet", + "No_Reactions": "No Reactions", + "No_Read_Receipts": "No Read Receipts", + "Not_logged": "Not logged", + "Not_RC_Server": "This is not a Rocket.Chat server.\n{{contact}}", + "Nothing": "Nothing", + "Nothing_to_save": "Nothing to save!", + "Notify_active_in_this_room": "Notify active users in this room", + "Notify_all_in_this_room": "Notify all in this room", + "Notifications": "Notifications", + "Notification_Duration": "Notification Duration", + "Notification_Preferences": "Notification Preferences", + "No_available_agents_to_transfer": "No available agents to transfer", + "Offline": "Offline", + "Oops": "Oops!", + "Omnichannel": "Omnichannel", + "Open_Livechats": "Chats in Progress", + "Omnichannel_enable_alert": "You're not available on Omnichannel. Would you like to be available?", + "Onboarding_description": "A workspace is your team or organization’s space to collaborate. Ask the workspace admin for address to join or create one for your team.", + "Onboarding_join_workspace": "Join a workspace", + "Onboarding_subtitle": "Beyond Team Collaboration", + "Onboarding_title": "Welcome to Rocket.Chat", + "Onboarding_join_open_description": "Join our open workspace to chat with the Rocket.Chat team and community.", + "Onboarding_agree_terms": "By continuing, you agree to Rocket.Chat", + "Onboarding_less_options": "Less options", + "Onboarding_more_options": "More options", + "Online": "Online", + "Only_authorized_users_can_write_new_messages": "Only authorized users can write new messages", + "Open_emoji_selector": "Open emoji selector", + "Open_Source_Communication": "Open Source Communication", + "Open_your_authentication_app_and_enter_the_code": "Open your authentication app and enter the code.", + "OR": "OR", + "OS": "OS", + "Overwrites_the_server_configuration_and_use_room_config": "Overwrites the server configuration and use room config", + "Password": "Password", + "Parent_channel_or_group": "Parent channel or group", + "Permalink_copied_to_clipboard": "Permalink copied to clipboard!", + "Phone": "Phone", + "Pin": "Pin", + "Pinned_Messages": "Pinned Messages", + "pinned": "pinned", + "Pinned": "Pinned", + "Please_add_a_comment": "Please add a comment", + "Please_enter_your_password": "Please enter your password", + "Please_wait": "Please wait.", + "Preferences": "Preferences", + "Preferences_saved": "Preferences saved!", + "Privacy_Policy": " Privacy Policy", + "Private_Channel": "Private Channel", + "Private": "Private", + "Processing": "Processing...", + "Profile_saved_successfully": "Profile saved successfully!", + "Profile": "Profile", + "Public_Channel": "Public Channel", + "Public": "Public", + "Push_Notifications": "Push Notifications", + "Push_Notifications_Alert_Info": "These notifications are delivered to you when the app is not open", + "Quote": "Quote", + "Reactions_are_disabled": "Reactions are disabled", + "Reactions_are_enabled": "Reactions are enabled", + "Reactions": "Reactions", + "Read": "Read", + "Read_External_Permission_Message": "Rocket.Chat needs to access photos, media, and files on your device", + "Read_External_Permission": "Read Media Permission", + "Read_Only_Channel": "Read Only Channel", + "Read_Only": "Read Only", + "Read_Receipt": "Read Receipt", + "Receive_Group_Mentions": "Receive Group Mentions", + "Receive_Group_Mentions_Info": "Receive @all and @here mentions", + "Register": "Register", + "Repeat_Password": "Repeat Password", + "Replied_on": "Replied on:", + "replies": "replies", + "reply": "reply", + "Reply": "Reply", + "Report": "Report", + "Receive_Notification": "Receive Notification", + "Receive_notifications_from": "Receive notifications from {{name}}", + "Resend": "Resend", + "Reset_password": "Reset password", + "resetting_password": "resetting password", + "RESET": "RESET", + "Return": "Return", + "Review_app_title": "Are you enjoying this app?", + "Review_app_desc": "Give us 5 stars on {{store}}", + "Review_app_yes": "Sure!", + "Review_app_no": "No", + "Review_app_later": "Maybe later", + "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}}", + "Room_changed_avatar": "Room avatar changed by {{userBy}}", + "Room_changed_description": "Room description changed to: {{description}} by {{userBy}}", + "Room_changed_privacy": "Room type changed to: {{type}} by {{userBy}}", + "Room_changed_topic": "Room topic changed to: {{topic}} by {{userBy}}", + "Room_Files": "Room Files", + "Room_Info_Edit": "Room Info Edit", + "Room_Info": "Room Info", + "Room_Members": "Room Members", + "Room_name_changed": "Room name changed to: {{name}} by {{userBy}}", + "SAVE": "SAVE", + "Save_Changes": "Save Changes", + "Save": "Save", + "Saved": "Saved", + "saving_preferences": "saving preferences", + "saving_profile": "saving profile", + "saving_settings": "saving settings", + "saved_to_gallery": "Saved to gallery", + "Save_Your_E2E_Password": "Save Your E2E Password", + "Save_Your_Encryption_Password": "Save Your Encryption Password", + "Save_Your_Encryption_Password_warning": "This password is not stored anywhere so save it carefully somewhere else.", + "Save_Your_Encryption_Password_info": "Notice that you lose your password, there is no way to recover it and you will lose access to your messages.", + "Search_Messages": "Search Messages", + "Search": "Search", + "Search_by": "Search by", + "Search_global_users": "Search for global users", + "Search_global_users_description": "If you turn-on, you can search for any user from others companies or servers.", + "Seconds": "{{second}} seconds", + "Security_and_privacy": "Security and privacy", + "Select_Avatar": "Select Avatar", + "Select_Server": "Select Server", + "Select_Users": "Select Users", + "Select_a_Channel": "Select a Channel", + "Select_a_Department": "Select a Department", + "Select_an_option": "Select an option", + "Select_a_User": "Select a User", + "Send": "Send", + "Send_audio_message": "Send audio message", + "Send_crash_report": "Send crash report", + "Send_message": "Send message", + "Send_me_the_code_again": "Send me the code again", + "Send_to": "Send to...", + "Sending_to": "Sending to", + "Sent_an_attachment": "Sent an attachment", + "Server": "Server", + "Servers": "Servers", + "Server_version": "Server version: {{version}}", + "Set_username_subtitle": "The username is used to allow others to mention you in messages", + "Set_custom_status": "Set custom status", + "Set_status": "Set status", + "Status_saved_successfully": "Status saved successfully!", + "Settings": "Settings", + "Settings_succesfully_changed": "Settings succesfully changed!", + "Share": "Share", + "Share_Link": "Share Link", + "Share_this_app": "Share this app", + "Show_more": "Show more..", + "Show_Unread_Counter": "Show Unread Counter", + "Show_Unread_Counter_Info": "Unread counter is displayed as a badge on the right of the channel, in the list", + "Sign_in_your_server": "Sign in your server", + "Sign_Up": "Sign Up", + "Some_field_is_invalid_or_empty": "Some field is invalid or empty", + "Sorting_by": "Sorting by {{key}}", + "Sound": "Sound", + "Star_room": "Star room", + "Star": "Star", + "Starred_Messages": "Starred Messages", + "starred": "starred", + "Starred": "Starred", + "Start_of_conversation": "Start of conversation", + "Start_a_Discussion": "Start a Discussion", + "Started_discussion": "Started a discussion:", + "Started_call": "Call started by {{userBy}}", + "Submit": "Submit", + "Table": "Table", + "Tags": "Tags", + "Take_a_photo": "Take a photo", + "Take_a_video": "Take a video", + "Take_it": "Take it!", + "tap_to_change_status": "tap to change status", + "Tap_to_view_servers_list": "Tap to view servers list", + "Terms_of_Service": " Terms of Service ", + "Theme": "Theme", + "The_user_wont_be_able_to_type_in_roomName": "The user won't be able to type in {{roomName}}", + "The_user_will_be_able_to_type_in_roomName": "The user will be able to type in {{roomName}}", + "There_was_an_error_while_action": "There was an error while {{action}}!", + "This_room_is_blocked": "This room is blocked", + "This_room_is_read_only": "This room is read only", + "Thread": "Thread", + "Threads": "Threads", + "Timezone": "Timezone", + "To": "To", + "topic": "topic", + "Topic": "Topic", + "Translate": "Translate", + "Try_again": "Try again", + "Two_Factor_Authentication": "Two-factor Authentication", + "Type_the_channel_name_here": "Type the channel name here", + "unarchive": "unarchive", + "UNARCHIVE": "UNARCHIVE", + "Unblock_user": "Unblock user", + "Unfavorite": "Unfavorite", + "Unfollowed_thread": "Unfollowed thread", + "Unmute": "Unmute", + "unmuted": "unmuted", + "Unpin": "Unpin", + "unread_messages": "unread", + "Unread": "Unread", + "Unread_on_top": "Unread on top", + "Unstar": "Unstar", + "Updating": "Updating...", + "Uploading": "Uploading", + "Upload_file_question_mark": "Upload file?", + "User": "User", + "Users": "Users", + "User_added_by": "User {{userAdded}} added by {{userBy}}", + "User_Info": "User Info", + "User_has_been_key": "User has been {{key}}", + "User_is_no_longer_role_by_": "{{user}} is no longer {{role}} by {{userBy}}", + "User_muted_by": "User {{userMuted}} muted by {{userBy}}", + "User_removed_by": "User {{userRemoved}} removed by {{userBy}}", + "User_sent_an_attachment": "{{user}} sent an attachment", + "User_unmuted_by": "User {{userUnmuted}} unmuted by {{userBy}}", + "User_was_set_role_by_": "{{user}} was set {{role}} by {{userBy}}", + "Username_is_empty": "Username is empty", + "Username": "Username", + "Username_or_email": "Username or email", + "Uses_server_configuration": "Uses server configuration", + "Validating": "Validating", + "Registration_Succeeded": "Registration Succeeded!", + "Verify": "Verify", + "Verify_email_title": "Registration Succeeded!", + "Verify_email_desc": "We have sent you an email to confirm your registration. If you do not receive an email shortly, please come back and try again.", + "Verify_your_email_for_the_code_we_sent": "Verify your email for the code we sent", + "Video_call": "Video call", + "View_Original": "View Original", + "Voice_call": "Voice call", + "Waiting_for_network": "Waiting for network...", + "Websocket_disabled": "Websocket is disabled for this server.\n{{contact}}", + "Welcome": "Welcome", + "What_are_you_doing_right_now": "What are you doing right now?", + "Whats_your_2fa": "What's your 2FA code?", + "Without_Servers": "Without Servers", + "Workspaces": "Workspaces", + "Would_you_like_to_return_the_inquiry": "Would you like to return the inquiry?", + "Write_External_Permission_Message": "Rocket.Chat needs access to your gallery so you can save images.", + "Write_External_Permission": "Gallery Permission", + "Yes": "Yes", + "Yes_action_it": "Yes, {{action}} it!", + "Yesterday": "Yesterday", + "You_are_in_preview_mode": "You are in preview mode", + "You_are_offline": "You are offline", + "You_can_search_using_RegExp_eg": "You can use RegExp. e.g. `/^text$/i`", + "You_colon": "You: ", + "you_were_mentioned": "you were mentioned", + "You_were_removed_from_channel": "You were removed from {{channel}}", + "you": "you", + "You": "You", + "Logged_out_by_server": "You've been logged out by the server. Please log in again.", + "You_need_to_access_at_least_one_RocketChat_server_to_share_something": "You need to access at least one Rocket.Chat server to share something.", + "You_need_to_verifiy_your_email_address_to_get_notications": "You need to verify your email address to get notifications", + "Your_certificate": "Your Certificate", + "Your_invite_link_will_expire_after__usesLeft__uses": "Your invite link will expire after {{usesLeft}} uses.", + "Your_invite_link_will_expire_on__date__or_after__usesLeft__uses": "Your invite link will expire on {{date}} or after {{usesLeft}} uses.", + "Your_invite_link_will_expire_on__date__": "Your invite link will expire on {{date}}.", + "Your_invite_link_will_never_expire": "Your invite link will never expire.", + "Your_workspace": "Your workspace", + "Your_password_is": "Your password is", + "Version_no": "Version: {{version}}", + "You_will_not_be_able_to_recover_this_message": "You will not be able to recover this message!", + "You_will_unset_a_certificate_for_this_server": "You will unset a certificate for this server", + "Change_Language": "Change Language", + "Crash_report_disclaimer": "We never track the content of your chats. The crash report and analytics events only contains relevant information for us in order to identify and fix issues.", + "Type_message": "Type message", + "Room_search": "Rooms search", + "Room_selection": "Room selection 1...9", + "Next_room": "Next room", + "Previous_room": "Previous room", + "New_room": "New room", + "Upload_room": "Upload to room", + "Search_messages": "Search messages", + "Scroll_messages": "Scroll messages", + "Reply_latest": "Reply to latest", + "Reply_in_Thread": "Reply in Thread", + "Server_selection": "Server selection", + "Server_selection_numbers": "Server selection 1...9", + "Add_server": "Add server", + "New_line": "New line", + "You_will_be_logged_out_of_this_application": "You will be logged out of this application.", + "Clear": "Clear", + "This_will_clear_all_your_offline_data": "This will clear all your offline data.", + "This_will_remove_all_data_from_this_server": "This will remove all data from this server.", + "Mark_unread": "Mark Unread", + "Wait_activation_warning": "Before you can login, your account must be manually activated by an administrator.", + "Screen_lock": "Screen lock", + "Local_authentication_biometry_title": "Authenticate", + "Local_authentication_biometry_fallback": "Use passcode", + "Local_authentication_unlock_option": "Unlock with Passcode", + "Local_authentication_change_passcode": "Change Passcode", + "Local_authentication_info": "Note: if you forget the Passcode, you'll need to delete and reinstall the app.", + "Local_authentication_facial_recognition": "facial recognition", + "Local_authentication_fingerprint": "fingerprint", + "Local_authentication_unlock_with_label": "Unlock with {{label}}", + "Local_authentication_auto_lock_60": "After 1 minute", + "Local_authentication_auto_lock_300": "After 5 minutes", + "Local_authentication_auto_lock_900": "After 15 minutes", + "Local_authentication_auto_lock_1800": "After 30 minutes", + "Local_authentication_auto_lock_3600": "After 1 hour", + "Passcode_enter_title": "Enter your passcode", + "Passcode_choose_title": "Choose your new passcode", + "Passcode_choose_confirm_title": "Confirm your new passcode", + "Passcode_choose_error": "Passcodes don't match. Try again.", + "Passcode_choose_force_set": "Passcode required by admin", + "Passcode_app_locked_title": "App locked", + "Passcode_app_locked_subtitle": "Try again in {{timeLeft}} seconds", + "After_seconds_set_by_admin": "After {{seconds}} seconds (set by admin)", + "Dont_activate": "Don't activate now", + "Queued_chats": "Queued chats", + "Queue_is_empty": "Queue is empty", + "Logout_from_other_logged_in_locations": "Logout from other logged in locations", + "You_will_be_logged_out_from_other_locations": "You'll be logged out from other locations.", + "Logged_out_of_other_clients_successfully": "Logged out of other clients successfully", + "Logout_failed": "Logout failed!", + "Log_analytics_events": "Log analytics events", + "E2E_encryption_change_password_title": "Change Encryption Password", + "E2E_encryption_change_password_description": "You can now create encrypted private groups and direct messages. You may also change existing private groups or DMs to encrypted. \nThis is end to end encryption so the key to encode/decode your messages will not be saved on the server. For that reason you need to store your password somewhere safe. You will be required to enter it on other devices you wish to use e2e encryption on.", + "E2E_encryption_change_password_error": "Error while changing E2E key password!", + "E2E_encryption_change_password_success": "E2E key password changed successfully!", + "E2E_encryption_change_password_message": "Make sure you've saved it carefully somewhere else.", + "E2E_encryption_change_password_confirmation": "Yes, change it", + "E2E_encryption_reset_title": "Reset E2E Key", + "E2E_encryption_reset_description": "This option will remove your current E2E key and log you out. \nWhen you login again, Rocket.Chat will generate you a new key and restore your access to any encrypted room that has one or more members online. \nDue to the nature of the E2E encryption, Rocket.Chat will not be able to restore access to any encrypted room that has no member online.", + "E2E_encryption_reset_button": "Reset E2E Key", + "E2E_encryption_reset_error": "Error while resetting E2E key!", + "E2E_encryption_reset_message": "You're going to be logged out.", + "E2E_encryption_reset_confirmation": "Yes, reset it", + "Following": "Following", + "Threads_displaying_all": "Displaying All", + "Threads_displaying_following": "Displaying Following", + "Threads_displaying_unread": "Displaying Unread", + "No_threads": "There are no threads", + "No_threads_following": "You are not following any threads", + "No_threads_unread": "There are no unread threads", + "No_discussions": "There are no discussions", + "Messagebox_Send_to_channel": "Send to channel", + "Leader": "Leader", + "Moderator": "Moderator", + "Owner": "Owner", + "Remove_from_room": "Remove from room", + "Ignore": "Ignore", + "Unignore": "Unignore", + "User_has_been_ignored": "User has been ignored", + "User_has_been_unignored": "User is no longer ignored", + "User_has_been_removed_from_s": "User has been removed from {{s}}", + "User__username__is_now_a_leader_of__room_name_": "User {{username}} is now a leader of {{room_name}}", + "User__username__is_now_a_moderator_of__room_name_": "User {{username}} is now a moderator of {{room_name}}", + "User__username__is_now_a_owner_of__room_name_": "User {{username}} is now a owner of {{room_name}}", + "User__username__removed_from__room_name__leaders": "User {{username}} removed from {{room_name}} leaders", + "User__username__removed_from__room_name__moderators": "User {{username}} removed from {{room_name}} moderators", + "User__username__removed_from__room_name__owners": "User {{username}} removed from {{room_name}} owners", + "The_user_will_be_removed_from_s": "The user will be removed from {{s}}", + "Yes_remove_user": "Yes, remove user!", + "Direct_message": "Direct message", + "Message_Ignored": "Message ignored. Tap to display it.", + "Enter_workspace_URL": "Enter workspace URL", + "Workspace_URL_Example": "Ex. your-company.rocket.chat", + "This_room_encryption_has_been_enabled_by__username_": "This room's encryption has been enabled by {{username}}", + "This_room_encryption_has_been_disabled_by__username_": "This room's encryption has been disabled by {{username}}", + "Teams": "Teams", + "No_team_channels_found": "No channels found", + "Team_not_found": "Team not found", + "Create_Team": "Create Team", + "Team_Name": "Team Name", + "Private_Team": "Private Team", + "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", + "Add_Channel_to_Team": "Add Channel to Team", + "Left_The_Team_Successfully": "Left the team successfully", + "Create_New": "Create New", + "Add_Existing": "Add Existing", + "Add_Existing_Channel": "Add Existing Channel", + "Remove_from_Team": "Remove from Team", + "Auto-join": "Auto-join", + "Remove_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", + "You_are_leaving_the_team": "You are leaving the team '{{team}}'", + "Leave_Team": "Leave Team", + "Select_Team": "Select Team", + "Select_Team_Channels": "Select the Team's channels you would like to leave.", + "Cannot_leave": "Cannot leave", + "Cannot_remove": "Cannot remove", + "Cannot_delete": "Cannot delete", + "Last_owner_team_room": "You are the last owner of this channel. Once you leave the team, the channel will be kept inside the team but you will be managing it from outside.", + "last-owner-can-not-be-removed": "Last owner cannot be removed", + "Remove_User_Teams": "Select channels you want the user to be removed from.", + "Delete_Team": "Delete Team", + "Select_channels_to_delete": "This can't be undone. Once you delete a team, all chat content and configuration will be deleted. \n\nSelect the channels you would like to delete. The ones you decide to keep will be available on your workspace. Notice that public channels will still be public and visible to everyone.", + "You_are_deleting_the_team": "You are deleting this team.", + "Removing_user_from_this_team": "You are removing {{user}} from this team", + "Remove_User_Team_Channels": "Select the channels you want the user to be removed from.", + "Remove_Member": "Remove Member", + "leaving_team": "leaving team", + "removing_team": "removing from team", + "moving_channel_to_team": "moving channel to team", + "deleting_team": "deleting team", + "member-does-not-exist": "Member does not exist", + "Convert": "Convert", + "Convert_to_Team": "Convert to Team", + "Convert_to_Team_Warning": "You are converting this Channel to a Team. All Members will be kept.", + "Move_to_Team": "Move to Team", + "Move_Channel_Paragraph": "Moving a channel inside a team means that this channel will be added in the team’s context, however, all channel’s members, which are not members of the respective team, will still have access to this channel, but will not be added as team’s members. \n\nAll channel’s management will still be made by the owners of this channel.\n\nTeam’s members and even team’s owners, if not a member of this channel, can not have access to the channel’s content. \n\nPlease notice that the Team’s owner will be able remove members from the Channel.", + "Move_to_Team_Warning": "After reading the previous intructions about this behavior, do you still want to move this channel to the selected team?", + "Load_More": "Load More", + "Load_Newer": "Load Newer", + "Load_Older": "Load Older", + "room-name-already-exists": "Room name already exists", + "error-team-creation": "Error team creation", + "unauthorized": "Unauthorized", + "Left_The_Room_Successfully": "Left the room successfully", + "Deleted_The_Team_Successfully": "Team deleted successfully", + "Deleted_The_Room_Successfully": "Room deleted successfully", + "Convert_to_Channel": "Convert to Channel", + "Converting_Team_To_Channel": "Converting Team to Channel", + "Select_Team_Channels_To_Delete": "Select the Team’s Channels you would like to delete, the ones you do not select will be moved to the Workspace. \n\nNotice that public Channels will be public and visible to everyone.", + "You_are_converting_the_team": "You are converting this Team to a Channel", + "creating_discussion": "creating discussion" } diff --git a/app/stacks/InsideStack.js b/app/stacks/InsideStack.js index fe9f0b8d5..9f11a4db5 100644 --- a/app/stacks/InsideStack.js +++ b/app/stacks/InsideStack.js @@ -70,7 +70,7 @@ import QueueListView from '../ee/omnichannel/views/QueueListView'; import AddChannelTeamView from '../views/AddChannelTeamView'; import AddExistingChannelView from '../views/AddExistingChannelView'; import SelectListView from '../views/SelectListView'; -import DiscussionMessagesView from '../views/DiscussionMessagesView'; +import DiscussionsView from '../views/DiscussionsView'; // ChatsStackNavigator const ChatsStack = createStackNavigator(); @@ -85,10 +85,7 @@ const ChatsStackNavigator = () => { - + { component={ForwardLivechatView} options={ForwardLivechatView.navigationOptions} /> - - - - - - + + + + + + { +const DiscussionsView = ({ navigation, route }) => { const rid = route.params?.rid; const canAutoTranslate = route.params?.canAutoTranslate; const autoTranslate = route.params?.autoTranslate; @@ -42,11 +42,12 @@ const DiscussionMessagesView = ({ navigation, route }) => { const [discussions, setDiscussions] = useState([]); const [search, setSearch] = useState([]); const [isSearching, setIsSearching] = useState(false); + const [total, setTotal] = useState(0); const { theme } = useTheme(); const insets = useSafeAreaInsets(); - const load = async(text = '') => { + const load = async (text = '') => { if (loading) { return; } @@ -63,8 +64,10 @@ const DiscussionMessagesView = ({ navigation, route }) => { if (result.success) { if (isSearching) { setSearch(result.messages); + setTotal(result.total); } else { setDiscussions(result.messages); + setTotal(result.total); } } setLoading(false); @@ -74,7 +77,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { } }; - const onSearchChangeText = debounce(async(text) => { + const onSearchChangeText = debounce(async text => { setIsSearching(true); await load(text); }, 300); @@ -95,10 +98,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { headerTitleAlign: 'left', headerLeft: () => ( - + ), headerTitle: () => ( @@ -119,11 +119,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { const options = { headerLeft: () => ( - navigation.pop()} - tintColor={themes[theme].headerTintColor} - /> + navigation.pop()} tintColor={themes[theme].headerTintColor} /> ), headerTitleAlign: 'center', headerTitle: I18n.t('Discussions'), @@ -154,12 +150,18 @@ const DiscussionMessagesView = ({ navigation, route }) => { navigation.setOptions(options); }, [navigation, isSearching]); - - const onDiscussionPress = debounce((item) => { - navigation.push('RoomView', { - rid: item.drid, prid: item.rid, name: item.msg, t: 'p' - }); - }, 1000, true); + const onDiscussionPress = debounce( + item => { + navigation.push('RoomView', { + rid: item.drid, + prid: item.rid, + name: item.msg, + t: 'p' + }); + }, + 1000, + true + ); const renderItem = ({ item }) => ( { /> ); if (!discussions?.length) { - return ( - <> - - - ); + return ; } return ( @@ -196,7 +194,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { windowSize={10} initialNumToRender={7} removeClippedSubviews={isIOS} - onEndReached={() => discussions.length > API_FETCH_COUNT ?? load()} + onEndReached={() => total > API_FETCH_COUNT ?? load()} ItemSeparatorComponent={List.Separator} ListFooterComponent={loading ? : null} scrollIndicatorInsets={{ right: 1 }} @@ -205,7 +203,7 @@ const DiscussionMessagesView = ({ navigation, route }) => { ); }; -DiscussionMessagesView.propTypes = { +DiscussionsView.propTypes = { navigation: PropTypes.object, route: PropTypes.object, item: PropTypes.shape({ @@ -213,4 +211,4 @@ DiscussionMessagesView.propTypes = { }) }; -export default DiscussionMessagesView; +export default DiscussionsView; diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 1e67eed33..5e6a2215a 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -1004,7 +1004,7 @@ class RoomActionsView extends React.Component { title='Discussions' onPress={() => this.onPressTouchable({ - route: 'DiscussionMessagesView', + route: 'DiscussionsView', params: { rid, t, diff --git a/e2e/tests/room/04-discussion.spec.js b/e2e/tests/room/04-discussion.spec.js index a5e0bd783..51e64ce34 100644 --- a/e2e/tests/room/04-discussion.spec.js +++ b/e2e/tests/room/04-discussion.spec.js @@ -171,24 +171,36 @@ describe('Discussion', () => { }); }); - describe('Open Discussion from DiscussionMessagesView', () => { - const discussionName = `${ data.random }message`; - it('should go back to main room', async() => { + describe('Open Discussion from DiscussionsView', () => { + const discussionName = `${data.random}message`; + it('should go back to main room', async () => { await tapBack(); - await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000); + await waitFor(element(by.id('room-actions-view'))) + .toBeVisible() + .withTimeout(5000); await tapBack(); - await waitFor(element(by.id(`room-view-title-${ discussionName }`))).toExist().withTimeout(5000); + await waitFor(element(by.id(`room-view-title-${discussionName}`))) + .toExist() + .withTimeout(5000); await tapBack(); await navigateToRoom(); }); - it('should navigate to DiscussionMessagesView', async() => { - await waitFor(element(by.id(`room-view-title-${ channel }`))).toExist().withTimeout(5000); - await waitFor(element(by.id('room-header'))).toBeVisible().withTimeout(5000); + it('should navigate to DiscussionsView', async () => { + await waitFor(element(by.id(`room-view-title-${channel}`))) + .toExist() + .withTimeout(5000); + await waitFor(element(by.id('room-header'))) + .toBeVisible() + .withTimeout(5000); await element(by.id('room-header')).tap(); - await waitFor(element(by.id('room-actions-discussions'))).toBeVisible().withTimeout(5000); + await waitFor(element(by.id('room-actions-discussions'))) + .toBeVisible() + .withTimeout(5000); await element(by.id('room-actions-discussions')).tap(); - await waitFor(element(by.id('discussion-messages-view'))).toBeVisible().withTimeout(5000); + await waitFor(element(by.id('discussion-messages-view'))) + .toBeVisible() + .withTimeout(5000); }); }); }); diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 68582e288..24401669a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -541,8 +541,35 @@ PODS: - TOCropViewController - RNLocalize (2.1.1): - React-Core - - RNReanimated (1.9.0): + - RNReanimated (2.2.0): + - DoubleConversion + - FBLazyVector + - FBReactNativeSpec + - glog + - RCT-Folly + - RCTRequired + - RCTTypeSafety - React + - React-callinvoker + - React-Core + - React-Core/DevSupport + - React-Core/RCTWebSocket + - React-CoreModules + - React-cxxreact + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-RCTActionSheet + - React-RCTAnimation + - React-RCTBlob + - React-RCTImage + - React-RCTLinking + - React-RCTNetwork + - React-RCTSettings + - React-RCTText + - React-RCTVibration + - ReactCommon/turbomodule/core + - Yoga - RNRootView (1.0.3): - React - RNScreens (2.9.0): @@ -940,7 +967,7 @@ SPEC CHECKSUMS: EXVideoThumbnails: cd257fc6e07884a704a5674d362a6410933acb68 EXWebBrowser: d37a5ffdea1b65947352bc001dd9f732463725d4 FBLazyVector: e686045572151edef46010a6f819ade377dfeb4b - FBReactNativeSpec: b427d2f482828b9533661dbcf9edf846cb60dc7b + FBReactNativeSpec: 686ac17e193dcf7d5df4d772b224504dd2f3ad81 Firebase: 919186c8e119dd9372a45fd1dd17a8a942bc1892 FirebaseAnalytics: 5fa308e1b13f838d0f6dc74719ac2a72e8c5afc4 FirebaseCore: 8cd4f8ea22075e0ee582849b1cf79d8816506085 @@ -1026,7 +1053,7 @@ SPEC CHECKSUMS: RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211 RNImageCropPicker: 38865ab4af1b0b2146ad66061196bc0184946855 RNLocalize: 82a569022724d35461e2dc5b5d015a13c3ca995b - RNReanimated: b5ccb50650ba06f6e749c7c329a1bc3ae0c88b43 + RNReanimated: 9c13c86454bfd54dab7505c1a054470bfecd2563 RNRootView: 895a4813dedeaca82db2fa868ca1c333d790e494 RNScreens: c526239bbe0e957b988dacc8d75ac94ec9cb19da RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4 From ecee12c9d039fb45faafd4edf5191c7ba1cb0402 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 17 Sep 2021 15:15:26 -0400 Subject: [PATCH 17/64] Migrate to TypeScript, update interfaces and some changes to container components --- app/containers/Avatar/interfaces.ts | 10 +- app/containers/ThreadDetails.tsx | 67 ++++---- app/containers/markdown/index.tsx | 28 ++-- app/lib/rocketchat.js | 10 +- .../index.tsx} | 145 ++++++++++-------- app/views/DiscussionsView/styles.ts | 7 + app/views/ThreadMessagesView/Item.js | 26 ++-- app/views/ThreadMessagesView/index.js | 10 +- 8 files changed, 173 insertions(+), 130 deletions(-) rename app/views/{DiscussionsView.js => DiscussionsView/index.tsx} (57%) create mode 100644 app/views/DiscussionsView/styles.ts diff --git a/app/containers/Avatar/interfaces.ts b/app/containers/Avatar/interfaces.ts index 692c4d0a3..2ff481463 100644 --- a/app/containers/Avatar/interfaces.ts +++ b/app/containers/Avatar/interfaces.ts @@ -1,19 +1,19 @@ export interface IAvatar { - server: string; + server?: string; style: any; text: string; - avatar: string; + avatar?: string; emoji: string; size: number; borderRadius: number; - type: string; - children: JSX.Element; + type?: string; + children?: JSX.Element; user: { id: string; token: string; }; theme: string; - onPress(): void; + onPress?(): void; getCustomEmoji(): any; avatarETag: string; isStatic: boolean; diff --git a/app/containers/ThreadDetails.tsx b/app/containers/ThreadDetails.tsx index 86f670f00..054d7595d 100644 --- a/app/containers/ThreadDetails.tsx +++ b/app/containers/ThreadDetails.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import Touchable from 'react-native-platform-touchable'; @@ -41,8 +42,9 @@ const styles = StyleSheet.create({ interface IThreadDetails { item: { - tcount: number | string; - replies: any; + tcount?: number | string; + dcount?: number | string; + replies?: any; id: string; }; user: { @@ -50,16 +52,25 @@ interface IThreadDetails { }; badgeColor: string; toggleFollowThread: Function; + thread: boolean; style: object; theme: string; } -const ThreadDetails = ({ item, user, badgeColor, toggleFollowThread, style, theme }: IThreadDetails) => { - let { tcount } = item; - if (tcount >= 1000) { - tcount = '+999'; - } else if (tcount >= 100) { - tcount = '+99'; +const ThreadDetails = ({ item, user, badgeColor, toggleFollowThread, thread, style, theme }: IThreadDetails) => { + let { tcount, dcount } = item; + if (thread) { + if (tcount! >= 1000) { + tcount = '+999'; + } else if (tcount! >= 100) { + tcount = '+99'; + } + } + + if (dcount! >= 1000) { + dcount = '+999'; + } else if (dcount! >= 100) { + dcount = '+99'; } let replies = item?.replies?.length ?? 0; @@ -75,30 +86,34 @@ const ThreadDetails = ({ item, user, badgeColor, toggleFollowThread, style, them - + - {tcount} + {thread ? tcount : dcount} - - - - {replies} - - + {thread ? ( + + + + {replies} + + + ) : null} - - {badgeColor ? : null} - toggleFollowThread?.(isFollowing, item.id)}> - - - + {thread ? ( + + {badgeColor ? : null} + toggleFollowThread?.(isFollowing, item.id)}> + + + + ) : null} ); }; diff --git a/app/containers/markdown/index.tsx b/app/containers/markdown/index.tsx index d3ce8453e..0aec122ff 100644 --- a/app/containers/markdown/index.tsx +++ b/app/containers/markdown/index.tsx @@ -23,25 +23,25 @@ import { isValidURL } from '../../utils/url'; interface IMarkdownProps { msg: string; - getCustomEmoji: Function; + getCustomEmoji?: Function; baseUrl: string; username: string; - tmid: string; - isEdited: boolean; - numberOfLines: number; - customEmojis: boolean; - useRealName: boolean; - channels: { + tmid?: string; + isEdited?: boolean; + numberOfLines?: number; + customEmojis?: boolean; + useRealName?: boolean; + channels?: { name: string; _id: number; }[]; - mentions: object[]; - navToRoomInfo: Function; - preview: boolean; - theme: string; - testID: string; - style: any; - onLinkPress: Function; + mentions?: object[]; + navToRoomInfo?: Function; + preview?: boolean; + theme?: string; + testID?: string; + style?: any; + onLinkPress?: Function; } type TLiteral = { diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index b9af9e87d..0604d6d48 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -807,21 +807,17 @@ const RocketChat = { encrypted }); }, - getDiscussions({ - roomId, offset, count, text - }) { + getDiscussions({ roomId, offset, count, text }) { const params = { roomId, offset, count, - text + ...(text && { text }) }; // RC 2.4.0 return this.sdk.get('chat.getDiscussions', params); }, - createTeam({ - name, users, type, readOnly, broadcast, encrypted - }) { + createTeam({ name, users, type, readOnly, broadcast, encrypted }) { const params = { name, users, diff --git a/app/views/DiscussionsView.js b/app/views/DiscussionsView/index.tsx similarity index 57% rename from app/views/DiscussionsView.js rename to app/views/DiscussionsView/index.tsx index e52863793..818816747 100644 --- a/app/views/DiscussionsView.js +++ b/app/views/DiscussionsView/index.tsx @@ -1,48 +1,76 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import React, { useEffect, useState } from 'react'; -import PropTypes from 'prop-types'; import { FlatList } from 'react-native'; import { useSelector } from 'react-redux'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { HeaderBackButton } from '@react-navigation/stack'; -import ActivityIndicator from '../containers/ActivityIndicator'; -import I18n from '../i18n'; -import StatusBar from '../containers/StatusBar'; -import log from '../utils/log'; -import debounce from '../utils/debounce'; -import { themes } from '../constants/colors'; -import SafeAreaView from '../containers/SafeAreaView'; -import * as HeaderButton from '../containers/HeaderButton'; -import * as List from '../containers/List'; -import BackgroundContainer from '../containers/BackgroundContainer'; -import { isIOS } from '../utils/deviceInfo'; -import { getHeaderTitlePosition } from '../containers/Header'; - -import { useTheme } from '../theme'; -import Message from '../containers/message'; -import RocketChat from '../lib/rocketchat'; -import SearchHeader from '../containers/SearchHeader'; +import ActivityIndicator from '../../containers/ActivityIndicator'; +import I18n from '../../i18n'; +import StatusBar from '../../containers/StatusBar'; +import log from '../../utils/log'; +import debounce from '../../utils/debounce'; +import { themes } from '../../constants/colors'; +import SafeAreaView from '../../containers/SafeAreaView'; +import * as HeaderButton from '../../containers/HeaderButton'; +import * as List from '../../containers/List'; +import BackgroundContainer from '../../containers/BackgroundContainer'; +import { isIOS } from '../../utils/deviceInfo'; +import { getHeaderTitlePosition } from '../../containers/Header'; +import { useTheme } from '../../theme'; +import RocketChat from '../../lib/rocketchat'; +import SearchHeader from '../../containers/SearchHeader'; +import Item from '../ThreadMessagesView/Item'; +import styles from './styles'; const API_FETCH_COUNT = 50; -const DiscussionsView = ({ navigation, route }) => { - const rid = route.params?.rid; - const canAutoTranslate = route.params?.canAutoTranslate; - const autoTranslate = route.params?.autoTranslate; - const autoTranslateLanguage = route.params?.autoTranslateLanguage; - const navToRoomInfo = route.params?.navToRoomInfo; +interface IDiscussionsViewProps { + navigation: any; + route: { + params?: { + rid: string; + canAutoTranslate: boolean; + autoTranslate: boolean; + autoTranslateLanguage: string; + navToRoomInfo: Function; + }; + }; + item: { + msg: string; + }; +} - const user = useSelector(state => state.login?.user); - const baseUrl = useSelector(state => state.server.server); - const useRealName = useSelector(state => state.settings.UI_Use_Real_Name); - const Message_TimeFormat = useSelector(state => state.settings.Message_TimeFormat); - const isMasterDetail = useSelector(state => state.app.isMasterDetail); +interface IState { + login?: { + user: object; + }; + server: { + server: string; + }; + settings: { + UI_Use_Real_Name: boolean; + Message_TimeFormat: string; + }; + app: { + isMasterDetail: boolean; + }; +} + +const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): JSX.Element => { + const rid = route.params?.rid; + + const user = useSelector((state: IState) => state.login?.user); + const baseUrl = useSelector((state: IState) => state.server?.server); + const useRealName = useSelector((state: IState) => state.settings?.UI_Use_Real_Name); + const isMasterDetail = useSelector((state: IState) => state.app?.isMasterDetail); const [loading, setLoading] = useState(false); const [discussions, setDiscussions] = useState([]); const [search, setSearch] = useState([]); const [isSearching, setIsSearching] = useState(false); const [total, setTotal] = useState(0); + const [searchTotal, setSearchTotal] = useState(0); const { theme } = useTheme(); const insets = useSafeAreaInsets(); @@ -64,7 +92,7 @@ const DiscussionsView = ({ navigation, route }) => { if (result.success) { if (isSearching) { setSearch(result.messages); - setTotal(result.total); + setSearchTotal(result.total); } else { setDiscussions(result.messages); setTotal(result.total); @@ -77,7 +105,7 @@ const DiscussionsView = ({ navigation, route }) => { } }; - const onSearchChangeText = debounce(async text => { + const onSearchChangeText = debounce(async (text: string) => { setIsSearching(true); await load(text); }, 300); @@ -119,25 +147,24 @@ const DiscussionsView = ({ navigation, route }) => { const options = { headerLeft: () => ( - navigation.pop()} tintColor={themes[theme].headerTintColor} /> + navigation.pop()} tintColor={themes[theme!].headerTintColor} /> ), headerTitleAlign: 'center', headerTitle: I18n.t('Discussions'), headerTitleContainerStyle: { left: null, right: null - } + }, + headerRight: () => ( + + + + ) }; if (isMasterDetail) { options.headerLeft = () => ; } - - options.headerRight = () => ( - - - - ); return options; }; @@ -151,7 +178,7 @@ const DiscussionsView = ({ navigation, route }) => { }, [navigation, isSearching]); const onDiscussionPress = debounce( - item => { + (item: any) => { navigation.push('RoomView', { rid: item.drid, prid: item.rid, @@ -163,20 +190,19 @@ const DiscussionsView = ({ navigation, route }) => { true ); - const renderItem = ({ item }) => ( - ( + ); + if (!discussions?.length) { return ; } @@ -187,14 +213,15 @@ const DiscussionsView = ({ navigation, route }) => { item.msg} - style={{ backgroundColor: themes[theme].backgroundColor }} + keyExtractor={(item: any) => item.msg} + style={{ backgroundColor: themes[theme!].backgroundColor }} + contentContainerStyle={styles.contentContainer} onEndReachedThreshold={0.5} maxToRenderPerBatch={5} windowSize={10} initialNumToRender={7} removeClippedSubviews={isIOS} - onEndReached={() => total > API_FETCH_COUNT ?? load()} + onEndReached={() => (isSearching ? searchTotal > API_FETCH_COUNT ?? load() : total > API_FETCH_COUNT ?? load())} ItemSeparatorComponent={List.Separator} ListFooterComponent={loading ? : null} scrollIndicatorInsets={{ right: 1 }} @@ -203,12 +230,4 @@ const DiscussionsView = ({ navigation, route }) => { ); }; -DiscussionsView.propTypes = { - navigation: PropTypes.object, - route: PropTypes.object, - item: PropTypes.shape({ - msg: PropTypes.string - }) -}; - export default DiscussionsView; diff --git a/app/views/DiscussionsView/styles.ts b/app/views/DiscussionsView/styles.ts new file mode 100644 index 000000000..c6478a8b5 --- /dev/null +++ b/app/views/DiscussionsView/styles.ts @@ -0,0 +1,7 @@ +import { StyleSheet } from 'react-native'; + +export default StyleSheet.create({ + contentContainer: { + marginBottom: 30 + } +}); diff --git a/app/views/ThreadMessagesView/Item.js b/app/views/ThreadMessagesView/Item.js index 1caef2c27..f10abe272 100644 --- a/app/views/ThreadMessagesView/Item.js +++ b/app/views/ThreadMessagesView/Item.js @@ -56,7 +56,7 @@ const styles = StyleSheet.create({ } }); -const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, toggleFollowThread }) => { +const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, toggleFollowThread, thread }) => { const username = (useRealName && item?.u?.name) || item?.u?.username; let time; if (item?.ts) { @@ -66,19 +66,10 @@ const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, to return ( onPress(item)} - testID={`thread-messages-view-${item.msg}`} + testID={thread ? `thread-messages-view-${item.msg}` : `discussions-view-${item.msg}`} style={{ backgroundColor: themes[theme].backgroundColor }}> - + @@ -98,7 +89,13 @@ const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, to /> {badgeColor ? : null} - + @@ -113,7 +110,8 @@ Item.propTypes = { user: PropTypes.object, badgeColor: PropTypes.string, onPress: PropTypes.func, - toggleFollowThread: PropTypes.func + toggleFollowThread: PropTypes.func, + thread: PropTypes.bool }; export default withTheme(Item); diff --git a/app/views/ThreadMessagesView/index.js b/app/views/ThreadMessagesView/index.js index 996058996..5951ba8b9 100644 --- a/app/views/ThreadMessagesView/index.js +++ b/app/views/ThreadMessagesView/index.js @@ -106,7 +106,14 @@ class ThreadMessagesView extends React.Component { ), - headerTitle: () => , + headerTitle: () => ( + + ), headerTitleContainerStyle: { left: headerTitlePosition.left, right: headerTitlePosition.right @@ -417,6 +424,7 @@ class ThreadMessagesView extends React.Component { useRealName, badgeColor }} + thread onPress={this.onThreadPress} toggleFollowThread={this.toggleFollowThread} /> From 6128bc4e5097534f6788ad0b7ce7c7e5b09e8a3c Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 17 Sep 2021 15:22:40 -0400 Subject: [PATCH 18/64] Migrate SearchHeader to TS --- .../{SearchHeader.js => SearchHeader.tsx} | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) rename app/containers/{SearchHeader.js => SearchHeader.tsx} (73%) diff --git a/app/containers/SearchHeader.js b/app/containers/SearchHeader.tsx similarity index 73% rename from app/containers/SearchHeader.js rename to app/containers/SearchHeader.tsx index cb0fb2bee..3f5bf4b93 100644 --- a/app/containers/SearchHeader.js +++ b/app/containers/SearchHeader.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { StyleSheet, View } from 'react-native'; -import PropTypes from 'prop-types'; import { withDimensions } from '../dimensions'; import { isIOS, isTablet } from '../utils/deviceInfo'; @@ -19,9 +18,16 @@ const styles = StyleSheet.create({ } }); -const SearchHeader = ({ - onSearchChangeText, placeholder, theme, testID, width, height -}) => { +interface ISearchHeaderProps { + onSearchChangeText(): void; + placeholder: string; + theme: string; + testID: string; + width: number; + height: number; +} + +const SearchHeader = ({ onSearchChangeText, placeholder, theme, testID, width, height }: ISearchHeaderProps) => { const isLight = theme === 'light'; const isLandscape = width > height; const scale = isIOS && isLandscape && !isTablet ? 0.8 : 1; @@ -41,12 +47,4 @@ const SearchHeader = ({ ); }; -SearchHeader.propTypes = { - onSearchChangeText: PropTypes.func.isRequired, - placeholder: PropTypes.string.isRequired, - theme: PropTypes.string, - testID: PropTypes.string, - width: PropTypes.number, - height: PropTypes.number -}; export default withDimensions(SearchHeader); From 88dbf345ead233ce4e1740433c9c553c49729254 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 17 Sep 2021 15:26:48 -0400 Subject: [PATCH 19/64] Update e2e tests --- app/views/DiscussionsView/index.tsx | 2 +- e2e/tests/room/04-discussion.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/DiscussionsView/index.tsx b/app/views/DiscussionsView/index.tsx index 818816747..96835a421 100644 --- a/app/views/DiscussionsView/index.tsx +++ b/app/views/DiscussionsView/index.tsx @@ -208,7 +208,7 @@ const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): JSX.Elem } return ( - + { .toBeVisible() .withTimeout(5000); await element(by.id('room-actions-discussions')).tap(); - await waitFor(element(by.id('discussion-messages-view'))) + await waitFor(element(by.id('discussions-view'))) .toBeVisible() .withTimeout(5000); }); From 9473bf4024d5f0f5c163dda03460f8e42dd6c91b Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 17 Sep 2021 15:55:06 -0400 Subject: [PATCH 20/64] Minor tweaks --- app/containers/ThreadDetails.tsx | 12 ++++++++++-- app/containers/markdown/index.tsx | 12 ++++++------ app/views/DiscussionsView/index.tsx | 2 ++ app/views/ThreadMessagesView/Item.js | 22 ++++++++++++++++------ 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/app/containers/ThreadDetails.tsx b/app/containers/ThreadDetails.tsx index 054d7595d..76a9f23e1 100644 --- a/app/containers/ThreadDetails.tsx +++ b/app/containers/ThreadDetails.tsx @@ -53,11 +53,12 @@ interface IThreadDetails { badgeColor: string; toggleFollowThread: Function; thread: boolean; + time: string; style: object; theme: string; } -const ThreadDetails = ({ item, user, badgeColor, toggleFollowThread, thread, style, theme }: IThreadDetails) => { +const ThreadDetails = ({ item, user, badgeColor, toggleFollowThread, thread, time, style, theme }: IThreadDetails) => { let { tcount, dcount } = item; if (thread) { if (tcount! >= 1000) { @@ -99,7 +100,14 @@ const ThreadDetails = ({ item, user, badgeColor, toggleFollowThread, thread, sty {replies} - ) : null} + ) : ( + + + + {time} + + + )} {thread ? ( diff --git a/app/containers/markdown/index.tsx b/app/containers/markdown/index.tsx index 0aec122ff..2055e3e12 100644 --- a/app/containers/markdown/index.tsx +++ b/app/containers/markdown/index.tsx @@ -28,20 +28,20 @@ interface IMarkdownProps { username: string; tmid?: string; isEdited?: boolean; - numberOfLines?: number; + numberOfLines: number; customEmojis?: boolean; - useRealName?: boolean; - channels?: { + useRealName: boolean; + channels: { name: string; _id: number; }[]; mentions?: object[]; - navToRoomInfo?: Function; + navToRoomInfo: Function; preview?: boolean; - theme?: string; + theme: string; testID?: string; style?: any; - onLinkPress?: Function; + onLinkPress: Function; } type TLiteral = { diff --git a/app/views/DiscussionsView/index.tsx b/app/views/DiscussionsView/index.tsx index 96835a421..118890c07 100644 --- a/app/views/DiscussionsView/index.tsx +++ b/app/views/DiscussionsView/index.tsx @@ -63,6 +63,7 @@ const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): JSX.Elem const user = useSelector((state: IState) => state.login?.user); const baseUrl = useSelector((state: IState) => state.server?.server); const useRealName = useSelector((state: IState) => state.settings?.UI_Use_Real_Name); + const timeFormat = useSelector((state: IState) => state.settings?.Message_TimeFormat); const isMasterDetail = useSelector((state: IState) => state.app?.isMasterDetail); const [loading, setLoading] = useState(false); @@ -199,6 +200,7 @@ const DiscussionsView = ({ navigation, route }: IDiscussionsViewProps): JSX.Elem baseUrl, useRealName }} + timeFormat={timeFormat} onPress={onDiscussionPress} /> ); diff --git a/app/views/ThreadMessagesView/Item.js b/app/views/ThreadMessagesView/Item.js index f10abe272..b04ec2e31 100644 --- a/app/views/ThreadMessagesView/Item.js +++ b/app/views/ThreadMessagesView/Item.js @@ -2,6 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { StyleSheet, Text, View } from 'react-native'; import Touchable from 'react-native-platform-touchable'; +import moment from 'moment'; import { withTheme } from '../../theme'; import Avatar from '../../containers/Avatar'; @@ -25,6 +26,11 @@ const styles = StyleSheet.create({ marginBottom: 2, alignItems: 'center' }, + discussionTitleContainer: { + flexDirection: 'row', + marginBottom: 2, + justifyContent: 'space-between' + }, title: { flexShrink: 1, fontSize: 18, @@ -56,11 +62,13 @@ const styles = StyleSheet.create({ } }); -const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, toggleFollowThread, thread }) => { +const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, toggleFollowThread, timeFormat, thread }) => { const username = (useRealName && item?.u?.name) || item?.u?.username; - let time; + let date; + let hour; if (item?.ts) { - time = formatDateThreads(item.ts); + date = formatDateThreads(item.ts); + hour = moment(item.ts).format(timeFormat); } return ( @@ -71,11 +79,11 @@ const Item = ({ item, baseUrl, theme, useRealName, user, badgeColor, onPress, to - + {username} - {time} + {thread ? date : hour} Date: Fri, 17 Sep 2021 16:10:57 -0400 Subject: [PATCH 21/64] Fix threads --- app/containers/message/Thread.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/containers/message/Thread.tsx b/app/containers/message/Thread.tsx index 16ed35a4b..23a546f80 100644 --- a/app/containers/message/Thread.tsx +++ b/app/containers/message/Thread.tsx @@ -27,6 +27,7 @@ const Thread = React.memo( tlm, id }} + thread user={user} badgeColor={threadBadgeColor} toggleFollowThread={toggleFollowThread} From cc07128eb1c95cc4e019436b4d0d67674ab5bf7d Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 17 Sep 2021 16:17:50 -0400 Subject: [PATCH 22/64] Remove unused params --- app/views/DiscussionsView/index.tsx | 4 ---- app/views/RoomActionsView/index.js | 8 +------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/app/views/DiscussionsView/index.tsx b/app/views/DiscussionsView/index.tsx index 118890c07..7bdff8477 100644 --- a/app/views/DiscussionsView/index.tsx +++ b/app/views/DiscussionsView/index.tsx @@ -30,10 +30,6 @@ interface IDiscussionsViewProps { route: { params?: { rid: string; - canAutoTranslate: boolean; - autoTranslate: boolean; - autoTranslateLanguage: string; - navToRoomInfo: Function; }; }; item: { diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index 5e6a2215a..c1abcb1ca 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -1006,13 +1006,7 @@ class RoomActionsView extends React.Component { this.onPressTouchable({ route: 'DiscussionsView', params: { - rid, - t, - prid, - canAutoTranslate, - autoTranslate: room.autoTranslate, - autoTranslateLanguage: room.autoTranslateLanguage, - navToRoomInfo: navParam => this.navToRoomInfo(navParam) + rid } }) } From ec665e0bdb404a6c2a36b532bcb951e4cc3c171a Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 17 Sep 2021 16:22:02 -0400 Subject: [PATCH 23/64] Simplify logic --- app/containers/ThreadDetails.tsx | 21 ++++++--------------- app/views/RoomActionsView/index.js | 1 - app/views/RoomView/index.js | 11 +++++++++-- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/app/containers/ThreadDetails.tsx b/app/containers/ThreadDetails.tsx index 76a9f23e1..fd49c2846 100644 --- a/app/containers/ThreadDetails.tsx +++ b/app/containers/ThreadDetails.tsx @@ -93,21 +93,12 @@ const ThreadDetails = ({ item, user, badgeColor, toggleFollowThread, thread, tim - {thread ? ( - - - - {replies} - - - ) : ( - - - - {time} - - - )} + + + + {thread ? replies : time} + + {thread ? ( diff --git a/app/views/RoomActionsView/index.js b/app/views/RoomActionsView/index.js index c1abcb1ca..5d085d850 100644 --- a/app/views/RoomActionsView/index.js +++ b/app/views/RoomActionsView/index.js @@ -74,7 +74,6 @@ class RoomActionsView extends React.Component { const member = props.route.params?.member; this.rid = props.route.params?.rid; this.t = props.route.params?.t; - this.navToRoomInfo = props.route.params?.navToRoomInfo; this.state = { room: room || { rid: this.rid, t: this.t }, membersCount: 0, diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 2aa61e504..2b5ff0bc5 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -439,12 +439,19 @@ class RoomView extends React.Component { navigation.navigate('ModalStackNavigator', { screen: screen ?? 'RoomActionsView', params: { - rid: this.rid, t: this.t, room, member, showCloseModal: !!screen, navToRoomInfo: navParam => this.navToRoomInfo(navParam) + rid: this.rid, + t: this.t, + room, + member, + showCloseModal: !!screen } }); } else { navigation.push('RoomActionsView', { - rid: this.rid, t: this.t, room, member, navToRoomInfo: navParam => this.navToRoomInfo(navParam) + rid: this.rid, + t: this.t, + room, + member }); } }; From 53791098824b99435ba184983203bfcf9d7d1ebf Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 17 Sep 2021 16:25:07 -0400 Subject: [PATCH 24/64] Rollback interfaces changes --- app/containers/Avatar/interfaces.ts | 10 +++++----- app/containers/markdown/index.tsx | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/containers/Avatar/interfaces.ts b/app/containers/Avatar/interfaces.ts index 2ff481463..692c4d0a3 100644 --- a/app/containers/Avatar/interfaces.ts +++ b/app/containers/Avatar/interfaces.ts @@ -1,19 +1,19 @@ export interface IAvatar { - server?: string; + server: string; style: any; text: string; - avatar?: string; + avatar: string; emoji: string; size: number; borderRadius: number; - type?: string; - children?: JSX.Element; + type: string; + children: JSX.Element; user: { id: string; token: string; }; theme: string; - onPress?(): void; + onPress(): void; getCustomEmoji(): any; avatarETag: string; isStatic: boolean; diff --git a/app/containers/markdown/index.tsx b/app/containers/markdown/index.tsx index 2055e3e12..d3ce8453e 100644 --- a/app/containers/markdown/index.tsx +++ b/app/containers/markdown/index.tsx @@ -23,24 +23,24 @@ import { isValidURL } from '../../utils/url'; interface IMarkdownProps { msg: string; - getCustomEmoji?: Function; + getCustomEmoji: Function; baseUrl: string; username: string; - tmid?: string; - isEdited?: boolean; + tmid: string; + isEdited: boolean; numberOfLines: number; - customEmojis?: boolean; + customEmojis: boolean; useRealName: boolean; channels: { name: string; _id: number; }[]; - mentions?: object[]; + mentions: object[]; navToRoomInfo: Function; - preview?: boolean; + preview: boolean; theme: string; - testID?: string; - style?: any; + testID: string; + style: any; onLinkPress: Function; } From df480fb8ae246807e81ff86ad368d8d9032a8851 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 17 Sep 2021 16:26:10 -0400 Subject: [PATCH 25/64] Update property type rule --- app/containers/ThreadDetails.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/containers/ThreadDetails.tsx b/app/containers/ThreadDetails.tsx index fd49c2846..6b000b9a2 100644 --- a/app/containers/ThreadDetails.tsx +++ b/app/containers/ThreadDetails.tsx @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import Touchable from 'react-native-platform-touchable'; @@ -42,8 +41,8 @@ const styles = StyleSheet.create({ interface IThreadDetails { item: { - tcount?: number | string; - dcount?: number | string; + tcount: number | string; + dcount: number | string; replies?: any; id: string; }; @@ -61,16 +60,16 @@ interface IThreadDetails { const ThreadDetails = ({ item, user, badgeColor, toggleFollowThread, thread, time, style, theme }: IThreadDetails) => { let { tcount, dcount } = item; if (thread) { - if (tcount! >= 1000) { + if (tcount >= 1000) { tcount = '+999'; - } else if (tcount! >= 100) { + } else if (tcount >= 100) { tcount = '+99'; } } - if (dcount! >= 1000) { + if (dcount >= 1000) { dcount = '+999'; - } else if (dcount! >= 100) { + } else if (dcount >= 100) { dcount = '+99'; } From d1d35c7a6ec16b2e14a76e0be8975b64d84ca7f4 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Fri, 17 Sep 2021 16:33:22 -0400 Subject: [PATCH 26/64] Minor tweak --- app/containers/ThreadDetails.tsx | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/app/containers/ThreadDetails.tsx b/app/containers/ThreadDetails.tsx index 6b000b9a2..ebda840b2 100644 --- a/app/containers/ThreadDetails.tsx +++ b/app/containers/ThreadDetails.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import Touchable from 'react-native-platform-touchable'; @@ -41,8 +42,8 @@ const styles = StyleSheet.create({ interface IThreadDetails { item: { - tcount: number | string; - dcount: number | string; + tcount?: number | string; + dcount?: number | string; replies?: any; id: string; }; @@ -58,19 +59,13 @@ interface IThreadDetails { } const ThreadDetails = ({ item, user, badgeColor, toggleFollowThread, thread, time, style, theme }: IThreadDetails) => { - let { tcount, dcount } = item; - if (thread) { - if (tcount >= 1000) { - tcount = '+999'; - } else if (tcount >= 100) { - tcount = '+99'; - } - } + const { tcount, dcount } = item; + let count = tcount || dcount; - if (dcount >= 1000) { - dcount = '+999'; - } else if (dcount >= 100) { - dcount = '+99'; + if (count! >= 1000) { + count = '+999'; + } else if (count! >= 100) { + count = '+99'; } let replies = item?.replies?.length ?? 0; @@ -88,7 +83,7 @@ const ThreadDetails = ({ item, user, badgeColor, toggleFollowThread, thread, tim - {thread ? tcount : dcount} + {count} From eedfd4216264d20dae3909cd9102022abdbcc781 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 4 Oct 2021 13:19:01 -0400 Subject: [PATCH 27/64] Minor tweak --- app/containers/SearchHeader.js | 49 --------------------------------- app/containers/SearchHeader.tsx | 2 +- 2 files changed, 1 insertion(+), 50 deletions(-) delete mode 100644 app/containers/SearchHeader.js diff --git a/app/containers/SearchHeader.js b/app/containers/SearchHeader.js deleted file mode 100644 index e231d0748..000000000 --- a/app/containers/SearchHeader.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import { StyleSheet, View } from 'react-native'; -import PropTypes from 'prop-types'; - -import { withTheme } from '../theme'; -import sharedStyles from '../views/Styles'; -import { themes } from '../constants/colors'; -import TextInput from '../presentation/TextInput'; -import { isIOS, isTablet } from '../utils/deviceInfo'; -import { useOrientation } from '../dimensions'; - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - marginLeft: 0 - }, - title: { - ...sharedStyles.textSemibold - } -}); - -// TODO: it might be useful to refactor this component for reusage -const SearchHeader = ({ theme, onSearchChangeText }) => { - const titleColorStyle = { color: themes[theme].headerTitleColor }; - const isLight = theme === 'light'; - const { isLandscape } = useOrientation(); - const scale = isIOS && isLandscape && !isTablet ? 0.8 : 1; - const titleFontSize = 16 * scale; - - return ( - - - - ); -}; - -SearchHeader.propTypes = { - theme: PropTypes.string, - onSearchChangeText: PropTypes.func -}; -export default withTheme(SearchHeader); diff --git a/app/containers/SearchHeader.tsx b/app/containers/SearchHeader.tsx index 3f5bf4b93..e6c535262 100644 --- a/app/containers/SearchHeader.tsx +++ b/app/containers/SearchHeader.tsx @@ -19,7 +19,7 @@ const styles = StyleSheet.create({ }); interface ISearchHeaderProps { - onSearchChangeText(): void; + onSearchChangeText?: (text: string) => void; placeholder: string; theme: string; testID: string; From b48a1896049df8d9c2677a201d1ec53cf2e2b742 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 4 Oct 2021 16:43:45 -0400 Subject: [PATCH 28/64] Update Storyshots.test.js.snap --- .../__snapshots__/Storyshots.test.js.snap | 696 ++---------------- 1 file changed, 72 insertions(+), 624 deletions(-) diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap index 0ad82c0d0..f1600b9e8 100644 --- a/__tests__/__snapshots__/Storyshots.test.js.snap +++ b/__tests__/__snapshots__/Storyshots.test.js.snap @@ -72220,7 +72220,7 @@ exports[`Storyshots Thread Messages.Item badge 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Message content" + testID="discussions-view-Message content" > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 @@ -72585,7 +72539,7 @@ exports[`Storyshots Thread Messages.Item badge 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Message content" + testID="discussions-view-Message content" > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 @@ -72950,7 +72858,7 @@ exports[`Storyshots Thread Messages.Item badge 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Message content" + testID="discussions-view-Message content" > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 @@ -73302,7 +73164,7 @@ exports[`Storyshots Thread Messages.Item badge 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + testID="discussions-view-Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 @@ -73687,7 +73503,7 @@ exports[`Storyshots Thread Messages.Item content 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Message content" + testID="discussions-view-Message content" > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 @@ -74036,7 +73806,7 @@ exports[`Storyshots Thread Messages.Item content 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + testID="discussions-view-Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 @@ -74385,7 +74109,7 @@ exports[`Storyshots Thread Messages.Item content 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Message content" + testID="discussions-view-Message content" > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - +999 - - - - - - -  + November 10, 2020 @@ -74734,7 +74412,7 @@ exports[`Storyshots Thread Messages.Item content 1`] = ` "opacity": 1, } } - testID="thread-messages-view-" + testID="discussions-view-" > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 @@ -75083,7 +74715,7 @@ exports[`Storyshots Thread Messages.Item content 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Message content" + testID="discussions-view-Message content" > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 @@ -75452,7 +75038,7 @@ exports[`Storyshots Thread Messages.Item themes 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Message content" + testID="discussions-view-Message content" > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 @@ -75804,7 +75344,7 @@ exports[`Storyshots Thread Messages.Item themes 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Message content" + testID="discussions-view-Message content" > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 @@ -76156,7 +75650,7 @@ exports[`Storyshots Thread Messages.Item themes 1`] = ` "opacity": 1, } } - testID="thread-messages-view-Message content" + testID="discussions-view-Message content" > - November 10, 2020 + 2020-11-10T10:00:00-04:00 -  +  -  +  - 1 - - - - - - -  + November 10, 2020 From 89a2381a1e45ebf44b344130f0e2d7fca19c7075 Mon Sep 17 00:00:00 2001 From: Gerzon Z Date: Mon, 4 Oct 2021 18:03:28 -0400 Subject: [PATCH 29/64] test commit --- app/containers/message/Attachments.tsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/containers/message/Attachments.tsx b/app/containers/message/Attachments.tsx index 8ca931836..22b517d94 100644 --- a/app/containers/message/Attachments.tsx +++ b/app/containers/message/Attachments.tsx @@ -36,20 +36,16 @@ const Attachments = React.memo( return attachments.map((file: any, index: number) => { if (file.image_url) { - return ( - - ); + return ; } if (file.audio_url) { - return