Arreglo en cliente Axios

This commit is contained in:
David Arranz 2026-04-03 21:42:11 +02:00
parent 8b0b90f0ce
commit 699e097016
3 changed files with 87 additions and 93 deletions

View File

@ -1,5 +1,6 @@
import { createContext, useCallback, useContext, useEffect, useState } from "react"; import { createContext, useCallback, useContext, useEffect, useState } from "react";
import { UNSAFE_NavigationContext, useBeforeUnload, useBlocker } from "react-router-dom"; import { UNSAFE_NavigationContext, useBeforeUnload, useBlocker } from "react-router-dom";
import { UnsavedChangesDialog } from "./components"; import { UnsavedChangesDialog } from "./components";
type ContextValue = { type ContextValue = {
@ -88,11 +89,10 @@ export function UnsavedChangesProvider({
}; };
}, [blocker, requestConfirm]); }, [blocker, requestConfirm]);
return ( return (
<UnsavedChangesContext.Provider value={{ requestConfirm }}> <UnsavedChangesContext.Provider value={{ requestConfirm }}>
{children} {children}
<UnsavedChangesDialog open={open} onConfirm={handleConfirm} /> <UnsavedChangesDialog onConfirm={handleConfirm} open={open} />
</UnsavedChangesContext.Provider> </UnsavedChangesContext.Provider>
); );
} }

View File

