Remove chat ui library and implement replacement
This commit is contained in:
parent
fa931f35b2
commit
a6d3d1d8a8
5 changed files with 161 additions and 78 deletions
|
|
@ -0,0 +1,20 @@
|
|||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { Box, BoxProps } from "@mui/material";
|
||||
|
||||
interface MessageProps extends BoxProps {
|
||||
message: string;
|
||||
sentTime: string;
|
||||
senderName: string;
|
||||
direction: "outgoing" | "incoming";
|
||||
}
|
||||
|
||||
export const Message: FC<MessageProps> = ({ message, sentTime, senderName, direction, ...props }) => {
|
||||
return (
|
||||
<Box {...props}>
|
||||
<Box className="cs-message__time">{sentTime}{senderName ? ` - ${senderName}` : ''}</Box>
|
||||
<Box className="cs-message__content" dangerouslySetInnerHTML={{ __html: message }} />
|
||||
</Box>
|
||||
)
|
||||
};
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
"use client";
|
||||
|
||||
import { FC, useEffect, useRef, useCallback } from "react";
|
||||
import { Box, styled, BoxProps } from "@mui/material";
|
||||
|
||||
interface MessageListProps extends BoxProps {
|
||||
ticketId: string;
|
||||
}
|
||||
|
||||
export const MessageList: FC<MessageListProps> = ({
|
||||
ticketId,
|
||||
children,
|
||||
...props
|
||||
}: MessageListProps) => {
|
||||
const messageListRef = useRef<HTMLElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
sessionStorage.removeItem("messageListScroll");
|
||||
}, [ticketId]);
|
||||
|
||||
const onRefChange = useCallback(node => {
|
||||
if (node !== null) {
|
||||
// DOM node referenced by ref has changed and exists
|
||||
const scrollTop = parseFloat(sessionStorage.getItem("messageListScroll") ?? "1000000");
|
||||
node.scrollTop = Math.min(scrollTop, node.scrollHeight - node.clientHeight);
|
||||
node.onscroll = () => {
|
||||
sessionStorage.setItem("messageListScroll", node.scrollTop.toPrecision(6));
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
node.scrollTo({
|
||||
top: node.scrollHeight - node.clientHeight,
|
||||
behavior: "smooth",
|
||||
});
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
const InternalMessageList = styled((props: any) => (
|
||||
<Box key="messageList" ref={onRefChange} {...props} />
|
||||
))(({ theme }) => ({
|
||||
overflowX: "hidden",
|
||||
overflowY: "auto",
|
||||
padding: "20px",
|
||||
}));
|
||||
|
||||
return (
|
||||
<InternalMessageList {...props}>
|
||||
{children}
|
||||
</InternalMessageList>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,18 +1,27 @@
|
|||
"use client";
|
||||
|
||||
import { FC, useState, useEffect } from "react";
|
||||
import { FC, useState, useEffect, useRef, memo } from "react";
|
||||
import { getTicketAction, getTicketArticlesAction } from "app/_actions/tickets";
|
||||
import { Grid, Box, Typography } from "@mui/material";
|
||||
import { Grid, Box, Typography, styled, BoxProps } from "@mui/material";
|
||||
import { Button, fonts, colors } from "@link-stack/ui";
|
||||
import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
|
||||
import {
|
||||
MainContainer,
|
||||
ChatContainer,
|
||||
MessageList,
|
||||
Message,
|
||||
ConversationHeader,
|
||||
} from "@chatscope/chat-ui-kit-react";
|
||||
import { ArticleCreateDialog } from "./ArticleCreateDialog";
|
||||
import { Message } from "./Message";
|
||||
import { MessageList } from "./MessageList";
|
||||
|
||||
const ChatContainer = styled((props: BoxProps) => <Box {...props} />)(
|
||||
({ theme }) => ({
|
||||
overflow: "hidden",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}),
|
||||
);
|
||||
|
||||
const ChatHeader = styled((props: any) => <Box {...props} />)(({ theme }) => ({
|
||||
padding: "20px",
|
||||
textAlign: "center",
|
||||
}));
|
||||
|
||||
interface TicketDetailProps {
|
||||
id: string;
|
||||
|
|
@ -26,9 +35,22 @@ export const TicketDetail: FC<TicketDetailProps> = ({ id }) => {
|
|||
const [dialogOpen, setDialogOpen] = useState(false);
|
||||
const [articleKind, setArticleKind] = useState("note");
|
||||
|
||||
const messageListRef = useRef<HTMLElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Reset remembered state
|
||||
sessionStorage.setItem("ticketDetailTicket", "");
|
||||
sessionStorage.setItem("ticketDetailArticles", "");
|
||||
}, [id])
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTicket = async () => {
|
||||
const result = await getTicketAction(id);
|
||||
const resultRaw = JSON.stringify(result);
|
||||
if (resultRaw == sessionStorage.getItem("ticketDetailTicket")) {
|
||||
return; // No change
|
||||
}
|
||||
sessionStorage.setItem("ticketDetailTicket", resultRaw);
|
||||
setTicket(result);
|
||||
};
|
||||
|
||||
|
|
@ -42,6 +64,11 @@ export const TicketDetail: FC<TicketDetailProps> = ({ id }) => {
|
|||
useEffect(() => {
|
||||
const fetchTicketArticles = async () => {
|
||||
const result = await getTicketArticlesAction(id);
|
||||
const resultRaw = JSON.stringify(result);
|
||||
if (resultRaw == sessionStorage.getItem("ticketDetailArticles")) {
|
||||
return; // No change
|
||||
}
|
||||
sessionStorage.setItem("ticketDetailArticles", resultRaw);
|
||||
setTicketArticles(result);
|
||||
};
|
||||
|
||||
|
|
@ -64,71 +91,52 @@ export const TicketDetail: FC<TicketDetailProps> = ({ id }) => {
|
|||
<Box sx={{ height: "100%", width: "100%", background: veryLightGray }}>
|
||||
{shouldRender && (
|
||||
<>
|
||||
<MainContainer>
|
||||
<ChatContainer>
|
||||
<ConversationHeader>
|
||||
<ConversationHeader.Content>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
textAlign: "center",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="h5"
|
||||
sx={{
|
||||
fontFamily: poppins.style.fontFamily,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
{ticket.title}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
fontFamily: roboto.style.fontFamily,
|
||||
fontWeight: 400,
|
||||
}}
|
||||
>{`Ticket #${ticket.number} (created ${new Date(
|
||||
ticket.createdAt,
|
||||
).toLocaleDateString()})`}</Typography>
|
||||
</Box>
|
||||
</ConversationHeader.Content>
|
||||
</ConversationHeader>
|
||||
<MessageList style={{ marginBottom: 80 }}>
|
||||
{ticketArticles.edges.map(({ node: article }: any) => (
|
||||
<Message
|
||||
key={article.id}
|
||||
className={
|
||||
article.internal
|
||||
? "internal-note"
|
||||
: article?.sender?.name === "Agent"
|
||||
? "outgoing-message"
|
||||
: "incoming-message"
|
||||
}
|
||||
model={{
|
||||
message: article.bodyWithUrls,
|
||||
sentTime: article.updatedAt,
|
||||
sender: article.from,
|
||||
direction:
|
||||
article.sender === "Agent" ? "outgoing" : "incoming",
|
||||
position: "single",
|
||||
}}
|
||||
>
|
||||
<Message.Header sender={article.sender?.name} sentTime={new Date(article.updatedAt).toLocaleString()} />
|
||||
</Message>
|
||||
))}
|
||||
</MessageList>
|
||||
</ChatContainer>
|
||||
<ChatContainer className="cs-main-container">
|
||||
<ChatHeader className="cs-conversation-header">
|
||||
<Typography
|
||||
variant="h5"
|
||||
sx={{
|
||||
fontFamily: poppins.style.fontFamily,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
{ticket.title}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
fontFamily: roboto.style.fontFamily,
|
||||
fontWeight: 400,
|
||||
}}
|
||||
>{`Ticket #${ticket.number} (created ${new Date(
|
||||
ticket.createdAt,
|
||||
).toLocaleDateString()})`}</Typography>
|
||||
</ChatHeader>
|
||||
<MessageList ticketId={id}>
|
||||
{ticketArticles.edges.map(({ node: article }: any) => (
|
||||
<Message
|
||||
key={article.id}
|
||||
className={
|
||||
article.internal
|
||||
? "internal-note"
|
||||
: article?.sender?.name === "Agent"
|
||||
? "outgoing-message"
|
||||
: "incoming-message"
|
||||
}
|
||||
message={article.bodyWithUrls}
|
||||
sentTime={new Date(article.updatedAt).toLocaleString()}
|
||||
senderName={article.sender?.name}
|
||||
direction={
|
||||
article.sender === "Agent" ? "outgoing" : "incoming"
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</MessageList>
|
||||
<Box
|
||||
sx={{
|
||||
height: 80,
|
||||
flex: "0 0 80",
|
||||
background: veryLightGray,
|
||||
borderTop: `1px solid ${lightGray}`,
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
width: "100%",
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
|
|
@ -162,7 +170,7 @@ export const TicketDetail: FC<TicketDetailProps> = ({ id }) => {
|
|||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</MainContainer>
|
||||
</ChatContainer>
|
||||
<ArticleCreateDialog
|
||||
ticketID={ticket.internalId}
|
||||
open={dialogOpen}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,15 @@ body {
|
|||
text-size-adjust: none;
|
||||
}
|
||||
|
||||
.cs-message__time {
|
||||
color: #888;
|
||||
font-family: Roboto;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
left: 12px;
|
||||
top: 12px;
|
||||
}
|
||||
|
||||
.internal-note .cs-message__content {
|
||||
background-color: #FFB62088 !important;
|
||||
border: 2px solid #FFB620 !important;
|
||||
|
|
@ -75,8 +84,6 @@ body {
|
|||
|
||||
.cs-conversation-header {
|
||||
background-color: #ddd !important;
|
||||
border: 0 !important;
|
||||
padding: 20px !important;
|
||||
border-bottom: 1px solid #ccc !important;
|
||||
}
|
||||
|
||||
|
|
@ -89,6 +96,5 @@ body {
|
|||
}
|
||||
|
||||
.cs-main-container {
|
||||
border: 0 !important;
|
||||
border-right: 1px solid #ccc !important;
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@
|
|||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chatscope/chat-ui-kit-react": "^2.0.3",
|
||||
"@chatscope/chat-ui-kit-styles": "^1.4.0",
|
||||
"@emotion/cache": "^11.13.1",
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/server": "^11.11.0",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue