client-web/src/components/Chat/Threads/ThreadContainer.tsx
import React, { useState } from "react";
import {
ChatContainer,
ConversationHeader,
MessageInput,
MessageList,
TypingIndicator,
} from "@chatscope/chat-ui-kit-react";
import { Box, Checkbox, Divider, IconButton, Typography } from "@mui/material";
import CloseIcon from "@mui/icons-material/Close";
import { Message } from "../Messages/Message";
import { TMessageHistory, TUserChatRooms, useStoreState } from "../../../store";
import xmpp from "../../../xmpp";
import * as DOMPurify from "dompurify";
import { SystemMessage } from "../Messages/SystemMessage";
import CustomMessageInput from "./CustomMessageInput";
import { TProfile } from "../../../pages/Profile/types";
import { IMessagePosition } from "../../../pages/ChatInRoom/Chat";
import { getPosition, stripHtml } from "../../../utils";
import { useHistory, useParams } from "react-router";
import { createMainMessageForThread } from "../../../utils/createMessage";
interface ThreadContainerProps {
roomData: {
jid: string;
name: string;
room_background: string;
room_thumbnail: string;
users_cnt: string;
};
handleSetThreadView: (value: boolean) => void;
isThreadView: boolean;
chooseRoom: (jid: string) => void;
profile: TProfile;
currentPickedRoom: TUserChatRooms;
currentRoom: string;
onYReachStart: () => void;
sendFile: (file: File, isReply: boolean) => void;
showInChannel: boolean;
toggleMediaModal: (value: boolean, message?: TMessageHistory) => void;
handleShowInChannel: (event: React.ChangeEvent<HTMLInputElement>) => void;
toggleTransferDialog: (value: boolean, message?: TMessageHistory) => void;
}
const ThreadContainer: React.FC<ThreadContainerProps> = ({
roomData,
handleSetThreadView,
isThreadView,
profile,
currentPickedRoom,
currentRoom,
onYReachStart,
sendFile,
toggleMediaModal,
toggleTransferDialog,
handleShowInChannel,
showInChannel,
}) => {
const currentThreadViewMessage = useStoreState(
(store) => store.currentThreadViewMessage
);
const [myThreadMessage, setMyThreadMessage] = useState("");
const user = useStoreState((store) => store.user);
const userChatRooms = useStoreState((store) => store.userChatRooms);
const messages = useStoreState((state) => state.historyMessages);
const { roomJID } = useParams<{ roomJID: string }>();
const threadWindowMessages = messages.filter(
(item: TMessageHistory) =>
item.roomJID.includes(roomJID) &&
item.data.isReply &&
item.data?.mainMessage?.id === currentThreadViewMessage.id
);
const currentUntrackedChatRoom = useStoreState(
(store) => store.currentUntrackedChatRoom
);
const loaderArchive = useStoreState((store) => store.loaderArchive);
const history = useHistory();
const setThreadMessage = (value: string) => {
setMyThreadMessage(value);
xmpp.isComposing(
user.walletAddress,
roomData.jid,
user.firstName + " " + user.lastName
);
};
const handleChatDetailClick = () => {
history.push("/chatDetails/" + currentUntrackedChatRoom);
};
const handlePaste = (event: any) => {
let item = Array.from(event.clipboardData.items).find((x: any) =>
/^image\//.test(x.type)
);
if (item) {
// @ts-ignore
let blob = item.getAsFile();
sendFile(blob, false);
}
};
const sendThreadMessage = (button: any) => {
if (myThreadMessage.trim().length > 0) {
let userAvatar = "";
if (profile?.profileImage) {
userAvatar = profile?.profileImage;
}
const clearMessageFromHtml = DOMPurify.sanitize(myThreadMessage);
const finalMessageTxt = stripHtml(clearMessageFromHtml);
if (finalMessageTxt.trim().length > 0) {
const data = {
senderFirstName: user.firstName,
senderLastName: user.lastName,
senderWalletAddress: user.walletAddress,
isSystemMessage: false,
tokenAmount: 0,
receiverMessageId: currentThreadViewMessage.data.receiverMessageId,
mucname: roomData.name,
photoURL: user.profileImage,
roomJid: roomData.jid,
isReply: true,
mainMessage: createMainMessageForThread(currentThreadViewMessage),
showInChannel: showInChannel,
push: true,
};
xmpp.sendMessageStanza(currentRoom, finalMessageTxt, data);
}
}
};
return (
<ChatContainer
style={{
borderLeftWidth: "2px",
}}
>
{!!roomData && (
<div is="ConversationHeader">
<ConversationHeader
style={{
height: "70px",
}}
>
<ConversationHeader.Content
datatype="dad"
userName={
<div>
<Typography fontWeight={"bold"}>Thread</Typography>
<Typography>{roomData.name}</Typography>
</div>
}
onClick={handleChatDetailClick}
/>
<ConversationHeader.Actions>
<IconButton
sx={{ color: "black" }}
onClick={() => handleSetThreadView(false)}
>
<CloseIcon />
</IconButton>
</ConversationHeader.Actions>
</ConversationHeader>
{/* Main Message Preview */}
<Box width={"100%"} padding={2}>
<span>
<div>
<Message
onMediaMessageClick={toggleMediaModal}
toggleTransferDialog={toggleTransferDialog}
isThread={isThreadView}
key={currentThreadViewMessage.id}
is={"Message"}
position={{ position: "single", type: "single" }}
message={currentThreadViewMessage}
onMessageButtonClick={sendThreadMessage}
/>
</div>
</span>
</Box>
<Divider>{currentThreadViewMessage.numberOfReplies}</Divider>
</div>
)}
<MessageList
style={{
backgroundImage: currentPickedRoom?.room_background
? `url(${currentPickedRoom.room_background})`
: "white",
backgroundRepeat: "no-repeat",
backgroundSize: "100% 100%",
}}
disableOnYReachWhenNoScroll={true}
typingIndicator={
!!userChatRooms.filter((e) => e.jid === currentRoom)[0]
?.composing && (
<TypingIndicator
style={{ opacity: ".6" }}
content={
userChatRooms.filter((e) => e.jid === currentRoom)[0]?.composing
}
/>
)
}
>
{threadWindowMessages.map((message, index, arr) =>
message.data.isSystemMessage === "false" ? (
<Message
onMediaMessageClick={toggleMediaModal}
toggleTransferDialog={toggleTransferDialog}
isThread={true}
key={message.id}
is={"Message"}
position={getPosition(arr, message, index)}
message={message}
onMessageButtonClick={sendThreadMessage}
/>
) : (
<SystemMessage
key={message.id}
is={"Message"}
message={message}
userJid={xmpp.client?.jid?.toString()}
/>
)
)}
{threadWindowMessages.length <= 0 ||
(!currentRoom && (
<MessageList.Content
style={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
height: "100%",
textAlign: "center",
fontSize: "1.2em",
}}
>
{!loaderArchive ? (
<span>
{!currentRoom && "To get started, please select a chat room."}
</span>
) : (
"Loading..."
)}
</MessageList.Content>
))}
{!loaderArchive && currentRoom && threadWindowMessages.length <= 0 && (
<MessageList.Content
style={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
height: "100%",
textAlign: "center",
fontSize: "1.2em",
}}
>
Message list is empty
</MessageList.Content>
)}
</MessageList>
{!!roomData?.name && (
<div is={"MessageInput"}>
<Divider />
<Box
borderColor={"#D3D3D3"}
height="30px"
alignItems={"center"}
flexDirection={"row"}
display="flex"
width={"100%"}
>
<Checkbox
checked={showInChannel}
onChange={handleShowInChannel}
inputProps={{ "aria-label": "controlled" }}
/>
<Typography>Also send to room</Typography>
</Box>
<CustomMessageInput
onChange={setThreadMessage}
onPaste={handlePaste}
onSend={sendThreadMessage}
placeholder="Type message here"
sendFile={sendFile}
/>
</div>
)}
</ChatContainer>
);
};
export default ThreadContainer;