mirror of
https://github.com/owncast/owncast.git
synced 2024-11-21 20:28:15 +03:00
Handle hide/show chat messages via moderation. Closes #1986
This commit is contained in:
parent
c0dc2eb707
commit
ac7e095fdf
5 changed files with 42 additions and 4 deletions
|
@ -5,11 +5,13 @@ import he from 'he';
|
|||
import cn from 'classnames';
|
||||
import { Tooltip } from 'antd';
|
||||
import { LinkOutlined } from '@ant-design/icons';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import s from './ChatUserMessage.module.scss';
|
||||
import { formatTimestamp } from './messageFmt';
|
||||
import { ChatMessage } from '../../../interfaces/chat-message.model';
|
||||
import ChatModerationActionMenu from '../ChatModerationActionMenu/ChatModerationActionMenu';
|
||||
import ChatUserBadge from '../ChatUserBadge/ChatUserBadge';
|
||||
import { accessTokenAtom } from '../../stores/ClientConfigStore';
|
||||
|
||||
interface Props {
|
||||
message: ChatMessage;
|
||||
|
@ -32,6 +34,7 @@ export default function ChatUserMessage({
|
|||
}: Props) {
|
||||
const { id: messageId, body, user, timestamp } = message;
|
||||
const { id: userId, displayName, displayColor } = user;
|
||||
const accessToken = useRecoilValue<string>(accessTokenAtom);
|
||||
|
||||
const color = `var(--theme-color-users-${displayColor})`;
|
||||
const formattedTimestamp = `Sent ${formatTimestamp(timestamp)}`;
|
||||
|
@ -81,7 +84,7 @@ export default function ChatUserMessage({
|
|||
<div className={s.modMenuWrapper}>
|
||||
<ChatModerationActionMenu
|
||||
messageID={messageId}
|
||||
accessToken=""
|
||||
accessToken={accessToken}
|
||||
userID={userId}
|
||||
userDisplayName={displayName}
|
||||
/>
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
ConnectedClientInfoEvent,
|
||||
MessageType,
|
||||
ChatEvent,
|
||||
MessageVisibilityEvent,
|
||||
SocketEvent,
|
||||
} from '../../interfaces/socket-events';
|
||||
|
||||
|
@ -111,6 +112,11 @@ export const clockSkewAtom = atom<Number>({
|
|||
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 state is set.
|
||||
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
|
||||
// a single flattened node.
|
||||
function mergeMeta(meta) {
|
||||
|
@ -171,6 +186,7 @@ export function ClientConfigStore() {
|
|||
const setAppState = useSetRecoilState<AppStateOptions>(appStateAtom);
|
||||
const setGlobalFatalErrorMessage = useSetRecoilState<DisplayableError>(fatalErrorStateAtom);
|
||||
const setWebsocketService = useSetRecoilState<WebsocketService>(websocketServiceAtom);
|
||||
const [hiddenMessageIds, setHiddenMessageIds] = useRecoilState<string[]>(removedMessageIdsAtom);
|
||||
|
||||
let ws: WebsocketService;
|
||||
|
||||
|
@ -259,6 +275,17 @@ export function ClientConfigStore() {
|
|||
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) => {
|
||||
switch (message.type) {
|
||||
case MessageType.ERROR_NEEDS_REGISTRATION:
|
||||
|
@ -287,6 +314,9 @@ export function ClientConfigStore() {
|
|||
case MessageType.SYSTEM:
|
||||
setChatMessages(currentState => [...currentState, message as ChatEvent]);
|
||||
break;
|
||||
case MessageType.VISIBILITY_UPDATE:
|
||||
handleMessageVisibilityChange(message as MessageVisibilityEvent);
|
||||
break;
|
||||
default:
|
||||
console.error('Unknown socket message type: ', message.type);
|
||||
}
|
||||
|
|
|
@ -5,17 +5,17 @@ import { ChatContainer } from '../../chat';
|
|||
import s from './Sidebar.module.scss';
|
||||
|
||||
import {
|
||||
chatMessagesAtom,
|
||||
chatDisplayNameAtom,
|
||||
chatUserIdAtom,
|
||||
isChatModeratorAtom,
|
||||
visibleChatMessagesSelector,
|
||||
} from '../../stores/ClientConfigStore';
|
||||
|
||||
export default function Sidebar() {
|
||||
const messages = useRecoilValue<ChatMessage[]>(chatMessagesAtom);
|
||||
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom);
|
||||
const chatUserId = useRecoilValue<string>(chatUserIdAtom);
|
||||
const isChatModerator = useRecoilValue<boolean>(isChatModeratorAtom);
|
||||
const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector);
|
||||
|
||||
return (
|
||||
<Sider className={s.root} collapsedWidth={0} width={320}>
|
||||
|
|
|
@ -37,3 +37,8 @@ export interface NameChangeEvent extends SocketEvent {
|
|||
user: User;
|
||||
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`;
|
||||
|
||||
// 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
|
||||
export const ACCESS_TOKENS = `${API_LOCATION}accesstokens`;
|
||||
|
|
Loading…
Reference in a new issue