diff --git a/app/actions/views/channel.js b/app/actions/views/channel.js index 08a3a73be..282449d78 100644 --- a/app/actions/views/channel.js +++ b/app/actions/views/channel.js @@ -46,15 +46,21 @@ export function loadChannelsByTeamName(teamName, errorHandler) { return async (dispatch, getState) => { const state = getState(); const {currentTeamId} = state.entities.teams; - const team = getTeamByName(state, teamName); - if (!team && errorHandler) { - errorHandler(); + if (teamName) { + const team = getTeamByName(state, teamName); + + if (!team && errorHandler) { + errorHandler(); + return {error: true}; + } + + if (team && team.id !== currentTeamId) { + await dispatch(fetchMyChannelsAndMembers(team.id)); + } } - if (team && team.id !== currentTeamId) { - await dispatch(fetchMyChannelsAndMembers(team.id)); - } + return {data: true}; }; } diff --git a/app/actions/views/permalink.ts b/app/actions/views/permalink.ts new file mode 100644 index 000000000..159638c4b --- /dev/null +++ b/app/actions/views/permalink.ts @@ -0,0 +1,51 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {intlShape} from 'react-intl'; +import {Keyboard} from 'react-native'; + +import {showModalOverCurrentContext} from '@actions/navigation'; +import {loadChannelsByTeamName} from '@actions/views/channel'; +import {selectFocusedPostId} from '@mm-redux/actions/posts'; +import type {DispatchFunc} from '@mm-redux/types/actions'; +import {permalinkBadTeam} from '@utils/general'; +import {changeOpacity} from '@utils/theme'; + +export let showingPermalink = false; + +export function showPermalink(intl: typeof intlShape, teamName: string, postId: string, openAsPermalink = true) { + return async (dispatch: DispatchFunc) => { + const loadTeam = await dispatch(loadChannelsByTeamName(teamName, permalinkBadTeam.bind(null, intl))); + + if (!loadTeam.error) { + Keyboard.dismiss(); + dispatch(selectFocusedPostId(postId)); + + if (!showingPermalink) { + const screen = 'Permalink'; + const passProps = { + isPermalink: openAsPermalink, + onClose: () => { + dispatch(closePermalink()); + }, + }; + + const options = { + layout: { + componentBackgroundColor: changeOpacity('#000', 0.2), + }, + }; + + showingPermalink = true; + showModalOverCurrentContext(screen, passProps, options); + } + } + }; +} + +export function closePermalink() { + return async (dispatch: DispatchFunc) => { + showingPermalink = false; + return dispatch(selectFocusedPostId('')); + }; +} \ No newline at end of file diff --git a/app/components/post_body/system_message_helpers.js b/app/components/post_body/system_message_helpers.js index 12f0e6cb9..2018ac5aa 100644 --- a/app/components/post_body/system_message_helpers.js +++ b/app/components/post_body/system_message_helpers.js @@ -16,7 +16,7 @@ const renderUsername = (value = '') => { }; const renderMessage = (postBodyProps, styles, intl, localeHolder, values, skipMarkdown = false) => { - const {onPress} = postBodyProps; + const {onPress, onPermalinkPress} = postBodyProps; const {messageStyle, textStyles} = styles; if (skipMarkdown) { @@ -32,6 +32,7 @@ const renderMessage = (postBodyProps, styles, intl, localeHolder, values, skipMa baseTextStyle={messageStyle} disableAtChannelMentionHighlight={true} onPostPress={onPress} + onPermalinkPress={onPermalinkPress} textStyles={textStyles} value={intl.formatMessage(localeHolder, values)} /> diff --git a/app/components/post_list/index.js b/app/components/post_list/index.js index 38b604ee3..535602439 100644 --- a/app/components/post_list/index.js +++ b/app/components/post_list/index.js @@ -4,12 +4,12 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {selectFocusedPostId} from '@mm-redux/actions/posts'; +import {closePermalink, showPermalink} from '@actions/views/permalink'; import {getConfig, getCurrentUrl} from '@mm-redux/selectors/entities/general'; import {getTheme} from '@mm-redux/selectors/entities/preferences'; import {makePreparePostIdsForPostList, START_OF_NEW_MESSAGES} from '@mm-redux/utils/post_list'; -import {handleSelectChannelByName, loadChannelsByTeamName, refreshChannelWithRetry} from 'app/actions/views/channel'; +import {handleSelectChannelByName, refreshChannelWithRetry} from 'app/actions/views/channel'; import {setDeepLinkURL} from 'app/actions/views/root'; import PostList from './post_list'; @@ -37,11 +37,11 @@ function makeMapStateToProps() { function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ + closePermalink, handleSelectChannelByName, - loadChannelsByTeamName, refreshChannelWithRetry, - selectFocusedPostId, setDeepLinkURL, + showPermalink, }, dispatch), }; } diff --git a/app/components/post_list/post_list.js b/app/components/post_list/post_list.js index 89c0ffe97..eec8c8561 100644 --- a/app/components/post_list/post_list.js +++ b/app/components/post_list/post_list.js @@ -15,10 +15,8 @@ import Post from 'app/components/post'; import {DeepLinkTypes, ListTypes, NavigationTypes} from '@constants'; import mattermostManaged from 'app/mattermost_managed'; import {makeExtraData} from 'app/utils/list_view'; -import {changeOpacity} from 'app/utils/theme'; import {matchDeepLink} from 'app/utils/url'; import telemetry from 'app/telemetry'; -import {showModalOverCurrentContext} from 'app/actions/navigation'; import {alertErrorWithFallback} from 'app/utils/general'; import {t} from 'app/utils/i18n'; @@ -42,11 +40,11 @@ const SCROLL_POSITION_CONFIG = { export default class PostList extends PureComponent { static propTypes = { actions: PropTypes.shape({ + closePermalink: PropTypes.func.isRequired, handleSelectChannelByName: PropTypes.func.isRequired, - loadChannelsByTeamName: PropTypes.func.isRequired, refreshChannelWithRetry: PropTypes.func.isRequired, - selectFocusedPostId: PropTypes.func.isRequired, setDeepLinkURL: PropTypes.func.isRequired, + showPermalink: PropTypes.func.isRequired, }).isRequired, channelId: PropTypes.string, deepLinkURL: PropTypes.string, @@ -60,7 +58,6 @@ export default class PostList extends PureComponent { loadMorePostsVisible: PropTypes.bool, onLoadMoreUp: PropTypes.func, onHashtagPress: PropTypes.func, - onPermalinkPress: PropTypes.func, onPostPress: PropTypes.func, onRefresh: PropTypes.func, postIds: PropTypes.array.isRequired, @@ -171,10 +168,8 @@ export default class PostList extends PureComponent { }; handleClosePermalink = () => { - const {actions} = this.props; - actions.selectFocusedPostId(''); - this.showingPermalink = false; - }; + this.props.actions.closePermalink(); + } handleContentSizeChange = (contentWidth, contentHeight, forceLoad) => { this.contentHeight = contentHeight; @@ -220,14 +215,9 @@ export default class PostList extends PureComponent { handlePermalinkPress = (postId, teamName) => { telemetry.start(['post_list:permalink']); - const {actions, onPermalinkPress} = this.props; + const {showPermalink} = this.props.actions; - if (onPermalinkPress) { - onPermalinkPress(postId, true); - } else { - actions.loadChannelsByTeamName(teamName, this.permalinkBadTeam); - this.showPermalinkView(postId); - } + showPermalink(this.context.intl, teamName, postId); }; handleRefresh = () => { @@ -286,16 +276,6 @@ export default class PostList extends PureComponent { }); }; - permalinkBadTeam = () => { - const {intl} = this.context; - const message = { - id: t('mobile.server_link.unreachable_team.error'), - defaultMessage: 'This link belongs to a deleted team or to a team to which you do not have access.', - }; - - alertErrorWithFallback(intl, {}, message); - }; - permalinkBadChannel = () => { const {intl} = this.context; const message = { @@ -452,29 +432,6 @@ export default class PostList extends PureComponent { } }; - showPermalinkView = (postId, error = '') => { - const {actions} = this.props; - - actions.selectFocusedPostId(postId); - - if (!this.showingPermalink) { - const screen = 'Permalink'; - const passProps = { - isPermalink: true, - onClose: this.handleClosePermalink, - error, - }; - const options = { - layout: { - componentBackgroundColor: changeOpacity('#000', 0.2), - }, - }; - - this.showingPermalink = true; - showModalOverCurrentContext(screen, passProps, options); - } - }; - registerViewableItemsListener = (listener) => { this.onViewableItemsChangedListener = listener; const removeListener = () => { diff --git a/app/components/post_list/post_list.test.js b/app/components/post_list/post_list.test.js index aafd200b4..5aec29c99 100644 --- a/app/components/post_list/post_list.test.js +++ b/app/components/post_list/post_list.test.js @@ -7,7 +7,6 @@ import {shallow} from 'enzyme'; import Preferences from '@mm-redux/constants/preferences'; import EventEmitter from '@mm-redux/utils/event_emitter'; -import * as NavigationActions from 'app/actions/navigation'; import {NavigationTypes} from '@constants'; import PostList from './post_list'; @@ -20,10 +19,10 @@ describe('PostList', () => { const baseProps = { actions: { + closePermalink: jest.fn(), handleSelectChannelByName: jest.fn(), - loadChannelsByTeamName: jest.fn(), refreshChannelWithRetry: jest.fn(), - selectFocusedPostId: jest.fn(), + showPermalink: jest.fn(), setDeepLinkURL: jest.fn(), }, channelId: 'channel-id', @@ -49,15 +48,13 @@ describe('PostList', () => { }); test('setting permalink deep link', () => { - const showModalOverCurrentContext = jest.spyOn(NavigationActions, 'showModalOverCurrentContext'); const wrapper = shallow( , ); wrapper.setProps({deepLinkURL: deepLinks.permalink}); expect(baseProps.actions.setDeepLinkURL).toHaveBeenCalled(); - expect(baseProps.actions.selectFocusedPostId).toHaveBeenCalled(); - expect(showModalOverCurrentContext).toHaveBeenCalled(); + expect(baseProps.actions.showPermalink).toHaveBeenCalled(); expect(wrapper.getElement()).toMatchSnapshot(); }); diff --git a/app/screens/channel_info/channel_info.js b/app/screens/channel_info/channel_info.js index 78a3e1d1e..02ca8ced9 100644 --- a/app/screens/channel_info/channel_info.js +++ b/app/screens/channel_info/channel_info.js @@ -10,8 +10,10 @@ import { } from 'react-native'; import {Navigation} from 'react-native-navigation'; -import {dismissModal, showModalOverCurrentContext} from '@actions/navigation'; +import {dismissModal} from '@actions/navigation'; import StatusBar from '@components/status_bar'; +import {alertErrorWithFallback} from '@utils/general'; +import {t} from '@utils/i18n'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; import AddMembers from './add_members'; @@ -32,10 +34,9 @@ export default class ChannelInfo extends PureComponent { static propTypes = { actions: PropTypes.shape({ getChannelStats: PropTypes.func.isRequired, - loadChannelsByTeamName: PropTypes.func.isRequired, getCustomEmojisInText: PropTypes.func.isRequired, - selectFocusedPostId: PropTypes.func.isRequired, setChannelDisplayName: PropTypes.func.isRequired, + showPermalink: PropTypes.func.isRequired, }), currentChannel: PropTypes.object.isRequired, currentChannelCreatorName: PropTypes.string, @@ -80,34 +81,18 @@ export default class ChannelInfo extends PureComponent { dismissModal(); }; - handleClosePermalink = () => { - const {actions} = this.props; - actions.selectFocusedPostId(''); - this.showingPermalink = false; - }; - handlePermalinkPress = (postId, teamName) => { - this.props.actions.loadChannelsByTeamName(teamName); - this.showPermalinkView(postId); + this.props.actions.showPermalink(this.context.intl, teamName, postId); }; - showPermalinkView = (postId) => { - const {actions} = this.props; - const screen = 'Permalink'; - const passProps = { - isPermalink: true, - onClose: this.handleClosePermalink, - }; - const options = { - layout: { - backgroundColor: changeOpacity('#000', 0.2), - }, + permalinkBadTeam = () => { + const {intl} = this.context; + const message = { + id: t('mobile.server_link.unreachable_team.error'), + defaultMessage: 'This link belongs to a deleted team or to a team to which you do not have access.', }; - actions.selectFocusedPostId(postId); - - this.showingPermalink = true; - showModalOverCurrentContext(screen, passProps, options); + alertErrorWithFallback(intl, {}, message); }; actionsRows = (channelIsArchived) => { diff --git a/app/screens/channel_info/channel_info.test.js b/app/screens/channel_info/channel_info.test.js index 16ccb4cbd..64ff9ec36 100644 --- a/app/screens/channel_info/channel_info.test.js +++ b/app/screens/channel_info/channel_info.test.js @@ -52,9 +52,8 @@ describe('channelInfo', () => { isLandscape: false, actions: { getChannelStats: jest.fn(), - loadChannelsByTeamName: jest.fn(), getCustomEmojisInText: jest.fn(), - selectFocusedPostId: jest.fn(), + showPermalink: jest.fn(), setChannelDisplayName: jest.fn(), }, }; diff --git a/app/screens/channel_info/index.js b/app/screens/channel_info/index.js index f28252b2f..d409ba915 100644 --- a/app/screens/channel_info/index.js +++ b/app/screens/channel_info/index.js @@ -4,10 +4,10 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {loadChannelsByTeamName, setChannelDisplayName} from '@actions/views/channel'; +import {setChannelDisplayName} from '@actions/views/channel'; +import {showPermalink} from '@actions/views/permalink'; import {getChannelStats} from '@mm-redux/actions/channels'; import {getCustomEmojisInText} from '@mm-redux/actions/emojis'; -import {selectFocusedPostId} from '@mm-redux/actions/posts'; import {General} from '@mm-redux/constants'; import {getTeammateNameDisplaySetting, getTheme} from '@mm-redux/selectors/entities/preferences'; import {getCurrentChannel, getCurrentChannelStats} from '@mm-redux/selectors/entities/channels'; @@ -69,10 +69,9 @@ function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ getChannelStats, - loadChannelsByTeamName, getCustomEmojisInText, - selectFocusedPostId, setChannelDisplayName, + showPermalink, }, dispatch), }; } diff --git a/app/screens/flagged_posts/flagged_posts.js b/app/screens/flagged_posts/flagged_posts.js index 129e833ce..905bdff52 100644 --- a/app/screens/flagged_posts/flagged_posts.js +++ b/app/screens/flagged_posts/flagged_posts.js @@ -12,34 +12,26 @@ import { } from 'react-native'; import {Navigation} from 'react-native-navigation'; +import {dismissModal, goToScreen, showSearchModal} from '@actions/navigation'; +import ChannelLoader from '@components/channel_loader'; +import DateHeader from '@components/post_list/date_header'; +import FailedNetworkAction from '@components/failed_network_action'; +import NoResults from '@components/no_results'; +import PostSeparator from '@components/post_separator'; +import StatusBar from '@components/status_bar'; import {isDateLine, getDateForDateLine} from '@mm-redux/utils/post_list'; - -import ChannelLoader from 'app/components/channel_loader'; -import DateHeader from 'app/components/post_list/date_header'; -import FailedNetworkAction from 'app/components/failed_network_action'; -import NoResults from 'app/components/no_results'; -import PostSeparator from 'app/components/post_separator'; -import StatusBar from 'app/components/status_bar'; +import SearchResultPost from '@screens/search/search_result_post'; +import ChannelDisplayName from '@screens/search/channel_display_name'; import mattermostManaged from 'app/mattermost_managed'; -import SearchResultPost from 'app/screens/search/search_result_post'; -import ChannelDisplayName from 'app/screens/search/channel_display_name'; -import {changeOpacity} from 'app/utils/theme'; -import { - goToScreen, - showModalOverCurrentContext, - showSearchModal, - dismissModal, -} from 'app/actions/navigation'; export default class FlaggedPosts extends PureComponent { static propTypes = { actions: PropTypes.shape({ clearSearch: PropTypes.func.isRequired, - loadChannelsByTeamName: PropTypes.func.isRequired, getPostThread: PropTypes.func.isRequired, getFlaggedPosts: PropTypes.func.isRequired, - selectFocusedPostId: PropTypes.func.isRequired, selectPost: PropTypes.func.isRequired, + showPermalink: PropTypes.func.isRequired, }).isRequired, postIds: PropTypes.array, theme: PropTypes.object.isRequired, @@ -108,15 +100,8 @@ export default class FlaggedPosts extends PureComponent { goToScreen(screen, title, passProps); }; - handleClosePermalink = () => { - const {actions} = this.props; - actions.selectFocusedPostId(''); - this.showingPermalink = false; - }; - handlePermalinkPress = (postId, teamName) => { - this.props.actions.loadChannelsByTeamName(teamName); - this.showPermalinkView(postId, true); + this.props.actions.showPermalink(this.context.intl, teamName, postId); }; handleHashtagPress = async (hashtag) => { @@ -187,28 +172,6 @@ export default class FlaggedPosts extends PureComponent { ); }; - showPermalinkView = (postId, isPermalink) => { - const {actions} = this.props; - - actions.selectFocusedPostId(postId); - - if (!this.showingPermalink) { - const screen = 'Permalink'; - const passProps = { - isPermalink, - onClose: this.handleClosePermalink, - }; - const options = { - layout: { - backgroundColor: changeOpacity('#000', 0.2), - }, - }; - - this.showingPermalink = true; - showModalOverCurrentContext(screen, passProps, options); - } - }; - retry = () => { this.getFlaggedPosts(); }; diff --git a/app/screens/flagged_posts/flagged_posts.test.js b/app/screens/flagged_posts/flagged_posts.test.js index 275d0b612..ddcb6952a 100644 --- a/app/screens/flagged_posts/flagged_posts.test.js +++ b/app/screens/flagged_posts/flagged_posts.test.js @@ -14,10 +14,9 @@ describe('FlaggedPosts', () => { const baseProps = { actions: { clearSearch: jest.fn(), - loadChannelsByTeamName: jest.fn(), getPostThread: jest.fn(), getFlaggedPosts: jest.fn(), - selectFocusedPostId: jest.fn(), + showPermalink: jest.fn(), selectPost: jest.fn(), }, theme: Preferences.THEMES.default, diff --git a/app/screens/flagged_posts/index.js b/app/screens/flagged_posts/index.js index fce9448ee..9f4eb060e 100644 --- a/app/screens/flagged_posts/index.js +++ b/app/screens/flagged_posts/index.js @@ -4,9 +4,9 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {loadChannelsByTeamName} from '@actions/views/channel'; +import {showPermalink} from '@actions/views/permalink'; import {getPostThread} from '@actions/views/post'; -import {selectFocusedPostId, selectPost} from '@mm-redux/actions/posts'; +import {selectPost} from '@mm-redux/actions/posts'; import {clearSearch, getFlaggedPosts} from '@mm-redux/actions/search'; import {getTheme} from '@mm-redux/selectors/entities/preferences'; import {makePreparePostIdsForSearchPosts} from '@selectors/post_list'; @@ -29,11 +29,10 @@ function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ clearSearch, - loadChannelsByTeamName, getPostThread, getFlaggedPosts, - selectFocusedPostId, selectPost, + showPermalink, }, dispatch), }; } diff --git a/app/screens/permalink/permalink.js b/app/screens/permalink/permalink.js index 7071bb2ea..7ebbca941 100644 --- a/app/screens/permalink/permalink.js +++ b/app/screens/permalink/permalink.js @@ -170,10 +170,6 @@ export default class Permalink extends PureComponent { // Do nothing because we're already in a modal }; - handlePermalinkPress = () => { - // Do nothing because we're already in permalink view for a different post - }; - handlePress = () => { if (this.viewRef) { this.viewRef.growOut().then(() => { @@ -322,7 +318,6 @@ export default class Permalink extends PureComponent { shouldRenderReplyButton={false} renderReplies={true} onHashtagPress={this.handleHashtagPress} - onPermalinkPress={this.handlePermalinkPress} onPostPress={this.goToThread} postIds={postIds} lastPostIndex={Platform.OS === 'android' ? getLastPostIndex(postIds || []) : -1} diff --git a/app/screens/pinned_posts/index.js b/app/screens/pinned_posts/index.js index b3f792504..8b9c9f0b7 100644 --- a/app/screens/pinned_posts/index.js +++ b/app/screens/pinned_posts/index.js @@ -4,9 +4,9 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {loadChannelsByTeamName} from '@actions/views/channel'; +import {showPermalink} from '@actions/views/permalink'; import {getPostThread} from '@actions/views/post'; -import {selectFocusedPostId, selectPost} from '@mm-redux/actions/posts'; +import {selectPost} from '@mm-redux/actions/posts'; import {clearSearch, getPinnedPosts} from '@mm-redux/actions/search'; import {getTheme} from '@mm-redux/selectors/entities/preferences'; import {makePreparePostIdsForSearchPosts} from '@selectors/post_list'; @@ -31,11 +31,10 @@ function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ clearSearch, - loadChannelsByTeamName, getPostThread, getPinnedPosts, - selectFocusedPostId, selectPost, + showPermalink, }, dispatch), }; } diff --git a/app/screens/pinned_posts/pinned_posts.js b/app/screens/pinned_posts/pinned_posts.js index ee624b135..42b9c0619 100644 --- a/app/screens/pinned_posts/pinned_posts.js +++ b/app/screens/pinned_posts/pinned_posts.js @@ -12,12 +12,7 @@ import { } from 'react-native'; import {Navigation} from 'react-native-navigation'; -import { - goToScreen, - showModalOverCurrentContext, - showSearchModal, - dismissModal, -} from '@actions/navigation'; +import {dismissModal, goToScreen, showSearchModal} from '@actions/navigation'; import ChannelLoader from '@components/channel_loader'; import DateHeader from '@components/post_list/date_header'; import FailedNetworkAction from '@components/failed_network_action'; @@ -26,7 +21,6 @@ import PostSeparator from '@components/post_separator'; import StatusBar from '@components/status_bar'; import {isDateLine, getDateForDateLine} from '@mm-redux/utils/post_list'; import SearchResultPost from '@screens/search/search_result_post'; -import {changeOpacity} from '@utils/theme'; import mattermostManaged from 'app/mattermost_managed'; @@ -34,11 +28,10 @@ export default class PinnedPosts extends PureComponent { static propTypes = { actions: PropTypes.shape({ clearSearch: PropTypes.func.isRequired, - loadChannelsByTeamName: PropTypes.func.isRequired, getPostThread: PropTypes.func.isRequired, getPinnedPosts: PropTypes.func.isRequired, - selectFocusedPostId: PropTypes.func.isRequired, selectPost: PropTypes.func.isRequired, + showPermalink: PropTypes.func.isRequired, }).isRequired, currentChannelId: PropTypes.string.isRequired, postIds: PropTypes.array, @@ -108,15 +101,8 @@ export default class PinnedPosts extends PureComponent { goToScreen(screen, title, passProps); }; - handleClosePermalink = () => { - const {actions} = this.props; - actions.selectFocusedPostId(''); - this.showingPermalink = false; - }; - handlePermalinkPress = (postId, teamName) => { - this.props.actions.loadChannelsByTeamName(teamName); - this.showPermalinkView(postId, true); + this.props.actions.showPermalink(this.context.intl, teamName, postId); }; handleHashtagPress = async (hashtag) => { @@ -127,9 +113,7 @@ export default class PinnedPosts extends PureComponent { keyExtractor = (item) => item; previewPost = (post) => { - Keyboard.dismiss(); - - this.showPermalinkView(post.id, false); + this.props.actions.showPermalink(this.context.intl, '', post.id, false); }; renderEmpty = () => { @@ -185,28 +169,6 @@ export default class PinnedPosts extends PureComponent { ); }; - showPermalinkView = (postId, isPermalink) => { - const {actions} = this.props; - - actions.selectFocusedPostId(postId); - - if (!this.showingPermalink) { - const screen = 'Permalink'; - const passProps = { - isPermalink, - onClose: this.handleClosePermalink, - }; - const options = { - layout: { - backgroundColor: changeOpacity('#000', 0.2), - }, - }; - - this.showingPermalink = true; - showModalOverCurrentContext(screen, passProps, options); - } - }; - retry = () => { this.getPinnedPosts(); }; diff --git a/app/screens/pinned_posts/pinned_posts.test.js b/app/screens/pinned_posts/pinned_posts.test.js index 834f574c3..de017c997 100644 --- a/app/screens/pinned_posts/pinned_posts.test.js +++ b/app/screens/pinned_posts/pinned_posts.test.js @@ -13,10 +13,9 @@ describe('PinnedPosts', () => { const baseProps = { actions: { clearSearch: jest.fn(), - loadChannelsByTeamName: jest.fn(), getPostThread: jest.fn(), getPinnedPosts: jest.fn(), - selectFocusedPostId: jest.fn(), + showPermalink: jest.fn(), selectPost: jest.fn(), }, theme: Preferences.THEMES.default, diff --git a/app/screens/recent_mentions/index.js b/app/screens/recent_mentions/index.js index ceb011abd..949ecdeb4 100644 --- a/app/screens/recent_mentions/index.js +++ b/app/screens/recent_mentions/index.js @@ -4,9 +4,9 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {loadChannelsByTeamName} from '@actions/views/channel'; +import {showPermalink} from '@actions/views/permalink'; import {getPostThread} from '@actions/views/post'; -import {selectFocusedPostId, selectPost} from '@mm-redux/actions/posts'; +import {selectPost} from '@mm-redux/actions/posts'; import {clearSearch, getRecentMentions} from '@mm-redux/actions/search'; import {getTheme} from '@mm-redux/selectors/entities/preferences'; import {makePreparePostIdsForSearchPosts} from '@selectors/post_list'; @@ -29,11 +29,10 @@ function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ clearSearch, - loadChannelsByTeamName, getPostThread, getRecentMentions, - selectFocusedPostId, selectPost, + showPermalink, }, dispatch), }; } diff --git a/app/screens/recent_mentions/recent_mentions.js b/app/screens/recent_mentions/recent_mentions.js index 8f33b2eda..554441dbf 100644 --- a/app/screens/recent_mentions/recent_mentions.js +++ b/app/screens/recent_mentions/recent_mentions.js @@ -12,34 +12,26 @@ import { } from 'react-native'; import {Navigation} from 'react-native-navigation'; +import {dismissModal, goToScreen, showSearchModal} from '@actions/navigation'; +import ChannelLoader from '@components/channel_loader'; +import DateHeader from '@components/post_list/date_header'; +import FailedNetworkAction from '@components/failed_network_action'; +import NoResults from '@components/no_results'; +import PostSeparator from '@components/post_separator'; +import StatusBar from '@components/status_bar'; import {isDateLine, getDateForDateLine} from '@mm-redux/utils/post_list'; - -import ChannelLoader from 'app/components/channel_loader'; -import DateHeader from 'app/components/post_list/date_header'; -import FailedNetworkAction from 'app/components/failed_network_action'; -import NoResults from 'app/components/no_results'; -import PostSeparator from 'app/components/post_separator'; -import StatusBar from 'app/components/status_bar'; +import SearchResultPost from '@screens/search/search_result_post'; +import ChannelDisplayName from '@screens/search/channel_display_name'; import mattermostManaged from 'app/mattermost_managed'; -import SearchResultPost from 'app/screens/search/search_result_post'; -import ChannelDisplayName from 'app/screens/search/channel_display_name'; -import {changeOpacity} from 'app/utils/theme'; -import { - goToScreen, - showModalOverCurrentContext, - showSearchModal, - dismissModal, -} from 'app/actions/navigation'; export default class RecentMentions extends PureComponent { static propTypes = { actions: PropTypes.shape({ clearSearch: PropTypes.func.isRequired, - loadChannelsByTeamName: PropTypes.func.isRequired, getPostThread: PropTypes.func.isRequired, getRecentMentions: PropTypes.func.isRequired, - selectFocusedPostId: PropTypes.func.isRequired, selectPost: PropTypes.func.isRequired, + showPermalink: PropTypes.func.isRequired, }).isRequired, postIds: PropTypes.array, theme: PropTypes.object.isRequired, @@ -102,15 +94,8 @@ export default class RecentMentions extends PureComponent { goToScreen(screen, title, passProps); }; - handleClosePermalink = () => { - const {actions} = this.props; - actions.selectFocusedPostId(''); - this.showingPermalink = false; - }; - handlePermalinkPress = (postId, teamName) => { - this.props.actions.loadChannelsByTeamName(teamName); - this.showPermalinkView(postId, true); + this.props.actions.showPermalink(this.context.intl, teamName, postId); }; handleHashtagPress = async (hashtag) => { @@ -127,9 +112,7 @@ export default class RecentMentions extends PureComponent { } previewPost = (post) => { - Keyboard.dismiss(); - - this.showPermalinkView(post.id, false); + this.props.actions.showPermalink(this.context.intl, '', post.id, false); }; renderEmpty = () => { @@ -185,28 +168,6 @@ export default class RecentMentions extends PureComponent { ); }; - showPermalinkView = (postId, isPermalink) => { - const {actions} = this.props; - - actions.selectFocusedPostId(postId); - - if (!this.showingPermalink) { - const screen = 'Permalink'; - const passProps = { - isPermalink, - onClose: this.handleClosePermalink, - }; - const options = { - layout: { - backgroundColor: changeOpacity('#000', 0.2), - }, - }; - - this.showingPermalink = true; - showModalOverCurrentContext(screen, passProps, options); - } - }; - retry = () => { this.getRecentMentions(); }; diff --git a/app/screens/recent_mentions/recent_mentions.test.js b/app/screens/recent_mentions/recent_mentions.test.js index 04a472275..3a7e86486 100644 --- a/app/screens/recent_mentions/recent_mentions.test.js +++ b/app/screens/recent_mentions/recent_mentions.test.js @@ -14,10 +14,9 @@ describe('RecentMentions', () => { const baseProps = { actions: { clearSearch: jest.fn(), - loadChannelsByTeamName: jest.fn(), getPostThread: jest.fn(), getRecentMentions: jest.fn(), - selectFocusedPostId: jest.fn(), + showPermalink: jest.fn(), selectPost: jest.fn(), }, theme: Preferences.THEMES.default, diff --git a/app/screens/search/index.js b/app/screens/search/index.js index a2f38035f..ad2412336 100644 --- a/app/screens/search/index.js +++ b/app/screens/search/index.js @@ -4,10 +4,10 @@ import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; -import {loadChannelsByTeamName} from '@actions/views/channel'; +import {closePermalink, showPermalink} from '@actions/views/permalink'; import {getPostThread} from '@actions/views/post'; import {handleSearchDraftChanged} from '@actions/views/search'; -import {selectFocusedPostId, selectPost} from '@mm-redux/actions/posts'; +import {selectPost} from '@mm-redux/actions/posts'; import {clearSearch, removeSearchTerms, searchPostsWithParams, getMorePostsForSearch} from '@mm-redux/actions/search'; import {getCurrentChannelId, filterPostIds} from '@mm-redux/selectors/entities/channels'; import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams'; @@ -74,14 +74,14 @@ function mapDispatchToProps(dispatch) { return { actions: bindActionCreators({ clearSearch, + closePermalink, handleSearchDraftChanged, - loadChannelsByTeamName, getPostThread, removeSearchTerms, - selectFocusedPostId, searchPostsWithParams, getMorePostsForSearch, selectPost, + showPermalink, }, dispatch), }; } diff --git a/app/screens/search/search.js b/app/screens/search/search.js index d5bdb8690..d7d84700b 100644 --- a/app/screens/search/search.js +++ b/app/screens/search/search.js @@ -17,7 +17,8 @@ import { import {Navigation} from 'react-native-navigation'; import HWKeyboardEvent from 'react-native-hw-keyboard-event'; -import {goToScreen, showModalOverCurrentContext, dismissModal} from '@actions/navigation'; +import {goToScreen, dismissModal} from '@actions/navigation'; +import {showingPermalink} from '@actions/views/permalink'; import Autocomplete from '@components/autocomplete'; import CompassIcon from '@components/compass_icon'; import KeyboardLayout from '@components/layout/keyboard_layout'; @@ -58,14 +59,14 @@ export default class Search extends PureComponent { static propTypes = { actions: PropTypes.shape({ clearSearch: PropTypes.func.isRequired, + closePermalink: PropTypes.func.isRequired, handleSearchDraftChanged: PropTypes.func.isRequired, - loadChannelsByTeamName: PropTypes.func.isRequired, getPostThread: PropTypes.func.isRequired, removeSearchTerms: PropTypes.func.isRequired, searchPostsWithParams: PropTypes.func.isRequired, getMorePostsForSearch: PropTypes.func.isRequired, - selectFocusedPostId: PropTypes.func.isRequired, selectPost: PropTypes.func.isRequired, + showPermalink: PropTypes.func.isRequired, }).isRequired, currentTeamId: PropTypes.string.isRequired, initialValue: PropTypes.string, @@ -235,9 +236,9 @@ export default class Search extends PureComponent { }; handleHashtagPress = (hashtag) => { - if (this.showingPermalink) { + if (showingPermalink) { dismissModal(); - this.handleClosePermalink(); + this.props.actions.closePermalink(); } const terms = '#' + hashtag; @@ -248,20 +249,13 @@ export default class Search extends PureComponent { Keyboard.dismiss(); }; - handleClosePermalink = () => { - const {actions} = this.props; - actions.selectFocusedPostId(''); - this.showingPermalink = false; - }; - handleLayout = (event) => { const {height} = event.nativeEvent.layout; this.setState({searchListHeight: height}); }; handlePermalinkPress = (postId, teamName) => { - this.props.actions.loadChannelsByTeamName(teamName); - this.showPermalinkView(postId, true); + this.props.actions.showPermalink(this.context.intl, teamName, postId); }; handleScroll = (event) => { @@ -337,9 +331,7 @@ export default class Search extends PureComponent { }, 100); previewPost = (post) => { - Keyboard.dismiss(); - - this.showPermalinkView(post.id, false); + this.props.actions.showPermalink(this.context.intl, '', post.id, false); }; removeSearchTerms = preventDoubleTap((item) => { @@ -477,28 +469,6 @@ export default class Search extends PureComponent { this.search(this.state.value.trim()); }; - showPermalinkView = (postId, isPermalink) => { - const {actions} = this.props; - - actions.selectFocusedPostId(postId); - - if (!this.showingPermalink) { - const screen = 'Permalink'; - const passProps = { - isPermalink, - onClose: this.handleClosePermalink, - }; - const options = { - layout: { - backgroundColor: changeOpacity('#000', 0.2), - }, - }; - - this.showingPermalink = true; - showModalOverCurrentContext(screen, passProps, options); - } - }; - scrollToTop = () => { if (this.listRef?._wrapperListRef) { this.listRef._wrapperListRef.getListRef().scrollToOffset({ diff --git a/app/utils/general.js b/app/utils/general.js index cb8f6fd6e..4e708cff5 100644 --- a/app/utils/general.js +++ b/app/utils/general.js @@ -4,6 +4,7 @@ import {Alert, Platform} from 'react-native'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; +import {t} from '@utils/i18n'; import {Posts} from '@mm-redux/constants'; const INVALID_VERSIONS = ['1.29.0']; @@ -95,4 +96,13 @@ export function validatePreviousVersion(previousVersion) { } return true; -} \ No newline at end of file +} + +export function permalinkBadTeam(intl) { + const message = { + id: t('mobile.server_link.unreachable_team.error'), + defaultMessage: 'This link belongs to a deleted team or to a team to which you do not have access.', + }; + + alertErrorWithFallback(intl, {}, message); +}