Inline chat moderation UI (#1331)

* - mock detect when user turns into moderator
- add moderator indicator to display on messages and username changer

* also mock moderator flag in message payload about user to display indicator

* add some menu looking icons and a menu of actions

* WIP chat moderators

* Add support for admin promoting a user to moderator

* WIP-
open a more info panel of user+message info; add some a11y to buttons

* style the details panel

* adjust positioning of menus

* Merge fixes. ChatClient->Client ChatServer->Server

* Remove moderator bool placeholders to use real state

* Support inline hiding of messages by moderators

* Support inline banning of chat users

* Cleanup linter warnings

* Puppeteer tests fail after typing take place

* Manually resolve conflicts in chat between moderator feature and develop

Co-authored-by: Gabe Kangas <gabek@real-ity.com>
This commit is contained in:
gingervitis
2021-11-02 19:27:41 -07:00
committed by GitHub
parent 4a52ba9f35
commit 9a91324456
23 changed files with 902 additions and 116 deletions

View File

@@ -10,12 +10,14 @@ import {
import { convertToText } from '../../utils/chat.js';
import { SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js';
import { getDiffInDaysFromNow } from '../../utils/helpers.js';
import ModeratorActions from './moderator-actions.js';
export default class ChatMessageView extends Component {
constructor(props) {
super(props);
this.state = {
formattedMessage: '',
moderatorMenuOpen: false,
};
}
@@ -37,11 +39,14 @@ export default class ChatMessageView extends Component {
});
}
}
render() {
const { message } = this.props;
const { message, isModerator, accessToken } = this.props;
const { user, timestamp } = message;
const { displayName, displayColor, createdAt } = user;
const { displayName, displayColor, createdAt,
isModerator: isAuthorModerator,
} = user;
const isMessageModeratable = isModerator && message.type === SOCKET_MESSAGE_TYPES.CHAT;
const { formattedMessage } = this.state;
if (!formattedMessage) {
@@ -61,8 +66,8 @@ export default class ChatMessageView extends Component {
? { backgroundColor: '#667eea' }
: { backgroundColor: messageBubbleColorForHue(displayColor) };
const messageClassString = isSystemMessage
? getSystemMessageClassString()
: getChatMessageClassString();
? 'message flex flex-row items-start p-4 m-2 rounded-lg shadow-l border-solid border-indigo-700 border-2 border-opacity-60 text-l'
: `message relative flex flex-row items-start p-3 m-3 rounded-lg shadow-s text-sm ${isMessageModeratable ? 'moderatable' : ''}`;
return html`
<div
@@ -73,11 +78,12 @@ export default class ChatMessageView extends Component {
<div class="message-content break-words w-full">
<div
style=${authorTextColor}
class="message-author font-bold"
class="message-author font-bold${isAuthorModerator ? ' moderator-flag' : ''}"
title=${userMetadata}
>
${displayName}
</div>
${isMessageModeratable && html`<${ModeratorActions} message=${message} accessToken=${accessToken} />`}
<div
class="message-text text-gray-300 font-normal overflow-y-hidden pt-2"
dangerouslySetInnerHTML=${{ __html: formattedMessage }}
@@ -88,14 +94,6 @@ export default class ChatMessageView extends Component {
}
}
function getSystemMessageClassString() {
return 'message flex flex-row items-start p-4 m-2 rounded-lg shadow-l border-solid border-indigo-700 border-2 border-opacity-60 text-l';
}
function getChatMessageClassString() {
return 'message flex flex-row items-start p-3 m-3 rounded-lg shadow-s text-sm';
}
export async function formatMessageText(message, username) {
let formattedText = getMessageWithEmbeds(message);
formattedText = convertToMarkup(formattedText);