@ -1,99 +1,100 @@
import type { AxiosInstance } from "axios"; import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
import type { ICustomParams, IDataSource } from "../datasource.interface"; import type { ICustomParams, IDataSource } from "../datasource.interface";
import { defaultAxiosRequestConfig } from "./create-axios-instance"; import { defaultAxiosRequestConfig } from "./create-axios-instance";
/**
* Crea un DataSource basado en Axios.
* @param client Instancia de Axios que se utilizará para las peticiones HTTP.
* @returns Un objeto que implementa la interfaz IDataSource.
* @throws Error si la instancia de Axios no es válida o no tiene la configuración necesaria.
* @example
* const axiosInstance = createAxiosInstance({
* baseURL: "https://api.example.com",
* getAccessToken: () => localStorage.getItem("accessToken"),
* onAuthError: () => {
* console.error("Error de autenticación");
* // Manejar el error de autenticación, por ejemplo, redirigir al login
* },
* });
* const dataSource = createAxiosDataSource(axiosInstance);
*
*/
export const createAxiosDataSource = (client: AxiosInstance): IDataSource => { export const createAxiosDataSource = (client: AxiosInstance): IDataSource => {
// Validaciones de la instancia de Axios
if (!client) { if (!client) {
throw new Error("[Axios] Se esperaba una instancia de Axios."); throw new Error("[Axios] Se esperaba una instancia de Axios.");
} }
if (!(client as AxiosInstance).getUri) { if (!client.getUri || typeof client.getUri !== "function") {
throw new Error("[Axios] La instancia proporcionada no es una instancia de Axios válida."); throw new Error("[Axios] La instancia proporcionada no es una instancia de Axios válida.");
} }
if (typeof (client as AxiosInstance).getUri !== "function") { if (typeof client.getUri() !== "string") {
throw new Error("[Axios] La instancia proporcionada no tiene el método getUri.");
}
if (typeof (client as AxiosInstance).getUri() !== "string") {
throw new Error("[Axios] baseURL no está definido en esta instancia."); throw new Error("[Axios] baseURL no está definido en esta instancia.");
} }
return { return {
getBaseUrl: () => (client as AxiosInstance).getUri(), getBaseUrl: () => client.getUri(),
getList: async <T>(resource: string, params?: Record<string, unknown>): Promise<T> => { getList: async <R>(resource: string, params?: Record<string, unknown>): Promise<R> => {
const { signal, ...rest } = params as any; // en 'rest' puede venir el "criteria". const { signal, ...rest } = (params ?? {}) as Record<string, unknown> & {
signal?: AbortSignal;
};
const res = await (client as AxiosInstance).get<T[]>(resource, { signal, params: rest }); const res = await client.get<R>(resource, {
return <T>res.data; signal,
}, params: rest,
});
getOne: async <T>(resource: string, id: string | number, params?: Record<string, unknown>) => {
const res = await (client as AxiosInstance).get<T>(`${resource}/${id}`, params);
return res.data; return res.data;
}, },
getMany: async <T, R>(resource: string, ids: Array<string | number>): Promise<R> => { getOne: async <R>(
const res = await (client as AxiosInstance).get<T[]>(`${resource}`, { params: { ids } });
return <R>res.data;
},
createOne: async <T>(
resource: string,
data: Partial<T>,
params?: Record<string, unknown>
): Promise<T> => {
const res = await (client as AxiosInstance).post<T>(resource, data, params);
return res.data;
},
updateOne: async <T>(
resource: string,
id: string | number,
data: Partial<T>,
params?: Record<string, unknown>
) => {
const res = await (client as AxiosInstance).put<T>(`${resource}/${id}`, data, params);
return res.data;
},
deleteOne: async <T>(
resource: string, resource: string,
id: string | number, id: string | number,
params?: Record<string, unknown> params?: Record<string, unknown>
) => { ): Promise<R> => {
await (client as AxiosInstance).delete(`${resource}/${id}`, params); const res = await client.get<R>(`${resource}/${id}`, params);
return res.data;
}, },
custom: async <T>(customParams: ICustomParams) => { getMany: async <R>(resource: string, ids: Array<string | number>): Promise<R> => {
const res = await client.get<R>(resource, {
params: { ids },
});
return res.data;
},
createOne: async <TData, R>(
resource: string,
data: TData,
params?: Record<string, unknown>
): Promise<R> => {
const res = await client.post<R, AxiosResponse<R>, TData>(
resource,
data,
params as AxiosRequestConfig<TData>
);
return res.data;
},
updateOne: async <TData, R>(
resource: string,
id: string | number,
data: TData,
params?: Record<string, unknown>
): Promise<R> => {
const res = await client.put<R, AxiosResponse<R>, TData>(
`${resource}/${id}`,
data,
params as AxiosRequestConfig<TData>
);
return res.data;
},
deleteOne: async <R = void>(
resource: string,
id: string | number,
params?: Record<string, unknown>
): Promise<R> => {
const res = await client.delete<R>(`${resource}/${id}`, params);
return res.data;
},
custom: async <TData, R>(customParams: ICustomParams<TData>): Promise<R> => {
const { url, path, method, responseType, headers, signal, data, ...payload } = customParams; const { url, path, method, responseType, headers, signal, data, ...payload } = customParams;
const requestUrl = path ? `${(client as AxiosInstance).getUri()}/${path}` : url; const requestUrl = path ? `${client.getUri()}/${path}` : url;
if (!requestUrl) throw new Error('"url" or "path" param is missing'); if (!requestUrl) throw new Error('"url" or "path" param is missing');
const config = { const config: AxiosRequestConfig<TData> = {
url: requestUrl, url: requestUrl,
method, method,
responseType, responseType,
@ -103,32 +104,27 @@ export const createAxiosDataSource = (client: AxiosInstance): IDataSource => {
headers, headers,
}; };
let customResponse; let customResponse: AxiosResponse<R, TData>;
switch (method) { switch (method) {
case "put": case "put":
case "post": case "post":
case "patch": case "patch":
customResponse = await (client as AxiosInstance).request<T>({ customResponse = await client.request<R, AxiosResponse<R>, TData>({
...config, ...config,
data, data,
}); });
break; break;
case "delete": case "delete":
customResponse = await (client as AxiosInstance).delete<T>(requestUrl, { customResponse = await client.delete<R, AxiosResponse<R>, TData>(requestUrl, {
responseType, ...config,
headers,
...payload,
}); });
break; break;
default: default:
customResponse = await (client as AxiosInstance).get<T>(requestUrl, { customResponse = await client.get<R, AxiosResponse<R>, TData>(requestUrl, {
responseType, ...config,
signal,
headers,
...payload,
}); });
break; break;
} }

View File

@ -1,34 +1,32 @@
import type { ResponseType } from "axios"; import type { AxiosRequestConfig, ResponseType } from "axios";
export interface ICustomParams { export interface ICustomParams<T> {
url?: string; url?: string;
path?: string; path?: string;
method: "get" | "delete" | "head" | "options" | "post" | "put" | "patch"; method: "get" | "delete" | "head" | "options" | "post" | "put" | "patch";
signal?: AbortSignal; signal?: AbortSignal;
responseType?: ResponseType; responseType?: ResponseType;
headers?: { headers?: AxiosRequestConfig<T>["headers"];
[key: string]: unknown; data: T;
};
[key: string]: unknown; [key: string]: unknown;
} }
export interface IDataSource { export interface IDataSource {
getBaseUrl(): string; getBaseUrl(): string;
getList<T>(resource: string, params?: Record<string, unknown>): Promise<T>; getList<R>(resource: string, params?: Record<string, unknown>): Promise<R>;
getOne<T>(resource: string, id: string | number, params?: Record<string, unknown>): Promise<T>; getOne<R>(resource: string, id: string | number, params?: Record<string, unknown>): Promise<R>;
getMany<T, R>(resource: string, ids: Array<string | number>): Promise<R>; getMany<R>(resource: string, ids: Array<string | number>): Promise<R[]>;
createOne<T>(resource: string, data: Partial<T>, params?: Record<string, unknown>): Promise<T>; createOne<TData, R>(resource: string, data: TData, params?: Record<string, unknown>): Promise<R>;
updateOne<T>( updateOne<TData, R>(
resource: string, resource: string,
id: string | number, id: string | number,
data: Partial<T>, data: TData,
params?: Record<string, unknown> params?: Record<string, unknown>
): Promise<T>; ): Promise<R>;
deleteOne<T>( deleteOne<R = void>(
resource: string, resource: string,
id: string | number, id: string | number,
params?: Record<string, unknown> params?: Record<string, unknown>
): Promise<void>; ): Promise<R>;
custom<TData, R>(customParams: ICustomParams<TData>): Promise<R>;
custom: <R>(customParams: ICustomParams) => Promise<R>;
} }