wrap components with error boundaries, minox fixes

This commit is contained in:
nflnkr 2023-10-27 20:38:06 +03:00
parent ebecee8a49
commit 4490536276
9 changed files with 310 additions and 245 deletions

@ -30,8 +30,11 @@ import { ReactComponent as CrossIcon } from "@root/assets/Icons/cross.svg";
import { payCart } from "@root/api/cart"; import { payCart } from "@root/api/cart";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
import { Link, useNavigate } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { withErrorBoundary } from "react-error-boundary";
import { handleComponentError } from "@root/utils/handleComponentError";
import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
export default function Drawers() { function Drawers() {
const [openNotificationsModal, setOpenNotificationsModal] = const [openNotificationsModal, setOpenNotificationsModal] =
useState<boolean>(false); useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
@ -324,3 +327,15 @@ export default function Drawers() {
</Box> </Box>
); );
} }
export default withErrorBoundary(Drawers, {
fallback: (
<Box sx={{
display: "flex",
alignItems: "center",
}}>
<ErrorOutlineIcon color="error" />
</Box>
),
onError: handleComponentError,
})

@ -13,256 +13,263 @@ import { getMessageFromFetchError } from "@frontend/kitui";
import { enqueueSnackbar } from "notistack"; import { enqueueSnackbar } from "notistack";
import { VerificationStatus } from "@root/model/account"; import { VerificationStatus } from "@root/model/account";
import { verify } from "./helper"; import { verify } from "./helper";
import { withErrorBoundary } from "react-error-boundary";
import { handleComponentError } from "@root/utils/handleComponentError";
export default function AccountSettings() { function AccountSettings() {
const theme = useTheme(); const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md")); const upMd = useMediaQuery(theme.breakpoints.up("md"));
const upSm = useMediaQuery(theme.breakpoints.up("sm")); const upSm = useMediaQuery(theme.breakpoints.up("sm"));
const isTablet = useMediaQuery(theme.breakpoints.down(1000)); const isTablet = useMediaQuery(theme.breakpoints.down(1000));
const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isMobile = useMediaQuery(theme.breakpoints.down(600));
const fields = useUserStore((state) => state.settingsFields); const fields = useUserStore((state) => state.settingsFields);
const verificationStatus = useUserStore((state) => state.verificationStatus); const verificationStatus = useUserStore((state) => state.verificationStatus);
const verificationType = useUserStore((state) => state.verificationType); const verificationType = useUserStore((state) => state.verificationType);
const comment = useUserStore((state) => state.comment); const comment = useUserStore((state) => state.comment);
const userId = useUserStore((state) => state.userId) ?? ""; const userId = useUserStore((state) => state.userId) ?? "";
useEffect(() => { useEffect(() => {
verify(userId); verify(userId);
}, []); }, []);
const textFieldProps = { const textFieldProps = {
gap: upMd ? "16px" : "10px", gap: upMd ? "16px" : "10px",
color: "#F2F3F7", color: "#F2F3F7",
bold: true, bold: true,
}; };
const verificationStatusData: Record<VerificationStatus, { text: string; color: string }> = { function handleSendDataClick() {
sendUserData()
.then(() => {
enqueueSnackbar("Информация обновлена");
})
.catch((error) => {
const message = getMessageFromFetchError(error);
if (message) enqueueSnackbar(message);
});
}
return (
<SectionWrapper
maxWidth="lg"
sx={{
mt: "25px",
mb: "70px",
px: isTablet ? (isMobile ? "18px" : "40px") : "20px",
}}
>
<DocumentsDialog />
<Typography variant="h4" mt="20px">
Настройки аккаунта
</Typography>
<Box
sx={{
mt: "40px",
mb: "40px",
backgroundColor: "white",
display: "flex",
flexDirection: "column",
borderRadius: "12px",
p: "20px",
gap: "40px",
boxShadow: cardShadow,
}}
>
<Box
sx={{
display: "flex",
gap: "31px",
justifyContent: "space-between",
flexDirection: upMd ? "row" : "column",
}}
>
<Box
sx={{
display: "grid",
gridAutoFlow: upSm ? "column" : "row",
gridTemplateRows: "repeat(4, auto)",
gridAutoColumns: "1fr",
rowGap: "15px",
columnGap: "31px",
flexGrow: 1,
}}
>
<InputTextfield
TextfieldProps={{
placeholder: "Имя",
value: fields.firstname.value || "",
helperText: fields.firstname.touched && fields.firstname.error,
error: fields.firstname.touched && Boolean(fields.firstname.error),
}}
onChange={(e) => setSettingsField("firstname", e.target.value)}
id="firstname"
label="Имя"
{...textFieldProps}
/>
<InputTextfield
TextfieldProps={{
placeholder: "Фамилия",
value: fields.secondname.value || "",
helperText: fields.secondname.touched && fields.secondname.error,
error: fields.secondname.touched && Boolean(fields.secondname.error),
}}
onChange={(e) => setSettingsField("secondname", e.target.value)}
id="secondname"
label="Фамилия"
{...textFieldProps}
/>
<InputTextfield
TextfieldProps={{
placeholder: "Отчество",
value: fields.middlename.value || "",
helperText: fields.middlename.touched && fields.middlename.error,
error: fields.middlename.touched && Boolean(fields.middlename.error),
}}
onChange={(e) => setSettingsField("middlename", e.target.value)}
id="middlename"
label="Отчество"
{...textFieldProps}
/>
<InputTextfield
TextfieldProps={{
placeholder: "ООО Фирма",
value: fields.orgname.value || "",
helperText: fields.orgname.touched && fields.orgname.error,
error: fields.orgname.touched && Boolean(fields.orgname.error),
}}
onChange={(e) => setSettingsField("orgname", e.target.value)}
id="orgname"
label="Название компании"
{...textFieldProps}
/>
<InputTextfield
TextfieldProps={{
placeholder: "username@penahaub.com",
value: fields.email.value || "",
helperText: fields.email.touched && fields.email.error,
error: fields.email.touched && Boolean(fields.email.error),
}}
onChange={(e) => setSettingsField("email", e.target.value)}
id="email"
label="E-mail"
{...textFieldProps}
/>
<InputTextfield
TextfieldProps={{
placeholder: "+7 900 000 00 00",
value: fields.phoneNumber.value || "",
helperText: fields.phoneNumber.touched && fields.phoneNumber.error,
error: fields.phoneNumber.touched && Boolean(fields.phoneNumber.error),
}}
onChange={(e) => setSettingsField("phoneNumber", e.target.value)}
id="phoneNumber"
label="Телефон"
{...textFieldProps}
/>
<PasswordInput
TextfieldProps={{
placeholder: "Не менее 8 символов",
value: fields.password.value || "",
helperText: fields.password.touched && fields.password.error,
error: fields.password.touched && Boolean(fields.password.error),
autoComplete: "new-password",
}}
onChange={(e) => setSettingsField("password", e.target.value)}
id="password"
label="Пароль"
{...textFieldProps}
/>
</Box>
<Box
sx={{
maxWidth: "246px",
}}
>
<Typography variant="p1">Статус</Typography>
<VerificationIndicator verificationStatus={verificationStatus} sx={{ mt: "16px", p: "14px 7.5px" }} />
{verificationStatus === VerificationStatus.NOT_VERIFICATED && (
<>
<UnderlinedButtonWithIcon
icon={<UploadIcon />}
sx={{ mt: "55px" }}
ButtonProps={{
onClick: () => openDocumentsDialog("juridical"),
}}
>
Загрузить документы для юр лиц
</UnderlinedButtonWithIcon>
<UnderlinedButtonWithIcon
icon={<UploadIcon />}
sx={{ mt: "15px" }}
ButtonProps={{
onClick: () => openDocumentsDialog("nko"),
}}
>
Загрузить документы для НКО
</UnderlinedButtonWithIcon>
</>
)}
{verificationStatus === VerificationStatus.VERIFICATED && (
<UnderlinedButtonWithIcon
icon={<EyeIcon />}
sx={{ mt: "55px" }}
ButtonProps={{
onClick: () => openDocumentsDialog(verificationType),
}}
>
Посмотреть свою верификацию
</UnderlinedButtonWithIcon>
)}
{comment && <p>{comment}</p>}
</Box>
</Box>
<Button
variant="pena-contained-dark"
onClick={handleSendDataClick}
disabled={fields.hasError}
sx={{ alignSelf: "end" }}
>
Сохранить
</Button>
</Box>
</SectionWrapper>
);
}
export default withErrorBoundary(AccountSettings, {
fallback: <Typography mt="8px" textAlign="center">Ошибка при отображении настроек аккаунта</Typography>,
onError: handleComponentError,
})
const verificationStatusData: Record<VerificationStatus, { text: string; color: string; }> = {
verificated: { text: "Верификация пройдена", color: "#0D9F00" }, verificated: { text: "Верификация пройдена", color: "#0D9F00" },
waiting: { text: "В ожидании верификации", color: "#F18956" }, waiting: { text: "В ожидании верификации", color: "#F18956" },
notVerificated: { text: "Не верифицирован", color: "#E02C2C" }, notVerificated: { text: "Не верифицирован", color: "#E02C2C" },
}; };
function handleSendDataClick() { function VerificationIndicator({
sendUserData()
.then(() => {
enqueueSnackbar("Информация обновлена");
})
.catch((error) => {
const message = getMessageFromFetchError(error);
if (message) enqueueSnackbar(message);
});
}
function VerificationIndicator({
verificationStatus, verificationStatus,
sx, sx,
}: { }: {
verificationStatus: VerificationStatus; verificationStatus: VerificationStatus;
sx?: SxProps<Theme>; sx?: SxProps<Theme>;
}) { }) {
return ( return (
<Box
sx={{
py: "14px",
px: "8.5px",
borderWidth: "1px",
borderStyle: "solid",
color: verificationStatusData[verificationStatus].color,
borderColor: verificationStatusData[verificationStatus].color,
borderRadius: "8px",
textAlign: "center",
...sx,
}}
>
<Typography lineHeight="100%">{verificationStatusData[verificationStatus].text}</Typography>
</Box>
);
}
return (
<SectionWrapper
maxWidth="lg"
sx={{
mt: "25px",
mb: "70px",
px: isTablet ? (isMobile ? "18px" : "40px") : "20px",
}}
>
<DocumentsDialog />
<Typography variant="h4" mt="20px">
Настройки аккаунта
</Typography>
<Box
sx={{
mt: "40px",
mb: "40px",
backgroundColor: "white",
display: "flex",
flexDirection: "column",
borderRadius: "12px",
p: "20px",
gap: "40px",
boxShadow: cardShadow,
}}
>
<Box <Box
sx={{ sx={{
display: "flex", py: "14px",
gap: "31px", px: "8.5px",
justifyContent: "space-between", borderWidth: "1px",
flexDirection: upMd ? "row" : "column", borderStyle: "solid",
}} color: verificationStatusData[verificationStatus].color,
borderColor: verificationStatusData[verificationStatus].color,
borderRadius: "8px",
textAlign: "center",
...sx,
}}
> >
<Box <Typography lineHeight="100%">{verificationStatusData[verificationStatus].text}</Typography>
sx={{
display: "grid",
gridAutoFlow: upSm ? "column" : "row",
gridTemplateRows: "repeat(4, auto)",
gridAutoColumns: "1fr",
rowGap: "15px",
columnGap: "31px",
flexGrow: 1,
}}
>
<InputTextfield
TextfieldProps={{
placeholder: "Имя",
value: fields.firstname.value || "",
helperText: fields.firstname.touched && fields.firstname.error,
error: fields.firstname.touched && Boolean(fields.firstname.error),
}}
onChange={(e) => setSettingsField("firstname", e.target.value)}
id="firstname"
label="Имя"
{...textFieldProps}
/>
<InputTextfield
TextfieldProps={{
placeholder: "Фамилия",
value: fields.secondname.value || "",
helperText: fields.secondname.touched && fields.secondname.error,
error: fields.secondname.touched && Boolean(fields.secondname.error),
}}
onChange={(e) => setSettingsField("secondname", e.target.value)}
id="secondname"
label="Фамилия"
{...textFieldProps}
/>
<InputTextfield
TextfieldProps={{
placeholder: "Отчество",
value: fields.middlename.value || "",
helperText: fields.middlename.touched && fields.middlename.error,
error: fields.middlename.touched && Boolean(fields.middlename.error),
}}
onChange={(e) => setSettingsField("middlename", e.target.value)}
id="middlename"
label="Отчество"
{...textFieldProps}
/>
<InputTextfield
TextfieldProps={{
placeholder: "ООО Фирма",
value: fields.orgname.value || "",
helperText: fields.orgname.touched && fields.orgname.error,
error: fields.orgname.touched && Boolean(fields.orgname.error),
}}
onChange={(e) => setSettingsField("orgname", e.target.value)}
id="orgname"
label="Название компании"
{...textFieldProps}
/>
<InputTextfield
TextfieldProps={{
placeholder: "username@penahaub.com",
value: fields.email.value || "",
helperText: fields.email.touched && fields.email.error,
error: fields.email.touched && Boolean(fields.email.error),
}}
onChange={(e) => setSettingsField("email", e.target.value)}
id="email"
label="E-mail"
{...textFieldProps}
/>
<InputTextfield
TextfieldProps={{
placeholder: "+7 900 000 00 00",
value: fields.phoneNumber.value || "",
helperText: fields.phoneNumber.touched && fields.phoneNumber.error,
error: fields.phoneNumber.touched && Boolean(fields.phoneNumber.error),
}}
onChange={(e) => setSettingsField("phoneNumber", e.target.value)}
id="phoneNumber"
label="Телефон"
{...textFieldProps}
/>
<PasswordInput
TextfieldProps={{
placeholder: "Не менее 8 символов",
value: fields.password.value || "",
helperText: fields.password.touched && fields.password.error,
error: fields.password.touched && Boolean(fields.password.error),
autoComplete: "new-password",
}}
onChange={(e) => setSettingsField("password", e.target.value)}
id="password"
label="Пароль"
{...textFieldProps}
/>
</Box>
<Box
sx={{
maxWidth: "246px",
}}
>
<Typography variant="p1">Статус</Typography>
<VerificationIndicator verificationStatus={verificationStatus} sx={{ mt: "16px", p: "14px 7.5px" }} />
{verificationStatus === VerificationStatus.NOT_VERIFICATED && (
<>
<UnderlinedButtonWithIcon
icon={<UploadIcon />}
sx={{ mt: "55px" }}
ButtonProps={{
onClick: () => openDocumentsDialog("juridical"),
}}
>
Загрузить документы для юр лиц
</UnderlinedButtonWithIcon>
<UnderlinedButtonWithIcon
icon={<UploadIcon />}
sx={{ mt: "15px" }}
ButtonProps={{
onClick: () => openDocumentsDialog("nko"),
}}
>
Загрузить документы для НКО
</UnderlinedButtonWithIcon>
</>
)}
{verificationStatus === VerificationStatus.VERIFICATED && (
<UnderlinedButtonWithIcon
icon={<EyeIcon />}
sx={{ mt: "55px" }}
ButtonProps={{
onClick: () => openDocumentsDialog(verificationType),
}}
>
Посмотреть свою верификацию
</UnderlinedButtonWithIcon>
)}
{comment && <p>{comment}</p>}
</Box>
</Box> </Box>
<Button );
variant="pena-contained-dark"
onClick={handleSendDataClick}
disabled={fields.hasError}
sx={{ alignSelf: "end" }}
>
Сохранить
</Button>
</Box>
</SectionWrapper>
);
} }

