MM-15719 Use metadata only to render post additional content (#4386)

* MM-15719 Use metadata only to render post additional content

* Default link to empty instead of undefined

* Feedback review
This commit is contained in:
Elias Nahum 2020-06-29 11:28:07 -04:00 committed by GitHub
parent 57719d7dcc
commit 0f72bb34c2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 93 additions and 279 deletions

View file

@ -11,7 +11,6 @@ import {
getChannelByNameAndTeamName,
leaveChannel as serviceLeaveChannel,
} from '@mm-redux/actions/channels';
import {getFilesForPost} from '@mm-redux/actions/files';
import {savePreferences} from '@mm-redux/actions/preferences';
import {selectTeam} from '@mm-redux/actions/teams';
import {Client4} from '@mm-redux/client';
@ -110,17 +109,6 @@ export function fetchPostActionWithRetry(action, maxTries = MAX_RETRIES) {
};
}
export function loadFilesForPostIfNecessary(postId) {
return async (dispatch, getState) => {
const {files} = getState().entities;
const fileIdsForPost = files.fileIdsByPostId[postId];
if (!fileIdsForPost?.length) {
await dispatch(getFilesForPost(postId));
}
};
}
export function loadThreadIfNecessary(rootId) {
return (dispatch, getState) => {
const state = getState();

View file

@ -17,9 +17,6 @@ const MAX_VISIBLE_ROW_IMAGES = 4;
export default class FileAttachmentList extends ImageViewPort {
static propTypes = {
actions: PropTypes.shape({
loadFilesForPostIfNecessary: PropTypes.func.isRequired,
}).isRequired,
canDownloadFiles: PropTypes.bool.isRequired,
fileIds: PropTypes.array.isRequired,
files: PropTypes.array,
@ -45,22 +42,12 @@ export default class FileAttachmentList extends ImageViewPort {
});
}
componentDidMount() {
super.componentDidMount();
const {files} = this.props;
if (files.length === 0) {
this.loadFilesForPost();
}
}
componentDidUpdate(prevProps) {
if (prevProps.files.length !== this.props.files.length) {
this.filesForGallery = this.getFilesForGallery(this.props);
this.buildGalleryFiles().then((results) => {
this.galleryFiles = results;
});
this.loadFilesForPost();
}
}
@ -139,10 +126,6 @@ export default class FileAttachmentList extends ImageViewPort {
isSingleImage = (files) => (files.length === 1 && this.isImage(files[0]));
loadFilesForPost = async () => {
await this.props.actions.loadFilesForPostIfNecessary(this.props.postId);
}
renderItems = (items, moreImagesCount, includeGutter = false) => {
const {canDownloadFiles, isReplyPost, onLongPress, theme} = this.props;
const isSingleImage = this.isSingleImage(items);

View file

@ -11,8 +11,6 @@ jest.mock('react-native-file-viewer', () => ({
}));
describe('FileAttachmentList', () => {
const loadFilesForPostIfNecessary = jest.fn().mockImplementationOnce(() => Promise.resolve({data: {}}));
const files = [{
create_at: 1546893090093,
delete_at: 0,
@ -55,9 +53,6 @@ describe('FileAttachmentList', () => {
};
const baseProps = {
actions: {
loadFilesForPostIfNecessary,
},
canDownloadFiles: true,
deviceHeight: 680,
deviceWidth: 660,
@ -162,45 +157,9 @@ describe('FileAttachmentList', () => {
expect(wrapper.getElement()).toMatchSnapshot();
});
test('should call loadFilesForPostIfNecessary when files does not exist', async () => {
const props = {
...baseProps,
files: undefined,
};
shallow(
<FileAttachment {...props}/>,
);
expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledWith(props.postId);
});
test('should call loadFilesForPostIfNecessary on componentUpdate and when files does not exist', async () => {
const loadFilesForPostIfNecessaryMock = jest.fn().mockImplementationOnce(() => Promise.resolve({data: {}}));
const props = {
...baseProps,
files: [],
actions: {
loadFilesForPostIfNecessary: loadFilesForPostIfNecessaryMock,
},
};
shallow(
<FileAttachment {...props}/>,
);
expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledTimes(1);
expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledWith(props.postId);
await loadFilesForPostIfNecessaryMock();
expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledTimes(2);
expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledWith(props.postId);
});
test('should call getFilesForGallery on props change', async () => {
const loadFilesForPostIfNecessaryMock = jest.fn().mockImplementationOnce(() => Promise.resolve({data: {}}));
const props = {
...baseProps,
actions: {
loadFilesForPostIfNecessary: loadFilesForPostIfNecessaryMock,
},
};
const wrapper = shallow(
@ -211,23 +170,4 @@ describe('FileAttachmentList', () => {
wrapper.setProps({files: [files[0], files[1]]});
expect(wrapper.instance().getFilesForGallery).toHaveBeenCalled();
});
test('should call loadFilesForPostIfNecessary when files object empty', async () => {
const loadFilesForPostIfNecessaryMock = jest.fn().mockImplementationOnce(() => Promise.resolve({data: {}}));
const props = {
...baseProps,
actions: {
loadFilesForPostIfNecessary: loadFilesForPostIfNecessaryMock,
},
};
const wrapper = shallow(
<FileAttachment {...props}/>,
);
wrapper.setProps({files: []});
expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledTimes(1);
expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledWith(props.postId);
wrapper.setProps({test: 'test'});
expect(props.actions.loadFilesForPostIfNecessary).toHaveBeenCalledTimes(1);
});
});

View file

@ -1,15 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {canDownloadFilesOnMobile} from '@mm-redux/selectors/entities/general';
import {makeGetFilesForPost} from '@mm-redux/selectors/entities/files';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {loadFilesForPostIfNecessary} from 'app/actions/views/channel';
import FileAttachmentList from './file_attachment_list';
function makeMapStateToProps() {
@ -23,12 +20,4 @@ function makeMapStateToProps() {
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
loadFilesForPostIfNecessary,
}, dispatch),
};
}
export default connect(makeMapStateToProps, mapDispatchToProps)(FileAttachmentList);
export default connect(makeMapStateToProps)(FileAttachmentList);

View file

@ -179,10 +179,15 @@ export default class Markdown extends PureComponent {
};
renderImage = ({linkDestination, reactChildren, context, src}) => {
if (!this.props.imagesMetadata) {
return null;
}
if (context.indexOf('table') !== -1) {
// We have enough problems rendering images as is, so just render a link inside of a table
return (
<MarkdownTableImage
imagesMetadata={this.props.imagesMetadata}
source={src}
textStyle={[this.computeTextStyle(this.props.baseTextStyle, context), this.props.textStyles.link]}
>

View file

@ -6,7 +6,6 @@ import React from 'react';
import {intlShape} from 'react-intl';
import {
Clipboard,
Image,
Linking,
Platform,
StyleSheet,
@ -57,11 +56,6 @@ export default class MarkdownImage extends ImageViewPort {
};
}
componentDidMount() {
super.componentDidMount();
this.loadImageSize(this.getSource());
}
setImageRef = (ref) => {
this.imageRef = ref;
}
@ -169,12 +163,6 @@ export default class MarkdownImage extends ImageViewPort {
previewImageAtIndex([this.itemRef], 0, files);
};
loadImageSize = (source) => {
if (!this.state.originalWidth) {
Image.getSize(source, this.handleSizeReceived, this.handleSizeFailed);
}
};
render() {
if (isGifTooLarge(this.props.imagesMetadata?.[this.props.source])) {
return null;

View file

@ -4,14 +4,12 @@
import {connect} from 'react-redux';
import {getCurrentUrl} from '@mm-redux/selectors/entities/general';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import MarkdownTableImage from './markdown_table_image';
function mapStateToProps(state) {
return {
serverURL: getCurrentUrl(state),
theme: getTheme(state),
};
}

View file

@ -14,10 +14,10 @@ import {goToScreen} from 'app/actions/navigation';
export default class MarkdownTableImage extends React.PureComponent {
static propTypes = {
children: PropTypes.node.isRequired,
imagesMetadata: PropTypes.object,
source: PropTypes.string.isRequired,
textStyle: CustomPropTypes.Style.isRequired,
serverURL: PropTypes.string,
theme: PropTypes.object.isRequired,
};
static contextTypes = {
@ -32,6 +32,7 @@ export default class MarkdownTableImage extends React.PureComponent {
defaultMessage: 'Image',
});
const passProps = {
imagesMetadata: this.props.imagesMetadata,
imageSource: this.getImageSource(),
};

View file

@ -3,7 +3,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {Image, View} from 'react-native';
import {View} from 'react-native';
import ProgressiveImage from 'app/components/progressive_image';
import TouchableWithFeedback from 'app/components/touchable_with_feedback';
@ -110,13 +110,7 @@ export default class AttachmentImage extends PureComponent {
if (imageMetadata) {
this.setImageDimensionsFromMeta(imageURL, imageMetadata);
return;
}
Image.getSize(imageURL, (width, height) => {
const dimensions = calculateDimensions(height, width, this.maxImageWidth);
this.setImageDimensions(imageURL, dimensions, width, height);
}, () => null);
};
setViewPortMaxWidth = () => {

View file

@ -1,12 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Image} from 'react-native';
import {shallow} from 'enzyme';
import React from 'react';
const originalGetSizeFn = Image.getSize;
import Preferences from '@mm-redux/constants/preferences';
import AttachmentImage from './index';
@ -20,10 +17,6 @@ describe('AttachmentImage', () => {
theme: Preferences.THEMES.default,
};
afterEach(() => {
Image.getSize = originalGetSizeFn;
});
test('it matches snapshot', () => {
const wrapper = shallow(<AttachmentImage {...baseProps}/>);
expect(wrapper).toMatchSnapshot();
@ -47,22 +40,6 @@ describe('AttachmentImage', () => {
expect(state.imageUri).toBe(null);
});
test('it calls Image.getSize if metadata is not present', () => {
const getSizeFn = jest.fn((_, callback) => {
callback(64, 64);
});
Image.getSize = getSizeFn;
const props = {...baseProps, imageMetadata: null};
const wrapper = shallow(<AttachmentImage {...props}/>);
const state = wrapper.state();
expect(state.hasImage).toBe(true);
expect(state.imageUri).toBe('https://images.com/image.png');
expect(state.originalWidth).toBe(64);
expect(getSizeFn).toHaveBeenCalled();
});
test('it updates image when imageUrl prop changes', () => {
const wrapper = shallow(<AttachmentImage {...baseProps}/>);

View file

@ -49,6 +49,7 @@ export default class MessageAttachment extends PureComponent {
const style = getStyleSheet(theme);
const STATUS_COLORS = getStatusColors(theme);
const hasImage = Boolean(metadata?.images?.[attachment.image_url]);
let borderStyle;
if (attachment.color) {
@ -111,6 +112,7 @@ export default class MessageAttachment extends PureComponent {
actions={attachment.actions}
postId={postId}
/>
{hasImage &&
<AttachmentImage
deviceHeight={deviceHeight}
deviceWidth={deviceWidth}
@ -118,6 +120,7 @@ export default class MessageAttachment extends PureComponent {
imageMetadata={metadata?.images?.[attachment.image_url]}
theme={theme}
/>
}
</View>
</React.Fragment>
);

View file

@ -2,9 +2,6 @@
// See LICENSE.txt for license information.
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {getOpenGraphMetadata} from '@mm-redux/actions/posts';
import {getDimensions} from 'app/selectors/device';
@ -16,12 +13,4 @@ function mapStateToProps(state) {
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
getOpenGraphMetadata,
}, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(PostAttachmentOpenGraph);
export default connect(mapStateToProps)(PostAttachmentOpenGraph);

View file

@ -3,7 +3,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {Image, Linking, Text, View} from 'react-native';
import {Linking, Text, View} from 'react-native';
import FastImage from 'react-native-fast-image';
import {TABLET_WIDTH} from '@components/sidebars/drawer_layout';
@ -19,9 +19,6 @@ const VIEWPORT_IMAGE_REPLY_OFFSET = 13;
export default class PostAttachmentOpenGraph extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
getOpenGraphMetadata: PropTypes.func.isRequired,
}).isRequired,
deviceHeight: PropTypes.number.isRequired,
deviceWidth: PropTypes.number.isRequired,
imagesMetadata: PropTypes.object,
@ -40,23 +37,11 @@ export default class PostAttachmentOpenGraph extends PureComponent {
componentDidMount() {
this.mounted = true;
this.fetchData(this.props.link, this.props.openGraphData);
if (this.state.openGraphImageUrl) {
this.getImageSize(this.state.openGraphImageUrl);
}
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.link !== this.props.link) {
this.fetchData(this.props.link, this.props.openGraphData);
}
if (prevState.openGraphImageUrl !== this.state.openGraphImageUrl) {
this.getImageSize(this.state.openGraphImageUrl);
}
}
componentWillUnmount() {
this.mounted = false;
}
@ -65,12 +50,6 @@ export default class PostAttachmentOpenGraph extends PureComponent {
this.itemRef = ref;
};
fetchData = (url, openGraphData) => {
if (!openGraphData) {
this.props.actions.getOpenGraphMetadata(url);
}
};
getBestImageUrlAndDimensions = (data) => {
if (!data || !data.images) {
return {
@ -147,11 +126,6 @@ export default class PostAttachmentOpenGraph extends PureComponent {
if (ogImage?.width && ogImage?.height) {
this.setImageSize(imageUrl, ogImage.width, ogImage.height);
} else {
// if we get to this point there can be a scroll pop
Image.getSize(imageUrl, (width, height) => {
this.setImageSize(imageUrl, width, height);
}, () => null);
}
};

View file

@ -274,7 +274,7 @@ export default class PostBody extends PureComponent {
return null;
}
if (metadata && !metadata.embeds) {
if (!metadata?.embeds?.length) {
return null;
}

View file

@ -49,9 +49,25 @@ describe('PostBody', () => {
};
test('should mount additional content for non-system messages', () => {
const metadata = {
embeds: [{
type: 'opengraph',
url: 'https://youtu.be/g-EXttb1C9A',
}],
images: {
'https://i.ytimg.com/vi/g-EXttb1C9A/maxresdefault.jpg': {
format: 'jpeg',
frame_count: 0,
height: 720,
width: 1280,
},
},
};
const props = {
...baseProps,
isSystemMessage: false,
metadata,
};
const wrapper = shallowWithIntl(<PostBody {...props}/>);

View file

@ -7,30 +7,15 @@ import {bindActionCreators} from 'redux';
import {getRedirectLocation} from '@mm-redux/actions/general';
import {Preferences} from '@mm-redux/constants';
import {getConfig} from '@mm-redux/selectors/entities/general';
import {getOpenGraphMetadataForUrl, getExpandedLink} from '@mm-redux/selectors/entities/posts';
import {getOpenGraphMetadataForUrl as selectOpenGraphMetadataForUrl, getExpandedLink as selectExpandedLink} from '@mm-redux/selectors/entities/posts';
import {getBool, getTheme} from '@mm-redux/selectors/entities/preferences';
import {ViewTypes} from 'app/constants';
import {getDimensions} from 'app/selectors/device';
import {extractFirstLink} from 'app/utils/url';
import PostBodyAdditionalContent from './post_body_additional_content';
function makeGetFirstLink() {
let link;
let lastMessage;
return (message) => {
if (message !== lastMessage) {
link = extractFirstLink(message);
lastMessage = message;
}
return link;
};
}
function getOpenGraphData(metadata, url) {
function selectOpenGraphData(metadata, url) {
if (!metadata || !metadata.embeds) {
return null;
}
@ -40,39 +25,35 @@ function getOpenGraphData(metadata, url) {
});
}
function makeMapStateToProps() {
const getFirstLink = makeGetFirstLink();
function mapStateToProps(state, ownProps) {
const config = getConfig(state);
const link = ownProps.metadata.embeds[0]?.url || '';
let expandedLink;
if (link) {
expandedLink = selectExpandedLink(state, link);
}
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.
const previewsEnabled = (getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, `${ViewTypes.FEATURE_TOGGLE_PREFIX}${ViewTypes.EMBED_PREVIEW}`) ||
getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.LINK_PREVIEW_DISPLAY, true));
// 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.
const previewsEnabled = (getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, `${ViewTypes.FEATURE_TOGGLE_PREFIX}${ViewTypes.EMBED_PREVIEW}`) ||
getBool(state, Preferences.CATEGORY_DISPLAY_SETTINGS, Preferences.LINK_PREVIEW_DISPLAY, true));
const removeLinkPreview = ownProps.postProps.remove_link_preview === 'true';
const removeLinkPreview = ownProps.postProps.remove_link_preview === 'true';
let openGraphData = selectOpenGraphMetadataForUrl(state, ownProps.postId, link);
if (!openGraphData) {
const data = selectOpenGraphData(ownProps.metadata, link);
openGraphData = data?.data;
}
let openGraphData = getOpenGraphMetadataForUrl(state, ownProps.postId, link);
if (!openGraphData) {
const data = getOpenGraphData(ownProps.metadata, link);
openGraphData = data?.data;
}
return {
...getDimensions(state),
googleDeveloperKey: config.GoogleDeveloperKey,
link,
expandedLink,
openGraphData,
showLinkPreviews: previewsEnabled && config.EnableLinkPreviews === 'true' && !removeLinkPreview,
theme: getTheme(state),
};
return {
...getDimensions(state),
googleDeveloperKey: config.GoogleDeveloperKey,
link,
expandedLink,
openGraphData,
showLinkPreviews: previewsEnabled && config.EnableLinkPreviews === 'true' && !removeLinkPreview,
theme: getTheme(state),
};
}
@ -84,4 +65,4 @@ function mapDispatchToProps(dispatch) {
};
}
export default connect(makeMapStateToProps, mapDispatchToProps)(PostBodyAdditionalContent);
export default connect(mapStateToProps, mapDispatchToProps)(PostBodyAdditionalContent);

View file

@ -34,24 +34,24 @@ export default class PostBodyAdditionalContent extends ImageViewPort {
actions: PropTypes.shape({
getRedirectLocation: PropTypes.func.isRequired,
}).isRequired,
link: PropTypes.string.isRequired,
message: PropTypes.string.isRequired,
baseTextStyle: CustomPropTypes.Style,
blockStyles: PropTypes.object,
deviceHeight: PropTypes.number.isRequired,
deviceWidth: PropTypes.number.isRequired,
expandedLink: PropTypes.string,
googleDeveloperKey: PropTypes.string,
isReplyPost: PropTypes.bool,
link: PropTypes.string.isRequired,
message: PropTypes.string.isRequired,
metadata: PropTypes.object,
onHashtagPress: PropTypes.func,
onPermalinkPress: PropTypes.func,
openGraphData: PropTypes.object,
postId: PropTypes.string.isRequired,
postProps: PropTypes.object.isRequired,
showLinkPreviews: PropTypes.bool.isRequired,
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 = {
@ -122,10 +122,6 @@ export default class PostBodyAdditionalContent extends ImageViewPort {
if (img && img.height && img.width) {
this.setImageSize(path, img.width, img.height);
} else {
Image.getSize(path, (width, height) => {
this.setImageSize(path, width, height);
}, () => this.setState({linkLoadError: true}));
}
}
};
@ -137,7 +133,7 @@ export default class PostBodyAdditionalContent extends ImageViewPort {
imageUrl = link;
} else if (isYoutubeLink(link)) {
const videoId = getYouTubeVideoId(link);
imageUrl = `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`;
imageUrl = Object.keys(this.props.metadata.images)[0] || `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`;
}
return imageUrl;
@ -221,12 +217,12 @@ export default class PostBodyAdditionalContent extends ImageViewPort {
const {link, expandedLink, actions} = this.props;
if (link) {
let imageUrl = this.getImageUrl(link);
if (isYoutubeLink(link)) {
return;
}
let imageUrl = this.getImageUrl(link);
if (!imageUrl) {
if (!expandedLink || linkChanged) {
actions.getRedirectLocation(link);
@ -295,6 +291,10 @@ export default class PostBodyAdditionalContent extends ImageViewPort {
const imageMetadata = this.props.metadata?.images?.[link];
const {width, height, uri} = this.state;
if (!imageMetadata) {
return null;
}
return (
<PostAttachmentImage
height={height || MAX_IMAGE_HEIGHT}
@ -360,11 +360,11 @@ export default class PostBodyAdditionalContent extends ImageViewPort {
return attachments;
}
if (!openGraphData && metadata) {
if (!openGraphData || !showLinkPreviews) {
return null;
}
if (link && showLinkPreviews) {
if (link) {
if (!PostAttachmentOpenGraph) {
PostAttachmentOpenGraph = require('app/components/post_attachment_opengraph').default;
}
@ -374,7 +374,7 @@ export default class PostBodyAdditionalContent extends ImageViewPort {
isReplyPost={isReplyPost}
link={link}
openGraphData={openGraphData}
imagesMetadata={metadata && metadata.images}
imagesMetadata={metadata.images}
theme={theme}
/>
);
@ -390,8 +390,8 @@ export default class PostBodyAdditionalContent extends ImageViewPort {
MAX_YOUTUBE_IMAGE_WIDTH,
getViewPortWidth(this.props.isReplyPost, this.hasPermanentSidebar()),
);
const imgUrl = `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`;
const imgUrl = Object.keys(this.props.metadata.images)[0] || `https://i.ytimg.com/vi/${videoId}/hqdefault.jpg`;
return (
<TouchableWithFeedback
style={[styles.imageContainer, {height: dimensions.height}]}

View file

@ -4,7 +4,7 @@
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {getReactionsForPost, removeReaction} from '@mm-redux/actions/posts';
import {removeReaction} from '@mm-redux/actions/posts';
import {makeGetReactionsForPost, getPost} from '@mm-redux/selectors/entities/posts';
import {haveIChannelPermission} from '@mm-redux/selectors/entities/roles';
import {hasNewPermissions} from '@mm-redux/selectors/entities/general';
@ -74,7 +74,6 @@ function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
addReaction,
getReactionsForPost,
removeReaction,
}, dispatch),
};

View file

@ -22,7 +22,6 @@ export default class Reactions extends PureComponent {
static propTypes = {
actions: PropTypes.shape({
addReaction: PropTypes.func.isRequired,
getReactionsForPost: PropTypes.func.isRequired,
removeReaction: PropTypes.func.isRequired,
}).isRequired,
canAddReaction: PropTypes.bool,
@ -43,13 +42,6 @@ export default class Reactions extends PureComponent {
intl: intlShape.isRequired,
};
componentDidMount() {
const {actions, postId, reactions} = this.props;
if (!reactions) {
actions.getReactionsForPost(postId);
}
}
handleAddReaction = preventDoubleTap(() => {
const {theme} = this.props;
const {formatMessage} = this.context.intl;

View file

@ -12,7 +12,6 @@ describe('Reactions', () => {
const baseProps = {
actions: {
addReaction: jest.fn(),
getReactionsForPost: jest.fn(),
removeReaction: jest.fn(),
},
canAddReaction: true,

View file

@ -14,23 +14,21 @@ import FastImage from 'react-native-fast-image';
export default class TableImage extends React.PureComponent {
static propTypes = {
deviceWidth: PropTypes.number.isRequired,
imagesMetadata: PropTypes.object,
imageSource: PropTypes.string.isRequired,
};
constructor(props) {
super(props);
const dimensions = props.imagesMetadata?.[props.imageSource];
this.state = {
imageSource: '',
width: -1,
height: -1,
width: dimensions?.width || -1,
height: dimensions?.height || -1,
};
}
componentDidMount() {
this.getImageSize(this.props.imageSource);
}
static getDerivedStateFromProps(nextProps, state) {
if (nextProps.imageSource !== state.imageSource) {
return {
@ -44,16 +42,16 @@ export default class TableImage extends React.PureComponent {
componentDidUpdate(prevProps) {
if (prevProps.imageSource !== this.props.imageSource) {
this.getImageSize(this.props.imageSource);
this.getImageSize();
}
}
getImageSize = (imageSource) => {
Image.getSize(imageSource, (width, height) => {
this.setState({
width,
height,
});
getImageSize = () => {
const {imageSource, imagesMetadata} = this.props;
const dimensions = imagesMetadata?.[imageSource];
this.setState({
width: dimensions?.width || -1,
height: dimensions?.height || -1,
});
}