Merge branch 'dev' into 'staging'
Dev See merge request frontend/squiz!390
This commit is contained in:
commit
cca1877021
@ -23,6 +23,7 @@ import { InfoPrivilege } from "./pages/InfoPrivilege";
|
|||||||
import AmoTokenExpiredDialog from "./pages/IntegrationsPage/IntegrationsModal/Amo/AmoTokenExpiredDialog";
|
import AmoTokenExpiredDialog from "./pages/IntegrationsPage/IntegrationsModal/Amo/AmoTokenExpiredDialog";
|
||||||
import Landing from "./pages/Landing/Landing";
|
import Landing from "./pages/Landing/Landing";
|
||||||
import Main from "./pages/main";
|
import Main from "./pages/main";
|
||||||
|
import { ErrorBoundary } from "react-error-boundary";
|
||||||
|
|
||||||
const MyQuizzesFull = lazy(() => import("./pages/createQuize/MyQuizzesFull"));
|
const MyQuizzesFull = lazy(() => import("./pages/createQuize/MyQuizzesFull"));
|
||||||
const QuizGallery = lazy(() => import("./pages/createQuize/QuizGallery"));
|
const QuizGallery = lazy(() => import("./pages/createQuize/QuizGallery"));
|
||||||
|
@ -8,6 +8,7 @@ import { clearUserData } from "@root/user";
|
|||||||
import { clearQuizData } from "@root/quizes/store";
|
import { clearQuizData } from "@root/quizes/store";
|
||||||
|
|
||||||
import type { AxiosResponse } from "axios";
|
import type { AxiosResponse } from "axios";
|
||||||
|
import { selectSendingMethod } from "@/ui_kit/FloatingSupportChat/utils";
|
||||||
|
|
||||||
interface MakeRequest {
|
interface MakeRequest {
|
||||||
method?: Method | undefined;
|
method?: Method | undefined;
|
||||||
@ -32,6 +33,11 @@ export const makeRequest = async <TRequest = unknown, TResponse = unknown>(
|
|||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const error = nativeError as AxiosError;
|
const error = nativeError as AxiosError;
|
||||||
|
|
||||||
|
selectSendingMethod({
|
||||||
|
messageField: `status: ${error.response?.status}. Message ${(error.response?.data as ExtendedAxiosResponse)?.message}`,
|
||||||
|
isSnackbar: false,
|
||||||
|
systemError: true
|
||||||
|
});
|
||||||
if (
|
if (
|
||||||
error.response?.status === 400 &&
|
error.response?.status === 400 &&
|
||||||
(error.response?.data as ExtendedAxiosResponse)?.message ===
|
(error.response?.data as ExtendedAxiosResponse)?.message ===
|
||||||
|
@ -12,7 +12,7 @@ export const getTariffs = async (
|
|||||||
try {
|
try {
|
||||||
const tariffs = await makeRequest<never, GetTariffsResponse>({
|
const tariffs = await makeRequest<never, GetTariffsResponse>({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: `${API_URL}?page=${page}&limit=100`,
|
url: `${API_URL}/getList?page=${page}&limit=100`,
|
||||||
});
|
});
|
||||||
return [tariffs];
|
return [tariffs];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
|
@ -18,6 +18,7 @@ const API_URL = `${process.env.REACT_APP_DOMAIN}/heruvym/v1.0.0`;
|
|||||||
export const sendTicketMessage = async (
|
export const sendTicketMessage = async (
|
||||||
ticketId: string,
|
ticketId: string,
|
||||||
message: string,
|
message: string,
|
||||||
|
systemError: boolean
|
||||||
): Promise<[null, string?]> => {
|
): Promise<[null, string?]> => {
|
||||||
try {
|
try {
|
||||||
const sendTicketMessageResponse = await makeRequest<
|
const sendTicketMessageResponse = await makeRequest<
|
||||||
@ -27,7 +28,8 @@ export const sendTicketMessage = async (
|
|||||||
url: `${API_URL}/send`,
|
url: `${API_URL}/send`,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
body: { ticket: ticketId, message: message, lang: "ru", files: [] },
|
body: { ticket: ticketId, message: message, lang: "ru", files: [], system: systemError },
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return [sendTicketMessageResponse];
|
return [sendTicketMessageResponse];
|
||||||
@ -82,11 +84,12 @@ export const sendFile = async (
|
|||||||
export const createTicket = async (
|
export const createTicket = async (
|
||||||
message: string,
|
message: string,
|
||||||
useToken: boolean,
|
useToken: boolean,
|
||||||
|
systemError: boolean
|
||||||
): Promise<[CreateTicketResponse | null, string?]> => {
|
): Promise<[CreateTicketResponse | null, string?]> => {
|
||||||
try {
|
try {
|
||||||
const createdTicket = await createTicketRequest({
|
const createdTicket = await createTicketRequest({
|
||||||
url: `${process.env.REACT_APP_DOMAIN}/heruvym/v1.0.0/create`,
|
url: `${process.env.REACT_APP_DOMAIN}/heruvym/v1.0.0/create`,
|
||||||
body: { Title: "Unauth title", Message: message },
|
body: { Title: "Unauth title", Message: message, system: systemError },
|
||||||
useToken,
|
useToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ import CloseIcon from "@icons/CloseBold";
|
|||||||
|
|
||||||
import type { SnackbarKey } from "notistack";
|
import type { SnackbarKey } from "notistack";
|
||||||
import { CheckFastlink } from "@ui_kit/CheckFastlink";
|
import { CheckFastlink } from "@ui_kit/CheckFastlink";
|
||||||
|
import { ErrorBoundary } from "react-error-boundary";
|
||||||
|
import { handleComponentError } from "./utils/handleComponentError";
|
||||||
|
|
||||||
moment.locale("ru");
|
moment.locale("ru");
|
||||||
polyfillCountryFlagEmojis();
|
polyfillCountryFlagEmojis();
|
||||||
@ -36,6 +38,8 @@ const snackbarAction = (snackbarId: SnackbarKey) => (
|
|||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const ApologyPage = () => <div><p>Что-то пошло не так</p></div>
|
||||||
|
|
||||||
const root = createRoot(document.getElementById("root")!);
|
const root = createRoot(document.getElementById("root")!);
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
@ -60,7 +64,13 @@ root.render(
|
|||||||
style={{ backgroundColor: lightTheme.palette.brightPurple.main }}
|
style={{ backgroundColor: lightTheme.palette.brightPurple.main }}
|
||||||
>
|
>
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
|
|
||||||
|
<ErrorBoundary
|
||||||
|
FallbackComponent={ApologyPage}
|
||||||
|
onError={handleComponentError}
|
||||||
|
>
|
||||||
<App />
|
<App />
|
||||||
|
</ErrorBoundary>
|
||||||
<CheckFastlink />
|
<CheckFastlink />
|
||||||
</SnackbarProvider>
|
</SnackbarProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
@ -128,10 +128,6 @@ export const useAmoIntegration = ({ isModalOpen, isTryRemoveAccount, quizID, que
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
console.log("got questions")
|
|
||||||
console.log(gottenQuestions)
|
|
||||||
console.log("settingsResponse")
|
|
||||||
console.log(settingsResponse.FieldsRule)
|
|
||||||
|
|
||||||
if (key === "Contact") {
|
if (key === "Contact") {
|
||||||
const MAP = settingsResponse.FieldsRule[key as QuestionKeys].ContactRuleMap
|
const MAP = settingsResponse.FieldsRule[key as QuestionKeys].ContactRuleMap
|
||||||
|
@ -74,7 +74,7 @@ function TariffPage() {
|
|||||||
const tariffsList: Tariff[] = [];
|
const tariffsList: Tariff[] = [];
|
||||||
let page = 2
|
let page = 2
|
||||||
const [tariffsResponse, tariffsResponseError] = await getTariffs(page - 1);
|
const [tariffsResponse, tariffsResponseError] = await getTariffs(page - 1);
|
||||||
|
console.log(tariffsResponse)
|
||||||
if (tariffsResponseError || !tariffsResponse) {
|
if (tariffsResponseError || !tariffsResponse) {
|
||||||
return tariffsList;
|
return tariffsList;
|
||||||
}
|
}
|
||||||
@ -182,7 +182,7 @@ function TariffPage() {
|
|||||||
inCart();
|
inCart();
|
||||||
};
|
};
|
||||||
|
|
||||||
const filteredTariffs = tariffs.filter((tariff) => {
|
const filteredTariffs = tariffs.filter((tariff, i) => {
|
||||||
return (
|
return (
|
||||||
tariff.privileges[0].serviceKey === "squiz" &&
|
tariff.privileges[0].serviceKey === "squiz" &&
|
||||||
!tariff.isDeleted &&
|
!tariff.isDeleted &&
|
||||||
|
@ -17,6 +17,8 @@ export const createTariffElements = (
|
|||||||
cc?: boolean,
|
cc?: boolean,
|
||||||
icon?: ReactNode
|
icon?: ReactNode
|
||||||
) => {
|
) => {
|
||||||
|
console.log("start work createTariffElements")
|
||||||
|
console.log("filteredTariffs ", filteredTariffs)
|
||||||
const tariffElements = filteredTariffs
|
const tariffElements = filteredTariffs
|
||||||
.filter((tariff) => tariff.privileges.length > 0)
|
.filter((tariff) => tariff.privileges.length > 0)
|
||||||
.map((tariff, index) => {
|
.map((tariff, index) => {
|
||||||
|
@ -22,6 +22,7 @@ import {
|
|||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import { parseAxiosError } from "@utils/parse-error";
|
import { parseAxiosError } from "@utils/parse-error";
|
||||||
import { createTicket, sendFile as sendFileRequest } from "@api/ticket";
|
import { createTicket, sendFile as sendFileRequest } from "@api/ticket";
|
||||||
|
import { selectSendingMethod } from "./utils";
|
||||||
|
|
||||||
type ModalWarningType =
|
type ModalWarningType =
|
||||||
| "errorType"
|
| "errorType"
|
||||||
@ -47,10 +48,9 @@ const ACCEPT_SEND_FILE_TYPES_MAP = [
|
|||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const user = useUserStore((state) => state.user?._id);
|
const user = useUserStore((state) => state.user?._id);
|
||||||
const ticket = useTicketStore(
|
const ticket = useTicketStore(state => state[user ? "authData" : "unauthData"]);
|
||||||
(state) => state[user ? "authData" : "unauthData"],
|
|
||||||
);
|
|
||||||
|
|
||||||
|
//Запись SEE в учётник
|
||||||
const { isActiveSSETab, updateSSEValue } = useSSETab<TicketMessage[]>(
|
const { isActiveSSETab, updateSSEValue } = useSSETab<TicketMessage[]>(
|
||||||
"ticket",
|
"ticket",
|
||||||
addOrUpdateUnauthMessages,
|
addOrUpdateUnauthMessages,
|
||||||
@ -192,40 +192,13 @@ export default () => {
|
|||||||
|
|
||||||
const sendMessage = async (messageField: string) => {
|
const sendMessage = async (messageField: string) => {
|
||||||
if (!messageField || ticket.isMessageSending) return false;
|
if (!messageField || ticket.isMessageSending) return false;
|
||||||
|
|
||||||
setSseEnabled(true);
|
setSseEnabled(true);
|
||||||
let successful = false;
|
|
||||||
setIsMessageSending(true);
|
setIsMessageSending(true);
|
||||||
if (!ticket.sessionData?.ticketId) {
|
|
||||||
const [data, createError] = await createTicket(
|
|
||||||
messageField,
|
|
||||||
Boolean(user),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (createError || !data) {
|
let successful = await selectSendingMethod({messageField});
|
||||||
successful = false;
|
|
||||||
|
|
||||||
enqueueSnackbar(createError);
|
|
||||||
} else {
|
|
||||||
successful = true;
|
|
||||||
|
|
||||||
setTicketData({ ticketId: data.Ticket, sessionId: data.sess });
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsMessageSending(false);
|
setIsMessageSending(false);
|
||||||
} else {
|
|
||||||
const [_, sendTicketMessageError] = await sendTicketMessage(
|
|
||||||
ticket.sessionData?.ticketId,
|
|
||||||
messageField,
|
|
||||||
);
|
|
||||||
successful = true;
|
|
||||||
|
|
||||||
if (sendTicketMessageError) {
|
|
||||||
successful = false;
|
|
||||||
enqueueSnackbar(sendTicketMessageError);
|
|
||||||
}
|
|
||||||
setIsMessageSending(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return successful;
|
return successful;
|
||||||
};
|
};
|
||||||
const sendFile = async (file: File) => {
|
const sendFile = async (file: File) => {
|
||||||
|
266
src/ui_kit/FloatingSupportChat/useTechnicalSupport.ts
Normal file
266
src/ui_kit/FloatingSupportChat/useTechnicalSupport.ts
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
import { sendTicketMessage, shownMessage } from "@/api/ticket";
|
||||||
|
import { useSSETab } from "@/utils/hooks/useSSETab";
|
||||||
|
import { parseAxiosError } from "@/utils/parse-error";
|
||||||
|
import { TicketMessage, createTicket, useSSESubscription, useTicketMessages, useTicketsFetcher, sendFile as sf } from "@frontend/kitui";
|
||||||
|
|
||||||
|
import {
|
||||||
|
addOrUpdateUnauthMessages,
|
||||||
|
cleanAuthTicketData,
|
||||||
|
cleanUnauthTicketData,
|
||||||
|
setIsMessageSending,
|
||||||
|
setTicketData,
|
||||||
|
setUnauthIsPreventAutoscroll,
|
||||||
|
setUnauthTicketMessageFetchState,
|
||||||
|
useTicketStore,
|
||||||
|
} from "@root/ticket";
|
||||||
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
userId?: string;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ({ userId }:Props) => {
|
||||||
|
const ticket = useTicketStore((state) => state[userId ? "authData" : "unauthData"]);
|
||||||
|
|
||||||
|
const { isActiveSSETab, updateSSEValue } = useSSETab<TicketMessage[]>(
|
||||||
|
"ticket",
|
||||||
|
addOrUpdateUnauthMessages,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [modalWarningType, setModalWarningType] =
|
||||||
|
useState<ModalWarningType>(null);
|
||||||
|
const [isChatOpened, setIsChatOpened] = useState<boolean>(false);
|
||||||
|
const [sseEnabled, setSseEnabled] = useState(true);
|
||||||
|
|
||||||
|
const handleChatClickOpen = () => {
|
||||||
|
setIsChatOpened(true);
|
||||||
|
};
|
||||||
|
const handleChatClickClose = () => {
|
||||||
|
setIsChatOpened(false);
|
||||||
|
};
|
||||||
|
const handleChatClickSwitch = () => {
|
||||||
|
setIsChatOpened((state) => !state);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getGreetingMessage: TicketMessage = useMemo(() => {
|
||||||
|
const workingHoursMessage =
|
||||||
|
"Здравствуйте, задайте ваш вопрос и наш оператор вам ответит в течение 10 минут";
|
||||||
|
const offHoursMessage =
|
||||||
|
"Здравствуйте, задайте ваш вопрос и наш оператор вам ответит в течение 10 минут";
|
||||||
|
const date = new Date();
|
||||||
|
const currentHourUTC = date.getUTCHours();
|
||||||
|
const MscTime = 3; // Москва UTC+3;
|
||||||
|
const moscowHour = (currentHourUTC + MscTime) % 24;
|
||||||
|
const greetingMessage =
|
||||||
|
moscowHour >= 3 && moscowHour < 10
|
||||||
|
? offHoursMessage
|
||||||
|
: workingHoursMessage;
|
||||||
|
|
||||||
|
return {
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
files: [],
|
||||||
|
id: "111",
|
||||||
|
message: greetingMessage,
|
||||||
|
request_screenshot: "",
|
||||||
|
session_id: "greetingMessage",
|
||||||
|
shown: { me: 1 },
|
||||||
|
ticket_id: "111",
|
||||||
|
user_id: "greetingMessage",
|
||||||
|
};
|
||||||
|
}, [isChatOpened]);
|
||||||
|
|
||||||
|
useTicketsFetcher({
|
||||||
|
url: `${process.env.REACT_APP_DOMAIN}/heruvym/v1.0.0/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 = parseAxiosError(error);
|
||||||
|
if (message) enqueueSnackbar(message);
|
||||||
|
},
|
||||||
|
onFetchStateChange: () => {},
|
||||||
|
enabled: Boolean(userId),
|
||||||
|
});
|
||||||
|
|
||||||
|
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<TicketMessage>({
|
||||||
|
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();
|
||||||
|
addOrUpdateUnauthMessages([getGreetingMessage]);
|
||||||
|
if (!userId) {
|
||||||
|
cleanUnauthTicketData();
|
||||||
|
localStorage.removeItem("unauth-ticket");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateSSEValue(ticketMessages);
|
||||||
|
addOrUpdateUnauthMessages(ticketMessages);
|
||||||
|
},
|
||||||
|
onDisconnect: useCallback(() => {
|
||||||
|
setUnauthIsPreventAutoscroll(false);
|
||||||
|
setSseEnabled(false);
|
||||||
|
}, []),
|
||||||
|
marker: "ticket",
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
cleanAuthTicketData();
|
||||||
|
setSseEnabled(true);
|
||||||
|
}, [userId]);
|
||||||
|
|
||||||
|
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;
|
||||||
|
setSseEnabled(true);
|
||||||
|
let successful = false;
|
||||||
|
setIsMessageSending(true);
|
||||||
|
if (!ticket.sessionData?.ticketId) {
|
||||||
|
const [data, createError] = await createTicket(
|
||||||
|
messageField,
|
||||||
|
Boolean(userId),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (createError || !data) {
|
||||||
|
successful = false;
|
||||||
|
|
||||||
|
enqueueSnackbar(createError);
|
||||||
|
} else {
|
||||||
|
successful = true;
|
||||||
|
|
||||||
|
setTicketData({ ticketId: data.Ticket, sessionId: data.sess });
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
let ticketId = ticket.sessionData?.ticketId;
|
||||||
|
if (!ticket.sessionData?.ticketId) {
|
||||||
|
const [data, createError] = await createTicket("", Boolean(userId));
|
||||||
|
ticketId = data?.Ticket;
|
||||||
|
|
||||||
|
if (createError || !data) {
|
||||||
|
enqueueSnackbar(createError);
|
||||||
|
} else {
|
||||||
|
setTicketData({ ticketId: data.Ticket, sessionId: data.sess });
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsMessageSending(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticketId !== undefined) {
|
||||||
|
if (file.size > MAX_FILE_SIZE) return setModalWarningType("errorSize");
|
||||||
|
|
||||||
|
const [_, sendFileError] = await sf(ticketId, file);
|
||||||
|
|
||||||
|
if (sendFileError) {
|
||||||
|
enqueueSnackbar(sendFileError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isChatOpened,
|
||||||
|
handleChatClickOpen,
|
||||||
|
handleChatClickClose,
|
||||||
|
handleChatClickSwitch,
|
||||||
|
sendMessage,
|
||||||
|
sendFile,
|
||||||
|
modalWarningType,
|
||||||
|
setModalWarningType,
|
||||||
|
getGreetingMessage
|
||||||
|
};
|
||||||
|
};
|
54
src/ui_kit/FloatingSupportChat/utils.ts
Normal file
54
src/ui_kit/FloatingSupportChat/utils.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { sendTicketMessage } from "@/api/ticket";
|
||||||
|
import { setTicketData, useTicketStore } from "@/stores/ticket";
|
||||||
|
import { useUserStore } from "@root/user";
|
||||||
|
import { createTicket, sendFile as sendFileRequest } from "@api/ticket";
|
||||||
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
|
||||||
|
interface SelectSendingMethod {
|
||||||
|
messageField: string;
|
||||||
|
isSnackbar?: boolean;
|
||||||
|
systemError?: boolean;
|
||||||
|
|
||||||
|
}
|
||||||
|
export const selectSendingMethod = async ({messageField, isSnackbar = true, systemError = false}: SelectSendingMethod) => {
|
||||||
|
console.log("click")
|
||||||
|
const user = useUserStore.getState().user?._id;
|
||||||
|
const ticket = useTicketStore.getState()[user ? "authData" : "unauthData"];
|
||||||
|
console.log(ticket)
|
||||||
|
|
||||||
|
console.log("click 2")
|
||||||
|
let successful = false;
|
||||||
|
|
||||||
|
if (!ticket.sessionData?.ticketId) {
|
||||||
|
console.log("autorisated 2")
|
||||||
|
const [data, createError] = await createTicket(
|
||||||
|
messageField,
|
||||||
|
Boolean(user),
|
||||||
|
systemError,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (createError || !data) {
|
||||||
|
successful = false;
|
||||||
|
|
||||||
|
if (isSnackbar) enqueueSnackbar(createError);
|
||||||
|
} else {
|
||||||
|
successful = true;
|
||||||
|
|
||||||
|
setTicketData({ ticketId: data.Ticket, sessionId: data.sess });
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const [_, sendTicketMessageError] = await sendTicketMessage(
|
||||||
|
ticket.sessionData?.ticketId,
|
||||||
|
messageField,
|
||||||
|
systemError,
|
||||||
|
);
|
||||||
|
successful = true;
|
||||||
|
|
||||||
|
if (sendTicketMessageError) {
|
||||||
|
successful = false;
|
||||||
|
if (isSnackbar) enqueueSnackbar(sendTicketMessageError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return successful;
|
||||||
|
}
|
47
src/utils/handleComponentError.ts
Normal file
47
src/utils/handleComponentError.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { selectSendingMethod } from "@/ui_kit/FloatingSupportChat/utils";
|
||||||
|
import { ErrorInfo } from "react";
|
||||||
|
|
||||||
|
interface ComponentError {
|
||||||
|
timestamp: number;
|
||||||
|
message: string;
|
||||||
|
callStack: string | undefined;
|
||||||
|
componentStack: string | null | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function handleComponentError(error: Error, info: ErrorInfo) {
|
||||||
|
const componentError: ComponentError = {
|
||||||
|
timestamp: Math.floor(Date.now() / 1000),
|
||||||
|
message: error.message,
|
||||||
|
callStack: error.stack,
|
||||||
|
componentStack: info.componentStack,
|
||||||
|
};
|
||||||
|
|
||||||
|
queueErrorRequest(componentError);
|
||||||
|
}
|
||||||
|
|
||||||
|
let errorsQueue: ComponentError[] = [];
|
||||||
|
let timeoutId: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
|
function queueErrorRequest(error: ComponentError) {
|
||||||
|
errorsQueue.push(error);
|
||||||
|
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
sendErrorsToServer();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendErrorsToServer() {
|
||||||
|
// makeRequest({
|
||||||
|
// url: "",
|
||||||
|
// method: "POST",
|
||||||
|
// body: errorsQueue,
|
||||||
|
// useToken: true,
|
||||||
|
// });
|
||||||
|
selectSendingMethod({
|
||||||
|
messageField: `Fake-sending ${errorsQueue.length} errors to server ${JSON.stringify(errorsQueue)}`,
|
||||||
|
isSnackbar: false,
|
||||||
|
systemError: true
|
||||||
|
});
|
||||||
|
// errorsQueue = [];
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user