@nocios/crudify-ui 1.2.1 → 1.2.3

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/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # CrudifyLogin - Integracion Completa
1
+ # @nocios/crudify-ui - Sistema Completo de Autenticación y CRUD
2
2
 
3
- > Componente de autenticacion completo y reutilizable para aplicaciones React, basado en la API de Crudify.
3
+ > Biblioteca completa de componentes React para autenticación y operaciones CRUD, basada en la API de Crudify con sistema de inicialización robusto y gestión unificada de estado.
4
4
 
5
- ## 🚀 Instalacion
5
+ ## 🚀 Instalación
6
6
 
7
7
  ```bash
8
8
  npm install @nocios/crudify-ui
@@ -10,23 +10,343 @@ npm install @nocios/crudify-ui
10
10
 
11
11
  ## 📋 Dependencias Requeridas
12
12
 
13
- Asegurate de tener estas dependencias en tu proyecto:
13
+ Asegúrate de tener estas dependencias en tu proyecto:
14
14
 
15
15
  ```bash
16
- npm install react react-dom @mui/material @mui/icons-material
16
+ npm install react react-dom @mui/material @mui/icons-material @emotion/react @emotion/styled
17
17
  ```
18
18
 
19
- ## 🎯 Uso Basico
19
+ ## **NUEVO: Sistema Unificado (Recomendado)**
20
20
 
21
- ### Integracion Simple
21
+ ### 🏗️ Implementación con CrudifyDataProvider
22
+
23
+ El nuevo sistema unificado proporciona inicialización robusta, gestión automática de tokens y operaciones CRUD sin configuración compleja:
24
+
25
+ ```tsx
26
+ // App.tsx - Configuración principal
27
+ import React from 'react';
28
+ import { CrudifyDataProvider } from '@nocios/crudify-ui';
29
+ import AppContent from './AppContent';
30
+
31
+ function App() {
32
+ return (
33
+ <CrudifyDataProvider
34
+ publicApiKey={process.env.REACT_APP_CRUDIFY_API_KEY}
35
+ env={process.env.NODE_ENV === 'development' ? 'dev' : 'prod'}
36
+ appName="Mi Aplicación"
37
+ >
38
+ <AppContent />
39
+ </CrudifyDataProvider>
40
+ );
41
+ }
42
+
43
+ export default App;
44
+ ```
45
+
46
+ ```tsx
47
+ // AppContent.tsx - Lógica de autenticación
48
+ import React from 'react';
49
+ import { useCrudifyAuth, CrudifyLogin } from '@nocios/crudify-ui';
50
+ import Dashboard from './Dashboard';
51
+
52
+ function AppContent() {
53
+ const { isAuthenticated, token, setToken, user, loading } = useCrudifyAuth();
54
+
55
+ if (loading) {
56
+ return <div>Cargando...</div>;
57
+ }
58
+
59
+ if (!isAuthenticated) {
60
+ return (
61
+ <CrudifyLogin
62
+ onLoginSuccess={(newToken) => {
63
+ setToken(newToken); // ✅ Sincronización automática
64
+ // No necesitas manejar redirección manual
65
+ }}
66
+ config={{
67
+ colors: { primaryColor: "#1066BA" },
68
+ loginActions: ["forgotPassword"]
69
+ }}
70
+ />
71
+ );
72
+ }
73
+
74
+ return <Dashboard user={user} />;
75
+ }
76
+ ```
22
77
 
23
78
  ```tsx
