@djangocfg/layouts 1.4.29 → 2.0.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.
Files changed (119) hide show
  1. package/README.md +277 -18
  2. package/package.json +15 -24
  3. package/src/auth/context/AuthContext.tsx +8 -5
  4. package/src/auth/hooks/useAuthGuard.ts +1 -1
  5. package/src/auth/hooks/useAutoAuth.ts +8 -7
  6. package/src/components/ErrorBoundary.tsx +78 -0
  7. package/src/components/JsonLd.tsx +31 -0
  8. package/src/components/LucideIcon.tsx +91 -0
  9. package/src/components/PageProgress.tsx +127 -0
  10. package/src/components/Suspense.tsx +29 -0
  11. package/src/{layouts/AppLayout/components → components}/UpdateNotifier/UpdateNotifier.tsx +56 -49
  12. package/src/components/index.ts +10 -0
  13. package/src/index.ts +25 -7
  14. package/src/layouts/AdminLayout/AdminLayout.tsx +46 -0
  15. package/src/layouts/AdminLayout/index.ts +7 -0
  16. package/src/layouts/AppLayout/AppLayout.tsx +278 -326
  17. package/src/layouts/AppLayout/index.ts +2 -39
  18. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/AuthContext.tsx +3 -2
  19. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/AuthHelp.tsx +1 -0
  20. package/src/layouts/AuthLayout/AuthLayout.tsx +61 -0
  21. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/IdentifierForm.tsx +47 -34
  22. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/OTPForm.tsx +2 -3
  23. package/src/layouts/AuthLayout/index.ts +24 -0
  24. package/src/layouts/{AppLayout/layouts/AuthLayout → AuthLayout}/types.ts +1 -0
  25. package/src/layouts/PrivateLayout/PrivateLayout.tsx +144 -0
  26. package/src/layouts/PrivateLayout/components/PrivateContent.tsx +32 -0
  27. package/src/layouts/PrivateLayout/components/PrivateHeader.tsx +57 -0
  28. package/src/layouts/PrivateLayout/components/PrivateSidebar.tsx +141 -0
  29. package/src/layouts/PrivateLayout/components/index.ts +8 -0
  30. package/src/layouts/PrivateLayout/index.ts +7 -0
  31. package/src/layouts/ProfileLayout/ProfileLayout.tsx +15 -7
  32. package/src/layouts/PublicLayout/PublicLayout.tsx +121 -0
  33. package/src/layouts/PublicLayout/components/PublicFooter.tsx +190 -0
  34. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +117 -0
  35. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +101 -0
  36. package/src/layouts/PublicLayout/components/index.ts +8 -0
  37. package/src/layouts/PublicLayout/index.ts +7 -0
  38. package/src/layouts/_components/UserMenu.tsx +160 -0
  39. package/src/layouts/_components/index.ts +7 -0
  40. package/src/layouts/index.ts +15 -8
  41. package/src/snippets/Analytics/AnalyticsProvider.tsx +8 -4
  42. package/src/snippets/Analytics/useAnalytics.ts +11 -21
  43. package/src/snippets/Chat/ChatWidget.tsx +4 -4
  44. package/src/snippets/ContactForm/ContactFormProvider.tsx +32 -19
  45. package/src/snippets/ContactForm/ContactPage.tsx +2 -4
  46. package/src/snippets/ContactForm/types.ts +3 -2
  47. package/src/snippets/index.ts +0 -1
  48. package/src/layouts/AppLayout/README.md +0 -204
  49. package/src/layouts/AppLayout/SUMMARY.md +0 -240
  50. package/src/layouts/AppLayout/USAGE.md +0 -312
  51. package/src/layouts/AppLayout/components/ErrorBoundary.tsx +0 -112
  52. package/src/layouts/AppLayout/components/PageProgress.tsx +0 -123
  53. package/src/layouts/AppLayout/components/Seo.tsx +0 -171
  54. package/src/layouts/AppLayout/components/UserMenu.tsx +0 -385
  55. package/src/layouts/AppLayout/components/index.ts +0 -11
  56. package/src/layouts/AppLayout/context/AppContext.tsx +0 -151
  57. package/src/layouts/AppLayout/context/index.ts +0 -5
  58. package/src/layouts/AppLayout/hooks/index.ts +0 -8
  59. package/src/layouts/AppLayout/hooks/useLayoutMode.ts +0 -26
  60. package/src/layouts/AppLayout/hooks/useNavigation.ts +0 -51
  61. package/src/layouts/AppLayout/layouts/AdminLayout/AdminLayout.tsx +0 -224
  62. package/src/layouts/AppLayout/layouts/AdminLayout/README.md +0 -409
  63. package/src/layouts/AppLayout/layouts/AdminLayout/components/PagePreloader.example.tsx +0 -98
  64. package/src/layouts/AppLayout/layouts/AdminLayout/components/PagePreloader.tsx +0 -149
  65. package/src/layouts/AppLayout/layouts/AdminLayout/components/ParentSync.tsx +0 -146
  66. package/src/layouts/AppLayout/layouts/AdminLayout/components/index.ts +0 -3
  67. package/src/layouts/AppLayout/layouts/AdminLayout/context/CfgAppContext.tsx +0 -48
  68. package/src/layouts/AppLayout/layouts/AdminLayout/context/index.ts +0 -2
  69. package/src/layouts/AppLayout/layouts/AdminLayout/hooks/index.ts +0 -6
  70. package/src/layouts/AppLayout/layouts/AdminLayout/hooks/useApp.ts +0 -279
  71. package/src/layouts/AppLayout/layouts/AdminLayout/index.ts +0 -24
  72. package/src/layouts/AppLayout/layouts/AdminLayout/lottie/energizing.json +0 -1
  73. package/src/layouts/AppLayout/layouts/AdminLayout/types/index.ts +0 -45
  74. package/src/layouts/AppLayout/layouts/AuthLayout/AuthLayout.tsx +0 -41
  75. package/src/layouts/AppLayout/layouts/AuthLayout/index.ts +0 -15
  76. package/src/layouts/AppLayout/layouts/PrivateLayout/PrivateLayout.tsx +0 -82
  77. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardContent.tsx +0 -62
  78. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardHeader.tsx +0 -89
  79. package/src/layouts/AppLayout/layouts/PrivateLayout/components/DashboardSidebar.tsx +0 -181
  80. package/src/layouts/AppLayout/layouts/PrivateLayout/components/index.ts +0 -9
  81. package/src/layouts/AppLayout/layouts/PrivateLayout/index.ts +0 -5
  82. package/src/layouts/AppLayout/layouts/PublicLayout/PublicLayout.tsx +0 -44
  83. package/src/layouts/AppLayout/layouts/PublicLayout/components/Footer.tsx +0 -242
  84. package/src/layouts/AppLayout/layouts/PublicLayout/components/MobileDrawer.tsx +0 -150
  85. package/src/layouts/AppLayout/layouts/PublicLayout/components/Navigation.tsx +0 -169
  86. package/src/layouts/AppLayout/layouts/PublicLayout/index.ts +0 -5
  87. package/src/layouts/AppLayout/layouts/index.ts +0 -7
  88. package/src/layouts/AppLayout/providers/CoreProviders.tsx +0 -80
  89. package/src/layouts/AppLayout/providers/index.ts +0 -5
  90. package/src/layouts/AppLayout/types/config.ts +0 -79
  91. package/src/layouts/AppLayout/types/index.ts +0 -11
  92. package/src/layouts/AppLayout/types/layout.ts +0 -54
  93. package/src/layouts/AppLayout/types/navigation.ts +0 -43
  94. package/src/layouts/AppLayout/types/page.ts +0 -80
  95. package/src/layouts/AppLayout/types/routes.ts +0 -43
  96. package/src/layouts/AppLayout/utils/index.ts +0 -5
  97. package/src/layouts/AppLayout/utils/routeDetection.ts +0 -31
  98. package/src/layouts/ErrorLayout/ErrorLayout.tsx +0 -173
  99. package/src/layouts/ErrorLayout/errorConfig.tsx +0 -152
  100. package/src/layouts/ErrorLayout/index.ts +0 -8
  101. package/src/layouts/SimpleLayout/SimpleLayout.tsx +0 -72
  102. package/src/layouts/SimpleLayout/index.ts +0 -3
  103. package/src/snippets/VideoPlayer/README.md +0 -238
  104. package/src/snippets/VideoPlayer/VideoControls.tsx +0 -137
  105. package/src/snippets/VideoPlayer/VideoPlayer.tsx +0 -248
  106. package/src/snippets/VideoPlayer/index.ts +0 -8
  107. package/src/snippets/VideoPlayer/types.ts +0 -61
  108. package/src/types/index.ts +0 -2
  109. package/src/types/pageConfig.ts +0 -100
  110. /package/src/{validation → components/ErrorsTracker}/README.md +0 -0
  111. /package/src/{validation → components/ErrorsTracker}/components/ErrorButtons.tsx +0 -0
  112. /package/src/{validation → components/ErrorsTracker}/components/ErrorToast.tsx +0 -0
  113. /package/src/{validation → components/ErrorsTracker}/hooks.ts +0 -0
  114. /package/src/{validation → components/ErrorsTracker}/index.ts +0 -0
  115. /package/src/{validation → components/ErrorsTracker}/providers/ErrorTrackingProvider.tsx +0 -0
  116. /package/src/{validation → components/ErrorsTracker}/types.ts +0 -0
  117. /package/src/{validation → components/ErrorsTracker}/utils/curl-generator.ts +0 -0
  118. /package/src/{validation → components/ErrorsTracker}/utils/formatters.ts +0 -0
  119. /package/src/{layouts/AppLayout/components → components}/UpdateNotifier/index.ts +0 -0
@@ -1,151 +0,0 @@
1
- /**
2
- * App Context
3
- *
4
- * Unified context for entire application layout system
5
- * Provides centralized access to configuration, state, and utilities
6
- */
7
-
8
- 'use client';
9
-
10
- import React, { createContext, useContext, useState, ReactNode, useMemo } from 'react';
11
- import { useRouter } from 'next/router';
12
- import type { AppLayoutConfig, LayoutMode, RouteDetectors } from '../types';
13
-
14
- // ═══════════════════════════════════════════════════════════════════════════
15
- // Context Types
16
- // ═══════════════════════════════════════════════════════════════════════════
17
-
18
- interface AppContextValue {
19
- // Configuration
20
- config: AppLayoutConfig;
21
-
22
- // Route detection
23
- routes: RouteDetectors;
24
- currentPath: string;
25
- layoutMode: LayoutMode;
26
-
27
- // Mobile drawer state
28
- mobileDrawerOpen: boolean;
29
- openMobileDrawer: () => void;
30
- closeMobileDrawer: () => void;
31
- toggleMobileDrawer: () => void;
32
-
33
- // User menu state (desktop dropdown)
34
- userMenuOpen: boolean;
35
- openUserMenu: () => void;
36
- closeUserMenu: () => void;
37
- toggleUserMenu: () => void;
38
-
39
- // Sidebar state (dashboard)
40
- sidebarCollapsed: boolean;
41
- collapseSidebar: () => void;
42
- expandSidebar: () => void;
43
- toggleSidebar: () => void;
44
-
45
- // Features
46
- showUpdateNotifier?: boolean;
47
- }
48
-
49
- // ═══════════════════════════════════════════════════════════════════════════
50
- // Context Creation
51
- // ═══════════════════════════════════════════════════════════════════════════
52
-
53
- const AppContext = createContext<AppContextValue | null>(null);
54
-
55
- // ═══════════════════════════════════════════════════════════════════════════
56
- // Provider Component
57
- // ═══════════════════════════════════════════════════════════════════════════
58
-
59
- export interface AppContextProviderProps {
60
- children: ReactNode;
61
- config: AppLayoutConfig;
62
- showUpdateNotifier?: boolean;
63
- }
64
-
65
- /**
66
- * AppContext Provider
67
- *
68
- * Provides unified application context to all child components
69
- * Manages layout state and exposes configuration
70
- */
71
- export function AppContextProvider({ children, config, showUpdateNotifier }: AppContextProviderProps) {
72
- const router = useRouter();
73
-
74
- // UI state
75
- const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false);
76
- const [userMenuOpen, setUserMenuOpen] = useState(false);
77
- const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
78
-
79
- // Determine current layout mode
80
- const layoutMode = useMemo((): LayoutMode => {
81
- const { isAuthRoute, isPrivateRoute } = config.routes.detectors;
82
-
83
- if (isAuthRoute(router.pathname)) return 'auth';
84
- if (isPrivateRoute(router.pathname)) return 'private';
85
- return 'public';
86
- }, [router.pathname, config.routes.detectors]);
87
-
88
- // Mobile drawer handlers
89
- const openMobileDrawer = () => setMobileDrawerOpen(true);
90
- const closeMobileDrawer = () => setMobileDrawerOpen(false);
91
- const toggleMobileDrawer = () => setMobileDrawerOpen(prev => !prev);
92
-
93
- // User menu handlers
94
- const openUserMenu = () => setUserMenuOpen(true);
95
- const closeUserMenu = () => setUserMenuOpen(false);
96
- const toggleUserMenu = () => setUserMenuOpen(prev => !prev);
97
-
98
- // Sidebar handlers
99
- const collapseSidebar = () => setSidebarCollapsed(true);
100
- const expandSidebar = () => setSidebarCollapsed(false);
101
- const toggleSidebar = () => setSidebarCollapsed(prev => !prev);
102
-
103
- const value: AppContextValue = {
104
- config,
105
- routes: config.routes.detectors,
106
- currentPath: router.pathname,
107
- layoutMode,
108
- mobileDrawerOpen,
109
- openMobileDrawer,
110
- closeMobileDrawer,
111
- toggleMobileDrawer,
112
- userMenuOpen,
113
- openUserMenu,
114
- closeUserMenu,
115
- toggleUserMenu,
116
- sidebarCollapsed,
117
- collapseSidebar,
118
- expandSidebar,
119
- toggleSidebar,
120
- showUpdateNotifier,
121
- };
122
-
123
- return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
124
- }
125
-
126
- // ═══════════════════════════════════════════════════════════════════════════
127
- // Hook
128
- // ═══════════════════════════════════════════════════════════════════════════
129
-
130
- /**
131
- * Hook to access AppContext
132
- *
133
- * @throws {Error} If used outside AppContextProvider
134
- *
135
- * @example
136
- * ```tsx
137
- * const { config, layoutMode, toggleMobileDrawer } = useAppContext();
138
- * ```
139
- */
140
- export function useAppContext(): AppContextValue {
141
- const context = useContext(AppContext);
142
-
143
- if (!context) {
144
- throw new Error(
145
- 'useAppContext must be used within AppContextProvider. ' +
146
- 'Make sure your component is wrapped with <AppLayout>.'
147
- );
148
- }
149
-
150
- return context;
151
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * Context Module
3
- */
4
-
5
- export * from './AppContext';
@@ -1,8 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * Hooks Module
5
- */
6
-
7
- export * from './useLayoutMode';
8
- export * from './useNavigation';
@@ -1,26 +0,0 @@
1
- /**
2
- * useLayoutMode Hook
3
- *
4
- * Returns current layout mode
5
- */
6
-
7
- import { useAppContext } from '../context';
8
- import type { LayoutMode } from '../types';
9
-
10
- /**
11
- * Get current layout mode
12
- *
13
- * @returns Current layout mode ('public' | 'private' | 'auth')
14
- *
15
- * @example
16
- * ```tsx
17
- * const mode = useLayoutMode();
18
- * if (mode === 'private') {
19
- * return <DashboardContent />;
20
- * }
21
- * ```
22
- */
23
- export function useLayoutMode(): LayoutMode {
24
- const { layoutMode } = useAppContext();
25
- return layoutMode;
26
- }
@@ -1,51 +0,0 @@
1
- /**
2
- * useNavigation Hook
3
- *
4
- * Navigation utilities
5
- */
6
-
7
- 'use client';
8
-
9
- import { useRouter } from 'next/navigation';
10
- import { useAppContext } from '../context';
11
-
12
- export interface UseNavigationReturn {
13
- /** Current pathname */
14
- currentPath: string;
15
-
16
- /** Check if path is active */
17
- isActive: (path: string) => boolean;
18
-
19
- /** Get page title for current route */
20
- getPageTitle: () => string;
21
- }
22
-
23
- /**
24
- * Navigation utilities hook
25
- *
26
- * @example
27
- * ```tsx
28
- * const { isActive, getPageTitle } = useNavigation();
29
- * const title = getPageTitle();
30
- * ```
31
- */
32
- export function useNavigation(): UseNavigationReturn {
33
- const router = useRouter();
34
- const { routes, currentPath } = useAppContext();
35
-
36
- const isActive = (path: string): boolean => {
37
- if (currentPath === path) return true;
38
- if (path !== '/' && currentPath.startsWith(path)) return true;
39
- return false;
40
- };
41
-
42
- const getPageTitle = (): string => {
43
- return routes.getPageTitle(currentPath);
44
- };
45
-
46
- return {
47
- currentPath,
48
- isActive,
49
- getPageTitle,
50
- };
51
- }
@@ -1,224 +0,0 @@
1
- // @ts-nocheck
2
- // ============================================================================
3
- // AdminLayout - Django CFG Layout with iframe Integration
4
- // ============================================================================
5
- // Universal layout component that handles:
6
- // - iframe embedding detection
7
- // - Parent ↔ iframe communication (postMessage)
8
- // - Theme synchronization from Django Unfold
9
- // - Auth token passing from parent window (automatically sets in API client)
10
- // - Auth status reporting to parent window
11
- // - Automatic layout disable in iframe mode
12
- //
13
- // This is a lightweight wrapper that can be used with any layout system
14
- // (AppLayout, custom layouts, etc.)
15
-
16
- 'use client';
17
-
18
- import React, { ReactNode } from 'react';
19
- import { ShieldAlert } from 'lucide-react';
20
- import { ParentSync, PagePreloader } from './components';
21
- import { CfgAppProvider, useCfgAppContext } from './context';
22
- import type { AdminLayoutConfig } from './types';
23
- import { api } from '@djangocfg/api';
24
- import { useAuth } from '../../../../auth';
25
- import { consola } from 'consola';
26
-
27
- export interface AdminLayoutProps {
28
- children: ReactNode;
29
- config?: AdminLayoutConfig;
30
- /**
31
- * Whether to render ParentSync component
32
- * Set to false if you want to handle sync manually
33
- * @default true
34
- */
35
- enableParentSync?: boolean;
36
- }
37
-
38
- /**
39
- * AdminLayout - Universal Layout Component for Django CFG
40
- *
41
- * Provides iframe integration features:
42
- * - Auto-detects iframe embedding
43
- * - Syncs theme from parent window (Django Unfold)
44
- * - Receives auth tokens from parent window and automatically sets them in API client
45
- * - Sends auth status to parent window
46
- * - Provides useApp hook data via context
47
- *
48
- * Usage:
49
- * ```tsx
50
- * // Wrap your app in _app.tsx - no config needed!
51
- * <AdminLayout>
52
- * <AppLayout config={appLayoutConfig}>
53
- * <Component {...pageProps} />
54
- * </AppLayout>
55
- * </AdminLayout>
56
- * ```
57
- *
58
- * Or with custom auth handler:
59
- * ```tsx
60
- * <AdminLayout config={{
61
- * onAuthTokenReceived: (authToken, refreshToken) => {
62
- * // Custom logic before/after setting tokens
63
- * console.log('Tokens received');
64
- * }
65
- * }}>
66
- * <AppLayout config={appLayoutConfig}>
67
- * <Component {...pageProps} />
68
- * </AppLayout>
69
- * </AdminLayout>
70
- * ```
71
- *
72
- * Use useCfgApp hook directly:
73
- * ```tsx
74
- * import { useCfgApp } from '@djangocfg/layouts/AdminLayout';
75
- *
76
- * function MyComponent() {
77
- * const { isEmbedded, disableLayout, parentTheme } = useCfgApp();
78
- * // ...
79
- * }
80
- * ```
81
- */
82
- export function AdminLayout({
83
- children,
84
- config,
85
- enableParentSync = true
86
- }: AdminLayoutProps) {
87
- return (
88
- <AdminLayoutClientWithProvider config={config} enableParentSync={enableParentSync}>{children}</AdminLayoutClientWithProvider>
89
- );
90
- }
91
-
92
- // Wrapper component that provides CfgAppProvider with auth callback
93
- function AdminLayoutClientWithProvider({
94
- children,
95
- config,
96
- enableParentSync
97
- }: AdminLayoutProps) {
98
- const { loadCurrentProfile } = useAuth();
99
-
100
- // Use refs to prevent re-renders and maintain state across renders
101
- const profileLoadedRef = React.useRef(false);
102
- const tokensReceivedRef = React.useRef(false);
103
- const loadCurrentProfileRef = React.useRef(loadCurrentProfile);
104
-
105
- // Update ref when loadCurrentProfile changes (but don't trigger re-render)
106
- React.useEffect(() => {
107
- loadCurrentProfileRef.current = loadCurrentProfile;
108
- }, [loadCurrentProfile]);
109
-
110
- // Create a STABLE callback that NEVER changes (no dependencies)
111
- // Use refs to access latest values without recreating the callback
112
- const handleAuthToken = React.useCallback(async (authToken: string, refreshToken?: string) => {
113
- consola.info('[AdminLayout] handleAuthToken called', {
114
- tokensReceived: tokensReceivedRef.current,
115
- profileLoaded: profileLoadedRef.current
116
- });
117
-
118
- // Prevent duplicate token processing
119
- if (tokensReceivedRef.current) {
120
- consola.warn('[AdminLayout] Tokens already received and processed, ignoring duplicate');
121
- return;
122
- }
123
-
124
- // Mark tokens as received IMMEDIATELY to prevent race conditions
125
- tokensReceivedRef.current = true;
126
-
127
- consola.start('[AdminLayout] First time receiving tokens, processing...');
128
- consola.debug('[AdminLayout] Tokens:', {
129
- authToken: authToken.substring(0, 20) + '...',
130
- refreshToken: refreshToken ? refreshToken.substring(0, 20) + '...' : 'null'
131
- });
132
-
133
- // Always set tokens in API client
134
- api.setToken(authToken, refreshToken);
135
- consola.success('[AdminLayout] Tokens set in API client');
136
-
137
- // Load user profile after setting tokens - ONLY ONCE per session
138
- if (!profileLoadedRef.current) {
139
- consola.start('[AdminLayout] Loading user profile (first time)...');
140
- try {
141
- await loadCurrentProfileRef.current('AdminLayout.onAuthTokenReceived');
142
- profileLoadedRef.current = true;
143
- consola.success('[AdminLayout] User profile loaded successfully');
144
- } catch (error) {
145
- consola.error('[AdminLayout] Failed to load profile:', error);
146
- // Reset flags on error so user can retry
147
- tokensReceivedRef.current = false;
148
- profileLoadedRef.current = false;
149
- }
150
- } else {
151
- consola.info('[AdminLayout] Profile already loaded, skipping duplicate call');
152
- }
153
-
154
- // Call custom handler if provided
155
- if (config?.onAuthTokenReceived) {
156
- consola.info('[AdminLayout] Calling custom onAuthTokenReceived handler');
157
- config.onAuthTokenReceived(authToken, refreshToken);
158
- }
159
- }, []); // ← EMPTY DEPS - callback NEVER changes
160
-
161
- return (
162
- <CfgAppProvider options={{
163
- onAuthTokenReceived: handleAuthToken
164
- }}>
165
- <AdminLayoutClient config={config} enableParentSync={enableParentSync}>{children}</AdminLayoutClient>
166
- </CfgAppProvider>
167
- );
168
- }
169
-
170
- function AdminLayoutClient({
171
- children,
172
- config,
173
- enableParentSync = true
174
- }: AdminLayoutProps) {
175
- const { isAdminUser, user, isLoading, isAuthenticated } = useAuth();
176
- // console.log('[AdminLayout] Rendering with user:', user, 'isLoading:', isLoading, 'isAuthenticated:', isAuthenticated);
177
-
178
- // Get embedding state from context (provided by CfgAppProvider wrapper)
179
- const { isEmbedded } = useCfgAppContext();
180
-
181
- // console.log('[AdminLayout] isEmbedded:', isEmbedded);
182
-
183
- // Show loading while auth is initializing (waiting for tokens from parent or profile loading)
184
- // OR if user object is not loaded yet (null/undefined)
185
- // OR if authentication status is not yet determined
186
- if (isLoading || !user || !isAuthenticated) {
187
- // console.log('[AdminLayout] Showing loading state - isLoading:', isLoading, 'user:', user, 'isAuthenticated:', isAuthenticated);
188
- return <PagePreloader text="Authenticating..." size="lg" />;
189
- }
190
-
191
- // Only show "Access Denied" when we are CERTAIN user doesn't have permissions
192
- // This prevents showing the message during auth/loading states
193
- if (!isAdminUser) {
194
- // Only show this when user is fully authenticated but lacks permissions
195
- // console.log('[AdminLayout] Authenticated user lacks admin permissions');
196
- return (
197
- <div className="min-h-screen flex items-center justify-center bg-background">
198
- <div className="text-center space-y-4 p-8">
199
- <div className="flex justify-center">
200
- <ShieldAlert className="w-16 h-16 text-destructive" />
201
- </div>
202
- <h1 className="text-2xl font-bold text-foreground">Access Denied</h1>
203
- <p className="text-muted-foreground max-w-md">
204
- You don't have permission to access this admin panel.
205
- <br />
206
- Staff or superuser privileges are required.
207
- </p>
208
- </div>
209
- </div>
210
- );
211
- }
212
-
213
- return (
214
- <>
215
- {/* ParentSync handles theme sync and auth status reporting */}
216
- {enableParentSync && <ParentSync />}
217
-
218
- {/* Apply padding only when NOT in iframe */}
219
- <div>
220
- {children}
221
- </div>
222
- </>
223
- );
224
- }