@nocios/crudify-ui 1.0.83 → 1.0.84

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.
Files changed (2) hide show
  1. package/README.md +302 -0
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -369,6 +369,308 @@ function AuthenticatedApp() {
369
369
  export default AuthenticatedApp;
370
370
  ```
371
371
 
372
+ ## 🏗️ Implementación con UnifiedProvider (Recomendado)
373
+
374
+ ### Patrón Unificado para Apps Completas
375
+
376
+ Para aplicaciones que necesitan gestión completa de estado y autenticación, recomendamos usar el patrón UnifiedProvider que combina la gestión de configuración y autenticación en un solo componente:
377
+
378
+ ```tsx
379
+ // src/contexts/UnifiedProvider.tsx
380
+ import React, { createContext, useContext, useMemo, useState, useCallback, useEffect, type ReactNode } from "react"
381
+ import { createTheme } from "@mui/material"
382
+ import { crudify, type CrudifyEnvType } from "@nocios/crudify-ui"
383
+
384
+ interface AppContextValue {
385
+ logo: string | null
386
+ setLogo: (logo: string) => void
387
+ publicApiKey: string | null
388
+ setPublicApiKey: (key: string | null) => void
389
+ env: CrudifyEnvType
390
+ setEnv: (env: CrudifyEnvType) => void
391
+ appName: string | null
392
+ setAppName: (name: string | null) => void
393
+ colors: { primaryColor: string; [key: string]: string }
394
+ setColors: (colors: any) => void
395
+ theme: any
396
+ setTheme: (theme: any) => void
397
+ configLoading: boolean
398
+ configError: string | null
399
+ loginActions: string[]
400
+ setLoginActions: (actions: string[]) => void
401
+ }
402
+
403
+ interface DataContextValue {
404
+ token: string | null
405
+ setToken: (token: string | null) => void
406
+ user: Record<string, any> | null
407
+ isInitialized: boolean
408
+ initializationError: string | null
409
+ }
410
+
411
+ const AppContext = createContext<AppContextValue | null>(null)
412
+ const DataContext = createContext<DataContextValue | null>(null)
413
+
414
+ const UnifiedProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
415
+ // Estado para token y usuario
416
+ const [token, setTokenState] = useState<string | null>(null)
417
+ const [user, setUser] = useState<Record<string, any> | null>(null)
418
+ const [isFullyInitialized, setIsFullyInitialized] = useState(false)
419
+
420
+ // Configuración desde variables de entorno
421
+ const config = useMemo(() => ({
422
+ publicApiKey: import.meta.env.VITE_TEST_PUBLIC_API_KEY || 'default-key',
423
+ env: import.meta.env.VITE_TEST_ENV || 'prod',
424
+ appName: 'Mi Aplicación'
425
+ }), [])
426
+
427
+ const handleSetToken = useCallback((newToken: string | null) => {
428
+ setTokenState(newToken)
429
+ if (newToken) {
430
+ sessionStorage.setItem('crud_token', newToken)
431
+ } else {
432
+ sessionStorage.removeItem('crud_token')
433
+ }
434
+ }, [])
435
+
436
+ // Inicializar token desde sessionStorage
437
+ useEffect(() => {
438
+ const savedToken = sessionStorage.getItem('crud_token')
439
+ if (savedToken) {
440
+ setTokenState(savedToken)
441
+ }
442
+ }, [])
443
+
444
+ // Inicialización de Crudify cuando hay token
445
+ useEffect(() => {
446
+ if (!token) {
447
+ setIsFullyInitialized(false)
448
+ return
449
+ }
450
+
451
+ const initializeCrudify = async () => {
452
+ if (isFullyInitialized) return
453
+
454
+ try {
455
+ await crudify.config(config.env)
456
+ await crudify.init(config.publicApiKey, "none")
457
+ crudify.setToken(token)
458
+ setIsFullyInitialized(true)
459
+ } catch (error) {
460
+ console.error('Error initializing Crudify:', error)
461
+ setIsFullyInitialized(true) // Evitar bucles
462
+ }
463
+ }
464
+
465
+ initializeCrudify()
466
+ }, [token, config.env, config.publicApiKey, isFullyInitialized])
467
+
468
+ // Contexto de App
469
+ const appContextValue: AppContextValue = {
470
+ logo: null,
471
+ setLogo: () => {},
472
+ publicApiKey: config.publicApiKey,
473
+ setPublicApiKey: () => {},
474
+ env: config.env as CrudifyEnvType,
475
+ setEnv: () => {},
476
+ appName: config.appName,
477
+ setAppName: () => {},
478
+ colors: { primaryColor: "#1066BA" },
479
+ setColors: () => {},
480
+ theme: createTheme({ palette: { primary: { main: "#1066BA" } } }),
481
+ setTheme: () => {},
482
+ configLoading: false,
483
+ configError: null,
484
+ loginActions: [],
485
+ setLoginActions: () => {}
486
+ }
487
+
488
+ // Contexto de Data
489
+ const dataContextValue: DataContextValue = {
490
+ token,
491
+ setToken: handleSetToken,
492
+ user,
493
+ isInitialized: !!token && isFullyInitialized,
494
+ initializationError: null
495
+ }
496
+
497
+ return (
498
+ <AppContext.Provider value={appContextValue}>
499
+ <DataContext.Provider value={dataContextValue}>
500
+ {children}
501
+ </DataContext.Provider>
502
+ </AppContext.Provider>
503
+ )
504
+ }
505
+
506
+ export const useApp = (): AppContextValue => {
507
+ const context = useContext(AppContext)
508
+ if (!context) throw new Error("useApp should be used within a UnifiedProvider")
509
+ return context
510
+ }
511
+
512
+ export const useData = (): DataContextValue => {
513
+ const context = useContext(DataContext)
514
+ if (!context) throw new Error("useData should be used within a UnifiedProvider")
515
+ return context
516
+ }
517
+
518
+ export { UnifiedProvider }
519
+ ```
520
+
521
+ ### Implementación del AppStatusHandler
522
+
523
+ ```tsx
524
+ // src/components/AppStatusHandler/index.tsx
525
+ import { type ReactNode } from "react"
526
+ import { useLocation } from "react-router-dom"
527
+ import { useApp, useData } from "@contexts/UnifiedProvider"
528
+ import LoadingApp from "@components/LoadingApp"
529
+ import { CssBaseline, ThemeProvider } from "@mui/material"
530
+ import InitError from "@components/InitError"
531
+
532
+ interface AppStatusHandlerProps {
533
+ children: ReactNode
534
+ }
535
+
536
+ const AppStatusHandler = ({ children }: AppStatusHandlerProps) => {
537
+ const location = useLocation()
538
+ const { theme, configLoading, configError } = useApp()
539
+ const { isInitialized, initializationError } = useData()
540
+
541
+ // Rutas que no requieren inicialización completa
542
+ const authRoutes = ['/login', '/login/forgotPassword', '/login/checkCode', '/login/resetPassword']
543
+ const isAuthRoute = authRoutes.some(route => location.pathname.startsWith(route))
544
+
545
+ if (configLoading) {
546
+ return <LoadingApp stage="config" />
547
+ }
548
+
549
+ if (!theme) {
550
+ return <LoadingApp stage="theme" />
551
+ }
552
+
553
+ // Solo requerir inicialización para rutas protegidas
554
+ if (!isInitialized && !isAuthRoute) {
555
+ return <LoadingApp stage="initializing" />
556
+ }
557
+
558
+ if (configError || initializationError) {
559
+ return <InitError configError={configError} initializationError={Boolean(initializationError)} />
560
+ }
561
+
562
+ return (
563
+ <ThemeProvider theme={theme}>
564
+ <CssBaseline />
565
+ {children}
566
+ </ThemeProvider>
567
+ )
568
+ }
569
+
570
+ export default AppStatusHandler
571
+ ```
572
+
573
+ ### Implementación de ProtectedRoute
574
+
575
+ ```tsx
576
+ // src/components/Auth/ProtectedRoute/index.tsx
577
+ import { type ReactNode } from "react"
578
+ import { Navigate, useLocation } from "react-router-dom"
579
+ import { useData } from "@contexts/UnifiedProvider"
580
+
581
+ interface ProtectedRouteProps {
582
+ children: ReactNode
583
+ }
584
+
585
+ const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
586
+ const { token } = useData()
587
+ const location = useLocation()
588
+
589
+ if (!token) {
590
+ const fullPath = location.pathname + location.search
591
+ const redirectPath = encodeURIComponent(fullPath)
592
+ return <Navigate to={`/login?redirect=${redirectPath}`} replace />
593
+ }
594
+
595
+ return children
596
+ }
597
+
598
+ export default ProtectedRoute
599
+ ```
600
+
601
+ ### Configuración de la App Principal
602
+
603
+ ```tsx
604
+ // src/main.tsx
605
+ import React from 'react'
606
+ import ReactDOM from 'react-dom/client'
607
+ import { BrowserRouter } from 'react-router-dom'
608
+ import { UnifiedProvider } from '@contexts/UnifiedProvider'
609
+ import { GlobalNotificationProvider } from '@contexts/GlobalNotificationProvider'
610
+ import AppStatusHandler from '@components/AppStatusHandler'
611
+ import App from './App'
612
+
613
+ ReactDOM.createRoot(document.getElementById('root')!).render(
614
+ <React.StrictMode>
615
+ <BrowserRouter>
616
+ <UnifiedProvider>
617
+ <GlobalNotificationProvider>
618
+ <AppStatusHandler>
619
+ <App />
620
+ </AppStatusHandler>
621
+ </GlobalNotificationProvider>
622
+ </UnifiedProvider>
623
+ </BrowserRouter>
624
+ </React.StrictMode>,
625
+ )
626
+ ```
627
+
628
+ ### Uso en Componentes
629
+
630
+ ```tsx
631
+ // Cualquier componente de la app
632
+ import { useApp, useData } from '@contexts/UnifiedProvider'
633
+
634
+ function Dashboard() {
635
+ const { appName, theme } = useApp()
636
+ const { user, token, isInitialized } = useData()
637
+
638
+ if (!isInitialized) {
639
+ return <div>Inicializando...</div>
640
+ }
641
+
642
+ return (
643
+ <div>
644
+ <h1>Bienvenido a {appName}</h1>
645
+ <p>Usuario: {user?.email}</p>
646
+ <p>Token válido: {token ? 'Sí' : 'No'}</p>
647
+ </div>
648
+ )
649
+ }
650
+ ```
651
+
652
+ ### Variables de Entorno Requeridas
653
+
654
+ ```env
655
+ # .env.development
656
+ VITE_TEST_PUBLIC_API_KEY=tu-clave-de-api-de-desarrollo
657
+ VITE_TEST_ENV=dev
658
+
659
+ # .env.production
660
+ VITE_TEST_PUBLIC_API_KEY=tu-clave-de-api-de-produccion
661
+ VITE_TEST_ENV=prod
662
+ ```
663
+
664
+ ### Ventajas de este Patrón
665
+
666
+ ✅ **Inicialización automática**: Crudify se inicializa automáticamente cuando hay token
667
+ ✅ **Gestión unificada**: Un solo provider para configuración y autenticación
668
+ ✅ **Rutas protegidas**: Manejo automático de redirecciones según autenticación
669
+ ✅ **Estados de carga**: Diferentes estados para config, theme e inicialización
670
+ ✅ **Variables de entorno**: Configuración centralizada desde .env
671
+ ✅ **Compatibilidad completa**: Mantiene la API de providers anteriores
672
+ ✅ **Sin recursión**: Evita problemas de bucles infinitos en la inicialización
673
+
372
674
  ---
373
675
 
374
676
  **Version:** 1.0.0+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocios/crudify-ui",
3
- "version": "1.0.83",
3
+ "version": "1.0.84",
4
4
  "description": "Biblioteca de componentes UI para Crudify",
5
5
  "author": "Nocios",
6
6
  "license": "MIT",