PLT-6215 Major post list refactor (#6501)
* Major post list refactor * Fix post and thread deletion * Fix preferences not selecting correctly * Fix military time displaying * Fix UP key for editing posts * Fix ESLint error * Various fixes and updates per feedback * Fix for permalink view * Revert to old scrolling method and various fixes * Add floating timestamp, new message indicator, scroll arrows * Update post loading for focus mode and add visibility limit * Fix pinning posts and a react warning * Add loading UI updates from Asaad * Fix refreshing loop * Temporarily bump post visibility limit * Update infinite scrolling * Remove infinite scrolling
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
0231e95f1c
Коммит
ab67f6e257
47
webapp/components/post_view/reaction/index.js
Обычный файл
47
webapp/components/post_view/reaction/index.js
Обычный файл
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getCurrentUserId, makeGetProfilesForReactions} from 'mattermost-redux/selectors/entities/users';
|
||||
import {getMissingProfilesByIds} from 'mattermost-redux/actions/users';
|
||||
import {addReaction, removeReaction} from 'mattermost-redux/actions/posts';
|
||||
import {getEmojiImageUrl} from 'mattermost-redux/utils/emoji_utils';
|
||||
import * as Emoji from 'utils/emoji.jsx';
|
||||
|
||||
import Reaction from './reaction.jsx';
|
||||
|
||||
function makeMapStateToProps() {
|
||||
const getProfilesForReactions = makeGetProfilesForReactions();
|
||||
|
||||
return function mapStateToProps(state, ownProps) {
|
||||
const profiles = getProfilesForReactions(state, ownProps.reactions);
|
||||
let emoji;
|
||||
if (Emoji.EmojiIndicesByAlias.has(ownProps.emojiName)) {
|
||||
emoji = Emoji.Emojis[Emoji.EmojiIndicesByAlias.get(ownProps.emojiName)];
|
||||
} else {
|
||||
emoji = ownProps.emojis[ownProps.emojiName];
|
||||
}
|
||||
|
||||
return {
|
||||
...ownProps,
|
||||
profiles,
|
||||
otherUsersCount: ownProps.reactions.length - profiles.length,
|
||||
currentUserId: getCurrentUserId(state),
|
||||
reactionCount: ownProps.reactions.length,
|
||||
emojiImageUrl: getEmojiImageUrl(emoji)
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
addReaction,
|
||||
removeReaction,
|
||||
getMissingProfilesByIds
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps, mapDispatchToProps)(Reaction);
|
||||
239
webapp/components/post_view/reaction/reaction.jsx
Обычный файл
239
webapp/components/post_view/reaction/reaction.jsx
Обычный файл
@@ -0,0 +1,239 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {OverlayTrigger, Tooltip} from 'react-bootstrap';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
export default class Reaction extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
||||
/*
|
||||
* The post to render the reaction for
|
||||
*/
|
||||
post: PropTypes.object.isRequired,
|
||||
|
||||
/*
|
||||
* The user id of the logged in user
|
||||
*/
|
||||
currentUserId: PropTypes.string.isRequired,
|
||||
|
||||
/*
|
||||
* The name of the emoji for the reaction
|
||||
*/
|
||||
emojiName: PropTypes.string.isRequired,
|
||||
|
||||
/*
|
||||
* The number of reactions to this post for this emoji
|
||||
*/
|
||||
reactionCount: PropTypes.number.isRequired,
|
||||
|
||||
/*
|
||||
* Array of users who reacted to this post
|
||||
*/
|
||||
profiles: PropTypes.array.isRequired,
|
||||
|
||||
/*
|
||||
* The number of users not in the profile list who have reacted with this emoji
|
||||
*/
|
||||
otherUsersCount: PropTypes.number.isRequired,
|
||||
|
||||
/*
|
||||
* The URL of the emoji image
|
||||
*/
|
||||
emojiImageUrl: PropTypes.string.isRequired,
|
||||
|
||||
actions: PropTypes.shape({
|
||||
|
||||
/*
|
||||
* Function to add a reaction to a post
|
||||
*/
|
||||
addReaction: PropTypes.func.isRequired,
|
||||
|
||||
/*
|
||||
* Function to get non-loaded profiles by id
|
||||
*/
|
||||
getMissingProfilesByIds: PropTypes.func.isRequired,
|
||||
|
||||
/*
|
||||
* Function to remove a reaction from a post
|
||||
*/
|
||||
removeReaction: PropTypes.func.isRequired
|
||||
})
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.addReaction = this.addReaction.bind(this);
|
||||
this.removeReaction = this.removeReaction.bind(this);
|
||||
}
|
||||
|
||||
addReaction(e) {
|
||||
e.preventDefault();
|
||||
this.props.actions.addReaction(this.props.post.id, this.props.emojiName);
|
||||
}
|
||||
|
||||
removeReaction(e) {
|
||||
e.preventDefault();
|
||||
this.props.actions.removeReaction(this.props.post.id, this.props.emojiName);
|
||||
}
|
||||
|
||||
render() {
|
||||
let currentUserReacted = false;
|
||||
const users = [];
|
||||
const otherUsersCount = this.props.otherUsersCount;
|
||||
for (const user of this.props.profiles) {
|
||||
if (user.id === this.props.currentUserId) {
|
||||
currentUserReacted = true;
|
||||
} else {
|
||||
users.push(Utils.displayUsernameForUser(user));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort users in alphabetical order with "you" being first if the current user reacted
|
||||
users.sort();
|
||||
if (currentUserReacted) {
|
||||
users.unshift(Utils.localizeMessage('reaction.you', 'You'));
|
||||
}
|
||||
|
||||
let names;
|
||||
if (otherUsersCount > 0) {
|
||||
if (users.length > 0) {
|
||||
names = (
|
||||
<FormattedMessage
|
||||
id='reaction.usersAndOthersReacted'
|
||||
defaultMessage='{users} and {otherUsers, number} other {otherUsers, plural, one {user} other {users}}'
|
||||
values={{
|
||||
users: users.join(', '),
|
||||
otherUsers: otherUsersCount
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
names = (
|
||||
<FormattedMessage
|
||||
id='reaction.othersReacted'
|
||||
defaultMessage='{otherUsers, number} {otherUsers, plural, one {user} other {users}}'
|
||||
values={{
|
||||
otherUsers: otherUsersCount
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
} else if (users.length > 1) {
|
||||
names = (
|
||||
<FormattedMessage
|
||||
id='reaction.usersReacted'
|
||||
defaultMessage='{users} and {lastUser}'
|
||||
values={{
|
||||
users: users.slice(0, -1).join(', '),
|
||||
lastUser: users[users.length - 1]
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
names = users[0];
|
||||
}
|
||||
|
||||
let reactionVerb;
|
||||
if (users.length + otherUsersCount > 1) {
|
||||
if (currentUserReacted) {
|
||||
reactionVerb = (
|
||||
<FormattedMessage
|
||||
id='reaction.reactionVerb.youAndUsers'
|
||||
defaultMessage='reacted'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
reactionVerb = (
|
||||
<FormattedMessage
|
||||
id='reaction.reactionVerb.users'
|
||||
defaultMessage='reacted'
|
||||
/>
|
||||
);
|
||||
}
|
||||
} else if (currentUserReacted) {
|
||||
reactionVerb = (
|
||||
<FormattedMessage
|
||||
id='reaction.reactionVerb.you'
|
||||
defaultMessage='reacted'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
reactionVerb = (
|
||||
<FormattedMessage
|
||||
id='reaction.reactionVerb.user'
|
||||
defaultMessage='reacted'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const tooltip = (
|
||||
<FormattedMessage
|
||||
id='reaction.reacted'
|
||||
defaultMessage='{users} {reactionVerb} with {emoji}'
|
||||
values={{
|
||||
users: <b>{names}</b>,
|
||||
reactionVerb,
|
||||
emoji: <b>{':' + this.props.emojiName + ':'}</b>
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
let handleClick;
|
||||
let clickTooltip;
|
||||
let className = 'post-reaction';
|
||||
if (currentUserReacted) {
|
||||
handleClick = this.removeReaction;
|
||||
clickTooltip = (
|
||||
<FormattedMessage
|
||||
id='reaction.clickToRemove'
|
||||
defaultMessage='(click to remove)'
|
||||
/>
|
||||
);
|
||||
|
||||
className += ' post-reaction--current-user';
|
||||
} else {
|
||||
handleClick = this.addReaction;
|
||||
clickTooltip = (
|
||||
<FormattedMessage
|
||||
id='reaction.clickToAdd'
|
||||
defaultMessage='(click to add)'
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
delayShow={1000}
|
||||
placement='top'
|
||||
shouldUpdatePosition={true}
|
||||
overlay={
|
||||
<Tooltip id={`${this.props.post.id}-${this.props.emojiName}-reaction`}>
|
||||
{tooltip}
|
||||
<br/>
|
||||
{clickTooltip}
|
||||
</Tooltip>
|
||||
}
|
||||
onEnter={this.props.actions.getMissingProfilesByIds}
|
||||
>
|
||||
<div
|
||||
className={className}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span
|
||||
className='post-reaction__emoji emoticon'
|
||||
style={{backgroundImage: 'url(' + this.props.emojiImageUrl + ')'}}
|
||||
/>
|
||||
<span className='post-reaction__count'>
|
||||
{this.props.reactionCount}
|
||||
</span>
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
);
|
||||
}
|
||||
}
|
||||
Ссылка в новой задаче
Block a user