24
- import { CrudifyLogin } from "@nocios/crudify-ui";
79
+ // Dashboard.tsx - Uso de operaciones CRUD
80
+ import React, { useEffect, useState } from 'react';
81
+ import { useCrudifyData } from '@nocios/crudify-ui';
82
+
83
+ function Dashboard({ user }) {
84
+ const { readItems, createItem, isReady, loading } = useCrudifyData();
85
+ const [items, setItems] = useState([]);
86
+
87
+ useEffect(() => {
88
+ if (isReady) {
89
+ loadItems();
90
+ }
91
+ }, [isReady]);
92
+
93
+ const loadItems = async () => {
94
+ try {
95
+ const response = await readItems('products', { active: true });
96
+ if (response.success) {
97
+ setItems(response.data);
98
+ }
99
+ } catch (error) {
100
+ console.error('Error loading items:', error);
101
+ }
102
+ };
103
+
104
+ if (!isReady) {
105
+ return <div>Inicializando sistema...</div>;
106
+ }
107
+
108
+ return (
109
+ <div>
110
+ <h1>Dashboard - {user?.name}</h1>
111
+ <div>
112
+ {items.map(item => (
113
+ <div key={item.id}>{item.name}</div>
114
+ ))}
115
+ </div>
116
+ </div>
117
+ );
118
+ }
119
+ ```
120
+
121
+ ## 🔧 **Hooks Disponibles**
122
+
123
+ ### 🎯 **useCrudifyAuth** - Gestión de Autenticación
124
+
125
+ Hook principal para manejar el estado de autenticación:
126
+
127
+ ```tsx
128
+ import { useCrudifyAuth } from '@nocios/crudify-ui';
129
+
130
+ function AuthComponent() {
131
+ const {
132
+ isAuthenticated, // boolean - Si el usuario está autenticado
133
+ token, // string | null - Token JWT actual
134
+ setToken, // (token: string | null) => void - Función para establecer token
135
+ user, // object | null - Datos del usuario
136
+ loading, // boolean - Estado de carga
137
+ login, // (email: string, password: string) => Promise<CrudifyApiResponse>
138
+ logout, // () => void - Función para logout
139
+ refreshUserData // () => Promise<void> - Actualizar datos del usuario
140
+ } = useCrudifyAuth();
141
+
142
+ return (
143
+ <div>
144
+ {isAuthenticated ? (
145
+ <div>
146
+ <h1>Bienvenido, {user?.name}</h1>
147
+ <button onClick={logout}>Cerrar Sesión</button>
148
+ </div>
149
+ ) : (
150
+ <div>No autenticado</div>
151
+ )}
152
+ </div>
153
+ );
154
+ }
155
+ ```
156
+
157
+ ### 📊 **useCrudifyData** - Operaciones CRUD
158
+
159
+ Hook para realizar operaciones CRUD con inicialización automática:
160
+
161
+ ```tsx
162
+ import { useCrudifyData } from '@nocios/crudify-ui';
163
+
164
+ function DataComponent() {
165
+ const {
166
+ readItems, // (moduleKey: string, filter?: object, options?: any) => Promise<CrudifyApiResponse>
167
+ readItem, // (moduleKey: string, filter: object, options?: any) => Promise<CrudifyApiResponse>
168
+ createItem, // (moduleKey: string, data: object, options?: any) => Promise<CrudifyApiResponse>
169
+ updateItem, // (moduleKey: string, data: object, options?: any) => Promise<CrudifyApiResponse>
170
+ deleteItem, // (moduleKey: string, id: string, options?: any) => Promise<CrudifyApiResponse>
171
+ transaction, // (operations: any[], options?: any) => Promise<CrudifyApiResponse>
172
+ getStructure, // (options?: any) => Promise<CrudifyApiResponse>
173
+ getStructurePublic,// (options?: any) => Promise<CrudifyApiResponse>
174
+ isReady, // boolean - Si el sistema está listo para operaciones
175
+ loading // boolean - Estado de carga
176
+ } = useCrudifyData();
177
+
178
+ const handleLoadProducts = async () => {
179
+ if (!isReady) return;
180
+
181
+ try {
182
+ const response = await readItems('products', { active: true });
183
+ if (response.success) {
184
+ console.log('Productos:', response.data);
185
+ }
186
+ } catch (error) {
187
+ console.error('Error:', error);
188
+ }
189
+ };
190
+
191
+ return (
192
+ <div>
193
+ <button onClick={handleLoadProducts} disabled={!isReady}>
194
+ Cargar Productos
195
+ </button>
196
+ </div>
197
+ );
198
+ }
199
+ ```
200
+
201
+ ### 👤 **useCrudifyUser** - Gestión de Usuario
202
+
203
+ Hook especializado para datos del usuario:
204
+
205
+ ```tsx
206
+ import { useCrudifyUser } from '@nocios/crudify-ui';
207
+
208
+ function UserProfile() {
209
+ const {
210
+ user, // object | null - Datos del usuario
211
+ loading, // boolean - Estado de carga
212
+ error, // string | null - Error si existe
213
+ refreshUserData, // () => Promise<void> - Actualizar datos
214
+ updateUserProfile, // (data: object) => Promise<CrudifyApiResponse>
215
+ isReady // boolean - Si está listo
216
+ } = useCrudifyUser();
217
+
218
+ if (loading) return <div>Cargando perfil...</div>;
219
+ if (error) return <div>Error: {error}</div>;
220
+
221
+ return (
222
+ <div>
223
+ <h2>Perfil de Usuario</h2>
224
+ <p>Nombre: {user?.name}</p>
225
+ <p>Email: {user?.email}</p>
226
+ <button onClick={refreshUserData}>Actualizar Datos</button>
227
+ </div>
228
+ );
229
+ }
230
+ ```
231
+
232
+ ### ⚙️ **useCrudifyConfig** - Acceso a Configuración
233
+
234
+ Hook para acceder a la configuración actual:
235
+
236
+ ```tsx
237
+ import { useCrudifyConfig } from '@nocios/crudify-ui';
238
+
239
+ function ConfigDisplay() {
240
+ const {
241
+ config, // CrudifyConfig - Configuración actual
242
+ updateConfig, // (newConfig: Partial<CrudifyConfig>) => void
243
+ isConfigured, // boolean - Si está configurado
244
+ environment // string - Entorno actual (dev, prod, etc.)
245
+ } = useCrudifyConfig();
246
+
247
+ return (
248
+ <div>
249
+ <h3>Configuración Actual</h3>
250
+ <p>App: {config.appName}</p>
251
+ <p>Entorno: {environment}</p>
252
+ <p>Configurado: {isConfigured ? 'Sí' : 'No'}</p>
253
+ </div>
254
+ );
255
+ }
256
+ ```
257
+
258
+ ## ⚙️ **Configuración del CrudifyDataProvider**
259
+
260
+ ### Props del Provider
261
+
262
+ ```tsx
263
+ interface CrudifyDataProviderProps {
264
+ children: React.ReactNode;
265
+
266
+ // Configuración básica
267
+ publicApiKey?: string; // Clave de API de Crudify
268
+ env?: 'dev' | 'stg' | 'api' | 'prod'; // Entorno
269
+ appName?: string; // Nombre de la aplicación
270
+
271
+ // Configuración visual
272
+ logo?: string; // URL del logo
273
+ colors?: {
274
+ primaryColor?: string; // Color principal
275
+ bgColor?: string; // Color de fondo
276
+ [key: string]: string | undefined;
277
+ };
278
+
279
+ // Configuración avanzada
280
+ autoReadFromCookies?: boolean; // Leer configuración desde cookies (default: true)
281
+ autoInitialize?: boolean; // Inicializar automáticamente (default: true)
282
+ persistToken?: boolean; // Persistir token entre sesiones (default: true)
283
+
284
+ // Configuración de login
285
+ loginActions?: string[]; // Acciones disponibles: ["forgotPassword", "createUser"]
286
+
287
+ // Callbacks opcionales
288
+ onInitialized?: () => void; // Callback cuando se inicializa
289
+ onError?: (error: string) => void; // Callback para errores
290
+ onTokenChange?: (token: string | null) => void; // Callback cuando cambia el token
291
+ }
292
+ ```
293
+
294
+ ### Ejemplo de Configuración Completa
295
+
296
+ ```tsx
297
+ import { CrudifyDataProvider } from '@nocios/crudify-ui';
298
+
299
+ function App() {
300
+ return (
301
+ <CrudifyDataProvider
302
+ // Configuración básica
303
+ publicApiKey={process.env.REACT_APP_CRUDIFY_API_KEY}
304
+ env={process.env.NODE_ENV === 'development' ? 'dev' : 'prod'}
305
+ appName="Mi Aplicación"
306
+
307
+ // Configuración visual
308
+ logo="/logo.png"
309
+ colors={{
310
+ primaryColor: "#1066BA",
311
+ bgColor: "#f5f5f5"
312
+ }}
313
+
314
+ // Configuración avanzada
315
+ autoReadFromCookies={true}
316
+ autoInitialize={true}
317
+ persistToken={true}
318
+
319
+ // Acciones de login disponibles
320
+ loginActions={["forgotPassword", "createUser"]}
321
+
322
+ // Callbacks
323
+ onInitialized={() => console.log('Sistema inicializado')}
324
+ onError={(error) => console.error('Error del sistema:', error)}
325
+ onTokenChange={(token) => console.log('Token actualizado:', !!token)}
326
+ >
327
+ <AppContent />
328
+ </CrudifyDataProvider>
329
+ );
330
+ }
331
+ ```
332
+
333
+ ## 🎨 **Componente CrudifyLogin**
334
+
335
+ ### Uso Standalone (Sistema Legacy)
336
+
337
+ Para uso directo del componente de login sin el provider unificado:
338
+
339
+ ```tsx
340
+ import { CrudifyLogin } from '@nocios/crudify-ui';
25
341
 
