first commit
This commit is contained in:
@@ -0,0 +1,722 @@
|
||||
"use client";
|
||||
import { useState, useEffect, useRef, Suspense } from "react";
|
||||
import Secure from "../components/Secure/Secure";
|
||||
import Alert from "@components/Alert/Alert";
|
||||
import Header from "@components/Header/Header";
|
||||
import { SystemNotificationsProvider } from "@components/SystemNotificationsProvider/SystemNotificationsProvider";
|
||||
import UserMenu from "@components/UserMenu/UserMenu";
|
||||
import style from "./style.module.css";
|
||||
import useWindowSize from "../hooks/WindowSize";
|
||||
import classNames from "classnames";
|
||||
import Textbox from "../components/Textbox/Textbox";
|
||||
import {
|
||||
FindConversationItem,
|
||||
IMessage,
|
||||
ISendMessageResult,
|
||||
MESSAGE_CONVERSATION_TYPES,
|
||||
SendMessageParams,
|
||||
} from "@core/Models/Messages.model";
|
||||
import {
|
||||
markConversationAsRead,
|
||||
messagesFind,
|
||||
messagesFindContacts,
|
||||
messagesFindConversations,
|
||||
sendMessage,
|
||||
} from "./Messages.service";
|
||||
import { useSessionStore } from "@core/Store/Sesion.Store";
|
||||
import Avatar from "../components/Avatar/Avatar";
|
||||
import SendIcon from "@mui/icons-material/Send";
|
||||
import BackIcon from "@mui/icons-material/ArrowBack";
|
||||
import { motion } from "motion/react";
|
||||
import { IconButton } from "@mui/material";
|
||||
import { EVENT_TYPES, useEventHandlerStore } from "@core/Store/EventHandler.Store";
|
||||
import { useAlert } from "@core/Store/Alert.Store";
|
||||
import { getChatClientSocket } from "./Messages.socket";
|
||||
import { Socket } from "socket.io-client";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import "dayjs/locale/es";
|
||||
import { blurElementsOnLoad } from "@core/helpers/blur";
|
||||
import HeaderConfProvider from "../components/HeaderConfProvider/HeaderConfProvider";
|
||||
import SuspenseLoading from "../components/SuspendeLoading/SuspenseLoading";
|
||||
|
||||
dayjs.locale("es");
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
* En la columna de conversaciones, vamos a poner en la parte superior una caja de texto
|
||||
* que permita buscar organizaciones, y en el caso de las organizaciones que el usuario es cliente
|
||||
* se tienen que mostrar los colaboradores de esa organizacion.
|
||||
* Si el usuario es colaborador de la organizacion, se tienen que mostrar los clientes de esa organizacion
|
||||
* y los otros colaboradores de la organizacion.
|
||||
*/
|
||||
|
||||
enum VIEW_FOCUS {
|
||||
CONVERSATIONS = "CONVERSATIONS",
|
||||
MESSAGES = "MESSAGES",
|
||||
}
|
||||
|
||||
enum MESSENGER_VIEWS {
|
||||
CONVERSATIONS = "CONVERSATIONS",
|
||||
MESSAGES = "MESSAGES",
|
||||
BOTH = "BOTH",
|
||||
}
|
||||
|
||||
type ViewClasses =
|
||||
| "MessengerContainer"
|
||||
| "MessengerBody"
|
||||
| "ConversationsContainer"
|
||||
| "ConversationsHeader"
|
||||
| "ConversationsBody"
|
||||
| "MessagesContainer"
|
||||
| "MessagesHeader"
|
||||
| "MessagesBody";
|
||||
|
||||
const classesMap = {
|
||||
CONVERSATIONS: {
|
||||
MessengerContainer: style.MessengerContainer_CONVERSATIONS,
|
||||
MessengerBody: style.MessengerBody_CONVERSATIONS,
|
||||
ConversationsContainer: style.ConversationsContainer_CONVERSATIONS,
|
||||
ConversationsHeader: style.ConversationsHeader_CONVERSATIONS,
|
||||
ConversationsBody: style.ConversationsBody_CONVERSATIONS,
|
||||
MessagesContainer: style.MessagesContainer_CONVERSATIONS,
|
||||
MessagesHeader: style.MessagesHeader_CONVERSATIONS,
|
||||
MessagesBody: style.MessagesBody_CONVERSATIONS,
|
||||
},
|
||||
MESSAGES: {
|
||||
MessengerContainer: style.MessengerContainer_MESSAGES,
|
||||
MessengerBody: style.MessengerBody_MESSAGES,
|
||||
ConversationsContainer: style.ConversationsContainer_MESSAGES,
|
||||
ConversationsHeader: style.ConversationsHeader_MESSAGES,
|
||||
ConversationsBody: style.ConversationsBody_MESSAGES,
|
||||
MessagesContainer: style.MessagesContainer_MESSAGES,
|
||||
MessagesHeader: style.MessagesHeader_MESSAGES,
|
||||
MessagesBody: style.MessagesBody_MESSAGES,
|
||||
},
|
||||
BOTH: {
|
||||
MessengerContainer: style.MessengerContainer_BOTH,
|
||||
MessengerBody: style.MessengerBody_BOTH,
|
||||
ConversationsContainer: style.ConversationsContainer_BOTH,
|
||||
ConversationsHeader: style.ConversationsHeader_BOTH,
|
||||
ConversationsBody: style.ConversationsBody_BOTH,
|
||||
MessagesContainer: style.MessagesContainer_BOTH,
|
||||
MessagesHeader: style.MessagesHeader_BOTH,
|
||||
MessagesBody: style.MessagesBody_BOTH,
|
||||
},
|
||||
};
|
||||
|
||||
interface FindConversationParams {
|
||||
selectConversationId?: string;
|
||||
page?: number;
|
||||
}
|
||||
|
||||
export default function Messages() {
|
||||
const SessionInfo = useSessionStore();
|
||||
const alert = useAlert();
|
||||
const eventHandler = useEventHandlerStore();
|
||||
const [width, height] = useWindowSize();
|
||||
const [view, setView] = useState<MESSENGER_VIEWS>(MESSENGER_VIEWS.BOTH);
|
||||
const [viewFocus, setViewFocus] = useState<VIEW_FOCUS>(VIEW_FOCUS.CONVERSATIONS);
|
||||
const [conversations, setConversations] = useState<FindConversationItem[]>([]);
|
||||
const [messages, setMessages] = useState<IMessage[]>([]);
|
||||
const [selectedConversation, setSelectedConversation] = useState<
|
||||
FindConversationItem | undefined
|
||||
>(undefined);
|
||||
const [filter, setFilter] = useState<string>("");
|
||||
const [chatText, setChatText] = useState<string>("");
|
||||
const chatBodyRef = useRef<HTMLDivElement>(null);
|
||||
const [chatSocket, setChatSocket] = useState<Socket | undefined>(undefined);
|
||||
const [newMessageReceived, setNewMessageReceived] = useState<ISendMessageResult | null>(null);
|
||||
|
||||
const [loadingChatNextPage, setLoadingChatNextPage] = useState<boolean>(false);
|
||||
const [chatPage, setChatPage] = useState<number>(1);
|
||||
|
||||
const getClassName = (name: ViewClasses) => {
|
||||
return classNames(style[name], classesMap[view][name]);
|
||||
};
|
||||
|
||||
const getMessageClassName = (message: IMessage) => {
|
||||
if (message.userId === SessionInfo.userId) {
|
||||
return classNames(style.MessageContainerSender);
|
||||
} else {
|
||||
return classNames(style.MessageContainerReceiver);
|
||||
}
|
||||
};
|
||||
|
||||
const viewManager = () => {
|
||||
if (width < 800) {
|
||||
if (viewFocus === VIEW_FOCUS.CONVERSATIONS) {
|
||||
setView(MESSENGER_VIEWS.CONVERSATIONS);
|
||||
} else if (viewFocus === VIEW_FOCUS.MESSAGES) {
|
||||
setView(MESSENGER_VIEWS.MESSAGES);
|
||||
}
|
||||
} else {
|
||||
setView(MESSENGER_VIEWS.BOTH);
|
||||
}
|
||||
};
|
||||
|
||||
const findContacts = (query: string) => {
|
||||
messagesFindContacts({
|
||||
page: 1,
|
||||
query: query,
|
||||
sessionUser: SessionInfo.userId,
|
||||
limit: 20,
|
||||
})
|
||||
.then((result) => {
|
||||
setConversations(result.data);
|
||||
})
|
||||
.finally(() => {
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
});
|
||||
};
|
||||
|
||||
const findConversations = ({ page = 1, selectConversationId = "" }: FindConversationParams) => {
|
||||
eventHandler.setEventType(EVENT_TYPES.LOADING);
|
||||
messagesFindConversations({
|
||||
page: page,
|
||||
sessionUser: SessionInfo.userId,
|
||||
limit: 20,
|
||||
})
|
||||
.then((result) => {
|
||||
setConversations(result.data);
|
||||
if (selectConversationId != "") {
|
||||
setSelectedConversation(
|
||||
result.data.find((item) => item.conversation.id === selectConversationId)
|
||||
);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
});
|
||||
};
|
||||
|
||||
const loadConversationChat = (markAsRead: boolean = false) => {
|
||||
if (!selectedConversation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedConversation.conversation.id) {
|
||||
setMessages([]);
|
||||
return;
|
||||
}
|
||||
|
||||
messagesFind({
|
||||
conversationId: selectedConversation.conversation.id,
|
||||
sessionUser: SessionInfo.userId,
|
||||
page: 1,
|
||||
limit: 20,
|
||||
})
|
||||
.then((result) => {
|
||||
const messages = result.data;
|
||||
const orderedMessages = messages.sort((a, b) => {
|
||||
return new Date(a.messageDate).getTime() - new Date(b.messageDate).getTime();
|
||||
});
|
||||
setMessages(orderedMessages);
|
||||
setChatPage(1);
|
||||
if (markAsRead) {
|
||||
setTimeout(() => {
|
||||
markCurrentConversationAsReadHandler();
|
||||
markConversationsAsReadHandler();
|
||||
}, 2000);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
chatScrollToEnd();
|
||||
});
|
||||
};
|
||||
|
||||
const loadConversationChatNextPage = () => {
|
||||
if (!selectedConversation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedConversation.conversation.id) {
|
||||
setMessages([]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (loadingChatNextPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoadingChatNextPage(true);
|
||||
|
||||
const chatBody = chatBodyRef.current;
|
||||
const previousScrollHeight = chatBody?.scrollHeight || 0;
|
||||
const previousScrollTop = chatBody?.scrollTop || 0;
|
||||
|
||||
messagesFind({
|
||||
conversationId: selectedConversation.conversation.id,
|
||||
sessionUser: SessionInfo.userId,
|
||||
page: chatPage + 1,
|
||||
limit: 20,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.page > chatPage && result.data.length > 0) {
|
||||
setChatPage(result.page);
|
||||
const messagesResult = [...messages, ...result.data];
|
||||
const orderedMessages = messagesResult.sort((a, b) => {
|
||||
return (
|
||||
new Date(a.messageDate).getTime() - new Date(b.messageDate).getTime()
|
||||
);
|
||||
});
|
||||
setMessages(orderedMessages);
|
||||
//Lleva dobre requestAnimationFrame porque sino no se entera del nuevo tamanio del div.
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const chatBody = chatBodyRef.current;
|
||||
if (chatBody) {
|
||||
const newScrollHeight = chatBody.scrollHeight;
|
||||
const delta = newScrollHeight - previousScrollHeight;
|
||||
chatBody.scrollTop = previousScrollTop + delta;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
setLoadingChatNextPage(false);
|
||||
});
|
||||
};
|
||||
|
||||
const send = () => {
|
||||
if (!selectedConversation) {
|
||||
return;
|
||||
}
|
||||
|
||||
eventHandler.setEventType(EVENT_TYPES.LOADING);
|
||||
|
||||
const conversationType = selectedConversation.conversation.type;
|
||||
|
||||
const sendMessageData: SendMessageParams = {
|
||||
conversationId: selectedConversation.conversation.id
|
||||
? selectedConversation.conversation.id
|
||||
: undefined,
|
||||
type: conversationType,
|
||||
userIdFrom: SessionInfo.userId,
|
||||
userIdTo:
|
||||
conversationType == MESSAGE_CONVERSATION_TYPES.USER_TO_USER
|
||||
? selectedConversation.conversation.userIdTo
|
||||
: undefined,
|
||||
companyId:
|
||||
conversationType == MESSAGE_CONVERSATION_TYPES.USER_TO_ORG
|
||||
? selectedConversation.conversation.companyId
|
||||
: undefined,
|
||||
message: chatText,
|
||||
sessionUser: SessionInfo.userId,
|
||||
};
|
||||
|
||||
sendMessage(sendMessageData)
|
||||
.then((result) => {
|
||||
if (!sendMessageData.conversationId) {
|
||||
findConversations({
|
||||
page: 1,
|
||||
selectConversationId: result.conversation.id,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
loadConversationChat();
|
||||
})
|
||||
.catch((error) => {
|
||||
alert.showError(error.format());
|
||||
})
|
||||
.finally(() => {
|
||||
chatScrollToEnd();
|
||||
setChatText("");
|
||||
eventHandler.setEventType(EVENT_TYPES.SLEEP);
|
||||
});
|
||||
};
|
||||
|
||||
const conversationSelectedHandler = (item: FindConversationItem) => {
|
||||
if (view != MESSENGER_VIEWS.BOTH) {
|
||||
setView(MESSENGER_VIEWS.MESSAGES);
|
||||
setViewFocus(VIEW_FOCUS.MESSAGES);
|
||||
}
|
||||
setSelectedConversation(item);
|
||||
setChatText("");
|
||||
setFilter("");
|
||||
};
|
||||
|
||||
const chatScrollToEnd = () => {
|
||||
requestAnimationFrame(() => {
|
||||
const chatBody = chatBodyRef.current;
|
||||
if (chatBody) {
|
||||
chatBody.scrollTop = chatBody.scrollHeight;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const chatScrollHandler = () => {
|
||||
const chatBody = chatBodyRef.current;
|
||||
if (chatBody && chatBody.scrollTop <= 50) {
|
||||
loadConversationChatNextPage();
|
||||
}
|
||||
};
|
||||
|
||||
const updateOtherConversationsReadedCounter = (data: ISendMessageResult) => {
|
||||
const conversation = conversations.find(
|
||||
(c) => c.conversation.id === data.message.conversationId
|
||||
);
|
||||
if (conversation) {
|
||||
const newMessagesCount = conversation.conversation.newMessages
|
||||
? conversation.conversation.newMessages + 1
|
||||
: 1;
|
||||
conversation.conversation.newMessages = newMessagesCount;
|
||||
const indexConversation = conversations.indexOf(conversation);
|
||||
const conversationsUpdated = [...conversations];
|
||||
conversationsUpdated[indexConversation] = conversation;
|
||||
setConversations(conversationsUpdated);
|
||||
}
|
||||
};
|
||||
|
||||
const newMessageReceivedHandler = (data: ISendMessageResult) => {
|
||||
if (!selectedConversation) {
|
||||
updateOtherConversationsReadedCounter(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedConversation.conversation.id != data.message.conversationId) {
|
||||
updateOtherConversationsReadedCounter(data);
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedMessages = [...messages, ...[data.message]];
|
||||
setMessages(updatedMessages);
|
||||
chatScrollToEnd();
|
||||
};
|
||||
|
||||
const markConversationsAsReadHandler = () => {
|
||||
if (!selectedConversation || !selectedConversation.conversation.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SessionInfo.userId) {
|
||||
return;
|
||||
}
|
||||
|
||||
markConversationAsRead({
|
||||
conversationId: selectedConversation.conversation.id,
|
||||
sessionUser: SessionInfo.userId,
|
||||
});
|
||||
};
|
||||
|
||||
const markCurrentConversationAsReadHandler = () => {
|
||||
if (!selectedConversation || !selectedConversation.conversation.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const conversation = conversations.find(
|
||||
(c) => c.conversation.id === selectedConversation.conversation.id
|
||||
);
|
||||
if (conversation) {
|
||||
conversation.conversation.newMessages = 0;
|
||||
const indexConversation = conversations.indexOf(conversation);
|
||||
const conversationsUpdated = [...conversations];
|
||||
conversationsUpdated[indexConversation] = conversation;
|
||||
setConversations(conversationsUpdated);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
eventHandler.setEventType(EVENT_TYPES.LOADING);
|
||||
setSelectedConversation(undefined);
|
||||
blurElementsOnLoad();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!SessionInfo.userId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filter != "") {
|
||||
findContacts(filter);
|
||||
return;
|
||||
}
|
||||
|
||||
findConversations({ page: 1 });
|
||||
}, [SessionInfo.userId, filter]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!SessionInfo.userId) {
|
||||
if (chatSocket) {
|
||||
chatSocket.off("new_message");
|
||||
chatSocket.disconnect();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
loadConversationChat(true);
|
||||
|
||||
if (chatSocket) {
|
||||
return;
|
||||
}
|
||||
|
||||
const socket = getChatClientSocket(SessionInfo.userId);
|
||||
setChatSocket(socket);
|
||||
}, [SessionInfo.userId, selectedConversation]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!chatSocket) {
|
||||
return;
|
||||
}
|
||||
|
||||
chatSocket.on("new_message", (message: ISendMessageResult) => {
|
||||
setNewMessageReceived(message);
|
||||
});
|
||||
|
||||
return () => {
|
||||
chatSocket.off("new_message");
|
||||
};
|
||||
}, [chatSocket]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!newMessageReceived) {
|
||||
return;
|
||||
}
|
||||
newMessageReceivedHandler(newMessageReceived);
|
||||
}, [newMessageReceived]);
|
||||
|
||||
useEffect(() => {
|
||||
viewManager();
|
||||
}, [width, height]);
|
||||
return (
|
||||
<Suspense fallback={<SuspenseLoading />}>
|
||||
<div>
|
||||
<Header />
|
||||
<HeaderConfProvider />
|
||||
<SystemNotificationsProvider />
|
||||
<Secure>
|
||||
<div className={getClassName("MessengerContainer")}>
|
||||
<div className={getClassName("MessengerBody")}>
|
||||
<div className={getClassName("ConversationsContainer")}>
|
||||
<div className={getClassName("ConversationsHeader")}>
|
||||
<Textbox
|
||||
type="text"
|
||||
value={filter}
|
||||
width="100%"
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className={getClassName("ConversationsBody")}>
|
||||
{conversations.length === 0 && (
|
||||
<div className={style.NoContacts}>
|
||||
No hay conversaciones activas. Puede buscar contactos en
|
||||
el cuadro de busqueda superior.
|
||||
</div>
|
||||
)}
|
||||
{conversations.map((item, index) => {
|
||||
return (
|
||||
<motion.div
|
||||
key={"conversation." + index}
|
||||
className="w-64 h-40 rounded-2xl cursor-pointer"
|
||||
initial={{ backgroundColor: "var(--white)" }}
|
||||
whileHover={{
|
||||
backgroundColor: "var(--gray-lighter)",
|
||||
color: "var(--black)",
|
||||
}} // Azul claro en hover
|
||||
whileTap={{
|
||||
backgroundColor: "var(--wine-dark)",
|
||||
color: "white",
|
||||
}} // Azul más fuerte en tap
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<div
|
||||
className={style.ConversationItem}
|
||||
onClick={() => {
|
||||
conversationSelectedHandler(item);
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
<Avatar
|
||||
src={item.image}
|
||||
alt={item.name}
|
||||
size="medium"
|
||||
border="none"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ width: "100%" }}>
|
||||
<div
|
||||
className={style.ConversationItemTitle}
|
||||
>
|
||||
{item.name}
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
style.ConversationItemDescription
|
||||
}
|
||||
>
|
||||
{item.description}
|
||||
</div>
|
||||
</div>
|
||||
{item.conversation.newMessages > 0 && (
|
||||
<div
|
||||
className={
|
||||
style.ConversationItemNewMessages
|
||||
}
|
||||
>
|
||||
{item.conversation.newMessages > 0
|
||||
? item.conversation.newMessages
|
||||
: "-1"}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div className={getClassName("MessagesContainer")}>
|
||||
{!selectedConversation && (
|
||||
<div className={style.NoConversation}>
|
||||
Seleccione un conversación
|
||||
</div>
|
||||
)}
|
||||
{selectedConversation && (
|
||||
<>
|
||||
<div className={getClassName("MessagesHeader")}>
|
||||
{selectedConversation && (
|
||||
<div className={style.MessageHeaderLeft}>
|
||||
{view === MESSENGER_VIEWS.MESSAGES && (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
setView(
|
||||
MESSENGER_VIEWS.CONVERSATIONS
|
||||
);
|
||||
setViewFocus(
|
||||
VIEW_FOCUS.CONVERSATIONS
|
||||
);
|
||||
}}
|
||||
>
|
||||
<BackIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<Avatar
|
||||
src={selectedConversation.image}
|
||||
alt={selectedConversation.name}
|
||||
size="small"
|
||||
border="none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
className={style.MessageHeaderLeftTitle}
|
||||
>
|
||||
{selectedConversation.name}
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
style.MessageHeaderLeftDescription
|
||||
}
|
||||
>
|
||||
{selectedConversation.description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
ref={chatBodyRef}
|
||||
className={getClassName("MessagesBody")}
|
||||
onScroll={chatScrollHandler}
|
||||
>
|
||||
<div className={style.MessageChatContainer}>
|
||||
{messages.map((item, index) => {
|
||||
const showDate =
|
||||
index === 0 ||
|
||||
!dayjs(item.messageDate)
|
||||
.startOf("day")
|
||||
.isSame(
|
||||
dayjs(
|
||||
messages[
|
||||
index - 1
|
||||
].messageDate.toString()
|
||||
).startOf("day")
|
||||
);
|
||||
|
||||
return (
|
||||
<div key={"message." + index}>
|
||||
{showDate && (
|
||||
<div
|
||||
className={
|
||||
style.MessageChatDateContainer
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={
|
||||
style.MessageChatDate
|
||||
}
|
||||
>
|
||||
{dayjs(
|
||||
item.messageDate
|
||||
).format(
|
||||
"dddd DD [de] MMMM, YYYY"
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={getMessageClassName(
|
||||
item
|
||||
)}
|
||||
>
|
||||
<div
|
||||
key={"message." + index}
|
||||
className={
|
||||
style.MessageChatItem
|
||||
}
|
||||
>
|
||||
<div>{item.message}</div>
|
||||
<div>
|
||||
{dayjs(
|
||||
item.messageDate
|
||||
).format("HH:mm")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className={style.MessageBottomBar}>
|
||||
<Textbox
|
||||
type="text"
|
||||
value={chatText}
|
||||
width="100%"
|
||||
onChange={(e) => {
|
||||
setChatText(e.target.value);
|
||||
}}
|
||||
onKeyUp={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
send();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<IconButton color="success" onClick={send}>
|
||||
<SendIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Secure>
|
||||
|
||||
<UserMenu />
|
||||
<Alert />
|
||||
</div>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user