114 lines
2.8 KiB
TypeScript
114 lines
2.8 KiB
TypeScript
import React, { useEffect, useRef } from "react";
|
|
import { Username } from "./Username";
|
|
import { useChat, useRootContext } from "../../hooks";
|
|
import "./ChatMessage.css";
|
|
import key from "weak-key";
|
|
|
|
interface ChatMessageProps extends ChatSpeakResponse {
|
|
showUser?: boolean;
|
|
}
|
|
|
|
export function ChatMessage({
|
|
avatar,
|
|
showUser = true,
|
|
namecolor,
|
|
username,
|
|
hat,
|
|
text,
|
|
text_html,
|
|
text_censored,
|
|
time,
|
|
timestamp,
|
|
}: ChatMessageProps) {
|
|
const message = {
|
|
avatar,
|
|
namecolor,
|
|
username,
|
|
hat,
|
|
text,
|
|
text_html,
|
|
text_censored,
|
|
time,
|
|
timestamp,
|
|
};
|
|
const {
|
|
username: loggedInUsername,
|
|
admin,
|
|
censored,
|
|
themeColor,
|
|
} = useRootContext();
|
|
const { quote, deleteMessage, quoteMessage } = useChat();
|
|
const content = censored ? text_censored : text_html;
|
|
const hasMention = content.includes(loggedInUsername);
|
|
const mentionStyle = hasMention
|
|
? { backgroundColor: `#${themeColor}55` }
|
|
: {};
|
|
const quoteStyle =
|
|
quote?.username === username && quote?.text === text && quote?.time === time
|
|
? { borderLeft: `2px solid #${themeColor}` }
|
|
: {};
|
|
const style = { ...mentionStyle, ...quoteStyle };
|
|
|
|
return (
|
|
<div className={"ChatMessage"} style={style}>
|
|
{showUser && (
|
|
<div className="ChatMessage-top">
|
|
<Username
|
|
avatar={avatar}
|
|
name={username}
|
|
color={namecolor}
|
|
hat={hat}
|
|
/>
|
|
<div className="ChatMessage-timestamp">{timestamp}</div>
|
|
</div>
|
|
)}
|
|
<div className="ChatMessage-bottom">
|
|
<div>
|
|
<span
|
|
className="ChatMessage-content"
|
|
title={content}
|
|
dangerouslySetInnerHTML={{
|
|
__html: content,
|
|
}}
|
|
/>
|
|
<button
|
|
className="ChatMessage-button quote btn"
|
|
onClick={() => quoteMessage(message)}
|
|
>
|
|
<i className="fas fa-reply"></i>
|
|
</button>
|
|
</div>
|
|
{admin && (
|
|
<button
|
|
className="ChatMessage-button ChatMessage-delete quote btn del"
|
|
onClick={() => deleteMessage(text)}
|
|
>
|
|
<i className="fas fa-trash-alt"></i>
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function ChatMessageList() {
|
|
const { messages } = useChat();
|
|
const messageWrapper = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
messageWrapper.current.scrollTop = messageWrapper.current.scrollHeight;
|
|
}, [messages]);
|
|
|
|
return (
|
|
<div className="ChatMessageList" ref={messageWrapper}>
|
|
{messages.map((message, index) => (
|
|
<ChatMessage
|
|
key={key(message)}
|
|
{...message}
|
|
showUser={message.username !== messages[index - 1]?.username}
|
|
/>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|