26
342
  function LoginPage() {
27
343
  const handleLoginSuccess = (token: string, redirectUrl?: string) => {
28
- // Guardar token y redirigir
344
+ // ⚠️ Importante: Sincronizar con el sistema global
29
345
  sessionStorage.setItem("authToken", token);
346
+
347
+ // Si usas CrudifyDataProvider, también sincronizar ahí
348
+ // setToken(token); // usando useCrudifyAuth
349
+
30
350
  window.location.href = redirectUrl || "/dashboard";
31
351
  };
32
352
 
@@ -35,60 +355,63 @@ function LoginPage() {
35
355
  config={{
36
356
  publicApiKey: "tu-api-key",
37
357
  env: "prod",
38
- appName: "Mi Aplicacion",
358
+ appName: "Mi Aplicación",
359
+ logo: "/logo.png",
360
+ colors: {
361
+ primaryColor: "#1066BA",
362
+ bgColor: "#f5f5f5"
363
+ },
364
+ loginActions: ["forgotPassword", "createUser"]
39
365
  }}
40
366
  onLoginSuccess={handleLoginSuccess}
367
+ onError={(error) => console.error('Login error:', error)}
41
368
  redirectUrl="/dashboard"
369
+ language="es"
42
370
  />
43
371
  );
44
372
  }