@ -6,8 +6,10 @@ import CustomWrapper from "./CustomWrapper";
import { useCart } from "@root/utils/hooks/useCart"; import { useCart } from "@root/utils/hooks/useCart";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { usePrevLocation } from "@root/utils/hooks/handleCustomBackNavigation"; import { usePrevLocation } from "@root/utils/hooks/handleCustomBackNavigation";
import { handleComponentError } from "@root/utils/handleComponentError";
import { withErrorBoundary } from "react-error-boundary";
export default function Cart() { function Cart() {
const theme = useTheme(); const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md")); const upMd = useMediaQuery(theme.breakpoints.up("md"));
const isMobile = useMediaQuery(theme.breakpoints.down(550)); const isMobile = useMediaQuery(theme.breakpoints.down(550));
@ -71,3 +73,8 @@ export default function Cart() {
</SectionWrapper> </SectionWrapper>
); );
} }
export default withErrorBoundary(Cart, {
fallback: <Typography mt="8px" textAlign="center">Ошибка при отображении корзины</Typography>,
onError: handleComponentError,
})

@ -5,8 +5,10 @@ import { useHistoryTracker } from "@root/utils/hooks/useHistoryTracker";
import SaveWrapper from "./SaveWrapper"; import SaveWrapper from "./SaveWrapper";
import { useTariffStore } from "@root/stores/tariffs"; import { useTariffStore } from "@root/stores/tariffs";
import { type Tariff } from "@frontend/kitui"; import { type Tariff } from "@frontend/kitui";
import { withErrorBoundary } from "react-error-boundary";
import { handleComponentError } from "@root/utils/handleComponentError";
export default function SavedTariffs() { function SavedTariffs() {
const theme = useTheme(); const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md")); const upMd = useMediaQuery(theme.breakpoints.up("md"));
const isMobile = useMediaQuery(theme.breakpoints.down(550)); const isMobile = useMediaQuery(theme.breakpoints.down(550));
@ -65,3 +67,8 @@ export default function SavedTariffs() {
</SectionWrapper> </SectionWrapper>
); );
} }
export default withErrorBoundary(SavedTariffs, {
fallback: <Typography mt="8px" textAlign="center">Ошибка при отображении сохраненных тарифов</Typography>,
onError: handleComponentError,
})

