refactor: requests

This commit is contained in:
IlyaDoronin 2024-05-29 14:58:54 +03:00
parent f58f2c0c47
commit a76fe4b0a0
13 changed files with 283 additions and 239 deletions

@ -87,9 +87,10 @@ export const getHistory = async (): Promise<
export const sendReport = async ( export const sendReport = async (
id: string id: string
): Promise<[unknown | null, string?]> => { ): Promise<[void | null, string?]> => {
debugger;
try { try {
const sendReportResponse = await makeRequest<{ id: string }, unknown>({ const sendReportResponse = await makeRequest<{ id: string }, void>({
method: "POST", method: "POST",
url: `${API_URL}/sendReport`, url: `${API_URL}/sendReport`,
body: { id }, body: { id },
@ -99,15 +100,16 @@ export const sendReport = async (
} catch (nativeError) { } catch (nativeError) {
const [error] = parseAxiosError(nativeError); const [error] = parseAxiosError(nativeError);
return [[], `Не удалось отправить отчёт. ${error}`]; return [null, `Не удалось отправить отчёт. ${error}`];
} }
}; };
export const sendReportById = async ( export const sendReportById = async (
tariffId: string tariffId: string
): Promise<[unknown | null, string?]> => { ): Promise<[void | null, string?]> => {
debugger;
try { try {
const sendReportResponse = await makeRequest<never, unknown>({ const sendReportResponse = await makeRequest<never, void>({
method: "POST", method: "POST",
url: `${API_URL}/sendReport/${tariffId}`, url: `${API_URL}/sendReport/${tariffId}`,
}); });
@ -116,6 +118,6 @@ export const sendReportById = async (
} catch (nativeError) { } catch (nativeError) {
const [error] = parseAxiosError(nativeError); const [error] = parseAxiosError(nativeError);
return [[], `Не удалось отправить отчёт. ${error}`]; return [null, `Не удалось отправить отчёт. ${error}`];
} }
}; };

@ -8,13 +8,13 @@ type GetRecentlyPurchasedTariffsResponse = {
}; };
export const getRecentlyPurchasedTariffs = async (): Promise< export const getRecentlyPurchasedTariffs = async (): Promise<
[GetRecentlyPurchasedTariffsResponse | null, string?] [GetRecentlyPurchasedTariffsResponse[] | null, string?]
> => { > => {
try { try {
debugger; debugger;
const recentlyPurchased = await makeRequest< const recentlyPurchased = await makeRequest<
never, never,
GetRecentlyPurchasedTariffsResponse GetRecentlyPurchasedTariffsResponse[]
>({ >({
method: "GET", method: "GET",
url: `${API_URL}/recent`, url: `${API_URL}/recent`,

@ -1,5 +1,7 @@
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 { createTicket as createTicketRequest } from "@frontend/kitui";
import type { CreateTicketResponse } from "@frontend/kitui";
import { SendTicketMessageRequest } from "@frontend/kitui"; import { SendTicketMessageRequest } from "@frontend/kitui";
@ -7,7 +9,7 @@ type SendFileResponse = {
message: string; message: string;
}; };
const API_URL = `${process.env.REACT_APP_DOMAIN}/heruvym`; const API_URL = `${process.env.REACT_APP_DOMAIN}/heruvym/v1.0.0`;
export const sendTicketMessage = async ( export const sendTicketMessage = async (
ticketId: string, ticketId: string,
@ -61,7 +63,7 @@ export const sendFile = async (
const sendResponse = await makeRequest<FormData, SendFileResponse>({ const sendResponse = await makeRequest<FormData, SendFileResponse>({
method: "POST", method: "POST",
url: `${process.env.REACT_APP_DOMAIN}/sendFiles`, url: `${API_URL}/sendFiles`,
body, body,
}); });
@ -72,3 +74,21 @@ export const sendFile = async (
return [null, `Не удалось отправить файл. ${error}`]; return [null, `Не удалось отправить файл. ${error}`];
} }
}; };
export const createTicket = async (
ticketNameField: string,
ticketBodyField: string
): Promise<[CreateTicketResponse | null, string?]> => {
try {
const createTicketResponse = await createTicketRequest({
url: `${API_URL}/create`,
body: { Title: ticketNameField, Message: ticketBodyField },
});
return [createTicketResponse];
} catch (nativeError) {
const [error] = parseAxiosError(nativeError);
return [null, `Не удалось отправить файл. ${error}`];
}
};

@ -63,20 +63,22 @@ export const sendPayment = async ({
} }
}; };
export const sendRSPayment = async (money: number): Promise<string | null> => { export const sendRSPayment = async (
money: number
): Promise<[string | null, string?]> => {
try { try {
await makeRequest<unknown, string>({ const sendRSPaymentResponse = await makeRequest<{ money: number }, string>({
method: "POST", method: "POST",
url: `${API_URL}/wallet/rspay`, url: `${API_URL}/wallet/rspay`,
body: { money: money }, body: { money },
useToken: true, useToken: true,
withCredentials: false, withCredentials: false,
}); });
return null; return [sendRSPaymentResponse];
} catch (nativeError) { } catch (nativeError) {
const [error] = parseAxiosError(nativeError); const [error] = parseAxiosError(nativeError);
return `Ошибка оплаты. ${error}`; return [null, `Ошибка оплаты. ${error}`];
} }
}; };

@ -11,7 +11,6 @@ import {
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
import { import {
createTicket,
getMessageFromFetchError, getMessageFromFetchError,
throttle, throttle,
TicketMessage, TicketMessage,
@ -59,6 +58,7 @@ import AttachFileIcon from "@mui/icons-material/AttachFile";
import ChatDocument from "./ChatDocument"; import ChatDocument from "./ChatDocument";
import ChatImage from "./ChatImage"; import ChatImage from "./ChatImage";
import ChatVideo from "./ChatVideo"; import ChatVideo from "./ChatVideo";
import { createTicket } from "@api/ticket";
type ModalWarningType = type ModalWarningType =
| "errorType" | "errorType"
@ -267,29 +267,24 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
if (!sessionData?.ticketId) { if (!sessionData?.ticketId) {
setIsMessageSending(true); setIsMessageSending(true);
createTicket({
url: process.env.REACT_APP_DOMAIN + "/heruvym/create", const [createTicketresult, createTicketerror] = await createTicket(
body: { "Unauth title",
Title: "Unauth title", messageField
Message: messageField, );
},
useToken: Boolean(user), if (createTicketerror) {
}) enqueueSnackbar(createTicketerror);
.then((response) => { } else if (createTicketresult) {
setTicketData({ setTicketData({
ticketId: response.Ticket, ticketId: createTicketresult.Ticket,
sessionId: response.sess, sessionId: createTicketresult.sess,
}); });
setSseEnabled(true); setSseEnabled(true);
}) }
.catch((error) => {
const errorMessage = getMessageFromFetchError(error);
if (errorMessage) enqueueSnackbar(errorMessage);
})
.finally(() => {
setMessageField(""); setMessageField("");
setIsMessageSending(false); setIsMessageSending(false);
});
} else { } else {
setIsMessageSending(true); setIsMessageSending(true);
@ -333,18 +328,18 @@ export default function Chat({ open = false, onclickArrow, sx }: Props) {
let data; let data;
if (!ticket.sessionData?.ticketId) { if (!ticket.sessionData?.ticketId) {
try { try {
data = await createTicket({ const [createTicketresult] = await createTicket("Unauth title", "");
url: process.env.REACT_APP_DOMAIN + "/heruvym/create",
body: { if (createTicketresult) {
Title: "Unauth title", data = createTicketresult;
Message: "", }
},
useToken: Boolean(user), if (data) {
});
setTicketData({ setTicketData({
ticketId: data.Ticket, ticketId: data.Ticket,
sessionId: data.sess, sessionId: data.sess,
}); });
}
} catch (error: any) { } catch (error: any) {
const errorMessage = getMessageFromFetchError(error); const errorMessage = getMessageFromFetchError(error);
if (errorMessage) enqueueSnackbar(errorMessage); if (errorMessage) enqueueSnackbar(errorMessage);

@ -98,7 +98,7 @@ export default function ChatDocument({
</svg> </svg>
<Link <Link
download="" download=""
href={`https://storage.yandexcloud.net/pair/${file}`} href={`https://3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b.s3.timeweb.cloud/pair/${file}`}
style={{ style={{
color: "#7E2AEA", color: "#7E2AEA",
display: "flex", display: "flex",

@ -110,7 +110,7 @@ export default function ChatImage({
height: "217px", height: "217px",
width: "217px", width: "217px",
}} }}
src={`https://storage.yandexcloud.net/pair/${file}`} src={`https://3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b.s3.timeweb.cloud/pair/${file}`}
/> />
</ButtonBase> </ButtonBase>
</Box> </Box>

@ -113,7 +113,7 @@ export default function ChatImage({
}} }}
controls controls
> >
<source src={`https://storage.yandexcloud.net/pair/${file}`} /> <source src={`https://3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b.s3.timeweb.cloud/pair/${file}`} />
</Box> </Box>
</Box> </Box>
</Box> </Box>

@ -139,10 +139,12 @@ export default function Payment() {
return; return;
} }
const sendRSPaymentError = await sendRSPayment(Number(paymentValueField)); const [sendRSPaymentResponse] = await sendRSPayment(
Number(paymentValueField)
);
if (sendRSPaymentError) { if (sendRSPaymentResponse) {
return enqueueSnackbar(sendRSPaymentError); return enqueueSnackbar(sendRSPaymentResponse);
} }
enqueueSnackbar( enqueueSnackbar(

@ -12,7 +12,7 @@ export default function ChatImageNewWindow() {
maxHeight: "100vh", maxHeight: "100vh",
maxWidth: "100vw", maxWidth: "100vw",
}} }}
src={`https://storage.yandexcloud.net/pair/${srcImage}`} src={`https://3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b.s3.timeweb.cloud/pair/${srcImage}`}
/> />
</> </>
); );

@ -1,32 +1,38 @@
import { Box, Typography, FormControl, InputBase, useMediaQuery, useTheme, Button } from "@mui/material" import {
import { useState } from "react" Box,
import { useNavigate } from "react-router-dom" Typography,
import { enqueueSnackbar } from "notistack" FormControl,
import { cardShadow } from "@root/utils/theme" InputBase,
import { createTicket } from "@frontend/kitui" useMediaQuery,
useTheme,
Button,
} from "@mui/material";
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { enqueueSnackbar } from "notistack";
import { cardShadow } from "@root/utils/theme";
import { createTicket } from "@api/ticket";
export default function CreateTicket() { export default function CreateTicket() {
const theme = useTheme() const theme = useTheme();
const upMd = useMediaQuery(theme.breakpoints.up("md")) const upMd = useMediaQuery(theme.breakpoints.up("md"));
const navigate = useNavigate() const navigate = useNavigate();
const [ticketNameField, setTicketNameField] = useState<string>("") const [ticketNameField, setTicketNameField] = useState<string>("");
const [ticketBodyField, setTicketBodyField] = useState<string>("") const [ticketBodyField, setTicketBodyField] = useState<string>("");
async function handleCreateTicket() { async function handleCreateTicket() {
if (!ticketBodyField || !ticketNameField) return if (!ticketBodyField || !ticketNameField) return;
createTicket({ const [createTicketresult, createTicketerror] = await createTicket(
url: process.env.REACT_APP_DOMAIN + "/heruvym/create", ticketNameField,
body: { ticketBodyField
Title: ticketNameField, );
Message: ticketBodyField,
if (createTicketerror) {
return enqueueSnackbar(createTicketerror);
} }
}).then(result => {
navigate(`/support/${result.Ticket}`) navigate(`/support/${createTicketresult?.Ticket}`);
}).catch(error => {
enqueueSnackbar(error.message)
})
} }
return ( return (
@ -39,9 +45,7 @@ export default function CreateTicket() {
borderRadius: "12px", borderRadius: "12px",
p: upMd ? "20px" : undefined, p: upMd ? "20px" : undefined,
gap: upMd ? "40px" : "20px", gap: upMd ? "40px" : "20px",
boxShadow: upMd boxShadow: upMd ? cardShadow : undefined,
? cardShadow
: undefined,
}} }}
> >
<Box <Box
@ -125,8 +129,10 @@ export default function CreateTicket() {
variant="pena-contained-dark" variant="pena-contained-dark"
onClick={handleCreateTicket} onClick={handleCreateTicket}
disabled={!ticketBodyField || !ticketNameField} disabled={!ticketBodyField || !ticketNameField}
>Отправить</Button> >
Отправить
</Button>
</Box> </Box>
</Box> </Box>
) );
} }

@ -1,8 +1,8 @@
import { useEffect, useLayoutEffect, useRef } from "react" import { useEffect, useLayoutEffect, useRef } from "react";
import { devlog } from "@frontend/kitui" import { devlog } from "@frontend/kitui";
import { ServiceKeyToPrivilegesMap } from "@root/model/privilege" import { ServiceKeyToPrivilegesMap } from "@root/model/privilege";
import { getCustomTariffs } from "@root/api/tariff" import { getCustomTariffs } from "@root/api/tariff";
export function useCustomTariffs({ export function useCustomTariffs({
onError, onError,
@ -11,28 +11,35 @@ export function useCustomTariffs({
onNewUser: (response: ServiceKeyToPrivilegesMap) => void; onNewUser: (response: ServiceKeyToPrivilegesMap) => void;
onError: (error: any) => void; onError: (error: any) => void;
}) { }) {
const onNewUserRef = useRef(onNewUser) const onNewUserRef = useRef(onNewUser);
const onErrorRef = useRef(onError) const onErrorRef = useRef(onError);
useLayoutEffect(() => { useLayoutEffect(() => {
onNewUserRef.current = onNewUser onNewUserRef.current = onNewUser;
onErrorRef.current = onError onErrorRef.current = onError;
}) });
useEffect(() => { useEffect(() => {
const controller = new AbortController() const controller = new AbortController();
getCustomTariffs(controller.signal) const getCustomTariffsRequest = async () => {
.then(([customTariffs]) => { const [customTariffs, customTariffsError] = await getCustomTariffs(
if (customTariffs) { controller.signal
onNewUserRef.current(customTariffs) );
if (customTariffsError) {
devlog("Error fetching custom tariffs", customTariffsError);
onErrorRef.current(customTariffsError);
return;
} }
}) if (customTariffs) {
.catch(([_, error]) => { onNewUserRef.current(customTariffs);
devlog("Error fetching custom tariffs", error) }
onErrorRef.current(error) };
})
return () => controller.abort() getCustomTariffsRequest();
}, [])
return () => controller.abort();
}, []);
} }

@ -1,8 +1,8 @@
import { useEffect, useLayoutEffect, useRef, useState } from "react" import { useEffect, useLayoutEffect, useRef, useState } from "react";
import { getTariffs } from "@root/api/tariff" import { getTariffs } from "@root/api/tariff";
import type { Tariff } from "@frontend/kitui" import type { Tariff } from "@frontend/kitui";
export function useTariffFetcher({ export function useTariffFetcher({
tariffsPerPage, tariffsPerPage,
@ -16,32 +16,42 @@ export function useTariffFetcher({
onSuccess: (response: Tariff[]) => void; onSuccess: (response: Tariff[]) => void;
onError?: (error: Error) => void; onError?: (error: Error) => void;
}) { }) {
const [fetchState, setFetchState] = useState<"fetching" | "idle" | "all fetched">("idle") const [fetchState, setFetchState] = useState<
const onSuccessRef = useRef(onSuccess) "fetching" | "idle" | "all fetched"
const onErrorRef = useRef(onError) >("idle");
const onSuccessRef = useRef(onSuccess);
const onErrorRef = useRef(onError);
useLayoutEffect(() => { useLayoutEffect(() => {
onSuccessRef.current = onSuccess onSuccessRef.current = onSuccess;
onErrorRef.current = onError onErrorRef.current = onError;
}, [onError, onSuccess]) }, [onError, onSuccess]);
useEffect(() => { useEffect(() => {
const controller = new AbortController() const controller = new AbortController();
setFetchState("fetching") const getTariffsRequest = async () => {
getTariffs(apiPage, tariffsPerPage, controller.signal) setFetchState("fetching");
.then(([result]) => { const [tariffs, tariffsError] = await getTariffs(
if (result && result.tariffs.length > 0) { apiPage,
onSuccessRef.current(result.tariffs) tariffsPerPage,
setFetchState("idle") controller.signal
} else setFetchState("all fetched") );
})
.catch(([_, error]) => {
onErrorRef.current?.(error)
})
return () => controller.abort() if (tariffsError) {
}, [apiPage, tariffsPerPage]) return onErrorRef.current?.(new Error(tariffsError));
}
return fetchState if (tariffs && tariffs.tariffs.length > 0) {
onSuccessRef.current(tariffs.tariffs);
setFetchState("idle");
} else setFetchState("all fetched");
};
getTariffsRequest();
return () => controller.abort();
}, [apiPage, tariffsPerPage]);
return fetchState;
} }