45
373
  ```
46
374
 
47
- ## ⚙️ Configuracion Completa
48
-
49
- ### Props del Componente
50
-
51
- | Prop | Tipo | Default | Descripcion |
52
- | --------------------- | ----------------------------------------------- | --------- | --------------------------------- |
53
- | `config` | `CrudifyLoginConfig` | `{}` | Configuracion del componente |
54
- | `onLoginSuccess` | `(token: string, redirectUrl?: string) => void` | - | Callback cuando login es exitoso |
55
- | `onError` | `(error: string) => void` | - | Callback para manejo de errores |
56
- | `onScreenChange` | `(screen: string, params?: object) => void` | - | Callback para cambios de pantalla |
57
- | `onExternalNavigate` | `(path: string) => void` | - | Callback para navegacion externa |
58
- | `initialScreen` | `login,forgotPassword,resetPassword,checkCode` | `"login"` | Pantalla inicial |
59
- | `redirectUrl` | `string` | `"/"` | URL de redireccion post-login |
60
- | `autoReadFromCookies` | `boolean` | `true` | Leer configuracion desde cookies |
61
- | `language` | `string` | `"en"` | Idioma de la interfaz |
62
- | `translations` | `CrudifyLoginTranslations` | - | Traducciones customizadas |
63
- | `translationsUrl` | `string` | - | URL para cargar traducciones |
64
-
65
- ### Configuracion (CrudifyLoginConfig)
375
+ ### Props del CrudifyLogin
66
376
 
67
377
  ```tsx
