diff --git a/app/components/post_body_additional_content/index.js b/app/components/post_body_additional_content/index.js index 019775ba4..b2ab09265 100644 --- a/app/components/post_body_additional_content/index.js +++ b/app/components/post_body_additional_content/index.js @@ -7,7 +7,7 @@ import {bindActionCreators} from 'redux'; import {getRedirectLocation} from 'mattermost-redux/actions/general'; import {Preferences} from 'mattermost-redux/constants'; import {getConfig} from 'mattermost-redux/selectors/entities/general'; -import {getOpenGraphMetadataForUrl} from 'mattermost-redux/selectors/entities/posts'; +import {getOpenGraphMetadataForUrl, getExpandedLink} from 'mattermost-redux/selectors/entities/posts'; import {getBool, getTheme} from 'mattermost-redux/selectors/entities/preferences'; import {ViewTypes} from 'app/constants'; @@ -46,6 +46,10 @@ function makeMapStateToProps() { return function mapStateToProps(state, ownProps) { const config = getConfig(state); const link = getFirstLink(ownProps.message); + let expandedLink; + if (link) { + expandedLink = getExpandedLink(state, link); + } // Link previews used to be an advanced settings until server version 4.4 when it was changed to be a display setting. // We are checking both here until we bump the server requirement for the mobile apps. @@ -64,6 +68,7 @@ function makeMapStateToProps() { ...getDimensions(state), googleDeveloperKey: config.GoogleDeveloperKey, link, + expandedLink, openGraphData, showLinkPreviews: previewsEnabled && config.EnableLinkPreviews === 'true' && !removeLinkPreview, theme: getTheme(state), diff --git a/app/components/post_body_additional_content/post_body_additional_content.js b/app/components/post_body_additional_content/post_body_additional_content.js index 9cf156791..1108de8e7 100644 --- a/app/components/post_body_additional_content/post_body_additional_content.js +++ b/app/components/post_body_additional_content/post_body_additional_content.js @@ -38,23 +38,24 @@ export default class PostBodyAdditionalContent extends PureComponent { actions: PropTypes.shape({ getRedirectLocation: PropTypes.func.isRequired, }).isRequired, - baseTextStyle: CustomPropTypes.Style, - blockStyles: PropTypes.object, - googleDeveloperKey: PropTypes.string, + link: PropTypes.string.isRequired, + message: PropTypes.string.isRequired, deviceHeight: PropTypes.number.isRequired, deviceWidth: PropTypes.number.isRequired, - metadata: PropTypes.object, - isReplyPost: PropTypes.bool, - link: PropTypes.string, - message: PropTypes.string.isRequired, - onHashtagPress: PropTypes.func, - onPermalinkPress: PropTypes.func, - openGraphData: PropTypes.object, postId: PropTypes.string.isRequired, postProps: PropTypes.object.isRequired, showLinkPreviews: PropTypes.bool.isRequired, - textStyles: PropTypes.object, theme: PropTypes.object.isRequired, + baseTextStyle: CustomPropTypes.Style, + blockStyles: PropTypes.object, + googleDeveloperKey: PropTypes.string, + metadata: PropTypes.object, + isReplyPost: PropTypes.bool, + onHashtagPress: PropTypes.func, + onPermalinkPress: PropTypes.func, + openGraphData: PropTypes.object, + textStyles: PropTypes.object, + expandedLink: PropTypes.string, }; static contextTypes = { @@ -79,7 +80,6 @@ export default class PostBodyAdditionalContent extends PureComponent { this.state = { linkLoadError: false, linkLoaded: false, - shortenedLink: null, ...dimensions, }; @@ -89,12 +89,12 @@ export default class PostBodyAdditionalContent extends PureComponent { componentDidMount() { this.mounted = true; - this.load(this.props); + this.load(); } componentDidUpdate(prevProps) { if (prevProps.link !== this.props.link) { - this.load(this.props); + this.load(true); } } @@ -116,33 +116,30 @@ export default class PostBodyAdditionalContent extends PureComponent { return false; }; - load = async (props) => { - const {link} = props; + getImageUrl = (link) => { + let imageUrl; + + if (this.isImage()) { + imageUrl = link; + } else if (isYoutubeLink(link)) { + const videoId = getYouTubeVideoId(link); + imageUrl = `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`; + } + + return imageUrl; + } + + load = (linkChanged = false) => { + const {link, expandedLink, actions} = this.props; + if (link) { - let imageUrl; - if (this.isImage()) { - imageUrl = link; - } else if (isYoutubeLink(link)) { - const videoId = getYouTubeVideoId(link); - imageUrl = `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`; - } else { - const {data} = await this.props.actions.getRedirectLocation(link); + let imageUrl = this.getImageUrl(link); - let shortenedLink; - if (data && data.location) { - shortenedLink = data.location; - } - - if (shortenedLink) { - if (this.isImage(shortenedLink)) { - imageUrl = shortenedLink; - } else if (isYoutubeLink(shortenedLink)) { - const videoId = getYouTubeVideoId(shortenedLink); - imageUrl = `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`; - } - if (this.mounted) { - this.setState({shortenedLink}); - } + if (!imageUrl) { + if (!expandedLink || linkChanged) { + actions.getRedirectLocation(link); + } else { + imageUrl = this.getImageUrl(expandedLink); } } @@ -215,9 +212,9 @@ export default class PostBodyAdditionalContent extends PureComponent { generateToggleableEmbed = (isImage, isYouTube) => { let {link} = this.props; - const {shortenedLink} = this.state; - if (shortenedLink) { - link = shortenedLink; + const {expandedLink} = this.props; + if (expandedLink) { + link = expandedLink; } const {width, height, uri} = this.state; @@ -407,10 +404,10 @@ export default class PostBodyAdditionalContent extends PureComponent { }; handlePreviewImage = (imageRef) => { - const {shortenedLink} = this.state; let {link} = this.props; - if (shortenedLink) { - link = shortenedLink; + const {expandedLink} = this.props; + if (expandedLink) { + link = expandedLink; } const { originalHeight, @@ -485,10 +482,10 @@ export default class PostBodyAdditionalContent extends PureComponent { render() { let {link} = this.props; - const {openGraphData, postProps} = this.props; - const {linkLoadError, shortenedLink} = this.state; - if (shortenedLink) { - link = shortenedLink; + const {openGraphData, postProps, expandedLink} = this.props; + const {linkLoadError} = this.state; + if (expandedLink) { + link = expandedLink; } const {attachments} = postProps; diff --git a/app/components/post_body_additional_content/post_body_additional_content.test.js b/app/components/post_body_additional_content/post_body_additional_content.test.js new file mode 100644 index 000000000..64bc6d3b0 --- /dev/null +++ b/app/components/post_body_additional_content/post_body_additional_content.test.js @@ -0,0 +1,52 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; + +import {Preferences} from 'mattermost-redux/constants'; + +import {shallowWithIntl} from 'test/intl-test-helper'; + +import PostBodyAdditionalContent from './post_body_additional_content.js'; + +describe('PostBodyAdditionalContent', () => { + const baseProps = { + actions: { + getRedirectLocation: jest.fn(), + }, + link: 'http://short.ened/123', + deviceHeight: 100, + deviceWidth: 100, + message: 'message', + postId: 'post-id', + postProps: {}, + showLinkPreviews: false, + theme: Preferences.THEMES.default, + }; + + test('should call getRedirectLocation only if expandedLink has not been set', () => { + const wrapper = shallowWithIntl(); + const instance = wrapper.instance(); + + expect(baseProps.actions.getRedirectLocation).toHaveBeenCalledTimes(1); + + wrapper.setProps({expandedLink: 'http://expanded.com/123'}); + instance.load(); + expect(baseProps.actions.getRedirectLocation).toHaveBeenCalledTimes(1); + }); + + test('should call getRedirectLocation if expandedLink is set but link changed', () => { + const props = { + ...baseProps, + expandedLink: 'http://expanded.com/123', + }; + const wrapper = shallowWithIntl(); + const instance = wrapper.instance(); + + expect(baseProps.actions.getRedirectLocation).toHaveBeenCalledTimes(0); + + wrapper.setProps({link: `${baseProps.link}/456`}); + instance.load(); + expect(baseProps.actions.getRedirectLocation).toHaveBeenCalledTimes(1); + }); +});