Handle hide/show chat messages via moderation. Closes #1986
This commit is contained in:
parent
c0dc2eb707
commit
ac7e095fdf
@ -5,11 +5,13 @@ import he from 'he';
|
|||||||
import cn from 'classnames';
|
import cn from 'classnames';
|
||||||
import { Tooltip } from 'antd';
|
import { Tooltip } from 'antd';
|
||||||
import { LinkOutlined } from '@ant-design/icons';
|
import { LinkOutlined } from '@ant-design/icons';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import s from './ChatUserMessage.module.scss';
|
import s from './ChatUserMessage.module.scss';
|
||||||
import { formatTimestamp } from './messageFmt';
|
import { formatTimestamp } from './messageFmt';
|
||||||
import { ChatMessage } from '../../../interfaces/chat-message.model';
|
import { ChatMessage } from '../../../interfaces/chat-message.model';
|
||||||
import ChatModerationActionMenu from '../ChatModerationActionMenu/ChatModerationActionMenu';
|
import ChatModerationActionMenu from '../ChatModerationActionMenu/ChatModerationActionMenu';
|
||||||
import ChatUserBadge from '../ChatUserBadge/ChatUserBadge';
|
import ChatUserBadge from '../ChatUserBadge/ChatUserBadge';
|
||||||
|
import { accessTokenAtom } from '../../stores/ClientConfigStore';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
message: ChatMessage;
|
message: ChatMessage;
|
||||||
@ -32,6 +34,7 @@ export default function ChatUserMessage({
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
const { id: messageId, body, user, timestamp } = message;
|
const { id: messageId, body, user, timestamp } = message;
|
||||||
const { id: userId, displayName, displayColor } = user;
|
const { id: userId, displayName, displayColor } = user;
|
||||||
|
const accessToken = useRecoilValue<string>(accessTokenAtom);
|
||||||
|
|
||||||
const color = `var(--theme-color-users-${displayColor})`;
|
const color = `var(--theme-color-users-${displayColor})`;
|
||||||
const formattedTimestamp = `Sent ${formatTimestamp(timestamp)}`;
|
const formattedTimestamp = `Sent ${formatTimestamp(timestamp)}`;
|
||||||
@ -81,7 +84,7 @@ export default function ChatUserMessage({
|
|||||||
<div className={s.modMenuWrapper}>
|
<div className={s.modMenuWrapper}>
|
||||||
<ChatModerationActionMenu
|
<ChatModerationActionMenu
|
||||||
messageID={messageId}
|
messageID={messageId}
|
||||||
accessToken=""
|
accessToken={accessToken}
|
||||||
userID={userId}
|
userID={userId}
|
||||||
userDisplayName={displayName}
|
userDisplayName={displayName}
|
||||||
/>
|
/>
|
||||||
|
@ -17,6 +17,7 @@ import {
|
|||||||
ConnectedClientInfoEvent,
|
ConnectedClientInfoEvent,
|
||||||
MessageType,
|
MessageType,
|
||||||
ChatEvent,
|
ChatEvent,
|
||||||
|
MessageVisibilityEvent,
|
||||||
SocketEvent,
|
SocketEvent,
|
||||||
} from '../../interfaces/socket-events';
|
} from '../../interfaces/socket-events';
|
||||||
|
|
||||||
@ -111,6 +112,11 @@ export const clockSkewAtom = atom<Number>({
|
|||||||
default: 0.0,
|
default: 0.0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const removedMessageIdsAtom = atom<string[]>({
|
||||||
|
key: 'removedMessageIds',
|
||||||
|
default: [],
|
||||||
|
});
|
||||||
|
|
||||||
// Chat is visible if the user wishes it to be visible AND the required
|
// Chat is visible if the user wishes it to be visible AND the required
|
||||||
// chat state is set.
|
// chat state is set.
|
||||||
export const isChatVisibleSelector = selector({
|
export const isChatVisibleSelector = selector({
|
||||||
@ -144,6 +150,15 @@ export const isOnlineSelector = selector({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const visibleChatMessagesSelector = selector<ChatMessage[]>({
|
||||||
|
key: 'visibleChatMessagesSelector',
|
||||||
|
get: ({ get }) => {
|
||||||
|
const messages: ChatMessage[] = get(chatMessagesAtom);
|
||||||
|
const removedIds: string[] = get(removedMessageIdsAtom);
|
||||||
|
return messages.filter(message => !removedIds.includes(message.id));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Take a nested object of state metadata and merge it into
|
// Take a nested object of state metadata and merge it into
|
||||||
// a single flattened node.
|
// a single flattened node.
|
||||||
function mergeMeta(meta) {
|
function mergeMeta(meta) {
|
||||||
@ -171,6 +186,7 @@ export function ClientConfigStore() {
|
|||||||
const setAppState = useSetRecoilState<AppStateOptions>(appStateAtom);
|
const setAppState = useSetRecoilState<AppStateOptions>(appStateAtom);
|
||||||
const setGlobalFatalErrorMessage = useSetRecoilState<DisplayableError>(fatalErrorStateAtom);
|
const setGlobalFatalErrorMessage = useSetRecoilState<DisplayableError>(fatalErrorStateAtom);
|
||||||
const setWebsocketService = useSetRecoilState<WebsocketService>(websocketServiceAtom);
|
const setWebsocketService = useSetRecoilState<WebsocketService>(websocketServiceAtom);
|
||||||
|
const [hiddenMessageIds, setHiddenMessageIds] = useRecoilState<string[]>(removedMessageIdsAtom);
|
||||||
|
|
||||||
let ws: WebsocketService;
|
let ws: WebsocketService;
|
||||||
|
|
||||||
@ -259,6 +275,17 @@ export function ClientConfigStore() {
|
|||||||
handleUserRegistration();
|
handleUserRegistration();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleMessageVisibilityChange = (message: MessageVisibilityEvent) => {
|
||||||
|
const { ids, visible } = message;
|
||||||
|
if (visible) {
|
||||||
|
const updatedIds = hiddenMessageIds.filter(id => !ids.includes(id));
|
||||||
|
setHiddenMessageIds(updatedIds);
|
||||||
|
} else {
|
||||||
|
const updatedIds = [...hiddenMessageIds, ...ids];
|
||||||
|
setHiddenMessageIds(updatedIds);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleMessage = (message: SocketEvent) => {
|
const handleMessage = (message: SocketEvent) => {
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case MessageType.ERROR_NEEDS_REGISTRATION:
|
case MessageType.ERROR_NEEDS_REGISTRATION:
|
||||||
@ -287,6 +314,9 @@ export function ClientConfigStore() {
|
|||||||
case MessageType.SYSTEM:
|
case MessageType.SYSTEM:
|
||||||
setChatMessages(currentState => [...currentState, message as ChatEvent]);
|
setChatMessages(currentState => [...currentState, message as ChatEvent]);
|
||||||
break;
|
break;
|
||||||
|
case MessageType.VISIBILITY_UPDATE:
|
||||||
|
handleMessageVisibilityChange(message as MessageVisibilityEvent);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.error('Unknown socket message type: ', message.type);
|
console.error('Unknown socket message type: ', message.type);
|
||||||
}
|
}
|
||||||
|
@ -5,17 +5,17 @@ import { ChatContainer } from '../../chat';
|
|||||||
import s from './Sidebar.module.scss';
|
import s from './Sidebar.module.scss';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
chatMessagesAtom,
|
|
||||||
chatDisplayNameAtom,
|
chatDisplayNameAtom,
|
||||||
chatUserIdAtom,
|
chatUserIdAtom,
|
||||||
isChatModeratorAtom,
|
isChatModeratorAtom,
|
||||||
|
visibleChatMessagesSelector,
|
||||||
} from '../../stores/ClientConfigStore';
|
} from '../../stores/ClientConfigStore';
|
||||||
|
|
||||||
export default function Sidebar() {
|
export default function Sidebar() {
|
||||||
const messages = useRecoilValue<ChatMessage[]>(chatMessagesAtom);
|
|
||||||
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom);
|
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom);
|
||||||
const chatUserId = useRecoilValue<string>(chatUserIdAtom);
|
const chatUserId = useRecoilValue<string>(chatUserIdAtom);
|
||||||
const isChatModerator = useRecoilValue<boolean>(isChatModeratorAtom);
|
const isChatModerator = useRecoilValue<boolean>(isChatModeratorAtom);
|
||||||
|
const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Sider className={s.root} collapsedWidth={0} width={320}>
|
<Sider className={s.root} collapsedWidth={0} width={320}>
|
||||||
|
@ -37,3 +37,8 @@ export interface NameChangeEvent extends SocketEvent {
|
|||||||
user: User;
|
user: User;
|
||||||
oldName: string;
|
oldName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MessageVisibilityEvent extends SocketEvent {
|
||||||
|
visible: boolean;
|
||||||
|
ids: string[];
|
||||||
|
}
|
||||||
|
@ -62,7 +62,7 @@ export const LOGS_WARN = `${API_LOCATION}logs/warnings`;
|
|||||||
export const CHAT_HISTORY = `${API_LOCATION}chat/messages`;
|
export const CHAT_HISTORY = `${API_LOCATION}chat/messages`;
|
||||||
|
|
||||||
// Get chat history
|
// Get chat history
|
||||||
export const UPDATE_CHAT_MESSGAE_VIZ = `${NEXT_PUBLIC_API_HOST}api/chat/messagevisibility`;
|
export const UPDATE_CHAT_MESSGAE_VIZ = `/api/admin/chat/messagevisibility`;
|
||||||
|
|
||||||
// Get all access tokens
|
// Get all access tokens
|
||||||
export const ACCESS_TOKENS = `${API_LOCATION}accesstokens`;
|
export const ACCESS_TOKENS = `${API_LOCATION}accesstokens`;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user