flysoft-react-ui 0.1.16 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/utils/Badge.d.ts +3 -0
- package/dist/components/utils/Badge.d.ts.map +1 -1
- package/dist/components/utils/Badge.js +11 -4
- package/dist/docs/BadgeDocs.d.ts +4 -0
- package/dist/docs/BadgeDocs.d.ts.map +1 -0
- package/dist/docs/BadgeDocs.js +7 -0
- package/dist/docs/DocsMenu.d.ts.map +1 -1
- package/dist/docs/DocsMenu.js +1 -1
- package/dist/docs/DocsRouter.d.ts.map +1 -1
- package/dist/docs/DocsRouter.js +2 -1
- package/dist/fontawesome/css/all.min.css +5 -0
- package/dist/fontawesome/webfonts/fa-brands-400.eot +0 -0
- package/dist/fontawesome/webfonts/fa-brands-400.svg +3717 -0
- package/dist/fontawesome/webfonts/fa-brands-400.ttf +0 -0
- package/dist/fontawesome/webfonts/fa-brands-400.woff +0 -0
- package/dist/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
- package/dist/fontawesome/webfonts/fa-duotone-900.eot +0 -0
- package/dist/fontawesome/webfonts/fa-duotone-900.svg +15328 -0
- package/dist/fontawesome/webfonts/fa-duotone-900.ttf +0 -0
- package/dist/fontawesome/webfonts/fa-duotone-900.woff +0 -0
- package/dist/fontawesome/webfonts/fa-duotone-900.woff2 +0 -0
- package/dist/fontawesome/webfonts/fa-light-300.eot +0 -0
- package/dist/fontawesome/webfonts/fa-light-300.svg +12423 -0
- package/dist/fontawesome/webfonts/fa-light-300.ttf +0 -0
- package/dist/fontawesome/webfonts/fa-light-300.woff +0 -0
- package/dist/fontawesome/webfonts/fa-light-300.woff2 +0 -0
- package/dist/fontawesome/webfonts/fa-regular-400.eot +0 -0
- package/dist/fontawesome/webfonts/fa-regular-400.svg +11323 -0
- package/dist/fontawesome/webfonts/fa-regular-400.ttf +0 -0
- package/dist/fontawesome/webfonts/fa-regular-400.woff +0 -0
- package/dist/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
- package/dist/fontawesome/webfonts/fa-solid-900.eot +0 -0
- package/dist/fontawesome/webfonts/fa-solid-900.svg +9653 -0
- package/dist/fontawesome/webfonts/fa-solid-900.ttf +0 -0
- package/dist/fontawesome/webfonts/fa-solid-900.woff +0 -0
- package/dist/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.js +1 -1
- package/dist/services/apiClient.d.ts +89 -0
- package/dist/services/apiClient.d.ts.map +1 -0
- package/dist/services/apiClient.js +207 -0
- package/package.json +3 -2
package/dist/main.js
CHANGED
|
@@ -3,4 +3,4 @@ import { StrictMode } from "react";
|
|
|
3
3
|
import { createRoot } from "react-dom/client";
|
|
4
4
|
import { BrowserRouter } from "react-router-dom";
|
|
5
5
|
import App from "./App";
|
|
6
|
-
createRoot(document.getElementById("root")).render(_jsx(StrictMode, { children: _jsx(BrowserRouter, { children: _jsx(App, {}) }) }));
|
|
6
|
+
createRoot(document.getElementById("root")).render(_jsx(StrictMode, { children: _jsx(BrowserRouter, { future: { v7_startTransition: true, v7_relativeSplatPath: true }, children: _jsx(App, {}) }) }));
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { type AxiosResponse } from "axios";
|
|
2
|
+
export interface ApiClientConfig {
|
|
3
|
+
baseURL?: string;
|
|
4
|
+
timeout?: number;
|
|
5
|
+
headers?: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
type TokenProvider = () => string | undefined;
|
|
8
|
+
interface FileResponse {
|
|
9
|
+
data: Blob;
|
|
10
|
+
headers: AxiosResponse["headers"];
|
|
11
|
+
}
|
|
12
|
+
interface UploadFileOptions {
|
|
13
|
+
paramName?: string;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
declare class ApiClientService {
|
|
17
|
+
private instance;
|
|
18
|
+
private tokenProvider?;
|
|
19
|
+
constructor(config?: ApiClientConfig);
|
|
20
|
+
private setupInterceptors;
|
|
21
|
+
/**
|
|
22
|
+
* Establece el proveedor de token que se usará en todas las peticiones
|
|
23
|
+
* @param provider Función que retorna el token de autorización
|
|
24
|
+
*/
|
|
25
|
+
setTokenProvider(provider: TokenProvider | undefined): void;
|
|
26
|
+
/**
|
|
27
|
+
* Limpia el proveedor de token
|
|
28
|
+
*/
|
|
29
|
+
clearTokenProvider(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Actualiza la configuración por defecto del cliente
|
|
32
|
+
*/
|
|
33
|
+
updateDefaults(config: ApiClientConfig): void;
|
|
34
|
+
private axiosRequest;
|
|
35
|
+
/**
|
|
36
|
+
* Realiza una petición GET
|
|
37
|
+
*/
|
|
38
|
+
get<T = unknown>(url: string, headers?: Record<string, string>): Promise<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Realiza una petición POST
|
|
41
|
+
*/
|
|
42
|
+
post<T = unknown>(url: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
43
|
+
/**
|
|
44
|
+
* Realiza una petición PUT
|
|
45
|
+
*/
|
|
46
|
+
put<T = unknown>(url: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Realiza una petición DELETE
|
|
49
|
+
*/
|
|
50
|
+
del<T = unknown>(url: string, headers?: Record<string, string>): Promise<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Obtiene un archivo como Blob
|
|
53
|
+
*/
|
|
54
|
+
getFile(url: string, headers?: Record<string, string>): Promise<FileResponse>;
|
|
55
|
+
/**
|
|
56
|
+
* Obtiene un archivo y retorna su URL como objeto
|
|
57
|
+
*/
|
|
58
|
+
getFileAsUrl(url: string, headers?: Record<string, string>): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Abre un archivo en una nueva ventana
|
|
61
|
+
*/
|
|
62
|
+
openFile(url: string, headers?: Record<string, string>): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Descarga un archivo
|
|
65
|
+
*/
|
|
66
|
+
downloadFile(url: string, headers?: Record<string, string>): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Sube uno o más archivos usando FormData
|
|
69
|
+
*/
|
|
70
|
+
uploadFile<T = unknown>(url: string, files: FileList | File[], headers?: UploadFileOptions): Promise<T>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Cliente de API compartido con todas las funciones de HTTP
|
|
74
|
+
*/
|
|
75
|
+
export declare const apiClient: ApiClientService;
|
|
76
|
+
/**
|
|
77
|
+
* Crea una nueva instancia del cliente de API
|
|
78
|
+
*/
|
|
79
|
+
export declare const createApiClient: (config?: ApiClientConfig) => ApiClientService;
|
|
80
|
+
/**
|
|
81
|
+
* Establece el proveedor de token global para el cliente compartido
|
|
82
|
+
*/
|
|
83
|
+
export declare const setApiClientTokenProvider: (provider: TokenProvider | undefined) => void;
|
|
84
|
+
/**
|
|
85
|
+
* Limpia el proveedor de token global
|
|
86
|
+
*/
|
|
87
|
+
export declare const clearApiClientTokenProvider: () => void;
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=apiClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../src/services/apiClient.ts"],"names":[],"mappings":"AAAA,OAAc,EAEZ,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAEf,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,KAAK,aAAa,GAAG,MAAM,MAAM,GAAG,SAAS,CAAC;AAE9C,UAAU,YAAY;IACpB,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;CACnC;AAED,UAAU,iBAAiB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,cAAM,gBAAgB;IACpB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,aAAa,CAAC,CAAgB;gBAE1B,MAAM,CAAC,EAAE,eAAe;IAapC,OAAO,CAAC,iBAAiB;IA8BzB;;;OAGG;IACH,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI;IAI3D;;OAEG;IACH,kBAAkB,IAAI,IAAI;IAI1B;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;YAa/B,YAAY;IAmB1B;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EACnB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,OAAO,CAAC,CAAC,CAAC;IASb;;OAEG;IACG,IAAI,CAAC,CAAC,GAAG,OAAO,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,OAAO,CAAC,CAAC,CAAC;IAUb;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EACnB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,OAAO,CAAC,CAAC,CAAC;IAUb;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EACnB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,OAAO,CAAC,CAAC,CAAC;IASb;;OAEG;IACG,OAAO,CACX,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACnC,OAAO,CAAC,YAAY,CAAC;IAWxB;;OAEG;IACG,YAAY,CAChB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACnC,OAAO,CAAC,MAAM,CAAC;IAMlB;;OAEG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAM5E;;OAEG;IACG,YAAY,CAChB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC;IAmBhB;;OAEG;IACG,UAAU,CAAC,CAAC,GAAG,OAAO,EAC1B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,QAAQ,GAAG,IAAI,EAAE,EACxB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,CAAC,CAAC;CAed;AAKD;;GAEG;AACH,eAAO,MAAM,SAAS,kBAAe,CAAC;AAEtC;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,SAAS,eAAe,KAAG,gBAE1D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,GACpC,UAAU,aAAa,GAAG,SAAS,KAClC,IAEF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,2BAA2B,QAAO,IAE9C,CAAC"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import axios, {} from "axios";
|
|
2
|
+
class ApiClientService {
|
|
3
|
+
instance;
|
|
4
|
+
tokenProvider;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.instance = axios.create({
|
|
7
|
+
baseURL: config?.baseURL ?? "",
|
|
8
|
+
timeout: config?.timeout ?? 15000,
|
|
9
|
+
headers: {
|
|
10
|
+
"Content-Type": "application/json",
|
|
11
|
+
...config?.headers,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
this.setupInterceptors();
|
|
15
|
+
}
|
|
16
|
+
setupInterceptors() {
|
|
17
|
+
// Request interceptor para inyectar el token automáticamente
|
|
18
|
+
this.instance.interceptors.request.use((config) => {
|
|
19
|
+
const token = this.tokenProvider?.();
|
|
20
|
+
if (token && config.headers) {
|
|
21
|
+
// Manejo compatible con diferentes versiones de axios
|
|
22
|
+
if ("set" in config.headers && typeof config.headers.set === "function") {
|
|
23
|
+
config.headers.set("Authorization", `Bearer ${token}`);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
const headers = config.headers;
|
|
27
|
+
headers.Authorization = `Bearer ${token}`;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return config;
|
|
31
|
+
}, (error) => {
|
|
32
|
+
return Promise.reject(error);
|
|
33
|
+
});
|
|
34
|
+
// Response interceptor para manejo de errores (opcional, puede extenderse)
|
|
35
|
+
this.instance.interceptors.response.use((response) => response, (error) => {
|
|
36
|
+
return Promise.reject(error);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Establece el proveedor de token que se usará en todas las peticiones
|
|
41
|
+
* @param provider Función que retorna el token de autorización
|
|
42
|
+
*/
|
|
43
|
+
setTokenProvider(provider) {
|
|
44
|
+
this.tokenProvider = provider;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Limpia el proveedor de token
|
|
48
|
+
*/
|
|
49
|
+
clearTokenProvider() {
|
|
50
|
+
this.tokenProvider = undefined;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Actualiza la configuración por defecto del cliente
|
|
54
|
+
*/
|
|
55
|
+
updateDefaults(config) {
|
|
56
|
+
if (config.baseURL) {
|
|
57
|
+
this.instance.defaults.baseURL = config.baseURL;
|
|
58
|
+
}
|
|
59
|
+
if (config.timeout) {
|
|
60
|
+
this.instance.defaults.timeout = config.timeout;
|
|
61
|
+
}
|
|
62
|
+
if (config.headers) {
|
|
63
|
+
// Actualizar headers comunes de forma segura
|
|
64
|
+
Object.assign(this.instance.defaults.headers.common || {}, config.headers);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async axiosRequest({ method, url, headers, body, }) {
|
|
68
|
+
return await this.instance({
|
|
69
|
+
method,
|
|
70
|
+
headers,
|
|
71
|
+
url,
|
|
72
|
+
data: body,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Realiza una petición GET
|
|
77
|
+
*/
|
|
78
|
+
async get(url, headers) {
|
|
79
|
+
const response = await this.axiosRequest({
|
|
80
|
+
method: "GET",
|
|
81
|
+
url,
|
|
82
|
+
headers,
|
|
83
|
+
});
|
|
84
|
+
return response.data;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Realiza una petición POST
|
|
88
|
+
*/
|
|
89
|
+
async post(url, body, headers) {
|
|
90
|
+
const response = await this.axiosRequest({
|
|
91
|
+
method: "POST",
|
|
92
|
+
url,
|
|
93
|
+
headers,
|
|
94
|
+
body,
|
|
95
|
+
});
|
|
96
|
+
return response.data;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Realiza una petición PUT
|
|
100
|
+
*/
|
|
101
|
+
async put(url, body, headers) {
|
|
102
|
+
const response = await this.axiosRequest({
|
|
103
|
+
method: "PUT",
|
|
104
|
+
url,
|
|
105
|
+
headers,
|
|
106
|
+
body,
|
|
107
|
+
});
|
|
108
|
+
return response.data;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Realiza una petición DELETE
|
|
112
|
+
*/
|
|
113
|
+
async del(url, headers) {
|
|
114
|
+
const response = await this.axiosRequest({
|
|
115
|
+
method: "DELETE",
|
|
116
|
+
url,
|
|
117
|
+
headers,
|
|
118
|
+
});
|
|
119
|
+
return response.data;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Obtiene un archivo como Blob
|
|
123
|
+
*/
|
|
124
|
+
async getFile(url, headers = {}) {
|
|
125
|
+
const response = await this.instance.get(url, {
|
|
126
|
+
responseType: "blob",
|
|
127
|
+
headers,
|
|
128
|
+
});
|
|
129
|
+
return {
|
|
130
|
+
data: response.data,
|
|
131
|
+
headers: response.headers,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Obtiene un archivo y retorna su URL como objeto
|
|
136
|
+
*/
|
|
137
|
+
async getFileAsUrl(url, headers = {}) {
|
|
138
|
+
const { data } = await this.getFile(url, headers);
|
|
139
|
+
const blob = new Blob([data], { type: data.type });
|
|
140
|
+
return URL.createObjectURL(blob);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Abre un archivo en una nueva ventana
|
|
144
|
+
*/
|
|
145
|
+
async openFile(url, headers) {
|
|
146
|
+
const { data } = await this.getFile(url, headers);
|
|
147
|
+
const urlData = URL.createObjectURL(data);
|
|
148
|
+
window.open(urlData);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Descarga un archivo
|
|
152
|
+
*/
|
|
153
|
+
async downloadFile(url, headers) {
|
|
154
|
+
const { data, headers: dataHeaders } = await this.getFile(url, headers);
|
|
155
|
+
const contentDisposition = dataHeaders["content-disposition"] || dataHeaders["Content-Disposition"];
|
|
156
|
+
const fileName = contentDisposition
|
|
157
|
+
?.split("filename=")[1]
|
|
158
|
+
?.split(";")[0]
|
|
159
|
+
.replaceAll('"', "");
|
|
160
|
+
const blob = new Blob([data], { type: data.type });
|
|
161
|
+
const link = document.createElement("a");
|
|
162
|
+
link.href = window.URL.createObjectURL(blob);
|
|
163
|
+
link.setAttribute("download", fileName || "");
|
|
164
|
+
document.body.appendChild(link);
|
|
165
|
+
link.click();
|
|
166
|
+
link.parentNode?.removeChild(link);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Sube uno o más archivos usando FormData
|
|
170
|
+
*/
|
|
171
|
+
async uploadFile(url, files, headers) {
|
|
172
|
+
const formData = new FormData();
|
|
173
|
+
const { paramName = "file", ...newHeaders } = headers || {};
|
|
174
|
+
const fileArray = Array.from(files);
|
|
175
|
+
for (const file of fileArray) {
|
|
176
|
+
formData.append(paramName, file, file.name);
|
|
177
|
+
}
|
|
178
|
+
const response = await this.instance.post(url, formData, {
|
|
179
|
+
headers: newHeaders,
|
|
180
|
+
});
|
|
181
|
+
return response.data;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Instancia compartida del cliente
|
|
185
|
+
const sharedClient = new ApiClientService();
|
|
186
|
+
/**
|
|
187
|
+
* Cliente de API compartido con todas las funciones de HTTP
|
|
188
|
+
*/
|
|
189
|
+
export const apiClient = sharedClient;
|
|
190
|
+
/**
|
|
191
|
+
* Crea una nueva instancia del cliente de API
|
|
192
|
+
*/
|
|
193
|
+
export const createApiClient = (config) => {
|
|
194
|
+
return new ApiClientService(config);
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Establece el proveedor de token global para el cliente compartido
|
|
198
|
+
*/
|
|
199
|
+
export const setApiClientTokenProvider = (provider) => {
|
|
200
|
+
sharedClient.setTokenProvider(provider);
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Limpia el proveedor de token global
|
|
204
|
+
*/
|
|
205
|
+
export const clearApiClientTokenProvider = () => {
|
|
206
|
+
sharedClient.clearTokenProvider();
|
|
207
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flysoft-react-ui",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "A modern React UI component library with Tailwind CSS, TypeScript, and FontAwesome 5. Includes forms, layouts, themes, and templates for rapid development.",
|
|
7
7
|
"keywords": [
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@tailwindcss/vite": "^4.1.12",
|
|
67
|
+
"axios": "^1.13.2",
|
|
67
68
|
"tailwindcss": "^4.1.12"
|
|
68
69
|
},
|
|
69
70
|
"devDependencies": {
|
|
@@ -77,9 +78,9 @@
|
|
|
77
78
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
78
79
|
"eslint-plugin-react-refresh": "^0.4.20",
|
|
79
80
|
"globals": "^16.3.0",
|
|
80
|
-
"react-router-dom": "^6.30.1",
|
|
81
81
|
"react": "^19.1.1",
|
|
82
82
|
"react-dom": "^19.1.1",
|
|
83
|
+
"react-router-dom": "^6.30.1",
|
|
83
84
|
"typescript": "~5.8.3",
|
|
84
85
|
"typescript-eslint": "^8.39.1",
|
|
85
86
|
"vite": "^7.1.2",
|