frontPanel/src/ui_kit/FloatingSupportChat/index.tsx

251 lines
6.9 KiB
TypeScript
Raw Normal View History

import {
TicketMessage,
useSSESubscription,
useTicketMessages,
useTicketsFetcher,
} from "@frontend/kitui";
import makeRequest from "@api/makeRequest";
import FloatingSupportChat from "./FloatingSupportChat";
import { useUserStore } from "@root/user";
import { useCallback, useEffect, useState } from "react";
import { sendTicketMessage, shownMessage } from "../../api/ticket";
import { useSSETab } from "../../utils/hooks/useSSETab";
import {
addOrUpdateUnauthMessages,
useTicketStore,
setUnauthIsPreventAutoscroll,
setUnauthTicketMessageFetchState,
cleanAuthTicketData,
setTicketData,
} from "@root/ticket";
import { enqueueSnackbar } from "notistack";
import { getMessageFromFetchError } from "@utils/backendMessageHandler";
import { createTicket } from "@frontend/kitui";
import { setIsMessageSending } from "@root/ticket";
type ModalWarningType =
| "errorType"
| "errorSize"
| "picture"
| "video"
| "audio"
| "document"
| null;
const MAX_FILE_SIZE = 419430400;
const ACCEPT_SEND_FILE_TYPES_MAP = [
".jpeg",
".jpg",
".png",
".mp4",
".doc",
".docx",
".pdf",
".txt",
".xlsx",
".csv",
] as const;
export default () => {
const user = useUserStore((state) => state.user?._id);
const ticket = useTicketStore(
(state) => state[user ? "authData" : "unauthData"],
);
const { isActiveSSETab, updateSSEValue } = useSSETab<TicketMessage[]>(
"ticket",
addOrUpdateUnauthMessages,
);
const [modalWarningType, setModalWarningType] =
useState<ModalWarningType>(null);
const [isChatOpened, setIsChatOpened] = useState<boolean>(false);
const handleChatClickOpen = () => {
setIsChatOpened(true);
};
const handleChatClickClose = () => {
setIsChatOpened(false);
};
const handleChatClickSwitch = () => {
setIsChatOpened((state) => !state);
};
useTicketsFetcher({
url: process.env.REACT_APP_DOMAIN + "/heruvym/getTickets",
ticketsPerPage: 10,
ticketApiPage: 0,
onSuccess: (result) => {
if (result.data?.length) {
const currentTicket = result.data.find(
({ origin }) => !origin.includes("/support"),
);
if (!currentTicket) {
return;
}
setTicketData({
ticketId: currentTicket.id,
sessionId: currentTicket.sess,
});
}
},
onError: (error: Error) => {
const message = getMessageFromFetchError(error);
if (message) enqueueSnackbar(message);
},
onFetchStateChange: () => {},
enabled: Boolean(user),
});
useTicketMessages({
url: process.env.REACT_APP_DOMAIN + "/heruvym/getMessages",
isUnauth: true,
ticketId: ticket.sessionData?.ticketId,
messagesPerPage: ticket.messagesPerPage,
messageApiPage: ticket.apiPage,
onSuccess: useCallback((messages) => {
addOrUpdateUnauthMessages(messages);
}, []),
onError: useCallback((error: Error) => {
const message = getMessageFromFetchError(error);
if (message) enqueueSnackbar(message);
}, []),
onFetchStateChange: setUnauthTicketMessageFetchState,
});
useSSESubscription<TicketMessage>({
enabled: isActiveSSETab && Boolean(ticket.sessionData?.sessionId),
url:
process.env.REACT_APP_DOMAIN +
`/heruvym/ticket?ticket=${ticket.sessionData?.ticketId}&s=${ticket.sessionData?.sessionId}`,
onNewData: (ticketMessages) => {
updateSSEValue(ticketMessages);
addOrUpdateUnauthMessages(ticketMessages);
},
onDisconnect: useCallback(() => {
setUnauthIsPreventAutoscroll(false);
}, []),
marker: "ticket",
});
useEffect(() => {
cleanAuthTicketData();
}, [user]);
useEffect(() => {
if (isChatOpened) {
const newMessages = ticket.messages.filter(
({ shown }) => shown?.me !== 1,
);
newMessages.map(async ({ id }) => {
await shownMessage(id);
});
}
}, [isChatOpened, ticket.messages]);
const sendMessage = async (messageField: string) => {
if (!messageField || ticket.isMessageSending) return false;
let successful = false;
setIsMessageSending(true);
if (!ticket.sessionData?.ticketId) {
try {
const data = await createTicket({
url: process.env.REACT_APP_DOMAIN + "/heruvym/create",
body: {
Title: "Unauth title",
Message: messageField,
},
useToken: Boolean(user),
});
successful = true;
setTicketData({
ticketId: data.Ticket,
sessionId: data.sess,
});
} catch (error: any) {
successful = false;
const errorMessage = getMessageFromFetchError(error);
if (errorMessage) enqueueSnackbar(errorMessage);
}
setIsMessageSending(false);
} else {
const [_, sendTicketMessageError] = await sendTicketMessage(
ticket.sessionData?.ticketId,
messageField,
);
successful = true;
if (sendTicketMessageError) {
successful = false;
enqueueSnackbar(sendTicketMessageError);
}
setIsMessageSending(false);
}
return successful;
};
const sendFile = async (file: File) => {
if (file === undefined) return true;
// const isFileTypeAccepted = ACCEPT_SEND_FILE_TYPES_MAP.some(
// fileType => file.name.toLowerCase().endsWith(fileType)
// );
// if (!isFileTypeAccepted) return setModalWarningType("errorType");
let data;
if (!ticket.sessionData?.ticketId) {
try {
data = await createTicket({
url: process.env.REACT_APP_DOMAIN + "/heruvym/create",
body: {
Title: "Unauth title",
Message: "",
},
useToken: Boolean(user),
});
setTicketData({
ticketId: data.Ticket,
sessionId: data.sess,
});
} catch (error: any) {
const errorMessage = getMessageFromFetchError(error);
if (errorMessage) enqueueSnackbar(errorMessage);
}
setIsMessageSending(false);
}
const ticketId = ticket.sessionData?.ticketId || data?.Ticket;
if (ticketId !== undefined) {
if (file.size > MAX_FILE_SIZE) return setModalWarningType("errorSize");
try {
const body = new FormData();
body.append(file.name, file);
body.append("ticket", ticketId);
await makeRequest({
url: process.env.REACT_APP_DOMAIN + "/heruvym/sendFiles",
body: body,
method: "POST",
});
} catch (error: any) {
const errorMessage = getMessageFromFetchError(error);
if (errorMessage) enqueueSnackbar(errorMessage);
}
return true;
}
};
return (
<FloatingSupportChat
isChatOpened={isChatOpened}
handleChatClickOpen={handleChatClickOpen}
handleChatClickClose={handleChatClickClose}
handleChatClickSwitch={handleChatClickSwitch}
sendMessage={sendMessage}
sendFile={sendFile}
modalWarningType={modalWarningType}
setModalWarningType={setModalWarningType}
/>
);
};