This commit is contained in:
talorr
2026-03-27 03:36:08 +03:00
parent 8a97ce6d54
commit cda36918e8
225 changed files with 35641 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
type ApiErrorPayload = {
message?: string;
issues?: {
formErrors?: string[];
fieldErrors?: Record<string, string[] | undefined>;
};
};
type ApiLikeError = Error & {
statusCode?: number;
status?: number;
data?: ApiErrorPayload;
};
const apiFieldLabels: Record<string, string> = {
email: "Email",
password: "Пароль",
confirmPassword: "Повтор пароля",
title: "Заголовок",
body: "Текст",
status: "Статус",
startsAt: "Начало",
expiresAt: "Окончание"
};
function getApiFieldLabel(field: string) {
return apiFieldLabels[field] ?? field;
}
function getApiErrorMessage(error: ApiLikeError) {
const formErrors = Array.isArray(error.data?.issues?.formErrors)
? error.data!.issues!.formErrors.filter((entry) => typeof entry === "string" && entry.trim())
: [];
if (formErrors.length > 0) {
return formErrors.join("\n");
}
const fieldErrors = error.data?.issues?.fieldErrors;
if (fieldErrors && typeof fieldErrors === "object") {
const messages = Object.entries(fieldErrors)
.flatMap(([field, value]) =>
(Array.isArray(value) ? value : [])
.filter((entry) => typeof entry === "string" && entry.trim())
.map((entry) => `${getApiFieldLabel(field)}: ${entry}`)
);
if (messages.length > 0) {
return messages.join("\n");
}
}
const responseMessage = typeof error.data?.message === "string" ? error.data.message.trim() : "";
if (responseMessage) {
return responseMessage;
}
const statusCode = error.statusCode ?? error.status;
if (statusCode === 400) return "Проверьте правильность заполнения формы";
if (statusCode === 401) return "Неверный логин или пароль";
if (statusCode === 403) return "Недостаточно прав для выполнения действия";
if (statusCode === 404) return "Запрашиваемые данные не найдены";
if (statusCode === 409) return "Такая запись уже существует";
if (statusCode === 422) return "Не удалось обработать введённые данные";
if (statusCode && statusCode >= 500) return "Ошибка сервера. Попробуйте ещё раз позже";
return error.message || "Не удалось выполнить запрос";
}
export function useApi<T>(path: string, options: Parameters<typeof $fetch<T>>[1] = {}) {
const config = useRuntimeConfig();
const token = useState<string | null>("auth-token", () => null);
const baseUrl = process.server ? config.apiBaseInternal : config.public.apiBase;
const headers = new Headers(options.headers as HeadersInit | undefined);
if (!headers.has("Content-Type") && options.method && options.method !== "GET") {
headers.set("Content-Type", "application/json");
}
if (token.value) {
headers.set("Authorization", `Bearer ${token.value}`);
}
return $fetch<T>(`${baseUrl}${path}`, {
...options,
headers,
credentials: "include"
}).catch((error: ApiLikeError) => {
throw new Error(getApiErrorMessage(error));
});
}