68
- interface CrudifyLoginConfig {
69
- publicApiKey?: string; // Clave de API de Crudify
70
- env?: "dev" | "stg" | "api" | "prod"; // Entorno de la API
71
- appName?: string; // Nombre de tu aplicacion
72
- logo?: string; // URL del logo
73
- colors?: {
74
- primaryColor?: string; // Color principal
75
- bgColor?: string; // Color de fondo
76
- [key: string]: string | undefined;
77
- };
78
- loginActions?: string[]; // Acciones disponibles: ["forgotPassword", "createUser"]
378
+ interface CrudifyLoginProps {
379
+ // Configuración
380
+ config?: CrudifyLoginConfig;
381
+
382
+ // Callbacks
383
+ onLoginSuccess?: (token: string, redirectUrl?: string) => void;
384
+ onError?: (error: string) => void;
385
+ onScreenChange?: (screen: string, params?: object) => void;
386
+ onExternalNavigate?: (path: string) => void;
387
+
388
+ // Navegación
389
+ initialScreen?: 'login' | 'forgotPassword' | 'resetPassword' | 'checkCode';
390
+ redirectUrl?: string;
391
+
392
+ // Personalización
393
+ language?: string;
394
+ translations?: CrudifyLoginTranslations;
395
+ translationsUrl?: string;
396
+
397
+ // Opciones
398
+ autoReadFromCookies?: boolean;
79
399
  }
80
400
  ```
81
401
 
82
- ## 🎨 Personalizacion Visual
83
-
84
- ### Colores y Branding
402
+ ### Personalización Visual
85
403
 
86
404
  ```tsx
87
405
  <CrudifyLogin
88
406
  config={{
89
407
  appName: "Mi App",
90
408
  logo: "/mi-logo.png",
91
- colors: { primaryColor: "#1066BA", bgColor: "#f5f5f5" },
409
+ colors: {
410
+ primaryColor: "#1066BA",
411
+ bgColor: "#f5f5f5",
412
+ textColor: "#333333",
413
+ buttonTextColor: "#ffffff"
414
+ },
92
415
  }}
93
416
  />
94
417
  ```
@@ -97,65 +420,63 @@ interface CrudifyLoginConfig {
97
420
 
98
421
  ```tsx
99
422
  const misTraduciones = {
100
- "login.title": "Iniciar Sesion",
423
+ "login.title": "Iniciar Sesión",
101
424
  "login.usernameLabel": "Usuario o Email",
102
- "login.passwordLabel": "Contrasena",
425
+ "login.passwordLabel": "Contraseña",
103
426
  "login.loginButton": "Entrar",
104
- "login.forgotPasswordLink": "¿Olvidaste tu contrasena?",
427
+ "login.forgotPasswordLink": "¿Olvidaste tu contraseña?",
428
+ "forgotPassword.title": "Recuperar Contraseña",
429
+ "forgotPassword.emailLabel": "Email",
430
+ "forgotPassword.sendButton": "Enviar Código"
105
431
  };
106
432
 
107
- <CrudifyLogin translations={misTraduciones} language="es" />;
433
+ <CrudifyLogin
434
+ translations={misTraduciones}
435
+ language="es"
436
+ />;
108
437
  ```
109
438
 
110
- ## 🔧 Hooks Disponibles
439
+ ## 🛠️ **Utilidades y Funciones de Alto Nivel**
111
440
 
112
- ### useUserProfile
441
+ ### 🔑 **Acceso Directo a la Instancia**
113
442
 
114
- Hook para obtener y manejar el perfil del usuario autenticado:
443
+ Para casos avanzados donde necesitas acceso directo a la instancia de crudify:
115
444
 
116
445
  ```tsx
117
- import { useUserProfile } from "@nocios/crudify-ui";
118
-
119
- function UserDashboard() {
120
- const { userProfile, loading, error, refreshProfile } = useUserProfile();
121
-
122
- if (loading) return <div>Cargando...</div>;
123
- if (error) return <div>Error: {error}</div>;
124
-
125
- return (
126
- <div>
127
- <h1>Bienvenido, {userProfile?.name}</h1>
128
- <p>Email: {userProfile?.email}</p>
129
- <button onClick={refreshProfile}>Actualizar Perfil</button>
130
- </div>
131
- );
446
+ import { getCrudifyInstanceAsync, getCrudifyInstanceSync } from '@nocios/crudify-ui';
447
+
448
+ // Método asíncrono (recomendado) - espera a que se inicialice
449
+ async function loadData() {
450
+ try {
451
+ const crudifyInstance = await getCrudifyInstanceAsync();
452
+ const response = await crudifyInstance.readItems('products', {});
453
+ return response;
454
+ } catch (error) {
455
+ console.error('Error:', error);
456
+ }
132
457
  }
133
- ```
134
-
135
- ### useCrudifyLogin
136
-
137
- Hook interno para configuracion avanzada:
138
-
139
- ```tsx
140
- import { useCrudifyLogin } from "@nocios/crudify-ui";
141
-
142
- function CustomLogin() {
143
- const { config } = useCrudifyLogin({
144
- publicApiKey: "mi-api-key",
145
- env: "prod",
146
- });
147
458
 
148
- // config contiene la configuracion final combinada con cookies
149
- return <div>App: {config.appName}</div>;
459
+ // Método síncrono - lanza error si no está listo
460
+ function quickOperation() {
461
+ try {
462
+ const crudifyInstance = await getCrudifyInstanceSync();
463
+ // Usar solo si estás seguro de que ya está inicializado
464
+ return crudifyInstance.readItems('products', {});
465
+ } catch (error) {
466
+ console.error('Crudify not ready:', error);
467
+ }
150
468
  }
151
469
  ```
152
470
 
153
- ## 🛠️ Utilidades Disponibles
154
-
155
- ### JWT Utils
471
+ ### 🔐 **Utilidades de Tokens JWT**
156
472
 
157
473
  ```tsx
158
- import { getCurrentUserEmail, decodeJwtSafely, isTokenExpired } from "@nocios/crudify-ui";
474
+ import {
475
+ getCurrentUserEmail,
476
+ decodeJwtSafely,
477
+ isTokenExpired,
478
+ getTokenPayload
479
+ } from '@nocios/crudify-ui';
159
480
 
160
481
  // Obtener email del usuario actual
161
482
  const userEmail = getCurrentUserEmail();
@@ -165,36 +486,125 @@ const payload = decodeJwtSafely(token);
165
486
 
166
487
  // Verificar si token ha expirado
167
488
  const expired = isTokenExpired(token);
489
+
490
+ // Obtener payload completo con validación
491
+ const tokenData = getTokenPayload(token);
492
+ console.log('Usuario:', tokenData?.email);
493
+ console.log('Expira:', new Date(tokenData?.exp * 1000));
168
494
  ```
169
495
 
170
- ### Storage Seguro
496
+ ### 🔒 **Storage Seguro**
171
497
 
172
498
  ```tsx
173
- import { secureSessionStorage, secureLocalStorage } from "@nocios/crudify-ui";
499
+ import {
500
+ secureSessionStorage,
501
+ secureLocalStorage,
502
+ TokenManager
503
+ } from '@nocios/crudify-ui';
174
504
 
175
- // Guardar token de forma segura
505
+ // Uso básico del storage seguro
176
506
  secureSessionStorage.setToken(token);
507
+ const currentToken = secureSessionStorage.getToken();
508
+ secureSessionStorage.clear();
177
509
 
178
- // Obtener token
179
- const token = secureSessionStorage.getToken();
510
+ // Uso avanzado con TokenManager
511
+ const tokenManager = TokenManager.getInstance();
180
512
 
181
- // Limpiar storage
182
- secureSessionStorage.clear();
513
+ // Establecer token con sincronización automática
514
+ await tokenManager.setToken(token);
515
+
516
+ // Obtener token válido (verifica expiración)
517
+ const validToken = tokenManager.getValidToken();
518
+
519
+ // Limpiar todo
520
+ tokenManager.clearToken();
521
+
522
+ // Verificar si hay token válido
523
+ const hasValidToken = tokenManager.hasValidToken();
183
524
  ```
184
525
 
185
- ### Manejo de Errores
526
+ ### 🚨 **Manejo de Errores**
186
527
 
187
528
  ```tsx
188
- import { handleCrudifyError, ERROR_CODES, getErrorMessage } from "@nocios/crudify-ui";
189
-
529
+ import {
530
+ handleCrudifyError,
531
+ ERROR_CODES,
532
+ getErrorMessage,
533
+ CrudifyErrorHandler
534
+ } from '@nocios/crudify-ui';
535
+
536
+ // Manejo básico de errores
190
537
  try {
191
- // Tu codigo
538
+ await readItems('products', {});
192
539
  } catch (error) {
193
540
  const parsedErrors = handleCrudifyError(error);
194
541
  parsedErrors.forEach((err) => {
195
542
  console.log(`Error ${err.code}: ${err.message} (Severidad: ${err.severity})`);
543
+
544
+ // Diferentes acciones según el código de error
545
+ switch (err.code) {
546
+ case ERROR_CODES.INVALID_CREDENTIALS:
547
+ // Redirigir a login
548
+ break;
549
+ case ERROR_CODES.NETWORK_ERROR:
550
+ // Mostrar mensaje de conectividad
551
+ break;
552
+ case ERROR_CODES.TOO_MANY_REQUESTS:
553
+ // Mostrar mensaje de espera
554
+ break;
555
+ }
196
556
  });
197
557
  }
558
+
559
+ // Manejo avanzado con categorías
560
+ const errorHandler = new CrudifyErrorHandler();
561
+ errorHandler.setErrorCallback('authentication', (error) => {
562
+ // Manejar errores de autenticación
563
+ console.log('Auth error:', error);
564
+ });
565
+
566
+ errorHandler.setErrorCallback('validation', (error) => {
567
+ // Manejar errores de validación
568
+ console.log('Validation error:', error);
569
+ });
570
+ ```
571
+
572
+ ### 🔍 **Hooks Legacy (Compatibilidad)**
573
+
574
+ Para migrar desde versiones anteriores:
575
+
576
+ ```tsx
577
+ // ✅ Hooks nuevos (recomendado)
578
+ import { useCrudifyAuth, useCrudifyData, useCrudifyUser } from '@nocios/crudify-ui';
579
+
580
+ // ⚠️ Hooks legacy (mantienen compatibilidad)
581
+ import { useUserProfile, useCrudifyLogin } from '@nocios/crudify-ui';
582
+
583
+ function LegacyComponent() {
584
+ // Hook legacy para perfil de usuario
585
+ const { userProfile, loading, error, refreshProfile } = useUserProfile();
586
+
587
+ if (loading) return <div>Cargando...</div>;
588
+ if (error) return <div>Error: {error}</div>;
589
+
590
+ return (
591
+ <div>
592
+ <h1>Bienvenido, {userProfile?.name}</h1>
593
+ <p>Email: {userProfile?.email}</p>
594
+ <button onClick={refreshProfile}>Actualizar Perfil</button>
595
+ </div>
596
+ );
597
+ }
598
+
599
+ function LegacyLoginConfig() {
600
+ // Hook legacy para configuración
601
+ const { config } = useCrudifyLogin({
602
+ publicApiKey: "mi-api-key",
603
+ env: "prod",
604
+ });
605
+
606
+ return <div>App: {config.appName}</div>;
607
+ }
198
608
  ```
199
609
 
200
610
  ## 📱 Flujos de Autenticacion
@@ -673,5 +1083,162 @@ VITE_TEST_ENV=prod
673
1083
 
674
1084
  ---
675
1085
 
676
- **Version:** 1.0.0+
1086
+ ## 🚀 **Mejores Prácticas**
1087
+
1088
+ ### ✅ **DO - Recomendaciones**
1089
+
1090
+ ```tsx
1091
+ // ✅ Usar el sistema unificado
1092
+ <CrudifyDataProvider publicApiKey="..." env="prod">
1093
+ <App />
1094
+ </CrudifyDataProvider>
1095
+
1096
+ // ✅ Verificar estado antes de operaciones
1097
+ const { isReady } = useCrudifyData();
1098
+ if (isReady) {
1099
+ await readItems('products', {});
1100
+ }
1101
+
1102
+ // ✅ Manejar errores apropiadamente
1103
+ try {
1104
+ const response = await createItem('products', data);
1105
+ if (response.success) {
1106
+ // Manejar éxito
1107
+ }
1108
+ } catch (error) {
1109
+ const errors = handleCrudifyError(error);
1110
+ // Mostrar errores al usuario
1111
+ }
1112
+
1113
+ // ✅ Usar hooks especializados
1114
+ const { isAuthenticated } = useCrudifyAuth();
1115
+ const { readItems } = useCrudifyData();
1116
+ const { user } = useCrudifyUser();
1117
+ ```
1118
+
1119
+ ### ❌ **DON'T - Evitar**
1120
+
1121
+ ```tsx
1122
+ // ❌ No inicializar crudify manualmente
1123
+ await crudify.init(); // La librería maneja esto
1124
+
1125
+ // ❌ No usar múltiples providers
1126
+ <CrudifyProvider>
1127
+ <AnotherProvider>
1128
+ <CrudifyDataProvider> // Conflicto
1129
+ <App />
1130
+ </CrudifyDataProvider>
1131
+ </AnotherProvider>
1132
+ </CrudifyProvider>
1133
+
1134
+ // ❌ No ignorar el estado isReady
1135
+ const { readItems } = useCrudifyData();
1136
+ await readItems('products', {}); // Puede fallar si no está listo
1137
+
1138
+ // ❌ No manejar tokens manualmente cuando usas el provider
1139
+ sessionStorage.setItem('token', token); // El provider lo maneja
1140
+ ```
1141
+
1142
+ ### 🔄 **Migración desde Versiones Anteriores**
1143
+
1144
+ Si tienes código existente, puedes migrar gradualmente:
1145
+
1146
+ ```tsx
1147
+ // Antes (código legacy)
1148
+ import { CrudifyLogin, useUserProfile } from '@nocios/crudify-ui';
1149
+
1150
+ function OldApp() {
1151
+ const { userProfile } = useUserProfile();
1152
+ return userProfile ? <Dashboard /> : <CrudifyLogin />;
1153
+ }
1154
+
1155
+ // Después (sistema unificado)
1156
+ import { CrudifyDataProvider, useCrudifyAuth, CrudifyLogin } from '@nocios/crudify-ui';
1157
+
1158
+ function NewApp() {
1159
+ return (
1160
+ <CrudifyDataProvider publicApiKey="..." env="prod">
1161
+ <AppContent />
1162
+ </CrudifyDataProvider>
1163
+ );
1164
+ }
1165
+
1166
+ function AppContent() {
1167
+ const { isAuthenticated, user, setToken } = useCrudifyAuth();
1168
+
1169
+ return isAuthenticated ? (
1170
+ <Dashboard user={user} />
1171
+ ) : (
1172
+ <CrudifyLogin onLoginSuccess={setToken} />
1173
+ );
1174
+ }
1175
+ ```
1176
+
1177
+ ### 🌍 **Variables de Entorno**
1178
+
1179
+ Configura estas variables en tu proyecto:
1180
+
1181
+ ```bash
1182
+ # .env.development
1183
+ REACT_APP_CRUDIFY_API_KEY=tu-clave-de-desarrollo
1184
+ REACT_APP_CRUDIFY_ENV=dev
1185
+
1186
+ # .env.production
1187
+ REACT_APP_CRUDIFY_API_KEY=tu-clave-de-produccion
1188
+ REACT_APP_CRUDIFY_ENV=prod
1189
+ ```
1190
+
1191
+ ```tsx
1192
+ // Uso en la aplicación
1193
+ <CrudifyDataProvider
1194
+ publicApiKey={process.env.REACT_APP_CRUDIFY_API_KEY}
1195
+ env={process.env.REACT_APP_CRUDIFY_ENV || 'prod'}
1196
+ appName="Mi Aplicación"
1197
+ >
1198
+ <App />
1199
+ </CrudifyDataProvider>
1200
+ ```
1201
+
1202
+ ### 📊 **Debugging y Desarrollo**
1203
+
1204
+ ```tsx
1205
+ // Habilitar logs detallados en desarrollo
1206
+ const isDevelopment = process.env.NODE_ENV === 'development';
1207
+
1208
+ <CrudifyDataProvider
1209
+ publicApiKey="..."
1210
+ onInitialized={() => isDevelopment && console.log('✅ Crudify inicializado')}
1211
+ onError={(error) => isDevelopment && console.error('❌ Error:', error)}
1212
+ onTokenChange={(token) => isDevelopment && console.log('🔑 Token:', !!token)}
1213
+ >
1214
+ <App />
1215
+ </CrudifyDataProvider>
1216
+ ```
1217
+
1218
+ ---
1219
+
1220
+ ## 📋 **Changelog y Migración**
1221
+
1222
+ ### Versión 1.2.x (Actual)
1223
+ - ✅ **Nuevo**: Sistema unificado `CrudifyDataProvider`
1224
+ - ✅ **Nuevo**: Hooks especializados (`useCrudifyAuth`, `useCrudifyData`, `useCrudifyUser`)
1225
+ - ✅ **Nuevo**: Inicialización robusta con singleton thread-safe
1226
+ - ✅ **Nuevo**: Gestión automática de tokens con sincronización cross-tab
1227
+ - ✅ **Nuevo**: Acceso directo a instancia con `getCrudifyInstanceAsync`
1228
+ - 🔄 **Mejorado**: Sistema de manejo de errores
1229
+ - 🔄 **Mejorado**: TypeScript con tipos más precisos
1230
+ - ⚠️ **Legacy**: Hooks anteriores mantienen compatibilidad
1231
+
1232
+ ### Migración desde 1.1.x
1233
+ 1. Envolver la aplicación con `CrudifyDataProvider`
1234
+ 2. Reemplazar hooks individuales con el sistema unificado
1235
+ 3. Actualizar manejo de tokens para usar `setToken` del hook
1236
+ 4. (Opcional) Migrar configuración a props del provider
1237
+
1238
+ ---
1239
+
1240
+ **Version:** 1.2.1
677
1241
  **Mantenido por:** Equipo Crudify
1242
+ **Repositorio:** [GitHub](https://github.com/nocios/crudify-ui)
1243
+ **Documentación:** [Docs](https://docs.crudify.com)
1244
+ **Soporte:** [Issues](https://github.com/nocios/crudify-ui/issues)