import { useCallback, useEffect, useMemo, useState } from "react"; import { TicketMessage, createTicket, shownMessage, useSSESubscription, useTicketMessages, useTicketsFetcher, sendFile as sf } from "@frontend/kitui"; import FloatingSupportChat from "./FloatingSupportChat"; import { useUserStore } from "@root/user"; import { useSSETab } from "../../utils/hooks/useSSETab"; import { addOrUpdateUnauthMessages, cleanAuthTicketData, cleanUnauthTicketData, setIsMessageSending, setTicketData, setUnauthIsPreventAutoscroll, setUnauthTicketMessageFetchState, useTicketStore, } from "@root/ticket"; import { enqueueSnackbar } from "notistack"; import { parseAxiosError } from "@utils/parse-error"; import { selectSendingMethod } from "./utils"; 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"]); //Запись SEE в учётник const { isActiveSSETab, updateSSEValue } = useSSETab( "ticket", addOrUpdateUnauthMessages, ); const [modalWarningType, setModalWarningType] = useState(null); const [isChatOpened, setIsChatOpened] = useState(false); const [sseEnabled, setSseEnabled] = useState(true); const handleChatClickOpen = () => { setIsChatOpened(true); }; const handleChatClickClose = () => { setIsChatOpened(false); }; const handleChatClickSwitch = () => { setIsChatOpened((state) => !state); }; useTicketMessages({ url: `${process.env.REACT_APP_DOMAIN}/heruvym/v1.0.0/getMessages`, isUnauth: true, ticketId: ticket.sessionData?.ticketId, messagesPerPage: ticket.messagesPerPage, messageApiPage: ticket.apiPage, onSuccess: useCallback((messages) => { addOrUpdateUnauthMessages(messages); }, []), onError: useCallback((error: Error) => { if (error.name === "CanceledError") { return; } const [message] = parseAxiosError(error); if (message) enqueueSnackbar(message); }, []), onFetchStateChange: setUnauthTicketMessageFetchState, }); useSSESubscription({ enabled: sseEnabled && isActiveSSETab && Boolean(ticket.sessionData?.sessionId), url: `${process.env.REACT_APP_DOMAIN}/heruvym/v1.0.0/ticket?ticket=${ticket.sessionData?.ticketId}&s=${ticket.sessionData?.sessionId}`, onNewData: (ticketMessages) => { const isTicketClosed = ticketMessages.some( (message) => message.session_id === "close", ); if (isTicketClosed) { cleanAuthTicketData(); if (!user) { cleanUnauthTicketData(); localStorage.removeItem("unauth-ticket"); } return; } updateSSEValue(ticketMessages); addOrUpdateUnauthMessages(ticketMessages); }, onDisconnect: useCallback(() => { setUnauthIsPreventAutoscroll(false); setSseEnabled(false); }, []), marker: "ticket", }); useEffect(() => { cleanAuthTicketData(); setSseEnabled(true); }, [user]); useEffect(() => { if (isChatOpened) { const newMessages = ticket.messages.filter( ({ shown }) => shown?.me !== 1, ); // Находим последнее сообщение, которое не от пользователя const lastNonUserMessage = newMessages .filter(({ user_id }) => (ticket.sessionData?.sessionId || user) !== user_id) .pop(); // Отправляем shown только на последнее сообщение, которое не от пользователя if (lastNonUserMessage) { shownMessage(lastNonUserMessage.id); } } }, [isChatOpened, ticket.messages]); const sendMessage = async (messageField: string) => { if (!messageField || ticket.isMessageSending) return false; setSseEnabled(true); setIsMessageSending(true); let successful = await selectSendingMethod({ messageField }); setIsMessageSending(false); return successful; }; const sendFile = async (file: File | undefined): Promise => { if (file === undefined) return; let ticketId = ticket.sessionData?.ticketId; if (!ticket.sessionData?.ticketId) { const [data, createError] = await createTicket({ message: "", useToken: Boolean(user), systemError: false }); ticketId = data?.Ticket; if (createError || !data) { enqueueSnackbar(`Не удалось создать диалог ${parseAxiosError(createError)}`); return; } else { setTicketData({ ticketId: data.Ticket, sessionId: data.sess }); } setIsMessageSending(false); } if (ticketId !== undefined) { if (file.size > MAX_FILE_SIZE) { setModalWarningType("errorSize"); return; } const [_, sendFileError] = await sf({ticketId, file}); if (sendFileError) { enqueueSnackbar(`Не удалось отправить файл ${parseAxiosError(sendFileError)}`); } } }; return ( ); };