refactor: makeRequests decomposed
This commit is contained in:
parent
8e79f16640
commit
9261f3e797
@ -9,7 +9,7 @@ import type {
|
|||||||
RegisterResponse,
|
RegisterResponse,
|
||||||
} from "@frontend/kitui";
|
} from "@frontend/kitui";
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_DOMAIN + "/auth";
|
const API_URL = `${process.env.REACT_APP_DOMAIN}/auth`;
|
||||||
|
|
||||||
export async function register(
|
export async function register(
|
||||||
login: string,
|
login: string,
|
||||||
@ -21,7 +21,7 @@ export async function register(
|
|||||||
RegisterRequest,
|
RegisterRequest,
|
||||||
RegisterResponse
|
RegisterResponse
|
||||||
>({
|
>({
|
||||||
url: apiUrl + "/register",
|
url: `${API_URL}/register`,
|
||||||
body: { login, password, phoneNumber },
|
body: { login, password, phoneNumber },
|
||||||
useToken: false,
|
useToken: false,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
@ -41,7 +41,7 @@ export async function login(
|
|||||||
): Promise<[LoginResponse | null, string?]> {
|
): Promise<[LoginResponse | null, string?]> {
|
||||||
try {
|
try {
|
||||||
const loginResponse = await makeRequest<LoginRequest, LoginResponse>({
|
const loginResponse = await makeRequest<LoginRequest, LoginResponse>({
|
||||||
url: apiUrl + "/login",
|
url: `${API_URL}/login`,
|
||||||
body: { login, password },
|
body: { login, password },
|
||||||
useToken: false,
|
useToken: false,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
@ -60,14 +60,20 @@ export async function recover(
|
|||||||
): Promise<[unknown | null, string?]> {
|
): Promise<[unknown | null, string?]> {
|
||||||
try {
|
try {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
formData.append("email", email);
|
formData.append("email", email);
|
||||||
formData.append("RedirectionURL", process.env.REACT_APP_DOMAIN + "/changepwd")
|
formData.append(
|
||||||
|
"RedirectionURL",
|
||||||
|
`${process.env.REACT_APP_DOMAIN}/changepwd`
|
||||||
|
);
|
||||||
|
|
||||||
const recoverResponse = await makeRequest<unknown, unknown>({
|
const recoverResponse = await makeRequest<unknown, unknown>({
|
||||||
url: process.env.REACT_APP_DOMAIN + "/codeword/recover",
|
url: `${process.env.REACT_APP_DOMAIN}/codeword/recover`,
|
||||||
body: formData,
|
body: formData,
|
||||||
useToken: false,
|
useToken: false,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
return [recoverResponse];
|
return [recoverResponse];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const [error] = parseAxiosError(nativeError);
|
const [error] = parseAxiosError(nativeError);
|
||||||
@ -79,7 +85,7 @@ export async function recover(
|
|||||||
export async function logout(): Promise<[unknown, string?]> {
|
export async function logout(): Promise<[unknown, string?]> {
|
||||||
try {
|
try {
|
||||||
const logoutResponse = await makeRequest<never, void>({
|
const logoutResponse = await makeRequest<never, void>({
|
||||||
url: apiUrl + "/logout",
|
url: `${API_URL}/logout`,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
|
@ -1,26 +1,27 @@
|
|||||||
import { UserAccount } from "@frontend/kitui"
|
import { UserAccount } from "@frontend/kitui";
|
||||||
import makeRequest from "@api/makeRequest"
|
import makeRequest from "@api/makeRequest";
|
||||||
|
|
||||||
import { parseAxiosError } from "@root/utils/parse-error"
|
import { parseAxiosError } from "@root/utils/parse-error";
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_DOMAIN + "/customer"
|
const API_URL = `${process.env.REACT_APP_DOMAIN}/customer`;
|
||||||
|
|
||||||
export async function patchCart(
|
export async function patchCart(
|
||||||
tariffId: string
|
tariffId: string
|
||||||
): Promise<[string[], string?]> {
|
): Promise<[string[], string?]> {
|
||||||
try {
|
try {
|
||||||
const patchCartResponse = await makeRequest<never, UserAccount>({
|
const patchCartResponse = await makeRequest<never, UserAccount>({
|
||||||
url: apiUrl + `/cart?id=${tariffId}`,
|
url: `${API_URL}/cart?id=${tariffId}`,
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
})
|
});
|
||||||
|
|
||||||
return [patchCartResponse.cart]
|
return [patchCartResponse.cart];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
let [error, status] = parseAxiosError(nativeError)
|
let [error, status] = parseAxiosError(nativeError);
|
||||||
if (status === 400 && error.indexOf("invalid id") !== -1) error = "Данный тариф более недоступен"
|
if (status === 400 && error.indexOf("invalid id") !== -1)
|
||||||
|
error = "Данный тариф более недоступен";
|
||||||
|
|
||||||
return [[], `Не удалось добавить товар в корзину. ${error}`]
|
return [[], `Не удалось добавить товар в корзину. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,32 +30,32 @@ export async function deleteCart(
|
|||||||
): Promise<[string[], string?]> {
|
): Promise<[string[], string?]> {
|
||||||
try {
|
try {
|
||||||
const deleteCartResponse = await makeRequest<never, UserAccount>({
|
const deleteCartResponse = await makeRequest<never, UserAccount>({
|
||||||
url: apiUrl + `/cart?id=${tariffId}`,
|
url: `${API_URL}/cart?id=${tariffId}`,
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
})
|
});
|
||||||
|
|
||||||
return [deleteCartResponse.cart]
|
return [deleteCartResponse.cart];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const [error] = parseAxiosError(nativeError)
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
return [[], `Не удалось удалить товар из корзины. ${error}`]
|
return [[], `Не удалось удалить товар из корзины. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function payCart(): Promise<[UserAccount | null, string?]> {
|
export async function payCart(): Promise<[UserAccount | null, string?]> {
|
||||||
try {
|
try {
|
||||||
const payCartResponse = await makeRequest<never, UserAccount>({
|
const payCartResponse = await makeRequest<never, UserAccount>({
|
||||||
url: apiUrl + "/cart/pay",
|
url: `${API_URL}/cart/pay`,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
})
|
});
|
||||||
|
|
||||||
return [payCartResponse]
|
return [payCartResponse];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const [error] = parseAxiosError(nativeError)
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
return [null, `Не удалось оплатить товар из корзины. ${error}`]
|
return [null, `Не удалось оплатить товар из корзины. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,18 +67,18 @@ export async function patchCurrency(
|
|||||||
{ currency: string },
|
{ currency: string },
|
||||||
UserAccount
|
UserAccount
|
||||||
>({
|
>({
|
||||||
url: apiUrl + "/wallet",
|
url: `${API_URL}/wallet`,
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
body: {
|
body: {
|
||||||
currency,
|
currency,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
return [patchCurrencyResponse]
|
return [patchCurrencyResponse];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const [error] = parseAxiosError(nativeError)
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
return [null, `Не удалось изменить валюту. ${error}`]
|
return [null, `Не удалось изменить валюту. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import {Tariff} from "@frontend/kitui"
|
import { Tariff } from "@frontend/kitui";
|
||||||
import {parseAxiosError} from "@root/utils/parse-error"
|
import { parseAxiosError } from "@root/utils/parse-error";
|
||||||
import makeRequest from "@api/makeRequest"
|
import makeRequest from "@api/makeRequest";
|
||||||
|
|
||||||
export interface GetHistoryResponse {
|
export interface GetHistoryResponse {
|
||||||
totalPages: number;
|
totalPages: number;
|
||||||
@ -37,24 +37,30 @@ export type HistoryRecord2 = {
|
|||||||
userId: string;
|
userId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export type KeyValue = { Key: string; Value: string | number };
|
export type KeyValue = { Key: string; Value: string | number };
|
||||||
|
|
||||||
export type RawDetails = {
|
export type RawDetails = {
|
||||||
Key: "tariffs" | "price";
|
Key: "tariffs" | "price";
|
||||||
Value: string | number | KeyValue[][];
|
Value: string | number | KeyValue[][];
|
||||||
}
|
};
|
||||||
|
|
||||||
export async function getHistory(): Promise<[GetHistoryResponse | GetHistoryResponse2 | null, string?]> {
|
const API_URL = `${process.env.REACT_APP_DOMAIN}/customer`;
|
||||||
|
|
||||||
|
export async function getHistory(): Promise<
|
||||||
|
[GetHistoryResponse | GetHistoryResponse2 | null, string?]
|
||||||
|
> {
|
||||||
try {
|
try {
|
||||||
const historyResponse = await makeRequest<never, GetHistoryResponse|GetHistoryResponse2>({
|
const historyResponse = await makeRequest<
|
||||||
url: process.env.REACT_APP_DOMAIN + "/customer/history?page=1&limit=100&type=payCart",
|
never,
|
||||||
method: "get",
|
GetHistoryResponse | GetHistoryResponse2
|
||||||
|
>({
|
||||||
|
url: `${API_URL}/history?page=1&limit=100&type=payCart`,
|
||||||
|
method: "GET",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!Array.isArray(historyResponse.records[0]?.rawDetails)) {
|
if (!Array.isArray(historyResponse.records[0]?.rawDetails)) {
|
||||||
return [historyResponse] as [GetHistoryResponse2]
|
return [historyResponse] as [GetHistoryResponse2];
|
||||||
}
|
}
|
||||||
|
|
||||||
const checked = historyResponse.records.map((data) => {
|
const checked = historyResponse.records.map((data) => {
|
||||||
@ -67,18 +73,56 @@ export async function getHistory(): Promise<[GetHistoryResponse | GetHistoryResp
|
|||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
//data.rawDetails = buffer
|
//data.rawDetails = buffer
|
||||||
const checkedRowDetails = [
|
const checkedRowDetails = [
|
||||||
(data.rawDetails as HistoryRecord["rawDetails"]).find((details) => details.Key === "tariffs") as RawDetails,
|
(data.rawDetails as HistoryRecord["rawDetails"]).find(
|
||||||
(data.rawDetails as HistoryRecord["rawDetails"]).find((details) => details.Key === "price") as KeyValue
|
(details) => details.Key === "tariffs"
|
||||||
]
|
) as RawDetails,
|
||||||
return {...data, rawDetails: checkedRowDetails} as HistoryRecord
|
(data.rawDetails as HistoryRecord["rawDetails"]).find(
|
||||||
})
|
(details) => details.Key === "price"
|
||||||
|
) as KeyValue,
|
||||||
|
];
|
||||||
|
return { ...data, rawDetails: checkedRowDetails } as HistoryRecord;
|
||||||
|
});
|
||||||
|
|
||||||
|
historyResponse.records = checked || [];
|
||||||
historyResponse.records = checked || []
|
return [historyResponse];
|
||||||
return [historyResponse]
|
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const [error] = parseAxiosError(nativeError)
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
return [null, `Не удалось получить историю. ${error}`]
|
return [null, `Не удалось получить историю. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sendReport = async (
|
||||||
|
id: string
|
||||||
|
): Promise<[unknown | null, string?]> => {
|
||||||
|
try {
|
||||||
|
const sendReportResponse = await makeRequest<{ id: string }, unknown>({
|
||||||
|
url: `${API_URL}/sendReport`,
|
||||||
|
method: "POST",
|
||||||
|
body: { id },
|
||||||
|
});
|
||||||
|
|
||||||
|
return [sendReportResponse];
|
||||||
|
} catch (nativeError) {
|
||||||
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
|
return [[], `Не удалось отправить отчёт. ${error}`];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const sendReportById = async (
|
||||||
|
tariffId: string
|
||||||
|
): Promise<[unknown | null, string?]> => {
|
||||||
|
try {
|
||||||
|
const sendReportResponse = await makeRequest<never, unknown>({
|
||||||
|
url: `${API_URL}/sendReport/${tariffId}`,
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
|
||||||
|
return [sendReportResponse];
|
||||||
|
} catch (nativeError) {
|
||||||
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
|
return [[], `Не удалось отправить отчёт. ${error}`];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -5,30 +5,44 @@ import { clearUserData } from "@root/stores/user";
|
|||||||
import { clearCustomTariffs } from "@root/stores/customTariffs";
|
import { clearCustomTariffs } from "@root/stores/customTariffs";
|
||||||
import { clearTickets } from "@root/stores/tickets";
|
import { clearTickets } from "@root/stores/tickets";
|
||||||
import { redirect } from "react-router-dom";
|
import { redirect } from "react-router-dom";
|
||||||
import {setNotEnoughMoneyAmount} from "@stores/cart"
|
import { setNotEnoughMoneyAmount } from "@stores/cart";
|
||||||
|
|
||||||
interface MakeRequest { method?: Method | undefined; url: string; body?: unknown; useToken?: boolean | undefined; contentType?: boolean | undefined; responseType?: ResponseType | undefined; signal?: AbortSignal | undefined; withCredentials?: boolean | undefined; }
|
interface MakeRequest {
|
||||||
|
method?: Method | undefined;
|
||||||
|
url: string;
|
||||||
|
body?: unknown;
|
||||||
|
useToken?: boolean | undefined;
|
||||||
|
contentType?: boolean | undefined;
|
||||||
|
responseType?: ResponseType | undefined;
|
||||||
|
signal?: AbortSignal | undefined;
|
||||||
|
withCredentials?: boolean | undefined;
|
||||||
|
}
|
||||||
interface ErrorResponseData {
|
interface ErrorResponseData {
|
||||||
message?: string;
|
message?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function makeRequest<TRequest = unknown, TResponse = unknown>(data: MakeRequest): Promise<TResponse> {
|
async function makeRequest<TRequest = unknown, TResponse = unknown>(
|
||||||
|
data: MakeRequest
|
||||||
|
): Promise<TResponse> {
|
||||||
try {
|
try {
|
||||||
const response = await KIT.makeRequest<unknown>(data)
|
const response = await KIT.makeRequest<unknown>(data);
|
||||||
|
|
||||||
return response as TResponse
|
return response as TResponse;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const error = e as AxiosError;
|
const error = e as AxiosError;
|
||||||
if (error.response?.status === 400 && (error.response?.data as ErrorResponseData)?.message === "refreshToken is empty") {
|
if (
|
||||||
|
error.response?.status === 400 &&
|
||||||
|
(error.response?.data as ErrorResponseData)?.message ===
|
||||||
|
"refreshToken is empty"
|
||||||
|
) {
|
||||||
clearAuthToken();
|
clearAuthToken();
|
||||||
clearUserData();
|
clearUserData();
|
||||||
clearCustomTariffs();
|
clearCustomTariffs();
|
||||||
clearTickets();
|
clearTickets();
|
||||||
setNotEnoughMoneyAmount(0)
|
setNotEnoughMoneyAmount(0);
|
||||||
redirect("/");
|
redirect("/");
|
||||||
}
|
}
|
||||||
throw e
|
throw e;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
export default makeRequest;
|
export default makeRequest;
|
||||||
|
@ -5,7 +5,7 @@ import { parseAxiosError } from "@root/utils/parse-error";
|
|||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_DOMAIN + "/price";
|
const API_URL = `${process.env.REACT_APP_DOMAIN}/price`;
|
||||||
|
|
||||||
export async function getDiscounts(userId: string | null) {
|
export async function getDiscounts(userId: string | null) {
|
||||||
if (userId === null) {
|
if (userId === null) {
|
||||||
@ -14,7 +14,7 @@ export async function getDiscounts(userId: string | null) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const discountsResponse = await makeRequest<never, GetDiscountsResponse>({
|
const discountsResponse = await makeRequest<never, GetDiscountsResponse>({
|
||||||
url: `${apiUrl}/discount/user/${userId}`,
|
url: `${API_URL}/discount/user/${userId}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
});
|
});
|
||||||
|
@ -1,28 +1,19 @@
|
|||||||
import makeRequest from "@api/makeRequest"
|
import makeRequest from "@api/makeRequest";
|
||||||
|
|
||||||
import { parseAxiosError } from "@utils/parse-error";
|
import { parseAxiosError } from "@utils/parse-error";
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_DOMAIN + "/codeword/promocode";
|
const API_URL = `${process.env.REACT_APP_DOMAIN}/codeword/promocode`;
|
||||||
|
|
||||||
export async function activatePromocode(promocode: string) {
|
export async function activatePromocode(promocode: string) {
|
||||||
try {
|
try {
|
||||||
const response = await makeRequest<
|
const response = await makeRequest<
|
||||||
| {
|
{ codeword: string } | { fastLink: string },
|
||||||
codeword: string;
|
{ greetings: string }
|
||||||
}
|
|
||||||
| {
|
|
||||||
fastLink: string;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
greetings: string;
|
|
||||||
}
|
|
||||||
>({
|
>({
|
||||||
url: apiUrl + "/activate",
|
url: `${API_URL}/activate`,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
contentType: true,
|
contentType: true,
|
||||||
body: {
|
body: { codeword: promocode },
|
||||||
codeword: promocode,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return response.greetings;
|
return response.greetings;
|
||||||
|
@ -1,17 +1,22 @@
|
|||||||
import makeRequest from "@api/makeRequest"
|
import makeRequest from "@api/makeRequest";
|
||||||
import { parseAxiosError } from "@root/utils/parse-error"
|
import { parseAxiosError } from "@root/utils/parse-error";
|
||||||
|
|
||||||
export async function getRecentlyPurchasedTariffs(): Promise<[any | null, string?]> {
|
const API_URL = `${process.env.REACT_APP_DOMAIN}/customer`;
|
||||||
|
|
||||||
|
export async function getRecentlyPurchasedTariffs(): Promise<
|
||||||
|
[any | null, string?]
|
||||||
|
> {
|
||||||
try {
|
try {
|
||||||
const recentlyPurchased = await makeRequest<never, any>({
|
const recentlyPurchased = await makeRequest<never, any>({
|
||||||
url: process.env.REACT_APP_DOMAIN + "/customer/recent",
|
url: `${API_URL}/recent`,
|
||||||
method: "get",
|
method: "GET",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
})
|
});
|
||||||
return [recentlyPurchased]
|
|
||||||
} catch (nativeError) {
|
|
||||||
const [error] = parseAxiosError(nativeError)
|
|
||||||
|
|
||||||
return [null, `Не удалось получить историю. ${error}`]
|
return [recentlyPurchased];
|
||||||
|
} catch (nativeError) {
|
||||||
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
|
return [null, `Не удалось получить историю. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,12 +1,15 @@
|
|||||||
import makeRequest from "@api/makeRequest"
|
import makeRequest from "@api/makeRequest";
|
||||||
import { Tariff } from "@frontend/kitui";
|
import { Tariff } from "@frontend/kitui";
|
||||||
import { parseAxiosError } from "@root/utils/parse-error";
|
import { parseAxiosError } from "@root/utils/parse-error";
|
||||||
|
|
||||||
import type { PrivilegeWithoutPrice, ServiceKeyToPrivilegesMap } from "@root/model/privilege";
|
import type {
|
||||||
|
PrivilegeWithoutPrice,
|
||||||
|
ServiceKeyToPrivilegesMap,
|
||||||
|
} from "@root/model/privilege";
|
||||||
import type { GetTariffsResponse } from "@root/model/tariff";
|
import type { GetTariffsResponse } from "@root/model/tariff";
|
||||||
import { removeTariffFromCart } from "@root/stores/user";
|
import { removeTariffFromCart } from "@root/stores/user";
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_DOMAIN + "/strator"
|
const API_URL = `${process.env.REACT_APP_DOMAIN}/strator`;
|
||||||
|
|
||||||
export async function getTariffs(
|
export async function getTariffs(
|
||||||
apiPage: number,
|
apiPage: number,
|
||||||
@ -15,7 +18,7 @@ export async function getTariffs(
|
|||||||
): Promise<[GetTariffsResponse | null, string?]> {
|
): Promise<[GetTariffsResponse | null, string?]> {
|
||||||
try {
|
try {
|
||||||
const tariffsResponse = await makeRequest<never, GetTariffsResponse>({
|
const tariffsResponse = await makeRequest<never, GetTariffsResponse>({
|
||||||
url: apiUrl + `/tariff?page=${apiPage}&limit=${tariffsPerPage}`,
|
url: `${API_URL}/tariff?page=${apiPage}&limit=${tariffsPerPage}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
signal,
|
signal,
|
||||||
@ -36,10 +39,12 @@ interface CreateTariffBody {
|
|||||||
privileges: PrivilegeWithoutPrice[];
|
privileges: PrivilegeWithoutPrice[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createTariff(tariff: CreateTariffBody): Promise<[Tariff | null, string?]> {
|
export async function createTariff(
|
||||||
|
tariff: CreateTariffBody
|
||||||
|
): Promise<[Tariff | null, string?]> {
|
||||||
try {
|
try {
|
||||||
const createTariffResponse = await makeRequest<CreateTariffBody, Tariff>({
|
const createTariffResponse = await makeRequest<CreateTariffBody, Tariff>({
|
||||||
url: `${apiUrl}/tariff`,
|
url: `${API_URL}/tariff`,
|
||||||
method: "post",
|
method: "post",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
body: tariff,
|
body: tariff,
|
||||||
@ -53,10 +58,12 @@ export async function createTariff(tariff: CreateTariffBody): Promise<[Tariff |
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getTariffById(tariffId: string): Promise<[Tariff | null, string?, number?]> {
|
export async function getTariffById(
|
||||||
|
tariffId: string
|
||||||
|
): Promise<[Tariff | null, string?, number?]> {
|
||||||
try {
|
try {
|
||||||
const getTariffByIdResponse = await makeRequest<never, Tariff>({
|
const getTariffByIdResponse = await makeRequest<never, Tariff>({
|
||||||
url: `${apiUrl}/tariff/${tariffId}`,
|
url: `${API_URL}/tariff/${tariffId}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
});
|
});
|
||||||
@ -73,8 +80,11 @@ export async function getCustomTariffs(
|
|||||||
signal: AbortSignal | undefined
|
signal: AbortSignal | undefined
|
||||||
): Promise<[ServiceKeyToPrivilegesMap | null, string?]> {
|
): Promise<[ServiceKeyToPrivilegesMap | null, string?]> {
|
||||||
try {
|
try {
|
||||||
const customTariffsResponse = await makeRequest<null, ServiceKeyToPrivilegesMap>({
|
const customTariffsResponse = await makeRequest<
|
||||||
url: apiUrl + "/privilege/service",
|
null,
|
||||||
|
ServiceKeyToPrivilegesMap
|
||||||
|
>({
|
||||||
|
url: `${API_URL}/privilege/service`,
|
||||||
signal,
|
signal,
|
||||||
method: "get",
|
method: "get",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
@ -82,7 +92,7 @@ export async function getCustomTariffs(
|
|||||||
|
|
||||||
const tempCustomTariffsResponse = {
|
const tempCustomTariffsResponse = {
|
||||||
...customTariffsResponse,
|
...customTariffsResponse,
|
||||||
squiz: customTariffsResponse.squiz
|
squiz: customTariffsResponse.squiz,
|
||||||
};
|
};
|
||||||
|
|
||||||
return [tempCustomTariffsResponse];
|
return [tempCustomTariffsResponse];
|
||||||
@ -96,13 +106,15 @@ export async function getCustomTariffs(
|
|||||||
export async function getTariffArray(tariffIds: string[] | undefined) {
|
export async function getTariffArray(tariffIds: string[] | undefined) {
|
||||||
if (!tariffIds) return null;
|
if (!tariffIds) return null;
|
||||||
|
|
||||||
const responses = await Promise.allSettled(tariffIds.map(tariffId =>
|
const responses = await Promise.allSettled(
|
||||||
|
tariffIds.map((tariffId) =>
|
||||||
makeRequest<never, Tariff>({
|
makeRequest<never, Tariff>({
|
||||||
url: `${apiUrl}/tariff/${tariffId}`,
|
url: `${API_URL}/tariff/${tariffId}`,
|
||||||
method: "get",
|
method: "get",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
})
|
})
|
||||||
));
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const tariffs: Tariff[] = [];
|
const tariffs: Tariff[] = [];
|
||||||
|
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
import makeRequest from "@api/makeRequest"
|
import makeRequest from "@api/makeRequest";
|
||||||
import { parseAxiosError } from "@root/utils/parse-error";
|
import { parseAxiosError } from "@root/utils/parse-error";
|
||||||
|
|
||||||
import { SendTicketMessageRequest } from "@frontend/kitui";
|
import { SendTicketMessageRequest } from "@frontend/kitui";
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_DOMAIN + "/heruvym";
|
type SendFileResponse = {
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const API_URL = `${process.env.REACT_APP_DOMAIN}/heruvym`;
|
||||||
|
|
||||||
export async function sendTicketMessage(
|
export async function sendTicketMessage(
|
||||||
ticketId: string,
|
ticketId: string,
|
||||||
@ -14,7 +18,7 @@ export async function sendTicketMessage(
|
|||||||
SendTicketMessageRequest,
|
SendTicketMessageRequest,
|
||||||
null
|
null
|
||||||
>({
|
>({
|
||||||
url: `${apiUrl}/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: [] },
|
||||||
@ -31,7 +35,7 @@ export async function sendTicketMessage(
|
|||||||
export async function shownMessage(id: string): Promise<[null, string?]> {
|
export async function shownMessage(id: string): Promise<[null, string?]> {
|
||||||
try {
|
try {
|
||||||
const shownMessageResponse = await makeRequest<{ id: string }, null>({
|
const shownMessageResponse = await makeRequest<{ id: string }, null>({
|
||||||
url: apiUrl + "/shown",
|
url: `${API_URL}/shown`,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
body: { id },
|
body: { id },
|
||||||
@ -44,3 +48,27 @@ export async function shownMessage(id: string): Promise<[null, string?]> {
|
|||||||
return [null, `Не удалось прочесть сообщение. ${error}`];
|
return [null, `Не удалось прочесть сообщение. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sendFile = async (
|
||||||
|
ticketId: string,
|
||||||
|
file: File
|
||||||
|
): Promise<[SendFileResponse | null, string?]> => {
|
||||||
|
try {
|
||||||
|
const body = new FormData();
|
||||||
|
|
||||||
|
body.append(file.name, file);
|
||||||
|
body.append("ticket", ticketId);
|
||||||
|
|
||||||
|
const sendResponse = await makeRequest<FormData, SendFileResponse>({
|
||||||
|
method: "POST",
|
||||||
|
url: `${process.env.REACT_APP_DOMAIN}/sendFiles`,
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
|
||||||
|
return [sendResponse];
|
||||||
|
} catch (nativeError) {
|
||||||
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
|
return [null, `Не удалось отправить файл. ${error}`];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
import { User } from "@frontend/kitui"
|
import { User } from "@frontend/kitui";
|
||||||
import makeRequest from "@api/makeRequest"
|
import makeRequest from "@api/makeRequest";
|
||||||
import { PatchUserRequest } from "@root/model/user"
|
import { PatchUserRequest } from "@root/model/user";
|
||||||
import { parseAxiosError } from "@root/utils/parse-error"
|
import { parseAxiosError } from "@root/utils/parse-error";
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_DOMAIN + "/user"
|
const API_URL = `${process.env.REACT_APP_DOMAIN}/user`;
|
||||||
|
|
||||||
export async function patchUser(
|
export async function patchUser(
|
||||||
user: PatchUserRequest
|
user: PatchUserRequest
|
||||||
): Promise<[User | null, string?]> {
|
): Promise<[User | null, string?]> {
|
||||||
try {
|
try {
|
||||||
const patchUserResponse = await makeRequest<PatchUserRequest, User>({
|
const patchUserResponse = await makeRequest<PatchUserRequest, User>({
|
||||||
url: apiUrl+"/",
|
url: `${API_URL}/`,
|
||||||
contentType: true,
|
contentType: true,
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
withCredentials: false,
|
withCredentials: false,
|
||||||
body: user,
|
body: user,
|
||||||
})
|
});
|
||||||
|
|
||||||
return [patchUserResponse]
|
return [patchUserResponse];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const [error] = parseAxiosError(nativeError)
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
return [null, `Не удалось изменить пользователя. ${error}`]
|
return [null, `Не удалось изменить пользователя. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,49 @@
|
|||||||
import makeRequest from "@api/makeRequest"
|
import makeRequest from "@api/makeRequest";
|
||||||
|
|
||||||
import { jsonToFormdata } from "@root/utils/jsonToFormdata"
|
import { jsonToFormdata } from "@root/utils/jsonToFormdata";
|
||||||
import { parseAxiosError } from "@root/utils/parse-error"
|
import { parseAxiosError } from "@root/utils/parse-error";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
Verification,
|
Verification,
|
||||||
SendDocumentsArgs,
|
SendDocumentsArgs,
|
||||||
UpdateDocumentsArgs,
|
UpdateDocumentsArgs,
|
||||||
} from "@root/model/auth"
|
} from "@root/model/auth";
|
||||||
import { AxiosError } from "axios"
|
|
||||||
|
|
||||||
const apiUrl = process.env.REACT_APP_DOMAIN + "/verification/v1.0.0"
|
const API_URL = `${process.env.REACT_APP_DOMAIN}/verification/v1.0.0/verification`;
|
||||||
|
|
||||||
export async function verification(
|
export async function verification(
|
||||||
userId: string
|
userId: string
|
||||||
): Promise<[Verification | null, string?]> {
|
): Promise<[Verification | null, string?]> {
|
||||||
try {
|
try {
|
||||||
const verificationResponse = await makeRequest<never, Verification>({
|
const verificationResponse = await makeRequest<never, Verification>({
|
||||||
url: apiUrl + "/verification/" + userId,
|
url: `${API_URL}/${userId}`,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
})
|
});
|
||||||
|
|
||||||
verificationResponse.files = verificationResponse.files.map((obj) => {
|
verificationResponse.files = verificationResponse.files.map((obj) => {
|
||||||
obj.url = obj.url.replace("https://hub.pena.digital", process.env.REACT_APP_DOMAIN?.toString() || "").replace("https://shub.pena.digital", process.env.REACT_APP_DOMAIN?.toString() || "")
|
obj.url = obj.url
|
||||||
return obj
|
.replace(
|
||||||
})
|
"https://hub.pena.digital",
|
||||||
|
process.env.REACT_APP_DOMAIN?.toString() || ""
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
"https://shub.pena.digital",
|
||||||
|
process.env.REACT_APP_DOMAIN?.toString() || ""
|
||||||
|
);
|
||||||
|
return obj;
|
||||||
|
});
|
||||||
|
|
||||||
return [verificationResponse]
|
return [verificationResponse];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const err = nativeError as AxiosError
|
const [error, status] = parseAxiosError(nativeError);
|
||||||
if (err.response?.status === 404) {
|
|
||||||
return [null, `нет данных`]
|
|
||||||
}
|
|
||||||
const [error] = parseAxiosError(nativeError)
|
|
||||||
|
|
||||||
return [null, `Ошибка запроса верификации. ${error}`]
|
if (status === 404) {
|
||||||
|
return [null, "нет данных"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [null, `Ошибка запроса верификации. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,39 +52,59 @@ export async function sendDocuments(
|
|||||||
): Promise<[Verification | "OK" | null, string?]> {
|
): Promise<[Verification | "OK" | null, string?]> {
|
||||||
try {
|
try {
|
||||||
const sendDocumentsResponse = await makeRequest<FormData, Verification>({
|
const sendDocumentsResponse = await makeRequest<FormData, Verification>({
|
||||||
url: apiUrl + "/verification",
|
url: API_URL,
|
||||||
method: "POST",
|
method: "POST",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
body: jsonToFormdata({ ...documents, egrule: documents.inn }),
|
body: jsonToFormdata({ ...documents, egrule: documents.inn }),
|
||||||
})
|
});
|
||||||
|
|
||||||
return [sendDocumentsResponse]
|
return [sendDocumentsResponse];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const [error] = parseAxiosError(nativeError)
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
return [null, `Ошибка отправки документов. ${error}`]
|
return [null, `Ошибка отправки документов. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateDocuments(
|
export async function updateDocuments(
|
||||||
documents: UpdateDocumentsArgs
|
documents: UpdateDocumentsArgs
|
||||||
): Promise<[Verification | "OK" | null, string? ]> {
|
): Promise<[Verification | "OK" | null, string?]> {
|
||||||
try {
|
try {
|
||||||
const updateDocumentsResponse = await makeRequest<FormData, Verification>({
|
const updateDocumentsResponse = await makeRequest<FormData, Verification>({
|
||||||
url: apiUrl + "/verification/file",
|
url: `${API_URL}/file`,
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
useToken: true,
|
useToken: true,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
body: jsonToFormdata(
|
body: jsonToFormdata(
|
||||||
documents.inn ? { ...documents, egrule: documents.inn } : documents
|
documents.inn ? { ...documents, egrule: documents.inn } : documents
|
||||||
),
|
),
|
||||||
})
|
});
|
||||||
|
|
||||||
return [updateDocumentsResponse]
|
return [updateDocumentsResponse];
|
||||||
} catch (nativeError) {
|
} catch (nativeError) {
|
||||||
const [error] = parseAxiosError(nativeError)
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
return [null, `Ошибка обновления документов. ${error}`]
|
return [null, `Ошибка обновления документов. ${error}`];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const updateDocument = async (
|
||||||
|
body: FormData
|
||||||
|
): Promise<[Verification | "OK" | null, string?]> => {
|
||||||
|
try {
|
||||||
|
const updateDocumentResponse = await makeRequest<FormData, Verification>({
|
||||||
|
url: API_URL,
|
||||||
|
method: "PATCH",
|
||||||
|
body,
|
||||||
|
useToken: true,
|
||||||
|
withCredentials: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return [updateDocumentResponse];
|
||||||
|
} catch (nativeError) {
|
||||||
|
const [error] = parseAxiosError(nativeError);
|
||||||
|
|
||||||
|
return [null, `Ошибка обновления документа. ${error}`];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -10,7 +10,6 @@ import {
|
|||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import makeRequest from "@api/makeRequest"
|
|
||||||
import {
|
import {
|
||||||
createTicket,
|
createTicket,
|
||||||
getMessageFromFetchError,
|
getMessageFromFetchError,
|
||||||
@ -28,13 +27,17 @@ import {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
WheelEvent
|
WheelEvent,
|
||||||
} from "react";
|
} from "react";
|
||||||
import ChatMessage from "../ChatMessage";
|
import ChatMessage from "../ChatMessage";
|
||||||
import SendIcon from "../icons/SendIcon";
|
import SendIcon from "../icons/SendIcon";
|
||||||
import ArrowLeft from "@root/assets/Icons/arrowLeft";
|
import ArrowLeft from "@root/assets/Icons/arrowLeft";
|
||||||
import UserCircleIcon from "./UserCircleIcon";
|
import UserCircleIcon from "./UserCircleIcon";
|
||||||
import { sendTicketMessage, shownMessage } from "@root/api/ticket";
|
import {
|
||||||
|
sendTicketMessage,
|
||||||
|
shownMessage,
|
||||||
|
sendFile as sendFileRequest,
|
||||||
|
} from "@root/api/ticket";
|
||||||
import { useSSETab } from "@root/utils/hooks/useSSETab";
|
import { useSSETab } from "@root/utils/hooks/useSSETab";
|
||||||
import {
|
import {
|
||||||
ACCEPT_SEND_MEDIA_TYPES_MAP,
|
ACCEPT_SEND_MEDIA_TYPES_MAP,
|
||||||
@ -115,7 +118,7 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
? offHoursMessage
|
? offHoursMessage
|
||||||
: workingHoursMessage;
|
: workingHoursMessage;
|
||||||
|
|
||||||
return ({
|
return {
|
||||||
created_at: new Date().toISOString(),
|
created_at: new Date().toISOString(),
|
||||||
files: [],
|
files: [],
|
||||||
id: "111",
|
id: "111",
|
||||||
@ -125,8 +128,7 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
shown: { me: 1 },
|
shown: { me: 1 },
|
||||||
ticket_id: "111",
|
ticket_id: "111",
|
||||||
user_id: "greetingMessage",
|
user_id: "greetingMessage",
|
||||||
});
|
};
|
||||||
|
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
useTicketMessages({
|
useTicketMessages({
|
||||||
@ -182,7 +184,8 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
onSuccess: (result) => {
|
onSuccess: (result) => {
|
||||||
if (result.data?.length) {
|
if (result.data?.length) {
|
||||||
const currentTicket = result.data.find(
|
const currentTicket = result.data.find(
|
||||||
({ origin, state }) => !origin.includes("/support") && state !== "close"
|
({ origin, state }) =>
|
||||||
|
!origin.includes("/support") && state !== "close"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!currentTicket) {
|
if (!currentTicket) {
|
||||||
@ -199,7 +202,7 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
const message = getMessageFromFetchError(error);
|
const message = getMessageFromFetchError(error);
|
||||||
if (message) enqueueSnackbar(message);
|
if (message) enqueueSnackbar(message);
|
||||||
},
|
},
|
||||||
onFetchStateChange: () => { },
|
onFetchStateChange: () => {},
|
||||||
enabled: Boolean(user),
|
enabled: Boolean(user),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -228,7 +231,6 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
function scrollOnNewMessage() {
|
function scrollOnNewMessage() {
|
||||||
if (!chatBoxRef.current) return;
|
if (!chatBoxRef.current) return;
|
||||||
@ -353,19 +355,15 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
const ticketId = ticket.sessionData?.ticketId || data?.Ticket;
|
const ticketId = ticket.sessionData?.ticketId || data?.Ticket;
|
||||||
if (ticketId !== undefined) {
|
if (ticketId !== undefined) {
|
||||||
if (file.size > MAX_FILE_SIZE) return setModalWarningType("errorSize");
|
if (file.size > MAX_FILE_SIZE) return setModalWarningType("errorSize");
|
||||||
try {
|
|
||||||
const body = new FormData();
|
|
||||||
|
|
||||||
body.append(file.name, file);
|
const [, sendFileError] = await sendFileRequest(
|
||||||
body.append("ticket", ticketId);
|
ticketId,
|
||||||
await makeRequest({
|
file
|
||||||
url: process.env.REACT_APP_DOMAIN + "/heruvym/sendFiles",
|
);
|
||||||
body: body,
|
|
||||||
method: "POST",
|
if(sendFileError) {
|
||||||
});
|
enqueueSnackbar(sendFileError)
|
||||||
} catch (error: any) {
|
}
|
||||||
const errorMessage = getMessageFromFetchError(error);
|
|
||||||
if (errorMessage) enqueueSnackbar(errorMessage);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -547,8 +545,13 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{!ticket.sessionData?.ticketId && (
|
{!ticket.sessionData?.ticketId && (
|
||||||
<ChatMessage unAuthenticated text={getGreetingMessage.message} createdAt={getGreetingMessage.created_at} isSelf={false} />)
|
<ChatMessage
|
||||||
}
|
unAuthenticated
|
||||||
|
text={getGreetingMessage.message}
|
||||||
|
createdAt={getGreetingMessage.created_at}
|
||||||
|
isSelf={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<FormControl fullWidth sx={{ borderTop: "1px solid black" }}>
|
<FormControl fullWidth sx={{ borderTop: "1px solid black" }}>
|
||||||
<InputBase
|
<InputBase
|
||||||
|
@ -1,77 +1,79 @@
|
|||||||
import axios from "axios"
|
import axios from "axios";
|
||||||
import { Box, IconButton, SxProps, Theme, Typography, useTheme } from "@mui/material"
|
import {
|
||||||
import { Document, Page } from "react-pdf"
|
Box,
|
||||||
import { Buffer } from "buffer"
|
IconButton,
|
||||||
import { downloadFileToDevice } from "@root/utils/downloadFileToDevice"
|
SxProps,
|
||||||
import EditIcon from "@mui/icons-material/Edit"
|
Theme,
|
||||||
import { ChangeEvent, useRef } from "react"
|
Typography,
|
||||||
import { SendDocumentsArgs, Verification } from "@root/model/auth"
|
useTheme,
|
||||||
import makeRequest from "@api/makeRequest"
|
} from "@mui/material";
|
||||||
import { jsonToFormdata } from "@utils/jsonToFormdata"
|
import { Document, Page } from "react-pdf";
|
||||||
import { parseAxiosError } from "@utils/parse-error"
|
import { Buffer } from "buffer";
|
||||||
import { readFile } from "@root/utils/readFile"
|
import { downloadFileToDevice } from "@root/utils/downloadFileToDevice";
|
||||||
import { enqueueSnackbar } from "notistack"
|
import EditIcon from "@mui/icons-material/Edit";
|
||||||
|
import { ChangeEvent, useRef } from "react";
|
||||||
|
import { SendDocumentsArgs, Verification } from "@root/model/auth";
|
||||||
|
import { updateDocument } from "@api/verification";
|
||||||
|
import { jsonToFormdata } from "@utils/jsonToFormdata";
|
||||||
|
import { parseAxiosError } from "@utils/parse-error";
|
||||||
|
import { readFile } from "@root/utils/readFile";
|
||||||
|
import { enqueueSnackbar } from "notistack";
|
||||||
|
|
||||||
type KeyNames =
|
type KeyNames = "inn" | "rule" | "certificate";
|
||||||
"inn" |
|
|
||||||
"rule" |
|
|
||||||
"certificate"
|
|
||||||
interface Props {
|
interface Props {
|
||||||
text: string;
|
text: string;
|
||||||
documentUrl: string;
|
documentUrl: string;
|
||||||
sx?: SxProps<Theme>;
|
sx?: SxProps<Theme>;
|
||||||
keyName: KeyNames
|
keyName: KeyNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function DocumentItem({
|
||||||
|
text,
|
||||||
|
documentUrl = "",
|
||||||
|
sx,
|
||||||
|
keyName,
|
||||||
|
}: Props) {
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
export default function DocumentItem({ text, documentUrl = "", sx, keyName }: Props) {
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||||
const theme = useTheme()
|
|
||||||
|
|
||||||
const fileInputRef = useRef<HTMLInputElement>(null)
|
|
||||||
|
|
||||||
function handleChooseFileClick() {
|
function handleChooseFileClick() {
|
||||||
fileInputRef.current?.click()
|
fileInputRef.current?.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadFile = async () => {
|
const downloadFile = async () => {
|
||||||
const { data } = await axios.get<ArrayBuffer>(documentUrl, {
|
const { data } = await axios.get<ArrayBuffer>(documentUrl, {
|
||||||
responseType: "arraybuffer",
|
responseType: "arraybuffer",
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadFileToDevice(
|
downloadFileToDevice(
|
||||||
`${documentUrl.split("/").pop()?.split(".")?.[0] || "document"}.pdf`,
|
`${documentUrl.split("/").pop()?.split(".")?.[0] || "document"}.pdf`,
|
||||||
Buffer.from(data)
|
Buffer.from(data)
|
||||||
)
|
);
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
async function sendDocument(
|
async function sendDocument(e: ChangeEvent<HTMLInputElement>) {
|
||||||
e: ChangeEvent<HTMLInputElement>
|
|
||||||
) {
|
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
const file = target?.files?.[0] || null;
|
const file = target?.files?.[0] || null;
|
||||||
if (file !== null) {
|
if (file !== null) {
|
||||||
const readedFile = await readFile(file, "binary")
|
const readedFile = await readFile(file, "binary");
|
||||||
try {
|
const [, updateDocumentError] = await updateDocument(
|
||||||
await makeRequest<FormData, Verification>({
|
jsonToFormdata({ [keyName]: readedFile })
|
||||||
url: `${process.env.REACT_APP_DOMAIN}/verification/v1.0.0/verification`,
|
);
|
||||||
method: "PATCH",
|
|
||||||
useToken: true,
|
|
||||||
withCredentials: true,
|
|
||||||
body: jsonToFormdata({ [keyName]: readedFile }),
|
|
||||||
})
|
|
||||||
|
|
||||||
enqueueSnackbar("Данные обновлены")
|
if (updateDocumentError) {
|
||||||
} catch (nativeError) {
|
return enqueueSnackbar(
|
||||||
const [error] = parseAxiosError(nativeError)
|
`Ошибка отправки документов. ${updateDocumentError}`
|
||||||
|
);
|
||||||
enqueueSnackbar(`Ошибка отправки документов. ${error}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enqueueSnackbar("Данные обновлены");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,9 +105,7 @@ export default function DocumentItem({ text, documentUrl = "", sx, keyName }: Pr
|
|||||||
>
|
>
|
||||||
{documentUrl.split("/").pop()?.split(".")?.[0]}
|
{documentUrl.split("/").pop()?.split(".")?.[0]}
|
||||||
</Typography>
|
</Typography>
|
||||||
<IconButton
|
<IconButton onClick={handleChooseFileClick}>
|
||||||
onClick={handleChooseFileClick}
|
|
||||||
>
|
|
||||||
<EditIcon sx={{ color: theme.palette.purple.main }} />
|
<EditIcon sx={{ color: theme.palette.purple.main }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<input
|
<input
|
||||||
@ -120,7 +120,6 @@ export default function DocumentItem({ text, documentUrl = "", sx, keyName }: Pr
|
|||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Document file={documentUrl}>
|
<Document file={documentUrl}>
|
||||||
|
|
||||||
<Page
|
<Page
|
||||||
pageNumber={1}
|
pageNumber={1}
|
||||||
width={200}
|
width={200}
|
||||||
@ -131,5 +130,5 @@ export default function DocumentItem({ text, documentUrl = "", sx, keyName }: Pr
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,17 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme
|
useTheme,
|
||||||
} from "@mui/material"
|
} from "@mui/material";
|
||||||
import CustomAccordion from "@components/CustomAccordion"
|
import CustomAccordion from "@components/CustomAccordion";
|
||||||
import File from "@components/icons/File"
|
import File from "@components/icons/File";
|
||||||
import {getDeclension} from "@utils/declension"
|
import { getDeclension } from "@utils/declension";
|
||||||
import {enqueueSnackbar} from "notistack"
|
import { enqueueSnackbar } from "notistack";
|
||||||
import {addTariffToCart, useUserStore} from "@root/stores/user"
|
import { addTariffToCart, useUserStore } from "@root/stores/user";
|
||||||
import ForwardToInboxOutlinedIcon
|
import ForwardToInboxOutlinedIcon from "@mui/icons-material/ForwardToInboxOutlined";
|
||||||
from "@mui/icons-material/ForwardToInboxOutlined";
|
import { KeyValue, RawDetails, sendReport } from "@api/history";
|
||||||
import {makeRequest} from "@frontend/kitui";
|
import { useNavigate } from "react-router-dom";
|
||||||
import {KeyValue, RawDetails} from "@api/history";
|
import { VerificationStatus } from "@root/model/account";
|
||||||
import {useNavigate} from "react-router-dom"
|
|
||||||
import {VerificationStatus} from "@root/model/account"
|
|
||||||
|
|
||||||
export type History = {
|
export type History = {
|
||||||
title: string;
|
title: string;
|
||||||
@ -31,61 +29,65 @@ interface AccordionWrapperProps {
|
|||||||
last?: boolean;
|
last?: boolean;
|
||||||
first?: boolean;
|
first?: boolean;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
onClickMail?: any
|
onClickMail?: any;
|
||||||
mainId: string
|
mainId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AccordionWrapper({ content, last, first, createdAt, onClickMail, mainId }: AccordionWrapperProps) {
|
export default function AccordionWrapper({
|
||||||
const theme = useTheme()
|
content,
|
||||||
const upMd = useMediaQuery(theme.breakpoints.up("md"))
|
last,
|
||||||
const upSm = useMediaQuery(theme.breakpoints.up("sm"))
|
first,
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(900))
|
createdAt,
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(560))
|
onClickMail,
|
||||||
|
mainId,
|
||||||
|
}: AccordionWrapperProps) {
|
||||||
|
const theme = useTheme();
|
||||||
|
const upMd = useMediaQuery(theme.breakpoints.up("md"));
|
||||||
|
const upSm = useMediaQuery(theme.breakpoints.up("sm"));
|
||||||
|
const isTablet = useMediaQuery(theme.breakpoints.down(900));
|
||||||
|
const isMobile = useMediaQuery(theme.breakpoints.down(560));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const verificationStatus = useUserStore((state) => state.verificationStatus)
|
const verificationStatus = useUserStore((state) => state.verificationStatus);
|
||||||
const OrgName = useUserStore((state) => state.userAccount?.name.orgname)
|
const OrgName = useUserStore((state) => state.userAccount?.name.orgname);
|
||||||
|
|
||||||
const valuesByKey: any = {}
|
const valuesByKey: any = {};
|
||||||
if (Array.isArray(content[0].Value) && Array.isArray(content[0].Value[0])) {
|
if (Array.isArray(content[0].Value) && Array.isArray(content[0].Value[0])) {
|
||||||
(content[0].Value[0] as KeyValue[]).forEach((item: KeyValue) => {
|
(content[0].Value[0] as KeyValue[]).forEach((item: KeyValue) => {
|
||||||
valuesByKey[item.Key] = item.Value;
|
valuesByKey[item.Key] = item.Value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const extractDateFromString = (tariffName: string) => {
|
const extractDateFromString = (tariffName: string) => {
|
||||||
const dateMatch = tariffName.match(/\d{4}-\d{2}-\d{2}/)
|
const dateMatch = tariffName.match(/\d{4}-\d{2}-\d{2}/);
|
||||||
return dateMatch ? dateMatch[0] : null
|
return dateMatch ? dateMatch[0] : null;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
async function handleTariffItemClick(tariffId: string) {
|
async function handleTariffItemClick(tariffId: string) {
|
||||||
const { patchCartError } = await addTariffToCart(tariffId)
|
const { patchCartError } = await addTariffToCart(tariffId);
|
||||||
if (patchCartError) {
|
if (patchCartError) {
|
||||||
enqueueSnackbar(patchCartError)
|
enqueueSnackbar(patchCartError);
|
||||||
} else {
|
} else {
|
||||||
enqueueSnackbar("Тариф добавлен в корзину")
|
enqueueSnackbar("Тариф добавлен в корзину");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendBillByEmail(logId: string) {
|
async function sendBillByEmail(logId: string) {
|
||||||
|
if (verificationStatus === VerificationStatus.VERIFICATED && OrgName) {
|
||||||
|
const [, sendReportError] = await sendReport(logId);
|
||||||
|
|
||||||
|
if (!sendReportError) {
|
||||||
|
return enqueueSnackbar(
|
||||||
|
"Акт будет отправлен на почту, указанную при регистрации"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if(verificationStatus === VerificationStatus.VERIFICATED && OrgName){
|
|
||||||
try {
|
|
||||||
await makeRequest({
|
|
||||||
url: process.env.REACT_APP_DOMAIN + `/customer/sendReport`,
|
|
||||||
body: {id: logId},
|
|
||||||
method: "POST",
|
|
||||||
});
|
|
||||||
return enqueueSnackbar("Акт будет отправлен на почту, указанную при регистрации");
|
|
||||||
} catch (e) {
|
|
||||||
enqueueSnackbar("Извините, произошла ошибка");
|
enqueueSnackbar("Извините, произошла ошибка");
|
||||||
}
|
}
|
||||||
}
|
navigate("/settings");
|
||||||
navigate("/settings")
|
if (verificationStatus !== VerificationStatus.VERIFICATED && !OrgName) {
|
||||||
if(verificationStatus !== VerificationStatus.VERIFICATED && !OrgName){
|
|
||||||
enqueueSnackbar("Пройдите верификацию и заполните название организации");
|
enqueueSnackbar("Пройдите верификацию и заполните название организации");
|
||||||
} else if(!OrgName){
|
} else if (!OrgName) {
|
||||||
enqueueSnackbar("Заполните поле название организации");
|
enqueueSnackbar("Заполните поле название организации");
|
||||||
}else if(verificationStatus !== VerificationStatus.VERIFICATED) {
|
} else if (verificationStatus !== VerificationStatus.VERIFICATED) {
|
||||||
enqueueSnackbar("Пройдите верификацию");
|
enqueueSnackbar("Пройдите верификацию");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,13 +102,12 @@ export default function AccordionWrapper({ content, last, first, createdAt, onCl
|
|||||||
last={last}
|
last={last}
|
||||||
first={first}
|
first={first}
|
||||||
divide
|
divide
|
||||||
text={valuesByKey.privileges.map((e:KeyValue[]) => (
|
text={valuesByKey.privileges.map((e: KeyValue[]) => (
|
||||||
<Typography
|
<Typography key={valuesByKey.id}>
|
||||||
key={valuesByKey.id}
|
{e[1].Value} - {e[5].Value}{" "}
|
||||||
>
|
{getDeclension(Number(e[5].Value), e[7].Value.toString())}
|
||||||
{e[1].Value} - {e[5].Value} {getDeclension(Number(e[5].Value), e[7].Value.toString())}
|
</Typography>
|
||||||
</Typography>)
|
))}
|
||||||
)}
|
|
||||||
header={
|
header={
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
@ -138,7 +139,9 @@ export default function AccordionWrapper({ content, last, first, createdAt, onCl
|
|||||||
fontSize: upMd ? "20px" : "18px",
|
fontSize: upMd ? "20px" : "18px",
|
||||||
lineHeight: upMd ? undefined : "19px",
|
lineHeight: upMd ? undefined : "19px",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
color: valuesByKey.expired ? theme.palette.text.disabled : theme.palette.text.secondary,
|
color: valuesByKey.expired
|
||||||
|
? theme.palette.text.disabled
|
||||||
|
: theme.palette.text.secondary,
|
||||||
px: 0,
|
px: 0,
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
}}
|
}}
|
||||||
@ -152,12 +155,14 @@ export default function AccordionWrapper({ content, last, first, createdAt, onCl
|
|||||||
fontSize: upMd ? "18px" : "16px",
|
fontSize: upMd ? "18px" : "16px",
|
||||||
lineHeight: upMd ? undefined : "19px",
|
lineHeight: upMd ? undefined : "19px",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
color: valuesByKey.expired ? theme.palette.text.disabled : theme.palette.gray.dark,
|
color: valuesByKey.expired
|
||||||
|
? theme.palette.text.disabled
|
||||||
|
: theme.palette.gray.dark,
|
||||||
px: 0,
|
px: 0,
|
||||||
width: "200px",
|
width: "200px",
|
||||||
maxWidth: "200px",
|
maxWidth: "200px",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
textOverflow: "ellipsis"
|
textOverflow: "ellipsis",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{valuesByKey.iscustom ? "Мой тариф" : valuesByKey.name}
|
{valuesByKey.iscustom ? "Мой тариф" : valuesByKey.name}
|
||||||
@ -179,19 +184,25 @@ export default function AccordionWrapper({ content, last, first, createdAt, onCl
|
|||||||
fontSize: upMd ? "18px" : "16px",
|
fontSize: upMd ? "18px" : "16px",
|
||||||
lineHeight: upMd ? undefined : "19px",
|
lineHeight: upMd ? undefined : "19px",
|
||||||
fontWeight: 400,
|
fontWeight: 400,
|
||||||
color: valuesByKey.expired ? theme.palette.text.disabled : theme.palette.gray.dark,
|
color: valuesByKey.expired
|
||||||
|
? theme.palette.text.disabled
|
||||||
|
: theme.palette.gray.dark,
|
||||||
px: 0,
|
px: 0,
|
||||||
}}
|
}}
|
||||||
title={`>Способ оплаты: ${valuesByKey.payMethod}</Typography>}`}
|
title={`>Способ оплаты: ${valuesByKey.payMethod}</Typography>}`}
|
||||||
>
|
>
|
||||||
{valuesByKey.payMethod && <Typography
|
{valuesByKey.payMethod && (
|
||||||
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
maxWidth: "300px",
|
maxWidth: "300px",
|
||||||
width: "300px",
|
width: "300px",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
textOverflow: "ellipsis"
|
textOverflow: "ellipsis",
|
||||||
}}
|
}}
|
||||||
>Способ оплаты: {valuesByKey.payMethod}</Typography>}
|
>
|
||||||
|
Способ оплаты: {valuesByKey.payMethod}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -205,18 +216,27 @@ export default function AccordionWrapper({ content, last, first, createdAt, onCl
|
|||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
marginLeft: isTablet ? (isMobile ? null : "auto") : null,
|
marginLeft: isTablet
|
||||||
color: valuesByKey.expired ? theme.palette.text.disabled : theme.palette.gray.dark,
|
? isMobile
|
||||||
|
? null
|
||||||
|
: "auto"
|
||||||
|
: null,
|
||||||
|
color: valuesByKey.expired
|
||||||
|
? theme.palette.text.disabled
|
||||||
|
: theme.palette.gray.dark,
|
||||||
fontSize: upSm ? "20px" : "16px",
|
fontSize: upSm ? "20px" : "16px",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Number(content[1].Value) / 100 ? Number(content[1].Value) / 100 : "nodata"} руб.
|
{Number(content[1].Value) / 100
|
||||||
|
? Number(content[1].Value) / 100
|
||||||
|
: "nodata"}{" "}
|
||||||
|
руб.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{!isMobile &&
|
{!isMobile && (
|
||||||
<>
|
<>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@ -235,40 +255,42 @@ export default function AccordionWrapper({ content, last, first, createdAt, onCl
|
|||||||
"&:active": {
|
"&:active": {
|
||||||
bgcolor: "black",
|
bgcolor: "black",
|
||||||
color: "white",
|
color: "white",
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ForwardToInboxOutlinedIcon fontSize={"medium"} sx={{ opacity: 0.9 }}/>
|
<ForwardToInboxOutlinedIcon
|
||||||
|
fontSize={"medium"}
|
||||||
|
sx={{ opacity: 0.9 }}
|
||||||
|
/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
title="Добавить в корзину тариф"
|
title="Добавить в корзину тариф"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation();
|
||||||
handleTariffItemClick(valuesByKey.id)
|
handleTariffItemClick(valuesByKey.id);
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
ml: "20px",
|
ml: "20px",
|
||||||
bgcolor:"#EEE4FC",
|
bgcolor: "#EEE4FC",
|
||||||
stroke: "#7E2AEA",
|
stroke: "#7E2AEA",
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
bgcolor:"#7E2AEA",
|
bgcolor: "#7E2AEA",
|
||||||
stroke: "white",
|
stroke: "white",
|
||||||
},
|
},
|
||||||
"&:active": {
|
"&:active": {
|
||||||
bgcolor:"black",
|
bgcolor: "black",
|
||||||
stroke: "white",
|
stroke: "white",
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<File></File>
|
<File></File>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
|
)}
|
||||||
}
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{isMobile &&
|
{isMobile && (
|
||||||
<>
|
<>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@ -287,40 +309,42 @@ export default function AccordionWrapper({ content, last, first, createdAt, onCl
|
|||||||
"&:active": {
|
"&:active": {
|
||||||
bgcolor: "black",
|
bgcolor: "black",
|
||||||
color: "white",
|
color: "white",
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ForwardToInboxOutlinedIcon fontSize={"medium"} sx={{ opacity: 0.9 }}/>
|
<ForwardToInboxOutlinedIcon
|
||||||
|
fontSize={"medium"}
|
||||||
|
sx={{ opacity: 0.9 }}
|
||||||
|
/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
title="Добавить в корзину тариф"
|
title="Добавить в корзину тариф"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation();
|
||||||
handleTariffItemClick(valuesByKey.id)
|
handleTariffItemClick(valuesByKey.id);
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
mr: "10px",
|
mr: "10px",
|
||||||
bgcolor:"#EEE4FC",
|
bgcolor: "#EEE4FC",
|
||||||
stroke: "#7E2AEA",
|
stroke: "#7E2AEA",
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
"&:hover": {
|
"&:hover": {
|
||||||
bgcolor:"#7E2AEA",
|
bgcolor: "#7E2AEA",
|
||||||
stroke: "white",
|
stroke: "white",
|
||||||
},
|
},
|
||||||
"&:active": {
|
"&:active": {
|
||||||
bgcolor:"black",
|
bgcolor: "black",
|
||||||
stroke: "white",
|
stroke: "white",
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<File></File>
|
<File></File>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
|
)}
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,19 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import CustomAccordion from "@components/CustomAccordion";
|
import CustomAccordion from "@components/CustomAccordion";
|
||||||
import File from "@components/icons/File";
|
import File from "@components/icons/File";
|
||||||
import {getDeclension} from "@utils/declension";
|
import { getDeclension } from "@utils/declension";
|
||||||
import {enqueueSnackbar} from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import {addTariffToCart, useUserStore} from "@root/stores/user"
|
import { addTariffToCart, useUserStore } from "@root/stores/user";
|
||||||
import {makeRequest, Tariff} from "@frontend/kitui";
|
import { makeRequest, Tariff } from "@frontend/kitui";
|
||||||
import {currencyFormatter} from "@root/utils/currencyFormatter";
|
import { currencyFormatter } from "@root/utils/currencyFormatter";
|
||||||
import ForwardToInboxIcon from '@mui/icons-material/ForwardToInbox';
|
import ForwardToInboxIcon from "@mui/icons-material/ForwardToInbox";
|
||||||
import {VerificationStatus} from "@root/model/account"
|
import { VerificationStatus } from "@root/model/account";
|
||||||
import {useNavigate} from "react-router-dom"
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { sendReport } from "@api/history";
|
||||||
|
|
||||||
export type History = {
|
export type History = {
|
||||||
title: string;
|
title: string;
|
||||||
@ -31,18 +32,25 @@ interface AccordionWrapperProps {
|
|||||||
last?: boolean;
|
last?: boolean;
|
||||||
first?: boolean;
|
first?: boolean;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
mainId: string
|
mainId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AccordionWrapper2({ tariff, price, last, first, createdAt, mainId }: AccordionWrapperProps) {
|
export default function AccordionWrapper2({
|
||||||
|
tariff,
|
||||||
|
price,
|
||||||
|
last,
|
||||||
|
first,
|
||||||
|
createdAt,
|
||||||
|
mainId,
|
||||||
|
}: AccordionWrapperProps) {
|
||||||
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(900));
|
const isTablet = useMediaQuery(theme.breakpoints.down(900));
|
||||||
const isMobile = useMediaQuery(theme.breakpoints.down(560));
|
const isMobile = useMediaQuery(theme.breakpoints.down(560));
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const verificationStatus = useUserStore((state) => state.verificationStatus)
|
const verificationStatus = useUserStore((state) => state.verificationStatus);
|
||||||
const OrgName = useUserStore((state) => state.userAccount?.name.orgname)
|
const OrgName = useUserStore((state) => state.userAccount?.name.orgname);
|
||||||
async function handleTariffItemClick(tariffId: string) {
|
async function handleTariffItemClick(tariffId: string) {
|
||||||
const { patchCartError } = await addTariffToCart(tariffId);
|
const { patchCartError } = await addTariffToCart(tariffId);
|
||||||
if (patchCartError) {
|
if (patchCartError) {
|
||||||
@ -53,24 +61,23 @@ export default function AccordionWrapper2({ tariff, price, last, first, createdA
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function sendBillByEmail(logId: string) {
|
async function sendBillByEmail(logId: string) {
|
||||||
if(verificationStatus === VerificationStatus.VERIFICATED && OrgName){
|
if (verificationStatus === VerificationStatus.VERIFICATED && OrgName) {
|
||||||
try {
|
const [, sendReportError] = await sendReport(logId);
|
||||||
await makeRequest({
|
|
||||||
url: process.env.REACT_APP_DOMAIN + `/customer/sendReport`,
|
if (!sendReportError) {
|
||||||
body: {id: logId},
|
return enqueueSnackbar(
|
||||||
method: "POST",
|
"Акт будет отправлен на почту, указанную при регистрации"
|
||||||
});
|
);
|
||||||
return enqueueSnackbar("Акт будет отправлен на почту, указанную при регистрации");
|
}
|
||||||
} catch (e) {
|
|
||||||
enqueueSnackbar("Извините, произошла ошибка");
|
enqueueSnackbar("Извините, произошла ошибка");
|
||||||
}
|
}
|
||||||
}
|
navigate("/settings");
|
||||||
navigate("/settings")
|
if (verificationStatus !== VerificationStatus.VERIFICATED && !OrgName) {
|
||||||
if(verificationStatus !== VerificationStatus.VERIFICATED && !OrgName){
|
|
||||||
enqueueSnackbar("Пройдите верификацию и заполните название организации");
|
enqueueSnackbar("Пройдите верификацию и заполните название организации");
|
||||||
} else if(!OrgName){
|
} else if (!OrgName) {
|
||||||
enqueueSnackbar("Заполните поле название организации");
|
enqueueSnackbar("Заполните поле название организации");
|
||||||
}else if(verificationStatus !== VerificationStatus.VERIFICATED) {
|
} else if (verificationStatus !== VerificationStatus.VERIFICATED) {
|
||||||
enqueueSnackbar("Пройдите верификацию");
|
enqueueSnackbar("Пройдите верификацию");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,9 +92,13 @@ export default function AccordionWrapper2({ tariff, price, last, first, createdA
|
|||||||
last={last}
|
last={last}
|
||||||
first={first}
|
first={first}
|
||||||
divide
|
divide
|
||||||
text={tariff.privileges.map(privilege => (
|
text={tariff.privileges.map(
|
||||||
`${privilege.description} - ${privilege.amount} ${getDeclension(Number(privilege.serviceKey), privilege.value)} `
|
(privilege) =>
|
||||||
))}
|
`${privilege.description} - ${privilege.amount} ${getDeclension(
|
||||||
|
Number(privilege.serviceKey),
|
||||||
|
privilege.value
|
||||||
|
)} `
|
||||||
|
)}
|
||||||
header={
|
header={
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
@ -119,7 +130,9 @@ export default function AccordionWrapper2({ tariff, price, last, first, createdA
|
|||||||
fontSize: upMd ? "20px" : "18px",
|
fontSize: upMd ? "20px" : "18px",
|
||||||
lineHeight: upMd ? undefined : "19px",
|
lineHeight: upMd ? undefined : "19px",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
color: /* valuesByKey.expired */ false ? theme.palette.text.disabled : theme.palette.text.secondary,
|
color: /* valuesByKey.expired */ false
|
||||||
|
? theme.palette.text.disabled
|
||||||
|
: theme.palette.text.secondary,
|
||||||
px: 0,
|
px: 0,
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
}}
|
}}
|
||||||
@ -133,9 +146,11 @@ export default function AccordionWrapper2({ tariff, price, last, first, createdA
|
|||||||
fontSize: upMd ? "18px" : "16px",
|
fontSize: upMd ? "18px" : "16px",
|
||||||
lineHeight: upMd ? undefined : "19px",
|
lineHeight: upMd ? undefined : "19px",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
color: /* valuesByKey.expired */ false ? theme.palette.text.disabled : theme.palette.gray.dark,
|
color: /* valuesByKey.expired */ false
|
||||||
|
? theme.palette.text.disabled
|
||||||
|
: theme.palette.gray.dark,
|
||||||
px: 0,
|
px: 0,
|
||||||
width: upMd? "200px" : "auto",
|
width: upMd ? "200px" : "auto",
|
||||||
maxWidth: "200px",
|
maxWidth: "200px",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
@ -185,8 +200,14 @@ export default function AccordionWrapper2({ tariff, price, last, first, createdA
|
|||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
marginLeft: isTablet ? (isMobile ? null : "auto") : null,
|
marginLeft: isTablet
|
||||||
color: /* valuesByKey.expired */ false ? theme.palette.text.disabled : theme.palette.gray.dark,
|
? isMobile
|
||||||
|
? null
|
||||||
|
: "auto"
|
||||||
|
: null,
|
||||||
|
color: /* valuesByKey.expired */ false
|
||||||
|
? theme.palette.text.disabled
|
||||||
|
: theme.palette.gray.dark,
|
||||||
fontSize: upSm ? "20px" : "16px",
|
fontSize: upSm ? "20px" : "16px",
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
@ -196,7 +217,7 @@ export default function AccordionWrapper2({ tariff, price, last, first, createdA
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{!isMobile &&
|
{!isMobile && (
|
||||||
<>
|
<>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@ -215,10 +236,13 @@ export default function AccordionWrapper2({ tariff, price, last, first, createdA
|
|||||||
"&:active": {
|
"&:active": {
|
||||||
bgcolor: "black",
|
bgcolor: "black",
|
||||||
color: "white",
|
color: "white",
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ForwardToInboxIcon fontSize={"medium"} sx={{ opacity: 0.9 }}/>
|
<ForwardToInboxIcon
|
||||||
|
fontSize={"medium"}
|
||||||
|
sx={{ opacity: 0.9 }}
|
||||||
|
/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
title="Добавить в корзину тариф"
|
title="Добавить в корзину тариф"
|
||||||
@ -238,17 +262,16 @@ export default function AccordionWrapper2({ tariff, price, last, first, createdA
|
|||||||
"&:active": {
|
"&:active": {
|
||||||
bgcolor: "black",
|
bgcolor: "black",
|
||||||
stroke: "white",
|
stroke: "white",
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<File></File>
|
<File></File>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
|
)}
|
||||||
}
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
{isMobile &&
|
{isMobile && (
|
||||||
<>
|
<>
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
@ -267,10 +290,13 @@ export default function AccordionWrapper2({ tariff, price, last, first, createdA
|
|||||||
"&:active": {
|
"&:active": {
|
||||||
bgcolor: "black",
|
bgcolor: "black",
|
||||||
color: "white",
|
color: "white",
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ForwardToInboxIcon fontSize={"medium"} sx={{ opacity: 0.9 }}/>
|
<ForwardToInboxIcon
|
||||||
|
fontSize={"medium"}
|
||||||
|
sx={{ opacity: 0.9 }}
|
||||||
|
/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
title="Добавить в корзину тариф"
|
title="Добавить в корзину тариф"
|
||||||
@ -290,14 +316,13 @@ export default function AccordionWrapper2({ tariff, price, last, first, createdA
|
|||||||
"&:active": {
|
"&:active": {
|
||||||
bgcolor: "black",
|
bgcolor: "black",
|
||||||
stroke: "white",
|
stroke: "white",
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<File></File>
|
<File></File>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</>
|
</>
|
||||||
|
)}
|
||||||
}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -1,25 +1,28 @@
|
|||||||
import {useState} from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
IconButton,
|
IconButton,
|
||||||
Typography,
|
Typography,
|
||||||
useMediaQuery,
|
useMediaQuery,
|
||||||
useTheme
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
||||||
|
|
||||||
import SectionWrapper from "@root/components/SectionWrapper";
|
import SectionWrapper from "@root/components/SectionWrapper";
|
||||||
import {Select} from "@root/components/Select";
|
import { Select } from "@root/components/Select";
|
||||||
import {Tabs} from "@root/components/Tabs";
|
import { Tabs } from "@root/components/Tabs";
|
||||||
|
|
||||||
import AccordionWrapper from "./AccordionWrapper";
|
import AccordionWrapper from "./AccordionWrapper";
|
||||||
import {useHistoryTracker} from "@root/utils/hooks/useHistoryTracker";
|
import { useHistoryTracker } from "@root/utils/hooks/useHistoryTracker";
|
||||||
import {ErrorBoundary} from "react-error-boundary";
|
import { ErrorBoundary } from "react-error-boundary";
|
||||||
import {handleComponentError} from "@root/utils/handleComponentError";
|
import { handleComponentError } from "@root/utils/handleComponentError";
|
||||||
import {useHistoryStore} from "@root/stores/history";
|
import { useHistoryStore } from "@root/stores/history";
|
||||||
import {enqueueSnackbar} from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import {makeRequest} from "@frontend/kitui";
|
import {
|
||||||
import {HistoryRecord, HistoryRecord2} from "@root/api/history";
|
HistoryRecord,
|
||||||
|
HistoryRecord2,
|
||||||
|
sendReportById,
|
||||||
|
} from "@root/api/history";
|
||||||
import AccordionWrapper2 from "./AccordionWrapper2";
|
import AccordionWrapper2 from "./AccordionWrapper2";
|
||||||
|
|
||||||
const subPages = ["Платежи"];
|
const subPages = ["Платежи"];
|
||||||
@ -32,7 +35,7 @@ export default function History() {
|
|||||||
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));
|
||||||
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
const isTablet = useMediaQuery(theme.breakpoints.down(1000));
|
||||||
const historyData = useHistoryStore(state => state.history);
|
const historyData = useHistoryStore((state) => state.history);
|
||||||
const handleCustomBackNavigation = useHistoryTracker();
|
const handleCustomBackNavigation = useHistoryTracker();
|
||||||
|
|
||||||
const extractDateFromString = (tariffName: string) => {
|
const extractDateFromString = (tariffName: string) => {
|
||||||
@ -41,17 +44,13 @@ export default function History() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function handleHistoryResponse(tariffId: string) {
|
async function handleHistoryResponse(tariffId: string) {
|
||||||
try {
|
const [, sendReportError] = await sendReportById(tariffId);
|
||||||
await makeRequest(
|
|
||||||
{
|
if (sendReportError) {
|
||||||
url: process.env.REACT_APP_DOMAIN + `/customer/sendReport/${tariffId}`,
|
return enqueueSnackbar(sendReportError);
|
||||||
method: "POST",
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
enqueueSnackbar("Запрос отправлен");
|
enqueueSnackbar("Запрос отправлен");
|
||||||
} catch (e) {
|
|
||||||
enqueueSnackbar("извините, произошла ошибка");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<SectionWrapper
|
<SectionWrapper
|
||||||
@ -72,7 +71,10 @@ export default function History() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isMobile && (
|
{isMobile && (
|
||||||
<IconButton onClick={handleCustomBackNavigation} sx={{ p: 0, height: "28px", width: "28px", color: "black" }}>
|
<IconButton
|
||||||
|
onClick={handleCustomBackNavigation}
|
||||||
|
sx={{ p: 0, height: "28px", width: "28px", color: "black" }}
|
||||||
|
>
|
||||||
<ArrowBackIcon />
|
<ArrowBackIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
@ -86,27 +88,37 @@ export default function History() {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<Select items={subPages} selectedItem={selectedItem} setSelectedItem={setSelectedItem} />
|
<Select
|
||||||
|
items={subPages}
|
||||||
|
selectedItem={selectedItem}
|
||||||
|
setSelectedItem={setSelectedItem}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Tabs items={subPages} selectedItem={selectedItem} setSelectedItem={setSelectedItem} />
|
<Tabs
|
||||||
|
items={subPages}
|
||||||
|
selectedItem={selectedItem}
|
||||||
|
setSelectedItem={setSelectedItem}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<ErrorBoundary
|
<ErrorBoundary
|
||||||
fallback={
|
fallback={<Typography mt="8px">Ошибка загрузки истории</Typography>}
|
||||||
<Typography mt="8px">Ошибка загрузки истории</Typography>
|
|
||||||
}
|
|
||||||
onError={handleComponentError}
|
onError={handleComponentError}
|
||||||
>
|
>
|
||||||
{historyData?.length === 0 && <Typography textAlign="center">Нет данных</Typography>}
|
{historyData?.length === 0 && (
|
||||||
|
<Typography textAlign="center">Нет данных</Typography>
|
||||||
|
)}
|
||||||
{/* Для ненормального rawDetails */}
|
{/* Для ненормального rawDetails */}
|
||||||
{historyData?.filter((e): e is HistoryRecord => {
|
{historyData
|
||||||
|
?.filter((e): e is HistoryRecord => {
|
||||||
e.createdAt = extractDateFromString(e.createdAt);
|
e.createdAt = extractDateFromString(e.createdAt);
|
||||||
return (
|
return (
|
||||||
!e.isDeleted
|
!e.isDeleted &&
|
||||||
&& e.key === "payCart"
|
e.key === "payCart" &&
|
||||||
&& Array.isArray(e.rawDetails)
|
Array.isArray(e.rawDetails) &&
|
||||||
&& Array.isArray(e.rawDetails[0].Value)
|
Array.isArray(e.rawDetails[0].Value)
|
||||||
);
|
);
|
||||||
}).map((e, index) => {
|
})
|
||||||
|
.map((e, index) => {
|
||||||
return (
|
return (
|
||||||
<Box key={index} sx={{ mt: index === 0 ? "27px" : "0px" }}>
|
<Box key={index} sx={{ mt: index === 0 ? "27px" : "0px" }}>
|
||||||
<AccordionWrapper
|
<AccordionWrapper
|
||||||
@ -125,15 +137,17 @@ export default function History() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{/* Для нормального rawDetails */}
|
{/* Для нормального rawDetails */}
|
||||||
{historyData?.filter((e): e is HistoryRecord2 => {
|
{historyData
|
||||||
|
?.filter((e): e is HistoryRecord2 => {
|
||||||
e.createdAt = extractDateFromString(e.createdAt);
|
e.createdAt = extractDateFromString(e.createdAt);
|
||||||
return (
|
return (
|
||||||
!e.isDeleted
|
!e.isDeleted &&
|
||||||
&& e.key === "payCart"
|
e.key === "payCart" &&
|
||||||
&& !Array.isArray(e.rawDetails)
|
!Array.isArray(e.rawDetails) &&
|
||||||
&& !!e.rawDetails.tariffs[0]
|
!!e.rawDetails.tariffs[0]
|
||||||
);
|
);
|
||||||
}).map((e, index) => {
|
})
|
||||||
|
.map((e, index) => {
|
||||||
return (
|
return (
|
||||||
<Box key={index} sx={{ mt: index === 0 ? "27px" : "0px" }}>
|
<Box key={index} sx={{ mt: index === 0 ? "27px" : "0px" }}>
|
||||||
<AccordionWrapper2
|
<AccordionWrapper2
|
||||||
@ -143,7 +157,7 @@ export default function History() {
|
|||||||
mainId={(e as HistoryRecord2).id}
|
mainId={(e as HistoryRecord2).id}
|
||||||
createdAt={e.createdAt}
|
createdAt={e.createdAt}
|
||||||
tariff={e.rawDetails.tariffs[0]}
|
tariff={e.rawDetails.tariffs[0]}
|
||||||
price={e.rawDetails.price/100}
|
price={e.rawDetails.price / 100}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import axios, { AxiosResponse } from "axios";
|
|
||||||
import { ApologyPage } from "../ApologyPage";
|
import { ApologyPage } from "../ApologyPage";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
@ -22,19 +21,6 @@ import { clearCustomTariffs } from "@root/stores/customTariffs";
|
|||||||
import { clearTickets } from "@root/stores/tickets";
|
import { clearTickets } from "@root/stores/tickets";
|
||||||
import {setNotEnoughMoneyAmount} from "@stores/cart"
|
import {setNotEnoughMoneyAmount} from "@stores/cart"
|
||||||
|
|
||||||
function refresh(token: string) {
|
|
||||||
return axios<never, AxiosResponse<{ accessToken: string }>>(
|
|
||||||
process.env.REACT_APP_DOMAIN + "/auth/refresh",
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer " + token,
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
const action = params.get("action");
|
const action = params.get("action");
|
||||||
const dif = params.get("dif");
|
const dif = params.get("dif");
|
||||||
|
@ -14,7 +14,6 @@ import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import SendIcon from "@components/icons/SendIcon";
|
import SendIcon from "@components/icons/SendIcon";
|
||||||
import makeRequest from "@api/makeRequest"
|
|
||||||
import { throttle, useToken } from "@frontend/kitui";
|
import { throttle, useToken } from "@frontend/kitui";
|
||||||
import { enqueueSnackbar } from "notistack";
|
import { enqueueSnackbar } from "notistack";
|
||||||
import { useTicketStore } from "@root/stores/tickets";
|
import { useTicketStore } from "@root/stores/tickets";
|
||||||
@ -35,7 +34,11 @@ import {
|
|||||||
useSSESubscription,
|
useSSESubscription,
|
||||||
useTicketMessages,
|
useTicketMessages,
|
||||||
} from "@frontend/kitui";
|
} from "@frontend/kitui";
|
||||||
import { shownMessage, sendTicketMessage } from "@root/api/ticket";
|
import {
|
||||||
|
shownMessage,
|
||||||
|
sendTicketMessage,
|
||||||
|
sendFile as sendFileRequest,
|
||||||
|
} from "@root/api/ticket";
|
||||||
import { withErrorBoundary } from "react-error-boundary";
|
import { withErrorBoundary } from "react-error-boundary";
|
||||||
import { handleComponentError } from "@root/utils/handleComponentError";
|
import { handleComponentError } from "@root/utils/handleComponentError";
|
||||||
import { useSSETab } from "@root/utils/hooks/useSSETab";
|
import { useSSETab } from "@root/utils/hooks/useSSETab";
|
||||||
@ -196,20 +199,12 @@ function SupportChat() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const [, sendFileError] = await sendFileRequest(ticketId, file);
|
||||||
const body = new FormData();
|
|
||||||
|
|
||||||
body.append(file.name, file);
|
if (sendFileError) {
|
||||||
body.append("ticket", ticketId);
|
enqueueSnackbar(sendFileError);
|
||||||
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 true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,6 @@ import { setUserId, useUserStore } from "@root/stores/user";
|
|||||||
import { cardShadow } from "@root/utils/theme";
|
import { cardShadow } from "@root/utils/theme";
|
||||||
import AmoButton from "./AmoButton";
|
import AmoButton from "./AmoButton";
|
||||||
import { recover } from "@root/api/auth";
|
import { recover } from "@root/api/auth";
|
||||||
import {AxiosError} from "axios"
|
|
||||||
|
|
||||||
interface Values {
|
interface Values {
|
||||||
email: string;
|
email: string;
|
||||||
|
@ -19,8 +19,8 @@ import { useEffect, useState } from "react";
|
|||||||
import { useUserStore } from "@root/stores/user";
|
import { useUserStore } from "@root/stores/user";
|
||||||
import { cardShadow } from "@root/utils/theme";
|
import { cardShadow } from "@root/utils/theme";
|
||||||
|
|
||||||
import makeRequest from "@api/makeRequest"
|
import { patchUser } from "@api/user";
|
||||||
import { setAuthToken } from "@frontend/kitui"
|
import { setAuthToken } from "@frontend/kitui";
|
||||||
interface Values {
|
interface Values {
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
@ -32,7 +32,10 @@ const initialValues: Values = {
|
|||||||
const validationSchema = object({
|
const validationSchema = object({
|
||||||
password: string()
|
password: string()
|
||||||
.min(8, "Минимум 8 символов")
|
.min(8, "Минимум 8 символов")
|
||||||
.matches(/^[.,:;\-_+!&()*<>\[\]\{\}`@"#$\%\^\=?\d\w]+$/, "Некорректные символы")
|
.matches(
|
||||||
|
/^[.,:;\-_+!&()*<>\[\]\{\}`@"#$\%\^\=?\d\w]+$/,
|
||||||
|
"Некорректные символы"
|
||||||
|
)
|
||||||
.required("Поле обязательно"),
|
.required("Поле обязательно"),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -49,32 +52,35 @@ export default function RecoverPassword() {
|
|||||||
validationSchema,
|
validationSchema,
|
||||||
onSubmit: async (values, formikHelpers) => {
|
onSubmit: async (values, formikHelpers) => {
|
||||||
if (tokenUser) {
|
if (tokenUser) {
|
||||||
setAuthToken(tokenUser || "")
|
setAuthToken(tokenUser || "");
|
||||||
try {
|
const [, patchUserError] = await patchUser({
|
||||||
const response = await makeRequest<unknown, unknown>({
|
password: values.password,
|
||||||
url: process.env.REACT_APP_DOMAIN + "/user/",
|
|
||||||
method: "PATCH",
|
|
||||||
body: {password: values.password},
|
|
||||||
});
|
});
|
||||||
setIsDialogOpen(false)
|
|
||||||
navigate("/")
|
|
||||||
enqueueSnackbar("Пароль успешно сменён")
|
|
||||||
} catch (error) {
|
|
||||||
setAuthToken("")
|
|
||||||
enqueueSnackbar("Извините, произошла ошибка, попробуйте повторить позже")}
|
|
||||||
|
|
||||||
|
if (!patchUserError) {
|
||||||
|
setIsDialogOpen(false);
|
||||||
|
navigate("/");
|
||||||
|
enqueueSnackbar("Пароль успешно сменён");
|
||||||
} else {
|
} else {
|
||||||
enqueueSnackbar("Неверный url-адрес")
|
setAuthToken("");
|
||||||
|
enqueueSnackbar(
|
||||||
|
"Извините, произошла ошибка, попробуйте повторить позже"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
enqueueSnackbar("Неверный url-адрес");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const params = new URLSearchParams(window.location.search)
|
const params = new URLSearchParams(window.location.search);
|
||||||
const authToken = params.get("auth")
|
const authToken = params.get("auth");
|
||||||
setTokenUser(authToken)
|
setTokenUser(authToken);
|
||||||
|
|
||||||
history.pushState(null, document.title, "/changepwd");
|
history.pushState(null, document.title, "/changepwd");
|
||||||
return () => {setAuthToken("")}
|
return () => {
|
||||||
|
setAuthToken("");
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function handleClose() {
|
function handleClose() {
|
||||||
@ -185,8 +191,7 @@ export default function RecoverPassword() {
|
|||||||
gap: "10px",
|
gap: "10px",
|
||||||
mt: "auto",
|
mt: "auto",
|
||||||
}}
|
}}
|
||||||
>
|
></Box>
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { ErrorInfo } from "react"
|
import { ErrorInfo } from "react";
|
||||||
|
|
||||||
|
|
||||||
interface ComponentError {
|
interface ComponentError {
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
@ -14,29 +13,23 @@ export function handleComponentError(error: Error, info: ErrorInfo) {
|
|||||||
message: error.message,
|
message: error.message,
|
||||||
callStack: error.stack,
|
callStack: error.stack,
|
||||||
componentStack: info.componentStack,
|
componentStack: info.componentStack,
|
||||||
}
|
};
|
||||||
|
|
||||||
queueErrorRequest(componentError)
|
queueErrorRequest(componentError);
|
||||||
}
|
}
|
||||||
|
|
||||||
let errorsQueue: ComponentError[] = []
|
let errorsQueue: ComponentError[] = [];
|
||||||
let timeoutId: ReturnType<typeof setTimeout>
|
let timeoutId: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
function queueErrorRequest(error: ComponentError) {
|
function queueErrorRequest(error: ComponentError) {
|
||||||
errorsQueue.push(error)
|
errorsQueue.push(error);
|
||||||
|
|
||||||
clearTimeout(timeoutId)
|
clearTimeout(timeoutId);
|
||||||
timeoutId = setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
sendErrorsToServer()
|
sendErrorsToServer();
|
||||||
}, 1000)
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendErrorsToServer() {
|
async function sendErrorsToServer() {
|
||||||
// makeRequest({
|
errorsQueue = [];
|
||||||
// url: "",
|
|
||||||
// method: "POST",
|
|
||||||
// body: errorsQueue,
|
|
||||||
// useToken: true,
|
|
||||||
// });
|
|
||||||
errorsQueue = []
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user