@ -35,8 +35,10 @@ import {
useTicketMessages, useTicketMessages,
} from "@frontend/kitui"; } from "@frontend/kitui";
import { shownMessage, sendTicketMessage } from "@root/api/ticket"; import { shownMessage, sendTicketMessage } from "@root/api/ticket";
import { withErrorBoundary } from "react-error-boundary";
import { handleComponentError } from "@root/utils/handleComponentError";
export default function SupportChat() { function SupportChat() {
const theme = useTheme(); const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md")); const upMd = useMediaQuery(theme.breakpoints.up("md"));
const isMobile = useMediaQuery(theme.breakpoints.up(460)); const isMobile = useMediaQuery(theme.breakpoints.up(460));
@ -128,7 +130,7 @@ export default function SupportChat() {
async function handleSendMessage() { async function handleSendMessage() {
if (!ticket || !messageField) return; if (!ticket || !messageField) return;
const [_, sendTicketMessageError] = await sendTicketMessage( const [, sendTicketMessageError] = await sendTicketMessage(
ticket.id, ticket.id,
messageField messageField
); );
@ -318,3 +320,8 @@ export default function SupportChat() {
</Box> </Box>
); );
} }
export default withErrorBoundary(SupportChat, {
fallback: <Typography mt="8px" textAlign="center">Не удалось отобразить чат</Typography>,
onError: handleComponentError,
})

@ -5,13 +5,16 @@ import {
Box, Box,
useTheme, useTheme,
Pagination, Pagination,
Typography,
} from "@mui/material"; } from "@mui/material";
import TicketCard from "./TicketCard"; import TicketCard from "./TicketCard";
import { setTicketApiPage, useTicketStore } from "@root/stores/tickets"; import { setTicketApiPage, useTicketStore } from "@root/stores/tickets";
import { Ticket } from "@frontend/kitui"; import { Ticket } from "@frontend/kitui";
import { withErrorBoundary } from "react-error-boundary";
import { handleComponentError } from "@root/utils/handleComponentError";
export default function TicketList() { function TicketList() {
const theme = useTheme(); const theme = useTheme();
const tickets = useTicketStore((state) => state.tickets); const tickets = useTicketStore((state) => state.tickets);
const ticketCount = useTicketStore((state) => state.ticketCount); const ticketCount = useTicketStore((state) => state.ticketCount);
@ -87,3 +90,8 @@ function sortTicketsByUpdateTime(ticket1: Ticket, ticket2: Ticket) {
const date2 = new Date(ticket2.updated_at).getTime(); const date2 = new Date(ticket2.updated_at).getTime();
return date2 - date1; return date2 - date1;
} }
export default withErrorBoundary(TicketList, {
fallback: <Typography mt="8px" textAlign="center">Ошибка загрузки тикетов</Typography>,
onError: handleComponentError,
});

@ -1,4 +1,4 @@
import { Box, IconButton, useMediaQuery, useTheme } from "@mui/material"; import { Box, IconButton, Typography, useMediaQuery, useTheme } from "@mui/material";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import SectionWrapper from "@components/SectionWrapper"; import SectionWrapper from "@components/SectionWrapper";
import { useCustomTariffsStore } from "@root/stores/customTariffs"; import { useCustomTariffsStore } from "@root/stores/customTariffs";
@ -8,8 +8,10 @@ import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import TotalPrice from "@root/components/TotalPrice"; import TotalPrice from "@root/components/TotalPrice";
import { serviceNameByKey } from "@root/utils/serviceKeys"; import { serviceNameByKey } from "@root/utils/serviceKeys";
import { useHistoryTracker } from "@root/utils/hooks/useHistoryTracker"; import { useHistoryTracker } from "@root/utils/hooks/useHistoryTracker";
import { withErrorBoundary } from "react-error-boundary";
import { handleComponentError } from "@root/utils/handleComponentError";
export default function TariffConstructor() { function TariffConstructor() {
const theme = useTheme(); const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md")); const upMd = useMediaQuery(theme.breakpoints.up("md"));
const isTablet = useMediaQuery(theme.breakpoints.down(1000)); const isTablet = useMediaQuery(theme.breakpoints.down(1000));
@ -84,3 +86,8 @@ export default function TariffConstructor() {
</SectionWrapper> </SectionWrapper>
); );
} }
export default withErrorBoundary(TariffConstructor, {
fallback: <Typography mt="8px" textAlign="center">Ошибка при отображении кастомных тарифов</Typography>,
onError: handleComponentError,
})

@ -18,6 +18,8 @@ import { Slider } from "./slider";
import { useCartStore } from "@root/stores/cart"; import { useCartStore } from "@root/stores/cart";
import ArrowBackIcon from "@mui/icons-material/ArrowBack"; import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import { usePrevLocation } from "@root/utils/hooks/handleCustomBackNavigation"; import { usePrevLocation } from "@root/utils/hooks/handleCustomBackNavigation";
import { withErrorBoundary } from "react-error-boundary";
import { handleComponentError } from "@root/utils/handleComponentError";
const subPages = ["Шаблонизатор", "Опросник", "Сокращатель ссылок"]; const subPages = ["Шаблонизатор", "Опросник", "Сокращатель ссылок"];
@ -26,7 +28,7 @@ const StepperText: Record<string, string> = {
time: "Тарифы на время", time: "Тарифы на время",
}; };
export default function TariffPage() { function TariffPage() {
const theme = useTheme(); const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md")); const upMd = useMediaQuery(theme.breakpoints.up("md"));
const isMobile = useMediaQuery(theme.breakpoints.down(600)); const isMobile = useMediaQuery(theme.breakpoints.down(600));
@ -178,3 +180,8 @@ export default function TariffPage() {
</SectionWrapper> </SectionWrapper>
); );
} }
export default withErrorBoundary(TariffPage, {
fallback: <Typography mt="8px" textAlign="center">Ошибка загрузки тарифов</Typography>,
onError: handleComponentError,
})

@ -39,6 +39,6 @@ async function sendErrorsToServer() {
// body: errorsQueue, // body: errorsQueue,
// useToken: true, // useToken: true,
// }); // });
console.log(`Sending ${errorsQueue.length} errors to server`, errorsQueue); console.log(`Fake-sending ${errorsQueue.length} errors to server`, errorsQueue);
errorsQueue = []; errorsQueue = [];
} }