MM-29252 Tapping on invalid permalink shows an error (#4926)
This commit is contained in:
parent
e5bf198f0e
commit
2c0b67067f
22 changed files with 155 additions and 305 deletions
|
|
@ -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};
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
51
app/actions/views/permalink.ts
Normal file
51
app/actions/views/permalink.ts
Normal file
|
|
@ -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(''));
|
||||
};
|
||||
}
|
||||
|
|
@ -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)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = () => {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
<PostList {...baseProps}/>,
|
||||
);
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue