@nocios/crudify-ui 1.3.1 → 1.3.2
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 +155 -1108
- package/README_DEPTH.md +1046 -0
- package/package.json +1 -1
- package/MIGRATION-GUIDE.md +0 -312
- package/MIGRATION.md +0 -201
- package/MIGRATION_EXAMPLE.md +0 -538
- package/TECHNICAL_SPECIFICATION.md +0 -344
- package/example-app.tsx +0 -197
- package/mejoras_npm_lib.md +0 -790
- package/tsup.config.ts +0 -9
package/MIGRATION_EXAMPLE.md
DELETED
|
@@ -1,538 +0,0 @@
|
|
|
1
|
-
# CrudifyDataProvider - Guía de Migración
|
|
2
|
-
|
|
3
|
-
## 🎯 Objetivo
|
|
4
|
-
|
|
5
|
-
Esta guía muestra cómo migrar de la implementación actual fragmentada (JWTSessionProvider + hooks individuales) al nuevo sistema unificado **CrudifyDataProvider**.
|
|
6
|
-
|
|
7
|
-
## 📊 Comparación: Antes vs Después
|
|
8
|
-
|
|
9
|
-
### ❌ ANTES (Sistema Fragmentado)
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
// App.tsx - Múltiples providers y configuraciones
|
|
13
|
-
import { JWTSessionProvider } from "./services/jwtSession"
|
|
14
|
-
import { CrudifyProvider } from "@nocios/crudify-ui" // Conflicto con DataProvider
|
|
15
|
-
|
|
16
|
-
function App() {
|
|
17
|
-
return (
|
|
18
|
-
<JWTSessionProvider>
|
|
19
|
-
<CrudifyProvider
|
|
20
|
-
env={process.env.VITE_TEST_ENV}
|
|
21
|
-
publicApiKey={process.env.VITE_TEST_PUBLIC_API_KEY}
|
|
22
|
-
>
|
|
23
|
-
<Routes>
|
|
24
|
-
{/* Tu aplicación */}
|
|
25
|
-
</Routes>
|
|
26
|
-
</CrudifyProvider>
|
|
27
|
-
</JWTSessionProvider>
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// TestPage.tsx - Múltiples hooks y estado fragmentado
|
|
32
|
-
import { useJWTSession } from "../services/jwtSession"
|
|
33
|
-
import { useUserProfileWithJWT } from "../hooks/useUserProfileWithJWT"
|
|
34
|
-
import { crudify } from "@nocios/crudify-ui"
|
|
35
|
-
|
|
36
|
-
function TestPage() {
|
|
37
|
-
const { token, user, isAuthenticated, logout } = useJWTSession()
|
|
38
|
-
const { userProfile, loading, error, extendedData } = useUserProfileWithJWT({
|
|
39
|
-
autoFetch: isAuthenticated
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
// Problemas comunes:
|
|
43
|
-
// - "Crudify: Not initialized" errors
|
|
44
|
-
// - Doble inicialización entre providers
|
|
45
|
-
// - Estado desincronizado entre hooks
|
|
46
|
-
// - Configuración duplicada y fragmentada
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### ✅ DESPUÉS (Sistema Unificado)
|
|
51
|
-
|
|
52
|
-
```tsx
|
|
53
|
-
// App.tsx - Un solo provider con toda la funcionalidad
|
|
54
|
-
import { CrudifyDataProvider } from "@nocios/crudify-ui"
|
|
55
|
-
|
|
56
|
-
function App() {
|
|
57
|
-
return (
|
|
58
|
-
<CrudifyDataProvider
|
|
59
|
-
env="dev" // o desde process.env.VITE_TEST_ENV
|
|
60
|
-
publicApiKey="tu-api-key" // o desde process.env.VITE_TEST_PUBLIC_API_KEY
|
|
61
|
-
appName="Mi App"
|
|
62
|
-
>
|
|
63
|
-
<Routes>
|
|
64
|
-
{/* Tu aplicación */}
|
|
65
|
-
</Routes>
|
|
66
|
-
</CrudifyDataProvider>
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// TestPage.tsx - Hooks simples y estado unificado
|
|
71
|
-
import { useCrudifyAuth, useCrudifyUser, useCrudifyData } from "@nocios/crudify-ui"
|
|
72
|
-
|
|
73
|
-
function TestPage() {
|
|
74
|
-
const { isAuthenticated, token, user, logout } = useCrudifyAuth()
|
|
75
|
-
const { userProfile, profileLoading, extendedData } = useCrudifyUser()
|
|
76
|
-
const { readItems, isInitialized } = useCrudifyData()
|
|
77
|
-
|
|
78
|
-
// Beneficios:
|
|
79
|
-
// ✅ Sin errores de inicialización
|
|
80
|
-
// ✅ Estado siempre sincronizado
|
|
81
|
-
// ✅ Configuración centralizada
|
|
82
|
-
// ✅ Hooks más simples y robustos
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## 🔄 Migración Paso a Paso
|
|
87
|
-
|
|
88
|
-
### Paso 1: Actualizar npm-crudify-ui
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
npm update @nocios/crudify-ui
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Paso 2: Reemplazar Providers
|
|
95
|
-
|
|
96
|
-
**Antes:**
|
|
97
|
-
```tsx
|
|
98
|
-
import { JWTSessionProvider } from "./services/jwtSession"
|
|
99
|
-
|
|
100
|
-
function App() {
|
|
101
|
-
return (
|
|
102
|
-
<JWTSessionProvider>
|
|
103
|
-
{/* tu app */}
|
|
104
|
-
</JWTSessionProvider>
|
|
105
|
-
)
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
**Después:**
|
|
110
|
-
```tsx
|
|
111
|
-
import { CrudifyDataProvider } from "@nocios/crudify-ui"
|
|
112
|
-
|
|
113
|
-
function App() {
|
|
114
|
-
return (
|
|
115
|
-
<CrudifyDataProvider
|
|
116
|
-
env="dev" // Configuración directa o desde env vars
|
|
117
|
-
publicApiKey="your-key"
|
|
118
|
-
appName="Your App"
|
|
119
|
-
>
|
|
120
|
-
{/* tu app */}
|
|
121
|
-
</CrudifyDataProvider>
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### Paso 3: Migrar Hooks de Autenticación
|
|
127
|
-
|
|
128
|
-
**Antes:**
|
|
129
|
-
```tsx
|
|
130
|
-
import { useJWTSession } from "../services/jwtSession"
|
|
131
|
-
|
|
132
|
-
function Component() {
|
|
133
|
-
const { token, user, isAuthenticated, logout } = useJWTSession()
|
|
134
|
-
// ...
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
**Después:**
|
|
139
|
-
```tsx
|
|
140
|
-
import { useCrudifyAuth } from "@nocios/crudify-ui"
|
|
141
|
-
|
|
142
|
-
function Component() {
|
|
143
|
-
const { token, user, isAuthenticated, logout } = useCrudifyAuth()
|
|
144
|
-
// ¡Misma API! Sin cambios en el código
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Paso 4: Migrar Hooks de Usuario
|
|
149
|
-
|
|
150
|
-
**Antes:**
|
|
151
|
-
```tsx
|
|
152
|
-
import { useUserProfileWithJWT } from "../hooks/useUserProfileWithJWT"
|
|
153
|
-
|
|
154
|
-
function Component() {
|
|
155
|
-
const {
|
|
156
|
-
userProfile,
|
|
157
|
-
loading: profileLoading,
|
|
158
|
-
error: profileError,
|
|
159
|
-
extendedData
|
|
160
|
-
} = useUserProfileWithJWT({ autoFetch: true })
|
|
161
|
-
// ...
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
**Después:**
|
|
166
|
-
```tsx
|
|
167
|
-
import { useCrudifyUser } from "@nocios/crudify-ui"
|
|
168
|
-
|
|
169
|
-
function Component() {
|
|
170
|
-
const {
|
|
171
|
-
userProfile,
|
|
172
|
-
profileLoading,
|
|
173
|
-
profileError,
|
|
174
|
-
extendedData
|
|
175
|
-
} = useCrudifyUser({ autoFetch: true })
|
|
176
|
-
// ¡Misma API! Sin cambios en el código
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### Paso 5: Migrar Operaciones CRUD
|
|
181
|
-
|
|
182
|
-
**Antes:**
|
|
183
|
-
```tsx
|
|
184
|
-
import { crudify } from "@nocios/crudify-ui"
|
|
185
|
-
|
|
186
|
-
async function loadUsers() {
|
|
187
|
-
try {
|
|
188
|
-
// Posible error: "Crudify: Not initialized"
|
|
189
|
-
const response = await crudify.readItems("users", { limit: 10 })
|
|
190
|
-
return response.data
|
|
191
|
-
} catch (error) {
|
|
192
|
-
console.error("Error:", error)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
**Después:**
|
|
198
|
-
```tsx
|
|
199
|
-
import { useCrudifyData } from "@nocios/crudify-ui"
|
|
200
|
-
|
|
201
|
-
function Component() {
|
|
202
|
-
const { readItems, isReady } = useCrudifyData()
|
|
203
|
-
|
|
204
|
-
async function loadUsers() {
|
|
205
|
-
if (!isReady()) {
|
|
206
|
-
console.warn("Crudify not ready yet")
|
|
207
|
-
return
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
try {
|
|
211
|
-
// Sin errores de inicialización garantizado
|
|
212
|
-
const response = await readItems("users", { limit: 10 })
|
|
213
|
-
return response.data
|
|
214
|
-
} catch (error) {
|
|
215
|
-
console.error("Error:", error)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
## 🚀 Ejemplo Completo Migrado
|
|
222
|
-
|
|
223
|
-
### TestPage.tsx - Versión Migrada
|
|
224
|
-
|
|
225
|
-
```tsx
|
|
226
|
-
import React from "react"
|
|
227
|
-
import {
|
|
228
|
-
Box, Container, Paper, Typography, Button,
|
|
229
|
-
Divider, Alert, CircularProgress
|
|
230
|
-
} from "@mui/material"
|
|
231
|
-
import { useNavigate } from "react-router-dom"
|
|
232
|
-
import {
|
|
233
|
-
useCrudifyAuth,
|
|
234
|
-
useCrudifyUser,
|
|
235
|
-
useCrudifyConfig
|
|
236
|
-
} from "@nocios/crudify-ui"
|
|
237
|
-
|
|
238
|
-
const TestPage: React.FC = () => {
|
|
239
|
-
const navigate = useNavigate()
|
|
240
|
-
|
|
241
|
-
// 🔐 Autenticación unificada
|
|
242
|
-
const {
|
|
243
|
-
isAuthenticated,
|
|
244
|
-
token,
|
|
245
|
-
user,
|
|
246
|
-
logout,
|
|
247
|
-
loading: authLoading
|
|
248
|
-
} = useCrudifyAuth()
|
|
249
|
-
|
|
250
|
-
// 👤 Datos de usuario desde BD
|
|
251
|
-
const {
|
|
252
|
-
userProfile,
|
|
253
|
-
profileLoading,
|
|
254
|
-
profileError,
|
|
255
|
-
extendedData,
|
|
256
|
-
refreshProfile
|
|
257
|
-
} = useCrudifyUser({ autoFetch: isAuthenticated })
|
|
258
|
-
|
|
259
|
-
// ⚙️ Configuración actual
|
|
260
|
-
const { config, isConfigured, getDebugInfo } = useCrudifyConfig()
|
|
261
|
-
|
|
262
|
-
const handleLogout = () => {
|
|
263
|
-
logout()
|
|
264
|
-
navigate("/")
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const handleGoToDashboard = () => {
|
|
268
|
-
navigate("/")
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// 🚫 Guard: Usuario no autenticado
|
|
272
|
-
if (!isAuthenticated) {
|
|
273
|
-
return (
|
|
274
|
-
<Container maxWidth="md" sx={{ minHeight: "100vh", display: "flex", alignItems: "center" }}>
|
|
275
|
-
<Paper elevation={3} sx={{ p: 4, width: "100%", textAlign: "center" }}>
|
|
276
|
-
<Typography variant="h4" color="error" gutterBottom>
|
|
277
|
-
No estás logueado
|
|
278
|
-
</Typography>
|
|
279
|
-
<Typography variant="body1" sx={{ mb: 3 }}>
|
|
280
|
-
Debes iniciar sesión para ver esta página.
|
|
281
|
-
</Typography>
|
|
282
|
-
<Button variant="contained" onClick={() => navigate("/")} size="large">
|
|
283
|
-
Ir al Login
|
|
284
|
-
</Button>
|
|
285
|
-
</Paper>
|
|
286
|
-
</Container>
|
|
287
|
-
)
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// 📊 Datos unificados para mostrar
|
|
291
|
-
const userData = {
|
|
292
|
-
// Sistema de autenticación
|
|
293
|
-
authentication: {
|
|
294
|
-
isAuthenticated,
|
|
295
|
-
hasToken: !!token,
|
|
296
|
-
tokenLength: token?.length || 0,
|
|
297
|
-
userEmail: user?.email || null,
|
|
298
|
-
userId: user?.sub || null,
|
|
299
|
-
expiration: user?.exp ? new Date(user.exp * 1000).toISOString() : null
|
|
300
|
-
},
|
|
301
|
-
// Perfil desde base de datos
|
|
302
|
-
profile: {
|
|
303
|
-
loading: profileLoading,
|
|
304
|
-
error: profileError,
|
|
305
|
-
hasProfileData: !!userProfile,
|
|
306
|
-
totalFields: extendedData?.totalFields || 0,
|
|
307
|
-
basicProfile: userProfile,
|
|
308
|
-
displayData: extendedData?.displayData || null
|
|
309
|
-
},
|
|
310
|
-
// Configuración actual
|
|
311
|
-
configuration: {
|
|
312
|
-
isConfigured,
|
|
313
|
-
env: config?.env,
|
|
314
|
-
appName: config?.appName,
|
|
315
|
-
configSources: config?.configSource
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
return (
|
|
320
|
-
<Container maxWidth="md" sx={{ minHeight: "100vh", py: 4 }}>
|
|
321
|
-
<Paper elevation={3} sx={{ p: 4, width: "100%" }}>
|
|
322
|
-
|
|
323
|
-
{/* 🎉 Encabezado de éxito */}
|
|
324
|
-
<Box sx={{ mb: 4, textAlign: "center" }}>
|
|
325
|
-
<Typography variant="h3" component="h1" gutterBottom sx={{ color: "primary.main" }}>
|
|
326
|
-
🎉 Usuario Logueado Exitosamente
|
|
327
|
-
</Typography>
|
|
328
|
-
<Typography variant="h6" color="text.secondary">
|
|
329
|
-
Bienvenido al nuevo sistema unificado CrudifyDataProvider
|
|
330
|
-
</Typography>
|
|
331
|
-
</Box>
|
|
332
|
-
|
|
333
|
-
<Divider sx={{ my: 3 }} />
|
|
334
|
-
|
|
335
|
-
{/* 🔐 Datos de autenticación JWT */}
|
|
336
|
-
<Box sx={{ mb: 4 }}>
|
|
337
|
-
<Typography variant="h5" gutterBottom sx={{ color: "secondary.main" }}>
|
|
338
|
-
🔐 Datos de Autenticación (JWT):
|
|
339
|
-
</Typography>
|
|
340
|
-
|
|
341
|
-
<Box sx={{ mt: 2, mb: 3 }}>
|
|
342
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
343
|
-
👤 <strong>Usuario:</strong> {user?.email || "Sin email"}
|
|
344
|
-
</Typography>
|
|
345
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
346
|
-
🆔 <strong>User ID:</strong> {user?.sub || "No definido"}
|
|
347
|
-
</Typography>
|
|
348
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
349
|
-
✅ <strong>Estado:</strong> {isAuthenticated ? "Autenticado (CrudifyDataProvider)" : "No autenticado"}
|
|
350
|
-
</Typography>
|
|
351
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
352
|
-
🎟️ <strong>JWT Token:</strong> {token ? "Presente" : "No disponible"}
|
|
353
|
-
{token && <span style={{ fontSize: '0.8em', color: '#666' }}> ({token.length} caracteres)</span>}
|
|
354
|
-
</Typography>
|
|
355
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
356
|
-
⏰ <strong>Token expira:</strong> {user?.exp ? new Date(user.exp * 1000).toLocaleString() : "No disponible"}
|
|
357
|
-
</Typography>
|
|
358
|
-
</Box>
|
|
359
|
-
</Box>
|
|
360
|
-
|
|
361
|
-
<Divider sx={{ my: 3 }} />
|
|
362
|
-
|
|
363
|
-
{/* 👤 Datos del perfil de usuario */}
|
|
364
|
-
<Box sx={{ mb: 4 }}>
|
|
365
|
-
<Typography variant="h5" gutterBottom sx={{ color: "primary.main" }}>
|
|
366
|
-
👤 Perfil de Usuario (Base de Datos):
|
|
367
|
-
</Typography>
|
|
368
|
-
|
|
369
|
-
{profileLoading && (
|
|
370
|
-
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
|
|
371
|
-
<CircularProgress size={20} sx={{ mr: 1 }} />
|
|
372
|
-
<Typography>Cargando perfil automáticamente...</Typography>
|
|
373
|
-
</Box>
|
|
374
|
-
)}
|
|
375
|
-
|
|
376
|
-
{profileError && (
|
|
377
|
-
<Alert severity="error" sx={{ mb: 2 }}>
|
|
378
|
-
Error al cargar perfil: {profileError}
|
|
379
|
-
<Button onClick={refreshProfile} size="small" sx={{ ml: 1 }}>
|
|
380
|
-
Reintentar
|
|
381
|
-
</Button>
|
|
382
|
-
</Alert>
|
|
383
|
-
)}
|
|
384
|
-
|
|
385
|
-
{userProfile && !profileLoading && (
|
|
386
|
-
<Box sx={{ mb: 2 }}>
|
|
387
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
388
|
-
👤 <strong>ID:</strong> {extendedData?.displayData?.id || 'No disponible'}
|
|
389
|
-
</Typography>
|
|
390
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
391
|
-
📧 <strong>Email:</strong> {extendedData?.displayData?.email || 'No disponible'}
|
|
392
|
-
</Typography>
|
|
393
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
394
|
-
🏷️ <strong>Username:</strong> {extendedData?.displayData?.username || 'No disponible'}
|
|
395
|
-
</Typography>
|
|
396
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
397
|
-
👨💼 <strong>Nombre Completo:</strong> {extendedData?.displayData?.fullName || 'No disponible'}
|
|
398
|
-
</Typography>
|
|
399
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
400
|
-
🎭 <strong>Rol:</strong> {extendedData?.displayData?.role || 'No definido'}
|
|
401
|
-
</Typography>
|
|
402
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
403
|
-
🔢 <strong>Total campos BD:</strong> {extendedData?.totalFields || 0}
|
|
404
|
-
</Typography>
|
|
405
|
-
</Box>
|
|
406
|
-
)}
|
|
407
|
-
</Box>
|
|
408
|
-
|
|
409
|
-
<Divider sx={{ my: 3 }} />
|
|
410
|
-
|
|
411
|
-
{/* ⚙️ Información de configuración */}
|
|
412
|
-
<Box sx={{ mb: 4 }}>
|
|
413
|
-
<Typography variant="h5" gutterBottom sx={{ color: "info.main" }}>
|
|
414
|
-
⚙️ Configuración Actual:
|
|
415
|
-
</Typography>
|
|
416
|
-
|
|
417
|
-
<Box sx={{ mt: 2, mb: 3 }}>
|
|
418
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
419
|
-
🌍 <strong>Entorno:</strong> {config?.env || "No definido"}
|
|
420
|
-
</Typography>
|
|
421
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
422
|
-
🏢 <strong>App Name:</strong> {config?.appName || "No definido"}
|
|
423
|
-
</Typography>
|
|
424
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
425
|
-
✅ <strong>Configurado:</strong> {isConfigured ? "Sí" : "No"}
|
|
426
|
-
</Typography>
|
|
427
|
-
<Typography variant="h6" sx={{ mb: 1 }}>
|
|
428
|
-
📚 <strong>Fuentes:</strong> {config?.configSource ? JSON.stringify(config.configSource) : "No disponible"}
|
|
429
|
-
</Typography>
|
|
430
|
-
</Box>
|
|
431
|
-
</Box>
|
|
432
|
-
|
|
433
|
-
<Divider sx={{ my: 3 }} />
|
|
434
|
-
|
|
435
|
-
{/* 📋 JSON completo para debugging */}
|
|
436
|
-
<Box sx={{ mb: 4 }}>
|
|
437
|
-
<Typography variant="h5" gutterBottom sx={{ color: "secondary.main" }}>
|
|
438
|
-
📋 Datos Completos (Debug):
|
|
439
|
-
</Typography>
|
|
440
|
-
|
|
441
|
-
<Paper
|
|
442
|
-
elevation={1}
|
|
443
|
-
sx={{
|
|
444
|
-
p: 3,
|
|
445
|
-
backgroundColor: "grey.50",
|
|
446
|
-
overflow: "auto",
|
|
447
|
-
maxHeight: "400px"
|
|
448
|
-
}}
|
|
449
|
-
>
|
|
450
|
-
<pre style={{
|
|
451
|
-
margin: 0,
|
|
452
|
-
fontFamily: "monospace",
|
|
453
|
-
fontSize: "14px",
|
|
454
|
-
whiteSpace: "pre-wrap",
|
|
455
|
-
wordBreak: "break-word"
|
|
456
|
-
}}>
|
|
457
|
-
{JSON.stringify({
|
|
458
|
-
userData,
|
|
459
|
-
debugInfo: getDebugInfo()
|
|
460
|
-
}, null, 2)}
|
|
461
|
-
</pre>
|
|
462
|
-
</Paper>
|
|
463
|
-
</Box>
|
|
464
|
-
|
|
465
|
-
<Divider sx={{ my: 3 }} />
|
|
466
|
-
|
|
467
|
-
{/* 🎛️ Acciones */}
|
|
468
|
-
<Box sx={{ display: "flex", gap: 2, justifyContent: "center", flexWrap: "wrap" }}>
|
|
469
|
-
<Button
|
|
470
|
-
variant="contained"
|
|
471
|
-
color="primary"
|
|
472
|
-
onClick={handleGoToDashboard}
|
|
473
|
-
size="large"
|
|
474
|
-
>
|
|
475
|
-
Ir al Dashboard
|
|
476
|
-
</Button>
|
|
477
|
-
|
|
478
|
-
<Button
|
|
479
|
-
variant="outlined"
|
|
480
|
-
color="secondary"
|
|
481
|
-
onClick={handleLogout}
|
|
482
|
-
size="large"
|
|
483
|
-
>
|
|
484
|
-
Cerrar Sesión
|
|
485
|
-
</Button>
|
|
486
|
-
|
|
487
|
-
<Button
|
|
488
|
-
variant="outlined"
|
|
489
|
-
color="info"
|
|
490
|
-
onClick={refreshProfile}
|
|
491
|
-
size="large"
|
|
492
|
-
disabled={profileLoading}
|
|
493
|
-
>
|
|
494
|
-
{profileLoading ? "Cargando..." : "Refresh Profile"}
|
|
495
|
-
</Button>
|
|
496
|
-
</Box>
|
|
497
|
-
</Paper>
|
|
498
|
-
</Container>
|
|
499
|
-
)
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
export default TestPage
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
## 🛡️ Garantías de Compatibilidad
|
|
506
|
-
|
|
507
|
-
### ✅ Para crudia-ui (Producción)
|
|
508
|
-
- **Sin cambios**: El sistema legacy sigue funcionando exactamente igual
|
|
509
|
-
- **Imports preserved**: Todos los exports existentes se mantienen
|
|
510
|
-
- **API compatibility**: 100% compatible con código existente
|
|
511
|
-
- **Storage compatibility**: Usa la misma clave `"authToken"`
|
|
512
|
-
|
|
513
|
-
### ✅ Para crudify-ui (Desarrollo)
|
|
514
|
-
- **API familiar**: Los nuevos hooks tienen la misma interfaz que los actuales
|
|
515
|
-
- **Migración gradual**: Puedes migrar componente por componente
|
|
516
|
-
- **Mejor error handling**: Sin más errores "Crudify: Not initialized"
|
|
517
|
-
- **Estado unificado**: Un solo source of truth para toda la app
|
|
518
|
-
|
|
519
|
-
## 🚀 Beneficios Inmediatos
|
|
520
|
-
|
|
521
|
-
1. **Sin errores de inicialización**: El doble provider problem está resuelto
|
|
522
|
-
2. **Estado sincronizado**: Token, usuario y configuración siempre consistentes
|
|
523
|
-
3. **Configuración simplificada**: Un solo provider con toda la funcionalidad
|
|
524
|
-
4. **Mejor debugging**: Información completa disponible en `getDebugInfo()`
|
|
525
|
-
5. **Cross-tab sync**: Los tokens se sincronizan automáticamente entre pestañas
|
|
526
|
-
6. **Automatic cleanup**: Tokens expirados se limpian automáticamente
|
|
527
|
-
|
|
528
|
-
## 🔄 Migración Incremental
|
|
529
|
-
|
|
530
|
-
Puedes migrar gradualmente:
|
|
531
|
-
|
|
532
|
-
1. **Fase 1**: Envolver la app con `CrudifyDataProvider`
|
|
533
|
-
2. **Fase 2**: Migrar componentes de autenticación usando `useCrudifyAuth`
|
|
534
|
-
3. **Fase 3**: Migrar componentes de usuario usando `useCrudifyUser`
|
|
535
|
-
4. **Fase 4**: Migrar operaciones CRUD usando `useCrudifyData`
|
|
536
|
-
5. **Fase 5**: Remover providers y hooks legacy
|
|
537
|
-
|
|
538
|
-
¡El nuevo sistema está listo para usar! 🎉
|